@registrystack/client 0.43.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,140 @@
1
+ 'use strict';
2
+
3
+ const { types: { isProxy } } = require('node:util');
4
+ const native = require('./index');
5
+
6
+ const MAX_JSON_DEPTH = 64;
7
+ const MAX_JSON_NODES = 20_000;
8
+ const MAX_JSON_STRING_BYTES = 1024 * 1024;
9
+
10
+ class CoordinatorClientError extends Error {
11
+ constructor(envelope) {
12
+ super(envelope.message);
13
+ this.name = 'CoordinatorClientError';
14
+ this.kind = envelope.kind;
15
+ this.outcomeUnknown = envelope.outcomeUnknown === true;
16
+ for (const field of ['code', 'status', 'transportKind', 'protocolFailure']) {
17
+ if (envelope[field] !== undefined && envelope[field] !== null) this[field] = envelope[field];
18
+ }
19
+ }
20
+ }
21
+
22
+ const FALLBACK_MESSAGES = {
23
+ configuration: 'Coordinator client configuration is invalid',
24
+ 'invalid-request': 'Coordinator client arguments are invalid',
25
+ protocol: 'Registry Coordinator client failed',
26
+ };
27
+
28
+ function normalized(error, fallbackKind) {
29
+ if (error instanceof CoordinatorClientError) return error;
30
+ if (error instanceof Error && typeof error.message === 'string') {
31
+ try {
32
+ const envelope = JSON.parse(error.message);
33
+ if (envelope && typeof envelope.kind === 'string') return new CoordinatorClientError(envelope);
34
+ } catch {
35
+ // napi argument conversion errors have no mapped envelope.
36
+ }
37
+ }
38
+ if (fallbackKind) {
39
+ return new CoordinatorClientError({
40
+ kind: fallbackKind,
41
+ message: FALLBACK_MESSAGES[fallbackKind],
42
+ outcomeUnknown: fallbackKind === 'protocol',
43
+ });
44
+ }
45
+ return error;
46
+ }
47
+
48
+ function cloneJson(value, budget, depth, kind) {
49
+ if (depth > MAX_JSON_DEPTH || ++budget.nodes > MAX_JSON_NODES) throw normalized({}, kind);
50
+ if (value === null || typeof value === 'boolean') return value;
51
+ if (typeof value === 'string') {
52
+ budget.bytes += Buffer.byteLength(value, 'utf8');
53
+ if (budget.bytes > MAX_JSON_STRING_BYTES) throw normalized({}, kind);
54
+ return value;
55
+ }
56
+ if (typeof value === 'number') {
57
+ if (!Number.isFinite(value) || (Number.isInteger(value) && !Number.isSafeInteger(value))) {
58
+ throw normalized({}, kind);
59
+ }
60
+ return value;
61
+ }
62
+ if (value === undefined || typeof value !== 'object' || isProxy(value)) throw normalized({}, kind);
63
+ const array = Array.isArray(value);
64
+ const prototype = Object.getPrototypeOf(value);
65
+ if (array ? prototype !== Array.prototype : prototype !== Object.prototype && prototype !== null) {
66
+ throw normalized({}, kind);
67
+ }
68
+ if (budget.active.has(value)) throw normalized({}, kind);
69
+ budget.active.add(value);
70
+ try {
71
+ if (array) {
72
+ if (value.length > MAX_JSON_NODES - budget.nodes) throw normalized({}, kind);
73
+ const keys = Reflect.ownKeys(value);
74
+ if (keys.length !== value.length + 1) throw normalized({}, kind);
75
+ const result = new Array(value.length);
76
+ for (let index = 0; index < value.length; index += 1) {
77
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
78
+ if (!descriptor || !Object.hasOwn(descriptor, 'value')) throw normalized({}, kind);
79
+ result[index] = cloneJson(descriptor.value, budget, depth + 1, kind);
80
+ }
81
+ return result;
82
+ }
83
+ const result = Object.create(null);
84
+ for (const key of Reflect.ownKeys(value)) {
85
+ if (typeof key !== 'string') throw normalized({}, kind);
86
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
87
+ if (!descriptor || !Object.hasOwn(descriptor, 'value')) throw normalized({}, kind);
88
+ if (descriptor.enumerable) {
89
+ budget.bytes += Buffer.byteLength(key, 'utf8');
90
+ if (budget.bytes > MAX_JSON_STRING_BYTES) throw normalized({}, kind);
91
+ result[key] = cloneJson(descriptor.value, budget, depth + 1, kind);
92
+ }
93
+ }
94
+ return result;
95
+ } finally {
96
+ budget.active.delete(value);
97
+ }
98
+ }
99
+
100
+ function sanitize(value, kind) {
101
+ return cloneJson(value, { nodes: 0, bytes: 0, active: new WeakSet() }, 0, kind);
102
+ }
103
+
104
+ const NativeCoordinatorClient = native.CoordinatorClient;
105
+
106
+ class CoordinatorClient {
107
+ constructor(config) {
108
+ try {
109
+ this.native = new NativeCoordinatorClient(sanitize(config, 'configuration'));
110
+ } catch (error) {
111
+ throw normalized(error, 'configuration');
112
+ }
113
+ }
114
+ }
115
+
116
+ for (const [method, jsonIndexes] of [
117
+ ['start', [2]],
118
+ ['workflow', []],
119
+ ['status', []],
120
+ ['inspect', []],
121
+ ['reconcile', []],
122
+ ['list', []],
123
+ ['retrySame', []],
124
+ ['cancel', []],
125
+ ]) {
126
+ CoordinatorClient.prototype[method] = function (...args) {
127
+ try {
128
+ for (const index of jsonIndexes) {
129
+ if (args[index] !== undefined && args[index] !== null) {
130
+ args[index] = sanitize(args[index], 'invalid-request');
131
+ }
132
+ }
133
+ return this.native[method](...args).catch((error) => { throw normalized(error, 'protocol'); });
134
+ } catch (error) {
135
+ throw normalized(error, 'invalid-request');
136
+ }
137
+ };
138
+ }
139
+
140
+ module.exports = { CoordinatorClient, CoordinatorClientError };
@@ -0,0 +1,19 @@
1
+ /* auto-generated by NAPI-RS */
2
+ /* eslint-disable */
3
+
4
+ export declare class CoordinatorClient {
5
+ constructor(config: import('./client').CoordinatorClientConfig)
6
+ start(token: string, idempotencyKey: string, request: import('./client').StartRunRequest): Promise<import('./client').CoordinatorOutcome<import('./client').RunStatus>>
7
+ workflow(token: string, workflow: string): Promise<import('./client').CoordinatorOutcome<import('./client').WorkflowContract>>
8
+ status(token: string, runId: import('./client').RunId): Promise<import('./client').CoordinatorOutcome<import('./client').RunStatus>>
9
+ inspect(token: string, runId: import('./client').RunId): Promise<import('./client').CoordinatorOutcome<import('./client').RunInspection>>
10
+ reconcile(token: string, runId: import('./client').RunId, reason: string): Promise<import('./client').CoordinatorOutcome<import('./client').RunInspection>>
11
+ list(token: string, limit: number, cursor?: string | null, state?: import('./client').RunListState | null, attention?: boolean | null, proposal?: string | null, turn?: import('./client').ProposalTurn | null): Promise<import('./client').CoordinatorOutcome<import('./client').RunList>>
12
+ retrySame(token: string, runId: import('./client').RunId, reason: string): Promise<import('./client').CoordinatorOutcome<import('./client').RetryScheduled>>
13
+ cancel(token: string, runId: import('./client').RunId, reason: string): Promise<import('./client').CoordinatorOutcome<import('./client').RunStatus>>
14
+ }
15
+
16
+ export interface CoordinatorOutcome {
17
+ kind: 'complete'
18
+ value: unknown
19
+ }
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ module.exports = require('../native').load('coordinator');
@@ -2,10 +2,10 @@ export type ServiceKind = 'evidence';
2
2
 
