feat(provider): publish full unit identity product
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
export {
|
||||
GELIOS_PROVIDER_PACKAGE_ID,
|
||||
GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
GELIOS_UNIT_IDENTITY_DATA_PRODUCT_ID,
|
||||
GELIOS_UNIT_IDENTITY_DATA_PRODUCT_VERSION,
|
||||
GELIOS_UNIT_IDENTITY_ONTOLOGY_REVISION,
|
||||
geliosProviderPackageV11,
|
||||
} from "./package.mjs";
|
||||
export { geliosTelemetryFieldRegistryV4 } from "./telemetry-field-registry.mjs";
|
||||
export { geliosCapabilityCatalogV3 } from "../capability-catalog-v3.mjs";
|
||||
@@ -0,0 +1,309 @@
|
||||
import { geliosProviderPackageV10 } from "../v10/package.mjs";
|
||||
|
||||
export const GELIOS_PROVIDER_PACKAGE_ID = "gelios.provider.v11";
|
||||
export const GELIOS_PROVIDER_PACKAGE_VERSION = "11.0.0";
|
||||
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 CAPABILITY_ID = "gelios.units.identity.read";
|
||||
const FIELD_POLICY_ID = "gelios.units.identity.fields.v1";
|
||||
const COLLECTION_PROFILE_ID = "gelios.units.identity.warm.v1";
|
||||
const MAPPING_ID = "gelios.units.to.fleet.units.identity.current.v1";
|
||||
const TEMPLATE_ID = "gelios.units.identity.l2.v1";
|
||||
|
||||
const identityFields = Object.freeze([
|
||||
"asset_brand",
|
||||
"asset_color",
|
||||
"asset_model",
|
||||
"asset_number_plate",
|
||||
"asset_vin",
|
||||
"asset_year",
|
||||
"assigned_driver_name",
|
||||
"assigned_driver_phone",
|
||||
"available_user_ids",
|
||||
"available_user_logins",
|
||||
"custom_fields",
|
||||
"device_imei",
|
||||
"device_phone_primary",
|
||||
"device_phone_secondary",
|
||||
"display_name",
|
||||
"hardware_manufacturer_id",
|
||||
"hardware_manufacturer_name",
|
||||
"hardware_port",
|
||||
"hardware_type_class",
|
||||
"hardware_type_id",
|
||||
"hardware_type_name",
|
||||
"provider_creator_id",
|
||||
"provider_creator_login",
|
||||
"provider_unit_id",
|
||||
"unit_type_class",
|
||||
"unit_type_id",
|
||||
"unit_type_name",
|
||||
]);
|
||||
|
||||
const value = structuredClone(geliosProviderPackageV10);
|
||||
const baseUnitsCapability = value.capabilities.find(
|
||||
(capability) => capability.id === "gelios.units.current.read",
|
||||
);
|
||||
if (!baseUnitsCapability) throw new Error("gelios_v11_units_capability_missing");
|
||||
const profileTemplate = value.l2Templates.find(
|
||||
(template) => template.id === "gelios.units.profile.l2.v1",
|
||||
);
|
||||
if (!profileTemplate) throw new Error("gelios_v11_profile_template_missing");
|
||||
|
||||
value.id = GELIOS_PROVIDER_PACKAGE_ID;
|
||||
value.version = GELIOS_PROVIDER_PACKAGE_VERSION;
|
||||
value.manifest = {
|
||||
...value.manifest,
|
||||
id: "gelios.provider.manifest.v11",
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
capabilityIds: [...value.manifest.capabilityIds, CAPABILITY_ID],
|
||||
fieldPolicyIds: [...value.manifest.fieldPolicyIds, FIELD_POLICY_ID],
|
||||
collectionProfileIds: [...value.manifest.collectionProfileIds, COLLECTION_PROFILE_ID],
|
||||
dataProductIds: [...value.manifest.dataProductIds, GELIOS_UNIT_IDENTITY_DATA_PRODUCT_ID],
|
||||
mappingContractIds: [...value.manifest.mappingContractIds, MAPPING_ID],
|
||||
l2TemplateIds: [...value.manifest.l2TemplateIds, TEMPLATE_ID],
|
||||
};
|
||||
|
||||
value.capabilities.push({
|
||||
...structuredClone(baseUnitsCapability),
|
||||
id: CAPABILITY_ID,
|
||||
request: {
|
||||
...structuredClone(baseUnitsCapability.request),
|
||||
query: {
|
||||
inclextra: "true",
|
||||
inclcstmflds: "true",
|
||||
incldrvrs: "true",
|
||||
inclusersav: "true",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
value.fieldPolicies.push({
|
||||
id: FIELD_POLICY_ID,
|
||||
version: GELIOS_UNIT_IDENTITY_DATA_PRODUCT_VERSION,
|
||||
dataProductId: GELIOS_UNIT_IDENTITY_DATA_PRODUCT_ID,
|
||||
targetFields: [...identityFields],
|
||||
unknownSourceFields: "drop",
|
||||
dynamicSourceFields: "drop_until_classified",
|
||||
restrictedSourcePaths: [
|
||||
"commands",
|
||||
"currentUserAccess",
|
||||
"extraInfo.autocompleteParams",
|
||||
"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: [CAPABILITY_ID],
|
||||
dataProductId: GELIOS_UNIT_IDENTITY_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_IDENTITY_DATA_PRODUCT_ID,
|
||||
version: GELIOS_UNIT_IDENTITY_DATA_PRODUCT_VERSION,
|
||||
ontologyRevision: GELIOS_UNIT_IDENTITY_ONTOLOGY_REVISION,
|
||||
deliveryMode: "snapshot+patch",
|
||||
semanticTypes: ["map.moving_object"],
|
||||
fields: [...identityFields],
|
||||
fieldContracts: {
|
||||
asset_brand: optional("string"),
|
||||
asset_color: optional("string"),
|
||||
asset_model: optional("string"),
|
||||
asset_number_plate: optional("string"),
|
||||
asset_vin: optional("string"),
|
||||
asset_year: nonNegative(),
|
||||
assigned_driver_name: optional("string"),
|
||||
assigned_driver_phone: optional("string"),
|
||||
available_user_ids: optional("string_array"),
|
||||
available_user_logins: optional("string_array"),
|
||||
custom_fields: optional("string_array"),
|
||||
device_imei: optional("string"),
|
||||
device_phone_primary: optional("string"),
|
||||
device_phone_secondary: optional("string"),
|
||||
display_name: { type: "string", required: true },
|
||||
hardware_manufacturer_id: optional("string"),
|
||||
hardware_manufacturer_name: optional("string"),
|
||||
hardware_port: nonNegative(),
|
||||
hardware_type_class: optional("string"),
|
||||
hardware_type_id: optional("string"),
|
||||
hardware_type_name: optional("string"),
|
||||
provider_creator_id: optional("string"),
|
||||
provider_creator_login: optional("string"),
|
||||
provider_unit_id: { type: "string", required: true },
|
||||
unit_type_class: optional("string"),
|
||||
unit_type_id: optional("string"),
|
||||
unit_type_name: optional("string"),
|
||||
},
|
||||
history: { mode: "none", retentionDays: 1 },
|
||||
});
|
||||
|
||||
value.mappingContracts.push({
|
||||
schemaVersion: "nodedc.semantic-mapping/v1",
|
||||
id: MAPPING_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
sourceCapabilityId: CAPABILITY_ID,
|
||||
fieldPolicyId: FIELD_POLICY_ID,
|
||||
target: {
|
||||
dataProductId: GELIOS_UNIT_IDENTITY_DATA_PRODUCT_ID,
|
||||
version: GELIOS_UNIT_IDENTITY_DATA_PRODUCT_VERSION,
|
||||
ontologyRevision: GELIOS_UNIT_IDENTITY_ONTOLOGY_REVISION,
|
||||
semanticType: "map.moving_object",
|
||||
},
|
||||
derivations: {
|
||||
available_user_ids: boundedStringList("availableToUsers", "id", 256),
|
||||
available_user_logins: boundedStringList("availableToUsers", "login", 256),
|
||||
custom_fields: {
|
||||
kind: "bounded_named_values",
|
||||
rules: ["array.named_values"],
|
||||
default: [],
|
||||
parameters: {
|
||||
arrayPath: "customFields",
|
||||
namePath: "name",
|
||||
valuePath: "value",
|
||||
maxItems: 256,
|
||||
maxItemLength: 512,
|
||||
},
|
||||
},
|
||||
},
|
||||
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: {
|
||||
asset_brand: stringField(["extraInfo.brand"]),
|
||||
asset_color: stringField(["extraInfo.color"]),
|
||||
asset_model: stringField(["extraInfo.model"]),
|
||||
asset_number_plate: stringField(["extraInfo.numberPlate"]),
|
||||
asset_vin: stringField(["extraInfo.vin"]),
|
||||
asset_year: nonNegativeField(["extraInfo.year"]),
|
||||
assigned_driver_name: stringField(["driver.name"]),
|
||||
assigned_driver_phone: stringField(["driver.phone"]),
|
||||
available_user_ids: { derive: "available_user_ids" },
|
||||
available_user_logins: { derive: "available_user_logins" },
|
||||
custom_fields: { derive: "custom_fields" },
|
||||
device_imei: stringField(["imei"]),
|
||||
device_phone_primary: stringField(["phone"]),
|
||||
device_phone_secondary: stringField(["phone2"]),
|
||||
display_name: stringField(["name", "unit_name", "title", "label"], false),
|
||||
hardware_manufacturer_id: stringField(["hwManufacturer.id"]),
|
||||
hardware_manufacturer_name: stringField(["hwManufacturer.name"]),
|
||||
hardware_port: nonNegativeField(["hwType.port"]),
|
||||
hardware_type_class: stringField(["hwType.type"]),
|
||||
hardware_type_id: stringField(["hwType.id"]),
|
||||
hardware_type_name: stringField(["hwType.name"]),
|
||||
provider_creator_id: stringField(["creator.id"]),
|
||||
provider_creator_login: stringField(["creator.login"]),
|
||||
provider_unit_id: stringField(["id", "unit_id", "unitId"], false),
|
||||
unit_type_class: stringField(["unitType.type"]),
|
||||
unit_type_id: stringField(["unitType.id"]),
|
||||
unit_type_name: stringField(["unitType.name"]),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
value.l2Templates.push({
|
||||
...structuredClone(profileTemplate),
|
||||
id: TEMPLATE_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
steps: [
|
||||
{ id: "collection.trigger", kind: "collection_trigger", collectionProfileDriven: true },
|
||||
{ id: "provider.fetch-identity", kind: "provider_request", capabilityId: CAPABILITY_ID },
|
||||
{ id: "provider.extract-units", kind: "extract_items", capabilityId: CAPABILITY_ID },
|
||||
{ id: "ontology.map", kind: "semantic_mapping", mappingContractId: MAPPING_ID },
|
||||
{
|
||||
id: "data-product.publish",
|
||||
kind: "data_product_publish",
|
||||
dataProductId: GELIOS_UNIT_IDENTITY_DATA_PRODUCT_ID,
|
||||
nodeType: "n8n-nodes-ndc.ndcDataProductPublish",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const geliosProviderPackageV11 = 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 nonNegativeField(paths) {
|
||||
return {
|
||||
strategy: "first_non_empty",
|
||||
paths,
|
||||
coerce: "number",
|
||||
minimum: 0,
|
||||
omitIfMissing: true,
|
||||
omitIfInvalid: true,
|
||||
};
|
||||
}
|
||||
|
||||
function boundedStringList(arrayPath, valuePath, maxItems) {
|
||||
return {
|
||||
kind: "bounded_string_list",
|
||||
rules: ["array.string_values"],
|
||||
default: [],
|
||||
parameters: {
|
||||
arrayPath,
|
||||
valuePath,
|
||||
maxItems,
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { geliosTelemetryFieldRegistryV3 } from "../v10/telemetry-field-registry.mjs";
|
||||
import {
|
||||
GELIOS_PROVIDER_PACKAGE_ID,
|
||||
GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
} from "./package.mjs";
|
||||
|
||||
const value = structuredClone(geliosTelemetryFieldRegistryV3);
|
||||
value.providerPackage = {
|
||||
id: GELIOS_PROVIDER_PACKAGE_ID,
|
||||
version: GELIOS_PROVIDER_PACKAGE_VERSION,
|
||||
};
|
||||
|
||||
export const geliosTelemetryFieldRegistryV4 = deepFreeze(value);
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user