@adcp/sdk 15.0.0 → 15.2.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.
Files changed (142) hide show
  1. package/bin/adcp-grade.js +46 -2
  2. package/bin/adcp.js +7 -2
  3. package/dist/lib/canonical-references/index.d.mts +19 -1
  4. package/dist/lib/canonical-references/index.d.ts +19 -1
  5. package/dist/lib/canonical-references/index.js +81 -9
  6. package/dist/lib/canonical-references/index.mjs +80 -9
  7. package/dist/lib/client/core.d.mts +1 -0
  8. package/dist/lib/client/core.d.ts +1 -0
  9. package/dist/lib/core/AgentClient.d.mts +9 -1
  10. package/dist/lib/core/AgentClient.d.ts +9 -1
  11. package/dist/lib/core/AgentClient.js +10 -0
  12. package/dist/lib/core/AgentClient.mjs +10 -0
  13. package/dist/lib/core/SingleAgentClient.d.mts +13 -2
  14. package/dist/lib/core/SingleAgentClient.d.ts +13 -2
  15. package/dist/lib/core/SingleAgentClient.js +23 -5
  16. package/dist/lib/core/SingleAgentClient.mjs +23 -5
  17. package/dist/lib/index.d.mts +1 -1
  18. package/dist/lib/index.d.ts +1 -1
  19. package/dist/lib/reporting/gcs/adapter.d.mts +31 -0
  20. package/dist/lib/reporting/gcs/adapter.d.ts +31 -0
  21. package/dist/lib/reporting/gcs/adapter.js +342 -0
  22. package/dist/lib/reporting/gcs/adapter.mjs +325 -0
  23. package/dist/lib/reporting/gcs/bucket-policy.d.mts +3 -0
  24. package/dist/lib/reporting/gcs/bucket-policy.d.ts +3 -0
  25. package/dist/lib/reporting/gcs/bucket-policy.js +31 -0
  26. package/dist/lib/reporting/gcs/bucket-policy.mjs +7 -0
  27. package/dist/lib/reporting/gcs/errors.d.mts +5 -0
  28. package/dist/lib/reporting/gcs/errors.d.ts +5 -0
  29. package/dist/lib/reporting/gcs/errors.js +41 -0
  30. package/dist/lib/reporting/gcs/errors.mjs +16 -0
  31. package/dist/lib/reporting/gcs/fence.d.mts +36 -0
  32. package/dist/lib/reporting/gcs/fence.d.ts +36 -0
  33. package/dist/lib/reporting/gcs/fence.js +250 -0
  34. package/dist/lib/reporting/gcs/fence.mjs +230 -0
  35. package/dist/lib/reporting/gcs/index.d.mts +7 -0
  36. package/dist/lib/reporting/gcs/index.d.ts +7 -0
  37. package/dist/lib/reporting/gcs/index.js +41 -0
  38. package/dist/lib/reporting/gcs/index.mjs +12 -0
  39. package/dist/lib/reporting/gcs/io.d.mts +7 -0
  40. package/dist/lib/reporting/gcs/io.d.ts +7 -0
  41. package/dist/lib/reporting/gcs/io.js +95 -0
  42. package/dist/lib/reporting/gcs/io.mjs +69 -0
  43. package/dist/lib/reporting/gcs/reader.d.mts +43 -0
  44. package/dist/lib/reporting/gcs/reader.d.ts +43 -0
  45. package/dist/lib/reporting/gcs/reader.js +193 -0
  46. package/dist/lib/reporting/gcs/reader.mjs +169 -0
  47. package/dist/lib/reporting/gcs/validation.d.mts +5 -0
  48. package/dist/lib/reporting/gcs/validation.d.ts +5 -0
  49. package/dist/lib/reporting/gcs/validation.js +49 -0
  50. package/dist/lib/reporting/gcs/validation.mjs +25 -0
  51. package/dist/lib/reporting/ledger/handler.d.mts +1 -0
  52. package/dist/lib/reporting/ledger/handler.d.ts +1 -0
  53. package/dist/lib/reporting/ledger/index.d.mts +1 -0
  54. package/dist/lib/reporting/ledger/index.d.ts +1 -0
  55. package/dist/lib/reporting/ledger/index.js +2 -0
  56. package/dist/lib/reporting/ledger/index.mjs +1 -0
  57. package/dist/lib/reporting/ledger/managed-postgres.d.mts +16 -1
  58. package/dist/lib/reporting/ledger/managed-postgres.d.ts +16 -1
  59. package/dist/lib/reporting/ledger/managed-postgres.js +243 -2
  60. package/dist/lib/reporting/ledger/managed-postgres.mjs +248 -2
  61. package/dist/lib/reporting/ledger/object-writes.d.mts +69 -0
  62. package/dist/lib/reporting/ledger/object-writes.d.ts +69 -0
  63. package/dist/lib/reporting/ledger/object-writes.js +147 -0
  64. package/dist/lib/reporting/ledger/object-writes.mjs +114 -0
  65. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  66. package/dist/lib/server/a2a-adapter.d.mts +50 -1
  67. package/dist/lib/server/a2a-adapter.d.ts +50 -1
  68. package/dist/lib/server/a2a-adapter.js +230 -7
  69. package/dist/lib/server/a2a-adapter.mjs +237 -7
  70. package/dist/lib/server/auth-signature.d.mts +84 -46
  71. package/dist/lib/server/auth-signature.d.ts +84 -46
  72. package/dist/lib/server/auth-signature.js +48 -14
  73. package/dist/lib/server/auth-signature.mjs +58 -15
  74. package/dist/lib/server/create-adcp-server.js +5 -16
  75. package/dist/lib/server/create-adcp-server.mjs +5 -16
  76. package/dist/lib/server/index.d.mts +1 -1
  77. package/dist/lib/server/index.d.ts +1 -1
  78. package/dist/lib/server/index.js +2 -0
  79. package/dist/lib/server/index.mjs +3 -1
  80. package/dist/lib/signing/agent-fetch.js +3 -33
  81. package/dist/lib/signing/agent-fetch.mjs +3 -33
  82. package/dist/lib/signing/middleware.d.mts +9 -1
  83. package/dist/lib/signing/middleware.d.ts +9 -1
  84. package/dist/lib/signing/operation-resolution.d.mts +37 -0
  85. package/dist/lib/signing/operation-resolution.d.ts +37 -0
  86. package/dist/lib/signing/operation-resolution.js +154 -0
  87. package/dist/lib/signing/operation-resolution.mjs +125 -0
  88. package/dist/lib/signing/postgres-replay-store.d.mts +1 -1
  89. package/dist/lib/signing/postgres-replay-store.d.ts +1 -1
  90. package/dist/lib/signing/redis-replay-store.d.mts +1 -1
  91. package/dist/lib/signing/redis-replay-store.d.ts +1 -1
  92. package/dist/lib/signing/server.d.mts +1 -0
  93. package/dist/lib/signing/server.d.ts +1 -0
  94. package/dist/lib/signing/server.js +7 -0
  95. package/dist/lib/signing/server.mjs +8 -0
  96. package/dist/lib/signing/verifier.d.mts +36 -1
  97. package/dist/lib/signing/verifier.d.ts +36 -1
  98. package/dist/lib/signing/verifier.js +66 -34
  99. package/dist/lib/signing/verifier.mjs +61 -34
  100. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.d.mts +12 -0
  101. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.d.ts +12 -0
  102. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.js +29 -2
  103. package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.mjs +27 -1
  104. package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.d.mts +61 -0
  105. package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.d.ts +61 -0
  106. package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.js +298 -0
  107. package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.mjs +276 -0
  108. package/dist/lib/testing/storyboard/request-signing/grader.d.mts +31 -1
  109. package/dist/lib/testing/storyboard/request-signing/grader.d.ts +31 -1
  110. package/dist/lib/testing/storyboard/request-signing/grader.js +11 -0
  111. package/dist/lib/testing/storyboard/request-signing/grader.mjs +11 -0
  112. package/dist/lib/testing/storyboard/request-signing/index.d.mts +5 -4
  113. package/dist/lib/testing/storyboard/request-signing/index.d.ts +5 -4
  114. package/dist/lib/testing/storyboard/request-signing/index.js +13 -0
  115. package/dist/lib/testing/storyboard/request-signing/index.mjs +18 -2
  116. package/dist/lib/testing/storyboard/request-signing/types.d.mts +43 -0
  117. package/dist/lib/testing/storyboard/request-signing/types.d.ts +43 -0
  118. package/dist/lib/testing/storyboard/request-signing/types.js +3 -0
  119. package/dist/lib/testing/storyboard/request-signing/types.mjs +2 -0
  120. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.mts +42 -1
  121. package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts +42 -1
  122. package/dist/lib/testing/storyboard/request-signing/vector-loader.js +100 -1
  123. package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +104 -3
  124. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  125. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  126. package/dist/lib/version.d.mts +3 -3
  127. package/dist/lib/version.d.ts +3 -3
  128. package/dist/lib/version.js +3 -3
  129. package/dist/lib/version.mjs +3 -3
  130. package/docs/TYPE-SUMMARY.md +2 -2
  131. package/docs/guides/BUILD-AN-AGENT.md +9 -4
  132. package/docs/guides/CREATIVE-DELIVERY.md +34 -0
  133. package/docs/guides/REPORTING-GCS-FENCE.md +52 -0
  134. package/docs/guides/REPORTING-GCS-MANAGED.md +56 -0
  135. package/docs/guides/REPORTING-OPERATIONS.md +4 -0
  136. package/docs/guides/SIGNING-GUIDE.md +20 -6
  137. package/docs/guides/VALIDATE-YOUR-AGENT.md +4 -0
  138. package/docs/llms.txt +2 -2
  139. package/docs/migration-14.x-rc-worksheet.md +5 -4
  140. package/docs/migration-buyer-agent-registry.md +1 -1
  141. package/package.json +19 -1
  142. package/skills/build-seller-agent/specialisms/signed-requests.md +2 -0
