@cortexkit/claustrum-client 0.9.0 → 0.11.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.
- package/README.md +15 -0
- package/dist/index.d.ts +1 -1
- package/dist/wire.d.ts +28 -0
- package/dist/wire.js +33 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -28,10 +28,25 @@ credential caching, refresh, account scheduling, and retry policy.
|
|
|
28
28
|
no provider ids are set. Since 0.6.2 a daemon too old to send the field decodes the
|
|
29
29
|
same way, so a newer client still lists against an older daemon. `authMethod` stays
|
|
30
30
|
optional.
|
|
31
|
+
• Since 0.10.0 `listScoped` also returns `grants` (how many grants the caller holds)
|
|
32
|
+
and `grantTuples` (`{ selectorKind, selector, operation }` per grant). They tell two
|
|
33
|
+
empty listings apart: `rows: []` with `grants === 0` means the caller has no grant;
|
|
34
|
+
`rows: []` with `grants > 0` means it holds a grant that currently reaches no
|
|
35
|
+
credential, usually a category no credential carries yet (the operator's fix is
|
|
36
|
+
`ck auth set-category`, or `ck auth reclassify --from-registry` for credentials created
|
|
37
|
+
before categories existed). Both are `undefined` against a vault too old to send
|
|
38
|
+
them; treat that as unknown, not as zero. A present but malformed value refuses the
|
|
39
|
+
reply like any other malformed field.
|
|
31
40
|
|
|
32
41
|
The client sends `consumerIdentity: null` for every managed request so inherited
|
|
33
42
|
`SUBC_MODULE_ID` and `SUBC_LAUNCH_NONCE` cannot impersonate a supervising host.
|
|
34
43
|
|
|
44
|
+
**Changed in 0.11.0:** the client depends on `@cortexkit/subc-client` ^0.22.0 (was
|
|
45
|
+
^0.16.0). A host that also uses subc-client must move to the 0.22 line, so both share one
|
|
46
|
+
copy. One behaviour reaches callers: while the vault is restarting or refusing route
|
|
47
|
+
opens as retryable, a call now keeps retrying for up to 90 s (paced, with jitter) instead
|
|
48
|
+
of 30 s. Give every vault call on a latency-sensitive path its own timeout.
|
|
49
|
+
|
|
35
50
|
## OpenCode handle-file exports
|
|
36
51
|
|
|
37
52
|
`defaultHandleFilePath`, `readHandleFile`, `handleFileRevision`, and `parseHandleFile`
|
package/dist/index.d.ts
CHANGED
|
@@ -3,5 +3,5 @@ export { storeIdentity, storageFingerprint } from './identity.js';
|
|
|
3
3
|
export { writeEnrollmentTokenFile, type EnrollmentTokenFile, } from './enrollment.js';
|
|
4
4
|
export { MANIFEST_LOCK, manifestLockQuarantinePrefix, withManifestLock, writeHandleFileLocked, type ManifestHandleAccount, type ManifestHandleFile, type ManifestHandleProvider, type ManifestLockError, type ManifestLockErrorCode, } from './manifest-lock.js';
|
|
5
5
|
export { ClaustrumCredentialError, credentialErrorAction, ERROR_CLASS_WIRE_SET, type ClaustrumCredentialErrorAction, type ClaustrumCredentialErrorClass, } from './errors.js';
|
|
6
|
-
export { ClaustrumClient, type ClaustrumClientOptions, type ClaustrumConnector, type ClaustrumReporterSource, type CredentialStatus, type EnrollmentPollOutcome, type ScopedInventory, type ScopedInventoryRow, type ServedCredential, } from './wire.js';
|
|
6
|
+
export { ClaustrumClient, type ClaustrumClientOptions, type ClaustrumConnector, type ClaustrumReporterSource, type CredentialStatus, type EnrollmentPollOutcome, type ScopedGrantTuple, type ScopedInventory, type ScopedInventoryRow, type ServedCredential, } from './wire.js';
|
|
7
7
|
export { HANDLE_FILE_CONTRACT, HandleFileValidationError, credentialIdMatchesProvider, defaultHandleFilePath, handleFileRevision, identifierIsValid, parseHandleFile, readHandleFile, type HandleAccount, type HandleFileIo, type HandleProvider, type OpenCodeHandleFileV1, } from './handles.js';
|
package/dist/wire.d.ts
CHANGED
|
@@ -250,10 +250,38 @@ export interface ScopedInventoryRow {
|
|
|
250
250
|
* and deliberately NOT over `record_version`, so a routine token refresh does not move it.
|
|
251
251
|
* Compare it against the previous call's to decide whether to reconcile at all; it is an
|
|
252
252
|
* opaque string and nothing but equality is defined on it.
|
|
253
|
+
*
|
|
254
|
+
* `grants` and `grantTuples` say what this caller is GRANTED, independent of what those
|
|
255
|
+
* grants currently reach. They are the only way to tell two empty listings apart:
|
|
256
|
+
*
|
|
257
|
+
* - `rows: []` with `grants === 0`: the caller holds no grant at all. The remedy is a
|
|
258
|
+
* grant (`ck auth grant`).
|
|
259
|
+
* - `rows: []` with `grants > 0`: the caller holds a grant that currently reaches no
|
|
260
|
+
* credential, typically a category no credential carries yet. The remedy is on the
|
|
261
|
+
* credential side (`ck auth set-category`, or `ck auth reclassify --from-registry` for
|
|
262
|
+
* credentials created before categories existed), not another grant.
|
|
263
|
+
*
|
|
264
|
+
* `grantTuples` lists each grant as `{ selectorKind, selector, operation }` (for example
|
|
265
|
+
* `{ selectorKind: 'category', selector: 'openai-native', operation: 'read' }`), so a
|
|
266
|
+
* consumer can name the selector that matched nothing. `grants` is its length.
|
|
267
|
+
*
|
|
268
|
+
* Both are `undefined` when the vault is too old to send them. That means "unknown",
|
|
269
|
+
* not "no grant": do not read an absent count as zero.
|
|
253
270
|
*/
|
|
254
271
|
export interface ScopedInventory {
|
|
255
272
|
readonly rows: readonly ScopedInventoryRow[];
|
|
256
273
|
readonly view: string;
|
|
274
|
+
readonly grants: number | undefined;
|
|
275
|
+
readonly grantTuples: readonly ScopedGrantTuple[] | undefined;
|
|
276
|
+
}
|
|
277
|
+
/** One grant the caller holds, as the vault's `list_scoped` reply names it. */
|
|
278
|
+
export interface ScopedGrantTuple {
|
|
279
|
+
/** `exact` or `category`; decoded as an open string. */
|
|
280
|
+
readonly selectorKind: string;
|
|
281
|
+
/** A credential id for `exact`, a bare category name for `category`. */
|
|
282
|
+
readonly selector: string;
|
|
283
|
+
/** The granted operation, e.g. `read` or `list`; decoded as an open string. */
|
|
284
|
+
readonly operation: string;
|
|
257
285
|
}
|
|
258
286
|
/**
|
|
259
287
|
* Exported for the golden-reply test only; `index.ts` re-exports by name, so this does not
|
package/dist/wire.js
CHANGED
|
@@ -346,6 +346,7 @@ export class ClaustrumClient {
|
|
|
346
346
|
await this.#reconnecting;
|
|
347
347
|
}
|
|
348
348
|
}
|
|
349
|
+
const GRANT_TUPLE_KEYS = ['operation', 'selector', 'selector_kind'];
|
|
349
350
|
/**
|
|
350
351
|
* Exported for the golden-reply test only; `index.ts` re-exports by name, so this does not
|
|
351
352
|
* widen the published surface. The test drives THIS function rather than asserting keys,
|
|
@@ -445,7 +446,38 @@ export function decodeScopedInventory(response, logUnknownClass) {
|
|
|
445
446
|
orgName: row.org_name,
|
|
446
447
|
};
|
|
447
448
|
});
|
|
448
|
-
|
|
449
|
+
// ABSENT IS UNKNOWN, PRESENT MUST BE WELL-FORMED. A vault from before these fields
|
|
450
|
+
// omits both, and refusing that would fail every listing against a still-supported
|
|
451
|
+
// vault. A present but malformed value is a broken reply, and decoding it leniently
|
|
452
|
+
// would hand the caller a grant count it cannot trust to tell "no grant" from "a grant
|
|
453
|
+
// that reaches nothing".
|
|
454
|
+
const rawGrants = result?.grants;
|
|
455
|
+
let grants;
|
|
456
|
+
if (rawGrants !== undefined) {
|
|
457
|
+
if (typeof rawGrants !== 'number' || !Number.isSafeInteger(rawGrants) || rawGrants < 0) {
|
|
458
|
+
throw asCredentialError(response, 'invalid_response', logUnknownClass);
|
|
459
|
+
}
|
|
460
|
+
grants = rawGrants;
|
|
461
|
+
}
|
|
462
|
+
const rawTuples = result?.grant_tuples;
|
|
463
|
+
let grantTuples;
|
|
464
|
+
if (rawTuples !== undefined) {
|
|
465
|
+
if (!Array.isArray(rawTuples))
|
|
466
|
+
throw asCredentialError(response, 'invalid_response', logUnknownClass);
|
|
467
|
+
grantTuples = rawTuples.map((tuple) => {
|
|
468
|
+
if (!isRecord(tuple) ||
|
|
469
|
+
Object.keys(tuple).length !== GRANT_TUPLE_KEYS.length ||
|
|
470
|
+
!GRANT_TUPLE_KEYS.every((key) => typeof tuple[key] === 'string')) {
|
|
471
|
+
throw asCredentialError(response, 'invalid_response', logUnknownClass);
|
|
472
|
+
}
|
|
473
|
+
return {
|
|
474
|
+
selectorKind: tuple.selector_kind,
|
|
475
|
+
selector: tuple.selector,
|
|
476
|
+
operation: tuple.operation,
|
|
477
|
+
};
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
return { rows: decoded, view, grants, grantTuples };
|
|
449
481
|
}
|
|
450
482
|
function decodeEnrollmentResult(response, logUnknownClass) {
|
|
451
483
|
if (hasCredentialError(response))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/claustrum-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -28,6 +28,6 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@cortexkit/store": "^0.2.1",
|
|
31
|
-
"@cortexkit/subc-client": "^0.
|
|
31
|
+
"@cortexkit/subc-client": "^0.22.0"
|
|
32
32
|
}
|
|
33
33
|
}
|