feat(engine): register MCP profiles and provider transitions
This commit is contained in:
@@ -7,3 +7,4 @@ export * from "./v9/index.mjs";
|
||||
export { geliosProviderPackageV10 } from "./v10/index.mjs";
|
||||
export { geliosProviderPackageV11 } from "./v11/index.mjs";
|
||||
export { geliosProviderPackageV12 } from "./v12/index.mjs";
|
||||
export { geliosProviderPackageV13 } from "./v13/index.mjs";
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { geliosProviderPackageV11 } from "../v11/package.mjs";
|
||||
|
||||
export const GELIOS_PROVIDER_PACKAGE_ID = "gelios.provider.v12";
|
||||
export const GELIOS_PROVIDER_PACKAGE_VERSION = "12.0.0";
|
||||
export const GELIOS_PROVIDER_PACKAGE_VERSION = "12.0.1";
|
||||
export const GELIOS_UNIT_IDENTITY_DATA_PRODUCT_ID = "fleet.units.identity.current.v1";
|
||||
export const GELIOS_UNIT_IDENTITY_DATA_PRODUCT_VERSION = "1.0.0";
|
||||
export const GELIOS_UNIT_IDENTITY_ONTOLOGY_REVISION = "ontology.map.moving_object.v3";
|
||||
|
||||
const IDENTITY_CONTRACT_VERSION = "12.0.0";
|
||||
const IDENTITY_CAPABILITY_ID = "gelios.units.identity.read";
|
||||
const UNITS_CAPABILITY_ID = "gelios.units.current.read";
|
||||
const IDENTITY_PROFILE_ID = "gelios.units.identity.warm.v1";
|
||||
const IDENTITY_MAPPING_ID = "gelios.units.to.fleet.units.identity.current.v1";
|
||||
const IDENTITY_TEMPLATE_ID = "gelios.units.identity.l2.v1";
|
||||
@@ -24,33 +26,43 @@ const identityCapability = value.capabilities.find(
|
||||
(capability) => capability.id === IDENTITY_CAPABILITY_ID,
|
||||
);
|
||||
if (!identityCapability) throw new Error("gelios_v12_identity_capability_missing");
|
||||
identityCapability.request.response.collectionPaths = [
|
||||
"items",
|
||||
...identityCapability.request.response.collectionPaths.filter(
|
||||
(path) => path !== "items",
|
||||
),
|
||||
];
|
||||
prependItemsCollectionPath(identityCapability);
|
||||
|
||||
const unitsCapability = value.capabilities.find(
|
||||
(capability) => capability.id === UNITS_CAPABILITY_ID,
|
||||
);
|
||||
if (!unitsCapability) throw new Error("gelios_v12_units_capability_missing");
|
||||
prependItemsCollectionPath(unitsCapability);
|
||||
|
||||
const identityProfile = value.collectionProfiles.find(
|
||||
(profile) => profile.id === IDENTITY_PROFILE_ID,
|
||||
);
|
||||
if (!identityProfile) throw new Error("gelios_v12_identity_profile_missing");
|
||||
identityProfile.version = GELIOS_PROVIDER_PACKAGE_VERSION;
|
||||
identityProfile.version = IDENTITY_CONTRACT_VERSION;
|
||||
|
||||
const identityMapping = value.mappingContracts.find(
|
||||
(mapping) => mapping.id === IDENTITY_MAPPING_ID,
|
||||
);
|
||||
if (!identityMapping) throw new Error("gelios_v12_identity_mapping_missing");
|
||||
identityMapping.version = GELIOS_PROVIDER_PACKAGE_VERSION;
|
||||
identityMapping.version = IDENTITY_CONTRACT_VERSION;
|
||||
|
||||
const identityTemplate = value.l2Templates.find(
|
||||
(template) => template.id === IDENTITY_TEMPLATE_ID,
|
||||
);
|
||||
if (!identityTemplate) throw new Error("gelios_v12_identity_template_missing");
|
||||
identityTemplate.version = GELIOS_PROVIDER_PACKAGE_VERSION;
|
||||
identityTemplate.version = IDENTITY_CONTRACT_VERSION;
|
||||
|
||||
export const geliosProviderPackageV12 = deepFreeze(value);
|
||||
|
||||
function prependItemsCollectionPath(capability) {
|
||||
capability.request.response.collectionPaths = [
|
||||
"items",
|
||||
...capability.request.response.collectionPaths.filter(
|
||||
(path) => path !== "items",
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
function deepFreeze(input) {
|
||||
if (!input || typeof input !== "object" || Object.isFrozen(input)) return input;
|
||||
Object.freeze(input);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
export {
|
||||
GELIOS_PROVIDER_PACKAGE_ID,
|
||||
GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
GELIOS_UNIT_CONTACTS_DATA_PRODUCT_ID,
|
||||
GELIOS_UNIT_CONTACTS_DATA_PRODUCT_VERSION,
|
||||
GELIOS_UNIT_CONTACTS_ONTOLOGY_REVISION,
|
||||
geliosProviderPackageV13,
|
||||
} from "./package.mjs";
|
||||
export { geliosTelemetryFieldRegistryV5 } from "../v12/index.mjs";
|
||||
export { geliosCapabilityCatalogV3 } from "../capability-catalog-v3.mjs";
|
||||
@@ -0,0 +1,318 @@
|
||||
import { geliosProviderPackageV12 } from "../v12/package.mjs";
|
||||
|
||||
export const GELIOS_PROVIDER_PACKAGE_ID = "gelios.provider.v13";
|
||||
export const GELIOS_PROVIDER_PACKAGE_VERSION = "13.0.0";
|
||||
export const GELIOS_UNIT_CONTACTS_DATA_PRODUCT_ID = "fleet.units.contacts.current.v2";
|
||||
export const GELIOS_UNIT_CONTACTS_DATA_PRODUCT_VERSION = "2.0.0";
|
||||
export const GELIOS_UNIT_CONTACTS_ONTOLOGY_REVISION = "ontology.map.moving_object.v3";
|
||||
|
||||
const UNITS_CAPABILITY_ID = "gelios.units.identity.read";
|
||||
const USERS_CAPABILITY_ID = "gelios.users.directory.read";
|
||||
const FIELD_POLICY_ID = "gelios.units.contacts.fields.v2";
|
||||
const COLLECTION_PROFILE_ID = "gelios.units.contacts.warm.v2";
|
||||
const MAPPING_ID = "gelios.units.to.fleet.units.contacts.current.v2";
|
||||
const TEMPLATE_ID = "gelios.units.contacts.l2.v2";
|
||||
|
||||
const contactFields = Object.freeze([
|
||||
"available_user_emails",
|
||||
"available_user_ids",
|
||||
"available_user_legal_names",
|
||||
"available_user_logins",
|
||||
"available_user_phones",
|
||||
"device_imei",
|
||||
"device_phone_primary",
|
||||
"device_phone_secondary",
|
||||
"display_name",
|
||||
"provider_creator_email",
|
||||
"provider_creator_id",
|
||||
"provider_creator_legal_name",
|
||||
"provider_creator_login",
|
||||
"provider_creator_phone",
|
||||
]);
|
||||
|
||||
const value = structuredClone(geliosProviderPackageV12);
|
||||
const unitsCapability = value.capabilities.find(
|
||||
(capability) => capability.id === UNITS_CAPABILITY_ID,
|
||||
);
|
||||
const templateBase = value.l2Templates.find(
|
||||
(template) => template.id === "gelios.units.identity.l2.v1",
|
||||
);
|
||||
if (!unitsCapability) throw new Error("gelios_v13_units_capability_missing");
|
||||
if (!templateBase) throw new Error("gelios_v13_template_base_missing");
|
||||
|
||||
value.id = GELIOS_PROVIDER_PACKAGE_ID;
|
||||
value.version = GELIOS_PROVIDER_PACKAGE_VERSION;
|
||||
value.manifest = {
|
||||
...value.manifest,
|
||||
id: "gelios.provider.manifest.v13",
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
capabilityIds: [...value.manifest.capabilityIds, USERS_CAPABILITY_ID],
|
||||
fieldPolicyIds: [...value.manifest.fieldPolicyIds, FIELD_POLICY_ID],
|
||||
collectionProfileIds: [...value.manifest.collectionProfileIds, COLLECTION_PROFILE_ID],
|
||||
dataProductIds: [...value.manifest.dataProductIds, GELIOS_UNIT_CONTACTS_DATA_PRODUCT_ID],
|
||||
mappingContractIds: [...value.manifest.mappingContractIds, MAPPING_ID],
|
||||
l2TemplateIds: [...value.manifest.l2TemplateIds, TEMPLATE_ID],
|
||||
};
|
||||
|
||||
value.capabilities.push({
|
||||
...structuredClone(unitsCapability),
|
||||
id: USERS_CAPABILITY_ID,
|
||||
request: {
|
||||
...structuredClone(unitsCapability.request),
|
||||
path: "/api/v1/users",
|
||||
query: {
|
||||
incladmpan: false,
|
||||
inclavfun: false,
|
||||
inclbillinf: false,
|
||||
inclextra: false,
|
||||
inclexs: false,
|
||||
inclmon: false,
|
||||
inclsmtp: false,
|
||||
o1: "userIdAsc",
|
||||
pl: 500,
|
||||
po: 0,
|
||||
},
|
||||
response: {
|
||||
collectionPaths: ["items"],
|
||||
pagination: {
|
||||
mode: "offset",
|
||||
limitParameter: "pl",
|
||||
offsetParameter: "po",
|
||||
pageSize: 500,
|
||||
itemsPath: "items",
|
||||
totalPath: "paginationMetadata.totalCount",
|
||||
maxPages: 10,
|
||||
maxItems: 5000,
|
||||
maxResponseBytes: 16 * 1024 * 1024,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
value.fieldPolicies.push({
|
||||
id: FIELD_POLICY_ID,
|
||||
version: GELIOS_UNIT_CONTACTS_DATA_PRODUCT_VERSION,
|
||||
dataProductId: GELIOS_UNIT_CONTACTS_DATA_PRODUCT_ID,
|
||||
targetFields: [...contactFields],
|
||||
unknownSourceFields: "drop",
|
||||
dynamicSourceFields: "drop_until_classified",
|
||||
restrictedSourcePaths: [
|
||||
"commands",
|
||||
"currentUserAccess",
|
||||
"customFields",
|
||||
"driver",
|
||||
"extraInfo",
|
||||
"hwDecryptKey",
|
||||
"lastMsg",
|
||||
"lastSensorsVal",
|
||||
"maintenancePlan",
|
||||
"preSetCommandGroup",
|
||||
"sensors",
|
||||
"stationaryLat",
|
||||
"stationaryLon",
|
||||
"storageInfo",
|
||||
],
|
||||
});
|
||||
|
||||
value.collectionProfiles.push({
|
||||
id: COLLECTION_PROFILE_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
mode: "realtime",
|
||||
schedule: { intervalMs: 5 * 60 * 1000 },
|
||||
capabilityIds: [UNITS_CAPABILITY_ID, USERS_CAPABILITY_ID],
|
||||
dataProductId: GELIOS_UNIT_CONTACTS_DATA_PRODUCT_ID,
|
||||
mappingContractId: MAPPING_ID,
|
||||
fieldPolicyId: FIELD_POLICY_ID,
|
||||
l2TemplateId: TEMPLATE_ID,
|
||||
entityScope: {
|
||||
mode: "all_visible_to_credential",
|
||||
refresh: "each_collection_run",
|
||||
businessEntityFilter: "forbidden",
|
||||
},
|
||||
batching: { maxFacts: 5000 },
|
||||
cardinality: {
|
||||
maxCurrentEntities: 5000,
|
||||
onExceed: "require_partitioned_data_product",
|
||||
},
|
||||
retry: { maxAttempts: 4, backoff: "fixed_delay", delayMs: 2000 },
|
||||
});
|
||||
|
||||
value.dataProducts.push({
|
||||
id: GELIOS_UNIT_CONTACTS_DATA_PRODUCT_ID,
|
||||
version: GELIOS_UNIT_CONTACTS_DATA_PRODUCT_VERSION,
|
||||
ontologyRevision: GELIOS_UNIT_CONTACTS_ONTOLOGY_REVISION,
|
||||
deliveryMode: "snapshot+patch",
|
||||
semanticTypes: ["map.moving_object"],
|
||||
fields: [...contactFields],
|
||||
fieldContracts: {
|
||||
available_user_emails: optional("string_array"),
|
||||
available_user_ids: optional("string_array"),
|
||||
available_user_legal_names: optional("string_array"),
|
||||
available_user_logins: optional("string_array"),
|
||||
available_user_phones: optional("string_array"),
|
||||
device_imei: optional("string"),
|
||||
device_phone_primary: optional("string"),
|
||||
device_phone_secondary: optional("string"),
|
||||
display_name: { type: "string", required: true },
|
||||
provider_creator_email: optional("string"),
|
||||
provider_creator_id: optional("string"),
|
||||
provider_creator_legal_name: optional("string"),
|
||||
provider_creator_login: optional("string"),
|
||||
provider_creator_phone: optional("string"),
|
||||
},
|
||||
history: { mode: "none", retentionDays: 1 },
|
||||
});
|
||||
|
||||
value.mappingContracts.push({
|
||||
schemaVersion: "nodedc.semantic-mapping/v1",
|
||||
id: MAPPING_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
sourceCapabilityId: UNITS_CAPABILITY_ID,
|
||||
fieldPolicyId: FIELD_POLICY_ID,
|
||||
target: {
|
||||
dataProductId: GELIOS_UNIT_CONTACTS_DATA_PRODUCT_ID,
|
||||
version: GELIOS_UNIT_CONTACTS_DATA_PRODUCT_VERSION,
|
||||
ontologyRevision: GELIOS_UNIT_CONTACTS_ONTOLOGY_REVISION,
|
||||
semanticType: "map.moving_object",
|
||||
},
|
||||
derivations: {
|
||||
available_user_emails: responseLookupList("availableToUsers", "email"),
|
||||
available_user_ids: boundedStringList("availableToUsers", "id"),
|
||||
available_user_legal_names: responseLookupList("availableToUsers", "legalName"),
|
||||
available_user_logins: boundedStringList("availableToUsers", "login"),
|
||||
available_user_phones: responseLookupList("availableToUsers", "phone"),
|
||||
provider_creator_email: responseLookupFirst("creator.id", "email"),
|
||||
provider_creator_legal_name: responseLookupFirst("creator.id", "legalName"),
|
||||
provider_creator_phone: responseLookupFirst("creator.id", "phone"),
|
||||
},
|
||||
fact: {
|
||||
sourceId: {
|
||||
strategy: "first_non_empty",
|
||||
paths: ["id", "unit_id", "unitId"],
|
||||
coerce: "string",
|
||||
prefix: "gelios-unit-",
|
||||
},
|
||||
semanticType: { constant: "map.moving_object" },
|
||||
observedAt: {
|
||||
strategy: "first_non_empty",
|
||||
paths: ["updatedAt"],
|
||||
coerce: "unix_or_iso_timestamp",
|
||||
fallback: "collection_received_at",
|
||||
},
|
||||
attributes: {
|
||||
available_user_emails: { derive: "available_user_emails" },
|
||||
available_user_ids: { derive: "available_user_ids" },
|
||||
available_user_legal_names: { derive: "available_user_legal_names" },
|
||||
available_user_logins: { derive: "available_user_logins" },
|
||||
available_user_phones: { derive: "available_user_phones" },
|
||||
device_imei: stringField(["imei"]),
|
||||
device_phone_primary: stringField(["phone"]),
|
||||
device_phone_secondary: stringField(["phone2"]),
|
||||
display_name: stringField(["name", "unit_name", "title", "label"], false),
|
||||
provider_creator_email: { derive: "provider_creator_email", omitIfMissing: true },
|
||||
provider_creator_id: stringField(["creator.id"]),
|
||||
provider_creator_legal_name: {
|
||||
derive: "provider_creator_legal_name",
|
||||
omitIfMissing: true,
|
||||
},
|
||||
provider_creator_login: stringField(["creator.login"]),
|
||||
provider_creator_phone: { derive: "provider_creator_phone", omitIfMissing: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
value.l2Templates.push({
|
||||
...structuredClone(templateBase),
|
||||
id: TEMPLATE_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
steps: [
|
||||
{ id: "collection.trigger", kind: "collection_trigger", collectionProfileDriven: true },
|
||||
{ id: "provider.fetch-units", kind: "provider_request", capabilityId: UNITS_CAPABILITY_ID },
|
||||
{ id: "provider.fetch-users", kind: "provider_request", capabilityId: USERS_CAPABILITY_ID },
|
||||
{ id: "provider.extract-units", kind: "extract_items", capabilityId: UNITS_CAPABILITY_ID },
|
||||
{ id: "ontology.map", kind: "semantic_mapping", mappingContractId: MAPPING_ID },
|
||||
{
|
||||
id: "data-product.publish",
|
||||
kind: "data_product_publish",
|
||||
dataProductId: GELIOS_UNIT_CONTACTS_DATA_PRODUCT_ID,
|
||||
nodeType: "n8n-nodes-ndc.ndcDataProductPublish",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const geliosProviderPackageV13 = deepFreeze(value);
|
||||
|
||||
function optional(type) {
|
||||
return { type, required: false };
|
||||
}
|
||||
|
||||
function stringField(paths, omitIfMissing = true) {
|
||||
return {
|
||||
strategy: "first_non_empty",
|
||||
paths,
|
||||
coerce: "string",
|
||||
...(omitIfMissing ? { omitIfMissing: true } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function boundedStringList(arrayPath, valuePath) {
|
||||
return {
|
||||
kind: "bounded_string_list",
|
||||
rules: ["array.string_values"],
|
||||
default: [],
|
||||
parameters: {
|
||||
arrayPath,
|
||||
valuePath,
|
||||
maxItems: 256,
|
||||
maxItemLength: 512,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function responseLookupList(sourceArrayPath, valuePath) {
|
||||
return {
|
||||
kind: "bounded_response_lookup",
|
||||
rules: ["response.lookup.list"],
|
||||
default: [],
|
||||
parameters: {
|
||||
responseCapabilityId: USERS_CAPABILITY_ID,
|
||||
responseCollectionPath: "items",
|
||||
responseKeyPath: "id",
|
||||
sourceArrayPath,
|
||||
sourceKeyPath: "id",
|
||||
valuePath,
|
||||
resultMode: "list",
|
||||
maxResponseItems: 5000,
|
||||
maxSourceKeys: 256,
|
||||
maxItems: 256,
|
||||
maxItemLength: 512,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function responseLookupFirst(sourceKeyPath, valuePath) {
|
||||
return {
|
||||
kind: "bounded_response_lookup",
|
||||
rules: ["response.lookup.first"],
|
||||
default: "",
|
||||
parameters: {
|
||||
responseCapabilityId: USERS_CAPABILITY_ID,
|
||||
responseCollectionPath: "items",
|
||||
responseKeyPath: "id",
|
||||
sourceKeyPath,
|
||||
valuePath,
|
||||
resultMode: "first",
|
||||
maxResponseItems: 5000,
|
||||
maxSourceKeys: 1,
|
||||
maxItems: 1,
|
||||
maxItemLength: 512,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function deepFreeze(input) {
|
||||
if (!input || typeof input !== "object" || Object.isFrozen(input)) return input;
|
||||
Object.freeze(input);
|
||||
for (const child of Object.values(input)) deepFreeze(child);
|
||||
return input;
|
||||
}
|
||||
@@ -9,11 +9,12 @@ export const L2_EXECUTION_PLAN_SCHEMA_VERSION = "nodedc.l2-execution-plan/v1";
|
||||
export const L2_GRAPH_BLUEPRINT_SCHEMA_VERSION = "nodedc.l2-graph-blueprint/v1";
|
||||
export const L2_MATERIALIZATION_RECEIPT_SCHEMA_VERSION = "nodedc.l2-materialization-receipt/v1";
|
||||
export const L2_MAPPING_RUNTIME_SCHEMA_VERSION = "nodedc.semantic-mapping-runtime/v1";
|
||||
export const L2_EXECUTION_PLAN_COMPILER_VERSION = "1.4.0";
|
||||
export const L2_EXECUTION_PLAN_COMPILER_VERSION = "1.5.0";
|
||||
export const L2_EXECUTION_PLAN_SUPPORTED_COMPILER_VERSIONS = Object.freeze([
|
||||
"1.1.0",
|
||||
"1.2.0",
|
||||
"1.3.0",
|
||||
"1.4.0",
|
||||
L2_EXECUTION_PLAN_COMPILER_VERSION,
|
||||
]);
|
||||
|
||||
|
||||
@@ -259,6 +259,14 @@ export function validateProviderPackage(value) {
|
||||
if (!selectedCapabilityIds.includes(mapping.sourceCapabilityId)) {
|
||||
errors.push(`collectionProfile.${profile.id}.mapping_source_capability_must_be_selected`);
|
||||
}
|
||||
for (const derivation of Object.values(mapping.derivations || {})) {
|
||||
if (
|
||||
derivation?.kind === "bounded_response_lookup"
|
||||
&& !selectedCapabilityIds.includes(derivation.parameters?.responseCapabilityId)
|
||||
) {
|
||||
errors.push(`collectionProfile.${profile.id}.lookup_response_capability_must_be_selected`);
|
||||
}
|
||||
}
|
||||
if (mapping.fieldPolicyId !== profile.fieldPolicyId) errors.push(`collectionProfile.${profile.id}.mapping_field_policy_mismatch`);
|
||||
if (mapping.target?.dataProductId !== profile.dataProductId) errors.push(`collectionProfile.${profile.id}.mapping_data_product_mismatch`);
|
||||
}
|
||||
@@ -283,6 +291,16 @@ export function validateProviderPackage(value) {
|
||||
}
|
||||
for (const mapping of mappingContracts) {
|
||||
assertReference(mapping.sourceCapabilityId, capabilityIds, `mappingContract.${mapping.id}.sourceCapabilityId`, errors);
|
||||
for (const [derivationId, derivation] of Object.entries(mapping.derivations || {})) {
|
||||
if (derivation?.kind === "bounded_response_lookup") {
|
||||
assertReference(
|
||||
derivation.parameters?.responseCapabilityId,
|
||||
capabilityIds,
|
||||
`mappingContract.${mapping.id}.derivations.${derivationId}.parameters.responseCapabilityId`,
|
||||
errors,
|
||||
);
|
||||
}
|
||||
}
|
||||
assertReference(mapping.fieldPolicyId, fieldPolicyIds, `mappingContract.${mapping.id}.fieldPolicyId`, errors);
|
||||
assertReference(mapping.target?.dataProductId, dataProductIds, `mappingContract.${mapping.id}.target.dataProductId`, errors);
|
||||
const product = dataProducts.find((item) => item.id === mapping.target?.dataProductId);
|
||||
@@ -1049,6 +1067,7 @@ function validateDerivation(value, path, errors) {
|
||||
"ordered_rules",
|
||||
"flag_set",
|
||||
"bounded_readings",
|
||||
"bounded_response_lookup",
|
||||
"bounded_string_list",
|
||||
"bounded_named_values",
|
||||
]).has(value.kind)) errors.push(`${path}.kind_invalid`);
|
||||
@@ -1075,6 +1094,89 @@ function validateDerivation(value, path, errors) {
|
||||
if (value.kind === "bounded_named_values") {
|
||||
validateBoundedNamedValuesDerivation(value, path, errors);
|
||||
}
|
||||
if (value.kind === "bounded_response_lookup") {
|
||||
validateBoundedResponseLookupDerivation(value, path, errors);
|
||||
}
|
||||
}
|
||||
|
||||
function validateBoundedResponseLookupDerivation(value, path, errors) {
|
||||
const parameters = isPlainObject(value.parameters) ? value.parameters : {};
|
||||
const allowed = new Set([
|
||||
"responseCapabilityId",
|
||||
"responseCollectionPath",
|
||||
"responseKeyPath",
|
||||
"sourceArrayPath",
|
||||
"sourceKeyPath",
|
||||
"valuePath",
|
||||
"resultMode",
|
||||
"maxResponseItems",
|
||||
"maxSourceKeys",
|
||||
"maxItems",
|
||||
"maxItemLength",
|
||||
]);
|
||||
if (Object.keys(parameters).some((key) => !allowed.has(key))) {
|
||||
errors.push(`${path}.parameters_shape_invalid`);
|
||||
}
|
||||
if (!IDENTIFIER.test(String(parameters.responseCapabilityId || ""))) {
|
||||
errors.push(`${path}.parameters.responseCapabilityId_invalid`);
|
||||
}
|
||||
for (const key of [
|
||||
"responseCollectionPath",
|
||||
"responseKeyPath",
|
||||
"sourceKeyPath",
|
||||
"valuePath",
|
||||
]) {
|
||||
if (!isCanonicalSourcePath(parameters[key])) {
|
||||
errors.push(`${path}.parameters.${key}_must_be_canonical_dot_path`);
|
||||
}
|
||||
}
|
||||
if (SECRET_FIELD_NAME.test(String(parameters.valuePath || ""))) {
|
||||
errors.push(`${path}.parameters.valuePath_secret_field_not_allowed`);
|
||||
}
|
||||
if (
|
||||
parameters.sourceArrayPath !== undefined
|
||||
&& !isCanonicalSourcePath(parameters.sourceArrayPath)
|
||||
) {
|
||||
errors.push(`${path}.parameters.sourceArrayPath_must_be_canonical_dot_path`);
|
||||
}
|
||||
if (!new Set(["first", "list"]).has(parameters.resultMode)) {
|
||||
errors.push(`${path}.parameters.resultMode_invalid`);
|
||||
}
|
||||
if (
|
||||
!Number.isInteger(parameters.maxResponseItems)
|
||||
|| parameters.maxResponseItems < 1
|
||||
|| parameters.maxResponseItems > 5000
|
||||
) {
|
||||
errors.push(`${path}.parameters.maxResponseItems_invalid`);
|
||||
}
|
||||
if (
|
||||
!Number.isInteger(parameters.maxSourceKeys)
|
||||
|| parameters.maxSourceKeys < 1
|
||||
|| parameters.maxSourceKeys > 256
|
||||
) {
|
||||
errors.push(`${path}.parameters.maxSourceKeys_invalid`);
|
||||
}
|
||||
if (
|
||||
!Number.isInteger(parameters.maxItems)
|
||||
|| parameters.maxItems < 1
|
||||
|| parameters.maxItems > 256
|
||||
) {
|
||||
errors.push(`${path}.parameters.maxItems_invalid`);
|
||||
}
|
||||
if (
|
||||
!Number.isInteger(parameters.maxItemLength)
|
||||
|| parameters.maxItemLength < 1
|
||||
|| parameters.maxItemLength > 512
|
||||
) {
|
||||
errors.push(`${path}.parameters.maxItemLength_invalid`);
|
||||
}
|
||||
if (parameters.resultMode === "list") {
|
||||
if (!Array.isArray(value.default) || value.default.length !== 0) {
|
||||
errors.push(`${path}.default_must_be_empty_array_for_list`);
|
||||
}
|
||||
} else if (value.default !== "") {
|
||||
errors.push(`${path}.default_must_be_empty_string_for_first`);
|
||||
}
|
||||
}
|
||||
|
||||
function validateBoundedStringListDerivation(value, path, errors) {
|
||||
|
||||
@@ -31,9 +31,9 @@ const positionsPlan = compileL2ExecutionPlan(
|
||||
);
|
||||
|
||||
assert.equal(positionsPlan.schemaVersion, L2_EXECUTION_PLAN_SCHEMA_VERSION);
|
||||
assert.equal(L2_EXECUTION_PLAN_COMPILER_VERSION, "1.4.0");
|
||||
assert.deepEqual(L2_EXECUTION_PLAN_SUPPORTED_COMPILER_VERSIONS, ["1.1.0", "1.2.0", "1.3.0", "1.4.0"]);
|
||||
assert.equal(positionsPlan.compilerVersion, "1.4.0");
|
||||
assert.equal(L2_EXECUTION_PLAN_COMPILER_VERSION, "1.5.0");
|
||||
assert.deepEqual(L2_EXECUTION_PLAN_SUPPORTED_COMPILER_VERSIONS, ["1.1.0", "1.2.0", "1.3.0", "1.4.0", "1.5.0"]);
|
||||
assert.equal(positionsPlan.compilerVersion, "1.5.0");
|
||||
assert.deepEqual(validateL2ExecutionPlan(positionsPlan), { ok: true, errors: [] });
|
||||
assert.match(positionsPlan.executionPlanDigest, /^sha256:[a-f0-9]{64}$/);
|
||||
assert.match(positionsPlan.artifacts.packageDigest, /^sha256:[a-f0-9]{64}$/);
|
||||
|
||||
@@ -25,6 +25,7 @@ import { geliosProviderPackageV9 } from "../providers/gelios/v9/index.mjs";
|
||||
import { geliosProviderPackageV10 } from "../providers/gelios/v10/index.mjs";
|
||||
import { geliosProviderPackageV11 } from "../providers/gelios/v11/index.mjs";
|
||||
import { geliosProviderPackageV12 } from "../providers/gelios/v12/index.mjs";
|
||||
import { geliosProviderPackageV13 } from "../providers/gelios/v13/index.mjs";
|
||||
import { normalizeDataProductDefinition } from "../../../services/external-data-plane/src/data-product-policy.mjs";
|
||||
|
||||
const expectedFields = [
|
||||
@@ -55,6 +56,7 @@ assert.deepEqual(validateProviderPackage(geliosProviderPackageV9), { ok: true, e
|
||||
assert.deepEqual(validateProviderPackage(geliosProviderPackageV10), { ok: true, errors: [] });
|
||||
assert.deepEqual(validateProviderPackage(geliosProviderPackageV11), { ok: true, errors: [] });
|
||||
assert.deepEqual(validateProviderPackage(geliosProviderPackageV12), { ok: true, errors: [] });
|
||||
assert.deepEqual(validateProviderPackage(geliosProviderPackageV13), { ok: true, errors: [] });
|
||||
assert.equal(geliosProviderPackageV9.id, "gelios.provider.v9");
|
||||
assert.equal(geliosProviderPackageV9.version, "9.0.0");
|
||||
assert.equal(geliosProviderPackageV10.id, "gelios.provider.v10");
|
||||
@@ -62,7 +64,9 @@ assert.equal(geliosProviderPackageV10.version, "10.0.0");
|
||||
assert.equal(geliosProviderPackageV11.id, "gelios.provider.v11");
|
||||
assert.equal(geliosProviderPackageV11.version, "11.0.0");
|
||||
assert.equal(geliosProviderPackageV12.id, "gelios.provider.v12");
|
||||
assert.equal(geliosProviderPackageV12.version, "12.0.0");
|
||||
assert.equal(geliosProviderPackageV12.version, "12.0.1");
|
||||
assert.equal(geliosProviderPackageV13.id, "gelios.provider.v13");
|
||||
assert.equal(geliosProviderPackageV13.version, "13.0.0");
|
||||
assert.equal(geliosProviderPackageV8.id, "gelios.provider.v8");
|
||||
|
||||
const profileProduct = geliosProviderPackageV8.dataProducts.find((product) => product.id === "fleet.units.profile.current.v1");
|
||||
@@ -127,13 +131,56 @@ assert.deepEqual(identityCapability.request.query, {
|
||||
const identityCapabilityV12 = geliosProviderPackageV12.capabilities.find(
|
||||
(capability) => capability.id === "gelios.units.identity.read",
|
||||
);
|
||||
const unitsCapabilityV12 = geliosProviderPackageV12.capabilities.find(
|
||||
(capability) => capability.id === "gelios.units.current.read",
|
||||
);
|
||||
assert.equal(identityCapability.request.response.collectionPaths.includes("items"), false);
|
||||
assert.deepEqual(identityCapabilityV12.request.response.collectionPaths, [
|
||||
"items",
|
||||
...identityCapability.request.response.collectionPaths,
|
||||
]);
|
||||
assert.deepEqual(unitsCapabilityV12.request.response.collectionPaths, [
|
||||
"items",
|
||||
...geliosProviderPackageV11.capabilities.find(
|
||||
(capability) => capability.id === "gelios.units.current.read",
|
||||
).request.response.collectionPaths,
|
||||
]);
|
||||
assert.equal(Object.isFrozen(geliosProviderPackageV12), true);
|
||||
assert.equal(Object.isFrozen(identityCapabilityV12.request.response.collectionPaths), true);
|
||||
assert.equal(Object.isFrozen(unitsCapabilityV12.request.response.collectionPaths), true);
|
||||
const directoryCapabilityV13 = geliosProviderPackageV13.capabilities.find(
|
||||
(capability) => capability.id === "gelios.users.directory.read",
|
||||
);
|
||||
assert.equal(directoryCapabilityV13.request.path, "/api/v1/users");
|
||||
assert.deepEqual(directoryCapabilityV13.request.response.collectionPaths, ["items"]);
|
||||
assert.equal(directoryCapabilityV13.request.response.pagination.maxItems, 5000);
|
||||
const contactsProductV2 = geliosProviderPackageV13.dataProducts.find(
|
||||
(product) => product.id === "fleet.units.contacts.current.v2",
|
||||
);
|
||||
const registeredContactsProductV2 = JSON.parse(await readFile(new URL(
|
||||
"../../../services/external-data-plane/definitions/fleet.units.contacts.current.v2.json",
|
||||
import.meta.url,
|
||||
), "utf8"));
|
||||
assert.deepEqual(contactsProductV2, registeredContactsProductV2);
|
||||
const contactsProfileV2 = geliosProviderPackageV13.collectionProfiles.find(
|
||||
(profile) => profile.id === "gelios.units.contacts.warm.v2",
|
||||
);
|
||||
assert.deepEqual(contactsProfileV2.capabilityIds, [
|
||||
"gelios.units.identity.read",
|
||||
"gelios.users.directory.read",
|
||||
]);
|
||||
const contactsMappingV2 = geliosProviderPackageV13.mappingContracts.find(
|
||||
(mapping) => mapping.id === "gelios.units.to.fleet.units.contacts.current.v2",
|
||||
);
|
||||
assert.equal(
|
||||
contactsMappingV2.derivations.available_user_emails.kind,
|
||||
"bounded_response_lookup",
|
||||
);
|
||||
assert.equal(
|
||||
contactsMappingV2.derivations.provider_creator_email.parameters.resultMode,
|
||||
"first",
|
||||
);
|
||||
assert.equal(Object.isFrozen(geliosProviderPackageV13), true);
|
||||
const identityMapping = geliosProviderPackageV11.mappingContracts.find(
|
||||
(mapping) => mapping.id === "gelios.units.to.fleet.units.identity.current.v1",
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user