From 8559dce180592b7a58113a409afd39843872b29c Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 09:30:51 +0000 Subject: [PATCH 1/5] Regenerate the TypeScript types from the code npm run tsc on rc changes 23 committed type files and writes one new one, callbackUrl.d.ts, so the types published with each package match what the code now offers. Members tsc leaves out of a subclass, such as CloudRequestEngine.isCacheable, are still declared on the base class with the same type. --- .../deviceDetectionCloudPipelineBuilder.d.ts | 6 +- .../types/deviceDetectionOnPremise.d.ts | 3 +- .../types/index.d.ts | 8 -- .../types/lib/testConstants.d.ts | 8 -- .../ipIntelligenceCloudPipelineBuilder.d.ts | 6 +- .../types/ipIntelligenceOnPremise.d.ts | 5 +- ...pIntelligenceOnPremisePipelineBuilder.d.ts | 2 +- .../types/index.d.ts | 13 --- .../types/lib/testConstants.d.ts | 13 --- location/types/geoLocationCloud.d.ts | 4 +- .../types/cloudRequestEngine.d.ts | 19 +--- .../types/callbackUrl.d.ts | 32 +++++++ .../types/elementDataDictionary.d.ts | 9 -- .../types/evidence.d.ts | 2 +- .../types/flowElement.d.ts | 9 +- .../types/javascriptbuilder.d.ts | 23 ++--- .../types/jsonbundler.d.ts | 9 ++ .../types/pipeline.d.ts | 2 +- .../types/pipelineBuilder.d.ts | 15 ++-- .../types/aspectDataDictionary.d.ts | 8 -- .../types/dataFile.d.ts | 1 + .../types/dataFileUpdateService.d.ts | 90 ++++++++++++++----- .../types/engine.d.ts | 19 ++-- .../types/index.d.ts | 2 + 24 files changed, 170 insertions(+), 138 deletions(-) create mode 100644 pipeline/fiftyone.pipeline.core/types/callbackUrl.d.ts diff --git a/device-detection/fiftyone.devicedetection.cloud/types/deviceDetectionCloudPipelineBuilder.d.ts b/device-detection/fiftyone.devicedetection.cloud/types/deviceDetectionCloudPipelineBuilder.d.ts index bddcc16d..4f4e72bf 100644 --- a/device-detection/fiftyone.devicedetection.cloud/types/deviceDetectionCloudPipelineBuilder.d.ts +++ b/device-detection/fiftyone.devicedetection.cloud/types/deviceDetectionCloudPipelineBuilder.d.ts @@ -12,15 +12,15 @@ declare class DeviceDetectionCloudPipelineBuilder extends DeviceDetectionCloudPi * @param {object} options the options for the pipeline builder * @param {string} options.licenceKeys license key(s) used by the * data file update service. A key can be obtained from the - * 51Degrees website: https://51degrees.com/pricing. + * 51Degrees website: https://51degrees.com/pricing?utm_source=code&utm_medium=comment&utm_campaign=51degrees-node&utm_content=fiftyone.devicedetection.cloud-devicedetectioncloudpipelinebuilder.js&utm_term=constructor. * This parameter MUST be set when using a data file. * If you do not wish to use a key then you can specify * an empty string, but this will cause automatic updates * to be disabled. - * @param {string} options.resourceKey resourceKey * @param {Array|string} options.requestedProperties the fully * qualified names of the properties to ask the cloud service for, such * as device.ismobile. Required with a license key and no resource key. + * @param {string} options.resourceKey resourceKey * @param {number} options.cacheSize size of the default cache * (includes cache if set). * @param {string} options.cloudEndPoint Choose a non default endpoint @@ -36,8 +36,8 @@ declare class DeviceDetectionCloudPipelineBuilder extends DeviceDetectionCloudPi */ constructor({ licenceKeys, resourceKey, requestedProperties, cacheSize, cloudEndPoint, cloudRequestOrigin }: { licenceKeys: string; - resourceKey: string; requestedProperties: Array | string; + resourceKey: string; cacheSize: number; cloudEndPoint: string; cloudRequestOrigin: string; diff --git a/device-detection/fiftyone.devicedetection.onpremise/types/deviceDetectionOnPremise.d.ts b/device-detection/fiftyone.devicedetection.onpremise/types/deviceDetectionOnPremise.d.ts index 1de6cead..808c56a1 100644 --- a/device-detection/fiftyone.devicedetection.onpremise/types/deviceDetectionOnPremise.d.ts +++ b/device-detection/fiftyone.devicedetection.onpremise/types/deviceDetectionOnPremise.d.ts @@ -69,7 +69,8 @@ declare class DeviceDetectionOnPremise extends DeviceDetectionOnPremise_base { * @param {string} options.tempDataDir The directory to use for the * temporary data copy if 'createTempDataCopy' is set to true. * @param {boolean} options.updateOnStart whether to download / update - * the datafile on initialisation + * the datafile on initialisation. If there is no file at dataFilePath it + * is downloaded, and processing fails if the download does not work. */ constructor({ dataFilePath, autoUpdate, cache, dataUpdateUrl, dataUpdateVerifyMd5, dataUpdateUseUrlFormatter, restrictedProperties, licenceKeys, download, performanceProfile, reuseTempFile, updateMatchedUserAgent, maxMatchedUserAgentLength, drift, difference, concurrency, allowUnmatched, fileSystemWatcher, pollingInterval, updateTimeMaximumRandomisation, createTempDataCopy, tempDataDir, updateOnStart }: { dataFilePath: string; diff --git a/device-detection/fiftyone.devicedetection.shared/types/index.d.ts b/device-detection/fiftyone.devicedetection.shared/types/index.d.ts index ab18f82a..a385f904 100644 --- a/device-detection/fiftyone.devicedetection.shared/types/index.d.ts +++ b/device-detection/fiftyone.devicedetection.shared/types/index.d.ts @@ -22,16 +22,8 @@ export let testConstants: { hardwareResourceKeyEnvVar: string; browserResourceKeyEnvVar: string; noSetHeaderResourceKeyEnvVar: string; - /** - * @deprecated No test reads a licence key under this name. The licence - * key is read from the _51DEGREES_LICENSE_KEY environment variable. - */ licenseKeyEnvVar: string; }; - /** - * @deprecated The name each of envVars replaced. An old name is read only - * when the name that replaced it is unset or empty. Use envVars. - */ legacyEnvVars: { _51DEGREES_RESOURCE_KEY: string; _51DEGREES_RESOURCE_KEY_SUPER: string; diff --git a/device-detection/fiftyone.devicedetection.shared/types/lib/testConstants.d.ts b/device-detection/fiftyone.devicedetection.shared/types/lib/testConstants.d.ts index 2b20d556..f893efa6 100644 --- a/device-detection/fiftyone.devicedetection.shared/types/lib/testConstants.d.ts +++ b/device-detection/fiftyone.devicedetection.shared/types/lib/testConstants.d.ts @@ -5,16 +5,8 @@ export namespace envVars { let hardwareResourceKeyEnvVar: string; let browserResourceKeyEnvVar: string; let noSetHeaderResourceKeyEnvVar: string; - /** - * @deprecated No test reads a licence key under this name. The licence - * key is read from the _51DEGREES_LICENSE_KEY environment variable. - */ let licenseKeyEnvVar: string; } -/** - * @deprecated The name each of envVars replaced. An old name is read only - * when the name that replaced it is unset or empty. Use envVars. - */ export namespace legacyEnvVars { let _51DEGREES_RESOURCE_KEY: string; let _51DEGREES_RESOURCE_KEY_SUPER: string; diff --git a/ip-intelligence/fiftyone.ipintelligence.cloud/types/ipIntelligenceCloudPipelineBuilder.d.ts b/ip-intelligence/fiftyone.ipintelligence.cloud/types/ipIntelligenceCloudPipelineBuilder.d.ts index f592a78f..ea5a8571 100644 --- a/ip-intelligence/fiftyone.ipintelligence.cloud/types/ipIntelligenceCloudPipelineBuilder.d.ts +++ b/ip-intelligence/fiftyone.ipintelligence.cloud/types/ipIntelligenceCloudPipelineBuilder.d.ts @@ -12,15 +12,15 @@ declare class IpIntelligenceCloudPipelineBuilder extends IpIntelligenceCloudPipe * @param {object} options the options for the pipeline builder * @param {string} options.licenceKeys license key(s) used by the * data file update service. A key can be obtained from the - * 51Degrees website: https://51degrees.com/pricing. + * 51Degrees website: https://51degrees.com/pricing?utm_source=code&utm_medium=comment&utm_campaign=51degrees-node&utm_content=fiftyone.ipintelligence.cloud-ipintelligencecloudpipelinebuilder.js&utm_term=constructor. * This parameter MUST be set when using a data file. * If you do not wish to use a key then you can specify * an empty string, but this will cause automatic updates * to be disabled. - * @param {string} options.resourceKey resourceKey * @param {Array|string} options.requestedProperties the fully * qualified names of the properties to ask the cloud service for, such * as ip.registeredcountry. Required with a license key and no resource key. + * @param {string} options.resourceKey resourceKey * @param {number} options.cacheSize size of the default cache * (includes cache if set). * @param {string} options.cloudEndPoint Choose a non default endpoint @@ -30,8 +30,8 @@ declare class IpIntelligenceCloudPipelineBuilder extends IpIntelligenceCloudPipe */ constructor({ licenceKeys, resourceKey, requestedProperties, cacheSize, cloudEndPoint, cloudRequestOrigin }: { licenceKeys: string; - resourceKey: string; requestedProperties: Array | string; + resourceKey: string; cacheSize: number; cloudEndPoint: string; cloudRequestOrigin: string; diff --git a/ip-intelligence/fiftyone.ipintelligence.onpremise/types/ipIntelligenceOnPremise.d.ts b/ip-intelligence/fiftyone.ipintelligence.onpremise/types/ipIntelligenceOnPremise.d.ts index 6d43e791..e2f34eb7 100644 --- a/ip-intelligence/fiftyone.ipintelligence.onpremise/types/ipIntelligenceOnPremise.d.ts +++ b/ip-intelligence/fiftyone.ipintelligence.onpremise/types/ipIntelligenceOnPremise.d.ts @@ -28,7 +28,7 @@ declare class IpIntelligenceOnPremise extends IpIntelligenceOnPremise_base { * will be restricted to * @param {string} options.licenceKeys license key(s) used by the * data file update service. A key can be obtained from the - * 51Degrees website: https://51degrees.com/pricing. + * 51Degrees website: https://51degrees.com/pricing?utm_source=code&utm_medium=comment&utm_campaign=51degrees-node&utm_content=fiftyone.ipintelligence.onpremise-ipintelligenceonpremise.js&utm_term=constructor. * If you do not wish to use a key then you can specify * an empty string, but this will cause automatic updates to * be disabled. @@ -51,7 +51,8 @@ declare class IpIntelligenceOnPremise extends IpIntelligenceOnPremise_base { * @param {string} options.tempDataDir The directory to use for the * temporary data copy if 'createTempDataCopy' is set to true. * @param {boolean} options.updateOnStart whether to download / update - * the datafile on initialisation + * the datafile on initialisation. If there is no file at dataFilePath it + * is downloaded, and processing fails if the download does not work. */ constructor({ dataFilePath, autoUpdate, cache, dataUpdateUrl, dataUpdateVerifyMd5, dataUpdateUseUrlFormatter, restrictedProperties, licenceKeys, download, performanceProfile, reuseTempFile, concurrency, fileSystemWatcher, pollingInterval, updateTimeMaximumRandomisation, createTempDataCopy, tempDataDir, updateOnStart }: { dataFilePath: string; diff --git a/ip-intelligence/fiftyone.ipintelligence.onpremise/types/ipIntelligenceOnPremisePipelineBuilder.d.ts b/ip-intelligence/fiftyone.ipintelligence.onpremise/types/ipIntelligenceOnPremisePipelineBuilder.d.ts index ec6bf9fa..b84322fd 100644 --- a/ip-intelligence/fiftyone.ipintelligence.onpremise/types/ipIntelligenceOnPremisePipelineBuilder.d.ts +++ b/ip-intelligence/fiftyone.ipintelligence.onpremise/types/ipIntelligenceOnPremisePipelineBuilder.d.ts @@ -12,7 +12,7 @@ declare class IpIntelligenceOnPremisePipelineBuilder extends IpIntelligenceOnPre * @param {object} options the options for the pipeline builder * @param {string} [options.licenceKeys] license key(s) used by the * data file update service. A key can be obtained from the - * 51Degrees website: https://51degrees.com/pricing. + * 51Degrees website: https://51degrees.com/pricing?utm_source=code&utm_medium=comment&utm_campaign=51degrees-node&utm_content=fiftyone.ipintelligence.onpremise-ipintelligenceonpremisepipelinebuilder.js&utm_term=constructor. * This parameter MUST be set when using a data file. * If you do not wish to use a key then you can specify * an empty string, but this will cause automatic updates diff --git a/ip-intelligence/fiftyone.ipintelligence.shared/types/index.d.ts b/ip-intelligence/fiftyone.ipintelligence.shared/types/index.d.ts index d29799b0..5597866b 100644 --- a/ip-intelligence/fiftyone.ipintelligence.shared/types/index.d.ts +++ b/ip-intelligence/fiftyone.ipintelligence.shared/types/index.d.ts @@ -17,21 +17,8 @@ export let errorMessages: { export let testConstants: { envVars: { superResourceKeyVariable: string; - /** - * @deprecated The name the variable had before, which is read only - * when the variable superResourceKeyVariable names is unset or empty. - * Use superResourceKeyVariable. - */ superResourceKeyEnvVar: string; - /** - * @deprecated No test reads a resource key under this name. Use - * superResourceKeyVariable. - */ ipiResourceKeyEnvVar: string; - /** - * @deprecated No test reads a licence key under this name. The licence - * key is read from the _51DEGREES_LICENSE_KEY environment variable. - */ licenseKeyEnvVar: string; }; ipAddresses: { diff --git a/ip-intelligence/fiftyone.ipintelligence.shared/types/lib/testConstants.d.ts b/ip-intelligence/fiftyone.ipintelligence.shared/types/lib/testConstants.d.ts index 21ce6616..a0b037af 100644 --- a/ip-intelligence/fiftyone.ipintelligence.shared/types/lib/testConstants.d.ts +++ b/ip-intelligence/fiftyone.ipintelligence.shared/types/lib/testConstants.d.ts @@ -1,20 +1,7 @@ export namespace envVars { let superResourceKeyVariable: string; - /** - * @deprecated The name the variable had before, which is read only - * when the variable superResourceKeyVariable names is unset or empty. - * Use superResourceKeyVariable. - */ let superResourceKeyEnvVar: string; - /** - * @deprecated No test reads a resource key under this name. Use - * superResourceKeyVariable. - */ let ipiResourceKeyEnvVar: string; - /** - * @deprecated No test reads a licence key under this name. The licence - * key is read from the _51DEGREES_LICENSE_KEY environment variable. - */ let licenseKeyEnvVar: string; } export namespace ipAddresses { diff --git a/location/types/geoLocationCloud.d.ts b/location/types/geoLocationCloud.d.ts index 3fcd7378..8cc411d4 100644 --- a/location/types/geoLocationCloud.d.ts +++ b/location/types/geoLocationCloud.d.ts @@ -1,5 +1,6 @@ export = GeoLocationCloud; -declare class GeoLocationCloud { +declare const GeoLocationCloud_base: typeof import("fiftyone.pipeline.cloudrequestengine/types/cloudEngine"); +declare class GeoLocationCloud extends GeoLocationCloud_base { /** * Constructor for GeoLocationCloud * @@ -9,5 +10,4 @@ declare class GeoLocationCloud { constructor({ locationProvider }: { locationProvider: string; }, ...args: any[]); - dataKey: string; } diff --git a/pipeline/fiftyone.pipeline.cloudrequestengine/types/cloudRequestEngine.d.ts b/pipeline/fiftyone.pipeline.cloudrequestengine/types/cloudRequestEngine.d.ts index 801f4acd..c4438a54 100644 --- a/pipeline/fiftyone.pipeline.cloudrequestengine/types/cloudRequestEngine.d.ts +++ b/pipeline/fiftyone.pipeline.cloudrequestengine/types/cloudRequestEngine.d.ts @@ -1,9 +1,5 @@ export = CloudRequestEngine; declare const CloudRequestEngine_base: typeof import("fiftyone.pipeline.engines/types/engine"); -/** - * @typedef {import('fiftyone.pipeline.core').FlowData} FlowData - * @typedef {import('fiftyone.pipeline.core').Evidence} Evidence - */ declare class CloudRequestEngine extends CloudRequestEngine_base { /** * Constructor for CloudRequestEngine @@ -86,17 +82,7 @@ declare class CloudRequestEngine extends CloudRequestEngine_base { * @returns {Promise} resolved once the FlowData is processed */ process(flowData: FlowData): Promise; - discovery: Promise; - /** - * A response with a top level `fodid` member, in any case, holds a 51Did - * created for the one request, so it is neither stored in the cache nor - * served from it. The answer is worked out once for each element data, - * so a cache hit does not parse the response again. - * - * @param {object} data the element data of a response - * @returns {boolean} false if the response has a top level fodid member - */ - isCacheable(data: object): boolean; + discovery: any; /** * Typically, cloud will return errors as JSON. * However, transport level errors or other failures can result in @@ -219,7 +205,8 @@ declare class CloudRequestEngine extends CloudRequestEngine_base { */ getSelectedEvidence(evidence: Evidence, type: string): Evidence; /** - * Check that the key of a KeyValuePair has the given prefix. + * Check that the key of a KeyValuePair has the given prefix, ignoring + * letter case as evidence keys do. * * @param {string} itemKey Key to check * @param {string} prefix The prefix to check for. diff --git a/pipeline/fiftyone.pipeline.core/types/callbackUrl.d.ts b/pipeline/fiftyone.pipeline.core/types/callbackUrl.d.ts new file mode 100644 index 00000000..790c0572 --- /dev/null +++ b/pipeline/fiftyone.pipeline.core/types/callbackUrl.d.ts @@ -0,0 +1,32 @@ +export = callbackUrl; +/** + * Builds the callback URL from its parts and checks it. One slash separates + * the host and the endpoint, being added when neither has one and removed + * when both do. The protocol and the host are written in lower case and the + * rest as given, apart from the percent-encoding. The host value holds no + * '?', '#' or '@'. + * + * @param {*} protocol the protocol, http or https in any case + * @param {*} host the host, which can end with a port and a path + * @param {*} endPoint the endpoint + * @returns {{valid: boolean, url: string}|null} null when the protocol, + * host or endpoint is not set. Otherwise whether the URL is valid, and the + * URL to write into the script when it is, or the URL as it was built, for + * the log, when it is not. The logged URL shows '***' in place of everything + * in the host before its last '@'. + */ +declare function callbackUrl(protocol: any, host: any, endPoint: any): { + valid: boolean; + url: string; +} | null; +declare namespace callbackUrl { + export { isScheme }; +} +/** + * Whether the protocol is http or https, ignoring the case of its ASCII + * letters only. + * + * @param {string} protocol the protocol + * @returns {boolean} true if the protocol is http or https + */ +declare function isScheme(protocol: string): boolean; diff --git a/pipeline/fiftyone.pipeline.core/types/elementDataDictionary.d.ts b/pipeline/fiftyone.pipeline.core/types/elementDataDictionary.d.ts index 43c68d84..fbfba8b5 100644 --- a/pipeline/fiftyone.pipeline.core/types/elementDataDictionary.d.ts +++ b/pipeline/fiftyone.pipeline.core/types/elementDataDictionary.d.ts @@ -26,15 +26,6 @@ declare class ElementDataDictionary extends ElementData { * @returns {number} integer value */ getInternal(key: string): number; - /** - * Looks for a key in the dictionary ignoring its letter case. The contents - * can change after the data is made, so they are searched each time - * rather than indexed once. - * - * @param {string} key the property key to retrieve - * @returns {*} the value, or undefined if there is none - */ - getInternalIgnoringCase(key: string): any; [Symbol.iterator](): Generator; } declare namespace ElementDataDictionary { diff --git a/pipeline/fiftyone.pipeline.core/types/evidence.d.ts b/pipeline/fiftyone.pipeline.core/types/evidence.d.ts index a79f9470..b7fb2694 100644 --- a/pipeline/fiftyone.pipeline.core/types/evidence.d.ts +++ b/pipeline/fiftyone.pipeline.core/types/evidence.d.ts @@ -14,7 +14,7 @@ declare class Evidence { constructor(flowData: FlowData); flowData: import("./flowData"); evidenceStore: {}; - keys: {}; + keys: any; unacceptedStore: {}; /** * The web request as server.http-request holds it, being every value diff --git a/pipeline/fiftyone.pipeline.core/types/flowElement.d.ts b/pipeline/fiftyone.pipeline.core/types/flowElement.d.ts index fddfa94c..51941aa6 100644 --- a/pipeline/fiftyone.pipeline.core/types/flowElement.d.ts +++ b/pipeline/fiftyone.pipeline.core/types/flowElement.d.ts @@ -20,8 +20,10 @@ declare class FlowElement { * elementData will be stored under * @param {Function} options.processInternal callback to act on flowData * @param {object} options.properties list of properties including metadata - * @param {EvidenceKeyFilter} options.evidenceKeyFilter an instance of - * an EvidenceKeyFilter to filter evidence added to the Pipeline + * @param {EvidenceKeyFilter} options.evidenceKeyFilter the evidence the + * element accepts, being the keys that can change its results. An element + * that gives none accepts no evidence, so it never widens what the + * Pipeline keeps * @param {EvidenceKeyFilter} [options.keptEvidenceKeyFilter] the evidence * the element reads without it changing its results, which the flow data * keeps but which is not accepted evidence @@ -44,7 +46,7 @@ declare class FlowElement { */ processInternal(flowData: FlowData): any; properties: object; - evidenceKeyFilter: EvidenceKeyFilterBase; + evidenceKeyFilter: import("./evidenceKeyFilter"); /** * Evidence the flow data keeps for the element, though it is not * accepted, such as the evidence the usage sharing element shares. @@ -111,7 +113,6 @@ declare class FlowElement { declare namespace FlowElement { export { FlowData, Pipeline, EvidenceKeyFilter }; } -import EvidenceKeyFilterBase = require("./evidenceKeyFilter"); type FlowData = import("./flowData"); type Pipeline = import("./pipeline"); type EvidenceKeyFilter = import("./evidenceKeyFilter"); diff --git a/pipeline/fiftyone.pipeline.core/types/javascriptbuilder.d.ts b/pipeline/fiftyone.pipeline.core/types/javascriptbuilder.d.ts index 0bf9ea8d..6dec7f80 100644 --- a/pipeline/fiftyone.pipeline.core/types/javascriptbuilder.d.ts +++ b/pipeline/fiftyone.pipeline.core/types/javascriptbuilder.d.ts @@ -18,10 +18,14 @@ declare class JavaScriptBuilderElement extends FlowElement { * * @param {object} options options object * @param {string} options.objName the name of the client - * side object with the JavaScript properties in it - * @param {string} options.protocol The protocol ("http" or "https") - * used by the client side callback url. - * This can be overriden with header.protocol evidence + * side object with the JavaScript properties in it. This must be a valid + * JavaScript identifier that is not a reserved word, or the constructor + * throws. Leaving it out, or giving null, means "fod". This can be overridden with "query.fod-js-object-name" evidence, + * which is ignored with a warning when it is not a valid name. + * @param {string} options.protocol The protocol of the client side + * callback url, http or https in any case of its ASCII letters. The + * constructor throws for any other protocol. Left out, the header.protocol + * evidence is used, or https when there is none * @param {string} options.host The host of the client side * callback url. This can be overriden with header.host evidence. * @param {string} options.endPoint The endpoint of the client side @@ -29,7 +33,7 @@ declare class JavaScriptBuilderElement extends FlowElement { * @param {boolean} options.enableCookies Whether the client JavaScript * stored results of client side processing in cookies. This can also * be set per request, using the "query.fod-js-enable-cookies" evidence key. - * For more details on personal data policy, see http://51degrees.com/terms/client-services-privacy-policy/ + * For more details on personal data policy, see https://51degrees.com/terms/client-services-privacy-policy/?utm_source=code&utm_medium=comment&utm_campaign=51degrees-node&utm_content=fiftyone.pipeline.core-javascriptbuilder.js&utm_term=constructor * @param {boolean} options.minify Whether to minify the JavaScript */ constructor({ objName, protocol, host, endPoint, enableCookies, minify }?: { @@ -49,6 +53,7 @@ declare class JavaScriptBuilderElement extends FlowElement { minify: boolean; }; evidenceKeyFilter: JSEvidenceKeyFilter; + _invalidUrlLogged: boolean; /** * Internal process function of the JavaScript builder * Gets JSON from the JSONBundler and constructs JavaScript @@ -67,11 +72,9 @@ import FlowElement = require("./flowElement.js"); * @typedef {import('./flowData')} FlowData */ /** - * The evidence the JavaScript builder reads, being every query value, which - * the script sends back as its parameters, and the host and protocol of the - * callback URL. Other headers do not change the script, so they are not - * accepted. - **/ + * The script reads the query string, and the host and protocol it calls + * back to, so those are the evidence that can change it. + */ declare class JSEvidenceKeyFilter extends EvidenceKeyFilter { filterEvidenceKey(key: any): boolean; } diff --git a/pipeline/fiftyone.pipeline.core/types/jsonbundler.d.ts b/pipeline/fiftyone.pipeline.core/types/jsonbundler.d.ts index 92854141..c2ec6de5 100644 --- a/pipeline/fiftyone.pipeline.core/types/jsonbundler.d.ts +++ b/pipeline/fiftyone.pipeline.core/types/jsonbundler.d.ts @@ -12,6 +12,15 @@ declare class JSONBundlerElement extends FlowElement { constructor(...args: any[]); evidenceKeyFilter: BasicListEvidenceKeyFilter; propertyCache: {}; + /** + * The sequence number the Sequence Element produced, which is its Element + * Data or, as a whole number a caller put in the evidence, query.sequence. + * Text from a query string does not count. + * + * @param {FlowData} flowData the FlowData being processed + * @returns {number} the sequence number + */ + getSequence(flowData: FlowData): number; /** * The JSON Builder extracts all properties and serializes them into JSON * diff --git a/pipeline/fiftyone.pipeline.core/types/pipeline.d.ts b/pipeline/fiftyone.pipeline.core/types/pipeline.d.ts index 286ae7c9..d06c0be3 100644 --- a/pipeline/fiftyone.pipeline.core/types/pipeline.d.ts +++ b/pipeline/fiftyone.pipeline.core/types/pipeline.d.ts @@ -1,7 +1,7 @@ export = Pipeline; /** * @typedef {import('./flowElement')} FlowElement - * @typedef {import('fiftyone.pipeline.engines').DataFileUpdateService} DataFileUpdateService + * @typedef {any} DataFileUpdateService */ /** * Pipeline holding a list of flowElements for processing, can create diff --git a/pipeline/fiftyone.pipeline.core/types/pipelineBuilder.d.ts b/pipeline/fiftyone.pipeline.core/types/pipelineBuilder.d.ts index 9a3a1ba3..987e99aa 100644 --- a/pipeline/fiftyone.pipeline.core/types/pipelineBuilder.d.ts +++ b/pipeline/fiftyone.pipeline.core/types/pipelineBuilder.d.ts @@ -62,6 +62,10 @@ declare class PipelineBuilder { flowElements: FlowElement[]; dataFileUpdateService: any; addJavaScriptBuilder: boolean; + addSequenceElement: boolean; + addJsonBuilderElement: boolean; + addJavaScriptBuilderElement: boolean; + addSetHeadersElement: boolean; javascriptBuilderSettings: { objName: string; protocol: string; @@ -70,11 +74,7 @@ declare class PipelineBuilder { enableCookies: boolean; minify: boolean; }; - addSequenceElement: boolean; - addJsonBuilderElement: boolean; - addJavaScriptBuilderElement: boolean; useSetHeaderProperties: boolean; - addSetHeadersElement: boolean; suppressProcessExceptions: boolean; /** * Helper that loads a JSON configuration file from @@ -103,7 +103,12 @@ declare class PipelineBuilder { */ getSuppressProcessExceptions(config: object): boolean; /** - * Add required elements to an existing FlowElement array + * Add required elements to an existing FlowElement array. Each web + * integration element is added only where the array has no element with + * its key, compared ignoring case, so one the caller added is the one + * used and building twice adds nothing more. A JSON Builder goes + * immediately before a JavaScript Builder the caller added, which reads + * what it writes. * * @param {FlowElement[]} flowElements array of elements to add to * @returns {FlowElement[]} resulting array with required elements diff --git a/pipeline/fiftyone.pipeline.engines/types/aspectDataDictionary.d.ts b/pipeline/fiftyone.pipeline.engines/types/aspectDataDictionary.d.ts index 07cfc583..5fb1f300 100644 --- a/pipeline/fiftyone.pipeline.engines/types/aspectDataDictionary.d.ts +++ b/pipeline/fiftyone.pipeline.engines/types/aspectDataDictionary.d.ts @@ -32,14 +32,6 @@ declare class AspectDataDictionary extends AspectData { * @returns {*} property value */ getInternal(key: string): any; - /** - * Looks for a key in the dictionary ignoring its letter case, as the core - * dictionary does. - * - * @param {string} key property key - * @returns {*} property value, or undefined if there is none - */ - getInternalIgnoringCase(key: string): any; [Symbol.iterator](): Generator; } declare namespace AspectDataDictionary { diff --git a/pipeline/fiftyone.pipeline.engines/types/dataFile.d.ts b/pipeline/fiftyone.pipeline.engines/types/dataFile.d.ts index 1be37b83..95292d78 100644 --- a/pipeline/fiftyone.pipeline.engines/types/dataFile.d.ts +++ b/pipeline/fiftyone.pipeline.engines/types/dataFile.d.ts @@ -110,6 +110,7 @@ declare class DataFile { * @param {string} identifier the identifier of the datafile */ refresh(identifier: string): void; + onUpdateComplete: Function; updating: boolean; /** * Getter for the update url for the datafile update service to use diff --git a/pipeline/fiftyone.pipeline.engines/types/dataFileUpdateService.d.ts b/pipeline/fiftyone.pipeline.engines/types/dataFileUpdateService.d.ts index 1d808cb6..fc55b206 100644 --- a/pipeline/fiftyone.pipeline.engines/types/dataFileUpdateService.d.ts +++ b/pipeline/fiftyone.pipeline.engines/types/dataFileUpdateService.d.ts @@ -41,19 +41,14 @@ declare class DataFileUpdateService { * @param {Function} callback callback */ once(listener: string | symbol, callback: Function): void; - /** - * Method that updates a datafile when it is due an update - * - * @param {DataFile} dataFile the datafile to update - * @param {boolean} [automatic] true where the update is one the service - * started itself, on start-up or when the polling interval has passed, - * and not one an application asked for. Only the log messages differ. - * @returns {boolean | void} returns false if already updating - * or request failed - */ - updateDataFile(dataFile: DataFile, automatic?: boolean): boolean | void; /** * Writes a message to the log of the pipeline the service is attached to. + * With no pipeline, an error is written to the console, as a pipeline + * with no error listener does, so that it is not lost. + * + * The service's messages name the update URL, which carries the license + * keys, so every one of them is masked here. The pipeline's log does not + * mask, because each detection goes through it. * * @param {string} level the log level * @param {*} message the message @@ -61,24 +56,65 @@ declare class DataFileUpdateService { log(level: string, message: any): void; /** * Reports how an update ended, to the listeners of 'updateComplete' and - * to the data file's own onUpdateComplete function, if it has one. + * to the data file's own onUpdateComplete function, if it has one. An + * error thrown by any of them is logged, goes no further, and the + * callbacks after it are not called. * * @param {DataFile} dataFile the data file the update was for * @param {string} status one of the AutoUpdateStatus values */ complete(dataFile: DataFile, status: string): void; /** - * Refreshes a data file that is held in memory with the bytes given. The - * data file keeps the data it has if the refresh fails. Nothing is - * downloaded and no file is written. + * The message for a data update service that could not be reached. * - * @param {DataFile} dataFile the memory data file to refresh - * @param {Buffer | Uint8Array} buffer the new data - * @returns {boolean} false if the data file is already updating or the - * refresh failed, which is also logged and reported through the - * 'updateComplete' event + * @param {DataFile} dataFile the data file being updated + * @returns {string} the message to log */ - updateFromMemory(dataFile: DataFile, buffer: Buffer | Uint8Array): boolean; + accessError(dataFile: DataFile): string; + /** + * Refreshes the engine of a data file with the data now in place, and + * logs a failure. The caller reports the outcome. + * + * @param {DataFile} dataFile the data file to refresh + * @param {boolean} [fromFile] true where the data came from a file that + * was written, which is the case the message names a try count for + * @returns {boolean} true if the refresh worked + */ + refreshDataFile(dataFile: DataFile, fromFile?: boolean): boolean; + /** + * Ends an update that failed, so that the next one can be scheduled. + * + * @param {DataFile} dataFile the data file being updated + * @param {string} status the AutoUpdateStatus to report + */ + fail(dataFile: DataFile, status: string): void; + /** + * Method that updates a datafile when it is due an update + * + * @param {DataFile} dataFile the datafile to update + * @param {boolean} [automatic] true where the update is one the service + * started itself, on start-up or when the polling interval has passed, + * and not one an application asked for. Only the log messages differ. + * @returns {boolean | void} returns false if already updating + * or request failed + */ + updateDataFile(dataFile: DataFile, automatic?: boolean): boolean | void; + /** + * Logs an error that has no message of its own, with its cause. + * + * @param {DataFile} dataFile the data file being updated + * @param {*} error the error, or whatever was thrown + */ + unhandled(dataFile: DataFile, error: any): void; + /** + * Logs a download whose MD5 hash does not match the one the response + * carried. + * + * @param {DataFile} dataFile the data file being updated + * @param {string} serverHash the hash the response carried + * @param {string} downloadHash the hash of the data that arrived + */ + integrityFailed(dataFile: DataFile, serverHash: string, downloadHash: string): void; /** * Internal method called when the datafile has * been downloaded and is ready after an update @@ -96,6 +132,18 @@ declare class DataFileUpdateService { * @param {string} filename the filename of the downloaded data */ processFile(dataFile: DataFile, filename: string): void; + /** + * Refreshes a data file that is held in memory with the bytes given. The + * data file keeps the data it has if the refresh fails. Nothing is + * downloaded and no file is written. + * + * @param {DataFile} dataFile the memory data file to refresh + * @param {Buffer | Uint8Array} buffer the new data + * @returns {boolean} false if the data file is already updating or the + * refresh failed, which is also logged and reported through the + * 'updateComplete' event + */ + updateFromMemory(dataFile: DataFile, buffer: Buffer | Uint8Array): boolean; /** * Internal method to check the next update of a * datafile at a polling interval set on the datafile diff --git a/pipeline/fiftyone.pipeline.engines/types/engine.d.ts b/pipeline/fiftyone.pipeline.engines/types/engine.d.ts index 07ce8bff..c7ef4295 100644 --- a/pipeline/fiftyone.pipeline.engines/types/engine.d.ts +++ b/pipeline/fiftyone.pipeline.engines/types/engine.d.ts @@ -36,23 +36,24 @@ declare class Engine extends Engine_base { * @type {Set} */ restrictedPropertyKeys: Set; - /** - * Checks cache and returns cached result if found. - * - * @param {FlowData} flowData checks if a FlowData's evidence - * is already in the cache and processing can be bypassed - * @returns {boolean} whether in cache - */ - inCache(flowData: FlowData): boolean; /** * Whether a result may be stored in the cache and served from it. A result * that holds a value created for the one request that asked for it, such - * as a 51Did, must not be. + * as a 51Did, must not be, or the next request with the same evidence + * would be given it. * * @param {object} data the element data of a result * @returns {boolean} true unless the result holds such a value */ isCacheable(data: object): boolean; + /** + * Checks cache and returns cached result if found. + * + * @param {FlowData} flowData checks if a FlowData's evidence + * is already in the cache and processing can be bypassed + * @returns {boolean} whether in cache + */ + inCache(flowData: FlowData): boolean; /** * An engine's process function checks cache for an item * (calling inCache) diff --git a/pipeline/fiftyone.pipeline.engines/types/index.d.ts b/pipeline/fiftyone.pipeline.engines/types/index.d.ts index d2e54e61..65e49c0d 100644 --- a/pipeline/fiftyone.pipeline.engines/types/index.d.ts +++ b/pipeline/fiftyone.pipeline.engines/types/index.d.ts @@ -19,5 +19,7 @@ export let AutoUpdateStatus: { AUTO_UPDATE_ERR_MD5_VALIDATION_FAILED: string; AUTO_UPDATE_NEW_FILE_CANT_RENAME: string; AUTO_UPDATE_REFRESH_FAILED: string; + AUTO_UPDATE_TEMP_PATH_NOT_SET: string; + AUTO_UPDATE_UNKNOWN_ERROR: string; }; export let Tracker: typeof import("./tracker"); From e422e2d10ec6464bf0a655d3706081b73ad076ac Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 09:30:51 +0000 Subject: [PATCH 2/5] Remove the types of cloudHelpers.js, which no longer exists Nothing in the repository has a cloudHelpers.js or refers to cloudHelpers, so the file declared a module the package does not hold. --- .../fiftyone.pipeline.cloudrequestengine/types/cloudHelpers.d.ts | 1 - 1 file changed, 1 deletion(-) delete mode 100644 pipeline/fiftyone.pipeline.cloudrequestengine/types/cloudHelpers.d.ts diff --git a/pipeline/fiftyone.pipeline.cloudrequestengine/types/cloudHelpers.d.ts b/pipeline/fiftyone.pipeline.cloudrequestengine/types/cloudHelpers.d.ts deleted file mode 100644 index 56a89eb7..00000000 --- a/pipeline/fiftyone.pipeline.cloudrequestengine/types/cloudHelpers.d.ts +++ /dev/null @@ -1 +0,0 @@ -export function makeHTTPRequest(url: string): Promise; From 4f5f80c705c479e16d73842d714d8232d7b10720 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 10:29:29 +0000 Subject: [PATCH 3/5] Test that every package's types compile for a TypeScript caller The test compiles, with TypeScript's own API, a file that imports each package with types by its package name, and checks the type files as well. It fails on fiftyone.devicedetection.cloud, whose types import ../fiftyone.devicedetection.cloud/hardwareProfileCloudEngine, which a caller's compiler cannot find. --- ci/tests/typesCompile.test.js | 84 +++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 ci/tests/typesCompile.test.js diff --git a/ci/tests/typesCompile.test.js b/ci/tests/typesCompile.test.js new file mode 100644 index 00000000..9ef4b398 --- /dev/null +++ b/ci/tests/typesCompile.test.js @@ -0,0 +1,84 @@ +/* ********************************************************************* + * This Original Work is copyright of 51 Degrees Mobile Experts Limited. + * Copyright 2026 51 Degrees Mobile Experts Limited, Davidson House, + * Forbury Square, Reading, Berkshire, United Kingdom RG1 3EU. + * + * This Original Work is licensed under the European Union Public Licence + * (EUPL) v.1.2 and is subject to its terms as set out below. + * + * If a copy of the EUPL was not distributed with this file, You can obtain + * one at https://opensource.org/licenses/EUPL-1.2. + * + * The 'Compatible Licences' set out in the Appendix to the EUPL (as may be + * amended by the European Commission) shall be deemed incompatible for + * the purposes of the Work and the provisions of the compatibility + * clause in Article 5 of the EUPL shall not apply. + * + * If using the Work as, or as part of, a network application, by + * including the attribution notice(s) required under Article 5 of the EUPL + * in the end user terms of the application under an appropriate heading, + * such notice(s) shall fulfill the requirements of that article. + * ********************************************************************* */ + +// Compiles a TypeScript file that imports every package with types by its +// package name, as a caller does, with the type files themselves checked. +// The file exists only in memory, at the repository root, so the packages +// resolve through the workspace links in node_modules. + +const path = require('path'); +const ts = require('typescript'); + +const ROOT = path.resolve(__dirname, '..', '..'); +const CHECK_FILE = path.join(ROOT, 'types-compile-check.ts'); +const COMPILE_TIMEOUT_MS = 120000; + +const OPTIONS = { + noEmit: true, + skipLibCheck: false, + esModuleInterop: true, + module: ts.ModuleKind.CommonJS, + target: ts.ScriptTarget.ES2020, + moduleResolution: ts.ModuleResolutionKind.Node10 +}; + +const packagesWithTypes = () => + require(path.join(ROOT, 'package.json')).workspaces + .map((folder) => require(path.join(ROOT, folder, 'package.json'))) + .filter((manifest) => manifest.types || manifest.typings) + .map((manifest) => manifest.name); + +const isCheckFile = (fileName) => + path.resolve(fileName).toLowerCase() === CHECK_FILE.toLowerCase(); + +const compile = (source) => { + const host = ts.createCompilerHost(OPTIONS); + const { fileExists, readFile, getSourceFile } = host; + host.fileExists = (fileName) => + isCheckFile(fileName) || fileExists.call(host, fileName); + host.readFile = (fileName) => + isCheckFile(fileName) ? source : readFile.call(host, fileName); + host.getSourceFile = (fileName, language, ...rest) => + isCheckFile(fileName) + ? ts.createSourceFile(fileName, source, language) + : getSourceFile.call(host, fileName, language, ...rest); + const program = ts.createProgram([CHECK_FILE], OPTIONS, host); + const formatHost = { + getCanonicalFileName: (fileName) => fileName, + getCurrentDirectory: () => ROOT, + getNewLine: () => '\n' + }; + return ts.getPreEmitDiagnostics(program) + .map((diagnostic) => ts.formatDiagnostic(diagnostic, formatHost).trim()); +}; + +describe('published types', () => { + test('every package\'s types compile when a TypeScript caller imports ' + + 'them', () => { + const names = packagesWithTypes(); + expect(names.length).toBeGreaterThan(0); + const source = names + .map((name, i) => `import * as p${i} from '${name}';\nexport { p${i} };`) + .join('\n'); + expect(compile(source)).toEqual([]); + }, COMPILE_TIMEOUT_MS); +}); From 0b5eced1947c9fbef83bba60b2cf33a0355c4e49 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 10:30:30 +0000 Subject: [PATCH 4/5] Require each package's own files by ./ Two package entry points required a file of their own through ..//, which works only while the folder has that name. The cloud package's types then imported the same path from the types folder, where a TypeScript caller cannot find it. --- device-detection/fiftyone.devicedetection.cloud/index.js | 2 +- device-detection/fiftyone.devicedetection.onpremise/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/device-detection/fiftyone.devicedetection.cloud/index.js b/device-detection/fiftyone.devicedetection.cloud/index.js index 8677918d..d79524c2 100644 --- a/device-detection/fiftyone.devicedetection.cloud/index.js +++ b/device-detection/fiftyone.devicedetection.cloud/index.js @@ -23,6 +23,6 @@ module.exports = { DeviceDetectionCloud: require('./deviceDetectionCloud'), DeviceDetectionCloudPipelineBuilder: require('./deviceDetectionCloudPipelineBuilder'), - HardwareProfileCloudEngine: require('../fiftyone.devicedetection.cloud/hardwareProfileCloudEngine') + HardwareProfileCloudEngine: require('./hardwareProfileCloudEngine') }; diff --git a/device-detection/fiftyone.devicedetection.onpremise/index.js b/device-detection/fiftyone.devicedetection.onpremise/index.js index 2c4c2058..e5bf84c9 100644 --- a/device-detection/fiftyone.devicedetection.onpremise/index.js +++ b/device-detection/fiftyone.devicedetection.onpremise/index.js @@ -24,5 +24,5 @@ module.exports = { DeviceDetectionOnPremise: require('./deviceDetectionOnPremise'), DeviceDetectionOnPremisePipelineBuilder: require('./deviceDetectionOnPremisePipelineBuilder'), SwigData: require('./swigData'), - swigHelpers: require('../fiftyone.devicedetection.onpremise/swigHelpers') + swigHelpers: require('./swigHelpers') }; From a8b05e9c6d7d947d0a559977828d8afe6217ebb0 Mon Sep 17 00:00:00 2001 From: James Rosewell Date: Sat, 14 Nov 2026 10:33:00 +0000 Subject: [PATCH 5/5] Regenerate the cloud package's index types With the require changed, tsc writes the import as ./hardwareProfileCloudEngine. --- .../fiftyone.devicedetection.cloud/types/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device-detection/fiftyone.devicedetection.cloud/types/index.d.ts b/device-detection/fiftyone.devicedetection.cloud/types/index.d.ts index d1da43e0..c0c0026a 100644 --- a/device-detection/fiftyone.devicedetection.cloud/types/index.d.ts +++ b/device-detection/fiftyone.devicedetection.cloud/types/index.d.ts @@ -1,3 +1,3 @@ export let DeviceDetectionCloud: typeof import("./deviceDetectionCloud"); export let DeviceDetectionCloudPipelineBuilder: typeof import("./deviceDetectionCloudPipelineBuilder"); -export let HardwareProfileCloudEngine: typeof import("../fiftyone.devicedetection.cloud/hardwareProfileCloudEngine"); +export let HardwareProfileCloudEngine: typeof import("./hardwareProfileCloudEngine");