@byok-sdk/core 0.26.1 → 0.27.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/dist/mailbox.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { CollectExpiredInput, CollectExpiredResult } from './retention';
1
2
  /**
2
3
  * Hosted mailbox contract (§12.7.3).
3
4
  *
@@ -41,6 +42,22 @@ export interface MailboxBody {
41
42
  readonly bodyHash: ContentHash;
42
43
  readonly byteSize: bigint;
43
44
  }
45
+ /**
46
+ * How an append is admitted against the tenant's `mailboxLimitBytes`.
47
+ *
48
+ * Mailbox bytes have one authority: the retained rows. Usage is the tenant's
49
+ * `SUM(byteSize)` over every retained row in any state, and the limit is
50
+ * checked in the same serialized unit that inserts the row — there is no
51
+ * counter for a writer to forget, so deleting a row needs no accounting.
52
+ *
53
+ * - `limited`: refused with `storage_quota_exceeded` when `used + byteSize`
54
+ * exceeds the limit, and with `storage_entitlement_missing` when the tenant
55
+ * has no entitlement. A refused append consumes no `seq`.
56
+ * - `cancellation`: always admitted and still counted. Reserved for the one
57
+ * cancellation row a task can own, so a full mailbox never blocks
58
+ * `cancelTask`.
59
+ */
60
+ export type MailboxAdmission = 'limited' | 'cancellation';
44
61
  export interface MailboxAppendInput {
45
62
  readonly deviceId: string;
46
63
  /**
@@ -57,6 +74,16 @@ export interface MailboxAppendInput {
57
74
  * out of order and let an ack skip a late lower sequence.
58
75
  */
59
76
  readonly materialize: (seq: number) => MailboxBody | Promise<MailboxBody>;
77
+ /**
78
+ * Limit admission for a NEW row. An existing `messageId` returns its row
79
+ * before any check, so a retry is never refused for capacity.
80
+ */
81
+ readonly admission: MailboxAdmission;
82
+ }
83
+ /** Tenant mailbox usage, derived from the retained rows on every read. */
84
+ export interface MailboxUsage {
85
+ /** `SUM(byteSize)` over every retained row (`pending`, `acked`, `expired`). */
86
+ readonly bytes: bigint;
60
87
  }
