@creatornader/agent-bridge 0.2.0 → 0.3.1
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/CHANGELOG.md +86 -4
- package/README.md +567 -55
- package/ROADMAP.md +114 -0
- package/SECURITY.md +90 -0
- package/SKILL.md +68 -2
- package/bin/agent-bridge +2 -2
- package/clients/claude-desktop.json +3 -1
- package/dist/archive.d.ts +163 -0
- package/dist/archive.js +50 -0
- package/dist/archive.js.map +1 -0
- package/dist/bridge-domain-CBX3IVqC.d.ts +153 -0
- package/dist/{bridge-service-CfqMcMAn.d.ts → bridge-service-hX1ZQp4W.d.ts} +15 -5
- package/dist/bridge-store-DPVSCwfs.d.ts +102 -0
- package/dist/bridge.d.ts +76 -17
- package/dist/bridge.js +52 -24
- package/dist/chunk-2DFNOLMO.js +618 -0
- package/dist/chunk-2DFNOLMO.js.map +1 -0
- package/dist/{chunk-KVR4JBRF.js → chunk-2EVLG3YA.js} +2 -2
- package/dist/{chunk-KVR4JBRF.js.map → chunk-2EVLG3YA.js.map} +1 -1
- package/dist/chunk-45BZGB77.js +709 -0
- package/dist/chunk-45BZGB77.js.map +1 -0
- package/dist/chunk-4VB44KJU.js +230 -0
- package/dist/chunk-4VB44KJU.js.map +1 -0
- package/dist/chunk-5GMB3A77.js +1013 -0
- package/dist/chunk-5GMB3A77.js.map +1 -0
- package/dist/chunk-A6W4QALF.js +1258 -0
- package/dist/chunk-A6W4QALF.js.map +1 -0
- package/dist/chunk-BZLMF5O5.js +328 -0
- package/dist/chunk-BZLMF5O5.js.map +1 -0
- package/dist/{chunk-AXL2I7FH.js → chunk-CEXBMOI5.js} +240 -79
- package/dist/chunk-CEXBMOI5.js.map +1 -0
- package/dist/chunk-GADH244D.js +527 -0
- package/dist/chunk-GADH244D.js.map +1 -0
- package/dist/chunk-MBPZXTJA.js +2428 -0
- package/dist/chunk-MBPZXTJA.js.map +1 -0
- package/dist/chunk-NCO7RLBM.js +146 -0
- package/dist/chunk-NCO7RLBM.js.map +1 -0
- package/dist/chunk-Q6PPMXJC.js +1050 -0
- package/dist/chunk-Q6PPMXJC.js.map +1 -0
- package/dist/{chunk-4KAOBC5X.js → chunk-SPSMZOCJ.js} +190 -165
- package/dist/chunk-SPSMZOCJ.js.map +1 -0
- package/dist/chunk-UAHMP6GC.js +54 -0
- package/dist/chunk-UAHMP6GC.js.map +1 -0
- package/dist/{chunk-YD6YJATN.js → chunk-VOQIDTCJ.js} +4 -2
- package/dist/chunk-VOQIDTCJ.js.map +1 -0
- package/dist/chunk-WAI2IYIQ.js +554 -0
- package/dist/chunk-WAI2IYIQ.js.map +1 -0
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +3555 -214
- package/dist/cli.js.map +1 -1
- package/dist/client-config.d.ts +1 -1
- package/dist/client-config.js +1 -1
- package/dist/client-runtime.d.ts +10 -6
- package/dist/client-runtime.js +9 -6
- package/dist/contracts/generate.d.ts +2 -0
- package/dist/contracts/generate.js +247 -0
- package/dist/contracts/generate.js.map +1 -0
- package/dist/dr.d.ts +324 -0
- package/dist/dr.js +124 -0
- package/dist/dr.js.map +1 -0
- package/dist/gateway-CggQ8vTC.d.ts +78 -0
- package/dist/gateway-main.js +190 -8
- package/dist/gateway-main.js.map +1 -1
- package/dist/gateway.d.ts +4 -3
- package/dist/gateway.js +4 -3
- package/dist/index.js +11 -8
- package/dist/index.js.map +1 -1
- package/dist/postgres-bridge-store-Bfd3hRId.d.ts +49 -0
- package/dist/server.d.ts +3 -2
- package/dist/server.js +13 -8
- package/dist/sqlite.d.ts +94 -12
- package/dist/sqlite.js +7 -4
- package/docs/architecture-v2.md +394 -0
- package/docs/decisions/0001-protocol-layers-and-acknowledgment-semantics.md +85 -0
- package/docs/decisions/0002-canonical-operation-contract-registry.md +46 -0
- package/docs/decisions/0003-host-adapters-and-consumer-instance-keys.md +88 -0
- package/docs/ecosystem.md +86 -0
- package/docs/postmortems/2026-07-08-wrapper-source-drift.md +82 -0
- package/docs/troubleshooting.md +89 -0
- package/llms.txt +107 -6
- package/openapi/agent-bridge-v2.openapi.json +9610 -0
- package/package.json +24 -4
- package/schemas/agent-bridge-v2.capabilities.json +1829 -0
- package/schemas/agent-bridge-v2.mcp.json +2074 -0
- package/schemas/agent-bridge-v2.schema.json +4560 -0
- package/sql/migrations/008_message_projects.sql +36 -0
- package/sql/migrations/009_mailbox_query_indexes.sql +28 -0
- package/sql/migrations/010_publisher_delivery_policy.sql +210 -0
- package/sql/migrations/011_credential_security.sql +875 -0
- package/sql/migrations/012_request_authority.sql +177 -0
- package/sql/migrations/013_row_isolation.sql +495 -0
- package/sql/migrations/014_owner_control_plane.sql +1641 -0
- package/sql/migrations/015_portable_archives.sql +1813 -0
- package/sql/migrations/016_native_dr_fence.sql +1005 -0
- package/bin/CLAUDE.md +0 -11
- package/dist/bridge-domain-BcnBeHOn.d.ts +0 -97
- package/dist/bridge-store-BuGjxTn4.d.ts +0 -61
- package/dist/chunk-4KAOBC5X.js.map +0 -1
- package/dist/chunk-6MAZ6YLZ.js +0 -146
- package/dist/chunk-6MAZ6YLZ.js.map +0 -1
- package/dist/chunk-AXL2I7FH.js.map +0 -1
- package/dist/chunk-BV6W4AJK.js +0 -211
- package/dist/chunk-BV6W4AJK.js.map +0 -1
- package/dist/chunk-CKSKUBDQ.js +0 -153
- package/dist/chunk-CKSKUBDQ.js.map +0 -1
- package/dist/chunk-JOUBDRYX.js +0 -272
- package/dist/chunk-JOUBDRYX.js.map +0 -1
- package/dist/chunk-JTC5YURG.js +0 -49
- package/dist/chunk-JTC5YURG.js.map +0 -1
- package/dist/chunk-O26W5QHS.js +0 -409
- package/dist/chunk-O26W5QHS.js.map +0 -1
- package/dist/chunk-WEULPMUY.js +0 -988
- package/dist/chunk-WEULPMUY.js.map +0 -1
- package/dist/chunk-YD6YJATN.js.map +0 -1
- package/dist/gateway-BULozv3K.d.ts +0 -54
package/dist/chunk-BV6W4AJK.js
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/atrib-receipt.ts
|
|
4
|
-
var ATRIB_RECEIPT_ID_RE = /^[A-Za-z0-9_-]{43}\.[A-Za-z0-9_-]{43}$/;
|
|
5
|
-
function normalizeReceiptId(value) {
|
|
6
|
-
if (typeof value !== "string") return void 0;
|
|
7
|
-
if (!ATRIB_RECEIPT_ID_RE.test(value)) return void 0;
|
|
8
|
-
return value;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// src/bridge-domain.ts
|
|
12
|
-
import { randomBytes } from "crypto";
|
|
13
|
-
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
14
|
-
var SEQUENCE_RE = /^(0|[1-9][0-9]*)$/;
|
|
15
|
-
var POSTGRES_BIGINT_MAX = 9223372036854775807n;
|
|
16
|
-
var TEXT_LIMIT = 64 * 1024;
|
|
17
|
-
var JSON_DEPTH_LIMIT = 16;
|
|
18
|
-
var RECORD_HASH_RE = /^sha256:[a-f0-9]{64}$/i;
|
|
19
|
-
var BridgeValidationError = class extends Error {
|
|
20
|
-
constructor() {
|
|
21
|
-
super(...arguments);
|
|
22
|
-
this.code = "invalid_input";
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
function clean(value, field, max = 512) {
|
|
26
|
-
if (typeof value !== "string" || !value.trim()) {
|
|
27
|
-
throw new BridgeValidationError(`${field} is required`);
|
|
28
|
-
}
|
|
29
|
-
const result = value.trim();
|
|
30
|
-
if (result.length > max) {
|
|
31
|
-
throw new BridgeValidationError(`${field} exceeds ${max} characters`);
|
|
32
|
-
}
|
|
33
|
-
return result;
|
|
34
|
-
}
|
|
35
|
-
function content(value) {
|
|
36
|
-
if (typeof value !== "string" || !value.trim()) {
|
|
37
|
-
throw new BridgeValidationError("content is required");
|
|
38
|
-
}
|
|
39
|
-
if (Buffer.byteLength(value) > TEXT_LIMIT) {
|
|
40
|
-
throw new BridgeValidationError(`content exceeds ${TEXT_LIMIT} bytes`);
|
|
41
|
-
}
|
|
42
|
-
return value;
|
|
43
|
-
}
|
|
44
|
-
function optional(value, field, max = 512) {
|
|
45
|
-
if (value === void 0 || value === null) return void 0;
|
|
46
|
-
return clean(value, field, max);
|
|
47
|
-
}
|
|
48
|
-
function timestamp(value, field) {
|
|
49
|
-
const raw = optional(value, field);
|
|
50
|
-
if (!raw) return void 0;
|
|
51
|
-
const date = new Date(raw);
|
|
52
|
-
if (Number.isNaN(date.getTime())) {
|
|
53
|
-
throw new BridgeValidationError(`${field} must be an ISO timestamp`);
|
|
54
|
-
}
|
|
55
|
-
return date.toISOString();
|
|
56
|
-
}
|
|
57
|
-
function assertJsonDepth(value, depth = 0) {
|
|
58
|
-
if (depth > JSON_DEPTH_LIMIT) {
|
|
59
|
-
throw new BridgeValidationError(`JSON exceeds ${JSON_DEPTH_LIMIT} levels`);
|
|
60
|
-
}
|
|
61
|
-
if (Array.isArray(value)) {
|
|
62
|
-
for (const entry of value) assertJsonDepth(entry, depth + 1);
|
|
63
|
-
} else if (value !== null && typeof value === "object") {
|
|
64
|
-
for (const entry of Object.values(value)) assertJsonDepth(entry, depth + 1);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function json(value, field) {
|
|
68
|
-
if (value === void 0) return void 0;
|
|
69
|
-
try {
|
|
70
|
-
const serialized = JSON.stringify(value);
|
|
71
|
-
if (!serialized || Buffer.byteLength(serialized) > TEXT_LIMIT) throw new Error();
|
|
72
|
-
const parsed = JSON.parse(serialized);
|
|
73
|
-
assertJsonDepth(parsed);
|
|
74
|
-
return parsed;
|
|
75
|
-
} catch (error) {
|
|
76
|
-
if (error instanceof BridgeValidationError) throw error;
|
|
77
|
-
throw new BridgeValidationError(`${field} must be JSON and at most ${TEXT_LIMIT} bytes`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function stringArray(value, field, limit, itemLimit) {
|
|
81
|
-
if (value === void 0) return [];
|
|
82
|
-
if (!Array.isArray(value)) {
|
|
83
|
-
throw new BridgeValidationError(`${field} must be an array`);
|
|
84
|
-
}
|
|
85
|
-
const result = [...new Set(value.map((entry) => clean(entry, field, itemLimit)))];
|
|
86
|
-
if (result.length > limit) {
|
|
87
|
-
throw new BridgeValidationError(`${field} exceeds ${limit} entries`);
|
|
88
|
-
}
|
|
89
|
-
return result;
|
|
90
|
-
}
|
|
91
|
-
function uuidv7(now = Date.now()) {
|
|
92
|
-
if (!Number.isSafeInteger(now) || now < 0 || now > 281474976710655) {
|
|
93
|
-
throw new BridgeValidationError("UUIDv7 timestamp is out of range");
|
|
94
|
-
}
|
|
95
|
-
const bytes = randomBytes(16);
|
|
96
|
-
let timestampValue = BigInt(now);
|
|
97
|
-
for (let index = 5; index >= 0; index -= 1) {
|
|
98
|
-
bytes[index] = Number(timestampValue & 0xffn);
|
|
99
|
-
timestampValue >>= 8n;
|
|
100
|
-
}
|
|
101
|
-
bytes[6] = bytes[6] & 15 | 112;
|
|
102
|
-
bytes[8] = bytes[8] & 63 | 128;
|
|
103
|
-
const hex = bytes.toString("hex");
|
|
104
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
105
|
-
}
|
|
106
|
-
function validatePrincipal(value) {
|
|
107
|
-
return {
|
|
108
|
-
workspace: clean(value?.workspace, "workspace", 128),
|
|
109
|
-
agent: clean(value?.agent, "agent", 128),
|
|
110
|
-
instance: optional(value?.instance, "instance", 128)
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
function validateUuid(value, field) {
|
|
114
|
-
const result = clean(value, field, 64);
|
|
115
|
-
if (!UUID_RE.test(result)) {
|
|
116
|
-
throw new BridgeValidationError(`${field} must be a UUID`);
|
|
117
|
-
}
|
|
118
|
-
return result;
|
|
119
|
-
}
|
|
120
|
-
function validateRetryPolicy(input = {}) {
|
|
121
|
-
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
122
|
-
throw new BridgeValidationError("retryPolicy must be an object");
|
|
123
|
-
}
|
|
124
|
-
const result = {
|
|
125
|
-
maxAttempts: input.maxAttempts ?? 5,
|
|
126
|
-
baseDelayMs: input.baseDelayMs ?? 1e3,
|
|
127
|
-
maxDelayMs: input.maxDelayMs ?? 6e4,
|
|
128
|
-
jitterRatio: input.jitterRatio ?? 0.2
|
|
129
|
-
};
|
|
130
|
-
if (!Number.isSafeInteger(result.maxAttempts) || result.maxAttempts < 1 || result.maxAttempts > 100) {
|
|
131
|
-
throw new BridgeValidationError("maxAttempts must be between 1 and 100");
|
|
132
|
-
}
|
|
133
|
-
if (!Number.isSafeInteger(result.baseDelayMs) || result.baseDelayMs < 1 || result.baseDelayMs > 36e5) {
|
|
134
|
-
throw new BridgeValidationError("baseDelayMs must be between 1 and 3600000");
|
|
135
|
-
}
|
|
136
|
-
if (!Number.isSafeInteger(result.maxDelayMs) || result.maxDelayMs < result.baseDelayMs || result.maxDelayMs > 864e5) {
|
|
137
|
-
throw new BridgeValidationError("maxDelayMs must be at least baseDelayMs and at most 86400000");
|
|
138
|
-
}
|
|
139
|
-
if (!Number.isFinite(result.jitterRatio) || result.jitterRatio < 0 || result.jitterRatio > 1) {
|
|
140
|
-
throw new BridgeValidationError("jitterRatio must be between 0 and 1");
|
|
141
|
-
}
|
|
142
|
-
return result;
|
|
143
|
-
}
|
|
144
|
-
function validateMessageDraft(input) {
|
|
145
|
-
const id = input.id ?? uuidv7();
|
|
146
|
-
if (!UUID_RE.test(id)) throw new BridgeValidationError("id must be a UUID");
|
|
147
|
-
const priority = input.priority ?? "info";
|
|
148
|
-
if (!["info", "high", "urgent"].includes(priority)) {
|
|
149
|
-
throw new BridgeValidationError("priority is invalid");
|
|
150
|
-
}
|
|
151
|
-
const atribReceiptId = optional(input.atribReceiptId, "atribReceiptId", 128);
|
|
152
|
-
if (atribReceiptId && !normalizeReceiptId(atribReceiptId)) {
|
|
153
|
-
throw new BridgeValidationError("atribReceiptId is invalid");
|
|
154
|
-
}
|
|
155
|
-
const informedBy = stringArray(input.informedBy, "informedBy", 64, 128);
|
|
156
|
-
if (informedBy.some((hash) => !RECORD_HASH_RE.test(hash))) {
|
|
157
|
-
throw new BridgeValidationError("informedBy must contain atrib record hashes");
|
|
158
|
-
}
|
|
159
|
-
return {
|
|
160
|
-
id,
|
|
161
|
-
type: clean(input.type, "type", 128),
|
|
162
|
-
content: content(input.content),
|
|
163
|
-
contentType: optional(input.contentType, "contentType", 128) ?? "text/plain",
|
|
164
|
-
data: json(input.data, "data"),
|
|
165
|
-
targets: stringArray(input.targets, "targets", 64, 128),
|
|
166
|
-
threadId: optional(input.threadId, "threadId", 128),
|
|
167
|
-
replyToId: optional(input.replyToId, "replyToId", 128),
|
|
168
|
-
correlationId: optional(input.correlationId, "correlationId", 128),
|
|
169
|
-
causationId: optional(input.causationId, "causationId", 128),
|
|
170
|
-
priority,
|
|
171
|
-
expiresAt: timestamp(input.expiresAt, "expiresAt"),
|
|
172
|
-
idempotencyKey: optional(input.idempotencyKey, "idempotencyKey", 256),
|
|
173
|
-
atribReceiptId,
|
|
174
|
-
informedBy: informedBy.map((hash) => hash.toLowerCase()),
|
|
175
|
-
metadata: json(input.metadata, "metadata")
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
function encodeCursor(sequence) {
|
|
179
|
-
if (!SEQUENCE_RE.test(sequence)) {
|
|
180
|
-
throw new BridgeValidationError("sequence is invalid");
|
|
181
|
-
}
|
|
182
|
-
return Buffer.from(JSON.stringify({ v: 1, sequence })).toString("base64url");
|
|
183
|
-
}
|
|
184
|
-
function decodeCursor(cursor) {
|
|
185
|
-
if (!cursor) return void 0;
|
|
186
|
-
if (typeof cursor !== "string" || cursor.length > 256) {
|
|
187
|
-
throw new BridgeValidationError("cursor is invalid");
|
|
188
|
-
}
|
|
189
|
-
try {
|
|
190
|
-
const parsed = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
|
|
191
|
-
if (parsed?.v !== 1 || typeof parsed.sequence !== "string" || !SEQUENCE_RE.test(parsed.sequence) || BigInt(parsed.sequence) > POSTGRES_BIGINT_MAX) {
|
|
192
|
-
throw new Error();
|
|
193
|
-
}
|
|
194
|
-
return parsed.sequence;
|
|
195
|
-
} catch {
|
|
196
|
-
throw new BridgeValidationError("cursor is invalid");
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export {
|
|
201
|
-
normalizeReceiptId,
|
|
202
|
-
BridgeValidationError,
|
|
203
|
-
uuidv7,
|
|
204
|
-
validatePrincipal,
|
|
205
|
-
validateUuid,
|
|
206
|
-
validateRetryPolicy,
|
|
207
|
-
validateMessageDraft,
|
|
208
|
-
encodeCursor,
|
|
209
|
-
decodeCursor
|
|
210
|
-
};
|
|
211
|
-
//# sourceMappingURL=chunk-BV6W4AJK.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/atrib-receipt.ts","../src/bridge-domain.ts"],"sourcesContent":["// §1.5.2 propagation token: base64url(record_hash).base64url(creator_key),\n// 43 + 1 + 43 = 87 chars. base64url alphabet is A-Z a-z 0-9 _ -.\nconst ATRIB_RECEIPT_ID_RE = /^[A-Za-z0-9_-]{43}\\.[A-Za-z0-9_-]{43}$/;\n\n/**\n * Validate an atrib_receipt_id input. Returns the value if it matches the\n * §1.5.2 token format, otherwise undefined. An atrib-signing wrapper\n * always emits valid tokens, but the field is on the public tool surface:\n * any other producer could send arbitrary strings, and we do not want\n * garbage on the column.\n */\nexport function normalizeReceiptId(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n if (!ATRIB_RECEIPT_ID_RE.test(value)) return undefined;\n return value;\n}\n","import { randomBytes } from \"node:crypto\";\nimport { normalizeReceiptId } from \"./atrib-receipt.js\";\n\nexport type JsonValue =\n | null\n | boolean\n | number\n | string\n | JsonValue[]\n | { [key: string]: JsonValue };\n\nexport type DeliveryState = \"pending\" | \"claimed\" | \"acked\" | \"retrying\" | \"dead\";\nexport type MessagePriority = \"info\" | \"high\" | \"urgent\";\n\nexport interface RetryPolicy {\n maxAttempts: number;\n baseDelayMs: number;\n maxDelayMs: number;\n jitterRatio: number;\n}\n\nexport interface BridgePrincipal {\n workspace: string;\n agent: string;\n instance?: string;\n}\n\nexport interface MessageDraft {\n id?: string;\n type: string;\n content: string;\n contentType?: string;\n data?: JsonValue;\n targets?: string[];\n threadId?: string;\n replyToId?: string;\n correlationId?: string;\n causationId?: string;\n priority?: MessagePriority;\n expiresAt?: string;\n idempotencyKey?: string;\n atribReceiptId?: string;\n informedBy?: string[];\n metadata?: JsonValue;\n}\n\nexport interface BridgeMessage\n extends Required<\n Pick<MessageDraft, \"id\" | \"type\" | \"content\" | \"contentType\" | \"targets\" | \"priority\">\n > {\n workspace: string;\n source: string;\n sequence: string;\n createdAt: string;\n data?: JsonValue;\n threadId?: string;\n replyToId?: string;\n correlationId?: string;\n causationId?: string;\n expiresAt?: string;\n idempotencyKey?: string;\n atribReceiptId?: string;\n informedBy?: string[];\n metadata?: JsonValue;\n}\n\nexport interface BridgeDelivery {\n id: string;\n messageId: string;\n workspace: string;\n recipient: string;\n state: DeliveryState;\n attempt: number;\n availableAt: string;\n leaseToken?: string;\n leaseOwner?: string;\n leaseExpiresAt?: string;\n lastError?: string;\n}\n\nexport interface BridgeDeliveryEvent {\n sequence: string;\n deliveryId: string;\n messageId: string;\n workspace: string;\n recipient: string;\n fromState?: DeliveryState;\n toState: DeliveryState;\n attempt: number;\n leaseOwner?: string;\n error?: string;\n createdAt: string;\n}\n\nexport interface AgentPresence {\n workspace: string;\n agent: string;\n instance: string;\n runtimeType?: string;\n capabilities: string[];\n leaseExpiresAt: string;\n lastSeenAt: string;\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\nconst SEQUENCE_RE = /^(0|[1-9][0-9]*)$/;\nconst POSTGRES_BIGINT_MAX = 9_223_372_036_854_775_807n;\nconst TEXT_LIMIT = 64 * 1024;\nconst JSON_DEPTH_LIMIT = 16;\nconst RECORD_HASH_RE = /^sha256:[a-f0-9]{64}$/i;\n\nexport class BridgeValidationError extends Error {\n readonly code = \"invalid_input\";\n}\n\nfunction clean(value: unknown, field: string, max = 512): string {\n if (typeof value !== \"string\" || !value.trim()) {\n throw new BridgeValidationError(`${field} is required`);\n }\n\n const result = value.trim();\n if (result.length > max) {\n throw new BridgeValidationError(`${field} exceeds ${max} characters`);\n }\n return result;\n}\n\nfunction content(value: unknown): string {\n if (typeof value !== \"string\" || !value.trim()) {\n throw new BridgeValidationError(\"content is required\");\n }\n if (Buffer.byteLength(value) > TEXT_LIMIT) {\n throw new BridgeValidationError(`content exceeds ${TEXT_LIMIT} bytes`);\n }\n return value;\n}\n\nfunction optional(value: unknown, field: string, max = 512): string | undefined {\n if (value === undefined || value === null) return undefined;\n return clean(value, field, max);\n}\n\nfunction timestamp(value: unknown, field: string): string | undefined {\n const raw = optional(value, field);\n if (!raw) return undefined;\n\n const date = new Date(raw);\n if (Number.isNaN(date.getTime())) {\n throw new BridgeValidationError(`${field} must be an ISO timestamp`);\n }\n return date.toISOString();\n}\n\nfunction assertJsonDepth(value: JsonValue, depth = 0): void {\n if (depth > JSON_DEPTH_LIMIT) {\n throw new BridgeValidationError(`JSON exceeds ${JSON_DEPTH_LIMIT} levels`);\n }\n if (Array.isArray(value)) {\n for (const entry of value) assertJsonDepth(entry, depth + 1);\n } else if (value !== null && typeof value === \"object\") {\n for (const entry of Object.values(value)) assertJsonDepth(entry, depth + 1);\n }\n}\n\nfunction json(value: unknown, field: string): JsonValue | undefined {\n if (value === undefined) return undefined;\n\n try {\n const serialized = JSON.stringify(value);\n if (!serialized || Buffer.byteLength(serialized) > TEXT_LIMIT) throw new Error();\n const parsed = JSON.parse(serialized) as JsonValue;\n assertJsonDepth(parsed);\n return parsed;\n } catch (error) {\n if (error instanceof BridgeValidationError) throw error;\n throw new BridgeValidationError(`${field} must be JSON and at most ${TEXT_LIMIT} bytes`);\n }\n}\n\nfunction stringArray(value: unknown, field: string, limit: number, itemLimit: number): string[] {\n if (value === undefined) return [];\n if (!Array.isArray(value)) {\n throw new BridgeValidationError(`${field} must be an array`);\n }\n\n const result = [...new Set(value.map((entry) => clean(entry, field, itemLimit)))];\n if (result.length > limit) {\n throw new BridgeValidationError(`${field} exceeds ${limit} entries`);\n }\n return result;\n}\n\nexport function uuidv7(now = Date.now()): string {\n if (!Number.isSafeInteger(now) || now < 0 || now > 0xffffffffffff) {\n throw new BridgeValidationError(\"UUIDv7 timestamp is out of range\");\n }\n\n const bytes = randomBytes(16);\n let timestampValue = BigInt(now);\n for (let index = 5; index >= 0; index -= 1) {\n bytes[index] = Number(timestampValue & 0xffn);\n timestampValue >>= 8n;\n }\n bytes[6] = (bytes[6] & 0x0f) | 0x70;\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\n\n const hex = bytes.toString(\"hex\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\nexport function validatePrincipal(value: BridgePrincipal): BridgePrincipal {\n return {\n workspace: clean(value?.workspace, \"workspace\", 128),\n agent: clean(value?.agent, \"agent\", 128),\n instance: optional(value?.instance, \"instance\", 128),\n };\n}\n\nexport function validateUuid(value: unknown, field: string): string {\n const result = clean(value, field, 64);\n if (!UUID_RE.test(result)) {\n throw new BridgeValidationError(`${field} must be a UUID`);\n }\n return result;\n}\n\nexport function validateRetryPolicy(input: Partial<RetryPolicy> | null = {}): RetryPolicy {\n if (input === null || typeof input !== \"object\" || Array.isArray(input)) {\n throw new BridgeValidationError(\"retryPolicy must be an object\");\n }\n const result: RetryPolicy = {\n maxAttempts: input.maxAttempts ?? 5,\n baseDelayMs: input.baseDelayMs ?? 1_000,\n maxDelayMs: input.maxDelayMs ?? 60_000,\n jitterRatio: input.jitterRatio ?? 0.2,\n };\n\n if (!Number.isSafeInteger(result.maxAttempts) || result.maxAttempts < 1 || result.maxAttempts > 100) {\n throw new BridgeValidationError(\"maxAttempts must be between 1 and 100\");\n }\n if (!Number.isSafeInteger(result.baseDelayMs) || result.baseDelayMs < 1 || result.baseDelayMs > 3_600_000) {\n throw new BridgeValidationError(\"baseDelayMs must be between 1 and 3600000\");\n }\n if (!Number.isSafeInteger(result.maxDelayMs) || result.maxDelayMs < result.baseDelayMs || result.maxDelayMs > 86_400_000) {\n throw new BridgeValidationError(\"maxDelayMs must be at least baseDelayMs and at most 86400000\");\n }\n if (!Number.isFinite(result.jitterRatio) || result.jitterRatio < 0 || result.jitterRatio > 1) {\n throw new BridgeValidationError(\"jitterRatio must be between 0 and 1\");\n }\n return result;\n}\n\nexport function validateMessageDraft(\n input: MessageDraft,\n): Omit<BridgeMessage, \"workspace\" | \"source\" | \"sequence\" | \"createdAt\"> {\n const id = input.id ?? uuidv7();\n if (!UUID_RE.test(id)) throw new BridgeValidationError(\"id must be a UUID\");\n\n const priority = input.priority ?? \"info\";\n if (![\"info\", \"high\", \"urgent\"].includes(priority)) {\n throw new BridgeValidationError(\"priority is invalid\");\n }\n\n const atribReceiptId = optional(input.atribReceiptId, \"atribReceiptId\", 128);\n if (atribReceiptId && !normalizeReceiptId(atribReceiptId)) {\n throw new BridgeValidationError(\"atribReceiptId is invalid\");\n }\n const informedBy = stringArray(input.informedBy, \"informedBy\", 64, 128);\n if (informedBy.some((hash) => !RECORD_HASH_RE.test(hash))) {\n throw new BridgeValidationError(\"informedBy must contain atrib record hashes\");\n }\n\n return {\n id,\n type: clean(input.type, \"type\", 128),\n content: content(input.content),\n contentType: optional(input.contentType, \"contentType\", 128) ?? \"text/plain\",\n data: json(input.data, \"data\"),\n targets: stringArray(input.targets, \"targets\", 64, 128),\n threadId: optional(input.threadId, \"threadId\", 128),\n replyToId: optional(input.replyToId, \"replyToId\", 128),\n correlationId: optional(input.correlationId, \"correlationId\", 128),\n causationId: optional(input.causationId, \"causationId\", 128),\n priority,\n expiresAt: timestamp(input.expiresAt, \"expiresAt\"),\n idempotencyKey: optional(input.idempotencyKey, \"idempotencyKey\", 256),\n atribReceiptId,\n informedBy: informedBy.map((hash) => hash.toLowerCase()),\n metadata: json(input.metadata, \"metadata\"),\n };\n}\n\nexport function encodeCursor(sequence: string): string {\n if (!SEQUENCE_RE.test(sequence)) {\n throw new BridgeValidationError(\"sequence is invalid\");\n }\n return Buffer.from(JSON.stringify({ v: 1, sequence })).toString(\"base64url\");\n}\n\nexport function decodeCursor(cursor: string | undefined): string | undefined {\n if (!cursor) return undefined;\n\n if (typeof cursor !== \"string\" || cursor.length > 256) {\n throw new BridgeValidationError(\"cursor is invalid\");\n }\n\n try {\n const parsed = JSON.parse(Buffer.from(cursor, \"base64url\").toString(\"utf8\"));\n if (\n parsed?.v !== 1 ||\n typeof parsed.sequence !== \"string\" ||\n !SEQUENCE_RE.test(parsed.sequence) ||\n BigInt(parsed.sequence) > POSTGRES_BIGINT_MAX\n ) {\n throw new Error();\n }\n return parsed.sequence;\n } catch {\n throw new BridgeValidationError(\"cursor is invalid\");\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-CKSKUBDQ.js
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
BridgeValidationError,
|
|
4
|
-
validateMessageDraft,
|
|
5
|
-
validatePrincipal,
|
|
6
|
-
validateRetryPolicy,
|
|
7
|
-
validateUuid
|
|
8
|
-
} from "./chunk-BV6W4AJK.js";
|
|
9
|
-
|
|
10
|
-
// src/bridge-service.ts
|
|
11
|
-
function validateLeaseMs(value = 3e4) {
|
|
12
|
-
if (!Number.isSafeInteger(value) || value < 1e3 || value > 15 * 6e4) {
|
|
13
|
-
throw new BridgeValidationError("leaseMs must be between 1000 and 900000");
|
|
14
|
-
}
|
|
15
|
-
return value;
|
|
16
|
-
}
|
|
17
|
-
function validateQuery(query) {
|
|
18
|
-
const limit = query.limit ?? 50;
|
|
19
|
-
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 200) {
|
|
20
|
-
throw new BridgeValidationError("limit must be between 1 and 200");
|
|
21
|
-
}
|
|
22
|
-
if (query.types !== void 0) {
|
|
23
|
-
if (!Array.isArray(query.types) || query.types.length > 64) {
|
|
24
|
-
throw new BridgeValidationError("types must contain at most 64 entries");
|
|
25
|
-
}
|
|
26
|
-
for (const type of query.types) {
|
|
27
|
-
if (typeof type !== "string" || !type.trim() || type.length > 128) {
|
|
28
|
-
throw new BridgeValidationError("type filter is invalid");
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
const source = query.source?.trim();
|
|
33
|
-
if (source !== void 0 && (!source || source.length > 128)) {
|
|
34
|
-
throw new BridgeValidationError("source filter is invalid");
|
|
35
|
-
}
|
|
36
|
-
const unacknowledgedBy = query.unacknowledgedBy?.trim();
|
|
37
|
-
if (unacknowledgedBy !== void 0 && (!unacknowledgedBy || unacknowledgedBy.length > 128)) {
|
|
38
|
-
throw new BridgeValidationError("unacknowledgedBy filter is invalid");
|
|
39
|
-
}
|
|
40
|
-
let since;
|
|
41
|
-
if (query.since !== void 0) {
|
|
42
|
-
const date = new Date(query.since);
|
|
43
|
-
if (Number.isNaN(date.getTime())) throw new BridgeValidationError("since must be an ISO timestamp");
|
|
44
|
-
since = date.toISOString();
|
|
45
|
-
}
|
|
46
|
-
const threadId = query.threadId?.trim();
|
|
47
|
-
if (threadId !== void 0 && (!threadId || threadId.length > 128)) {
|
|
48
|
-
throw new BridgeValidationError("threadId filter is invalid");
|
|
49
|
-
}
|
|
50
|
-
if (query.latest && query.cursor) {
|
|
51
|
-
throw new BridgeValidationError("latest cannot be combined with cursor");
|
|
52
|
-
}
|
|
53
|
-
return { ...query, limit, source, since, unacknowledgedBy, threadId, latest: query.latest === true };
|
|
54
|
-
}
|
|
55
|
-
var BridgeService = class {
|
|
56
|
-
constructor(store) {
|
|
57
|
-
this.store = store;
|
|
58
|
-
}
|
|
59
|
-
async publish(principalInput, draftInput) {
|
|
60
|
-
const principal = validatePrincipal(principalInput);
|
|
61
|
-
const draft = validateMessageDraft(draftInput);
|
|
62
|
-
return this.store.insertMessage({
|
|
63
|
-
...draft,
|
|
64
|
-
workspace: principal.workspace,
|
|
65
|
-
source: principal.agent
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
async history(principalInput, query = {}) {
|
|
69
|
-
return this.store.listMessages(validatePrincipal(principalInput), validateQuery(query));
|
|
70
|
-
}
|
|
71
|
-
async acknowledge(principalInput, messageIds) {
|
|
72
|
-
const principal = validatePrincipal(principalInput);
|
|
73
|
-
if (!Array.isArray(messageIds) || !messageIds.length || messageIds.length > 200) {
|
|
74
|
-
throw new BridgeValidationError("messageIds must contain between 1 and 200 entries");
|
|
75
|
-
}
|
|
76
|
-
const ids = messageIds.map((id) => validateUuid(id, "messageId"));
|
|
77
|
-
return this.store.recordReceipt(principal.workspace, ids, principal.agent);
|
|
78
|
-
}
|
|
79
|
-
async claim(principalInput, options = {}) {
|
|
80
|
-
const principal = validatePrincipal(principalInput);
|
|
81
|
-
const delivery = await this.store.claimDelivery(principal, {
|
|
82
|
-
leaseMs: validateLeaseMs(options.leaseMs),
|
|
83
|
-
maxAttempts: validateRetryPolicy({ maxAttempts: options.maxAttempts }).maxAttempts
|
|
84
|
-
});
|
|
85
|
-
return delivery?.leaseToken ? { delivery, leaseToken: delivery.leaseToken } : null;
|
|
86
|
-
}
|
|
87
|
-
async extend(principalInput, deliveryId, leaseToken, leaseMs = 3e4) {
|
|
88
|
-
const principal = validatePrincipal(principalInput);
|
|
89
|
-
return this.store.renewDelivery(
|
|
90
|
-
principal,
|
|
91
|
-
validateUuid(deliveryId, "deliveryId"),
|
|
92
|
-
validateUuid(leaseToken, "leaseToken"),
|
|
93
|
-
validateLeaseMs(leaseMs)
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
async ack(principalInput, deliveryId, leaseToken) {
|
|
97
|
-
const principal = validatePrincipal(principalInput);
|
|
98
|
-
return this.store.settleDelivery(
|
|
99
|
-
principal,
|
|
100
|
-
validateUuid(deliveryId, "deliveryId"),
|
|
101
|
-
validateUuid(leaseToken, "leaseToken"),
|
|
102
|
-
"acked",
|
|
103
|
-
void 0,
|
|
104
|
-
validateRetryPolicy()
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
async nack(principalInput, deliveryId, leaseToken, error, dead = false, retryPolicy = {}) {
|
|
108
|
-
const principal = validatePrincipal(principalInput);
|
|
109
|
-
if (typeof dead !== "boolean") {
|
|
110
|
-
throw new BridgeValidationError("dead must be a boolean");
|
|
111
|
-
}
|
|
112
|
-
if (typeof error !== "string" || !error.trim()) {
|
|
113
|
-
throw new BridgeValidationError("error is required");
|
|
114
|
-
}
|
|
115
|
-
return this.store.settleDelivery(
|
|
116
|
-
principal,
|
|
117
|
-
validateUuid(deliveryId, "deliveryId"),
|
|
118
|
-
validateUuid(leaseToken, "leaseToken"),
|
|
119
|
-
dead ? "dead" : "retrying",
|
|
120
|
-
error.slice(0, 1024),
|
|
121
|
-
validateRetryPolicy(retryPolicy)
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
async heartbeat(principalInput, options = {}) {
|
|
125
|
-
const principal = validatePrincipal(principalInput);
|
|
126
|
-
if (!principal.instance) throw new BridgeValidationError("instance is required for presence");
|
|
127
|
-
if (!this.store.heartbeat) throw new BridgeValidationError("presence is not supported by this provider");
|
|
128
|
-
if (options.runtimeType !== void 0 && typeof options.runtimeType !== "string") {
|
|
129
|
-
throw new BridgeValidationError("runtimeType must be a string");
|
|
130
|
-
}
|
|
131
|
-
const runtimeType = options.runtimeType?.trim();
|
|
132
|
-
if (runtimeType && runtimeType.length > 128) throw new BridgeValidationError("runtimeType exceeds 128 characters");
|
|
133
|
-
if (options.capabilities !== void 0 && !Array.isArray(options.capabilities)) {
|
|
134
|
-
throw new BridgeValidationError("capabilities must be an array");
|
|
135
|
-
}
|
|
136
|
-
const capabilities = [...new Set(options.capabilities ?? [])].map((value) => {
|
|
137
|
-
if (typeof value !== "string" || !value.trim() || value.length > 128) throw new BridgeValidationError("capability is invalid");
|
|
138
|
-
return value.trim();
|
|
139
|
-
});
|
|
140
|
-
if (capabilities.length > 64) throw new BridgeValidationError("capabilities exceeds 64 entries");
|
|
141
|
-
return this.store.heartbeat(principal, validateLeaseMs(options.leaseMs), runtimeType, capabilities);
|
|
142
|
-
}
|
|
143
|
-
async presence(principalInput) {
|
|
144
|
-
const principal = validatePrincipal(principalInput);
|
|
145
|
-
if (!this.store.listPresence) throw new BridgeValidationError("presence is not supported by this provider");
|
|
146
|
-
return this.store.listPresence(principal);
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
export {
|
|
151
|
-
BridgeService
|
|
152
|
-
};
|
|
153
|
-
//# sourceMappingURL=chunk-CKSKUBDQ.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/bridge-service.ts"],"sourcesContent":["import {\n BridgeValidationError,\n encodeCursor,\n validateMessageDraft,\n validatePrincipal,\n validateRetryPolicy,\n validateUuid,\n type BridgeDelivery,\n type BridgeMessage,\n type BridgePrincipal,\n type MessageDraft,\n type RetryPolicy,\n type AgentPresence,\n} from \"./bridge-domain.js\";\nimport type {\n BridgeStore,\n InsertMessageResult,\n MessagePage,\n MessageQuery,\n} from \"./bridge-store.js\";\n\nfunction validateLeaseMs(value = 30_000): number {\n if (!Number.isSafeInteger(value) || value < 1_000 || value > 15 * 60_000) {\n throw new BridgeValidationError(\"leaseMs must be between 1000 and 900000\");\n }\n return value;\n}\n\nfunction validateQuery(query: MessageQuery): MessageQuery {\n const limit = query.limit ?? 50;\n if (!Number.isSafeInteger(limit) || limit < 1 || limit > 200) {\n throw new BridgeValidationError(\"limit must be between 1 and 200\");\n }\n if (query.types !== undefined) {\n if (!Array.isArray(query.types) || query.types.length > 64) {\n throw new BridgeValidationError(\"types must contain at most 64 entries\");\n }\n for (const type of query.types) {\n if (typeof type !== \"string\" || !type.trim() || type.length > 128) {\n throw new BridgeValidationError(\"type filter is invalid\");\n }\n }\n }\n const source = query.source?.trim();\n if (source !== undefined && (!source || source.length > 128)) {\n throw new BridgeValidationError(\"source filter is invalid\");\n }\n const unacknowledgedBy = query.unacknowledgedBy?.trim();\n if (\n unacknowledgedBy !== undefined &&\n (!unacknowledgedBy || unacknowledgedBy.length > 128)\n ) {\n throw new BridgeValidationError(\"unacknowledgedBy filter is invalid\");\n }\n let since: string | undefined;\n if (query.since !== undefined) {\n const date = new Date(query.since);\n if (Number.isNaN(date.getTime())) throw new BridgeValidationError(\"since must be an ISO timestamp\");\n since = date.toISOString();\n }\n const threadId = query.threadId?.trim();\n if (threadId !== undefined && (!threadId || threadId.length > 128)) {\n throw new BridgeValidationError(\"threadId filter is invalid\");\n }\n if (query.latest && query.cursor) {\n throw new BridgeValidationError(\"latest cannot be combined with cursor\");\n }\n return { ...query, limit, source, since, unacknowledgedBy, threadId, latest: query.latest === true };\n}\n\nexport class BridgeService {\n constructor(private readonly store: BridgeStore) {}\n\n async publish(\n principalInput: BridgePrincipal,\n draftInput: MessageDraft,\n ): Promise<InsertMessageResult> {\n const principal = validatePrincipal(principalInput);\n const draft = validateMessageDraft(draftInput);\n return this.store.insertMessage({\n ...draft,\n workspace: principal.workspace,\n source: principal.agent,\n });\n }\n\n async history(\n principalInput: BridgePrincipal,\n query: MessageQuery = {},\n ): Promise<MessagePage> {\n return this.store.listMessages(validatePrincipal(principalInput), validateQuery(query));\n }\n\n async acknowledge(principalInput: BridgePrincipal, messageIds: string[]): Promise<number> {\n const principal = validatePrincipal(principalInput);\n if (!Array.isArray(messageIds) || !messageIds.length || messageIds.length > 200) {\n throw new BridgeValidationError(\"messageIds must contain between 1 and 200 entries\");\n }\n const ids = messageIds.map((id) => validateUuid(id, \"messageId\"));\n return this.store.recordReceipt(principal.workspace, ids, principal.agent);\n }\n\n async claim(\n principalInput: BridgePrincipal,\n options: { leaseMs?: number; maxAttempts?: number } = {},\n ): Promise<{ delivery: BridgeDelivery; leaseToken: string } | null> {\n const principal = validatePrincipal(principalInput);\n const delivery = await this.store.claimDelivery(principal, {\n leaseMs: validateLeaseMs(options.leaseMs),\n maxAttempts: validateRetryPolicy({ maxAttempts: options.maxAttempts }).maxAttempts,\n });\n return delivery?.leaseToken ? { delivery, leaseToken: delivery.leaseToken } : null;\n }\n\n async extend(\n principalInput: BridgePrincipal,\n deliveryId: string,\n leaseToken: string,\n leaseMs = 30_000,\n ): Promise<BridgeDelivery | null> {\n const principal = validatePrincipal(principalInput);\n return this.store.renewDelivery(\n principal,\n validateUuid(deliveryId, \"deliveryId\"),\n validateUuid(leaseToken, \"leaseToken\"),\n validateLeaseMs(leaseMs),\n );\n }\n\n async ack(\n principalInput: BridgePrincipal,\n deliveryId: string,\n leaseToken: string,\n ): Promise<BridgeDelivery | null> {\n const principal = validatePrincipal(principalInput);\n return this.store.settleDelivery(\n principal,\n validateUuid(deliveryId, \"deliveryId\"),\n validateUuid(leaseToken, \"leaseToken\"),\n \"acked\",\n undefined,\n validateRetryPolicy(),\n );\n }\n\n async nack(\n principalInput: BridgePrincipal,\n deliveryId: string,\n leaseToken: string,\n error: string,\n dead = false,\n retryPolicy: Partial<RetryPolicy> = {},\n ): Promise<BridgeDelivery | null> {\n const principal = validatePrincipal(principalInput);\n if (typeof dead !== \"boolean\") {\n throw new BridgeValidationError(\"dead must be a boolean\");\n }\n if (typeof error !== \"string\" || !error.trim()) {\n throw new BridgeValidationError(\"error is required\");\n }\n return this.store.settleDelivery(\n principal,\n validateUuid(deliveryId, \"deliveryId\"),\n validateUuid(leaseToken, \"leaseToken\"),\n dead ? \"dead\" : \"retrying\",\n error.slice(0, 1_024),\n validateRetryPolicy(retryPolicy),\n );\n }\n\n async heartbeat(\n principalInput: BridgePrincipal,\n options: { leaseMs?: number; runtimeType?: string; capabilities?: string[] } = {},\n ): Promise<AgentPresence> {\n const principal = validatePrincipal(principalInput);\n if (!principal.instance) throw new BridgeValidationError(\"instance is required for presence\");\n if (!this.store.heartbeat) throw new BridgeValidationError(\"presence is not supported by this provider\");\n if (\n options.runtimeType !== undefined &&\n typeof options.runtimeType !== \"string\"\n ) {\n throw new BridgeValidationError(\"runtimeType must be a string\");\n }\n const runtimeType = options.runtimeType?.trim();\n if (runtimeType && runtimeType.length > 128) throw new BridgeValidationError(\"runtimeType exceeds 128 characters\");\n if (options.capabilities !== undefined && !Array.isArray(options.capabilities)) {\n throw new BridgeValidationError(\"capabilities must be an array\");\n }\n const capabilities = [...new Set(options.capabilities ?? [])].map((value) => {\n if (typeof value !== \"string\" || !value.trim() || value.length > 128) throw new BridgeValidationError(\"capability is invalid\");\n return value.trim();\n });\n if (capabilities.length > 64) throw new BridgeValidationError(\"capabilities exceeds 64 entries\");\n return this.store.heartbeat(principal, validateLeaseMs(options.leaseMs), runtimeType, capabilities);\n }\n\n async presence(principalInput: BridgePrincipal): Promise<AgentPresence[]> {\n const principal = validatePrincipal(principalInput);\n if (!this.store.listPresence) throw new BridgeValidationError(\"presence is not supported by this provider\");\n return this.store.listPresence(principal);\n }\n}\n\nexport { encodeCursor, type BridgeMessage };\n"],"mappings":"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","names":[]}
|