215 lines
7.8 KiB
JavaScript
215 lines
7.8 KiB
JavaScript
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;
|
|
}
|