@byok-sdk/core 0.4.1 → 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 +7 -0
- package/dist/device-assertion.d.ts +57 -0
- package/dist/in-memory/device-assertion-replay.d.ts +8 -0
- package/dist/in-memory/index.d.ts +2 -1
- package/dist/in-memory/presence.d.ts +1 -7
- package/dist/index.d.ts +5 -5
- package/dist/index.js +91 -63
- package/dist/index.js.map +1 -1
- package/dist/presence.d.ts +2 -48
- package/dist/stores.d.ts +3 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,4 +8,11 @@ This package is runtime-neutral: it has no Node built-in or protocol dependency.
|
|
|
8
8
|
import { tenantId, InMemoryCoreStores } from '@byok-sdk/core';
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
For connector setup, `authenticateDeviceAssertion()` verifies exact trusted
|
|
12
|
+
issuer/product/audience bindings, derives the principal from the current device
|
|
13
|
+
row, and consumes the JTI through an injected `DeviceAssertionReplayAuthority`.
|
|
14
|
+
`InMemoryDeviceAssertionReplayAuthority` is the reference implementation; a
|
|
15
|
+
hosted production composition must inject durable atomic storage. The assertion
|
|
16
|
+
authorizes one exchange only and is not a connector session or refresh token.
|
|
17
|
+
|
|
11
18
|
MIT licensed. Node.js 22.22.0 or newer.
|
|
@@ -44,6 +44,8 @@
|
|
|
44
44
|
*/
|
|
45
45
|
import { z } from 'zod';
|
|
46
46
|
import { type JsonObject } from './attestation';
|
|
47
|
+
import type { DevicePrincipal } from './principals';
|
|
48
|
+
import { type TenantId } from './tenant';
|
|
47
49
|
/** Envelope schema id, self-consistent with the domain prefix below. */
|
|
48
50
|
export declare const DEVICE_ASSERTION_SCHEMA_ID = "byok-device-assertion-v1";
|
|
49
51
|
/**
|
|
@@ -222,3 +224,58 @@ export interface DeviceAssertionVerifyDeps {
|
|
|
222
224
|
* verifier's job.
|
|
223
225
|
*/
|
|
224
226
|
export declare function verifyDeviceAssertion(input: unknown, deps: DeviceAssertionVerifyDeps): Promise<DeviceAssertionClaims | undefined>;
|
|
227
|
+
/** The verifier's complete current row. Claims remain lookup keys, never authority. */
|
|
228
|
+
export interface DeviceAssertionAuthorityRow extends DeviceAssertionDeviceRow {
|
|
229
|
+
readonly tenantId: TenantId;
|
|
230
|
+
readonly productId: string;
|
|
231
|
+
readonly deviceId: string;
|
|
232
|
+
}
|
|
233
|
+
/** Trusted deployment values the host compares with exact string equality. */
|
|
234
|
+
export interface DeviceAssertionExpectedBinding {
|
|
235
|
+
readonly issuer: string;
|
|
236
|
+
readonly productId: string;
|
|
237
|
+
readonly audience: string;
|
|
238
|
+
}
|
|
239
|
+
/** One replay key. Every field is derived from verified claims/current authority. */
|
|
240
|
+
export interface DeviceAssertionReplayConsumeInput {
|
|
241
|
+
readonly tenantId: TenantId;
|
|
242
|
+
readonly issuer: string;
|
|
243
|
+
readonly productId: string;
|
|
244
|
+
readonly deviceId: string;
|
|
245
|
+
readonly audience: string;
|
|
246
|
+
readonly jti: string;
|
|
247
|
+
readonly expiresAt: string;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Atomic single-use authority. `true` means this caller inserted the key;
|
|
251
|
+
* `false` means it was already consumed. Operational failures throw and must
|
|
252
|
+
* never be translated into authenticated success.
|
|
253
|
+
*/
|
|
254
|
+
export interface DeviceAssertionReplayAuthority {
|
|
255
|
+
consume(input: DeviceAssertionReplayConsumeInput): Promise<boolean>;
|
|
256
|
+
}
|
|
257
|
+
export interface AuthenticateDeviceAssertionDeps {
|
|
258
|
+
readonly verifier: DeviceAssertionVerifier;
|
|
259
|
+
readonly lookupDevice: (deviceId: string) => Promise<DeviceAssertionAuthorityRow | undefined> | DeviceAssertionAuthorityRow | undefined;
|
|
260
|
+
readonly replay: DeviceAssertionReplayAuthority;
|
|
261
|
+
readonly expected: DeviceAssertionExpectedBinding;
|
|
262
|
+
readonly now: Date;
|
|
263
|
+
readonly maxLifetimeMs?: number;
|
|
264
|
+
}
|
|
265
|
+
/** Audit-safe result of a consumed assertion; no credential or signature is retained. */
|
|
266
|
+
export interface AuthenticatedDeviceAssertion {
|
|
267
|
+
readonly device: DevicePrincipal;
|
|
268
|
+
readonly issuer: string;
|
|
269
|
+
readonly audience: string;
|
|
270
|
+
readonly jti: string;
|
|
271
|
+
readonly issuedAt: string;
|
|
272
|
+
readonly expiresAt: string;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Authenticate one device assertion and atomically consume its JTI.
|
|
276
|
+
*
|
|
277
|
+
* All invalid authentication states collapse to `undefined`. Replay-store
|
|
278
|
+
* operational failures reject the promise, allowing a host to return an
|
|
279
|
+
* availability error without ever degrading to signature-only acceptance.
|
|
280
|
+
*/
|
|
281
|
+
export declare function authenticateDeviceAssertion(input: unknown, deps: AuthenticateDeviceAssertionDeps): Promise<AuthenticatedDeviceAssertion | undefined>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DeviceAssertionReplayConsumeInput, DeviceAssertionReplayAuthority } from '../device-assertion';
|
|
2
|
+
/** Process-local reference authority. Production runtimes need durable atomic storage. */
|
|
3
|
+
export declare class InMemoryDeviceAssertionReplayAuthority implements DeviceAssertionReplayAuthority {
|
|
4
|
+
#private;
|
|
5
|
+
consume(input: DeviceAssertionReplayConsumeInput): Promise<boolean>;
|
|
6
|
+
/** Delete at most `limit` keys whose assertion lifetime ended at or before `before`. */
|
|
7
|
+
deleteExpired(before: Date, limit: number): Promise<number>;
|
|
8
|
+
}
|
|
@@ -3,10 +3,11 @@ export { createMutableClock, IN_MEMORY_CLOCK_EPOCH } from './clock';
|
|
|
3
3
|
export { InMemoryMailboxStore } from './mailbox';
|
|
4
4
|
export { InMemoryBoardStore } from './board';
|
|
5
5
|
export { InMemoryTruthStore } from './truth';
|
|
6
|
-
export { InMemoryPresenceStore
|
|
6
|
+
export { InMemoryPresenceStore } from './presence';
|
|
7
7
|
export { InMemoryObjectStore } from './blob';
|
|
8
8
|
export { InMemoryQuotaStore } from './quota';
|
|
9
9
|
export { InMemorySkillPackStore } from './skill-pack';
|
|
10
|
+
export { InMemoryDeviceAssertionReplayAuthority } from './device-assertion-replay';
|
|
10
11
|
export interface InMemoryCoreOptions {
|
|
11
12
|
/** Defaults to a fresh {@link createMutableClock}, so TTL behavior is deterministic. */
|
|
12
13
|
readonly clock?: Clock;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type PresenceHint, type PresenceHintInput, type PresenceStore } from '../presence';
|
|
2
2
|
import type { Clock } from '../stores';
|
|
3
3
|
import { type TenantId } from '../tenant';
|
|
4
4
|
export declare class InMemoryPresenceStore implements PresenceStore {
|
|
@@ -8,9 +8,3 @@ export declare class InMemoryPresenceStore implements PresenceStore {
|
|
|
8
8
|
read(tenant: TenantId, deviceId: string): Promise<PresenceHint | undefined>;
|
|
9
9
|
list(tenant: TenantId): Promise<readonly PresenceHint[]>;
|
|
10
10
|
}
|
|
11
|
-
export declare class InMemoryActivityStore implements ActivityStore {
|
|
12
|
-
#private;
|
|
13
|
-
constructor(clock: Clock);
|
|
14
|
-
append(tenant: TenantId, input: ActivityAppendInput): Promise<ActivityTail>;
|
|
15
|
-
read(tenant: TenantId, taskId: string): Promise<ActivityTail | undefined>;
|
|
16
|
-
}
|
package/dist/index.d.ts
CHANGED
|
@@ -23,8 +23,8 @@ export { BOARD_STATUSES, BOARD_TRANSITIONS, isLegalBoardTransition } from './boa
|
|
|
23
23
|
export type { BoardAssignee, BoardClaimInput, BoardItem, BoardItemInput, BoardListQuery, BoardPage, BoardStatus, BoardStatusUpdateInput, BoardStore, BoardUnclaimInput, } from './board';
|
|
24
24
|
export { TRUTH_RECORD_KINDS } from './truth';
|
|
25
25
|
export type { SnapshotWriteInput, TerminalWriteInput, TruthBodyRef, TruthManifestEntry, TruthManifestQuery, TruthRecord, TruthRecordKind, TruthRecordSelector, TruthStore, } from './truth';
|
|
26
|
-
export { PRESENCE_LEVELS
|
|
27
|
-
export type {
|
|
26
|
+
export { PRESENCE_LEVELS } from './presence';
|
|
27
|
+
export type { PresenceHint, PresenceHintInput, PresenceLevel, PresenceStore, } from './presence';
|
|
28
28
|
export { CONTENT_HASH_PATTERN, OBJECT_KEY_PREFIX_PATTERN, OBJECT_STATES, OBJECT_STATE_TRANSITIONS, contentHash, isContentHash, isLegalObjectTransition, objectKeyPrefix, tenantObjectKey, } from './blob';
|
|
29
29
|
export type { ContentHash, ObjectCommitInput, ObjectKeyPrefix, ObjectListQuery, ObjectManifestEntry, ObjectManifestInput, ObjectReference, ObjectReferenceInput, ObjectState, ObjectStore, } from './blob';
|
|
30
30
|
export { STORAGE_ERROR_CODES, STORAGE_ERROR_HTTP_STATUS, STORAGE_RESERVATION_STATES, STORAGE_WRITE_KINDS, STORAGE_WRITE_POSTURES, } from './quota';
|
|
@@ -38,8 +38,8 @@ export type { Clock, CoreStoreName, CoreStores, MutableClock } from './stores';
|
|
|
38
38
|
export { CORE_NON_COMPOSITION_PORT_NAMES, CORE_PORT_INTERFACES, CORE_PORT_METHODS, } from './ports-contract';
|
|
39
39
|
export { DEVICE_PROOF_ALGORITHMS, DEVICE_PROOF_DOMAIN_PREFIX, DEVICE_PROOF_HEADER, DEVICE_PROOF_SCHEMA_ID, DEVICE_PROOF_VERSION, DeviceProofEnvelopeV1Schema, DeviceProofProtectedClaimsSchema, canonicalizeJson, canonicalizeJsonBytes, deviceProofCanonicalClaims, deviceProofCanonicalJson, deviceProofSigningInput, parseDeviceProofEnvelope, } from './attestation';
|
|
40
40
|
export type { DeviceProofAlgorithm, DeviceProofEnvelopeV1, DeviceProofProtectedClaims, DeviceProofVerifier, DeviceProofVerifyInput, JsonObject, JsonPrimitive, JsonValue, } from './attestation';
|
|
41
|
-
export { DEVICE_ASSERTION_ALGORITHMS, DEVICE_ASSERTION_AUDIENCE_MAX_BYTES, DEVICE_ASSERTION_DEFAULT_TTL_MS, DEVICE_ASSERTION_DOMAIN_PREFIX, DEVICE_ASSERTION_MAX_TTL_MS, DEVICE_ASSERTION_SCHEMA_ID, DEVICE_ASSERTION_VERSION, DeviceAssertionClaimsSchema, DeviceAssertionEnvelopeV1Schema, deviceAssertionCanonicalClaims, deviceAssertionCanonicalJson, deviceAssertionSigningInput, parseDeviceAssertionEnvelope, verifyDeviceAssertion, } from './device-assertion';
|
|
42
|
-
export type { DeviceAssertionAlgorithm, DeviceAssertionClaims, DeviceAssertionDeviceRow, DeviceAssertionEnvelopeV1, DeviceAssertionVerifier, DeviceAssertionVerifyDeps, DeviceAssertionVerifyInput, } from './device-assertion';
|
|
41
|
+
export { authenticateDeviceAssertion, DEVICE_ASSERTION_ALGORITHMS, DEVICE_ASSERTION_AUDIENCE_MAX_BYTES, DEVICE_ASSERTION_DEFAULT_TTL_MS, DEVICE_ASSERTION_DOMAIN_PREFIX, DEVICE_ASSERTION_MAX_TTL_MS, DEVICE_ASSERTION_SCHEMA_ID, DEVICE_ASSERTION_VERSION, DeviceAssertionClaimsSchema, DeviceAssertionEnvelopeV1Schema, deviceAssertionCanonicalClaims, deviceAssertionCanonicalJson, deviceAssertionSigningInput, parseDeviceAssertionEnvelope, verifyDeviceAssertion, } from './device-assertion';
|
|
42
|
+
export type { AuthenticateDeviceAssertionDeps, AuthenticatedDeviceAssertion, DeviceAssertionAlgorithm, DeviceAssertionAuthorityRow, DeviceAssertionClaims, DeviceAssertionDeviceRow, DeviceAssertionEnvelopeV1, DeviceAssertionExpectedBinding, DeviceAssertionReplayConsumeInput, DeviceAssertionReplayAuthority, DeviceAssertionVerifier, DeviceAssertionVerifyDeps, DeviceAssertionVerifyInput, } from './device-assertion';
|
|
43
43
|
export { NONCE_SIGNING_DOMAIN, nonceSigningBytes } from './pairing';
|
|
44
|
-
export { IN_MEMORY_CLOCK_EPOCH,
|
|
44
|
+
export { IN_MEMORY_CLOCK_EPOCH, InMemoryBoardStore, InMemoryMailboxStore, InMemoryDeviceAssertionReplayAuthority, InMemoryObjectStore, InMemoryPresenceStore, InMemoryQuotaStore, InMemorySkillPackStore, InMemoryTruthStore, createInMemoryCoreStores, createInMemoryCoreCompositionWithClock, createMutableClock, } from './in-memory/index';
|
|
45
45
|
export type { InMemoryCoreComposition, InMemoryCoreOptions } from './in-memory/index';
|
package/dist/index.js
CHANGED
|
@@ -173,7 +173,6 @@ var TRUTH_RECORD_KINDS = ["task.terminal", "profile", "memory"];
|
|
|
173
173
|
|
|
174
174
|
// src/presence.ts
|
|
175
175
|
var PRESENCE_LEVELS = ["online", "thinking", "working", "error", "offline"];
|
|
176
|
-
var DEFAULT_ACTIVITY_CAPACITY = 50;
|
|
177
176
|
|
|
178
177
|
// src/blob.ts
|
|
179
178
|
var CONTENT_HASH_PATTERN = /^sha256:[0-9a-f]{64}$/;
|
|
@@ -529,7 +528,6 @@ var CORE_STORE_NAMES = [
|
|
|
529
528
|
"board",
|
|
530
529
|
"truth",
|
|
531
530
|
"presence",
|
|
532
|
-
"activity",
|
|
533
531
|
"objects",
|
|
534
532
|
"quota",
|
|
535
533
|
"skillPacks"
|
|
@@ -542,7 +540,6 @@ var CORE_PORT_METHODS = {
|
|
|
542
540
|
board: ["create", "get", "list", "claim", "unclaim", "updateStatus"],
|
|
543
541
|
truth: ["writeTerminal", "writeSnapshot", "getRecord", "listManifest"],
|
|
544
542
|
presence: ["publish", "read", "list"],
|
|
545
|
-
activity: ["append", "read"],
|
|
546
543
|
objects: [
|
|
547
544
|
"putManifest",
|
|
548
545
|
"commit",
|
|
@@ -572,7 +569,6 @@ var CORE_PORT_INTERFACES = {
|
|
|
572
569
|
board: "BoardStore",
|
|
573
570
|
truth: "TruthStore",
|
|
574
571
|
presence: "PresenceStore",
|
|
575
|
-
activity: "ActivityStore",
|
|
576
572
|
objects: "ObjectStore",
|
|
577
573
|
quota: "QuotaStore",
|
|
578
574
|
skillPacks: "SkillPackStore"
|
|
@@ -856,6 +852,58 @@ async function verifyDeviceAssertion(input, deps) {
|
|
|
856
852
|
if (!verified) return void 0;
|
|
857
853
|
return claims;
|
|
858
854
|
}
|
|
855
|
+
function isNonEmptyExactString(value) {
|
|
856
|
+
return typeof value === "string" && value.length > 0 && value.trim() === value;
|
|
857
|
+
}
|
|
858
|
+
function isAuthorityRow(row, requestedDeviceId) {
|
|
859
|
+
if (row === null || typeof row !== "object") return false;
|
|
860
|
+
const candidate = row;
|
|
861
|
+
return isTenantId(candidate.tenantId) && isNonEmptyExactString(candidate.productId) && candidate.deviceId === requestedDeviceId;
|
|
862
|
+
}
|
|
863
|
+
async function authenticateDeviceAssertion(input, deps) {
|
|
864
|
+
if (!isNonEmptyExactString(deps.expected.issuer) || !isNonEmptyExactString(deps.expected.productId) || !isNonEmptyExactString(deps.expected.audience) || utf8ByteLength(deps.expected.audience) > DEVICE_ASSERTION_AUDIENCE_MAX_BYTES) {
|
|
865
|
+
return void 0;
|
|
866
|
+
}
|
|
867
|
+
let authorityRow;
|
|
868
|
+
const claims = await verifyDeviceAssertion(input, {
|
|
869
|
+
verifier: deps.verifier,
|
|
870
|
+
lookupDevice: async (deviceId) => {
|
|
871
|
+
const row = await deps.lookupDevice(deviceId);
|
|
872
|
+
if (!isAuthorityRow(row, deviceId)) return void 0;
|
|
873
|
+
authorityRow = row;
|
|
874
|
+
return { publicKeyJwkX: row.publicKeyJwkX, revoked: row.revoked };
|
|
875
|
+
},
|
|
876
|
+
now: deps.now,
|
|
877
|
+
...deps.maxLifetimeMs === void 0 ? {} : { maxLifetimeMs: deps.maxLifetimeMs }
|
|
878
|
+
});
|
|
879
|
+
if (claims === void 0 || authorityRow === void 0) return void 0;
|
|
880
|
+
if (claims.issuer !== deps.expected.issuer || claims.productId !== deps.expected.productId || claims.audience !== deps.expected.audience || authorityRow.productId !== deps.expected.productId || authorityRow.deviceId !== claims.deviceId) {
|
|
881
|
+
return void 0;
|
|
882
|
+
}
|
|
883
|
+
const consumed = await deps.replay.consume({
|
|
884
|
+
tenantId: authorityRow.tenantId,
|
|
885
|
+
issuer: claims.issuer,
|
|
886
|
+
productId: authorityRow.productId,
|
|
887
|
+
deviceId: authorityRow.deviceId,
|
|
888
|
+
audience: claims.audience,
|
|
889
|
+
jti: claims.jti,
|
|
890
|
+
expiresAt: claims.expiresAt
|
|
891
|
+
});
|
|
892
|
+
if (!consumed) return void 0;
|
|
893
|
+
return {
|
|
894
|
+
device: {
|
|
895
|
+
kind: "device",
|
|
896
|
+
tenantId: authorityRow.tenantId,
|
|
897
|
+
productId: authorityRow.productId,
|
|
898
|
+
deviceId: authorityRow.deviceId
|
|
899
|
+
},
|
|
900
|
+
issuer: claims.issuer,
|
|
901
|
+
audience: claims.audience,
|
|
902
|
+
jti: claims.jti,
|
|
903
|
+
issuedAt: claims.issuedAt,
|
|
904
|
+
expiresAt: claims.expiresAt
|
|
905
|
+
};
|
|
906
|
+
}
|
|
859
907
|
|
|
860
908
|
// src/pairing.ts
|
|
861
909
|
var NONCE_SIGNING_DOMAIN = "byok-nonce-v1\n";
|
|
@@ -938,63 +986,6 @@ var InMemoryPresenceStore = class {
|
|
|
938
986
|
return this.#clock.now().toISOString() >= expiresAt;
|
|
939
987
|
}
|
|
940
988
|
};
|
|
941
|
-
var InMemoryActivityStore = class {
|
|
942
|
-
#tails = /* @__PURE__ */ new Map();
|
|
943
|
-
#clock;
|
|
944
|
-
constructor(clock) {
|
|
945
|
-
this.#clock = clock;
|
|
946
|
-
}
|
|
947
|
-
async append(tenant, input) {
|
|
948
|
-
assertTtl(input.ttlMs);
|
|
949
|
-
const capacity = input.capacity ?? DEFAULT_ACTIVITY_CAPACITY;
|
|
950
|
-
if (!Number.isSafeInteger(capacity) || capacity <= 0) {
|
|
951
|
-
throw new ByokCoreError(
|
|
952
|
-
"activity_capacity_invalid",
|
|
953
|
-
`Activity capacity must be a positive integer, received ${String(capacity)}.`
|
|
954
|
-
);
|
|
955
|
-
}
|
|
956
|
-
if (input.details.length === 0 || !Number.isSafeInteger(input.dropped) || input.dropped < 0) {
|
|
957
|
-
throw new ByokCoreError(
|
|
958
|
-
"activity_batch_invalid",
|
|
959
|
-
"Activity batches require at least one detail and a non-negative integer dropped count."
|
|
960
|
-
);
|
|
961
|
-
}
|
|
962
|
-
const now = this.#clock.now();
|
|
963
|
-
const key = tenantKey(tenant, input.taskId);
|
|
964
|
-
const existing = this.#tails.get(key);
|
|
965
|
-
const live = existing !== void 0 && now.toISOString() < existing.expiresAt ? existing : void 0;
|
|
966
|
-
const appended = input.details.map((detail) => ({
|
|
967
|
-
at: now.toISOString(),
|
|
968
|
-
detail
|
|
969
|
-
}));
|
|
970
|
-
const entries = [...live?.entries ?? [], ...appended];
|
|
971
|
-
let dropped = (live?.dropped ?? 0) + input.dropped;
|
|
972
|
-
while (entries.length > capacity) {
|
|
973
|
-
entries.shift();
|
|
974
|
-
dropped += 1;
|
|
975
|
-
}
|
|
976
|
-
const tail = {
|
|
977
|
-
tenantId: tenant,
|
|
978
|
-
taskId: input.taskId,
|
|
979
|
-
entries,
|
|
980
|
-
dropped,
|
|
981
|
-
capacity,
|
|
982
|
-
expiresAt: new Date(now.getTime() + input.ttlMs).toISOString()
|
|
983
|
-
};
|
|
984
|
-
this.#tails.set(key, tail);
|
|
985
|
-
return tail;
|
|
986
|
-
}
|
|
987
|
-
async read(tenant, taskId) {
|
|
988
|
-
const key = tenantKey(tenant, taskId);
|
|
989
|
-
const tail = this.#tails.get(key);
|
|
990
|
-
if (tail === void 0) return void 0;
|
|
991
|
-
if (this.#clock.now().toISOString() >= tail.expiresAt) {
|
|
992
|
-
this.#tails.delete(key);
|
|
993
|
-
return void 0;
|
|
994
|
-
}
|
|
995
|
-
return tail;
|
|
996
|
-
}
|
|
997
|
-
};
|
|
998
989
|
|
|
999
990
|
// src/in-memory/board.ts
|
|
1000
991
|
var DEFAULT_LIST_LIMIT = 50;
|
|
@@ -1956,6 +1947,44 @@ function createMutableClock(start = new Date(IN_MEMORY_CLOCK_EPOCH)) {
|
|
|
1956
1947
|
};
|
|
1957
1948
|
}
|
|
1958
1949
|
|
|
1950
|
+
// src/in-memory/device-assertion-replay.ts
|
|
1951
|
+
function replayKey(input) {
|
|
1952
|
+
return JSON.stringify([
|
|
1953
|
+
input.tenantId,
|
|
1954
|
+
input.issuer,
|
|
1955
|
+
input.productId,
|
|
1956
|
+
input.deviceId,
|
|
1957
|
+
input.audience,
|
|
1958
|
+
input.jti
|
|
1959
|
+
]);
|
|
1960
|
+
}
|
|
1961
|
+
var InMemoryDeviceAssertionReplayAuthority = class {
|
|
1962
|
+
#expiresAtByKey = /* @__PURE__ */ new Map();
|
|
1963
|
+
async consume(input) {
|
|
1964
|
+
const expiresAt = Date.parse(input.expiresAt);
|
|
1965
|
+
if (!Number.isFinite(expiresAt)) throw new Error("device assertion replay expiry is invalid");
|
|
1966
|
+
const key = replayKey(input);
|
|
1967
|
+
if (this.#expiresAtByKey.has(key)) return false;
|
|
1968
|
+
this.#expiresAtByKey.set(key, expiresAt);
|
|
1969
|
+
return true;
|
|
1970
|
+
}
|
|
1971
|
+
/** Delete at most `limit` keys whose assertion lifetime ended at or before `before`. */
|
|
1972
|
+
async deleteExpired(before, limit) {
|
|
1973
|
+
const cutoff = before.getTime();
|
|
1974
|
+
if (!Number.isFinite(cutoff) || !Number.isSafeInteger(limit) || limit <= 0) {
|
|
1975
|
+
throw new Error("device assertion replay cleanup bounds are invalid");
|
|
1976
|
+
}
|
|
1977
|
+
let deleted = 0;
|
|
1978
|
+
for (const [key, expiresAt] of this.#expiresAtByKey) {
|
|
1979
|
+
if (expiresAt > cutoff) continue;
|
|
1980
|
+
this.#expiresAtByKey.delete(key);
|
|
1981
|
+
deleted += 1;
|
|
1982
|
+
if (deleted === limit) break;
|
|
1983
|
+
}
|
|
1984
|
+
return deleted;
|
|
1985
|
+
}
|
|
1986
|
+
};
|
|
1987
|
+
|
|
1959
1988
|
// src/in-memory/index.ts
|
|
1960
1989
|
function createInMemoryCoreStores(options = {}) {
|
|
1961
1990
|
const clock = options.clock ?? createMutableClock();
|
|
@@ -1965,7 +1994,6 @@ function createInMemoryCoreStores(options = {}) {
|
|
|
1965
1994
|
board: new InMemoryBoardStore(clock),
|
|
1966
1995
|
truth: new InMemoryTruthStore(clock),
|
|
1967
1996
|
presence: new InMemoryPresenceStore(clock),
|
|
1968
|
-
activity: new InMemoryActivityStore(clock),
|
|
1969
1997
|
objects,
|
|
1970
1998
|
quota: new InMemoryQuotaStore(clock, objects),
|
|
1971
1999
|
skillPacks: new InMemorySkillPackStore()
|
|
@@ -1977,6 +2005,6 @@ function createInMemoryCoreCompositionWithClock() {
|
|
|
1977
2005
|
return { stores: createInMemoryCoreStores({ clock }).stores, clock };
|
|
1978
2006
|
}
|
|
1979
2007
|
|
|
1980
|
-
export { BOARD_STATUSES, BOARD_TRANSITIONS, ByokCoreError, CANONICAL_TIMESTAMP_PATTERN, CAPABILITY_DECLARATION_SCHEMA_ID, CAPABILITY_NAME_PATTERN, CONTENT_HASH_PATTERN, CORE_ERROR_CODES, CORE_NON_COMPOSITION_PORT_NAMES, CORE_PORT_INTERFACES, CORE_PORT_METHODS, CORE_STORE_NAMES, CapabilityDeclarationSchema, CoreConflictError,
|
|
2008
|
+
export { BOARD_STATUSES, BOARD_TRANSITIONS, ByokCoreError, CANONICAL_TIMESTAMP_PATTERN, CAPABILITY_DECLARATION_SCHEMA_ID, CAPABILITY_NAME_PATTERN, CONTENT_HASH_PATTERN, CORE_ERROR_CODES, CORE_NON_COMPOSITION_PORT_NAMES, CORE_PORT_INTERFACES, CORE_PORT_METHODS, CORE_STORE_NAMES, CapabilityDeclarationSchema, CoreConflictError, DEVICE_ASSERTION_ALGORITHMS, DEVICE_ASSERTION_AUDIENCE_MAX_BYTES, DEVICE_ASSERTION_DEFAULT_TTL_MS, DEVICE_ASSERTION_DOMAIN_PREFIX, DEVICE_ASSERTION_MAX_TTL_MS, DEVICE_ASSERTION_SCHEMA_ID, DEVICE_ASSERTION_VERSION, DEVICE_PROOF_ALGORITHMS, DEVICE_PROOF_DOMAIN_PREFIX, DEVICE_PROOF_HEADER, DEVICE_PROOF_SCHEMA_ID, DEVICE_PROOF_VERSION, DeviceAssertionClaimsSchema, DeviceAssertionEnvelopeV1Schema, DeviceProofEnvelopeV1Schema, DeviceProofProtectedClaimsSchema, IN_MEMORY_CLOCK_EPOCH, InMemoryBoardStore, InMemoryDeviceAssertionReplayAuthority, InMemoryMailboxStore, InMemoryObjectStore, InMemoryPresenceStore, InMemoryQuotaStore, InMemorySkillPackStore, InMemoryTruthStore, MAILBOX_MESSAGE_STATES, NONCE_SIGNING_DOMAIN, OBJECT_KEY_PREFIX_PATTERN, OBJECT_STATES, OBJECT_STATE_TRANSITIONS, PRESENCE_LEVELS, PRINCIPAL_KINDS, SKILL_FRONTMATTER_FIELDS, SKILL_PACK_DESCRIPTION_MAX_LENGTH, SKILL_PACK_ENTRY_PATH, SKILL_PACK_FILE_MAX_BYTES, SKILL_PACK_FILE_PATH_MAX_LENGTH, SKILL_PACK_FILE_PATH_PATTERN, SKILL_PACK_FORBIDDEN_FIELDS, SKILL_PACK_MANIFEST_SCHEMA_ID, SKILL_PACK_MAX_BYTES, SKILL_PACK_MAX_FILES, SKILL_PACK_NAME_MAX_LENGTH, SKILL_PACK_NAME_PATTERN, SKILL_PACK_REJECTIONS, SKILL_PACK_VERSION_PATTERN, STORAGE_ERROR_CODES, STORAGE_ERROR_HTTP_STATUS, STORAGE_RESERVATION_STATES, STORAGE_WRITE_KINDS, STORAGE_WRITE_POSTURES, SkillPackFileSchema, SkillPackManifestSchema, TENANT_ID_MAX_LENGTH, TENANT_KEY_SEPARATOR, TRUTH_RECORD_KINDS, assertCanonicalTimestamp, assertCapability, authenticateDeviceAssertion, canonicalizeJson, canonicalizeJsonBytes, checkSkillPackEntry, checkSkillPackFileContent, checkSkillPackManifest, contentHash, createInMemoryCoreCompositionWithClock, createInMemoryCoreStores, createMutableClock, deviceAssertionCanonicalClaims, deviceAssertionCanonicalJson, deviceAssertionSigningInput, deviceProofCanonicalClaims, deviceProofCanonicalJson, deviceProofSigningInput, hasCapability, isCanonicalTimestamp, isContentHash, isControlPlanePrincipal, isCoreConflictError, isCoreError, isDevicePrincipal, isLegalBoardTransition, isLegalObjectTransition, isSkillPackPathSafe, isTenantId, nonceSigningBytes, objectKeyPrefix, parseCapabilityDeclaration, parseDeviceAssertionEnvelope, parseDeviceProofEnvelope, parseSkillFrontmatter, parseSkillPackManifest, principalTenant, skillPackContentHashInput, tenantId, tenantKey, tenantObjectKey, verifyDeviceAssertion };
|
|
1981
2009
|
//# sourceMappingURL=index.js.map
|
|
1982
2010
|
//# sourceMappingURL=index.js.map
|