@cortexkit/claustrum-client 0.4.0 → 0.5.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 +5 -0
- package/dist/wire.d.ts +44 -1
- package/dist/wire.js +17 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,11 @@ credential caching, refresh, account scheduling, and retry policy.
|
|
|
16
16
|
by design (the vault cannot enumerate which). Treat it as gone either way: re-run
|
|
17
17
|
`ck auth migrate-opencode` to mint a fresh handle; the prior record, if any, is kept.
|
|
18
18
|
• `auth_required` means the record is latched and needs reauthentication.
|
|
19
|
+
• `statusCredential` on an unknown or revoked handle RESOLVES, it does not throw: it
|
|
20
|
+
returns `ready: false, lastErrorCode: 'not_found'` with `recordVersion`, `credentialId`
|
|
21
|
+
and `stalePending` absent. Since 0.5.0 `CredentialStatus.recordVersion` is optional for
|
|
22
|
+
that reason; handle `undefined` rather than defaulting it to a number, which would read
|
|
23
|
+
as a version older than every real one.
|
|
19
24
|
• Unknown server error classes are bounded to `transient`; callers must retry them
|
|
20
25
|
rather than treating a forward-compatible class as permanent.
|
|
21
26
|
|
package/dist/wire.d.ts
CHANGED
|
@@ -15,6 +15,14 @@ export type ClaustrumClientOptions = {
|
|
|
15
15
|
/**
|
|
16
16
|
* Credential material plus optional non-secret identity metadata. Missing wire fields remain
|
|
17
17
|
* `undefined`; a present non-string identity value rejects the response as invalid.
|
|
18
|
+
*
|
|
19
|
+
* An absent identity field means the vault had nothing to assert — NOT that identity failed.
|
|
20
|
+
* Consumers must not collapse absence into mismatch: assert on presence, refuse on a present
|
|
21
|
+
* difference, and serve (log, if it matters) when the field is missing. Absence proves neither
|
|
22
|
+
* the right identity nor the wrong one, so treating it as a failure converts a vault that could
|
|
23
|
+
* not answer into a consumer that cannot serve. The vault records no per-read success (at most
|
|
24
|
+
* the first scoped read per principal), and nothing at all when a consumer declines to serve, so
|
|
25
|
+
* an outage caused that way is visible only to the consumer that caused it.
|
|
18
26
|
*/
|
|
19
27
|
export type ServedCredential = {
|
|
20
28
|
material: string;
|
|
@@ -30,6 +38,12 @@ export type ServedCredential = {
|
|
|
30
38
|
/**
|
|
31
39
|
* Provider account identity the served token executes under. Account-scoped routing joins this
|
|
32
40
|
* value with `recordVersion`; it is neither the operator's credential label nor the bearer handle.
|
|
41
|
+
*
|
|
42
|
+
* BEST-EFFORT, NEVER GUARANTEED, including for JWT providers. The vault parses the claim live
|
|
43
|
+
* from the served access token and falls back to stored login-time identity; both legs can be
|
|
44
|
+
* empty, and the serve path yields nothing rather than fabricating an id. It is absent when the
|
|
45
|
+
* provider has no known claim, the token does not carry one, or no identity was captured at
|
|
46
|
+
* login. Do not gate serving on its presence.
|
|
33
47
|
*/
|
|
34
48
|
accountId?: string;
|
|
35
49
|
/** Non-secret account display metadata captured at login. */
|
|
@@ -37,14 +51,43 @@ export type ServedCredential = {
|
|
|
37
51
|
/** Non-secret organization or workspace display metadata captured at login. */
|
|
38
52
|
orgName?: string;
|
|
39
53
|
};
|
|
54
|
+
/**
|
|
55
|
+
* Non-secret health for one handle, read without minting anything.
|
|
56
|
+
*
|
|
57
|
+
* An unresolved handle (unknown or revoked) is an ordinary answer, not an error: it decodes
|
|
58
|
+
* as `ready: false, lastErrorCode: 'not_found'` with `credentialId`, `recordVersion` and
|
|
59
|
+
* `stalePending` all absent. The vault omits them on purpose so a probe learns nothing about
|
|
60
|
+
* what exists and no placeholder value is asserted about a record it never saw.
|
|
61
|
+
*/
|
|
40
62
|
export type CredentialStatus = {
|
|
41
63
|
ready: boolean;
|
|
42
64
|
lastErrorCode: string | null;
|
|
43
65
|
leaseHeld: boolean;
|
|
44
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Operator-chosen record label the handle resolved to, for verifying a binding the caller
|
|
68
|
+
* already holds. Not a routing key. Absent when the handle did not resolve.
|
|
69
|
+
*/
|
|
70
|
+
credentialId?: string;
|
|
71
|
+
/**
|
|
72
|
+
* The record's change cursor, present only when the handle resolved to a record.
|
|
73
|
+
*
|
|
74
|
+
* Optional, and OMITTED from the object rather than defaulted, because there is no honest
|
|
75
|
+
* default: 0 or -1 would compare as older than every real version, so a poller would read a
|
|
76
|
+
* revoked handle as a change it had yet to see, forever. With the key absent, TypeScript
|
|
77
|
+
* refuses arithmetic or ordering on it until the caller has handled `undefined`, and
|
|
78
|
+
* `'recordVersion' in status` is false. Never replace absence with a number (`?? 0`).
|
|
79
|
+
*/
|
|
80
|
+
recordVersion?: number;
|
|
45
81
|
stalePending?: boolean;
|
|
46
82
|
};
|
|
47
83
|
export type ClaustrumReporterSource = 'direct' | 'relay_status_field' | 'relay_message_parse';
|
|
84
|
+
/**
|
|
85
|
+
* Exported for the golden-reply test only; `index.ts` re-exports by name, so this does not
|
|
86
|
+
* widen the published surface.
|
|
87
|
+
*/
|
|
88
|
+
export declare function decodeCredential(response: unknown, logUnknownClass: (errorClass: string) => void): ServedCredential;
|
|
89
|
+
/** Exported for the golden-reply test only, like `decodeCredential`. */
|
|
90
|
+
export declare function decodeStatus(response: unknown, logUnknownClass: (errorClass: string) => void): CredentialStatus;
|
|
48
91
|
export declare class ClaustrumClient {
|
|
49
92
|
#private;
|
|
50
93
|
private constructor();
|
package/dist/wire.js
CHANGED
|
@@ -15,7 +15,11 @@ function asRecordVersion(value) {
|
|
|
15
15
|
function isOptionalString(value) {
|
|
16
16
|
return value === undefined || typeof value === 'string';
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Exported for the golden-reply test only; `index.ts` re-exports by name, so this does not
|
|
20
|
+
* widen the published surface.
|
|
21
|
+
*/
|
|
22
|
+
export function decodeCredential(response, logUnknownClass) {
|
|
19
23
|
if (hasCredentialError(response))
|
|
20
24
|
throw asCredentialError(response, 'invalid_response', logUnknownClass);
|
|
21
25
|
const result = isRecord(response) && isRecord(response.result) ? response.result : undefined;
|
|
@@ -61,15 +65,22 @@ function decodeCredential(response, logUnknownClass) {
|
|
|
61
65
|
orgName,
|
|
62
66
|
};
|
|
63
67
|
}
|
|
64
|
-
|
|
68
|
+
/** Exported for the golden-reply test only, like `decodeCredential`. */
|
|
69
|
+
export function decodeStatus(response, logUnknownClass) {
|
|
65
70
|
if (hasCredentialError(response))
|
|
66
71
|
throw asCredentialError(response, 'invalid_response', logUnknownClass);
|
|
67
72
|
const result = isRecord(response) && isRecord(response.result) ? response.result : undefined;
|
|
68
|
-
|
|
73
|
+
// Absent is a valid reply (the handle did not resolve); a PRESENT value that is not a
|
|
74
|
+
// non-negative integer is malformed. The producer omits the key rather than nulling it,
|
|
75
|
+
// so an explicit null is refused too.
|
|
76
|
+
const rawRecordVersion = result?.record_version;
|
|
77
|
+
const recordVersion = rawRecordVersion === undefined ? undefined : asRecordVersion(rawRecordVersion);
|
|
78
|
+
const credentialId = result?.credential_id;
|
|
69
79
|
if (typeof result?.ready !== 'boolean' ||
|
|
70
80
|
(result?.last_error_code !== undefined && result?.last_error_code !== null && typeof result?.last_error_code !== 'string') ||
|
|
71
81
|
typeof result?.lease_held !== 'boolean' ||
|
|
72
|
-
recordVersion === undefined ||
|
|
82
|
+
(rawRecordVersion !== undefined && recordVersion === undefined) ||
|
|
83
|
+
!isOptionalString(credentialId) ||
|
|
73
84
|
(result?.stale_pending !== undefined && typeof result.stale_pending !== 'boolean')) {
|
|
74
85
|
throw asCredentialError(response, 'invalid_status', logUnknownClass);
|
|
75
86
|
}
|
|
@@ -77,7 +88,8 @@ function decodeStatus(response, logUnknownClass) {
|
|
|
77
88
|
ready: result.ready,
|
|
78
89
|
lastErrorCode: result.last_error_code ?? null,
|
|
79
90
|
leaseHeld: result.lease_held,
|
|
80
|
-
|
|
91
|
+
...(credentialId === undefined ? {} : { credentialId }),
|
|
92
|
+
...(recordVersion === undefined ? {} : { recordVersion }),
|
|
81
93
|
...(result.stale_pending === undefined ? {} : { stalePending: result.stale_pending }),
|
|
82
94
|
};
|
|
83
95
|
}
|