61
88
  export interface MailboxReadQuery {
62
89
  readonly deviceId: string;
@@ -90,7 +117,7 @@ export interface MailboxPage {
90
117
  * retained, which §12.7.5 requires.
91
118
  *
92
119
  * This is a READ of the retained window, never a second retention authority:
93
- * `collectRetired` decides what is retained, this reports what it cost.
120
+ * `collectExpired` decides what is retained, this reports what it cost.
94
121
  */
95
122
  readonly recoverableFrom: number;
96
123
  }
@@ -123,18 +150,12 @@ export interface MailboxCursorState {
123
150
  * `timestamptz` comparison read differently is the worst place to guess — see
124
151
  * `time.ts`.
125
152
  */
126
- export interface MailboxRetentionInput {
127
- readonly deviceId?: string;
153
+ export interface MailboxCollectExpiredInput extends CollectExpiredInput {
128
154
  /** Acked rows appended before this instant are deleted. */
129
155
  readonly ackedBefore: string;
130
156
  /** Unacked rows appended before this instant move to `expired`, never deleted here. */
131
157
  readonly expireUnackedBefore: string;
132
158
  }
133
- export interface MailboxRetentionResult {
134
- readonly deletedCount: number;
135
- readonly expiredCount: number;
136
- readonly releasedBytes: bigint;
137
- }
138
159
  /**
139
160
  * Mailbox port. Tenant-first, async.
140
161
  *
@@ -143,10 +164,13 @@ export interface MailboxRetentionResult {
143
164
  * `mailbox_cursor_ahead_of_delivery` (an ack beyond the highest cursor the
144
165
  * server has returned to that device),
145
166
  * `timestamp_not_canonical` (a retention cutoff that is not a canonical
146
- * ISO-8601 UTC instant).
167
+ * ISO-8601 UTC instant), `storage_quota_exceeded` and
168
+ * `storage_entitlement_missing` (a `limited` append refused at admission).
147
169
  */
148
170
  export interface MailboxStore {
149
171
  append(tenant: TenantId, input: MailboxAppendInput): Promise<MailboxMessage>;
172
+ /** The tenant's mailbox bytes, summed from the retained rows. */
173
+ readUsage(tenant: TenantId): Promise<MailboxUsage>;
150
174
  /** Pure read. Never advances the cursor, never deletes, never marks acked. */
151
175
  readAfter(tenant: TenantId, query: MailboxReadQuery): Promise<MailboxPage>;
152
176
  /** Records the highest cursor a device-facing response is about to return. */
@@ -155,5 +179,5 @@ export interface MailboxStore {
155
179
  advanceCursor(tenant: TenantId, input: MailboxAdvanceCursorInput): Promise<MailboxCursorState>;
156
180
  readCursor(tenant: TenantId, deviceId: string): Promise<MailboxCursorState>;
157
181
  /** Retention hook: delete acked rows, dead-letter unacked ones. */
158
- collectRetired(tenant: TenantId, input: MailboxRetentionInput): Promise<MailboxRetentionResult>;
182
+ collectExpired(tenant: TenantId, input: MailboxCollectExpiredInput): Promise<CollectExpiredResult>;
159
183
  }
@@ -1,3 +1,4 @@
1
+ import type { CollectExpiredInput, CollectExpiredResult } from './retention';
1
2
  /**
2
3
  * Presence hints (§12.3).
3
4
  *
@@ -100,6 +101,7 @@ export interface PresenceHintInput {
100
101
  * expired hint is indistinguishable from one that was never written.
101
102
  */
102
103
  export interface PresenceStore {
104
+ collectExpired(tenant: TenantId, input: CollectExpiredInput): Promise<CollectExpiredResult>;
103
105
  publish(tenant: TenantId, input: PresenceHintInput): Promise<PresenceHint>;
104
106
  read(tenant: TenantId, deviceId: string): Promise<PresenceHint | undefined>;
105
107
  list(tenant: TenantId): Promise<readonly PresenceHint[]>;
package/dist/quota.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { CollectExpiredInput, CollectExpiredResult } from './retention';
1
2
  /**
2
3
  * Tenant storage entitlement, usage, reservation and retention (§12.7.6-12.7.7).
3
4
  *
@@ -47,7 +48,6 @@ export interface TenantStorageUsage {
47
48
  committedObjectBytes: bigint;
48
49
  committedInlineBytes: bigint;
49
50
  reservedBytes: bigint;
50
- mailboxBytes: bigint;
51
51
  objectCount: bigint;
52
52
  updatedAt: string;
53
53
  }
@@ -146,10 +146,6 @@ export declare const STORAGE_ERROR_HTTP_STATUS: {
146
146
  readonly storage_integrity_mismatch: 422;
147
147
  readonly storage_write_suspended: 423;
148
148
  };
149
- export interface MailboxUsageDeltaInput {
150
- /** Signed. Negative deltas release bytes after retention deletes rows. */
151
- readonly deltaBytes: bigint;
152
- }
153
149
  /**
154
150
  * Quota port. Tenant-first, async.
155
151
  *
@@ -158,6 +154,7 @@ export interface MailboxUsageDeltaInput {
158
154
  * `storage_reservation_not_found`, and the five wire-stable codes above.
159
155
  */
160
156
  export interface QuotaStore {
157
+ collectExpired(tenant: TenantId, input: QuotaCollectExpiredInput): Promise<CollectExpiredResult>;
161
158
  readEntitlement(tenant: TenantId): Promise<TenantStorageEntitlement | undefined>;
162
159
  /**
163
160
  * Version CAS: a write at or below the stored version is rejected with the
@@ -182,8 +179,7 @@ export interface QuotaStore {
182
179
  finalizeReservation(tenant: TenantId, input: StorageFinalizeInput): Promise<StorageFinalizeResult>;
183
180
  /** Idempotent release. Already-settled reservations return their settled row. */
184
181
  abortReservation(tenant: TenantId, reservationId: string): Promise<StorageReservation>;
185
- /** Cleanup hook: expires reservations past their TTL and releases their bytes. */
186
- expireReservations(tenant: TenantId): Promise<readonly StorageReservation[]>;
187
- /** Mailbox bytes are platform-protection accounting, bounded by `mailboxLimitBytes`. */
188
- applyMailboxDelta(tenant: TenantId, input: MailboxUsageDeltaInput): Promise<TenantStorageUsage>;
182
+ }
183
+ export interface QuotaCollectExpiredInput extends CollectExpiredInput {
184
+ readonly settledBefore: string;
189
185
  }
@@ -0,0 +1,21 @@
1
+ import { ByokCoreError } from './errors';
2
+ export interface CollectExpiredInput {
3
+ readonly now: string;
4
+ readonly limit: number;
5
+ }
6
+ export interface CollectExpiredCounts {
7
+ readonly removed: number;
8
+ readonly expired: number;
9
+ readonly releasedBytes: bigint;
10
+ }
11
+ export interface CollectExpiredResult extends CollectExpiredCounts {
12
+ readonly more: boolean;
13
+ }
14
+ export declare function assertCollectExpiredInput(input: CollectExpiredInput): void;
15
+ /** A committed partial result remains visible when external deletion fails. */
16
+ export declare class CollectExpiredFailure extends ByokCoreError {
17
+ readonly committed: CollectExpiredCounts;
18
+ readonly failedRows: number;
19
+ readonly more?: boolean | undefined;
20
+ constructor(committed: CollectExpiredCounts, failedRows: number, more?: boolean | undefined, options?: ErrorOptions);
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byok-sdk/core",
3
- "version": "0.26.1",
3
+ "version": "0.27.0",
4
4
  "description": "BYOK SDK platform contracts: branded tenant identity, tenant-first store ports, device proof canonicalization, and the composition conformance reference",
5
5
  "type": "module",
6
6
  "license": "MIT",