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; }