@@ -0,0 +1,250 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var fence_exports = {};
20
+ __export(fence_exports, {
21
+ ReportingGcsFenceError: () => import_errors2.ReportingGcsFenceError,
22
+ createGcsReportingObjectFenceV1: () => createGcsReportingObjectFenceV1
23
+ });
24
+ module.exports = __toCommonJS(fence_exports);
25
+ var import_node_crypto = require("node:crypto");
26
+ var import_object_writes = require('../ledger/object-writes.js');
27
+ var import_errors = require('./errors.js');
28
+ var import_io = require('./io.js');
29
+ var import_bucket_policy = require('./bucket-policy.js');
30
+ var import_errors2 = require('./errors.js');
31
+ const hash = (bytes) => (0, import_node_crypto.createHash)("sha256").update(bytes).digest("hex");
32
+ const TOMBSTONE = "adcp_reporting_tombstone";
33
+ function createGcsReportingObjectFenceV1(options) {
34
+ if (!options || typeof options.bucket !== "string" || !/^[a-z0-9][a-z0-9.-]{1,220}[a-z0-9]$/.test(options.bucket) || typeof options.namespace !== "string" || options.namespace.length < 1 || options.namespace.length > 255 || !options.storage || typeof options.storage.bucket !== "function" || !options.store)
35
+ throw new import_errors.ReportingGcsFenceError("INVALID_INPUT");
36
+ const { storage, store, bucket: bucketName, namespace } = options;
37
+ const deadline = options.operationDeadlineMilliseconds ?? 6e4;
38
+ if (!Number.isSafeInteger(deadline) || deadline < 1 || deadline > 6e4)
39
+ throw new import_errors.ReportingGcsFenceError("INVALID_INPUT");
40
+ const provider = { bucket: bucketName, namespace_key: hash(namespace) };
41
+ const status = (error, code) => !!error && typeof error === "object" && "code" in error && Number(error.code) === code;
42
+ const bounded = (work, signal) => (0, import_io.withGcsDeadline)(work, { signal, milliseconds: deadline });
43
+ async function probe(bucket, signal) {
44
+ (0, import_io.activeGcsSignal)(signal);
45
+ try {
46
+ const [metadata] = await bucket.getMetadata();
47
+ (0, import_io.activeGcsSignal)(signal);
48
+ try {
49
+ (0, import_bucket_policy.assertGcsReportingBucketPolicy)(metadata);
50
+ } catch {
51
+ throw new import_errors.ReportingGcsFenceError("UNSAFE_BUCKET");
52
+ }
53
+ } catch (error) {
54
+ (0, import_io.activeGcsSignal)(signal);
55
+ if ((0, import_errors.isReportingGcsFenceError)(error)) throw error;
56
+ throw new import_errors.ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
57
+ }
58
+ }
59
+ function assertScope(scope) {
60
+ try {
61
+ (0, import_object_writes.assertReportingObjectWriteScope)(scope);
62
+ } catch {
63
+ throw new import_errors.ReportingGcsFenceError("INVALID_INPUT");
64
+ }
65
+ }
66
+ function assertPlan(plan) {
67
+ try {
68
+ (0, import_object_writes.reportingObjectWritePlanFingerprint)(plan);
69
+ } catch {
70
+ throw new import_errors.ReportingGcsFenceError("INVALID_INPUT");
71
+ }
72
+ if (plan.provider.bucket !== bucketName || plan.provider.namespace_key !== provider.namespace_key)
73
+ throw new import_errors.ReportingGcsFenceError("INVALID_INPUT");
74
+ }
75
+ async function register(scope, deliveryId, bodies, signal) {
76
+ assertScope(scope);
77
+ if (typeof deliveryId !== "string" || deliveryId.length < 1 || deliveryId.length > 255 || !Array.isArray(bodies) || bodies.length < 1 || bodies.length > 128 || bodies.some((b) => !(b instanceof Uint8Array) || b.byteLength > 64 * 1024 * 1024) || bodies.reduce((total, b) => total + b.byteLength, 0) > 64 * 1024 * 1024)
78
+ throw new import_errors.ReportingGcsFenceError("INVALID_INPUT");
79
+ const scopeCopy = {
80
+ account_id: scope.account_id,
81
+ destination_ref: scope.destination_ref,
82
+ generation: scope.generation
83
+ };
84
+ const planId = hash(deliveryId);
85
+ const plan = {
86
+ ...scopeCopy,
87
+ provider: { ...provider },
88
+ plan_id: planId,
89
+ objects: bodies.map((b, i) => ({
90
+ bucket: bucketName,
91
+ object_name: (0, import_object_writes.reportingObjectWriteName)(scopeCopy, provider, planId, i),
92
+ sha256: hash(b),
93
+ size_bytes: b.byteLength
94
+ }))
95
+ };
96
+ await probe(storage.bucket(bucketName), signal);
97
+ (0, import_io.activeGcsSignal)(signal);
98
+ const registered = await store.registerObjectWritePlan(plan, { signal });
99
+ (0, import_io.activeGcsSignal)(signal);
100
+ if (registered === "revoked") throw new import_errors.ReportingGcsFenceError("REVOKED");
101
+ return plan;
102
+ }
103
+ async function write(input, index, inputBytes, signal) {
104
+ const plan = structuredClone(input);
105
+ assertPlan(plan);
106
+ const expected = plan.objects[index];
107
+ if (!Number.isInteger(index) || !expected || !(inputBytes instanceof Uint8Array))
108
+ throw new import_errors.ReportingGcsFenceError("INVALID_INPUT");
109
+ if (inputBytes.byteLength !== expected.size_bytes) throw new import_errors.ReportingGcsFenceError("CONTENT_CONFLICT");
110
+ const bytes = Buffer.from(inputBytes);
111
+ if (hash(bytes) !== expected.sha256) throw new import_errors.ReportingGcsFenceError("CONTENT_CONFLICT");
112
+ (0, import_io.activeGcsSignal)(signal);
113
+ const bucket = storage.bucket(bucketName);
114
+ await probe(bucket, signal);
115
+ (0, import_io.activeGcsSignal)(signal);
116
+ const registered = await store.registerObjectWritePlan(plan, { signal });
117
+ (0, import_io.activeGcsSignal)(signal);
118
+ if (registered === "revoked") throw new import_errors.ReportingGcsFenceError("REVOKED");
119
+ const file = bucket.file(expected.object_name);
120
+ try {
121
+ await file.save(bytes, {
122
+ resumable: false,
123
+ preconditionOpts: { ifGenerationMatch: 0 },
124
+ metadata: { cacheControl: "no-store" }
125
+ });
126
+ (0, import_io.activeGcsSignal)(signal);
127
+ } catch (error) {
128
+ (0, import_io.activeGcsSignal)(signal);
129
+ if (!status(error, 412)) throw new import_errors.ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
130
+ try {
131
+ const [metadata] = await file.getMetadata();
132
+ (0, import_io.activeGcsSignal)(signal);
133
+ if (metadata.metadata?.[TOMBSTONE] !== void 0) throw new import_errors.ReportingGcsFenceError("REVOKED");
134
+ const existing = await (0, import_io.readGcsBytes)(
135
+ bucket.file(expected.object_name, { generation: metadata.generation }),
136
+ bytes.length,
137
+ signal
138
+ );
139
+ if (existing.length !== bytes.length || hash(existing) !== expected.sha256)
140
+ throw new import_errors.ReportingGcsFenceError("CONTENT_CONFLICT");
141
+ } catch (error2) {
142
+ (0, import_io.activeGcsSignal)(signal);
143
+ if (status(error2, 404)) {
144
+ const current = await store.registerObjectWritePlan(plan, { signal });
145
+ (0, import_io.activeGcsSignal)(signal);
146
+ if (current === "revoked") throw new import_errors.ReportingGcsFenceError("REVOKED");
147
+ }
148
+ if ((0, import_errors.isReportingGcsFenceError)(error2)) throw error2;
149
+ throw new import_errors.ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
150
+ }
151
+ }
152
+ (0, import_io.activeGcsSignal)(signal);
153
+ if (await store.registerObjectWritePlan(plan, { signal }) === "revoked")
154
+ throw new import_errors.ReportingGcsFenceError("REVOKED");
155
+ (0, import_io.activeGcsSignal)(signal);
156
+ }
157
+ async function revoke(scopeInput, maxObjects, signal) {
158
+ assertScope(scopeInput);
159
+ const scope = {
160
+ account_id: scopeInput.account_id,
161
+ destination_ref: scopeInput.destination_ref,
162
+ generation: scopeInput.generation
163
+ };
164
+ const limit = maxObjects ?? 10;
165
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e3) throw new import_errors.ReportingGcsFenceError("INVALID_INPUT");
166
+ (0, import_io.activeGcsSignal)(signal);
167
+ const binding = await store.getObjectWriteBinding(scope, { signal });
168
+ (0, import_io.activeGcsSignal)(signal);
169
+ const objects = await store.listRevokedObjectWrites(scope, { limit }, { signal });
170
+ (0, import_io.activeGcsSignal)(signal);
171
+ if (!binding) {
172
+ if (objects.length) throw new import_errors.ReportingGcsFenceError("STATE_UNAVAILABLE");
173
+ return { fenced: 0, complete: true };
174
+ }
175
+ const bucket = storage.bucket(binding.bucket);
176
+ await probe(bucket, signal);
177
+ const scopeKey = (0, import_object_writes.reportingObjectWriteScopeKey)(scope);
178
+ for (const object of objects) {
179
+ (0, import_io.activeGcsSignal)(signal);
180
+ if (object.bucket !== binding.bucket || object.object_name !== (0, import_object_writes.reportingObjectWriteName)(scope, binding, object.plan_id, object.object_index))
181
+ throw new import_errors.ReportingGcsFenceError("STATE_UNAVAILABLE");
182
+ const file = bucket.file(object.object_name);
183
+ let fencedGeneration;
184
+ for (let attempt = 0; attempt < 4 && !fencedGeneration; attempt++) {
185
+ (0, import_io.activeGcsSignal)(signal);
186
+ let generation = 0;
187
+ try {
188
+ const [metadata] = await file.getMetadata();
189
+ (0, import_io.activeGcsSignal)(signal);
190
+ generation = String(metadata.generation);
191
+ if (metadata.metadata?.[TOMBSTONE] === scopeKey && String(metadata.size) === "0") {
192
+ fencedGeneration = String(metadata.generation);
193
+ break;
194
+ }
195
+ } catch (error) {
196
+ (0, import_io.activeGcsSignal)(signal);
197
+ if (!status(error, 404)) throw new import_errors.ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
198
+ }
199
+ (0, import_io.activeGcsSignal)(signal);
200
+ try {
201
+ await file.save(Buffer.alloc(0), {
202
+ resumable: false,
203
+ preconditionOpts: { ifGenerationMatch: generation },
204
+ metadata: { cacheControl: "no-store", metadata: { [TOMBSTONE]: scopeKey } }
205
+ });
206
+ (0, import_io.activeGcsSignal)(signal);
207
+ const [verified] = await file.getMetadata();
208
+ (0, import_io.activeGcsSignal)(signal);
209
+ if (verified.metadata?.[TOMBSTONE] !== scopeKey || String(verified.size) !== "0")
210
+ throw new import_errors.ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
211
+ fencedGeneration = String(verified.generation);
212
+ } catch (error) {
213
+ (0, import_io.activeGcsSignal)(signal);
214
+ if ((0, import_errors.isReportingGcsFenceError)(error)) throw error;
215
+ if (!status(error, 412)) throw new import_errors.ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
216
+ }
217
+ }
218
+ if (!fencedGeneration) throw new import_errors.ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
219
+ (0, import_io.activeGcsSignal)(signal);
220
+ await store.markObjectWriteFenced(
221
+ {
222
+ ...scope,
223
+ plan_id: object.plan_id,
224
+ object_index: object.object_index,
225
+ tombstone_generation: fencedGeneration
226
+ },
227
+ { signal }
228
+ );
229
+ (0, import_io.activeGcsSignal)(signal);
230
+ }
231
+ const remaining = await store.listRevokedObjectWrites(scope, { limit: 1 }, { signal });
232
+ (0, import_io.activeGcsSignal)(signal);
233
+ return { fenced: objects.length, complete: remaining.length === 0 };
234
+ }
235
+ function requireSignal(context) {
236
+ if (!(context?.signal instanceof AbortSignal)) throw new import_errors.ReportingGcsFenceError("INVALID_INPUT");
237
+ return context.signal;
238
+ }
239
+ return {
240
+ probe: async (context) => bounded((signal) => probe(storage.bucket(bucketName), signal), context?.signal),
241
+ register: async (scope, deliveryId, bodies, context) => bounded((signal) => register(scope, deliveryId, bodies, signal), context?.signal),
242
+ write: async (plan, index, bytes, context) => bounded((signal) => write(plan, index, bytes, signal), requireSignal(context)),
243
+ revoke: async (scope, context) => bounded((signal) => revoke(scope, context.maxObjects, signal), requireSignal(context))
244
+ };
245
+ }
246
+ // Annotate the CommonJS export names for ESM import in node:
247
+ 0 && (module.exports = {
248
+ ReportingGcsFenceError,
249
+ createGcsReportingObjectFenceV1
250
+ });
@@ -0,0 +1,230 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ assertReportingObjectWriteScope,
4
+ reportingObjectWritePlanFingerprint,
5
+ reportingObjectWriteName,
6
+ reportingObjectWriteScopeKey
7
+ } from "../ledger/object-writes.mjs";
8
+ import { ReportingGcsFenceError, isReportingGcsFenceError } from "./errors.mjs";
9
+ import { activeGcsSignal as active, withGcsDeadline, readGcsBytes } from "./io.mjs";
10
+ import { assertGcsReportingBucketPolicy } from "./bucket-policy.mjs";
11
+ const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
12
+ const TOMBSTONE = "adcp_reporting_tombstone";
13
+ import { ReportingGcsFenceError as ReportingGcsFenceError2 } from "./errors.mjs";
14
+ function createGcsReportingObjectFenceV1(options) {
15
+ if (!options || typeof options.bucket !== "string" || !/^[a-z0-9][a-z0-9.-]{1,220}[a-z0-9]$/.test(options.bucket) || typeof options.namespace !== "string" || options.namespace.length < 1 || options.namespace.length > 255 || !options.storage || typeof options.storage.bucket !== "function" || !options.store)
16
+ throw new ReportingGcsFenceError("INVALID_INPUT");
17
+ const { storage, store, bucket: bucketName, namespace } = options;
18
+ const deadline = options.operationDeadlineMilliseconds ?? 6e4;
19
+ if (!Number.isSafeInteger(deadline) || deadline < 1 || deadline > 6e4)
20
+ throw new ReportingGcsFenceError("INVALID_INPUT");
21
+ const provider = { bucket: bucketName, namespace_key: hash(namespace) };
22
+ const status = (error, code) => !!error && typeof error === "object" && "code" in error && Number(error.code) === code;
23
+ const bounded = (work, signal) => withGcsDeadline(work, { signal, milliseconds: deadline });
24
+ async function probe(bucket, signal) {
25
+ active(signal);
26
+ try {
27
+ const [metadata] = await bucket.getMetadata();
28
+ active(signal);
29
+ try {
30
+ assertGcsReportingBucketPolicy(metadata);
31
+ } catch {
32
+ throw new ReportingGcsFenceError("UNSAFE_BUCKET");
33
+ }
34
+ } catch (error) {
35
+ active(signal);
36
+ if (isReportingGcsFenceError(error)) throw error;
37
+ throw new ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
38
+ }
39
+ }
40
+ function assertScope(scope) {
41
+ try {
42
+ assertReportingObjectWriteScope(scope);
43
+ } catch {
44
+ throw new ReportingGcsFenceError("INVALID_INPUT");
45
+ }
46
+ }
47
+ function assertPlan(plan) {
48
+ try {
49
+ reportingObjectWritePlanFingerprint(plan);
50
+ } catch {
51
+ throw new ReportingGcsFenceError("INVALID_INPUT");
52
+ }
53
+ if (plan.provider.bucket !== bucketName || plan.provider.namespace_key !== provider.namespace_key)
54
+ throw new ReportingGcsFenceError("INVALID_INPUT");
55
+ }
56
+ async function register(scope, deliveryId, bodies, signal) {
57
+ assertScope(scope);
58
+ if (typeof deliveryId !== "string" || deliveryId.length < 1 || deliveryId.length > 255 || !Array.isArray(bodies) || bodies.length < 1 || bodies.length > 128 || bodies.some((b) => !(b instanceof Uint8Array) || b.byteLength > 64 * 1024 * 1024) || bodies.reduce((total, b) => total + b.byteLength, 0) > 64 * 1024 * 1024)
59
+ throw new ReportingGcsFenceError("INVALID_INPUT");
60
+ const scopeCopy = {
61
+ account_id: scope.account_id,
62
+ destination_ref: scope.destination_ref,
63
+ generation: scope.generation
64
+ };
65
+ const planId = hash(deliveryId);
66
+ const plan = {
67
+ ...scopeCopy,
68
+ provider: { ...provider },
69
+ plan_id: planId,
70
+ objects: bodies.map((b, i) => ({
71
+ bucket: bucketName,
72
+ object_name: reportingObjectWriteName(scopeCopy, provider, planId, i),
73
+ sha256: hash(b),
74
+ size_bytes: b.byteLength
75
+ }))
76
+ };
77
+ await probe(storage.bucket(bucketName), signal);
78
+ active(signal);
79
+ const registered = await store.registerObjectWritePlan(plan, { signal });
80
+ active(signal);
81
+ if (registered === "revoked") throw new ReportingGcsFenceError("REVOKED");
82
+ return plan;
83
+ }
84
+ async function write(input, index, inputBytes, signal) {
85
+ const plan = structuredClone(input);
86
+ assertPlan(plan);
87
+ const expected = plan.objects[index];
88
+ if (!Number.isInteger(index) || !expected || !(inputBytes instanceof Uint8Array))
89
+ throw new ReportingGcsFenceError("INVALID_INPUT");
90
+ if (inputBytes.byteLength !== expected.size_bytes) throw new ReportingGcsFenceError("CONTENT_CONFLICT");
91
+ const bytes = Buffer.from(inputBytes);
92
+ if (hash(bytes) !== expected.sha256) throw new ReportingGcsFenceError("CONTENT_CONFLICT");
93
+ active(signal);
94
+ const bucket = storage.bucket(bucketName);
95
+ await probe(bucket, signal);
96
+ active(signal);
97
+ const registered = await store.registerObjectWritePlan(plan, { signal });
98
+ active(signal);
99
+ if (registered === "revoked") throw new ReportingGcsFenceError("REVOKED");
100
+ const file = bucket.file(expected.object_name);
101
+ try {
102
+ await file.save(bytes, {
103
+ resumable: false,
104
+ preconditionOpts: { ifGenerationMatch: 0 },
105
+ metadata: { cacheControl: "no-store" }
106
+ });
107
+ active(signal);
108
+ } catch (error) {
109
+ active(signal);
110
+ if (!status(error, 412)) throw new ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
111
+ try {
112
+ const [metadata] = await file.getMetadata();
113
+ active(signal);
114
+ if (metadata.metadata?.[TOMBSTONE] !== void 0) throw new ReportingGcsFenceError("REVOKED");
115
+ const existing = await readGcsBytes(
116
+ bucket.file(expected.object_name, { generation: metadata.generation }),
117
+ bytes.length,
118
+ signal
119
+ );
120
+ if (existing.length !== bytes.length || hash(existing) !== expected.sha256)
121
+ throw new ReportingGcsFenceError("CONTENT_CONFLICT");
122
+ } catch (error2) {
123
+ active(signal);
124
+ if (status(error2, 404)) {
125
+ const current = await store.registerObjectWritePlan(plan, { signal });
126
+ active(signal);
127
+ if (current === "revoked") throw new ReportingGcsFenceError("REVOKED");
128
+ }
129
+ if (isReportingGcsFenceError(error2)) throw error2;
130
+ throw new ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
131
+ }
132
+ }
133
+ active(signal);
134
+ if (await store.registerObjectWritePlan(plan, { signal }) === "revoked")
135
+ throw new ReportingGcsFenceError("REVOKED");
136
+ active(signal);
137
+ }
138
+ async function revoke(scopeInput, maxObjects, signal) {
139
+ assertScope(scopeInput);
140
+ const scope = {
141
+ account_id: scopeInput.account_id,
142
+ destination_ref: scopeInput.destination_ref,
143
+ generation: scopeInput.generation
144
+ };
145
+ const limit = maxObjects ?? 10;
146
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e3) throw new ReportingGcsFenceError("INVALID_INPUT");
147
+ active(signal);
148
+ const binding = await store.getObjectWriteBinding(scope, { signal });
149
+ active(signal);
150
+ const objects = await store.listRevokedObjectWrites(scope, { limit }, { signal });
151
+ active(signal);
152
+ if (!binding) {
153
+ if (objects.length) throw new ReportingGcsFenceError("STATE_UNAVAILABLE");
154
+ return { fenced: 0, complete: true };
155
+ }
156
+ const bucket = storage.bucket(binding.bucket);
157
+ await probe(bucket, signal);
158
+ const scopeKey = reportingObjectWriteScopeKey(scope);
159
+ for (const object of objects) {
160
+ active(signal);
161
+ if (object.bucket !== binding.bucket || object.object_name !== reportingObjectWriteName(scope, binding, object.plan_id, object.object_index))
162
+ throw new ReportingGcsFenceError("STATE_UNAVAILABLE");
163
+ const file = bucket.file(object.object_name);
164
+ let fencedGeneration;
165
+ for (let attempt = 0; attempt < 4 && !fencedGeneration; attempt++) {
166
+ active(signal);
167
+ let generation = 0;
168
+ try {
169
+ const [metadata] = await file.getMetadata();
170
+ active(signal);
171
+ generation = String(metadata.generation);
172
+ if (metadata.metadata?.[TOMBSTONE] === scopeKey && String(metadata.size) === "0") {
173
+ fencedGeneration = String(metadata.generation);
174
+ break;
175
+ }
176
+ } catch (error) {
177
+ active(signal);
178
+ if (!status(error, 404)) throw new ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
179
+ }
180
+ active(signal);
181
+ try {
182
+ await file.save(Buffer.alloc(0), {
183
+ resumable: false,
184
+ preconditionOpts: { ifGenerationMatch: generation },
185
+ metadata: { cacheControl: "no-store", metadata: { [TOMBSTONE]: scopeKey } }
186
+ });
187
+ active(signal);
188
+ const [verified] = await file.getMetadata();
189
+ active(signal);
190
+ if (verified.metadata?.[TOMBSTONE] !== scopeKey || String(verified.size) !== "0")
191
+ throw new ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
192
+ fencedGeneration = String(verified.generation);
193
+ } catch (error) {
194
+ active(signal);
195
+ if (isReportingGcsFenceError(error)) throw error;
196
+ if (!status(error, 412)) throw new ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
197
+ }
198
+ }
199
+ if (!fencedGeneration) throw new ReportingGcsFenceError("PROVIDER_UNAVAILABLE");
200
+ active(signal);
201
+ await store.markObjectWriteFenced(
202
+ {
203
+ ...scope,
204
+ plan_id: object.plan_id,
205
+ object_index: object.object_index,
206
+ tombstone_generation: fencedGeneration
207
+ },
208
+ { signal }
209
+ );
210
+ active(signal);
211
+ }
212
+ const remaining = await store.listRevokedObjectWrites(scope, { limit: 1 }, { signal });
213
+ active(signal);
214
+ return { fenced: objects.length, complete: remaining.length === 0 };
215
+ }
216
+ function requireSignal(context) {
217
+ if (!(context?.signal instanceof AbortSignal)) throw new ReportingGcsFenceError("INVALID_INPUT");
218
+ return context.signal;
219
+ }
220
+ return {
221
+ probe: async (context) => bounded((signal) => probe(storage.bucket(bucketName), signal), context?.signal),
222
+ register: async (scope, deliveryId, bodies, context) => bounded((signal) => register(scope, deliveryId, bodies, signal), context?.signal),
223
+ write: async (plan, index, bytes, context) => bounded((signal) => write(plan, index, bytes, signal), requireSignal(context)),
224
+ revoke: async (scope, context) => bounded((signal) => revoke(scope, context.maxObjects, signal), requireSignal(context))
225
+ };
226
+ }
227
+ export {
228
+ ReportingGcsFenceError2 as ReportingGcsFenceError,
229
+ createGcsReportingObjectFenceV1
230
+ };
@@ -0,0 +1,7 @@
1
+ export { createGcsReportingObjectFenceV1 } from './fence.mjs';
2
+ export type { GcsReportingObjectFenceV1 } from './fence.mjs';
3
+ export { ReportingGcsFenceError, isReportingGcsFenceError } from './errors.mjs';
4
+ export { createGcsReportingResourceReaderV1, createGcsReportingReferenceResolverV1 } from './reader.mjs';
5
+ export type { GcsReportingReadScopeV1, GcsReportingReadAuthorizationV1, GcsReportingReaderOptionsV1 } from './reader.mjs';
6
+ export { createGcsReportingManagedDeliveryAdapterV1 } from './adapter.mjs';
7
+ export type { CreateGcsReportingManagedDeliveryAdapterOptionsV1 } from './adapter.mjs';
@@ -0,0 +1,7 @@
1
+ export { createGcsReportingObjectFenceV1 } from './fence';
2
+ export type { GcsReportingObjectFenceV1 } from './fence';
3
+ export { ReportingGcsFenceError, isReportingGcsFenceError } from './errors';
4
+ export { createGcsReportingResourceReaderV1, createGcsReportingReferenceResolverV1 } from './reader';
5
+ export type { GcsReportingReadScopeV1, GcsReportingReadAuthorizationV1, GcsReportingReaderOptionsV1 } from './reader';
6
+ export { createGcsReportingManagedDeliveryAdapterV1 } from './adapter';
7
+ export type { CreateGcsReportingManagedDeliveryAdapterOptionsV1 } from './adapter';
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var gcs_exports = {};
20
+ __export(gcs_exports, {
21
+ ReportingGcsFenceError: () => import_errors.ReportingGcsFenceError,
22
+ createGcsReportingManagedDeliveryAdapterV1: () => import_adapter.createGcsReportingManagedDeliveryAdapterV1,
23
+ createGcsReportingObjectFenceV1: () => import_fence.createGcsReportingObjectFenceV1,
24
+ createGcsReportingReferenceResolverV1: () => import_reader.createGcsReportingReferenceResolverV1,
25
+ createGcsReportingResourceReaderV1: () => import_reader.createGcsReportingResourceReaderV1,
26
+ isReportingGcsFenceError: () => import_errors.isReportingGcsFenceError
27
+ });
28
+ module.exports = __toCommonJS(gcs_exports);
29
+ var import_fence = require('./fence.js');
30
+ var import_errors = require('./errors.js');
31
+ var import_reader = require('./reader.js');
32
+ var import_adapter = require('./adapter.js');
33
+ // Annotate the CommonJS export names for ESM import in node:
34
+ 0 && (module.exports = {
35
+ ReportingGcsFenceError,
36
+ createGcsReportingManagedDeliveryAdapterV1,
37
+ createGcsReportingObjectFenceV1,
38
+ createGcsReportingReferenceResolverV1,
39
+ createGcsReportingResourceReaderV1,
40
+ isReportingGcsFenceError
41
+ });
@@ -0,0 +1,12 @@
1
+ import { createGcsReportingObjectFenceV1 } from "./fence.mjs";
2
+ import { ReportingGcsFenceError, isReportingGcsFenceError } from "./errors.mjs";
3
+ import { createGcsReportingResourceReaderV1, createGcsReportingReferenceResolverV1 } from "./reader.mjs";
4
+ import { createGcsReportingManagedDeliveryAdapterV1 } from "./adapter.mjs";
5
+ export {
6
+ ReportingGcsFenceError,
7
+ createGcsReportingManagedDeliveryAdapterV1,
8
+ createGcsReportingObjectFenceV1,
9
+ createGcsReportingReferenceResolverV1,
10
+ createGcsReportingResourceReaderV1,
11
+ isReportingGcsFenceError
12
+ };
@@ -0,0 +1,7 @@
1
+ import type { File } from '@google-cloud/storage';
2
+ export declare function activeGcsSignal(signal: AbortSignal): void;
3
+ export declare function withGcsDeadline<T>(work: (signal: AbortSignal) => Promise<T>, context?: {
4
+ signal?: AbortSignal;
5
+ milliseconds?: number;
6
+ }): Promise<T>;
7
+ export declare function readGcsBytes(file: File, maxBytes: number, signal: AbortSignal): Promise<Buffer>;
@@ -0,0 +1,7 @@
1
+ import type { File } from '@google-cloud/storage';
2
+ export declare function activeGcsSignal(signal: AbortSignal): void;
3
+ export declare function withGcsDeadline<T>(work: (signal: AbortSignal) => Promise<T>, context?: {
4
+ signal?: AbortSignal;
5
+ milliseconds?: number;
6
+ }): Promise<T>;
7
+ export declare function readGcsBytes(file: File, maxBytes: number, signal: AbortSignal): Promise<Buffer>;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var io_exports = {};
20
+ __export(io_exports, {
21
+ activeGcsSignal: () => activeGcsSignal,
22
+ readGcsBytes: () => readGcsBytes,
23
+ withGcsDeadline: () => withGcsDeadline
24
+ });
25
+ module.exports = __toCommonJS(io_exports);
26
+ var import_object_writes = require('../ledger/object-writes.js');
27
+ var import_errors = require('./errors.js');
28
+ function activeGcsSignal(signal) {
29
+ if (signal.aborted) throw signal.reason;
30
+ }
31
+ const active = activeGcsSignal;
32
+ async function withGcsDeadline(work, context = {}) {
33
+ const signal = context.signal;
34
+ const deadline = context.milliseconds ?? 6e4;
35
+ if (!Number.isSafeInteger(deadline) || deadline < 1 || deadline > 6e4)
36
+ throw new import_errors.ReportingGcsFenceError("INVALID_INPUT");
37
+ if (signal !== void 0 && !(signal instanceof AbortSignal)) throw new import_errors.ReportingGcsFenceError("INVALID_INPUT");
38
+ const controller = new AbortController();
39
+ const onAbort = () => controller.abort(new import_errors.ReportingGcsFenceError("ABORTED"));
40
+ signal?.addEventListener("abort", onAbort, { once: true });
41
+ if (signal?.aborted) onAbort();
42
+ const timer = setTimeout(() => controller.abort(new import_errors.ReportingGcsFenceError("DEADLINE_EXCEEDED")), deadline);
43
+ let rejectAbort;
44
+ try {
45
+ active(controller.signal);
46
+ return await Promise.race([
47
+ work(controller.signal),
48
+ new Promise((_, reject) => {
49
+ rejectAbort = () => reject(controller.signal.reason);
50
+ controller.signal.addEventListener("abort", rejectAbort, { once: true });
51
+ if (controller.signal.aborted) rejectAbort();
52
+ })
53
+ ]);
54
+ } catch (error) {
55
+ if (controller.signal.aborted) throw controller.signal.reason;
56
+ if ((0, import_errors.isReportingGcsFenceError)(error)) throw error;
57
+ if ((0, import_object_writes.isReportingObjectWriteConflictError)(error) || error instanceof Error && (0, import_object_writes.isReportingObjectWriteConflictError)(error.cause))
58
+ throw new import_errors.ReportingGcsFenceError("CONTENT_CONFLICT");
59
+ if ((0, import_object_writes.isReportingObjectWriteNotRevokedError)(error) || error instanceof Error && (0, import_object_writes.isReportingObjectWriteNotRevokedError)(error.cause))
60
+ throw new import_errors.ReportingGcsFenceError("NOT_REVOKED");
61
+ throw new import_errors.ReportingGcsFenceError("STATE_UNAVAILABLE");
62
+ } finally {
63
+ clearTimeout(timer);
64
+ signal?.removeEventListener("abort", onAbort);
65
+ if (rejectAbort) controller.signal.removeEventListener("abort", rejectAbort);
66
+ }
67
+ }
68
+ async function readGcsBytes(file, maxBytes, signal) {
69
+ active(signal);
70
+ const stream = file.createReadStream();
71
+ const abort = () => stream.destroy(new import_errors.ReportingGcsFenceError("ABORTED"));
72
+ signal.addEventListener("abort", abort, { once: true });
73
+ if (signal.aborted) abort();
74
+ const chunks = [];
75
+ let count = 0;
76
+ try {
77
+ for await (const chunk of stream) {
78
+ active(signal);
79
+ count += chunk.length;
80
+ if (count > maxBytes) throw new import_errors.ReportingGcsFenceError("CONTENT_CONFLICT");
81
+ chunks.push(Buffer.from(chunk));
82
+ }
83
+ active(signal);
84
+ return Buffer.concat(chunks);
85
+ } finally {
86
+ signal.removeEventListener("abort", abort);
87
+ stream.destroy();
88
+ }
89
+ }
90
+ // Annotate the CommonJS export names for ESM import in node:
91
+ 0 && (module.exports = {
92
+ activeGcsSignal,
93
+ readGcsBytes,
94
+ withGcsDeadline
95
+ });