Skip to content

FEAT: 51Did four platform and browser factors, usageIsIndirect and refusing usage bits 000 - #202

Merged
Automation51D merged 5 commits into
mainfrom
feat/cloud-438-and-usage-indirect
Sep 19, 2026
Merged

Automation51D merged 5 commits into
mainfrom
feat/cloud-438-and-usage-indirect

Conversation

@jwrosewell

@jwrosewell jwrosewell commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Summary

This brings the 51Did package (fiftyone.pipeline.did) up to cloud release 4.4.38 and to the flags byte rules in specifications pull request 30, which is still a draft. This is a breaking change with no alias, so the next release of these packages is a minor version rather than a patch. The latest published version on npm is 4.5.47, so the next one is 4.6.0. The version comes from GitVersion, which reads the commit messages since the last tag, so this branch carries an empty commit whose message is +semver: minor and nothing else needs changing.

  1. Four platform and browser factors. Cloud release 4.4.38 replaced the single browser creator context factor with platformname, platformversion, browsername and browserversion. A new frozen Factor constant (exported from the package) lists the nine factor names in the order the cloud lists them. RedeemResult.factors and toJSON() keep every factor name exactly as the cloud sends it, as before and as the other 51Did packages do, so a factor the cloud adds later reaches callers without a package release, and an older service's browser key stays under its own name rather than filling any of the four.
  2. usageFromConsent is renamed to usageIsIndirect, with no alias. The documentation now describes bit 3 as direct against indirect, with a consent string as the only indirect signal today.
  3. Usage bits 000 are refused at parse. Usage.NONE is removed, so Usage has exactly three values. A payload whose usage bits are all clear is refused with the new FodId.ParseStatus.NO_USAGE ('NoUsage'). The throwing surfaces throw a RangeError carrying that status, with a message naming the bits (51Did payload carries usage bits 000, which is not a usage.), which follows the pattern already used for an unknown payload version. The version is still checked first, so a later version with usage bits 000 is still reported as UNSUPPORTED_PAYLOAD_VERSION. Usage.fromFlags throws a RangeError for 000, and Usage.name and Usage.idUsage answer null for a value that is not a Usage. The patterns 010, 100, 101 and 110 read as before, and the payload version stays 0.

The creator context section is now 28 bytes. The reader applies only a lower bound to the payload length, so reading is unchanged. No fixture in this package builds a context section of a fixed size, and the live identifiers below have 66 byte payloads (37 + 1 terms byte + 28) and read correctly. No file in this package emits the PMP script tag, so nothing needed changing for the path-only PMP tag.

Files changed

