@creatornader/agent-bridge 0.5.2 → 0.6.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.
Files changed (78) hide show
  1. package/CHANGELOG.md +57 -1
  2. package/README.md +59 -34
  3. package/ROADMAP.md +74 -17
  4. package/SECURITY.md +6 -5
  5. package/SKILL.md +4 -1
  6. package/dist/archive.d.ts +2 -2
  7. package/dist/{bridge-service-CNBKdYXh.d.ts → bridge-service-DjSYfjKt.d.ts} +4 -2
  8. package/dist/{bridge-store-ByJ6CaJk.d.ts → bridge-store-Bi_LCX8e.d.ts} +5 -1
  9. package/dist/bridge.d.ts +9 -37
  10. package/dist/bridge.js +6 -10
  11. package/dist/chunk-23UDQZMT.js +54 -0
  12. package/dist/chunk-23UDQZMT.js.map +1 -0
  13. package/dist/{chunk-AWE3DFZV.js → chunk-4V2PFJEF.js} +11 -4
  14. package/dist/chunk-4V2PFJEF.js.map +1 -0
  15. package/dist/{chunk-E4OWHGUE.js → chunk-63JKCBC6.js} +10 -8
  16. package/dist/chunk-63JKCBC6.js.map +1 -0
  17. package/dist/chunk-6ZOLE3E3.js +242 -0
  18. package/dist/chunk-6ZOLE3E3.js.map +1 -0
  19. package/dist/chunk-7B3XRRNI.js +27 -0
  20. package/dist/chunk-7B3XRRNI.js.map +1 -0
  21. package/dist/{chunk-7VJI2MXI.js → chunk-IF5OKPBK.js} +32 -14
  22. package/dist/chunk-IF5OKPBK.js.map +1 -0
  23. package/dist/{chunk-QPC6JHA3.js → chunk-IXNQG4SB.js} +12 -16
  24. package/dist/chunk-IXNQG4SB.js.map +1 -0
  25. package/dist/{chunk-HUHG7XTB.js → chunk-JIRNR75D.js} +30 -193
  26. package/dist/chunk-JIRNR75D.js.map +1 -0
  27. package/dist/{chunk-JUTJRAMA.js → chunk-LF37B6KL.js} +6 -4
  28. package/dist/chunk-LF37B6KL.js.map +1 -0
  29. package/dist/{chunk-2EVLG3YA.js → chunk-UKFRCP6X.js} +10 -7
  30. package/dist/chunk-UKFRCP6X.js.map +1 -0
  31. package/dist/{chunk-SN7PIVDF.js → chunk-ZUZ7TCIH.js} +13 -1
  32. package/dist/{chunk-SN7PIVDF.js.map → chunk-ZUZ7TCIH.js.map} +1 -1
  33. package/dist/cli.js +45 -40
  34. package/dist/cli.js.map +1 -1
  35. package/dist/client-config.d.ts +1 -1
  36. package/dist/client-config.js +1 -1
  37. package/dist/client-runtime.d.ts +3 -3
  38. package/dist/client-runtime.js +5 -5
  39. package/dist/contracts/generate.js +3 -3
  40. package/dist/contracts/generate.js.map +1 -1
  41. package/dist/dr.d.ts +8 -0
  42. package/dist/dr.js +1 -1
  43. package/dist/{gateway-CW-61lvs.d.ts → gateway-DWZ3pX48.d.ts} +7 -2
  44. package/dist/gateway-main.js +12 -3
  45. package/dist/gateway-main.js.map +1 -1
  46. package/dist/gateway.d.ts +3 -3
  47. package/dist/gateway.js +3 -3
  48. package/dist/index.js +8 -7
  49. package/dist/index.js.map +1 -1
  50. package/dist/{postgres-bridge-store-C9KG9Z69.d.ts → postgres-bridge-store-ChoOuFEY.d.ts} +1 -1
  51. package/dist/server.d.ts +0 -2
  52. package/dist/server.js +8 -7
  53. package/dist/{sqlite-edge-store-CdMIOrho.d.ts → sqlite-edge-store-BAFUeysk.d.ts} +1 -1
  54. package/dist/sqlite.d.ts +7 -3
  55. package/dist/sqlite.js +1 -1
  56. package/docs/architecture-v2.md +26 -14
  57. package/docs/decisions/0001-protocol-layers-and-acknowledgment-semantics.md +2 -1
  58. package/docs/decisions/0002-canonical-operation-contract-registry.md +11 -1
  59. package/docs/decisions/0005-retire-direct-supabase-runtime.md +52 -0
  60. package/docs/deployment.md +41 -17
  61. package/docs/ecosystem.md +6 -4
  62. package/docs/troubleshooting.md +15 -0
  63. package/llms.txt +4 -4
  64. package/openapi/agent-bridge-v2.openapi.json +11 -6
  65. package/package.json +5 -3
  66. package/schemas/agent-bridge-v2.capabilities.json +11 -5
  67. package/schemas/agent-bridge-v2.mcp.json +13 -12
  68. package/schemas/agent-bridge-v2.schema.json +26 -24
  69. package/scripts/gateway-release-check.mjs +92 -0
  70. package/dist/chunk-2EVLG3YA.js.map +0 -1
  71. package/dist/chunk-7VJI2MXI.js.map +0 -1
  72. package/dist/chunk-AWE3DFZV.js.map +0 -1
  73. package/dist/chunk-E4OWHGUE.js.map +0 -1
  74. package/dist/chunk-HUHG7XTB.js.map +0 -1
  75. package/dist/chunk-JUTJRAMA.js.map +0 -1
  76. package/dist/chunk-QPC6JHA3.js.map +0 -1
  77. package/dist/chunk-Z6JP6MYD.js +0 -584
  78. package/dist/chunk-Z6JP6MYD.js.map +0 -1
