import { geliosProviderPackageV7 } from "../v7/package.mjs"; export const GELIOS_PROVIDER_PACKAGE_ID = "gelios.provider.v8"; export const GELIOS_PROVIDER_PACKAGE_VERSION = "8.0.0"; export const GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID = "fleet.units.profile.current.v1"; export const GELIOS_UNIT_PROFILE_DATA_PRODUCT_VERSION = "1.0.0"; export const GELIOS_UNIT_PROFILE_ONTOLOGY_REVISION = "ontology.map.moving_object.v3"; const FIELD_POLICY_ID = "gelios.units.profile.fields.v1"; const COLLECTION_PROFILE_ID = "gelios.units.profile.cold.v1"; const MAPPING_ID = "gelios.units.to.fleet.units.profile.current.v1"; const TEMPLATE_ID = "gelios.units.profile.l2.v1"; const profileFields = Object.freeze([ "corrected_engine_hours_factor", "corrected_mileage_factor", "display_name", "filter_by_satellite_count_enabled", "filter_by_satellite_count_value", "filter_emissions", "hardware_manufacturer_name", "hardware_port", "hardware_type_class", "hardware_type_name", "limit_acceleration", "lost_connection_enabled", "lost_connection_time_value", "maximum_permissible_speed", "maximum_valid_height", "maximum_valid_speed", "mileage_by_ignition", "minimum_movement_speed", "minimum_movement_time", "minimum_parking_time", "minimum_stop_time", "minimum_trip_distance", "minimum_valid_height", "speed_parameter", "trip_detection_type", "unit_type_class", "unit_type_name", "use_odometer", ]); const fieldContracts = Object.freeze({ corrected_engine_hours_factor: optional("number"), corrected_mileage_factor: optional("number"), display_name: { type: "string", required: true }, filter_by_satellite_count_enabled: optional("boolean"), filter_by_satellite_count_value: nonNegative(), filter_emissions: nonNegative(), hardware_manufacturer_name: optional("string"), hardware_port: nonNegative(), hardware_type_class: optional("string"), hardware_type_name: optional("string"), limit_acceleration: nonNegative(), lost_connection_enabled: optional("boolean"), lost_connection_time_value: nonNegative(), maximum_permissible_speed: nonNegative(), maximum_valid_height: optional("number"), maximum_valid_speed: nonNegative(), mileage_by_ignition: optional("boolean"), minimum_movement_speed: nonNegative(), minimum_movement_time: nonNegative(), minimum_parking_time: nonNegative(), minimum_stop_time: nonNegative(), minimum_trip_distance: nonNegative(), minimum_valid_height: optional("number"), speed_parameter: optional("string"), trip_detection_type: optional("string"), unit_type_class: optional("string"), unit_type_name: optional("string"), use_odometer: optional("boolean"), }); const value = structuredClone(geliosProviderPackageV7); value.id = GELIOS_PROVIDER_PACKAGE_ID; value.version = GELIOS_PROVIDER_PACKAGE_VERSION; value.manifest = { ...value.manifest, id: "gelios.provider.manifest.v8", version: GELIOS_PROVIDER_PACKAGE_VERSION, fieldPolicyIds: [...value.manifest.fieldPolicyIds, FIELD_POLICY_ID], collectionProfileIds: [...value.manifest.collectionProfileIds, COLLECTION_PROFILE_ID], dataProductIds: [...value.manifest.dataProductIds, GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID], mappingContractIds: [...value.manifest.mappingContractIds, MAPPING_ID], l2TemplateIds: [...value.manifest.l2TemplateIds, TEMPLATE_ID], }; value.fieldPolicies.push({ id: FIELD_POLICY_ID, version: GELIOS_UNIT_PROFILE_DATA_PRODUCT_VERSION, dataProductId: GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID, targetFields: [...profileFields], unknownSourceFields: "drop", dynamicSourceFields: "drop_until_classified", restrictedSourcePaths: [ "availableToUsers", "commands", "creator", "currentUserAccess", "customFields", "driver", "extraInfo.autocompleteParams", "extraInfo.numberPlate", "extraInfo.vin", "hwDecryptKey", "imei", "lastMsg.address", "lastMsg.params", "lastSensorsVal", "phone", "phone2", "preSetCommandGroup", "sensors", "stationaryLat", "stationaryLon", ], }); value.collectionProfiles.push({ id: COLLECTION_PROFILE_ID, version: GELIOS_PROVIDER_PACKAGE_VERSION, mode: "realtime", schedule: { intervalMs: 6 * 60 * 60 * 1000 }, capabilityIds: ["gelios.units.current.read"], dataProductId: GELIOS_UNIT_PROFILE_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: "exponential_with_jitter" }, }); value.dataProducts.push({ id: GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID, version: GELIOS_UNIT_PROFILE_DATA_PRODUCT_VERSION, ontologyRevision: GELIOS_UNIT_PROFILE_ONTOLOGY_REVISION, deliveryMode: "snapshot+patch", semanticTypes: ["map.moving_object"], fields: [...profileFields], fieldContracts, history: { mode: "none", retentionDays: 1 }, }); value.mappingContracts.push({ schemaVersion: "nodedc.semantic-mapping/v1", id: MAPPING_ID, version: GELIOS_PROVIDER_PACKAGE_VERSION, sourceCapabilityId: "gelios.units.current.read", fieldPolicyId: FIELD_POLICY_ID, target: { dataProductId: GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID, version: GELIOS_UNIT_PROFILE_DATA_PRODUCT_VERSION, ontologyRevision: GELIOS_UNIT_PROFILE_ONTOLOGY_REVISION, semanticType: "map.moving_object", }, derivations: {}, 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: { corrected_engine_hours_factor: numberField(["tripParams.correctedEngineHoursFactor"]), corrected_mileage_factor: numberField(["tripParams.correctedMileageFactor"]), display_name: stringField(["name", "unit_name", "title", "label"], false), filter_by_satellite_count_enabled: booleanField(["tripParams.filterBySatellitesCountIsOn"]), filter_by_satellite_count_value: nonNegativeField(["tripParams.filterBySatellitesCountValue"]), filter_emissions: nonNegativeField(["tripParams.filterEmissions"]), hardware_manufacturer_name: stringField(["hwManufacturer.name"]), hardware_port: nonNegativeField(["hwType.port"]), hardware_type_class: stringField(["hwType.type"]), hardware_type_name: stringField(["hwType.name"]), limit_acceleration: nonNegativeField(["tripParams.limitAcceleration"]), lost_connection_enabled: booleanField(["tripParams.lostConnectionIsOn"]), lost_connection_time_value: nonNegativeField(["tripParams.lostConnectionTimeValue"]), maximum_permissible_speed: nonNegativeField(["tripParams.maximumPermissibleSpeed"]), maximum_valid_height: numberField(["tripParams.maximumValidHeight"]), maximum_valid_speed: nonNegativeField(["tripParams.maximumValidSpeed"]), mileage_by_ignition: booleanField(["tripParams.mileageByIgnition"]), minimum_movement_speed: nonNegativeField(["tripParams.minimumMovementSpeed"]), minimum_movement_time: nonNegativeField(["tripParams.minimumMovementTime"]), minimum_parking_time: nonNegativeField(["tripParams.minimumParkingTime"]), minimum_stop_time: nonNegativeField(["tripParams.minimumTimeStop"]), minimum_trip_distance: nonNegativeField(["tripParams.minimumTripDistance"]), minimum_valid_height: numberField(["tripParams.minimumValidHeight"]), speed_parameter: stringField(["tripParams.speedParam"]), trip_detection_type: stringField(["tripParams.tripDetectionType.name"]), unit_type_class: stringField(["unitType.type"]), unit_type_name: stringField(["unitType.name"]), use_odometer: booleanField(["tripParams.useOdometer"]), }, }, }); const positionsTemplate = value.l2Templates.find((template) => template.id === "gelios.positions.current.l2.v7"); if (!positionsTemplate) throw new Error("gelios_v8_positions_template_missing"); value.l2Templates.push({ ...structuredClone(positionsTemplate), 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: "gelios.units.current.read" }, { id: "provider.extract-units", kind: "extract_items", capabilityId: "gelios.units.current.read" }, { id: "ontology.map", kind: "semantic_mapping", mappingContractId: MAPPING_ID }, { id: "data-product.publish", kind: "data_product_publish", dataProductId: GELIOS_UNIT_PROFILE_DATA_PRODUCT_ID, nodeType: "n8n-nodes-ndc.ndcDataProductPublish", }, ], }); export const geliosProviderPackageV8 = deepFreeze(value); function optional(type) { return { type, required: false }; } function nonNegative() { return { type: "number", required: false, minimum: 0 }; } function stringField(paths, omitIfMissing = true) { return { strategy: "first_non_empty", paths, coerce: "string", ...(omitIfMissing ? { omitIfMissing: true } : {}), }; } function numberField(paths) { return { strategy: "first_non_empty", paths, coerce: "number", omitIfMissing: true }; } function nonNegativeField(paths) { return { strategy: "first_non_empty", paths, coerce: "number", minimum: 0, omitIfMissing: true, omitIfInvalid: true, }; } function booleanField(paths) { return { strategy: "first_non_empty", paths, coerce: "boolean", omitIfMissing: true }; } 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; }