File Change
fiftyone.pipeline.did/fodId.js usageFromConsent renamed to usageIsIndirect with new documentation. ParseStatus.NO_USAGE added, and the payload walk refuses usage bits 000 after the version check. The RangeError message names the bits
fiftyone.pipeline.did/usage.js NONE removed. fromFlags throws for 000. name and idUsage answer null for a value that is not a Usage
fiftyone.pipeline.did/didClient.js New Factor constant. RedeemResult.factors documented with the nine names, and still passes every name through unchanged
fiftyone.pipeline.did/index.js Exports Factor
fiftyone.pipeline.did/fodIdParseError.js Comment now says four payload statuses rather than three
fiftyone.pipeline.did/types/*.d.ts Generated again with tsc from the changed source
fiftyone.pipeline.did/readme.md Usage table without NONE, the refusal explained, usageIsIndirect described, NO_USAGE added to the status and thrown tables, the factors list updated and a paragraph on the four factors saying names pass through unchanged
fiftyone.pipeline.did/examples/fodIdExample.js Prints usageIsIndirect
fiftyone.pipeline.did/tests/fodId.test.js New tests (below). Existing tests that used usage bits 000 by accident (Reserved type fixtures, the zero flags byte test) now set bit 0, and the version test expects NO_USAGE for 000 under version 0
fiftyone.pipeline.did/tests/didClient.test.js The mismatch fixture uses the four new factors. New factor tests (below). A short Reserved payload fixture sets bit 0
fiftyone.pipeline.did/tests/didClient.integration.test.js Uses usageIsIndirect

Tests added

  • usage bits 000 are refused for the <type> type, and the refusal names them, for all four types, with bit 3 clear and set, through tryParse, tryFromByteArray and fromBase64.
  • Usage has exactly the three usages.
  • usage is indirect is bit three, and flags <n> answer usage is indirect <bool>, and only from bit three for bits 3 set and clear on each usage.
  • the old usage from consent name is gone, with no alias.
  • the four platform and browser factors are read into their names.
  • the factor names are the nine the cloud lists, in its order, which tests the Factor constant.
  • an old browser factor populates none of the four, and is kept, which checks that none of the four new names is set and that browser is still present under its own name.
  • a factor name this package does not list is passed through.

In the first commit, with only the source files stashed (usage.js, fodId.js, didClient.js, index.js, fodIdParseError.js), all 16 new test cases then present failed (Tests: 16 failed, 161 skipped, 177 total), and with the source change all 16 passed (Tests: 161 skipped, 16 passed, 177 total). The second commit restores the pass-through of factor names, as main already did, and adds the pass-through test.

Unit tests (fiftyone.pipeline.did only, live tests skipped)

Before, on main:

Test Suites: 1 skipped, 3 passed, 3 of 4 total
Tests:       4 skipped, 163 passed, 167 total

After:

Test Suites: 1 skipped, 3 passed, 3 of 4 total
Tests:       4 skipped, 178 passed, 182 total

ESLint on the changed files reports 0 errors. The warnings it reports are the same JSDoc style warnings as the rest of the package.

Live check against https://cloud.51degrees.com

I created a probabilistic identifier with id.usage=standard (both the global and the licensed one) and read each one with this branch.

Field Global Licensed
tryParse status Parsed Parsed
type Probabilistic Probabilistic
usage Standard (standard) Standard (standard)
usageIsIndirect false false
terms https://m4ow.uk/mtm/2.txt https://m4ow.uk/mtm/2.txt
Envelope version, payload bytes 3, 66 3, 66
verifySignature (published keys, offline) true true
verify (cloud id/verify) true true
verify-full HTTP 200, sealed result HTTP 200, sealed result
redeem HTTP 200, context unreadable, no factors HTTP 200, context unreadable, no factors

The redeem answered unreadable because the account holds licence keys and the check sent none. The redeem endpoint answers unreadable in that case by design, so the four live factors were not seen in this run. They are covered by the unit tests above.

The live integration test file also passes against the service with this branch (Tests: 4 passed, 4 total), including Terms checked on 4 marketing identifier(s). and Usage is indirect read on 4 identifier(s)., which shows that identifiers created from a consent string read usageIsIndirect as true.

Outstanding

  • ContextResult.NOT_CHECKABLE ('notcheckable') is still listed in didClient.js and in the readme's redeemed.context comment, and that comment does not list misconfigured or invaliddate. Release 4.4.38 lists only verified, mismatch, nocontext, misconfigured and invaliddate for redeem. This pull request leaves that alone.
  • The readme usage example destructures Terms from the package, which the package does not export. Fixed by the third commit, DOC: Drop Terms from the readme usage example, as the package does not export it. The example only ever read fodId.terms, so nothing else changed.

The same change in the other ports

The Java port of this change is
pipeline-java#140,
which makes the same rename, refuses the same usage bits and reads the same
four factors.

Overlap with other work in this repository

#208 changes the same
demo (examples/creator-context-web/). The two were merged locally in both
directions and both merges are clean.

CI evidence for the head commit

main has been merged into this branch and the +semver: minor commit sits on
top, so the head is 5e67566. The "Pull Requests" workflow was dispatched on
that head with dryrun=true, which builds the branch and merges nothing. Run
35267773922
concluded success with all 13 jobs green. In the Ubuntu_Node_24 job the
unit tests give Test Suites: 25 passed, Tests: 361 passed and the integration
tests Test Suites: 2 passed, Tests: 6 passed, with no error lines anywhere in
the log. The four 51Did suites, didClient.test.js, fodId.test.js,
creatorContextServer.test.js and didClient.integration.test.js, all pass.

…ect and refuse usage bits 000

Cloud release 4.4.38 replaced the single browser factor of the creator
context with platformname, platformversion, browsername and
browserversion. RedeemResult.factors now carries only the nine factor
names in the new Factor constant, in the order the cloud lists them, so
the old browser key is no longer read into it. The body as sent stays in
raw.

The flags byte rules in specifications pull request 30 are applied.
FodId.usageFromConsent is renamed to FodId.usageIsIndirect with no alias,
and its documentation now says direct against indirect, with a consent
string as the only indirect signal today. Usage.NONE is removed, and a
payload whose usage bits are all clear is refused with the new
ParseStatus.NO_USAGE, thrown as a RangeError naming the bits by the
throwing surfaces. The patterns 010, 100, 101 and 110 read as before.

The readme, the example and the generated types follow.
RedeemResult.factors and toJSON pass every factor name through unchanged again, as the other 51Did packages do, so a factor the cloud adds later reaches callers without a package release and an older service's browser key stays under its own name. The Factor constant still lists the nine names in the cloud's order.
…t export it

The 51Did readme's usage example destructured Terms from the package,
which index.js has never exported, so the line as written gives undefined
and misleads anyone copying it. The example only ever reads fodId.terms,
so nothing else changes.
@jwrosewell
jwrosewell marked this pull request as ready for review September 17, 2026 20:10
@jwrosewell
jwrosewell marked this pull request as draft September 17, 2026 20:39
@jwrosewell
jwrosewell marked this pull request as ready for review September 18, 2026 06:44
@Automation51D
Automation51D merged commit 8767f6b into main Sep 19, 2026
14 checks passed
@Automation51D
Automation51D deleted the feat/cloud-438-and-usage-indirect branch September 19, 2026 02:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants