Repository navigation
Release candidate - #152
Draft
jwrosewell wants to merge 51 commits into
Draft
jwrosewell wants to merge 51 commits into
jwrosewell wants to merge 51 commits into
Conversation
AGENTS.md gains a section linking common-ci's list of environment variable names (environment-variables.md, made from environment-variables.json) at commit 18f9a570, and saying the list decides. README.md points at the same page where it names the variables the tests or examples read. Documentation only.
…file before reporting it (#94) * Test that a download cut short reports the access error The data update specification's Errors table gives the messages of the .NET data update service. .NET reads the whole response before its request returns, so a download cut short fails that request, and .NET reports it as "Error accessing data update service at '<url>' for engine '<name>'" with the cause attached. The test of a download cut short closed the connections 10 milliseconds after the check started, whether or not the response had arrived, so it passed or failed by chance. On a slow runner the connection closed before the response, and the message was the one for a failed connection. The test now cuts the connection only once the service's request has its response, from a server that never sends the whole file, and a connection closed before any response is tested on its own. The test of a reset part way through the download expects the same error, which a reset gives whether it comes before or after the response. * Report a download cut short as the access error, with its cause A download that ended before the whole file arrived was logged as "No response from data update service", a message .NET writes only when its request returns no response at all. .NET reads the whole response before its request returns, so it reports a download cut short as "Error accessing data update service at '<url>' for engine '<name>'" with the cause attached, which is what Node already wrote for a connection that failed before any response. The service now writes that message for a download cut short too, with the first error the request or the response raised after the response arrived as the cause. The status is unchanged. * Test that a download cut short leaves no part file, with no timer The test of a reset part way through the download reset the connection 50 milliseconds after the server wrote, and waited 500 milliseconds before it looked, so its check that the part file had gone held only because of those two times. It now resets once the service's request has its response, waits for the update to be reported, and then checks that there is one report, one scheduled check and no part file. The test of a download cut short checks the folder too. In both tests the cut comes before the service has opened its part file. * Remove a cut short download's part file before reporting the update When a download was cut short the service destroyed the write stream for the part file, asked for the file to be removed straight away, and reported the update. A stream still opening its file has not created it yet, so the removal could find nothing and the file the stream then created would stay in the temporary folder. In every order the file could still be there when the update was reported. The service now removes the part file once the stream has closed, which is after the file is open, and reports the update once the file has gone. * Test that the part file is removed before the update is reported The folder checks in the two cut short tests passed or failed by chance on the service before the fix, because fs.unlink removes the part file on another thread while the test goes on. A spy on fs.unlink now records each removal as it finishes, and both tests check that the part file's removal had finished when the update was reported. Before the fix the service reports the update first, so the check fails every time.
…or (#15) * Package text: say what each package does in the words people search for Developers search npm with words such as user agent parser, device detection, and IP geolocation. The descriptions of the six Device Detection and IP Intelligence packages now say what each package does in those words, and the keywords add the matching terms. Existing keywords that are still true are kept, and keywords naming other companies' products are removed. Both package.json and remote_package.json change, because ci/build-package.ps1 publishes remote_package.json and the two files should match. Only the description and keywords fields change, and no version number moves. * Package text: name the products these packages are an alternative to People searching npm for WURFL, DeviceAtlas, MaxMind, or ipinfo should find these packages too. The keywords naming those products are restored exactly as they were, and each description now ends with the products the package is an alternative to. Only the description and keywords lines change, and no version number moves. * Package text: name UAParser.js in full The Device Detection descriptions now say "An alternative to UAParser.js, DeviceAtlas, and WURFL." The 51Degrees fork is called 51Degrees UAParser, so the bare name could read as our own package. Only the description line changes, and no version number moves.
…ntries (#27) On Ubuntu the Selenium contract step reports a pass without running a test, so the browser contract has had no Linux coverage. And a pull request into `rc` runs all eight configurations, two of them on macOS, of which only five run at once across the whole organisation.
…ue (#66) The JSON Builder wrote `delayexecution` for every property whose metadata sets the delay execution flag, before it read the value ([`jsonbundler.js` line 168 at 24592ac](https://github.com/51Degrees/51degrees-node/blob/24592acbee7fd2881a96ac661296535daed6f157/pipeline/fiftyone.pipeline.core/jsonbundler.js#L168)). So a property with no value, and one that could not be read at all, were marked too. The cross-language audit found this, and PHP ([51degrees-php#61](51Degrees/51degrees-php#61)), Go ([51degrees-go#91](51Degrees/51degrees-go#91)) and Python ([51degrees-python#92](51Degrees/51degrees-python#92)) have already merged the same change.
…heck what the location examples print (#95) The Publish run for release 4.5.103, [run 43412143722](https://github.com/51Degrees/51degrees-node/actions/runs/43412143722) on `main` at 4d5832f (the merge of #83), failed, so nothing was published and npm still has 4.5.102. In each of the eight "Publish / Test" jobs (Ubuntu, Ubuntu ARM, Windows and macOS, on Node.js 22 and 24) exactly one test failed, "Examples without settings › the mixed web page marks the Enterprise properties" in [`examplesWithoutSettings.test.js`](https://github.com/51Degrees/51degrees-node/blob/24592acbee7fd2881a96ac661296535daed6f157/ip-intelligence/fiftyone.ipintelligence.onpremise/examples/onpremise/examplesWithoutSettings.test.js#L234-L244).
[#8](#8). The JavaScript builder sets the template's `_parameters` only when it has a callback URL ([`javascriptbuilder.js` lines 340 to 365 at 24592ac](https://github.com/51Degrees/51degrees-node/blob/24592acbee7fd2881a96ac661296535daed6f157/pipeline/fiftyone.pipeline.core/javascriptbuilder.js#L340-L365)). With no endpoint, the template's line `var renderedParameters = function() { return {{&_parameters}}; };` renders as `return ;`.
… a named branch (#99) common-ci refuses a release that comes less than a week after the last one unless `allow-early-release` is set, and the refusal tells the person to "run this repository's Publish workflow with allow-early-release set." ([common-ci `.github/workflows/nightly-publish.yml` lines 28 to 31, 202 and 210 at 1c5c0e0b](https://github.com/51Degrees/common-ci/blob/1c5c0e0b09a1f77722e20ba2d10cbd1031caca9e/.github/workflows/nightly-publish.yml#L28-L31)). This repository's Publish workflow has only the `dryrun` input ([`.github/workflows/publish.yml` lines 3 to 8 at 758fea8](https://github.com/51Degrees/51degrees-node/blob/758fea819c13fe0df4275a0a0478cdd03f57d5ed/.github/workflows/publish.yml#L3-L8)), so a release agreed to go out early cannot be started, whatever the message says.
) The Cloud 51Did workflow runs the live 51Did tests on a pull request only when it targets `main` ([`.github/workflows/cloud-51did.yml` lines 32 and 33 at 758fea8](https://github.com/51Degrees/51degrees-node/blob/758fea819c13fe0df4275a0a0478cdd03f57d5ed/.github/workflows/cloud-51did.yml#L32-L33)). Changes reach `main` through `rc`, so a change to the 51Did package is first tested against the live cloud service when the release pull request from `rc` opens, after it has been reviewed and merged into `rc`.
…es when a value is not yet known (#104) Five pipeline examples had tests that never ran them, and two examples had no test at all (gaps DX-node-34 and DX-node-35).
…kage (#106) `fiftyone.pipeline.core` has no `files` list ([`pipeline/fiftyone.pipeline.core/package.json` at 758fea8](https://github.com/51Degrees/51degrees-node/blob/758fea819c13fe0df4275a0a0478cdd03f57d5ed/pipeline/fiftyone.pipeline.core/package.json)), so npm packs the whole `javascript-templates` submodule, its tests, README, LICENSE and GitHub workflows, where the JavaScript Builder reads only `JavaScriptResource.mustache` ([`javascriptbuilder.js` lines 27 to 30](https://github.com/51Degrees/51degrees-node/blob/758fea819c13fe0df4275a0a0478cdd03f57d5ed/pipeline/fiftyone.pipeline.core/javascriptbuilder.js#L27-L30)). Anything the templates repository adds later would be published in this package too, so the submodule could not move on without changing what the package holds. The Device Detection and IP Intelligence packages already have a `files` list, for example [`device-detection/fiftyone.devicedetection.cloud/package.json`](https://github.com/51Degrees/51degrees-node/blob/758fea819c13fe0df4275a0a0478cdd03f57d5ed/device-detection/fiftyone.devicedetection.cloud/package.json). This is gap DX-node-15, item 6 of run book 9.
Step 3.1 of [common-ci#306](51Degrees/common-ci#306). [`ci/build-package.ps1` line 35 at 21fa119](https://github.com/51Degrees/51degrees-node/blob/21fa11996a1e584e855ef548871cc006d23e5873/ci/build-package.ps1#L35) runs `npm version` with the run's one version for every package, so all 16 packages published 4.5.102 on 4 November 2026 ([Publish run 41918901313](https://github.com/51Degrees/51degrees-node/actions/runs/41918901313)) whatever had changed. That spends every package's allowance under the weekly release rule, and the [release of 13 November](#83) would have done the same.
) `PipelineBuilder.addRequiredElements` adds the Sequence Element, the JSON Builder, the JavaScript Builder and the Set Headers Element whatever the caller already added ([`pipeline/fiftyone.pipeline.core/pipelineBuilder.js` lines 200 to 205 at 758fea8](https://github.com/51Degrees/51degrees-node/blob/758fea819c13fe0df4275a0a0478cdd03f57d5ed/pipeline/fiftyone.pipeline.core/pipelineBuilder.js#L200-L205)). This has three effects.
This draft closes two gaps from the audit of the deferred work and the examples, DX-node-26 and DX-node-27. On `rc` at 758fea8 the examples did not end with a "Find out more" section, which is the part of an example that gives the person running it somewhere to go next.
Eleven of the examples' `51d.json` files name an engine by a path into this repository's source, such as `"../../../deviceDetectionCloud"` in [`device-detection/fiftyone.devicedetection.cloud/examples/cloud/gettingstarted-console/51d.json` at fe81e01](https://github.com/51Degrees/51degrees-node/blob/fe81e01866b5aae0e2c6ec11a25a4f0a5d1ccd31/device-detection/fiftyone.devicedetection.cloud/examples/cloud/gettingstarted-console/51d.json). Such a file only works beside the source. [`ci/install-package.ps1` lines 43 to 55](https://github.com/51Degrees/51degrees-node/blob/fe81e01866b5aae0e2c6ec11a25a4f0a5d1ccd31/ci/install-package.ps1#L43-L55) rewrites two of them so the Publish tests run them against the packed packages, and [`device-detection/run_examples.md` lines 72 to 92](https://github.com/51Degrees/51degrees-node/blob/fe81e01866b5aae0e2c6ec11a25a4f0a5d1ccd31/device-detection/run_examples.md#L72-L92) and [`ip-intelligence/run_examples.md` lines 61 to 81](https://github.com/51Degrees/51degrees-node/blob/fe81e01866b5aae0e2c6ec11a25a4f0a5d1ccd31/ip-intelligence/run_examples.md#L61-L81) tell a person running an example against the published packages to edit the rest by hand. This is gap DX-node-20, left under "What remains" in [#95](#95), which named the mixed web example's engine by package.
This draft was to wait until https://51degrees.com/configure answers. At 17:35 UTC on 13 November it does. `/configure`, `/configure/`, `/configure/gGc3T5pT` and `/configure?utm_source=code` each answer 200 with the page title "Cloud Configuration | 51Degrees", the same title `configure.51degrees.com` serves, and the page at the new address loads the configuration app with `<base href="/configure/">`. On 13 November at 15:01 the same addresses answered 404.
…ata file reload (#108) Two test gaps, with no package code to change.
…id and sequence in any letters (#109) Two faults in the usage sharing record, and two cases no test covered, all at [fe81e01](https://github.com/51Degrees/51degrees-node/tree/fe81e01866b5aae0e2c6ec11a25a4f0a5d1ccd31).
… name what needs the Enterprise files (#111) The IP Intelligence mixed API example, which runs a local copy of the cloud service's API on both on-premise engines, does not run from a fresh clone as the other examples do (gap DX-node-29, left under "Not changed" in [#32](#32) and "What remains" in [#95](#95)). At [7539a0b](https://github.com/51Degrees/51degrees-node/tree/7539a0be284aec3e0aae12cf50cf727ead68fb4c):
…n the packed packages (#112) The Nightly Pipeline dry run [43578169805](https://github.com/51Degrees/51degrees-node/actions/runs/43578169805), on a throwaway branch holding `rc` at 7539a0b with the drafts then approved merged in, fails one test in all eight Test jobs of its Publish stage, being Ubuntu, Ubuntu ARM, Windows and macOS on Node.js 22 and 24.
fiftyone.pipeline.did took the [OWID library](https://github.com/SWAN-community/owid-js) as the npm dependency `"owid": "github:SWAN-community/owid-js#6c5ff4e7"`, bundled into its tarball, where every other 51Degrees language takes OWID as a git submodule. This takes owid-js as the submodule `pipeline/fiftyone.pipeline.did/owid-js`, pinned at the same commit, and packs only the library's `v1.js` and its `LICENSE` from it.
…le for a TypeScript caller (#113) Each package publishes the `types/*.d.ts` files committed in this repository, and nothing writes them again before a package is packed. The readmes say that "Calling the generation step is manual for now" ([`device-detection/readme.md` line 236 at a9a3bd2](https://github.com/51Degrees/51degrees-node/blob/a9a3bd2ec192f0006296a39366a710c5ec090f18/device-detection/readme.md?plain=1#L236)). So the published types have fallen behind the code. With TypeScript 5.9.3, `npm run tsc` on `rc` at a9a3bd2 changes 23 of the committed files and writes one that was never committed, `pipeline/fiftyone.pipeline.core/types/callbackUrl.d.ts` ([run 43580575276](https://github.com/51Degrees/51degrees-node/actions/runs/43580575276)).
…and mark the raw flags byte deprecated (#115) 1. **A short payload that names another version is refused as too short, and the version it names is not reported.** `unpack` checks the length against version 0's header before it reads the version ([`pipeline/fiftyone.pipeline.did/internal/payload.js` lines 88 to 113 at 6d5d4fe](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.did/internal/payload.js#L88-L113)), so a payload of 1 to 4 bytes whose flags byte names version 1, 2 or 3 gets `PayloadTooShort`, measured against a header that a later version need not have. A payload of normal length is refused naming its version, and tested ([`tests/fodId.test.js` lines 611 to 632](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.did/tests/fodId.test.js#L611-L632)). 2. **The raw flags byte is part of the typed surface.** `FodId` declares `_flags: number` ([`types/fodId.d.ts` line 189](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.did/types/fodId.d.ts#L189)), set at [`fodId.js` line 132](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.did/fodId.js#L132) and [line 480](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.did/fodId.js#L480). The published fiftyone.pipeline.did 4.5.102 declares it too ([its `types/fodId.d.ts` line 177](https://unpkg.com/fiftyone.pipeline.did@4.5.102/types/fodId.d.ts)), where the offsets and the Terms index are kept in modules that are not exported.
…e's headers, and read Set Header identifiers that hold digits (#120) 1. **The client-side endpoints process a request before they compare its If-None-Match with the ETag.** `Helpers.writeClientSideResponse` takes "the processed flow data for the request" ([`pipeline/fiftyone.pipeline.core/helpers.js` lines 148 to 168 at 6d5d4fe](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/helpers.js#L148-L168)), so every example that serves the JSON or JavaScript endpoint runs the Pipeline first, for example the Device Detection on-premise web example ([`gettingStarted.js` lines 233 to 250](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/device-detection/fiftyone.devicedetection.onpremise/examples/onpremise/gettingstarted-web/gettingStarted.js#L233-L250)). A browser that revalidates a script it already holds still costs a full detection. 2. **A 304 sent while processing records errors loses the ETag and max-age.** The response then carries `Cache-Control: private, no-cache` and no ETag, 304 included ([`helpers.js` lines 185 to 202](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/helpers.js#L185-L202)), and a test asserts it ([`tests/clientSideCaching.test.js` lines 226 to 230](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/tests/clientSideCaching.test.js#L226-L230)). So a browser that holds a good response keeps it through an outage but its cache drops the ETag and max-age. 3. **A Set Header identifier that holds a digit ends early.** `getHeaderName` skips only `a` to `z` after the identifier's first character ([`setHeadersElement.js` lines 61 to 72](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/setHeadersElement.js#L61-L72)), so `SetHeaderBrowser2Accept-CH` gives the header `2Accept-CH`. No property in use today has a digit in its identifier, so no response is wrong today. 4. **No test passes the max-age option**, which `writeClientSideResponse` takes ([line 167](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/helpers.js#L167)).
Element Data is found only by its key as written. `FlowData.get` looks the key up as given, `const elementData = this.data[flowElementDataKey];` ([`pipeline/fiftyone.pipeline.core/flowData.js` line 191 at 6d5d4fe](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/flowData.js#L191)), so `flowData.get('Device')` and `flowData.Device` throw where `flowData.device` works. Property names already ignore letter case ([`elementData.js` lines 100 to 123](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/elementData.js#L100-L123)).
…warning (#123) 1. **The warnings a cloud response carries are never logged.** The cloud service can answer with a `warnings` array beside its results, and no code in `fiftyone.pipeline.cloudrequestengine` reads it. The request engine parses the discovery response for its products ([`cloudRequestEngine.js` lines 404 to 415 at 6d5d4fe](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.cloudrequestengine/cloudRequestEngine.js#L404-L415)) and keeps the processing response as it is ([lines 504 to 515](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.cloudrequestengine/cloudRequestEngine.js#L504-L515)), so a warning from the service reaches nobody. 2. **A product the key does not include is logged as an error.** The cloud engine logs it once, at error level ([`cloudEngine.js` lines 131 to 141](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.cloudrequestengine/cloudEngine.js#L131-L141)), though nothing is wrong with the request and the other products in the answer are used.
…, read _51DEGREES_LICENSE_KEY and end with status 0 (#101) Five faults in the examples that update a data file, and in two example messages, all at [758fea8](https://github.com/51Degrees/51degrees-node/tree/758fea819c13fe0df4275a0a0478cdd03f57d5ed).
…uires (#121) The pipeline specification asks for four star sign examples in the core, and Node.js had three. The simple Flow Element and the client-side evidence Flow Element are in [`pipeline/fiftyone.pipeline.core/examples/customFlowElements`](https://github.com/51Degrees/51degrees-node/tree/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/examples/customFlowElements) and the on-premise Engine is [`pipeline/fiftyone.pipeline.engines/examples/onPremiseFlowElement.js`](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.engines/examples/onPremiseFlowElement.js), but no example makes a Cloud Engine, and `fiftyone.pipeline.cloudrequestengine` had no examples folder.
…a is refreshed (#130) Both on-premise engines read the Evidence keys they accept from the native engine once, when the native engine is created, and never again. A refresh of the data file calls `refreshData()` and keeps the filter made from the data file the engine started with.
…e on-premise form (#124) The IP Intelligence cloud engine keeps every value as the cloud service sends it. `CloudEngine` stores each one unchanged, `result[key].value = value;` ([`pipeline/fiftyone.pipeline.cloudrequestengine/cloudEngine.js` lines 152 to 159 at 6d5d4fe](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.cloudrequestengine/cloudEngine.js#L152-L159)), and `IpIntelligenceCloud` adds nothing ([`ip-intelligence/fiftyone.ipintelligence.cloud/ipIntelligenceCloud.js` lines 24 to 42](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/ip-intelligence/fiftyone.ipintelligence.cloud/ipIntelligenceCloud.js#L24-L42)). So for the same address:
…idence keys (#125) An Engine's cache key is the JSON of the Evidence it accepts, in the order the Evidence was added and with each key as it was first spelled ([`pipeline/fiftyone.pipeline.engines/engine.js` lines 99 to 104 and 136 to 141 at 6d5d4fe](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.engines/engine.js#L99-L141)). So the same Evidence added in another order, or with a key in other letters, such as `header.User-Agent` where an earlier request sent `header.user-agent`, misses the cache and is processed again. The key stored was also made after processing, from Evidence processing may have added to, where the lookup is made before.
…and write lists of Element Data by the JSON rules (#118) 1. **The script takes its session id and sequence from the evidence, not from the Sequence Element.** The JavaScript Builder reads `query.session-id` and `query.sequence` from the evidence ([`pipeline/fiftyone.pipeline.core/javascriptbuilder.js` lines 383 to 386 at 6d5d4fe](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/javascriptbuilder.js#L383-L386)). With a Sequence Element the two agree, because the element writes the same values to the evidence and to its data. With no Sequence Element, which the JSON Builder allows when a caller adds a whole number as `query.sequence`, the script carries whatever the evidence held, and a test asserted that ([`tests/sessionIdAndSequence.test.js` lines 157 to 167](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/tests/sessionIdAndSequence.test.js#L157-L167)). 2. **A list of Element Data is written with each item's internal fields.** The JSON Builder writes a Property whose value is a list as it is ([`jsonbundler.js` lines 186 to 190](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/jsonbundler.js#L186-L190)). The cloud hardware profile lookup gives `profiles` as a list of objects of Aspect Property Values ([`hardwareProfileCloudEngine.js` lines 103 to 126](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/device-detection/fiftyone.devicedetection.cloud/hardwareProfileCloudEngine.js#L103-L126)), so each profile reaches the JSON as `noValueMessage`, `_value` and `hasValue` for every Property, rather than the value, or null with its reason. 3. **Two JSON rules the code meets had no test**, that a plain null has no entry and that every key is in lower case.
The Sequence Element counted any JavaScript number with no fractional part as a sequence ([`pipeline/fiftyone.pipeline.core/sequenceElement.js` lines 89 to 95 at 6d5d4fe](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/pipeline/fiftyone.pipeline.core/sequenceElement.js#L89-L95)), so a floating-point 2.0 counted as 2, and a `BigInt` did not count at all. Every ordinary JavaScript number is a floating-point value, so 2.0 and 2 are the same number and cannot be told apart.
…iles, defaults and order (#137) The on-premise Device Detection engine adds the seven match metric Properties to its Property metadata itself, as the data file does not hold them ([`device-detection/fiftyone.devicedetection.onpremise/deviceDetectionOnPremise.js` lines 93 to 172 at cdbbee8](https://github.com/51Degrees/51degrees-node/blob/cdbbee828ec2e2af1b48209a7deb95a660c64570/device-detection/fiftyone.devicedetection.onpremise/deviceDetectionOnPremise.js#L93-L172)). Their metadata differed from the specification's in three ways.
…ice Detection one does (#131) The IP Intelligence on-premise getting started web example builds its Pipeline with usage sharing turned off ([`ip-intelligence/fiftyone.ipintelligence.onpremise/examples/onpremise/gettingstarted-web/gettingStarted.js` line 122 at 6d5d4fe](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/ip-intelligence/fiftyone.ipintelligence.onpremise/examples/onpremise/gettingstarted-web/gettingStarted.js#L122)), though the example's own `51d.json` lists the usage sharing element. The Device Detection on-premise web example shares usage through its `51d.json` ([lines 13 to 23](https://github.com/51Degrees/51degrees-node/blob/6d5d4fef292afffffae3e7892d3e8c043f1b22c7/device-detection/fiftyone.devicedetection.onpremise/examples/onpremise/gettingstarted-web/51d.json#L13-L23)), and every console example turns it off.
…get one (#133) A person who runs a cloud example from a fresh clone has no resource key set. Every cloud example should then end without an error, name the environment variable to set, give a tagged link to the page where a key is created, end with its Find out more section and exit with status 0, so that CI can run it with no settings. At `rc` 6d5d4fe, 11 of the 20 cloud examples did not.
…e it is in (#143) At `rc` 1ed293b the JSON Builder worked out which Properties of each element have delayed execution once, from the first Pipeline it processed, and used that for every Pipeline after ([`pipeline/fiftyone.pipeline.core/jsonbundler.js` lines 145 to 155](https://github.com/51Degrees/51degrees-node/blob/1ed293b2876f39853c93f4a83291d531b293cffe/pipeline/fiftyone.pipeline.core/jsonbundler.js#L145-L155) and [lines 207 to 213](https://github.com/51Degrees/51degrees-node/blob/1ed293b2876f39853c93f4a83291d531b293cffe/pipeline/fiftyone.pipeline.core/jsonbundler.js#L207-L213)). One JSON Builder can be added to several Pipelines, as any element can, so in a second Pipeline:
…ight and rawWeight for this release (#139) The JSON Builder writes a Property's value as the Element Data gives it ([`pipeline/fiftyone.pipeline.core/jsonbundler.js` line 271 at 7c99e78](https://github.com/51Degrees/51degrees-node/blob/7c99e7802ea3fa564c360d13af94332511ffdda1/pipeline/fiftyone.pipeline.core/jsonbundler.js#L271)), with only a list of Element Data rewritten ([lines 242 to 246](https://github.com/51Degrees/51degrees-node/blob/7c99e7802ea3fa564c360d13af94332511ffdda1/pipeline/fiftyone.pipeline.core/jsonbundler.js#L242-L246)). So each item of a weighted value in the JSON sent to the browser has the members the Element Data uses, `value`, `weight` and `rawWeight` ([`ip-intelligence/fiftyone.ipintelligence.onpremise/swigHelpers.js` line 59](https://github.com/51Degrees/51degrees-node/blob/7c99e7802ea3fa564c360d13af94332511ffdda1/ip-intelligence/fiftyone.ipintelligence.onpremise/swigHelpers.js#L59)), where the specification writes `rawweighting` and `value`, in lower case. A cloud weighted value carries `rawweighting` as well since [#124](#124), and an on-premise one does not.
…sharing's sessions apart (#145) With session tracking on, usage sharing compares a request with those already shared using the values it would share and the session cookie ([`pipeline/fiftyone.pipeline.engines.fiftyone/shareUsage.js` lines 263 to 276 at 0e89a40](https://github.com/51Degrees/51degrees-node/blob/0e89a4009ae74a42eef36110c1f88262cf616c4b/pipeline/fiftyone.pipeline.engines.fiftyone/shareUsage.js#L263-L276)). Those values come from the Evidence and from the web request supplied as `server.http-request` ([lines 289 to 313](https://github.com/51Degrees/51degrees-node/blob/0e89a4009ae74a42eef36110c1f88262cf616c4b/pipeline/fiftyone.pipeline.engines.fiftyone/shareUsage.js#L289-L313)), as the specification asks. The only test of session tracking, in `shareUsage.test.js`, gives the session cookie as Evidence, so nothing showed that a cookie found only in the web request is read too.
…ers result (#146) At `rc` 0e89a40 `Helpers.setResponseHeaders` read the Set Headers element's result as `flowData['set-headers']` ([`pipeline/fiftyone.pipeline.core/helpers.js` line 183](https://github.com/51Degrees/51degrees-node/blob/0e89a4009ae74a42eef36110c1f88262cf616c4b/pipeline/fiftyone.pipeline.core/helpers.js#L183)), which throws when the Flow Data has no such result ([`flowData.js` lines 188 to 208](https://github.com/51Degrees/51degrees-node/blob/0e89a4009ae74a42eef36110c1f88262cf616c4b/pipeline/fiftyone.pipeline.core/flowData.js#L188-L208)), for example when an element stopped processing before the Set Headers element ran. The Device Detection getting started web examples call it inside `flowData.process().then(...)` with no `catch` ([on-premise `gettingStarted.js` line 268](https://github.com/51Degrees/51degrees-node/blob/0e89a4009ae74a42eef36110c1f88262cf616c4b/device-detection/fiftyone.devicedetection.onpremise/examples/onpremise/gettingstarted-web/gettingStarted.js#L268), [cloud `gettingStarted.js` line 267](https://github.com/51Degrees/51degrees-node/blob/0e89a4009ae74a42eef36110c1f88262cf616c4b/device-detection/fiftyone.devicedetection.cloud/examples/cloud/gettingstarted-web/gettingStarted.js#L267)), so code written the same way meets an unhandled rejection, which ends a Node.js process by default.
…rs hear (#141) Usage sharing logged its six warnings at the level `'warning'` ([`pipeline/fiftyone.pipeline.engines.fiftyone/shareUsage.js` lines 393, 522, 565, 586, 603 and 609 at a2aef52](https://github.com/51Degrees/51degrees-node/blob/a2aef527e72caad6f2ba0cf46c1ca3a0a35c23b9/pipeline/fiftyone.pipeline.engines.fiftyone/shareUsage.js#L393-L609)), being a full queue, a pause and its delay, and each failed send. The Pipeline emits a log entry as an event named by its level ([`pipeline.js` line 236](https://github.com/51Degrees/51degrees-node/blob/a2aef527e72caad6f2ba0cf46c1ca3a0a35c23b9/pipeline/fiftyone.pipeline.core/pipeline.js#L236)), and the levels callers listen for are `info`, `debug`, `warn` and `error`, as the examples say (for example [`nativeModelLookup.js` line 142](https://github.com/51Degrees/51degrees-node/blob/a2aef527e72caad6f2ba0cf46c1ca3a0a35c23b9/device-detection/fiftyone.devicedetection.cloud/examples/cloud/nativemodellookup-console/nativeModelLookup.js#L142)), and as every other element warns. So none of those warnings reached a caller listening for warnings. The tests of the back-off replaced the element's `_log` and read what it was given, so they never saw that no listener heard it.
…150) At `rc` d4f2615, with `minify: true` the JavaScript Builder gave its script unminified. It called `uglifyJS.minify` and used the result only when `minified.error === null` ([`pipeline/fiftyone.pipeline.core/javascriptbuilder.js` lines 418 to 423](https://github.com/51Degrees/51degrees-node/blob/d4f26155f50aaf7b518c3efbd4fcecc76b2bedca/pipeline/fiftyone.pipeline.core/javascriptbuilder.js#L418-L423)), but uglify-js leaves `error` undefined when minifying succeeds, as [its README at 111746bb](https://github.com/mishoo/UglifyJS/blob/111746bbae5f55c88e3b82b42f14fd0f3129ea53/README.md?plain=1#L396) says (``console.log(result.error); // runtime error, or `undefined` if no error``). So the minified code was never used, and a failure to minify was not reported either. No test ran the builder with `minify` on, as `javascriptbuilder.test.js` only checks that it is off by default.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Releases what has collected on
rcsince the last release, #83, which merged intomainon 13 November 2026 at 10:49 UTC. Its Publish run 43412143722 failed in one example test before it published anything, so npm still has 4.5.102 of every package, and this release takes #83's changes to npm too. Everything below "Before you upgrade" that #83 listed is listed here again, because no one has had it yet.This is the first release in which each package has its own version (#37). A package is released when its own code changed since its last release, or when a package it depends on is released, and only the patch number moves. Since 4.5.102 every package has changed or depends on one that has, so all 16 are released, each at 4.5.103.
This release comes three days after #83 merged, sooner than the week common-ci's CONTRIBUTING.md asks between releases, by James Rosewell's decision of 13 November to release every 51Degrees repository on Monday 16 November. npm last had a release of these packages on 4 November, so the Publish workflow's weekly check, which counts from each package's last release, does not refuse it.
This release moves Node.js toward one behavior across every 51Degrees language. Each element it changes now follows the published 51Degrees specifications, which in turn follow the RFCs they cite, so that the same input gives the same answer in .NET, Java, Node.js, Python, PHP, Go, Rust and C. The native modules take the C library release 51degrees-cxx 4.5.106, whose C code is that of 4.5.105.
Before you upgrade
performanceProfilenow defaults to'Balanced', where it was'LowMemory', andupdateMatchedUserAgentis now on. SetperformanceProfile: 'LowMemory'andupdateMatchedUserAgent: falseto keep the old behavior (#42).PipelineBuildernow adds the Sequence Element first, so only a Pipeline built withaddSequenceElement: false, or one that addsJSONBundlerElementby hand, is affected (#53, #74).sequenceentry, which holdssession-idandsequence. A request with a session id and no sequence now gets sequence 1, where it got 2 (#59).resource,license,licenceandvalues, which it writes itself. Before, it sent only the Evidence that a Flow Element in the Pipeline accepted, so do not add Evidence that must not reach the cloud service (#72).51D_ones. It shared every cookie. It now shares a cookie only when its name starts51D_, whatever the settings,shareAll: trueincluded, and never theCookieheader. WithtrackSessionon, the session cookie named bycookieis read for the repeat check and is not sent unless its name starts51D_. Every query string and form value is still shared by default. To share only those whose names start51D_or are inqueryWhitelist, set the new optionshareAllQueryStringParameters: false(#35, #45, #135).evidenceKeyFilteraccepted every key and now accepts none, andflowData.evidence.getgivesundefinedfor a key that no element accepts. Give the elementevidenceKeyFilter: new BasicListEvidenceKeyFilter([...])with the keys it reads (#45).Error during check for data update, so a log search or alert on the old text needs to change (#69).Areas, so18.542741172521133is now18.543(#62).1.2.3.4/24,1.2.3.4, 5.6.7.8and01.2.3.4were read and are now skipped. Pass one address in each value (#67).propertieskeeps the first Data File's Properties across every data update. A Property that only a later Data File holds has no value until the Engine is created again (#55).protocolother thanhttporhttps, anobjNamesuch aswindowordocument(#31, #60), and a Translation Enginebehaviorthat names none ofOriginal,EmptyStringorFlowError(#49).INVALID_BASE64.FodId.toStandardBase64returnsnullfor such a text, so a TypeScript caller needs to handlenull(#40, #56).query,header,cookie,server,fiftyone,location, and compares prefixes and names ignoring letter case, soheader.User-Agentandquery.user-agentare sent as one field (#75)._51DEGREES_CLOUD_ENDPOINTreplacesFOD_CLOUD_API_URL, which still works in this release. The Cloud Request Engine and the 51Did client read_51DEGREES_CLOUD_ENDPOINT, and readFOD_CLOUD_API_URLonly when the new name is unset or empty. An engine whose endpoint came from the old name logs one warning to its Pipeline, and the first 51Did client that uses it raises one NodeDeprecationWarningfor the process. ThebaseURLandendpointoptions still come first. Set_51DEGREES_CLOUD_ENDPOINTto the same value as the old name (#77, #88).^, so a caller that pins everyfiftyone.*package to one number should pin each to its own (#37).lib.fiftyone.devicedetection.sharedandfiftyone.ipintelligence.sharedmoved the modules theirindex.jsexports out ofexamplesandtests. Arequireof an old path, such asfiftyone.devicedetection.shared/tests/keyUtils, still works, as each old file now re-exports the module inlib. The generatedtypesare only undertypes/lib(#37).delayexecutiononly on a Property with a value, as the JSON Builder specification asks, so a Property with no value no longer carries it (#66).If-None-Matchbefore processing. CallHelpers.writeClientSideNotModified(request, response, flowData, options)once the evidence is added and stop when it returns true, as every web example now does. Without it a revalidation is still answered correctly but processed first. A 304 sent while processing records errors now carriesCache-Control: private, max-age=<max-age>, the Vary header and the ETag of a good response, where it carriedprivate, no-cacheand no ETag (#120).FodId's raw flags byte_flagsis deprecated. Readtype,usageandusageIsIndirect, which name its bits. A later release removes it (#115, #128).HardwareProfileCloudEnginefrom the Device Detection cloud package now has its real type, where a caller that skips checking type files gotany, so that caller's use of it is now checked (#113).profiles, as plain lower-case values, with null and anullreasonfor a Property with no value, where it wrote each Property's_value,hasValueandnoValueMessage. With no Sequence Element in the Pipeline, the script carries an empty session id and a sequence of 1, where it carried the evidence's (#118).weightandrawWeight, as the on-premise engine's values do.rawweightingis still there and deprecated, so readrawWeightin new code (#124, #138).query.sequenceadded as a JavaScript number now counts as absent. The Sequence Element counts a given sequence only when it is aBigIntor text made only of digits, from 0 up to 2,147,483,646, so an application that addsquery.sequenceitself as a number now gets a sequence of 1. Add the text of the number, as a query string gives it, or aBigInt. A web integration that hands over the request sees no change (#134).pipeline.flowElements. Code that changed a list given toaddParallelornew Pipeline,flowElementsChainorpipeline.flowElementsafter the build needs to build a new Pipeline instead. A method that changesflowElementsChainnow throws aTypeError, and so does a change topipeline.flowElementsin strict mode code (#142).weightandrawWeighton each weighted item in the JSON sent to the browser are deprecated. Each item now also carriesrawweightingandvalue, as the specification writes them, so read those. A later release removesweightandrawWeight(#139, #147).errorsarray has entries now fails the request, whatever its HTTP status, with an error for each entry, and the error messages name the URL the request went to. A log search or alert on "No data in response from cloud service" or "Cloud service returned status code" needs to change, and a failed answer that is not JSON gives the status code message, not "Error parsing response" (#140).'warn', as every other element's are, and at'warning'as well, which is deprecated. Listen withpipeline.on('warn', ...). A later release stops emitting'warning'(#141, #149).minify: truenow minifies the client script. It never did, as the JavaScript Builder threw the minified script away. Minifying takes time on every request for the script, so measure it before keeping the setting (#150, #132).What changes
Packages and versions
<package>/<version>in this repository with one GitHub release for each, and the Publish workflow releases only the packages that changed since their last tag, with every package that depends on one of them. A change only to documentation, tests, examples, or a manifest'sdescription,keywordsor links releases nothing (#37).fiftyone.pipeline.corepacks only the template its JavaScript Builder reads,JavaScriptResource.mustache, and not the rest of the JavaScript templates repository, its tests, workflows, README and licence (#106).fiftyone.pipeline.didcarries the OWID library as a submodule and packs only itsv1.jsand its licence, where it installed OWID from GitHub as a bundled dependency, so installing the package needs no access to GitHub (#107).npm run tsc, so they match the code, and each package's types compile for a TypeScript caller (#113).Web integration and client-side caching
Helpers.writeClientSideResponsewrites the response of a client-side JavaScript or JSON endpoint withCache-Control,Varyand an ETag. Node.js has no web integration package, so call it from your own endpoints, as the web examples do (#44).The ETag is a weak entity tag,
W/"...", andIf-None-Matchis compared weakly, as RFC 9110 section 8.8.3 and section 13.1.2 ask. A match gets 304 for GET and HEAD, and 412 for any other method. A response to a request whose processing failed hasCache-Control: private, no-cacheand no ETag. The same Evidence gives the same ETag in every process (#44).Evidence.addFromRequestadds the web request as a read-only view underserver.http-request(#45).Helpers.writeClientSideNotModifiedanswers a request whoseIf-None-Matchmatches before the Pipeline processes it, with 304 for GET and HEAD and 412 for any other method, as the web integration specification asks. A 304 carries a good response'sCache-Control, Vary and ETag, during an outage too, andwriteClientSideResponsegives a matching request the same answer (#120).A Set Header Property's identifier may hold digits and other characters, and the header name starts at the next upper-case letter, so
SetHeaderBrowser2Accept-CHsetsAccept-CH(#120).PipelineBuilderadds the Sequence Element, the JSON Builder, the JavaScript Builder and the Set Headers Element only where the Pipeline has none with that key, compared ignoring case, so one the caller added is the one used, and building twice adds none of them twice (#105).JavaScript Builder
The JavaScript Builder checks the callback URL before it writes it into the client script. The protocol must be
httporhttps, and the host must be ASCII labels or an IPv6 address in brackets, with no user information, query, fragment or zone identifier, following RFC 3986. A URL from the request that fails is left out of the script and logged (#31, #51).The script always carries the page request's query parameters, whether or not the builder has a callback URL, as step 7 of the JavaScript Builder specification asks (#97).
The script takes its session id and sequence from the Sequence Element's data, with sequence 1 and no session id where there is no Sequence Element, and the JSON writes each item of a list of Element Data by the same rules as the Element Data's own Properties (#118).
The JSON sent to the browser writes each item of a weighted value with
rawweightingandvalue, keepingweightandrawWeightbeside them for this release (#139).Evidence
header.User-Agentandheader.user-agentare one key, andflowData.device.get('IsMobile')works in any letter case (#71, #68).flowData.get('Device')andflowData.Devicework asflowData.devicedoes (#122).query.sequenceonly when it is aBigIntor text made only of digits, from 0 up to 2,147,483,646. Any other value gives a sequence of 1 (#134).Cloud
licenseKey. With a License Key alone the Properties wanted must be named withrequestedProperties. Both keys now travel in the request body (#64).*. The packages mask a key where one can enter a message, so the mask no longer runs on each detection, andPipeline.logpasses the message it is given to its listeners unchanged (#58, #85).cacheSizesets (#57).warningsarray, from discovery or processing, is logged as a warning with any License Key masked, and a product the Resource Key does not include is logged once for each engine at warning level (#123).value,weightandrawWeight, as the on-premise engine does, keeping the service'srawweightingbeside them for this release (#124).errorsarray has entries, fails the request with the specification's messages, which name the URL (#140).Usage Sharing
Varyheader. The Flow Data still keeps what Usage Sharing shares.evidence.addkeeps a value when a Flow Element accepts its key or when Usage Sharing would share it. An application that adds its own Evidence therefore has nothing to change, and the values it adds are shared under the same rules as the values of a request.evidence.addFromRequestalso adds the whole request asserver.http-request, which isConstants.evidenceHttpRequestinfiftyone.pipeline.core, a frozen object that holds each value of the request under the key it has as Evidence. Read it withevidence.get('server.http-request').evidence.getAll()leaves it out, and it is never shared whole (#45).trackSessionoption tells sessions apart (#36, #35).fiftyone.pipeline.core, where every release wrote 4.4.7, so the spread of a release can be measured. The session id and sequence are recorded as SessionId and Sequence whatever the letters of their keys (#109).escaped="true", where it wasreplaced="true", and cuts a value at 10,000 code points, where it was 512 characters (#54).shareAllQueryStringParametersoption, true unless set to false, shares every query string and form value. Set to false, only the names that start51D_and those inqueryWhitelistare shared. No cookie but51D_ones is shared,shareAllincluded (#135).Data updates
Data update log entries and errors use the text and levels of the specification's error table, which every language now shares. Every check reports a status, and an
updateCompletelistener that throws is logged (#69).With
updateOnStartand a License Key or an update URL, an on-premise Engine downloads a missing Data File, where the build threw.DataFileUpdateService.updateFromMemoryis new (#52).The file system watcher runs on its own
fileSystemWatchersetting, whether automatic updates are on or not, and needs no License Key. This reverses a change onrcthat made the watcher wait for automatic updates, and so for a License Key (#52), which was a mistake. That change never reached npm, so the watcher behaves as in 4.5.102 (#90).A data file has one polling timer. An update started by hand with
updateDataFilereplaces the waiting timer rather than adding another, so the file is checked once in each polling interval however many updates are started (#63).Device Detection and IP Intelligence
IsMobileon Ubuntu ARM with Node.js 22 (run 42995016804, #68). The IP Intelligence engine was timed on its own as well, and a read by name took about a third of the time of a read by position on Ubuntu x64 and ARM (run 43487633019, #81).51Did
Translation
TranslationEngineaccepts the specification's option names,sourceElementDataKeyandmissingTranslationBehavior.sourceDataKeyandbehaviorstill work and are deprecated (#49).C library
51D_GetHighEntropyValuesand51D_StructuredUserAgentthe query value is used before the cookie value (#67, #55, #92).Configuration
restrictedPropertiesand usage sharing'squeryWhitelistandheaderBlacklistread it as its items, through the newlistSettingoffiftyone.pipeline.core, and an array works as before (#129).Examples and documentation
51d.jsonnames its engines by package, so the same file works in this repository and with the installed packages, where eleven named them by a path into the source (#110)._51DEGREES_LICENSE_KEYfirst. The cloud metadata example says a resource key is needed when none is set, and the match metrics example prints a documentation link a person can follow (#101).fiftyone.pipeline.cloudrequestenginehas the star sign Cloud Engine example the pipeline specification asks for, using the real Cloud Request Engine against a star sign service it starts on the same machine, so it needs no key or network. The simple star sign example takes a date of birth as its argument (#121).51d.jsondoes and as the Device Detection one does, with a comment saying production should leave usage sharing on. The console examples still turn it off (#131)._51DEGREES_RESOURCE_KEY, gives a tagged link to where a key is created and ends with its Find out more section, and a test runs each of the 20 with no key (#133).configure.51degrees.com(#87).LICENSEfile at its root, the EUPL 1.2 text, and every JavaScript source file carries the standard 51Degrees header. Thefiftyone.geolocationpackage no longer carries aLICENSEfile of its own (#79).Building and testing
dotnetwas missing and the step reported a pass without running a test. The step now fails whendotnetis missing or when no test passed, and a pull request intorcis built on the configurations its changes need, with macOS and the performance tests left to builds ofrcand the release (#27).allow-early-release, for a release agreed to go out less than a week after the last, andcommon-ci-ref, to run common-ci's steps from a branch other thanmain(#99).rcas well asmain, so a change to the 51Did package is tested against the live cloud service before it reaches a release (#100).AGENTS.mdsays that a test failing on timing is fixed rather than run again, and points at common-ci's one list of environment variable names (#93, #89).Environment variables
Each name below has a new name that starts
_51DEGREES_, which every shell can set. The Cloud Request Engine and the 51Did client read the cloud endpoint, and the examples and tests read the rest. Every old name is still read in this release, but only when its new name is unset or empty, and its first use is reported as deprecated, through the Pipeline's logger or aDeprecationWarningin the packages, and in a printed message in the examples and tests. Each constant that held an old name holds it again and is marked@deprecated(#70, #77, #88).FOD_CLOUD_API_URL_51DEGREES_CLOUD_ENDPOINT51DEGREES_DD_PATH_51DEGREES_DD_PATH51DEGREES_IPI_PATH_51DEGREES_IPI_PATH51DEGREES_RESOURCE_KEY,RESOURCE_KEY_51DEGREES_RESOURCE_KEYLICENSE_KEY_51DEGREES_LICENSE_KEYLicenseKey,LICENSEKEY(the update data file examples)_51DEGREES_LICENSE_KEYTEST_SUPER_RESOURCE_KEY,TEST_PLATFORM_RESOURCE_KEY,TEST_HARDWARE_RESOURCE_KEY,TEST_BROWSER_RESOURCE_KEY,TEST_NO_SETHEADER_RESOURCE_KEY_51DEGREES_RESOURCE_KEY_SUPER,_51DEGREES_RESOURCE_KEY_PLATFORM,_51DEGREES_RESOURCE_KEY_HARDWARE,_51DEGREES_RESOURCE_KEY_BROWSER,_51DEGREES_RESOURCE_KEY_NO_SETHEADERFixed
delayexecutionandevidencepropertiesfor every element but one, because the JSON Builder kept each element's delayed Properties under one shared key (#66).updateDataFilestarted another polling timer for the same data file each time, so the file was checked once for each of them in every polling interval (#63).renderedParametersreturned nothing, and the script then threw aTypeErroron a page whose tab held a record of an earlier request and values saved from it (#97).ReferenceError: resourceKey is not defined, and now read the key as the other examples do (#95).TypeError: Cannot convert undefined or null to objectwhen the Resource Key did not include its product. One error is now logged for each Engine and the request carries on (#41).updateCompletelistener that threw ended the Node.js process (#65).<Device>elements of a message, logged a failed send asUsage data sent, and wrote<ClientIP>undefined</ClientIP>for a request with no client IP (#35, #36, #54).nulluntil known (#104).RangeError: Maximum call stack size exceededwhile they searched for a Data File (#32).flowData.get('Device')andflowData.Devicethrew whereflowData.deviceworked (#122).index.jsrequired its own files through..(#113).TypeErrorforrestrictedPropertiesandheaderBlacklist, and was split into single characters forqueryWhitelist(#129).addParallelstayed the caller's list, so an element added to it after the build was processed by the built Pipeline, and one taken out was not (#142).errorsmember threw aTypeError(#140).warning, which no example or document listens for (#141).Helpers.setResponseHeadersthrew when processing stopped before the Set Headers element, which ended the process where it was called in a promise with nocatch, as the getting started web examples do. It now sets no headers and logs a warning (#146).minify: truethe JavaScript Builder gave its script unminified, because it used the minified script only when uglify-js reportederrorasnull, where uglify-js leaves it undefined. A failure to minify is now logged as a warning (#150).Issues this closes
mainwith Release candidate #83.Build
The release build, the timing against
main, the Publish dry run and the Nightly Pipeline dry run on this head are running, and this section is filled in from them when they end.Only the patch number moves.