@@ -0,0 +1,242 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ContractResponseError,
4
+ PROTOCOL_HEADER,
5
+ PROTOCOL_VERSION,
6
+ SUPPORTED_PROTOCOL_HEADER,
7
+ SUPPORTED_PROTOCOL_VERSIONS,
8
+ parseResponse
9
+ } from "./chunk-63JKCBC6.js";
10
+
11
+ // src/http-bridge-store.ts
12
+ var BridgeHttpError = class extends Error {
13
+ constructor(status, code, requestId, details, message = `Agent Bridge request failed: ${code}`) {
14
+ super(message);
15
+ this.status = status;
16
+ this.code = code;
17
+ this.requestId = requestId;
18
+ this.details = details;
19
+ }
20
+ };
21
+ var HttpBridgeStore = class {
22
+ constructor(options) {
23
+ this.options = options;
24
+ this.closeController = new AbortController();
25
+ this.closed = false;
26
+ const url = new URL(options.baseUrl);
27
+ const loopback = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]";
28
+ if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback) && !options.allowInsecureRemoteHttp) {
29
+ throw new Error("Agent Bridge requires HTTPS for non-loopback gateways");
30
+ }
31
+ this.fetchImpl = options.fetch ?? fetch;
32
+ }
33
+ async initialize(options = {}) {
34
+ if (options.mode === "passive") return;
35
+ await this.request(void 0, "/readyz", { authenticated: false, signal: options.signal });
36
+ const status = await this.request("status", "/v2/status", { signal: options.signal });
37
+ this.assertBoundPrincipal(status);
38
+ }
39
+ assertBoundPrincipal(status) {
40
+ const principal = status?.principal;
41
+ if (!principal || principal.workspace !== this.options.principal.workspace || principal.agent !== this.options.principal.agent) {
42
+ throw new BridgeHttpError(403, "principal_mismatch");
43
+ }
44
+ }
45
+ async request(operationId, path, options = {}) {
46
+ if (options.method === "POST" && !options.skipProtocolProbe) await this.ensureProtocol(options.signal);
47
+ if (this.closed) throw new BridgeHttpError(0, "store_closed");
48
+ if (options.signal?.aborted) throw new BridgeHttpError(0, "request_cancelled");
49
+ const requestController = new AbortController();
50
+ const abort = () => requestController.abort(this.closeController.signal.reason);
51
+ const abortRequest = () => requestController.abort(options.signal?.reason);
52
+ this.closeController.signal.addEventListener("abort", abort, { once: true });
53
+ options.signal?.addEventListener("abort", abortRequest, { once: true });
54
+ let timedOut = false;
55
+ const timeout = setTimeout(() => {
56
+ timedOut = true;
57
+ requestController.abort(new Error("request timeout"));
58
+ }, this.options.timeoutMs ?? 1e4);
59
+ timeout.unref?.();
60
+ try {
61
+ const response = await this.fetchImpl(`${this.options.baseUrl.replace(/\/$/, "")}${path}`, {
62
+ method: options.method ?? "GET",
63
+ signal: requestController.signal,
64
+ headers: {
65
+ [PROTOCOL_HEADER]: this.selectedProtocolVersion ?? PROTOCOL_VERSION,
66
+ ...options.authenticated === false ? {} : { authorization: `Bearer ${this.options.token}` },
67
+ ...this.options.principal.instance ? { "x-agent-bridge-instance": this.options.principal.instance } : {},
68
+ ...options.body === void 0 ? {} : { "content-type": "application/json" }
69
+ },
70
+ body: options.body === void 0 ? void 0 : JSON.stringify(options.body)
71
+ });
72
+ const requestId = response.headers.get("x-request-id") ?? void 0;
73
+ const selectedHeader = response.headers.get(PROTOCOL_HEADER);
74
+ const supportedHeader = response.headers.get(SUPPORTED_PROTOCOL_HEADER);
75
+ const supportedProtocols = supportedHeader?.split(",").map((value) => value.trim()).filter(Boolean) ?? [];
76
+ const inconsistentProtocol = selectedHeader === null || supportedHeader === null || !SUPPORTED_PROTOCOL_VERSIONS.includes(selectedHeader) || !supportedProtocols.includes(selectedHeader) || selectedHeader !== PROTOCOL_VERSION;
77
+ if (operationId && inconsistentProtocol) {
78
+ throw new BridgeHttpError(502, "protocol_mismatch", requestId, {
79
+ expected: PROTOCOL_VERSION,
80
+ selected: selectedHeader,
81
+ supported: supportedHeader
82
+ });
83
+ }
84
+ const contentType = response.headers.get("content-type") ?? "";
85
+ const payload = contentType.startsWith("application/json") ? await response.json().catch(() => ({})) : await response.text();
86
+ if (!response.ok) {
87
+ const envelope = payload && typeof payload === "object" ? payload.error : void 0;
88
+ throw new BridgeHttpError(
89
+ response.status,
90
+ envelope?.code ?? "request_failed",
91
+ envelope?.requestId ?? requestId,
92
+ envelope?.details ?? envelope,
93
+ envelope?.message ?? `Agent Bridge request failed: ${envelope?.code ?? "request_failed"}`
94
+ );
95
+ }
96
+ if (operationId) this.selectedProtocolVersion = PROTOCOL_VERSION;
97
+ if (!operationId) return payload;
98
+ return parseResponse(operationId, payload);
99
+ } catch (error) {
100
+ if (error instanceof BridgeHttpError) throw error;
101
+ if (error instanceof ContractResponseError) {
102
+ throw new BridgeHttpError(error.status, error.code, void 0, {
103
+ operation: error.operation,
104
+ issues: error.issues
105
+ }, error.message);
106
+ }
107
+ if (this.closed) throw new BridgeHttpError(0, "store_closed");
108
+ if (options.signal?.aborted) throw new BridgeHttpError(0, "request_cancelled");
109
+ if (timedOut) throw new BridgeHttpError(504, "request_timeout");
110
+ if (error instanceof Error && (error.name === "TimeoutError" || error.name === "AbortError")) {
111
+ throw new BridgeHttpError(504, "request_timeout");
112
+ }
113
+ throw new BridgeHttpError(0, "network_error");
114
+ } finally {
115
+ clearTimeout(timeout);
116
+ this.closeController.signal.removeEventListener("abort", abort);
117
+ options.signal?.removeEventListener("abort", abortRequest);
118
+ }
119
+ }
120
+ ensureProtocol(signal) {
121
+ if (this.selectedProtocolVersion) return Promise.resolve(this.selectedProtocolVersion);
122
+ if (!this.protocolProbe) {
123
+ this.protocolProbe = this.request("status", "/v2/status", { signal, skipProtocolProbe: true }).then(() => this.selectedProtocolVersion).finally(() => {
124
+ this.protocolProbe = void 0;
125
+ });
126
+ }
127
+ return this.protocolProbe;
128
+ }
129
+ async capabilities() {
130
+ return this.request("capabilities", "/v2/capabilities");
131
+ }
132
+ assertPrincipal(principal, includeInstance = true) {
133
+ const expected = this.options.principal;
134
+ if (principal.workspace !== expected.workspace || principal.agent !== expected.agent || includeInstance && principal.instance !== expected.instance) {
135
+ throw new BridgeHttpError(403, "principal_mismatch");
136
+ }
137
+ }
138
+ async insertMessage(message, options = {}) {
139
+ this.assertPrincipal({ workspace: message.workspace, agent: message.source }, false);
140
+ await this.ensureProtocol(options.signal);
141
+ const { workspace: _workspace, source: _source, ...draft } = message;
142
+ return this.request("publish_message", "/v2/messages", { method: "POST", body: draft, signal: options.signal });
143
+ }
144
+ async listMessages(principal, query = {}, options = {}) {
145
+ this.assertPrincipal(principal);
146
+ const requestQuery = query;
147
+ const params = new URLSearchParams();
148
+ if (requestQuery.cursor) params.set("cursor", requestQuery.cursor);
149
+ if (requestQuery.mailbox) params.set("mailbox", requestQuery.mailbox);
150
+ if (requestQuery.receiptState) params.set("receiptState", requestQuery.receiptState);
151
+ if (requestQuery.limit) params.set("limit", String(requestQuery.limit));
152
+ if (requestQuery.includeExpired) params.set("includeExpired", "true");
153
+ if (requestQuery.source) params.set("source", requestQuery.source);
154
+ if (requestQuery.project) params.set("project", requestQuery.project);
155
+ if (requestQuery.since) params.set("since", requestQuery.since);
156
+ if (requestQuery.threadId) params.set("threadId", requestQuery.threadId);
157
+ if (requestQuery.latest) params.set("latest", "true");
158
+ for (const type of requestQuery.types ?? []) params.append("type", type);
159
+ return this.request("history", `/v2/history${params.size ? `?${params}` : ""}`, { signal: options.signal });
160
+ }
161
+ async recordReceipt(principal, ids) {
162
+ this.assertPrincipal(principal, false);
163
+ return (await this.request("record_receipt", "/v2/receipts", { method: "POST", body: { messageIds: ids } })).recorded;
164
+ }
165
+ async diagnostics(principal) {
166
+ this.assertPrincipal(principal);
167
+ const status = await this.request("status", "/v2/status");
168
+ this.assertBoundPrincipal(status);
169
+ return status;
170
+ }
171
+ async claimDelivery(principal, options) {
172
+ this.assertPrincipal(principal);
173
+ return (await this.request("claim_delivery", "/v2/deliveries/claim", { method: "POST", body: options }))?.delivery ?? null;
174
+ }
175
+ async listDeliveries(principal, query = {}) {
176
+ this.assertPrincipal(principal);
177
+ const params = new URLSearchParams();
178
+ if (query.cursor) params.set("cursor", query.cursor);
179
+ if (query.limit) params.set("limit", String(query.limit));
180
+ if (query.role) params.set("role", query.role);
181
+ if (query.messageId) params.set("messageId", query.messageId);
182
+ if (query.recipient) params.set("recipient", query.recipient);
183
+ for (const state of query.states ?? []) params.append("state", state);
184
+ return this.request("list_deliveries", `/v2/deliveries${params.size ? `?${params}` : ""}`);
185
+ }
186
+ async listDeliveryEvents(principal, id, query = {}) {
187
+ this.assertPrincipal(principal);
188
+ const params = new URLSearchParams();
189
+ if (query.cursor) params.set("cursor", query.cursor);
190
+ if (query.limit) params.set("limit", String(query.limit));
191
+ return this.request("list_delivery_events", `/v2/deliveries/${id}/events${params.size ? `?${params}` : ""}`);
192
+ }
193
+ async cancelDelivery(principal, id) {
194
+ this.assertPrincipal(principal);
195
+ return (await this.request("cancel_delivery", `/v2/deliveries/${id}/cancel`, { method: "POST", body: {} })).delivery;
196
+ }
197
+ async requeueDelivery(principal, id) {
198
+ this.assertPrincipal(principal);
199
+ return (await this.request("requeue_delivery", `/v2/deliveries/${id}/requeue`, { method: "POST", body: {} })).delivery;
200
+ }
201
+ async renewDelivery(principal, id, token, leaseMs) {
202
+ this.assertPrincipal(principal);
203
+ try {
204
+ return (await this.request("extend_delivery", `/v2/deliveries/${id}/extend`, { method: "POST", body: { leaseToken: token, leaseMs } })).delivery;
205
+ } catch (error) {
206
+ if (error instanceof BridgeHttpError && error.status === 409) return null;
207
+ throw error;
208
+ }
209
+ }
210
+ async settleDelivery(principal, id, token, state, error, _retryPolicy) {
211
+ this.assertPrincipal(principal);
212
+ await this.ensureProtocol();
213
+ const action = state === "acked" ? "ack" : "nack";
214
+ try {
215
+ const operationId = action === "ack" ? "acknowledge_delivery" : "negative_acknowledge_delivery";
216
+ const nackBody = { leaseToken: token, error, disposition: state === "dead" ? "dead" : "retry" };
217
+ return (await this.request(operationId, `/v2/deliveries/${id}/${action}`, { method: "POST", body: action === "ack" ? { leaseToken: token } : nackBody })).delivery;
218
+ } catch (caught) {
219
+ if (caught instanceof BridgeHttpError && caught.status === 409) return null;
220
+ throw caught;
221
+ }
222
+ }
223
+ async heartbeat(principal, leaseMs, runtimeType, capabilities = []) {
224
+ this.assertPrincipal(principal);
225
+ return this.request("heartbeat", "/v2/presence/heartbeat", { method: "POST", body: { leaseMs, runtimeType, capabilities } });
226
+ }
227
+ async listPresence(principal) {
228
+ this.assertPrincipal(principal);
229
+ return (await this.request("presence", "/v2/presence")).agents;
230
+ }
231
+ async close() {
232
+ if (this.closed) return;
233
+ this.closed = true;
234
+ this.closeController.abort(new Error("store closed"));
235
+ }
236
+ };
237
+
238
+ export {
239
+ BridgeHttpError,
240
+ HttpBridgeStore
241
+ };
242
+ //# sourceMappingURL=chunk-6ZOLE3E3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/http-bridge-store.ts"],"sourcesContent":["import type { AgentPresence, BridgeDelivery, BridgeMessage, BridgePrincipal } from \"./bridge-domain.js\";\nimport type { BridgeDiagnostics, BridgeStore, ClaimOptions, InsertMessageResult, MessagePage, MessageQuery } from \"./bridge-store.js\";\nimport {\n ContractResponseError,\n parseResponse,\n PROTOCOL_HEADER,\n PROTOCOL_VERSION,\n SUPPORTED_PROTOCOL_HEADER,\n SUPPORTED_PROTOCOL_VERSIONS,\n type OperationId,\n} from \"./contracts/registry.js\";\n\nexport interface HttpBridgeStoreOptions {\n baseUrl: string;\n token: string;\n principal: BridgePrincipal;\n timeoutMs?: number;\n allowInsecureRemoteHttp?: boolean;\n fetch?: typeof fetch;\n}\n\nexport class BridgeHttpError extends Error {\n constructor(\n readonly status: number,\n readonly code: string,\n readonly requestId?: string,\n readonly details?: unknown,\n message = `Agent Bridge request failed: ${code}`,\n ) {\n super(message);\n }\n}\n\nexport class HttpBridgeStore implements BridgeStore {\n private readonly fetchImpl: typeof fetch;\n private readonly closeController = new AbortController();\n private closed = false;\n private selectedProtocolVersion?: string;\n private protocolProbe?: Promise<string>;\n constructor(private readonly options: HttpBridgeStoreOptions) {\n const url = new URL(options.baseUrl);\n const loopback = url.hostname === \"localhost\" || url.hostname === \"127.0.0.1\" || url.hostname === \"[::1]\";\n if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && loopback) && !options.allowInsecureRemoteHttp) {\n throw new Error(\"Agent Bridge requires HTTPS for non-loopback gateways\");\n }\n this.fetchImpl = options.fetch ?? fetch;\n }\n async initialize(options: { signal?: AbortSignal; mode?: \"active\" | \"passive\" } = {}): Promise<void> {\n if (options.mode === \"passive\") return;\n await this.request(undefined, \"/readyz\", { authenticated: false, signal: options.signal });\n const status = await this.request(\"status\", \"/v2/status\", { signal: options.signal });\n this.assertBoundPrincipal(status);\n }\n\n private assertBoundPrincipal(status: any): void {\n const principal = status?.principal;\n if (\n !principal ||\n principal.workspace !== this.options.principal.workspace ||\n principal.agent !== this.options.principal.agent\n ) {\n throw new BridgeHttpError(403, \"principal_mismatch\");\n }\n }\n\n private async request(operationId: OperationId | undefined, path: string, options: { method?: string; body?: unknown; authenticated?: boolean; signal?: AbortSignal; skipProtocolProbe?: boolean } = {}): Promise<any> {\n if (options.method === \"POST\" && !options.skipProtocolProbe) await this.ensureProtocol(options.signal);\n if (this.closed) throw new BridgeHttpError(0, \"store_closed\");\n if (options.signal?.aborted) throw new BridgeHttpError(0, \"request_cancelled\");\n const requestController = new AbortController();\n const abort = () => requestController.abort(this.closeController.signal.reason);\n const abortRequest = () => requestController.abort(options.signal?.reason);\n this.closeController.signal.addEventListener(\"abort\", abort, { once: true });\n options.signal?.addEventListener(\"abort\", abortRequest, { once: true });\n let timedOut = false;\n const timeout = setTimeout(() => {\n timedOut = true;\n requestController.abort(new Error(\"request timeout\"));\n }, this.options.timeoutMs ?? 10_000);\n timeout.unref?.();\n try {\n const response = await this.fetchImpl(`${this.options.baseUrl.replace(/\\/$/, \"\")}${path}`, {\n method: options.method ?? \"GET\", signal: requestController.signal,\n headers: {\n [PROTOCOL_HEADER]: this.selectedProtocolVersion ?? PROTOCOL_VERSION,\n ...(options.authenticated === false ? {} : { authorization: `Bearer ${this.options.token}` }),\n ...(this.options.principal.instance ? { \"x-agent-bridge-instance\": this.options.principal.instance } : {}),\n ...(options.body === undefined ? {} : { \"content-type\": \"application/json\" }),\n },\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n });\n const requestId = response.headers.get(\"x-request-id\") ?? undefined;\n const selectedHeader = response.headers.get(PROTOCOL_HEADER);\n const supportedHeader = response.headers.get(SUPPORTED_PROTOCOL_HEADER);\n const supportedProtocols = supportedHeader?.split(\",\").map((value) => value.trim()).filter(Boolean) ?? [];\n const inconsistentProtocol = (\n selectedHeader === null || supportedHeader === null ||\n !(SUPPORTED_PROTOCOL_VERSIONS as readonly string[]).includes(selectedHeader) ||\n !supportedProtocols.includes(selectedHeader) ||\n selectedHeader !== PROTOCOL_VERSION\n );\n if (operationId && inconsistentProtocol) {\n throw new BridgeHttpError(502, \"protocol_mismatch\", requestId, {\n expected: PROTOCOL_VERSION,\n selected: selectedHeader,\n supported: supportedHeader,\n });\n }\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const payload = contentType.startsWith(\"application/json\")\n ? await response.json().catch(() => ({}))\n : await response.text();\n if (!response.ok) {\n const envelope = payload && typeof payload === \"object\" ? (payload as any).error : undefined;\n throw new BridgeHttpError(\n response.status,\n envelope?.code ?? \"request_failed\",\n envelope?.requestId ?? requestId,\n envelope?.details ?? envelope,\n envelope?.message ?? `Agent Bridge request failed: ${envelope?.code ?? \"request_failed\"}`,\n );\n }\n if (operationId) this.selectedProtocolVersion = PROTOCOL_VERSION;\n if (!operationId) return payload;\n return parseResponse(operationId, payload);\n } catch (error) {\n if (error instanceof BridgeHttpError) throw error;\n if (error instanceof ContractResponseError) {\n throw new BridgeHttpError(error.status, error.code, undefined, {\n operation: error.operation,\n issues: error.issues,\n }, error.message);\n }\n if (this.closed) throw new BridgeHttpError(0, \"store_closed\");\n if (options.signal?.aborted) throw new BridgeHttpError(0, \"request_cancelled\");\n if (timedOut) throw new BridgeHttpError(504, \"request_timeout\");\n if (error instanceof Error && (error.name === \"TimeoutError\" || error.name === \"AbortError\")) {\n throw new BridgeHttpError(504, \"request_timeout\");\n }\n throw new BridgeHttpError(0, \"network_error\");\n } finally {\n clearTimeout(timeout);\n this.closeController.signal.removeEventListener(\"abort\", abort);\n options.signal?.removeEventListener(\"abort\", abortRequest);\n }\n }\n\n private ensureProtocol(signal?: AbortSignal): Promise<string> {\n if (this.selectedProtocolVersion) return Promise.resolve(this.selectedProtocolVersion);\n if (!this.protocolProbe) {\n this.protocolProbe = this.request(\"status\", \"/v2/status\", { signal, skipProtocolProbe: true })\n .then(() => this.selectedProtocolVersion!)\n .finally(() => { this.protocolProbe = undefined; });\n }\n return this.protocolProbe;\n }\n async capabilities(): Promise<unknown> { return this.request(\"capabilities\", \"/v2/capabilities\"); }\n\n private assertPrincipal(principal: BridgePrincipal, includeInstance = true): void {\n const expected = this.options.principal;\n if (\n principal.workspace !== expected.workspace ||\n principal.agent !== expected.agent ||\n (includeInstance && principal.instance !== expected.instance)\n ) {\n throw new BridgeHttpError(403, \"principal_mismatch\");\n }\n }\n\n async insertMessage(message: Omit<BridgeMessage, \"sequence\" | \"createdAt\">, options: { signal?: AbortSignal } = {}): Promise<InsertMessageResult> {\n this.assertPrincipal({ workspace: message.workspace, agent: message.source }, false);\n await this.ensureProtocol(options.signal);\n const { workspace: _workspace, source: _source, ...draft } = message;\n return this.request(\"publish_message\", \"/v2/messages\", { method: \"POST\", body: draft, signal: options.signal });\n }\n async listMessages(principal: BridgePrincipal, query: MessageQuery = {}, options: { signal?: AbortSignal } = {}): Promise<MessagePage> {\n this.assertPrincipal(principal);\n const requestQuery = query;\n const params = new URLSearchParams();\n if (requestQuery.cursor) params.set(\"cursor\", requestQuery.cursor);\n if (requestQuery.mailbox) params.set(\"mailbox\", requestQuery.mailbox);\n if (requestQuery.receiptState) params.set(\"receiptState\", requestQuery.receiptState);\n if (requestQuery.limit) params.set(\"limit\", String(requestQuery.limit));\n if (requestQuery.includeExpired) params.set(\"includeExpired\", \"true\");\n if (requestQuery.source) params.set(\"source\", requestQuery.source);\n if (requestQuery.project) params.set(\"project\", requestQuery.project);\n if (requestQuery.since) params.set(\"since\", requestQuery.since);\n if (requestQuery.threadId) params.set(\"threadId\", requestQuery.threadId);\n if (requestQuery.latest) params.set(\"latest\", \"true\");\n for (const type of requestQuery.types ?? []) params.append(\"type\", type);\n return this.request(\"history\", `/v2/history${params.size ? `?${params}` : \"\"}`, { signal: options.signal });\n }\n async recordReceipt(principal: BridgePrincipal, ids: string[]): Promise<number> {\n this.assertPrincipal(principal, false);\n return (await this.request(\"record_receipt\", \"/v2/receipts\", { method: \"POST\", body: { messageIds: ids } })).recorded;\n }\n async diagnostics(principal: BridgePrincipal): Promise<BridgeDiagnostics> {\n this.assertPrincipal(principal);\n const status = await this.request(\"status\", \"/v2/status\");\n this.assertBoundPrincipal(status);\n return status;\n }\n async claimDelivery(principal: BridgePrincipal, options: ClaimOptions): Promise<BridgeDelivery | null> {\n this.assertPrincipal(principal);\n return (await this.request(\"claim_delivery\", \"/v2/deliveries/claim\", { method: \"POST\", body: options }))?.delivery ?? null;\n }\n async listDeliveries(principal: BridgePrincipal, query: import(\"./bridge-store.js\").DeliveryQuery = {}) {\n this.assertPrincipal(principal); const params=new URLSearchParams(); if(query.cursor)params.set(\"cursor\",query.cursor);if(query.limit)params.set(\"limit\",String(query.limit));if(query.role)params.set(\"role\",query.role);if(query.messageId)params.set(\"messageId\",query.messageId);if(query.recipient)params.set(\"recipient\",query.recipient);for(const state of query.states??[])params.append(\"state\",state);return this.request(\"list_deliveries\",`/v2/deliveries${params.size?`?${params}`:\"\"}`);\n }\n async listDeliveryEvents(principal: BridgePrincipal,id:string,query:{cursor?:string;limit?:number}={}) { this.assertPrincipal(principal);const params=new URLSearchParams();if(query.cursor)params.set(\"cursor\",query.cursor);if(query.limit)params.set(\"limit\",String(query.limit));return this.request(\"list_delivery_events\",`/v2/deliveries/${id}/events${params.size?`?${params}`:\"\"}`); }\n async cancelDelivery(principal:BridgePrincipal,id:string){this.assertPrincipal(principal);return (await this.request(\"cancel_delivery\",`/v2/deliveries/${id}/cancel`,{method:\"POST\",body:{}})).delivery;}\n async requeueDelivery(principal:BridgePrincipal,id:string){this.assertPrincipal(principal);return (await this.request(\"requeue_delivery\",`/v2/deliveries/${id}/requeue`,{method:\"POST\",body:{}})).delivery;}\n async renewDelivery(principal: BridgePrincipal, id: string, token: string, leaseMs: number): Promise<BridgeDelivery | null> {\n this.assertPrincipal(principal);\n try {\n return (await this.request(\"extend_delivery\", `/v2/deliveries/${id}/extend`, { method: \"POST\", body: { leaseToken: token, leaseMs } })).delivery;\n } catch (error) {\n if (error instanceof BridgeHttpError && error.status === 409) return null;\n throw error;\n }\n }\n async settleDelivery(principal: BridgePrincipal, id: string, token: string, state: \"acked\" | \"retrying\" | \"dead\", error?: string, _retryPolicy?: import(\"./bridge-domain.js\").RetryPolicy): Promise<BridgeDelivery | null> {\n this.assertPrincipal(principal);\n await this.ensureProtocol();\n const action = state === \"acked\" ? \"ack\" : \"nack\";\n try {\n const operationId = action === \"ack\" ? \"acknowledge_delivery\" : \"negative_acknowledge_delivery\";\n const nackBody = { leaseToken: token, error, disposition: state === \"dead\" ? \"dead\" : \"retry\" };\n return (await this.request(operationId, `/v2/deliveries/${id}/${action}`, { method: \"POST\", body: action === \"ack\" ? { leaseToken: token } : nackBody })).delivery;\n } catch (caught) {\n if (caught instanceof BridgeHttpError && caught.status === 409) return null;\n throw caught;\n }\n }\n async heartbeat(principal: BridgePrincipal, leaseMs: number, runtimeType?: string, capabilities: string[] = []): Promise<AgentPresence> {\n this.assertPrincipal(principal);\n return this.request(\"heartbeat\", \"/v2/presence/heartbeat\", { method: \"POST\", body: { leaseMs, runtimeType, capabilities } });\n }\n async listPresence(principal: BridgePrincipal): Promise<AgentPresence[]> {\n this.assertPrincipal(principal);\n return (await this.request(\"presence\", \"/v2/presence\")).agents;\n }\n async close(): Promise<void> {\n if (this.closed) return;\n this.closed = true;\n this.closeController.abort(new Error(\"store closed\"));\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/package-metadata.ts
4
+ import { readFileSync } from "fs";
5
+ import { fileURLToPath } from "url";
6
+ function packageVersion() {
7
+ const manifest = JSON.parse(
8
+ readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf8")
9
+ );
10
+ if (typeof manifest.version !== "string" || !manifest.version) {
11
+ throw new Error("package version is unavailable");
12
+ }
13
+ return manifest.version;
14
+ }
15
+ function buildRevision(value) {
16
+ if (value === void 0 || value === "") return void 0;
17
+ if (!/^[0-9a-f]{7,40}$/u.test(value)) {
18
+ throw new Error("AGENT_BRIDGE_BUILD_REVISION must be a lowercase Git commit hash");
19
+ }
20
+ return value;
21
+ }
22
+
23
+ export {
24
+ packageVersion,
25
+ buildRevision
26
+ };
27
+ //# sourceMappingURL=chunk-7B3XRRNI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/package-metadata.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\nexport function packageVersion(): string {\n const manifest = JSON.parse(\n readFileSync(fileURLToPath(new URL(\"../package.json\", import.meta.url)), \"utf8\"),\n ) as { version?: unknown };\n if (typeof manifest.version !== \"string\" || !manifest.version) {\n throw new Error(\"package version is unavailable\");\n }\n return manifest.version;\n}\n\nexport function buildRevision(value: string | undefined): string | undefined {\n if (value === undefined || value === \"\") return undefined;\n if (!/^[0-9a-f]{7,40}$/u.test(value)) {\n throw new Error(\"AGENT_BRIDGE_BUILD_REVISION must be a lowercase Git commit hash\");\n }\n return value;\n}\n"],"mappings":";;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAEvB,SAAS,iBAAyB;AACvC,QAAM,WAAW,KAAK;AAAA,IACpB,aAAa,cAAc,IAAI,IAAI,mBAAmB,YAAY,GAAG,CAAC,GAAG,MAAM;AAAA,EACjF;AACA,MAAI,OAAO,SAAS,YAAY,YAAY,CAAC,SAAS,SAAS;AAC7D,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AACA,SAAO,SAAS;AAClB;AAEO,SAAS,cAAc,OAA+C;AAC3E,MAAI,UAAU,UAAa,UAAU,GAAI,QAAO;AAChD,MAAI,CAAC,oBAAoB,KAAK,KAAK,GAAG;AACpC,UAAM,IAAI,MAAM,iEAAiE;AAAA,EACnF;AACA,SAAO;AACT;","names":[]}
@@ -1301,21 +1301,24 @@ async function collectPostgresRoleInventory(client, databaseName) {
1301
1301
  CROSS JOIN LATERAL pg_catalog.aclexplode(type.typacl) acl WHERE namespace.nspname='agent_bridge' AND acl.grantee<>0
1302
1302
  UNION SELECT defaults.defaclrole, 'object-role' FROM pg_catalog.pg_default_acl defaults
1303
1303
  LEFT JOIN pg_catalog.pg_namespace namespace ON namespace.oid=defaults.defaclnamespace
1304
- WHERE namespace.nspname='agent_bridge' OR defaults.defaclrole=(
1305
- SELECT nspowner FROM pg_catalog.pg_namespace WHERE nspname='agent_bridge')
1304
+ WHERE namespace.nspname='agent_bridge' OR (
1305
+ defaults.defaclnamespace=0 AND defaults.defaclrole=(
1306
+ SELECT nspowner FROM pg_catalog.pg_namespace WHERE nspname='agent_bridge'))
1306
1307
  OR (defaults.defaclnamespace=0 AND defaults.defaclrole=(SELECT oid FROM pg_catalog.pg_roles
1307
1308
  WHERE rolname='agent_bridge_control_owner_'||substr(pg_catalog.md5(pg_catalog.current_database()),1,16)))
1308
1309
  UNION SELECT acl.grantor, 'object-role' FROM pg_catalog.pg_default_acl defaults
1309
1310
  LEFT JOIN pg_catalog.pg_namespace namespace ON namespace.oid=defaults.defaclnamespace
1310
1311
  CROSS JOIN LATERAL pg_catalog.aclexplode(defaults.defaclacl) acl WHERE namespace.nspname='agent_bridge'
1311
- OR defaults.defaclrole=(SELECT nspowner FROM pg_catalog.pg_namespace WHERE nspname='agent_bridge')
1312
+ OR (defaults.defaclnamespace=0 AND defaults.defaclrole=(
1313
+ SELECT nspowner FROM pg_catalog.pg_namespace WHERE nspname='agent_bridge'))
1312
1314
  OR (defaults.defaclnamespace=0 AND defaults.defaclrole=(SELECT oid FROM pg_catalog.pg_roles
1313
1315
  WHERE rolname='agent_bridge_control_owner_'||substr(pg_catalog.md5(pg_catalog.current_database()),1,16)))
1314
1316
  UNION SELECT acl.grantee, 'object-role' FROM pg_catalog.pg_default_acl defaults
1315
1317
  LEFT JOIN pg_catalog.pg_namespace namespace ON namespace.oid=defaults.defaclnamespace
1316
1318
  CROSS JOIN LATERAL pg_catalog.aclexplode(defaults.defaclacl) acl WHERE acl.grantee<>0 AND (
1317
- namespace.nspname='agent_bridge' OR defaults.defaclrole=(
1318
- SELECT nspowner FROM pg_catalog.pg_namespace WHERE nspname='agent_bridge')
1319
+ namespace.nspname='agent_bridge' OR (
1320
+ defaults.defaclnamespace=0 AND defaults.defaclrole=(
1321
+ SELECT nspowner FROM pg_catalog.pg_namespace WHERE nspname='agent_bridge'))
1319
1322
  OR (defaults.defaclnamespace=0 AND defaults.defaclrole=(SELECT oid FROM pg_catalog.pg_roles
1320
1323
  WHERE rolname='agent_bridge_control_owner_'||substr(pg_catalog.md5(pg_catalog.current_database()),1,16))))
1321
1324
  ), base_roles AS (
@@ -1325,12 +1328,19 @@ async function collectPostgresRoleInventory(client, databaseName) {
1325
1328
  UNION
1326
1329
  SELECT role.oid, 'derived' FROM pg_catalog.pg_roles role
1327
1330
  WHERE role.rolname IN (SELECT name FROM derived_names)
1331
+ ), canonical_base_roles AS (
1332
+ SELECT oid, CASE WHEN bool_or(kind='schema-owner') THEN 'schema-owner'
1333
+ WHEN bool_or(kind='derived') THEN 'derived'
1334
+ ELSE 'object-role' END AS kind
1335
+ FROM base_roles GROUP BY oid
1328
1336
  ), related_roles AS (
1329
- SELECT oid, kind FROM base_roles
1337
+ SELECT oid, kind FROM canonical_base_roles
1330
1338
  UNION SELECT membership.roleid, 'external-principal' FROM pg_catalog.pg_auth_members membership
1331
- WHERE membership.member IN (SELECT oid FROM base_roles)
1339
+ WHERE membership.member IN (
1340
+ SELECT oid FROM canonical_base_roles WHERE kind<>'schema-owner')
1332
1341
  UNION SELECT membership.member, 'external-principal' FROM pg_catalog.pg_auth_members membership
1333
- WHERE membership.roleid IN (SELECT oid FROM base_roles)
1342
+ WHERE membership.roleid IN (
1343
+ SELECT oid FROM canonical_base_roles WHERE kind<>'schema-owner')
1334
1344
  )
1335
1345
  SELECT role.rolname AS name,
1336
1346
  CASE WHEN bool_or(related.kind='schema-owner') THEN 'schema-owner'
@@ -1340,6 +1350,7 @@ async function collectPostgresRoleInventory(client, databaseName) {
1340
1350
  FROM related_roles related JOIN pg_catalog.pg_roles role ON role.oid=related.oid
1341
1351
  GROUP BY role.rolname ORDER BY role.rolname`);
1342
1352
  const names = roleRows.rows.map((row) => row.name);
1353
+ const schemaOwnerNames = roleRows.rows.filter((row) => row.kind === "schema-owner").map((row) => row.name);
1343
1354
  const membershipRows = names.length === 0 ? { rows: [], rowCount: 0 } : await client.query(`
1344
1355
  SELECT granted.rolname AS role, member.rolname AS member,
1345
1356
  bool_or(membership.admin_option) AS "adminOption",
@@ -1353,15 +1364,21 @@ async function collectPostgresRoleInventory(client, databaseName) {
1353
1364
  ORDER BY granted.rolname,member.rolname`, [names]);
1354
1365
  if (names.length > 0) {
1355
1366
  const boundary = await client.query(`
1356
- SELECT 1 AS found FROM pg_catalog.pg_auth_members membership
1367
+ SELECT granted.rolname AS role, member.rolname AS member
1368
+ FROM pg_catalog.pg_auth_members membership
1357
1369
  JOIN pg_catalog.pg_roles granted ON granted.oid=membership.roleid
1358
1370
  JOIN pg_catalog.pg_roles member ON member.oid=membership.member
1359
1371
  WHERE (granted.rolname=ANY($1::text[])) <> (member.rolname=ANY($1::text[]))
1360
- LIMIT 1`, [names]);
1372
+ AND NOT (
1373
+ granted.rolname=ANY($1::text[]) AND granted.rolname=ANY($2::text[])
1374
+ OR member.rolname=ANY($1::text[]) AND member.rolname=ANY($2::text[])
1375
+ )
1376
+ ORDER BY granted.rolname,member.rolname LIMIT 10`, [names, schemaOwnerNames]);
1361
1377
  if (boundary.rows.length > 0) {
1362
1378
  throw new PostgresNativeDrError(
1363
1379
  "TRANSITIVE_ROLE_MEMBERSHIP_UNSUPPORTED",
1364
- "PostgreSQL role inventory has a transitive external membership outside the bounded restore graph"
1380
+ "PostgreSQL role inventory has a transitive external membership outside the bounded restore graph",
1381
+ { roleMemberships: boundary.rows }
1365
1382
  );
1366
1383
  }
1367
1384
  }
@@ -1380,8 +1397,9 @@ async function collectPostgresRoleInventory(client, databaseName) {
1380
1397
  LEFT JOIN LATERAL pg_catalog.aclexplode(defaults.defaclacl) acl ON true
1381
1398
  LEFT JOIN pg_catalog.pg_roles grantor ON grantor.oid=acl.grantor
1382
1399
  LEFT JOIN pg_catalog.pg_roles grantee ON grantee.oid=acl.grantee
1383
- WHERE namespace.nspname='agent_bridge' OR defaults.defaclrole=(
1384
- SELECT nspowner FROM pg_catalog.pg_namespace WHERE nspname='agent_bridge')
1400
+ WHERE namespace.nspname='agent_bridge' OR (
1401
+ defaults.defaclnamespace=0 AND defaults.defaclrole=(
1402
+ SELECT nspowner FROM pg_catalog.pg_namespace WHERE nspname='agent_bridge'))
1385
1403
  OR (defaults.defaclnamespace=0 AND defaults.defaclrole=(SELECT oid FROM pg_catalog.pg_roles
1386
1404
  WHERE rolname='agent_bridge_control_owner_'||substr(pg_catalog.md5(pg_catalog.current_database()),1,16)))
1387
1405
  ORDER BY owner.rolname,namespace.nspname NULLS FIRST,defaults.defaclobjtype,
@@ -2668,4 +2686,4 @@ export {
2668
2686
  restoreLocalSqlite,
2669
2687
  SQLITE_EDGE_APPLICATION_ID
2670
2688
  };
2671
- //# sourceMappingURL=chunk-7VJI2MXI.js.map
2689
+ //# sourceMappingURL=chunk-IF5OKPBK.js.map