import { geliosProviderPackageV6 } from "../v6/package.mjs"; export const GELIOS_PROVIDER_PACKAGE_ID = "gelios.provider.v7"; export const GELIOS_PROVIDER_PACKAGE_VERSION = "7.0.0"; export const GELIOS_POSITIONS_DATA_PRODUCT_ID = "fleet.positions.current.v5"; export const GELIOS_POSITIONS_DATA_PRODUCT_VERSION = "5.0.0"; export const GELIOS_POSITIONS_ONTOLOGY_REVISION = "ontology.map.moving_object.v3"; export const GELIOS_UNIT_SOURCE_ID_PREFIX = "gelios-unit-"; const PREVIOUS_PRODUCT_ID = "fleet.positions.current.v4"; const PREVIOUS_FIELD_POLICY_ID = "gelios.positions.current.fields.v4"; const PREVIOUS_REALTIME_PROFILE_ID = "gelios.positions.current.realtime.v5"; const PREVIOUS_MANUAL_PROFILE_ID = "gelios.positions.current.manual.v5"; const PREVIOUS_MAPPING_ID = "gelios.units.to.fleet.positions.current.v5"; const PREVIOUS_TEMPLATE_ID = "gelios.positions.current.l2.v5"; const FIELD_POLICY_ID = "gelios.positions.current.fields.v5"; const REALTIME_PROFILE_ID = "gelios.positions.current.realtime.v7"; const MANUAL_PROFILE_ID = "gelios.positions.current.manual.v7"; const MAPPING_ID = "gelios.units.to.fleet.positions.current.v7"; const TEMPLATE_ID = "gelios.positions.current.l2.v7"; const positionFields = Object.freeze([ "course_degrees", "display_name", "elevation_meters", "engine_hours", "geometry", "hdop", "horizontal_accuracy_meters", "mileage_km", "movement_state", "object_kind", "position_source", "satellite_count", "sensor_readings", "signal_state", "speed_kph", ]); const value = structuredClone(geliosProviderPackageV6); const previousMapping = value.mappingContracts.find((mapping) => mapping.id === PREVIOUS_MAPPING_ID); if (!previousMapping) throw new Error("gelios_v7_previous_mapping_missing"); value.id = GELIOS_PROVIDER_PACKAGE_ID; value.version = GELIOS_PROVIDER_PACKAGE_VERSION; value.manifest = { ...value.manifest, id: "gelios.provider.manifest.v7", version: GELIOS_PROVIDER_PACKAGE_VERSION, fieldPolicyIds: replaceOne(value.manifest.fieldPolicyIds, PREVIOUS_FIELD_POLICY_ID, FIELD_POLICY_ID), collectionProfileIds: replaceOne( replaceOne(value.manifest.collectionProfileIds, PREVIOUS_REALTIME_PROFILE_ID, REALTIME_PROFILE_ID), PREVIOUS_MANUAL_PROFILE_ID, MANUAL_PROFILE_ID, ), dataProductIds: replaceOne(value.manifest.dataProductIds, PREVIOUS_PRODUCT_ID, GELIOS_POSITIONS_DATA_PRODUCT_ID), mappingContractIds: replaceOne(value.manifest.mappingContractIds, PREVIOUS_MAPPING_ID, MAPPING_ID), l2TemplateIds: replaceOne(value.manifest.l2TemplateIds, PREVIOUS_TEMPLATE_ID, TEMPLATE_ID), }; value.capabilities = value.capabilities.map((capability) => ( capability.id === "gelios.units.current.read" ? { ...capability, request: { ...capability.request, query: { ...capability.request.query, incltrip: "true", inclcntrs: "true", inclsnsrs: "true", incllsv: "true", }, }, } : capability )); value.fieldPolicies = value.fieldPolicies.map((policy) => ( policy.id === PREVIOUS_FIELD_POLICY_ID ? { ...policy, id: FIELD_POLICY_ID, version: GELIOS_POSITIONS_DATA_PRODUCT_VERSION, dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID, targetFields: [...positionFields], restrictedSourcePaths: policy.restrictedSourcePaths .filter((path) => path !== "sensors") .concat(["sensors.conversionTable"]), } : policy )); value.collectionProfiles = value.collectionProfiles.map((profile) => { if (profile.dataProductId !== PREVIOUS_PRODUCT_ID) return profile; return { ...profile, id: profile.mode === "realtime" ? REALTIME_PROFILE_ID : MANUAL_PROFILE_ID, version: GELIOS_PROVIDER_PACKAGE_VERSION, dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID, mappingContractId: MAPPING_ID, fieldPolicyId: FIELD_POLICY_ID, l2TemplateId: TEMPLATE_ID, }; }); value.dataProducts = value.dataProducts.map((product) => ( product.id === PREVIOUS_PRODUCT_ID ? { id: GELIOS_POSITIONS_DATA_PRODUCT_ID, version: GELIOS_POSITIONS_DATA_PRODUCT_VERSION, ontologyRevision: GELIOS_POSITIONS_ONTOLOGY_REVISION, deliveryMode: "snapshot+patch", semanticTypes: ["map.moving_object"], fields: [...positionFields], fieldContracts: { course_degrees: { type: "number", required: false, minimum: 0, maximum: 360 }, display_name: { type: "string", required: true }, elevation_meters: { type: "number", required: false }, engine_hours: { type: "number", required: false, minimum: 0 }, geometry: { type: "point", required: false }, hdop: { type: "number", required: false, minimum: 0 }, horizontal_accuracy_meters: { type: "number", required: false, minimum: 0 }, mileage_km: { type: "number", required: false, minimum: 0 }, movement_state: { type: "string", required: true, enum: ["moving", "stopped"] }, object_kind: { type: "string", required: true }, position_source: { type: "string", required: true }, satellite_count: { type: "number", required: false, minimum: 0 }, sensor_readings: { type: "telemetry_readings", required: false }, signal_state: { type: "string", required: true, enum: ["active", "inactive"] }, speed_kph: { type: "number", required: false, minimum: 0 }, }, history: { mode: "sampled", intervalMs: 60_000, strategy: "latest-per-entity-per-bucket", retentionDays: 90 }, } : product )); value.mappingContracts = value.mappingContracts.map((mapping) => { if (mapping.id !== PREVIOUS_MAPPING_ID) return mapping; return { ...mapping, id: MAPPING_ID, version: GELIOS_PROVIDER_PACKAGE_VERSION, fieldPolicyId: FIELD_POLICY_ID, target: { ...mapping.target, dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID, version: GELIOS_POSITIONS_DATA_PRODUCT_VERSION, ontologyRevision: GELIOS_POSITIONS_ONTOLOGY_REVISION, }, derivations: { ...mapping.derivations, sensor_readings: { kind: "bounded_readings", rules: ["last_sensor_values.normalized"], default: [], parameters: { maxReadings: 128 }, }, }, fact: { ...mapping.fact, attributes: { ...mapping.fact.attributes, engine_hours: { strategy: "first_non_empty", paths: ["counters.engineHours.value"], coerce: "number", minimum: 0, omitIfMissing: true, omitIfInvalid: true, }, mileage_km: { strategy: "first_non_empty", paths: ["counters.mileage.value"], coerce: "number", minimum: 0, omitIfMissing: true, omitIfInvalid: true, }, sensor_readings: { derive: "sensor_readings" }, }, }, }; }); value.l2Templates = value.l2Templates.map((template) => { if (template.id !== PREVIOUS_TEMPLATE_ID) return template; return { ...template, id: TEMPLATE_ID, version: GELIOS_PROVIDER_PACKAGE_VERSION, steps: template.steps.map((step) => { if (step.kind === "semantic_mapping") return { ...step, mappingContractId: MAPPING_ID }; if (step.kind === "data_product_publish") return { ...step, dataProductId: GELIOS_POSITIONS_DATA_PRODUCT_ID }; return step; }), }; }); export const geliosProviderPackageV7 = deepFreeze(value); function replaceOne(items, previous, next) { if (!Array.isArray(items) || items.filter((item) => item === previous).length !== 1) { throw new Error(`gelios_v7_manifest_predecessor_invalid:${previous}`); } return items.map((item) => item === previous ? next : item); } 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; }