@byok-sdk/cloud 0.4.2 → 0.6.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 +19 -0
- package/dist/auth/device-assertion.d.ts +18 -0
- package/dist/cloud.d.ts +9 -6
- package/dist/errors.d.ts +2 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +315 -56
- package/dist/index.js.map +1 -1
- package/dist/stores/in-memory/device-directory.d.ts +2 -1
- package/dist/stores/in-memory/index.d.ts +2 -1
- package/dist/stores/in-memory/task-attempts.d.ts +11 -1
- package/dist/stores/in-memory/task-cancellations.d.ts +9 -0
- package/dist/stores/ports.d.ts +31 -3
- package/dist/tenant-stores.d.ts +8 -2
- package/dist/terminal-result.d.ts +7 -1
- package/package.json +3 -3
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* so a revocation applied through the composite key is immediately visible to
|
|
8
8
|
* `/byok/challenge` and `/byok/token` with no second copy to keep in sync.
|
|
9
9
|
*/
|
|
10
|
-
import { type TenantId } from '@byok-sdk/core';
|
|
10
|
+
import { type PresenceStore, type TenantId, type TenantReadiness } from '@byok-sdk/core';
|
|
11
11
|
import type { DeviceDirectory, DeviceRecord, DeviceRegistration } from '../ports';
|
|
12
12
|
export declare class InMemoryDeviceDirectory implements DeviceDirectory {
|
|
13
13
|
#private;
|
|
@@ -15,5 +15,6 @@ export declare class InMemoryDeviceDirectory implements DeviceDirectory {
|
|
|
15
15
|
get(tenant: TenantId, deviceId: string): Promise<DeviceRecord | undefined>;
|
|
16
16
|
revoke(tenant: TenantId, deviceId: string): Promise<void>;
|
|
17
17
|
list(tenant: TenantId): Promise<readonly DeviceRecord[]>;
|
|
18
|
+
readiness(tenant: TenantId, presence: PresenceStore): Promise<TenantReadiness>;
|
|
18
19
|
resolveByDeviceId(deviceId: string): Promise<DeviceRecord | undefined>;
|
|
19
20
|
}
|
|
@@ -19,6 +19,7 @@ export { InMemoryPairingCodeStore } from './pairing-codes';
|
|
|
19
19
|
export { InMemoryRequestReceiptStore } from './receipts';
|
|
20
20
|
export { InMemoryProofRequestReceiptStore } from './proof-receipts';
|
|
21
21
|
export { InMemoryTaskAttemptStore } from './task-attempts';
|
|
22
|
+
export { InMemoryTaskCancellationStore } from './task-cancellations';
|
|
22
23
|
export { InMemoryActivityStore } from './activity';
|
|
23
24
|
export { InMemoryApprovalTimelineStore } from './approval-timeline';
|
|
24
25
|
/**
|
|
@@ -34,4 +35,4 @@ export interface InMemoryCloudComposition {
|
|
|
34
35
|
readonly stores: CloudStores;
|
|
35
36
|
readonly blobContentProxy: BlobContentProxy;
|
|
36
37
|
}
|
|
37
|
-
export declare function createInMemoryCloudStores(clock: Clock, crypto: CloudCrypto, objects: ObjectStore): InMemoryCloudComposition;
|
|
38
|
+
export declare function createInMemoryCloudStores(clock: Clock, crypto: CloudCrypto, objects: ObjectStore, mailbox: import('@byok-sdk/core').MailboxStore): InMemoryCloudComposition;
|
|
@@ -19,12 +19,13 @@ import { type Clock, type TenantId } from '@byok-sdk/core';
|
|
|
19
19
|
import type { TaskAttempt, TaskAttemptStatus, TaskAttemptStore } from '../ports';
|
|
20
20
|
export declare class InMemoryTaskAttemptStore implements TaskAttemptStore {
|
|
21
21
|
#private;
|
|
22
|
-
constructor(clock: Clock);
|
|
22
|
+
constructor(clock: Clock, state?: InMemoryTaskAttemptState);
|
|
23
23
|
open(tenant: TenantId, input: {
|
|
24
24
|
taskId: string;
|
|
25
25
|
deviceId: string;
|
|
26
26
|
}): Promise<TaskAttempt>;
|
|
27
27
|
get(tenant: TenantId, taskId: string): Promise<TaskAttempt | undefined>;
|
|
28
|
+
getMany(tenant: TenantId, taskIds: readonly string[]): Promise<readonly TaskAttempt[]>;
|
|
28
29
|
claim(tenant: TenantId, input: {
|
|
29
30
|
taskId: string;
|
|
30
31
|
deviceId: string;
|
|
@@ -34,3 +35,12 @@ export declare class InMemoryTaskAttemptStore implements TaskAttemptStore {
|
|
|
34
35
|
status: TaskAttemptStatus;
|
|
35
36
|
}): Promise<TaskAttempt | undefined>;
|
|
36
37
|
}
|
|
38
|
+
/** Shared mutable state for the task and cancellation reference ports. */
|
|
39
|
+
export declare class InMemoryTaskAttemptState {
|
|
40
|
+
#private;
|
|
41
|
+
readonly attempts: Map<string, TaskAttempt>;
|
|
42
|
+
constructor(clock: Clock);
|
|
43
|
+
now(): string;
|
|
44
|
+
/** Serialize every state-changing operation for one tenant/task key. */
|
|
45
|
+
mutate<T>(key: string, operation: () => T | Promise<T>): Promise<T>;
|
|
46
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type MailboxStore, type TenantId } from '@byok-sdk/core';
|
|
2
|
+
import type { TaskCancellationMutation, TaskCancellationRequest, TaskCancellationStore } from '../ports';
|
|
3
|
+
import { InMemoryTaskAttemptState } from './task-attempts';
|
|
4
|
+
/** Failure-free reference composition of the atomic cancellation port. */
|
|
5
|
+
export declare class InMemoryTaskCancellationStore implements TaskCancellationStore {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(state: InMemoryTaskAttemptState, mailbox: MailboxStore);
|
|
8
|
+
request(tenant: TenantId, input: TaskCancellationRequest): Promise<TaskCancellationMutation | undefined>;
|
|
9
|
+
}
|
package/dist/stores/ports.d.ts
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* because a composition backed by object storage physically cannot proxy
|
|
35
35
|
* bytes (see the blobs section below).
|
|
36
36
|
*/
|
|
37
|
-
import type { StorageReservation, TenantId } from '@byok-sdk/core';
|
|
37
|
+
import type { MailboxBody, MailboxMessage, PresenceStore, StorageReservation, TenantId, TenantReadiness } from '@byok-sdk/core';
|
|
38
38
|
import type { ActivityStore } from '../activity';
|
|
39
39
|
import type { ApprovalTimelineStore } from '../approval-timeline';
|
|
40
40
|
export interface DeviceRecord {
|
|
@@ -65,6 +65,8 @@ export interface DeviceDirectory {
|
|
|
65
65
|
get(tenant: TenantId, deviceId: string): Promise<DeviceRecord | undefined>;
|
|
66
66
|
revoke(tenant: TenantId, deviceId: string): Promise<void>;
|
|
67
67
|
list(tenant: TenantId): Promise<readonly DeviceRecord[]>;
|
|
68
|
+
/** Set-wise tenant observation; revoked devices never contribute presence. */
|
|
69
|
+
readiness(tenant: TenantId, presence: PresenceStore): Promise<TenantReadiness>;
|
|
68
70
|
/** Pre-tenant. Two callers only: `POST /byok/challenge` and `POST /byok/token`. Never exposed through the tenant facade. */
|
|
69
71
|
resolveByDeviceId(deviceId: string): Promise<DeviceRecord | undefined>;
|
|
70
72
|
}
|
|
@@ -115,7 +117,7 @@ export interface InboundDedupStore {
|
|
|
115
117
|
*/
|
|
116
118
|
checkAndRecord(tenant: TenantId, deviceId: string, envelopeId: string): Promise<boolean>;
|
|
117
119
|
}
|
|
118
|
-
export declare const TASK_ATTEMPT_STATUSES: readonly ['offered', 'claimed', 'running', 'complete', 'failed', 'cancelled'];
|
|
120
|
+
export declare const TASK_ATTEMPT_STATUSES: readonly ['offered', 'claimed', 'running', 'cancel_requested', 'complete', 'failed', 'cancelled'];
|
|
119
121
|
export type TaskAttemptStatus = (typeof TASK_ATTEMPT_STATUSES)[number];
|
|
120
122
|
export interface TaskAttempt {
|
|
121
123
|
readonly tenantId: TenantId;
|
|
@@ -125,6 +127,11 @@ export interface TaskAttempt {
|
|
|
125
127
|
/** Set by `task.claim`, and only by the first one. Until then the task has no owner and the gate lets any of this tenant's devices through, matching the reference server. */
|
|
126
128
|
readonly ownerDeviceId?: string;
|
|
127
129
|
readonly status: TaskAttemptStatus;
|
|
130
|
+
/** Durable host cancellation authority. Its presence outranks later device terminal receipts. */
|
|
131
|
+
readonly cancellation?: {
|
|
132
|
+
readonly requestedAt: string;
|
|
133
|
+
readonly reason?: string;
|
|
134
|
+
};
|
|
128
135
|
readonly updatedAt: string;
|
|
129
136
|
}
|
|
130
137
|
export interface TaskAttemptStore {
|
|
@@ -134,6 +141,8 @@ export interface TaskAttemptStore {
|
|
|
134
141
|
readonly deviceId: string;
|
|
135
142
|
}): Promise<TaskAttempt>;
|
|
136
143
|
get(tenant: TenantId, taskId: string): Promise<TaskAttempt | undefined>;
|
|
144
|
+
/** Batch lookup used by mailbox projection; implementations must not turn one poll into N queries. */
|
|
145
|
+
getMany(tenant: TenantId, taskIds: readonly string[]): Promise<readonly TaskAttempt[]>;
|
|
137
146
|
/** First claim wins the ownership; a later claim by the same device is idempotent. No-op (returns `undefined`) for a task this tenant never offered. */
|
|
138
147
|
claim(tenant: TenantId, input: {
|
|
139
148
|
readonly taskId: string;
|
|
@@ -145,6 +154,24 @@ export interface TaskAttemptStore {
|
|
|
145
154
|
readonly status: TaskAttemptStatus;
|
|
146
155
|
}): Promise<TaskAttempt | undefined>;
|
|
147
156
|
}
|
|
157
|
+
export interface TaskCancellationRequest {
|
|
158
|
+
readonly taskId: string;
|
|
159
|
+
readonly proposedMessageId: string;
|
|
160
|
+
readonly reason?: string;
|
|
161
|
+
readonly materialize: (seq: number, messageId: string) => MailboxBody | Promise<MailboxBody>;
|
|
162
|
+
}
|
|
163
|
+
export interface TaskCancellationMutation {
|
|
164
|
+
readonly attempt: TaskAttempt;
|
|
165
|
+
/** Absent only when the task was already complete or failed before cancellation. */
|
|
166
|
+
readonly message?: MailboxMessage;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* One atomic authority for the cancellation tombstone plus its durable device
|
|
170
|
+
* delivery. Implementations must commit both or neither.
|
|
171
|
+
*/
|
|
172
|
+
export interface TaskCancellationStore {
|
|
173
|
+
request(tenant: TenantId, input: TaskCancellationRequest): Promise<TaskCancellationMutation | undefined>;
|
|
174
|
+
}
|
|
148
175
|
export interface RequestReceipt {
|
|
149
176
|
readonly tenantId: TenantId;
|
|
150
177
|
readonly key: string;
|
|
@@ -288,11 +315,12 @@ export interface CloudStores {
|
|
|
288
315
|
readonly nonces: NonceStore;
|
|
289
316
|
readonly dedup: InboundDedupStore;
|
|
290
317
|
readonly tasks: TaskAttemptStore;
|
|
318
|
+
readonly cancellations: TaskCancellationStore;
|
|
291
319
|
readonly receipts: RequestReceiptStore;
|
|
292
320
|
readonly proofReceipts: ProofRequestReceiptStore;
|
|
293
321
|
readonly blobs: CloudBlobStore;
|
|
294
322
|
readonly rateLimiter: InboundRateLimiter;
|
|
295
323
|
}
|
|
296
324
|
/** Names of every port in {@link CloudStores}, in contract order. */
|
|
297
|
-
export declare const CLOUD_STORE_NAMES: readonly ['activity', 'approvals', 'devices', 'pairingCodes', 'nonces', 'dedup', 'tasks', 'receipts', 'proofReceipts', 'blobs', 'rateLimiter'];
|
|
325
|
+
export declare const CLOUD_STORE_NAMES: readonly ['activity', 'approvals', 'devices', 'pairingCodes', 'nonces', 'dedup', 'tasks', 'cancellations', 'receipts', 'proofReceipts', 'blobs', 'rateLimiter'];
|
|
298
326
|
export type CloudStoreName = (typeof CLOUD_STORE_NAMES)[number];
|
package/dist/tenant-stores.d.ts
CHANGED
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
* presigned blob calls) are deliberately absent from this surface: a
|
|
22
22
|
* device-facing handler must not be able to reach them.
|
|
23
23
|
*/
|
|
24
|
-
import { type BoardClaimInput, type BoardItem, type BoardItemInput, type BoardListQuery, type BoardPage, type BoardStatusUpdateInput, type BoardUnclaimInput, type CoreStores, type MailboxAdvanceCursorInput, type MailboxAppendInput, type MailboxCursorState, type MailboxMessage, type MailboxPage, type MailboxReadQuery, type Principal, type PresenceHint, type PresenceHintInput, type StorageFinalizeInput, type StorageFinalizeResult, type StorageReservation, type StorageReservationInput, type TenantId } from '@byok-sdk/core';
|
|
24
|
+
import { type BoardClaimInput, type BoardItem, type BoardItemInput, type BoardListQuery, type BoardPage, type BoardStatusUpdateInput, type BoardUnclaimInput, type CoreStores, type MailboxAdvanceCursorInput, type MailboxAppendInput, type MailboxCursorState, type MailboxMessage, type MailboxPage, type MailboxReadQuery, type Principal, type PresenceHint, type PresenceHintInput, type TenantReadiness, type StorageFinalizeInput, type StorageFinalizeResult, type StorageReservation, type StorageReservationInput, type TenantId } from '@byok-sdk/core';
|
|
25
25
|
import type { ActivityAppendInput, ActivityTail } from './activity';
|
|
26
26
|
import type { ApprovalTimelineAppendInput, ApprovalTimelineTail } from './approval-timeline';
|
|
27
|
-
import type { BlobObservation, CloudStores, DeviceRecord, RequestReceipt, TaskAttempt, TaskAttemptStatus } from './stores/ports';
|
|
27
|
+
import type { BlobObservation, CloudStores, DeviceRecord, RequestReceipt, TaskCancellationMutation, TaskCancellationRequest, TaskAttempt, TaskAttemptStatus } from './stores/ports';
|
|
28
28
|
export interface TenantBoundMailbox {
|
|
29
29
|
append(input: MailboxAppendInput): Promise<MailboxMessage>;
|
|
30
30
|
/** Pure read. Never advances the cursor — the daemon's next poll is the only ack. */
|
|
@@ -57,6 +57,7 @@ export interface TenantBoundDevices {
|
|
|
57
57
|
get(deviceId: string): Promise<DeviceRecord | undefined>;
|
|
58
58
|
list(): Promise<readonly DeviceRecord[]>;
|
|
59
59
|
revoke(deviceId: string): Promise<void>;
|
|
60
|
+
readiness(): Promise<TenantReadiness>;
|
|
60
61
|
}
|
|
61
62
|
export interface TenantBoundTaskAttempts {
|
|
62
63
|
open(input: {
|
|
@@ -64,6 +65,7 @@ export interface TenantBoundTaskAttempts {
|
|
|
64
65
|
readonly deviceId: string;
|
|
65
66
|
}): Promise<TaskAttempt>;
|
|
66
67
|
get(taskId: string): Promise<TaskAttempt | undefined>;
|
|
68
|
+
getMany(taskIds: readonly string[]): Promise<readonly TaskAttempt[]>;
|
|
67
69
|
claim(input: {
|
|
68
70
|
readonly taskId: string;
|
|
69
71
|
readonly deviceId: string;
|
|
@@ -73,6 +75,9 @@ export interface TenantBoundTaskAttempts {
|
|
|
73
75
|
readonly status: TaskAttemptStatus;
|
|
74
76
|
}): Promise<TaskAttempt | undefined>;
|
|
75
77
|
}
|
|
78
|
+
export interface TenantBoundTaskCancellations {
|
|
79
|
+
request(input: TaskCancellationRequest): Promise<TaskCancellationMutation | undefined>;
|
|
80
|
+
}
|
|
76
81
|
export interface TenantBoundDedup {
|
|
77
82
|
checkAndRecord(deviceId: string, envelopeId: string): Promise<boolean>;
|
|
78
83
|
}
|
|
@@ -113,6 +118,7 @@ export interface TenantStores {
|
|
|
113
118
|
readonly approvals: TenantBoundApprovalTimeline;
|
|
114
119
|
readonly devices: TenantBoundDevices;
|
|
115
120
|
readonly tasks: TenantBoundTaskAttempts;
|
|
121
|
+
readonly cancellations: TenantBoundTaskCancellations;
|
|
116
122
|
readonly dedup: TenantBoundDedup;
|
|
117
123
|
readonly receipts: TenantBoundReceipts;
|
|
118
124
|
readonly blobs: TenantBoundBlobs;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type BlobRef } from '@byok-sdk/protocol';
|
|
1
|
+
import { type BlobRef, type TerminalInferenceUsage } from '@byok-sdk/protocol';
|
|
2
2
|
import type { RequestReceipt } from './stores/ports';
|
|
3
3
|
/**
|
|
4
4
|
* The typed terminal read model — the hosted counterpart of the embedded
|
|
@@ -20,6 +20,12 @@ export interface TerminalResult {
|
|
|
20
20
|
* `resultDocument` extractor.
|
|
21
21
|
*/
|
|
22
22
|
readonly document?: unknown;
|
|
23
|
+
/**
|
|
24
|
+
* Device/runtime terminal observation copied from the canonical winning
|
|
25
|
+
* receipt. It is telemetry only — never cloud storage usage, billing, quota
|
|
26
|
+
* or entitlement authority.
|
|
27
|
+
*/
|
|
28
|
+
readonly usage?: TerminalInferenceUsage;
|
|
23
29
|
readonly reason?: string;
|
|
24
30
|
readonly retryable?: boolean;
|
|
25
31
|
/** When the receipt store wrote the terminal fact — the first one, by its own first-write-wins rule. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byok-sdk/cloud",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "BYOK SDK hosted device surface: stateless frozen-v1 HTTP handlers over tenant-first @byok-sdk/core ports",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"clean": "rm -rf dist"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@byok-sdk/core": "0.
|
|
48
|
-
"@byok-sdk/protocol": "0.
|
|
47
|
+
"@byok-sdk/core": "0.6.0",
|
|
48
|
+
"@byok-sdk/protocol": "0.6.0",
|
|
49
49
|
"hono": "^4.12.30",
|
|
50
50
|
"zod": "^4.4.3"
|
|
51
51
|
}
|