3
3
  export interface DiscoveryClientOptions {
4
4
  baseUrl: string;
5
- requestTimeoutMilliseconds?: number;
5
+ attemptTimeoutMilliseconds?: number;
6
6
  connectTimeoutMilliseconds?: number;
7
7
  maximumResponseBytes?: number;
8
- trustedRootCertificates?: Buffer;
8
+ trustedRootCertificates?: string;
9
9
  }
10
10
 
11
11
  export interface EvidenceTypeResolveRequest {
@@ -158,7 +158,7 @@ function configurationValue(options) {
158
158
  }
159
159
  const allowed = new Set([
160
160
  'baseUrl',
161
- 'requestTimeoutMilliseconds',
161
+ 'attemptTimeoutMilliseconds',
162
162
  'connectTimeoutMilliseconds',
163
163
  'maximumResponseBytes',
164
164
  'trustedRootCertificates',
@@ -172,10 +172,10 @@ function configurationValue(options) {
172
172
  }
173
173
  const value = descriptor.value;
174
174
  if (key === 'trustedRootCertificates') {
175
- if (!Buffer.isBuffer(value) || value.length > 4 * 1024 * 1024) {
175
+ if (typeof value !== 'string' || Buffer.byteLength(value, 'utf8') > 4 * 1024 * 1024) {
176
176
  throw inputError('configuration');
177
177
  }
178
- copy[key] = Buffer.from(value);
178
+ copy[key] = value;
179
179
  } else if (key === 'baseUrl') {
180
180
  if (typeof value !== 'string') throw inputError('configuration');
181
181
  copy[key] = value;
@@ -13,10 +13,10 @@ export declare class DiscoveryClient {
13
13
 
14
14
  export interface DiscoveryClientOptions {
15
15
  baseUrl: string
16
- requestTimeoutMilliseconds?: number
16
+ attemptTimeoutMilliseconds?: number
17
17
  connectTimeoutMilliseconds?: number
18
18
  maximumResponseBytes?: number
19
- trustedRootCertificates?: Buffer
19
+ trustedRootCertificates?: string
20
20
  }
21
21
 
22
22
  export declare function renewUnchangedSelection(previous: any, current: any): any
@@ -73,7 +73,7 @@ export type ProgressiveResult =
73
73
  | ({ readonly responseFormat: 'sd-jwt-vc' } & ProgressiveVerifiedAudienceScopedCredential)
74
74
 
75
75
  export type AudienceScopedRequest = {
76
- requirement: string
76
+ handle: string
77
77
  responseFormat?: EvidenceResponseFormat
78
78
  /** One request-origin subject. Node keeps the selector map explicit. */
79
79
  selectors?: Readonly<Record<string, string | number | boolean>>
@@ -120,8 +120,8 @@ export interface PrivateKeyJwtConfig {
120
120
  scopes?: ReadonlyArray<string>
121
121
  assertionLifetimeSeconds?: number
122
122
  refreshMarginSeconds?: number
123
- requestTimeoutMs?: number
124
- connectTimeoutMs?: number
123
+ attemptTimeoutMilliseconds?: number
124
+ connectTimeoutMilliseconds?: number
125
125
  userAgent?: string
126
126
  /** Additional trust roots for the token endpoint, as a PEM bundle. */
127
127
  trustedRootCertificates?: string
@@ -151,11 +151,8 @@ export interface EvidenceExchangeContext {
151
151
  * This is not a `PrivateKeyJwtConfig`, even though the two describe the same
152
152
  * kind of client: an exchange is pinned to one resource and scope set, so both
153
153
  * are required here, and the object is read by the shared exchange
154
- * configuration parser rather than by the binding's own reader, so its timeout
155
- * members are the full-word ones that parser accepts. State at most one of
156
- * `requestTimeoutMilliseconds` and `requestTimeoutSeconds`, and at most one of
157
- * `connectTimeoutMilliseconds` and `connectTimeoutSeconds`; naming both of a
158
- * pair is refused.
154
+ * configuration parser rather than by the binding's own reader. Node exposes
155
+ * both timeout controls in milliseconds.
159
156
  */
160
157
  export interface EvidenceExchangeClientConfig {
161
158
  tokenEndpoint: string
@@ -180,10 +177,8 @@ export interface EvidenceExchangeClientConfig {
180
177
  scopes: ReadonlyArray<string>
181
178
  assertionLifetimeSeconds?: number
182
179
  refreshMarginSeconds?: number
183
- requestTimeoutMilliseconds?: number
184
- requestTimeoutSeconds?: number
180
+ attemptTimeoutMilliseconds?: number
185
181
  connectTimeoutMilliseconds?: number
186
- connectTimeoutSeconds?: number
187
182
  userAgent?: string
188
183
  /** Additional trust roots for the token endpoint, as a PEM bundle. */
189
184
  trustedRootCertificates?: string
@@ -195,10 +190,8 @@ export interface EvidenceExchangeRemoteSourceConfig {
195
190
  bootstrap: EvidenceExchangeClientConfig
196
191
  bootstrapResource: string
197
192
  bootstrapScope: string
198
- requestTimeoutMilliseconds?: number
199
- requestTimeoutSeconds?: number
193
+ attemptTimeoutMilliseconds?: number
200
194
  connectTimeoutMilliseconds?: number
201
- connectTimeoutSeconds?: number
202
195
  userAgent?: string
203
196
  /** Additional trust roots for the authority, as a PEM bundle. */
204
197
  trustedRootCertificates?: string
@@ -220,12 +213,12 @@ export interface EvidenceClientConfig {
220
213
  /** Configure exactly one of `token` or `authorization`. */
221
214
  token?: EvidenceTokenConfig
222
215
  authorization?: { exchange: EvidenceExchangeAuthorizationConfig }
223
- requestTimeoutMs?: number
224
- connectTimeoutMs?: number
216
+ attemptTimeoutMilliseconds?: number
217
+ connectTimeoutMilliseconds?: number
225
218
  userAgent?: string
226
219
  /** Additional trust roots for the deployment, as a PEM bundle. */
227
220
  trustedRootCertificates?: string
228
- maxResponseBytes?: number
221
+ maximumResponseBytes?: number
229
222
  maxMetadataBytes?: number
230
223
  }
231
224
 
@@ -340,18 +333,18 @@ export interface EvidenceRequestBatchSpec {
340
333
  }
341
334
 
342
335
  /**
343
- * The stable eight-kind error envelope every mapped Evidence Node failure
336
+ * The stable ten-kind error envelope every mapped Evidence Node failure
344
337
  * carries, as properties on a thrown `Error` (see `src/lib.rs`'s
345
338
  * `to_napi_error` and `src/convert.rs`'s `map_client_error` for the Rust side
346
339
  * of this contract).
347
340
  *
348
341
  * `kind` is always present. The rest are present only when the underlying
349
342
  * failure carries them:
350
- * - `status`: `denied`, `protocol`, and any `token` failure whose `tokenKind`
343
+ * - `status`: `denied`, `invalid-request`, `unavailable`, `protocol`, and any `token` failure whose `tokenKind`
351
344
  * is `protocol`
352
- * - `code`: `denied`, `protocol` (optional), `verification`, and any `token`
345
+ * - `code`: `denied`, `invalid-request`, `unavailable`, `protocol` (optional), `verification`, and any `token`
353
346
  * failure whose `tokenKind` is `refused`
354
- * - `traceId`: `denied`, `not-available`, `protocol` (all optional)
347
+ * - `traceId`: `denied`, `not-available`, `invalid-request`, `unavailable`, `protocol` (all optional)
355
348
  * - `retryAfterSeconds`: `denied`, `protocol` (both optional)
356
349
  * - `transportKind`: `transport`, and any `token` failure whose `tokenKind`
357
350
  * is `transport`
@@ -9,7 +9,7 @@
9
9
  const native = require('./index');
10
10
 
11
11
  /**
12
- * The stable eight-kind error envelope every mapped Evidence Node failure
12
+ * The stable ten-kind error envelope every mapped Evidence Node failure
13
13
  * carries (see `crates/registry-evidence-client-node/src/convert.rs`'s
14
14
  * `map_client_error`), as properties on a thrown `Error` rather than as JSON
15
15
  * text a caller has to `JSON.parse` out of `.message`.
@@ -45,7 +45,7 @@ class EvidenceClientError extends Error {
45
45
  * serialization defect, a caught panic, napi's own argument-type checking)
46
46
  * throws a plain, non-JSON reason instead, and is left exactly as thrown:
47
47
  * only a recognized envelope becomes an `EvidenceClientError`, so a caller
48
- * cannot mistake "some other native failure" for one of the eight stable
48
+ * cannot mistake "some other native failure" for one of the ten stable
49
49
  * kinds.
50
50
  */
51
51
  function normalize(error) {
@@ -26,7 +26,7 @@ export declare class EvidenceClient {
26
26
  * mandatory trust inputs. A key set or revoked-key list the verifier could
27
27
  * never use is refused, exactly as the Rust configuration refuses it.
28
28
  *
29
- * `maxResponseBytes` bounds the signed response `send` reads.
29
+ * `maximumResponseBytes` bounds the signed response `send` reads.
30
30
  * `maxMetadataBytes` bounds the documents `discover` and `fetchJwks` read,
31
31
  * which are neither signed nor verified, and is a separate decision.
32
32
  */
package/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as coordinator from './coordinator/client'
1
2
  import * as discovery from './discovery/client'
2
3
  import * as evidence from './evidence/client'
3
4
  import * as breg from './breg/client'
@@ -5,4 +6,4 @@ import * as casework from './casework/client'
5
6
  import * as messaging from './messaging/client'
6
7
  import * as scheduling from './scheduling/client'
7
8
 
8
- export { discovery, evidence, breg, casework, messaging, scheduling }
9
+ export { discovery, evidence, breg, casework, messaging, scheduling, coordinator }
package/index.js CHANGED
@@ -2,10 +2,11 @@
2
2
 
3
3
  // One assignment per namespace, never a `module.exports` object literal: Node
4
4
  // scans this file for these statements to synthesise the named exports an ESM
5
- // consumer imports, and `require()` sees the same six properties either way.
5
+ // consumer imports, and `require()` sees the same product properties either way.
6
6
  exports.discovery = require('./discovery/client');
7
7
  exports.evidence = require('./evidence/client');
8
8
  exports.breg = require('./breg/client');
9
9
  exports.casework = require('./casework/client');
10
10
  exports.messaging = require('./messaging/client');
11
11
  exports.scheduling = require('./scheduling/client');
12
+ exports.coordinator = require('./coordinator/client');
@@ -9,18 +9,19 @@ export type JsonValue = JsonScalar | ReadonlyArray<JsonValue> | { readonly [key:
9
9
 
10
10
  export interface MessagingClientConfig {
11
11
  baseUrl: string
12
- requestTimeoutMilliseconds?: SafeInteger | null
13
- connectTimeoutMilliseconds?: SafeInteger | null
14
- maxResponseBytes?: SafeInteger | null
15
- userAgent?: string | null
16
- trustedRootCertificates?: string | null
12
+ attemptTimeoutMilliseconds?: SafeInteger
13
+ connectTimeoutMilliseconds?: SafeInteger
14
+ maximumResponseBytes?: SafeInteger
15
+ userAgent?: string
16
+ /** Additional trust roots for the deployment, as PEM text. */
17
+ trustedRootCertificates?: string
17
18
  /**
18
19
  * How many times a submission whose outcome is unknown is resent,
19
20
  * identically and under the same idempotency key, before its error is
20
21
  * returned: a whole number from 0 to 2, default 2; 0 sends it once. Any
21
22
  * other value is a `configuration` error.
22
23
  */
23
- maxMutationRetries?: SafeInteger | null
24
+ maximumMutationRetries?: SafeInteger
24
25
  }
25
26
 
26
27
  export type Channel = 'email' | 'sms'
package/native.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const PACKAGE_VERSION = '0.43.0';
4
- const PRODUCTS = new Set(['discovery', 'evidence', 'breg', 'casework', 'messaging', 'scheduling']);
3
+ const PACKAGE_VERSION = '0.45.0';
4
+ const PRODUCTS = new Set(["breg", "casework", "coordinator", "discovery", "evidence", "messaging", "scheduling"]);
5
5
 
6
6
  function target() {
7
7
  if (process.platform === 'darwin' && process.arch === 'arm64') return 'darwin-arm64';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@registrystack/client",
3
- "version": "0.43.0",
3
+ "version": "0.45.0",
4
4
  "description": "Unified Node.js client for Registry Stack products.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://docs.registrystack.org/reference/client-api/",
@@ -15,7 +15,9 @@
15
15
  "breg",
16
16
  "casework",
17
17
  "messaging",
18
- "scheduling"
18
+ "scheduling",
19
+ "render",
20
+ "coordinator"
19
21
  ],
20
22
  "publishConfig": {
21
23
  "access": "public",
@@ -32,18 +34,25 @@
32
34
  ".": {
33
35
  "types": "./index.d.ts",
34
36
  "default": "./index.js"
37
+ },
38
+ "./compatibility.json": "./compatibility.json",
39
+ "./coordinator": {
40
+ "types": "./coordinator/client.d.ts",
41
+ "default": "./coordinator/client.js"
35
42
  }
36
43
  },
37
44
  "files": [
38
45
  "index.js",
39
46
  "index.d.ts",
40
47
  "native.js",
48
+ "compatibility.json",
41
49
  "discovery",
42
50
  "evidence",
43
51
  "breg",
44
52
  "casework",
45
53
  "messaging",
46
- "scheduling"
54
+ "scheduling",
55
+ "coordinator"
47
56
  ],
48
57
  "engines": {
49
58
  "node": ">=24.11.0"
@@ -59,8 +68,8 @@
59
68
  "typescript": "6.0.3"
60
69
  },
61
70
  "optionalDependencies": {
62
- "@registrystack/client-darwin-arm64": "0.43.0",
63
- "@registrystack/client-linux-arm64-gnu": "0.43.0",
64
- "@registrystack/client-linux-x64-gnu": "0.43.0"
71
+ "@registrystack/client-darwin-arm64": "0.45.0",
72
+ "@registrystack/client-linux-arm64-gnu": "0.45.0",
73
+ "@registrystack/client-linux-x64-gnu": "0.45.0"
65
74
  }
66
75
  }