@byok-sdk/server 0.11.0 → 0.12.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/pairing.d.ts CHANGED
@@ -20,10 +20,27 @@ export interface PairingCodeInfo {
20
20
  code: string;
21
21
  expiresAt: string;
22
22
  }
23
+ /** Immutable facts supplied by one first-pair HTTP request. */
24
+ export interface PairingAttemptBinding {
25
+ deviceName: string;
26
+ devicePublicKey: string;
27
+ }
28
+ /** The recoverable enrollment fact created exactly once for one pairing code. */
29
+ export interface PairingCompletion {
30
+ deviceId: string;
31
+ tenantId: TenantId;
32
+ productId: string;
33
+ deviceName: string;
34
+ devicePublicKey: string;
35
+ }
23
36
  /** Thrown when a pairing code is missing, expired, or already used. */
24
37
  export declare class PairingCodeInvalidError extends Error {
25
38
  constructor(reason: string);
26
39
  }
40
+ /** A spent code may be replayed only with the immutable request that spent it. */
41
+ export declare class PairingAttemptConflictError extends Error {
42
+ constructor();
43
+ }
27
44
  /**
28
45
  * In-memory pairing-code lifecycle: single-use, ~10min TTL codes minted
29
46
  * out-of-band (by the SaaS's own auth/device-flow UI) and redeemed exactly
@@ -55,4 +72,16 @@ export declare class PairingManager {
55
72
  * code can never reach the registration step at all.
56
73
  */
57
74
  redeemPairingCode(code: string): PairingCodeClaims;
75
+ /**
76
+ * Bind a code to one exact pairing request, returning any completion that a
77
+ * prior response/token failure left recoverable. This mutation is entirely
78
+ * synchronous: the HTTP route cannot yield between binding, registration,
79
+ * and completion recording, so concurrent requests have one winner.
80
+ */
81
+ beginPairingAttempt(code: string, binding: PairingAttemptBinding): {
82
+ claims: PairingCodeClaims;
83
+ completion?: PairingCompletion;
84
+ };
85
+ /** Record the one device identity a bound pairing attempt completed as. */
86
+ completePairingAttempt(code: string, binding: PairingAttemptBinding, completion: PairingCompletion): PairingCompletion;
58
87
  }
@@ -1,5 +1,6 @@
1
1
  import type { DatabaseSync } from 'node:sqlite';
2
2
  import { type BlobStore, type CreateUploadInput, type ReadContentResult, type WriteContentResult } from './blob-store';
3
+ import type { TenantId } from './auth';
3
4
  export interface SqliteBlobStoreOptions {
4
5
  /**
5
6
  * Database file path. Use `:memory:` to exercise the SQLite code path
@@ -24,7 +25,7 @@ export interface SqliteBlobStoreOptions {
24
25
  signingKey?: Buffer;
25
26
  }
26
27
  /** Exported (only) so `sqlite-blob-store.test.ts` can apply the same schema to a raw `DatabaseSync` connection when testing {@link loadOrCreateSigningSecret}'s concurrency behavior directly. */
27
- export declare const SCHEMA = "\nCREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\nCREATE TABLE IF NOT EXISTS blobs (\n blob_id TEXT PRIMARY KEY,\n size INTEGER NOT NULL,\n content_type TEXT NOT NULL,\n content_hash TEXT NOT NULL,\n uploaded INTEGER NOT NULL DEFAULT 0,\n data BLOB\n);\n";
28
+ export declare const SCHEMA = "\nCREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\nCREATE TABLE IF NOT EXISTS blobs (\n blob_id TEXT PRIMARY KEY,\n tenant_id TEXT NOT NULL,\n size INTEGER NOT NULL,\n content_type TEXT NOT NULL,\n content_hash TEXT NOT NULL,\n uploaded INTEGER NOT NULL DEFAULT 0,\n data BLOB\n);\n";
28
29
  /**
29
30
  * Atomically load the persisted HMAC signing secret from `db`'s `meta`
30
31
  * table, generating and persisting one if none exists yet.
@@ -74,12 +75,15 @@ export declare class SqliteBlobStore implements BlobStore {
74
75
  private readonly writeContentStmt;
75
76
  private closed;
76
77
  constructor(opts: SqliteBlobStoreOptions);
77
- createUpload(input: CreateUploadInput, requestedBlobId?: string): Promise<{
78
+ createUpload(tenantId: TenantId, input: CreateUploadInput, requestedBlobId?: string): Promise<{
78
79
  blobId: string;
79
80
  uploadUrl: string;
80
81
  }>;
81
- getDownloadUrl(blobId: string): Promise<string | undefined>;
82
- exists(blobId: string): Promise<boolean>;
82
+ getDownloadUrl(tenantId: TenantId, blobId: string): Promise<string | undefined>;
83
+ exists(tenantId: TenantId, blobId: string): Promise<boolean>;
84
+ getUploadReservation(blobId: string): Promise<{
85
+ size: number;
86
+ } | undefined>;
83
87
  verifySignedUrl(blobId: string, action: 'put' | 'get', sig: string, exp: number): boolean;
84
88
  writeContent(blobId: string, data: Buffer): Promise<WriteContentResult>;
85
89
  readContent(blobId: string): Promise<ReadContentResult | undefined>;
package/dist/types.d.ts CHANGED
@@ -14,6 +14,12 @@ export interface CreateByokServerOptions {
14
14
  productId: string;
15
15
  /** WS-native ping interval, ms (§ heartbeat). Default 30s. */
16
16
  heartbeatIntervalMs?: number;
17
+ /** Deadline for one authenticated socket to present a valid `conn.hello`. Default 5s. */
18
+ webSocketHelloTimeoutMs?: number;
19
+ /** Global cap for authenticated sockets that have not completed `conn.hello`. Default 32. */
20
+ maxPendingWebSockets?: number;
21
+ /** Maximum inbound WS message bytes before envelope decoding. Default accommodates the largest protocol document envelope. */
22
+ maxWebSocketPayloadBytes?: number;
17
23
  /** How long `GET /byok/events` holds an empty poll open before returning, ms (§8). Default ~50s; override for tests. */
18
24
  longPollHoldMs?: number;
19
25
  /** Per-product blob size ceiling in bytes (§7). Default 100MB. */
@@ -6,6 +6,9 @@ interface AttachDeps extends AuthDeps {
6
6
  productId: string;
7
7
  /** WS-native ping interval, ms. Defaults inside `heartbeat.ts` (30s) if omitted. */
8
8
  heartbeatIntervalMs?: number;
9
+ helloTimeoutMs: number;
10
+ maxPendingWebSockets: number;
11
+ maxPayloadBytes: number;
9
12
  }
10
13
  /**
11
14
  * Wire up the `GET /byok/ws` upgrade on a raw Node HTTP server (the one
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byok-sdk/server",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "BYOK SDK server: in-memory M0 reference implementation of the SaaS-side coordinator",
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.11.0",
48
- "@byok-sdk/protocol": "0.11.0",
47
+ "@byok-sdk/core": "0.12.0",
48
+ "@byok-sdk/protocol": "0.12.0",
49
49
  "@hono/node-server": "^2.0.10",
50
50
  "hono": "^4.12.30",
51
51
  "jose": "^6.2.3",