@alvin0/ai-agent-sdk-observability-fetch 0.1.10 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ObservationBoundary } from "@alvin0/ai-agent-sdk-core";
2
2
  import { ExportAck, FlushResult, Observability, ObservationBatch, ObservationExporter, ObservationExporterPlugin } from "@alvin0/ai-agent-sdk-core/observability";
3
- //#region src/fetch-exporter.d.ts
3
+ //#region src/fetch-options.d.ts
4
4
  interface FetchObservationExporterOptions {
5
5
  readonly id?: string;
6
6
  readonly endpoint: string | URL;
@@ -23,6 +23,8 @@ interface FetchObservationExporterOptions {
23
23
  /** Clock injection used only for HTTP-date `Retry-After`. */
24
24
  readonly now?: () => number;
25
25
  }
26
+ //#endregion
27
+ //#region src/fetch-exporter.d.ts
26
28
  /** A remote-acknowledged exporter using only Fetch and Web streams. */
27
29
  declare class FetchObservationExporter implements ObservationExporter {
28
30
  readonly id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/fetch-exporter.ts","../src/wait-until.ts"],"mappings":";;;UA4BiB;WACN;WACA,mBAAmB;WACnB,UAAU,SAAS;WACnB,eAAe;;WAEf;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;WAEA;;WAEA,SAAS,sBAAsB,QAAQ,gBAAgB;;WAEvD;;;cAsME,oCAAoC;WACtC;WACA,8BAA8B;mBACtB;EAEjB,YAAY,SAAS;EAWf,OAAO,OAAO,kBAAkB,QAAQ,cAAc,QAAQ;;;iBAsFtD,yBACd,SAAS,kCACR;;;KC5VS,aAAa,SAAS;;iBAGlB,gCACd,aAAa,KAAK,yBAClB,WAAW,WACX,SAAS,cACR,QAAQ"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/fetch-options.ts","../src/fetch-exporter.ts","../src/wait-until.ts"],"mappings":";;;UAYiB;WACN;WACA,mBAAmB;WACnB,UAAU,SAAS;WACnB,eAAe;;WAEf;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;WAEA;;WAEA,SAAS,sBAAsB,QAAQ,gBAAgB;;WAEvD;;;;;cCfE,oCAAoC;WACtC;WACA,8BAA8B;mBACtB;EAEjB,YAAY,SAAS;EAWf,OAAO,OAAO,kBAAkB,QAAQ,cAAc,QAAQ;;;iBAQtD,yBACd,SAAS,kCACR;;;KCzCS,aAAa,SAAS;;iBAGlB,gCACd,aAAa,KAAK,yBAClB,WAAW,WACX,SAAS,cACR,QAAQ"}
package/dist/index.js CHANGED
@@ -1,77 +1,16 @@
1
1
  import { waitForSettlement } from "@alvin0/ai-agent-sdk-core";
2
2
  import { defineObservationExporter } from "@alvin0/ai-agent-sdk-core/observability";
3
3
 
4
- //#region src/fetch-exporter.ts
5
- const DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
6
- const DEFAULT_MAX_ATTEMPTS = 8;
7
- const DEFAULT_BASE_DELAY_MS = 250;
8
- const DEFAULT_MAX_DELAY_MS = 3e4;
9
- const MAX_RETRY_AFTER_MS = 6e4;
10
- const DEFAULT_MAX_BATCH_EVENTS = 256;
11
- const DEFAULT_MAX_BATCH_BYTES = 524288;
12
- const DEFAULT_MAX_ACK_BYTES = 65536;
13
- const DEFAULT_MAX_ACK_CHUNKS = 1e3;
4
+ //#region src/fetch-transport.ts
14
5
  const RETRYABLE_STATUSES = /* @__PURE__ */ new Set([
15
6
  408,
16
7
  425,
17
8
  429
18
9
  ]);
19
- const FORBIDDEN_HEADER_NAMES = /* @__PURE__ */ new Set([
20
- "content-length",
21
- "content-type",
22
- "host",
23
- "idempotency-key"
24
- ]);
10
+ const MAX_RETRY_AFTER_MS = 6e4;
25
11
  var ObservationProtocolError = class extends Error {
26
12
  name = "ObservationProtocolError";
27
13
  };
28
- function positiveSafeInteger(value, field) {
29
- if (!Number.isSafeInteger(value) || value < 1) throw new RangeError(`${field} must be a positive safe integer`);
30
- return value;
31
- }
32
- function nonNegativeFinite(value, field) {
33
- if (!Number.isFinite(value) || value < 0) throw new RangeError(`${field} must be a non-negative finite number`);
34
- return value;
35
- }
36
- function endpointOf(value, allowInsecureHttp) {
37
- const endpoint = new URL(value);
38
- if (endpoint.username.length > 0 || endpoint.password.length > 0) throw new TypeError("observation endpoint must not contain credentials");
39
- const local = endpoint.hostname === "localhost" || endpoint.hostname === "127.0.0.1" || endpoint.hostname === "[::1]" || endpoint.hostname === "::1";
40
- if (endpoint.protocol !== "https:" && !(allowInsecureHttp && endpoint.protocol === "http:" && local)) throw new TypeError("observation endpoint must use https");
41
- return endpoint;
42
- }
43
- function headersOf(headers) {
44
- const output = Object.create(null);
45
- for (const [name, value] of Object.entries(headers ?? {})) {
46
- const normalized = name.toLowerCase();
47
- if (FORBIDDEN_HEADER_NAMES.has(normalized)) throw new TypeError(`observation header ${name} is managed by the exporter`);
48
- if (typeof value !== "string" || !/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name) || /[\r\n]/.test(value)) throw new TypeError(`observation header ${name} is invalid`);
49
- output[normalized] = value;
50
- }
51
- return Object.freeze(output);
52
- }
53
- function resolveOptions(options) {
54
- if (typeof options?.fetch !== "function" && typeof globalThis.fetch !== "function") throw new TypeError("Fetch observation exporter requires fetch");
55
- if (options.random !== void 0 && typeof options.random !== "function") throw new TypeError("random must be a function");
56
- if (options.delay !== void 0 && typeof options.delay !== "function") throw new TypeError("delay must be a function");
57
- if (options.now !== void 0 && typeof options.now !== "function") throw new TypeError("now must be a function");
58
- return Object.freeze({
59
- endpoint: endpointOf(options.endpoint, options.allowInsecureHttp ?? false),
60
- headers: headersOf(options.headers),
61
- fetch: options.fetch ?? globalThis.fetch,
62
- requestTimeoutMs: positiveSafeInteger(options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS, "requestTimeoutMs"),
63
- maxAttempts: positiveSafeInteger(options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS, "maxAttempts"),
64
- baseDelayMs: nonNegativeFinite(options.baseDelayMs ?? DEFAULT_BASE_DELAY_MS, "baseDelayMs"),
65
- maxDelayMs: nonNegativeFinite(options.maxDelayMs ?? DEFAULT_MAX_DELAY_MS, "maxDelayMs"),
66
- maxBatchEvents: positiveSafeInteger(options.maxBatchEvents ?? DEFAULT_MAX_BATCH_EVENTS, "maxBatchEvents"),
67
- maxBatchBytes: positiveSafeInteger(options.maxBatchBytes ?? DEFAULT_MAX_BATCH_BYTES, "maxBatchBytes"),
68
- maxAckBytes: positiveSafeInteger(options.maxAckBytes ?? DEFAULT_MAX_ACK_BYTES, "maxAckBytes"),
69
- maxAckChunks: positiveSafeInteger(options.maxAckChunks ?? DEFAULT_MAX_ACK_CHUNKS, "maxAckChunks"),
70
- random: options.random ?? Math.random,
71
- delay: options.delay ?? abortableDelay,
72
- now: options.now ?? Date.now
73
- });
74
- }
75
14
  function retryableStatus(status) {
76
15
  return RETRYABLE_STATUSES.has(status) || status >= 500 && status <= 599;
77
16
  }
@@ -190,103 +129,205 @@ async function validateNoRedirectResponse(response, endpoint) {
190
129
  if (responseOrigin !== endpoint.origin) throw new ObservationProtocolError("observation response origin does not match its endpoint");
191
130
  }
192
131
  }
193
- /** A remote-acknowledged exporter using only Fetch and Web streams. */
194
- var FetchObservationExporter = class {
195
- id;
196
- supportedBoundaries = Object.freeze(["remote-acknowledged"]);
197
- options;
198
- constructor(options) {
199
- if (typeof options !== "object" || options === null) throw new TypeError("Fetch observation exporter options are required");
200
- this.id = options.id ?? "fetch";
201
- if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,63})$/.test(this.id)) throw new TypeError("Fetch observation exporter id must be a safe 1-64 character identifier");
202
- this.options = resolveOptions(options);
132
+
133
+ //#endregion
134
+ //#region src/fetch-options.ts
135
+ const DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
136
+ const DEFAULT_MAX_ATTEMPTS = 8;
137
+ const DEFAULT_BASE_DELAY_MS = 250;
138
+ const DEFAULT_MAX_DELAY_MS = 3e4;
139
+ const DEFAULT_MAX_BATCH_EVENTS = 256;
140
+ const DEFAULT_MAX_BATCH_BYTES = 524288;
141
+ const DEFAULT_MAX_ACK_BYTES = 65536;
142
+ const DEFAULT_MAX_ACK_CHUNKS = 1e3;
143
+ const FORBIDDEN_HEADER_NAMES = /* @__PURE__ */ new Set([
144
+ "content-length",
145
+ "content-type",
146
+ "host",
147
+ "idempotency-key"
148
+ ]);
149
+ function positiveSafeInteger(value, field) {
150
+ if (!Number.isSafeInteger(value) || value < 1) throw new RangeError(`${field} must be a positive safe integer`);
151
+ return value;
152
+ }
153
+ function nonNegativeFinite(value, field) {
154
+ if (!Number.isFinite(value) || value < 0) throw new RangeError(`${field} must be a non-negative finite number`);
155
+ return value;
156
+ }
157
+ function endpointOf(value, allowInsecureHttp) {
158
+ const endpoint = new URL(value);
159
+ if (endpoint.username.length > 0 || endpoint.password.length > 0) throw new TypeError("observation endpoint must not contain credentials");
160
+ const local = endpoint.hostname === "localhost" || endpoint.hostname === "127.0.0.1" || endpoint.hostname === "[::1]" || endpoint.hostname === "::1";
161
+ if (endpoint.protocol !== "https:" && !(allowInsecureHttp && endpoint.protocol === "http:" && local)) throw new TypeError("observation endpoint must use https");
162
+ return endpoint;
163
+ }
164
+ function headersOf(headers) {
165
+ const output = Object.create(null);
166
+ for (const [name, value] of Object.entries(headers ?? {})) {
167
+ const normalized = name.toLowerCase();
168
+ if (FORBIDDEN_HEADER_NAMES.has(normalized)) throw new TypeError(`observation header ${name} is managed by the exporter`);
169
+ if (typeof value !== "string" || !/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name) || /[\r\n]/.test(value)) throw new TypeError(`observation header ${name} is invalid`);
170
+ output[normalized] = value;
203
171
  }
204
- async export(batch, signal) {
205
- const result = await sendBatch(this.options, batch.batchId, batch.events.length, batch, signal);
172
+ return Object.freeze(output);
173
+ }
174
+ function resolveOptions(options) {
175
+ validateInjectedFunctions(options);
176
+ return Object.freeze({
177
+ endpoint: endpointOf(options.endpoint, options.allowInsecureHttp ?? false),
178
+ headers: headersOf(options.headers),
179
+ fetch: options.fetch ?? globalThis.fetch,
180
+ ...retryOptions(options),
181
+ ...resourceLimits(options),
182
+ random: options.random ?? Math.random,
183
+ delay: options.delay ?? abortableDelay,
184
+ now: options.now ?? Date.now
185
+ });
186
+ }
187
+ function validateInjectedFunctions(options) {
188
+ if (typeof options?.fetch !== "function" && typeof globalThis.fetch !== "function") throw new TypeError("Fetch observation exporter requires fetch");
189
+ if (options.random !== void 0 && typeof options.random !== "function") throw new TypeError("random must be a function");
190
+ if (options.delay !== void 0 && typeof options.delay !== "function") throw new TypeError("delay must be a function");
191
+ if (options.now !== void 0 && typeof options.now !== "function") throw new TypeError("now must be a function");
192
+ }
193
+ function retryOptions(options) {
194
+ return {
195
+ requestTimeoutMs: positiveSafeInteger(options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS, "requestTimeoutMs"),
196
+ maxAttempts: positiveSafeInteger(options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS, "maxAttempts"),
197
+ baseDelayMs: nonNegativeFinite(options.baseDelayMs ?? DEFAULT_BASE_DELAY_MS, "baseDelayMs"),
198
+ maxDelayMs: nonNegativeFinite(options.maxDelayMs ?? DEFAULT_MAX_DELAY_MS, "maxDelayMs")
199
+ };
200
+ }
201
+ function resourceLimits(options) {
202
+ return {
203
+ maxBatchEvents: positiveSafeInteger(options.maxBatchEvents ?? DEFAULT_MAX_BATCH_EVENTS, "maxBatchEvents"),
204
+ maxBatchBytes: positiveSafeInteger(options.maxBatchBytes ?? DEFAULT_MAX_BATCH_BYTES, "maxBatchBytes"),
205
+ maxAckBytes: positiveSafeInteger(options.maxAckBytes ?? DEFAULT_MAX_ACK_BYTES, "maxAckBytes"),
206
+ maxAckChunks: positiveSafeInteger(options.maxAckChunks ?? DEFAULT_MAX_ACK_CHUNKS, "maxAckChunks")
207
+ };
208
+ }
209
+
210
+ //#endregion
211
+ //#region src/fetch-send.ts
212
+ async function successfulResponse(response, options, batchId, signal) {
213
+ if (response.status === 204) {
214
+ await cancelBody(response);
206
215
  return Object.freeze({
207
- batchId: batch.batchId,
208
- ...result
216
+ accepted: true,
217
+ retryable: false
209
218
  });
210
219
  }
211
- };
212
- async function sendBatch(options, batchId, itemCount, batch, signal) {
213
- if (itemCount > options.maxBatchEvents) return Object.freeze({
220
+ const raw = await boundedText(response, options, signal);
221
+ let parsed;
222
+ try {
223
+ parsed = JSON.parse(raw);
224
+ } catch {
225
+ parsed = void 0;
226
+ }
227
+ const acceptedBatchId = typeof parsed === "object" && parsed !== null ? Reflect.get(parsed, "acceptedBatchId") : void 0;
228
+ return Object.freeze({
229
+ accepted: acceptedBatchId === batchId,
230
+ retryable: false
231
+ });
232
+ }
233
+ async function responseResult(response, options, batchId, control) {
234
+ await validateNoRedirectResponse(response, options.endpoint);
235
+ if (response.status >= 200 && response.status < 300) return { result: await successfulResponse(response, options, batchId, control.signal) };
236
+ const retryable = retryableStatus(response.status);
237
+ const retryAfter = retryAfterMs(response.headers.get("retry-after"), options.now());
238
+ await cancelBody(response);
239
+ if (!retryable || control.attempt === options.maxAttempts) return { result: Object.freeze({
240
+ accepted: false,
241
+ retryable
242
+ }) };
243
+ return { retryDelay: retryAfter ?? backoffMs(control.attempt, options) };
244
+ }
245
+ function failedAttempt(error, options, attempt, signal) {
246
+ if (signal.aborted) throw signal.reason ?? error;
247
+ if (error instanceof ObservationProtocolError || error instanceof RangeError) return { result: Object.freeze({
248
+ accepted: false,
249
+ retryable: false
250
+ }) };
251
+ if (attempt === options.maxAttempts) return { result: Object.freeze({
252
+ accepted: false,
253
+ retryable: true
254
+ }) };
255
+ return { retryDelay: backoffMs(attempt, options) };
256
+ }
257
+ async function sendAttempt(options, batchId, body, control) {
258
+ const request = combinedSignal(control.signal, options.requestTimeoutMs);
259
+ const dispatch = options.fetch;
260
+ try {
261
+ return await responseResult(await raceAbort(Promise.resolve(dispatch(options.endpoint, {
262
+ method: "POST",
263
+ headers: {
264
+ ...options.headers,
265
+ "content-type": "application/json",
266
+ "idempotency-key": batchId
267
+ },
268
+ body,
269
+ redirect: "manual",
270
+ signal: request.signal
271
+ })), request.signal), options, batchId, {
272
+ attempt: control.attempt,
273
+ signal: request.signal
274
+ });
275
+ } catch (error) {
276
+ return failedAttempt(error, options, control.attempt, control.signal);
277
+ } finally {
278
+ request.clear();
279
+ }
280
+ }
281
+ async function sendBatch(options, batch, signal) {
282
+ if (batch.count > options.maxBatchEvents) return Object.freeze({
214
283
  accepted: false,
215
284
  retryable: false
216
285
  });
217
- const body = JSON.stringify(batch);
286
+ const body = JSON.stringify(batch.value);
218
287
  if (new TextEncoder().encode(body).byteLength > options.maxBatchBytes) return Object.freeze({
219
288
  accepted: false,
220
289
  retryable: false
221
290
  });
222
- const dispatch = options.fetch;
223
291
  for (let attempt = 1; attempt <= options.maxAttempts; attempt++) {
224
292
  if (signal.aborted) throw signal.reason ?? /* @__PURE__ */ new Error("observation export aborted");
225
- const request = combinedSignal(signal, options.requestTimeoutMs);
226
- let retryDelay;
227
- try {
228
- const response = await raceAbort(Promise.resolve(dispatch(options.endpoint, {
229
- method: "POST",
230
- headers: {
231
- ...options.headers,
232
- "content-type": "application/json",
233
- "idempotency-key": batchId
234
- },
235
- body,
236
- redirect: "manual",
237
- signal: request.signal
238
- })), request.signal);
239
- await validateNoRedirectResponse(response, options.endpoint);
240
- if (response.status === 204) {
241
- await cancelBody(response);
242
- return Object.freeze({
243
- accepted: true,
244
- retryable: false
245
- });
246
- }
247
- if (response.status >= 200 && response.status < 300) {
248
- const raw = await boundedText(response, options, request.signal);
249
- let parsed;
250
- try {
251
- parsed = JSON.parse(raw);
252
- } catch {
253
- parsed = void 0;
254
- }
255
- const acceptedBatchId = typeof parsed === "object" && parsed !== null ? Reflect.get(parsed, "acceptedBatchId") : void 0;
256
- return Object.freeze({
257
- accepted: acceptedBatchId === batchId,
258
- retryable: false
259
- });
260
- }
261
- const retryable = retryableStatus(response.status);
262
- const retryAfter = retryAfterMs(response.headers.get("retry-after"), options.now());
263
- await cancelBody(response);
264
- if (!retryable || attempt === options.maxAttempts) return Object.freeze({
265
- accepted: false,
266
- retryable
267
- });
268
- retryDelay = retryAfter ?? backoffMs(attempt, options);
269
- } catch (error) {
270
- if (signal.aborted) throw signal.reason ?? error;
271
- if (error instanceof ObservationProtocolError || error instanceof RangeError) return Object.freeze({
272
- accepted: false,
273
- retryable: false
274
- });
275
- if (attempt === options.maxAttempts) return Object.freeze({
276
- accepted: false,
277
- retryable: true
278
- });
279
- retryDelay = backoffMs(attempt, options);
280
- } finally {
281
- request.clear();
282
- }
283
- await raceAbort(Promise.resolve(options.delay(retryDelay ?? 0, signal)), signal);
293
+ const outcome = await sendAttempt(options, batch.id, body, {
294
+ attempt,
295
+ signal
296
+ });
297
+ if ("result" in outcome) return outcome.result;
298
+ await raceAbort(Promise.resolve(options.delay(outcome.retryDelay, signal)), signal);
284
299
  }
285
300
  return Object.freeze({
286
301
  accepted: false,
287
302
  retryable: true
288
303
  });
289
304
  }
305
+
306
+ //#endregion
307
+ //#region src/fetch-exporter.ts
308
+ /** A remote-acknowledged exporter using only Fetch and Web streams. */
309
+ var FetchObservationExporter = class {
310
+ id;
311
+ supportedBoundaries = Object.freeze(["remote-acknowledged"]);
312
+ options;
313
+ constructor(options) {
314
+ if (typeof options !== "object" || options === null) throw new TypeError("Fetch observation exporter options are required");
315
+ this.id = options.id ?? "fetch";
316
+ if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,63})$/.test(this.id)) throw new TypeError("Fetch observation exporter id must be a safe 1-64 character identifier");
317
+ this.options = resolveOptions(options);
318
+ }
319
+ async export(batch, signal) {
320
+ const result = await sendBatch(this.options, {
321
+ id: batch.batchId,
322
+ count: batch.events.length,
323
+ value: batch
324
+ }, signal);
325
+ return Object.freeze({
326
+ batchId: batch.batchId,
327
+ ...result
328
+ });
329
+ }
330
+ };
290
331
  /** Recommended inert runtime exporter; transport begins only when core exports a batch. */
291
332
  function fetchObservationExporter(options) {
292
333
  if (typeof options !== "object" || options === null) throw new TypeError("Fetch observation exporter options are required");
@@ -297,7 +338,11 @@ function fetchObservationExporter(options) {
297
338
  id,
298
339
  supportedBoundaries: ["remote-acknowledged"],
299
340
  async export(batch, signal) {
300
- const result = await sendBatch(captured, batch.id, batch.events.length + batch.runRecords.length, batch, signal);
341
+ const result = await sendBatch(captured, {
342
+ id: batch.id,
343
+ count: batch.events.length + batch.runRecords.length,
344
+ value: batch
345
+ }, signal);
301
346
  return Object.freeze({
302
347
  batchId: batch.id,
303
348
  acceptedEventIds: result.accepted ? batch.events.map((event) => event.eventId) : [],
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/fetch-exporter.ts","../src/wait-until.ts"],"sourcesContent":["import { waitForSettlement, type ObservationBoundary } from '@alvin0/ai-agent-sdk-core'\nimport type {\n ExportAck,\n ObservationBatch,\n ObservationExporter,\n} from '@alvin0/ai-agent-sdk-core/observability'\nimport {\n defineObservationExporter,\n type ObservationDeliveryBatch,\n type ObservationExporterPlugin,\n} from '@alvin0/ai-agent-sdk-core/observability'\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 10_000\nconst DEFAULT_MAX_ATTEMPTS = 8\nconst DEFAULT_BASE_DELAY_MS = 250\nconst DEFAULT_MAX_DELAY_MS = 30_000\nconst MAX_RETRY_AFTER_MS = 60_000\nconst DEFAULT_MAX_BATCH_EVENTS = 256\nconst DEFAULT_MAX_BATCH_BYTES = 512 * 1024\nconst DEFAULT_MAX_ACK_BYTES = 64 * 1024\nconst DEFAULT_MAX_ACK_CHUNKS = 1_000\nconst RETRYABLE_STATUSES = new Set([408, 425, 429])\nconst FORBIDDEN_HEADER_NAMES = new Set(['content-length', 'content-type', 'host', 'idempotency-key'])\n\nclass ObservationProtocolError extends Error {\n override readonly name = 'ObservationProtocolError'\n}\n\nexport interface FetchObservationExporterOptions {\n readonly id?: string\n readonly endpoint: string | URL\n readonly headers?: Readonly<Record<string, string>>\n readonly fetch?: typeof fetch\n /** Permit cleartext only for localhost/loopback test endpoints. */\n readonly allowInsecureHttp?: boolean\n readonly requestTimeoutMs?: number\n readonly maxAttempts?: number\n readonly baseDelayMs?: number\n readonly maxDelayMs?: number\n readonly maxBatchEvents?: number\n readonly maxBatchBytes?: number\n readonly maxAckBytes?: number\n readonly maxAckChunks?: number\n /** Deterministic injection for tests; defaults to `Math.random`. */\n readonly random?: () => number\n /** Timer injection for tests; defaults to an abortable Web timer. */\n readonly delay?: (milliseconds: number, signal: AbortSignal) => Promise<void>\n /** Clock injection used only for HTTP-date `Retry-After`. */\n readonly now?: () => number\n}\n\ninterface ResolvedOptions {\n readonly endpoint: URL\n readonly headers: Readonly<Record<string, string>>\n readonly fetch: typeof fetch\n readonly requestTimeoutMs: number\n readonly maxAttempts: number\n readonly baseDelayMs: number\n readonly maxDelayMs: number\n readonly maxBatchEvents: number\n readonly maxBatchBytes: number\n readonly maxAckBytes: number\n readonly maxAckChunks: number\n readonly random: () => number\n readonly delay: (milliseconds: number, signal: AbortSignal) => Promise<void>\n readonly now: () => number\n}\n\nfunction positiveSafeInteger(value: number, field: string): number {\n if (!Number.isSafeInteger(value) || value < 1) throw new RangeError(`${field} must be a positive safe integer`)\n return value\n}\n\nfunction nonNegativeFinite(value: number, field: string): number {\n if (!Number.isFinite(value) || value < 0) throw new RangeError(`${field} must be a non-negative finite number`)\n return value\n}\n\nfunction endpointOf(value: string | URL, allowInsecureHttp: boolean): URL {\n const endpoint = new URL(value)\n if (endpoint.username.length > 0 || endpoint.password.length > 0) {\n throw new TypeError('observation endpoint must not contain credentials')\n }\n const local = endpoint.hostname === 'localhost' || endpoint.hostname === '127.0.0.1'\n || endpoint.hostname === '[::1]' || endpoint.hostname === '::1'\n if (endpoint.protocol !== 'https:' && !(allowInsecureHttp && endpoint.protocol === 'http:' && local)) {\n throw new TypeError('observation endpoint must use https')\n }\n return endpoint\n}\n\nfunction headersOf(headers: Readonly<Record<string, string>> | undefined): Readonly<Record<string, string>> {\n const output = Object.create(null) as Record<string, string>\n for (const [name, value] of Object.entries(headers ?? {})) {\n const normalized = name.toLowerCase()\n if (FORBIDDEN_HEADER_NAMES.has(normalized)) throw new TypeError(`observation header ${name} is managed by the exporter`)\n if (typeof value !== 'string' || !/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name) || /[\\r\\n]/.test(value)) {\n throw new TypeError(`observation header ${name} is invalid`)\n }\n output[normalized] = value\n }\n return Object.freeze(output)\n}\n\nfunction resolveOptions(options: FetchObservationExporterOptions): ResolvedOptions {\n if (typeof options?.fetch !== 'function' && typeof globalThis.fetch !== 'function') {\n throw new TypeError('Fetch observation exporter requires fetch')\n }\n if (options.random !== undefined && typeof options.random !== 'function') {\n throw new TypeError('random must be a function')\n }\n if (options.delay !== undefined && typeof options.delay !== 'function') {\n throw new TypeError('delay must be a function')\n }\n if (options.now !== undefined && typeof options.now !== 'function') {\n throw new TypeError('now must be a function')\n }\n return Object.freeze({\n endpoint: endpointOf(options.endpoint, options.allowInsecureHttp ?? false),\n headers: headersOf(options.headers),\n fetch: options.fetch ?? globalThis.fetch,\n requestTimeoutMs: positiveSafeInteger(options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS, 'requestTimeoutMs'),\n maxAttempts: positiveSafeInteger(options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS, 'maxAttempts'),\n baseDelayMs: nonNegativeFinite(options.baseDelayMs ?? DEFAULT_BASE_DELAY_MS, 'baseDelayMs'),\n maxDelayMs: nonNegativeFinite(options.maxDelayMs ?? DEFAULT_MAX_DELAY_MS, 'maxDelayMs'),\n maxBatchEvents: positiveSafeInteger(options.maxBatchEvents ?? DEFAULT_MAX_BATCH_EVENTS, 'maxBatchEvents'),\n maxBatchBytes: positiveSafeInteger(options.maxBatchBytes ?? DEFAULT_MAX_BATCH_BYTES, 'maxBatchBytes'),\n maxAckBytes: positiveSafeInteger(options.maxAckBytes ?? DEFAULT_MAX_ACK_BYTES, 'maxAckBytes'),\n maxAckChunks: positiveSafeInteger(options.maxAckChunks ?? DEFAULT_MAX_ACK_CHUNKS, 'maxAckChunks'),\n random: options.random ?? Math.random,\n delay: options.delay ?? abortableDelay,\n now: options.now ?? Date.now,\n })\n}\n\nfunction retryableStatus(status: number): boolean {\n return RETRYABLE_STATUSES.has(status) || (status >= 500 && status <= 599)\n}\n\nfunction retryAfterMs(value: string | null, now: number): number | undefined {\n if (value === null) return undefined\n const trimmed = value.trim()\n if (/^\\d+(?:\\.\\d+)?$/.test(trimmed)) return Math.min(MAX_RETRY_AFTER_MS, Number(trimmed) * 1_000)\n const at = Date.parse(trimmed)\n if (!Number.isFinite(at)) return undefined\n return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, at - now))\n}\n\nfunction backoffMs(attempt: number, options: ResolvedOptions): number {\n const cap = Math.min(options.maxDelayMs, options.baseDelayMs * (2 ** Math.max(0, attempt - 1)))\n const random = options.random()\n const unit = Number.isFinite(random) ? Math.min(1, Math.max(0, random)) : 0\n return Math.floor(cap * unit)\n}\n\nfunction combinedSignal(external: AbortSignal, timeoutMs: number): { signal: AbortSignal; clear(): void } {\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(new DOMException('observation request timed out', 'TimeoutError')), timeoutMs)\n const abort = () => controller.abort(external.reason ?? new DOMException('observation export aborted', 'AbortError'))\n if (external.aborted) abort()\n else external.addEventListener('abort', abort, { once: true })\n return {\n signal: controller.signal,\n clear() { clearTimeout(timeout); external.removeEventListener('abort', abort) },\n }\n}\n\nfunction raceAbort<T>(pending: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) return Promise.reject(signal.reason ?? new Error('observation export aborted'))\n return new Promise<T>((resolve, reject) => {\n const abort = () => { cleanup(); reject(signal.reason ?? new Error('observation export aborted')) }\n const cleanup = () => signal.removeEventListener('abort', abort)\n signal.addEventListener('abort', abort, { once: true })\n void pending.then(\n value => { cleanup(); resolve(value) },\n error => { cleanup(); reject(error) },\n )\n })\n}\n\nasync function abortableDelay(milliseconds: number, signal: AbortSignal): Promise<void> {\n if (milliseconds <= 0) return\n await new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => { cleanup(); resolve() }, milliseconds)\n const abort = () => { cleanup(); reject(signal.reason ?? new Error('observation export aborted')) }\n const cleanup = () => { clearTimeout(timer); signal.removeEventListener('abort', abort) }\n if (signal.aborted) abort()\n else signal.addEventListener('abort', abort, { once: true })\n })\n}\n\nasync function cancelBody(response: Response): Promise<void> {\n if (response.body === null) return\n await waitForSettlement(response.body.cancel().catch(() => undefined), 1_000)\n}\n\nasync function boundedText(response: Response, options: ResolvedOptions, signal: AbortSignal): Promise<string> {\n const declared = Number(response.headers.get('content-length'))\n if (Number.isFinite(declared) && declared > options.maxAckBytes) {\n await cancelBody(response)\n throw new RangeError('observation acknowledgment exceeds its byte limit')\n }\n if (response.body === null) return ''\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n let output = ''\n let bytes = 0\n let chunks = 0\n try {\n while (true) {\n const next = await raceAbort(reader.read(), signal)\n if (next.done) return output + decoder.decode()\n if (next.value === undefined) continue\n bytes += next.value.byteLength\n chunks++\n if (bytes > options.maxAckBytes || chunks > options.maxAckChunks) {\n await waitForSettlement(reader.cancel().catch(() => undefined), 1_000)\n throw new RangeError('observation acknowledgment exceeds its resource limit')\n }\n output += decoder.decode(next.value, { stream: true })\n }\n } finally {\n reader.releaseLock()\n }\n}\n\nasync function validateNoRedirectResponse(response: Response, endpoint: URL): Promise<void> {\n const redirectStatus = response.status >= 300 && response.status < 400\n const opaqueRedirect = response.type === 'opaqueredirect'\n const responseUrlChanged = response.url.length > 0 && response.url !== endpoint.href\n if (response.redirected || redirectStatus || opaqueRedirect || responseUrlChanged) {\n await cancelBody(response)\n throw new ObservationProtocolError('observation exporter rejected a redirect before following it')\n }\n if (response.url.length > 0) {\n let responseOrigin: string\n try { responseOrigin = new URL(response.url).origin } catch {\n throw new ObservationProtocolError('observation response URL is invalid')\n }\n if (responseOrigin !== endpoint.origin) {\n throw new ObservationProtocolError('observation response origin does not match its endpoint')\n }\n }\n}\n\n/** A remote-acknowledged exporter using only Fetch and Web streams. */\nexport class FetchObservationExporter implements ObservationExporter {\n readonly id: string\n readonly supportedBoundaries: readonly ObservationBoundary[] = Object.freeze(['remote-acknowledged'])\n private readonly options: ResolvedOptions\n\n constructor(options: FetchObservationExporterOptions) {\n if (typeof options !== 'object' || options === null) {\n throw new TypeError('Fetch observation exporter options are required')\n }\n this.id = options.id ?? 'fetch'\n if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,63})$/.test(this.id)) {\n throw new TypeError('Fetch observation exporter id must be a safe 1-64 character identifier')\n }\n this.options = resolveOptions(options)\n }\n\n async export(batch: ObservationBatch, signal: AbortSignal): Promise<ExportAck> {\n const result = await sendBatch(this.options, batch.batchId, batch.events.length, batch, signal)\n return Object.freeze({ batchId: batch.batchId, ...result })\n }\n}\n\ninterface BatchSendResult {\n readonly accepted: boolean\n readonly retryable: boolean\n}\n\nasync function sendBatch(\n options: ResolvedOptions,\n batchId: string,\n itemCount: number,\n batch: unknown,\n signal: AbortSignal,\n): Promise<BatchSendResult> {\n if (itemCount > options.maxBatchEvents) return Object.freeze({ accepted: false, retryable: false })\n const body = JSON.stringify(batch)\n if (new TextEncoder().encode(body).byteLength > options.maxBatchBytes) {\n return Object.freeze({ accepted: false, retryable: false })\n }\n // Web IDL fetch rejects a property-call receiver such as `options.fetch(...)`\n // in browsers. Capture it as a standalone callable so native Window/Worker\n // fetch and injected implementations share the same invocation contract.\n const dispatch = options.fetch\n\n for (let attempt = 1; attempt <= options.maxAttempts; attempt++) {\n if (signal.aborted) throw signal.reason ?? new Error('observation export aborted')\n const request = combinedSignal(signal, options.requestTimeoutMs)\n let retryDelay: number | undefined\n try {\n const response = await raceAbort(Promise.resolve(dispatch(options.endpoint, {\n method: 'POST',\n headers: {\n ...options.headers,\n 'content-type': 'application/json',\n 'idempotency-key': batchId,\n },\n body,\n redirect: 'manual',\n signal: request.signal,\n })), request.signal)\n await validateNoRedirectResponse(response, options.endpoint)\n if (response.status === 204) {\n await cancelBody(response)\n return Object.freeze({ accepted: true, retryable: false })\n }\n if (response.status >= 200 && response.status < 300) {\n const raw = await boundedText(response, options, request.signal)\n let parsed: unknown\n try { parsed = JSON.parse(raw) } catch { parsed = undefined }\n const acceptedBatchId = typeof parsed === 'object' && parsed !== null\n ? Reflect.get(parsed, 'acceptedBatchId')\n : undefined\n return Object.freeze({\n accepted: acceptedBatchId === batchId,\n retryable: false,\n })\n }\n const retryable = retryableStatus(response.status)\n const retryAfter = retryAfterMs(response.headers.get('retry-after'), options.now())\n await cancelBody(response)\n if (!retryable || attempt === options.maxAttempts) {\n return Object.freeze({ accepted: false, retryable })\n }\n retryDelay = retryAfter ?? backoffMs(attempt, options)\n } catch (error) {\n if (signal.aborted) throw signal.reason ?? error\n if (error instanceof ObservationProtocolError || error instanceof RangeError) {\n return Object.freeze({ accepted: false, retryable: false })\n }\n if (attempt === options.maxAttempts) {\n return Object.freeze({ accepted: false, retryable: true })\n }\n retryDelay = backoffMs(attempt, options)\n } finally {\n request.clear()\n }\n await raceAbort(Promise.resolve(options.delay(retryDelay ?? 0, signal)), signal)\n }\n return Object.freeze({ accepted: false, retryable: true })\n}\n\n/** Recommended inert runtime exporter; transport begins only when core exports a batch. */\nexport function fetchObservationExporter(\n options: FetchObservationExporterOptions,\n): ObservationExporterPlugin {\n if (typeof options !== 'object' || options === null) {\n throw new TypeError('Fetch observation exporter options are required')\n }\n const id = options.id ?? 'fetch'\n if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,63})$/.test(id)) {\n throw new TypeError('Fetch observation exporter id must be a safe 1-64 character identifier')\n }\n const captured = resolveOptions(options)\n return defineObservationExporter({\n id,\n supportedBoundaries: ['remote-acknowledged'],\n async export(batch: ObservationDeliveryBatch, signal: AbortSignal) {\n const result = await sendBatch(\n captured,\n batch.id,\n batch.events.length + batch.runRecords.length,\n batch,\n signal,\n )\n return Object.freeze({\n batchId: batch.id,\n acceptedEventIds: result.accepted ? batch.events.map(event => event.eventId) : [],\n acceptedRunIds: result.accepted ? batch.runRecords.map(record => record.runId) : [],\n })\n },\n })\n}\n","import type { FlushResult, Observability } from '@alvin0/ai-agent-sdk-core/observability'\n\nexport type WaitUntil = (pending: Promise<unknown>) => void\n\n/** Start one flush and explicitly attach it to an Edge host's lifetime. */\nexport function flushObservabilityWithWaitUntil(\n observation: Pick<Observability, 'flush'>,\n waitUntil: WaitUntil,\n signal?: AbortSignal,\n): Promise<FlushResult> {\n if (typeof waitUntil !== 'function') throw new TypeError('waitUntil must be a function')\n const pending = observation.flush(signal)\n waitUntil(pending)\n return pending\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/fetch-transport.ts","../src/fetch-options.ts","../src/fetch-send.ts","../src/fetch-exporter.ts","../src/wait-until.ts"],"sourcesContent":["import { waitForSettlement } from '@alvin0/ai-agent-sdk-core'\nimport type { ResolvedOptions } from './fetch-options.ts'\nconst RETRYABLE_STATUSES = new Set([408, 425, 429])\nconst MAX_RETRY_AFTER_MS = 60_000\nexport class ObservationProtocolError extends Error {\n override readonly name = 'ObservationProtocolError'\n}\n\nexport function retryableStatus(status: number): boolean {\n return RETRYABLE_STATUSES.has(status) || (status >= 500 && status <= 599)\n}\n\nexport function retryAfterMs(value: string | null, now: number): number | undefined {\n if (value === null) return undefined\n const trimmed = value.trim()\n if (/^\\d+(?:\\.\\d+)?$/.test(trimmed)) return Math.min(MAX_RETRY_AFTER_MS, Number(trimmed) * 1_000)\n const at = Date.parse(trimmed)\n if (!Number.isFinite(at)) return undefined\n return Math.min(MAX_RETRY_AFTER_MS, Math.max(0, at - now))\n}\n\nexport function backoffMs(attempt: number, options: ResolvedOptions): number {\n const cap = Math.min(options.maxDelayMs, options.baseDelayMs * (2 ** Math.max(0, attempt - 1)))\n const random = options.random()\n const unit = Number.isFinite(random) ? Math.min(1, Math.max(0, random)) : 0\n return Math.floor(cap * unit)\n}\n\nexport function combinedSignal(external: AbortSignal, timeoutMs: number): { signal: AbortSignal; clear(): void } {\n const controller = new AbortController()\n const timeout = setTimeout(() =>\n controller.abort(new DOMException('observation request timed out', 'TimeoutError')), timeoutMs)\n const abort = () => controller.abort(external.reason ?? new DOMException('observation export aborted', 'AbortError'))\n if (external.aborted) abort()\n else external.addEventListener('abort', abort, { once: true })\n return {\n signal: controller.signal,\n clear() { clearTimeout(timeout); external.removeEventListener('abort', abort) },\n }\n}\n\nexport function raceAbort<T>(pending: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) return Promise.reject(signal.reason ?? new Error('observation export aborted'))\n return new Promise<T>((resolve, reject) => {\n const abort = () => { cleanup(); reject(signal.reason ?? new Error('observation export aborted')) }\n const cleanup = () => signal.removeEventListener('abort', abort)\n signal.addEventListener('abort', abort, { once: true })\n void pending.then(\n value => { cleanup(); resolve(value) },\n error => { cleanup(); reject(error) },\n )\n })\n}\n\nexport async function abortableDelay(milliseconds: number, signal: AbortSignal): Promise<void> {\n if (milliseconds <= 0) return\n await new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => { cleanup(); resolve() }, milliseconds)\n const abort = () => { cleanup(); reject(signal.reason ?? new Error('observation export aborted')) }\n const cleanup = () => { clearTimeout(timer); signal.removeEventListener('abort', abort) }\n if (signal.aborted) abort()\n else signal.addEventListener('abort', abort, { once: true })\n })\n}\n\nexport async function cancelBody(response: Response): Promise<void> {\n if (response.body === null) return\n await waitForSettlement(response.body.cancel().catch(() => undefined), 1_000)\n}\n\nexport async function boundedText(response: Response, options: ResolvedOptions, signal: AbortSignal): Promise<string> {\n const declared = Number(response.headers.get('content-length'))\n if (Number.isFinite(declared) && declared > options.maxAckBytes) {\n await cancelBody(response)\n throw new RangeError('observation acknowledgment exceeds its byte limit')\n }\n if (response.body === null) return ''\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n let output = ''\n let bytes = 0\n let chunks = 0\n try {\n while (true) {\n const next = await raceAbort(reader.read(), signal)\n if (next.done) return output + decoder.decode()\n if (next.value === undefined) continue\n bytes += next.value.byteLength\n chunks++\n if (bytes > options.maxAckBytes || chunks > options.maxAckChunks) {\n await waitForSettlement(reader.cancel().catch(() => undefined), 1_000)\n throw new RangeError('observation acknowledgment exceeds its resource limit')\n }\n output += decoder.decode(next.value, { stream: true })\n }\n } finally {\n reader.releaseLock()\n }\n}\n\nexport async function validateNoRedirectResponse(response: Response, endpoint: URL): Promise<void> {\n const redirectStatus = response.status >= 300 && response.status < 400\n const opaqueRedirect = response.type === 'opaqueredirect'\n const responseUrlChanged = response.url.length > 0 && response.url !== endpoint.href\n if (response.redirected || redirectStatus || opaqueRedirect || responseUrlChanged) {\n await cancelBody(response)\n throw new ObservationProtocolError('observation exporter rejected a redirect before following it')\n }\n if (response.url.length > 0) {\n let responseOrigin: string\n try { responseOrigin = new URL(response.url).origin } catch {\n throw new ObservationProtocolError('observation response URL is invalid')\n }\n if (responseOrigin !== endpoint.origin) {\n throw new ObservationProtocolError('observation response origin does not match its endpoint')\n }\n }\n}\n\n","import { abortableDelay } from './fetch-transport.ts'\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 10_000\nconst DEFAULT_MAX_ATTEMPTS = 8\nconst DEFAULT_BASE_DELAY_MS = 250\nconst DEFAULT_MAX_DELAY_MS = 30_000\nconst DEFAULT_MAX_BATCH_EVENTS = 256\nconst DEFAULT_MAX_BATCH_BYTES = 512 * 1024\nconst DEFAULT_MAX_ACK_BYTES = 64 * 1024\nconst DEFAULT_MAX_ACK_CHUNKS = 1_000\nconst FORBIDDEN_HEADER_NAMES = new Set(['content-length', 'content-type', 'host', 'idempotency-key'])\n\nexport interface FetchObservationExporterOptions {\n readonly id?: string\n readonly endpoint: string | URL\n readonly headers?: Readonly<Record<string, string>>\n readonly fetch?: typeof fetch\n /** Permit cleartext only for localhost/loopback test endpoints. */\n readonly allowInsecureHttp?: boolean\n readonly requestTimeoutMs?: number\n readonly maxAttempts?: number\n readonly baseDelayMs?: number\n readonly maxDelayMs?: number\n readonly maxBatchEvents?: number\n readonly maxBatchBytes?: number\n readonly maxAckBytes?: number\n readonly maxAckChunks?: number\n /** Deterministic injection for tests; defaults to `Math.random`. */\n readonly random?: () => number\n /** Timer injection for tests; defaults to an abortable Web timer. */\n readonly delay?: (milliseconds: number, signal: AbortSignal) => Promise<void>\n /** Clock injection used only for HTTP-date `Retry-After`. */\n readonly now?: () => number\n}\n\nexport interface ResolvedOptions {\n readonly endpoint: URL\n readonly headers: Readonly<Record<string, string>>\n readonly fetch: typeof fetch\n readonly requestTimeoutMs: number\n readonly maxAttempts: number\n readonly baseDelayMs: number\n readonly maxDelayMs: number\n readonly maxBatchEvents: number\n readonly maxBatchBytes: number\n readonly maxAckBytes: number\n readonly maxAckChunks: number\n readonly random: () => number\n readonly delay: (milliseconds: number, signal: AbortSignal) => Promise<void>\n readonly now: () => number\n}\n\nfunction positiveSafeInteger(value: number, field: string): number {\n if (!Number.isSafeInteger(value) || value < 1) throw new RangeError(`${field} must be a positive safe integer`)\n return value\n}\n\nfunction nonNegativeFinite(value: number, field: string): number {\n if (!Number.isFinite(value) || value < 0) throw new RangeError(`${field} must be a non-negative finite number`)\n return value\n}\n\nfunction endpointOf(value: string | URL, allowInsecureHttp: boolean): URL {\n const endpoint = new URL(value)\n if (endpoint.username.length > 0 || endpoint.password.length > 0) {\n throw new TypeError('observation endpoint must not contain credentials')\n }\n const local = endpoint.hostname === 'localhost' || endpoint.hostname === '127.0.0.1'\n || endpoint.hostname === '[::1]' || endpoint.hostname === '::1'\n if (endpoint.protocol !== 'https:' && !(allowInsecureHttp && endpoint.protocol === 'http:' && local)) {\n throw new TypeError('observation endpoint must use https')\n }\n return endpoint\n}\n\nfunction headersOf(headers: Readonly<Record<string, string>> | undefined): Readonly<Record<string, string>> {\n const output = Object.create(null) as Record<string, string>\n for (const [name, value] of Object.entries(headers ?? {})) {\n const normalized = name.toLowerCase()\n if (FORBIDDEN_HEADER_NAMES.has(normalized)) {\n throw new TypeError(`observation header ${name} is managed by the exporter`)\n }\n if (typeof value !== 'string' || !/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name) || /[\\r\\n]/.test(value)) {\n throw new TypeError(`observation header ${name} is invalid`)\n }\n output[normalized] = value\n }\n return Object.freeze(output)\n}\n\nexport function resolveOptions(options: FetchObservationExporterOptions): ResolvedOptions {\n validateInjectedFunctions(options)\n return Object.freeze({\n endpoint: endpointOf(options.endpoint, options.allowInsecureHttp ?? false),\n headers: headersOf(options.headers),\n fetch: options.fetch ?? globalThis.fetch,\n ...retryOptions(options),\n ...resourceLimits(options),\n random: options.random ?? Math.random,\n delay: options.delay ?? abortableDelay,\n now: options.now ?? Date.now,\n })\n}\n\n\nfunction validateInjectedFunctions(options: FetchObservationExporterOptions) {\n if (typeof options?.fetch !== 'function' && typeof globalThis.fetch !== 'function') {\n throw new TypeError('Fetch observation exporter requires fetch')\n }\n if (options.random !== undefined && typeof options.random !== 'function') {\n throw new TypeError('random must be a function')\n }\n if (options.delay !== undefined && typeof options.delay !== 'function') {\n throw new TypeError('delay must be a function')\n }\n if (options.now !== undefined && typeof options.now !== 'function') {\n throw new TypeError('now must be a function')\n }\n}\n\nfunction retryOptions(options: FetchObservationExporterOptions) {\n return {\n requestTimeoutMs: positiveSafeInteger(options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS, 'requestTimeoutMs'),\n maxAttempts: positiveSafeInteger(options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS, 'maxAttempts'),\n baseDelayMs: nonNegativeFinite(options.baseDelayMs ?? DEFAULT_BASE_DELAY_MS, 'baseDelayMs'),\n maxDelayMs: nonNegativeFinite(options.maxDelayMs ?? DEFAULT_MAX_DELAY_MS, 'maxDelayMs'),\n }\n}\n\nfunction resourceLimits(options: FetchObservationExporterOptions) {\n return {\n maxBatchEvents: positiveSafeInteger(options.maxBatchEvents ?? DEFAULT_MAX_BATCH_EVENTS, 'maxBatchEvents'),\n maxBatchBytes: positiveSafeInteger(options.maxBatchBytes ?? DEFAULT_MAX_BATCH_BYTES, 'maxBatchBytes'),\n maxAckBytes: positiveSafeInteger(options.maxAckBytes ?? DEFAULT_MAX_ACK_BYTES, 'maxAckBytes'),\n maxAckChunks: positiveSafeInteger(options.maxAckChunks ?? DEFAULT_MAX_ACK_CHUNKS, 'maxAckChunks'),\n }\n}\n","import type { ResolvedOptions } from './fetch-options.ts'\nimport { retryableStatus, retryAfterMs, backoffMs, combinedSignal, raceAbort, cancelBody,\n boundedText, validateNoRedirectResponse, ObservationProtocolError } from './fetch-transport.ts'\n\ninterface BatchSendResult { readonly accepted: boolean; readonly retryable: boolean }\ninterface Batch { id: string; count: number; value: unknown }\ntype AttemptResult = { result: BatchSendResult } | { retryDelay: number }\n\nasync function successfulResponse(response: Response, options: ResolvedOptions, batchId: string, signal: AbortSignal)\n : Promise<BatchSendResult> {\n if (response.status === 204) {\n await cancelBody(response)\n return Object.freeze({ accepted: true, retryable: false })\n }\n const raw = await boundedText(response, options, signal)\n let parsed: unknown\n try { parsed = JSON.parse(raw) } catch { parsed = undefined }\n const acceptedBatchId = typeof parsed === 'object' && parsed !== null\n ? Reflect.get(parsed, 'acceptedBatchId') : undefined\n return Object.freeze({ accepted: acceptedBatchId === batchId, retryable: false })\n}\n\nasync function responseResult(response: Response, options: ResolvedOptions,\n batchId: string, control: { attempt: number; signal: AbortSignal }): Promise<AttemptResult> {\n await validateNoRedirectResponse(response, options.endpoint)\n if (response.status >= 200 && response.status < 300) {\n return { result: await successfulResponse(response, options, batchId, control.signal) }\n }\n const retryable = retryableStatus(response.status)\n const retryAfter = retryAfterMs(response.headers.get('retry-after'), options.now())\n await cancelBody(response)\n if (!retryable || control.attempt === options.maxAttempts) {\n return { result: Object.freeze({ accepted: false, retryable }) }\n }\n return { retryDelay: retryAfter ?? backoffMs(control.attempt, options) }\n}\n\nfunction failedAttempt(error: unknown, options: ResolvedOptions, attempt: number, signal: AbortSignal): AttemptResult {\n if (signal.aborted) throw signal.reason ?? error\n if (error instanceof ObservationProtocolError || error instanceof RangeError) {\n return { result: Object.freeze({ accepted: false, retryable: false }) }\n }\n if (attempt === options.maxAttempts) return { result: Object.freeze({ accepted: false, retryable: true }) }\n return { retryDelay: backoffMs(attempt, options) }\n}\n\nasync function sendAttempt(options: ResolvedOptions, batchId: string, body: string,\n control: { attempt: number; signal: AbortSignal }): Promise<AttemptResult> {\n const request = combinedSignal(control.signal, options.requestTimeoutMs)\n // Native Window/Worker fetch must be invoked as a standalone callable.\n const dispatch = options.fetch\n try {\n const response = await raceAbort(Promise.resolve(dispatch(options.endpoint, {\n method: 'POST', headers: { ...options.headers, 'content-type': 'application/json', 'idempotency-key': batchId },\n body, redirect: 'manual', signal: request.signal,\n })), request.signal)\n return await responseResult(response, options, batchId, { attempt: control.attempt, signal: request.signal })\n } catch (error) {\n return failedAttempt(error, options, control.attempt, control.signal)\n } finally { request.clear() }\n}\n\nexport async function sendBatch(options: ResolvedOptions, batch: Batch, signal: AbortSignal): Promise<BatchSendResult> {\n if (batch.count > options.maxBatchEvents) return Object.freeze({ accepted: false, retryable: false })\n const body = JSON.stringify(batch.value)\n if (new TextEncoder().encode(body).byteLength > options.maxBatchBytes) {\n return Object.freeze({ accepted: false, retryable: false })\n }\n for (let attempt = 1; attempt <= options.maxAttempts; attempt++) {\n if (signal.aborted) throw signal.reason ?? new Error('observation export aborted')\n const outcome = await sendAttempt(options, batch.id, body, { attempt, signal })\n if ('result' in outcome) return outcome.result\n await raceAbort(Promise.resolve(options.delay(outcome.retryDelay, signal)), signal)\n }\n return Object.freeze({ accepted: false, retryable: true })\n}\n","import { type ObservationBoundary } from '@alvin0/ai-agent-sdk-core'\nimport type {\n ExportAck,\n ObservationBatch,\n ObservationExporter,\n} from '@alvin0/ai-agent-sdk-core/observability'\nimport {\n defineObservationExporter,\n type ObservationDeliveryBatch,\n type ObservationExporterPlugin,\n} from '@alvin0/ai-agent-sdk-core/observability'\n\nimport { resolveOptions, type ResolvedOptions, type FetchObservationExporterOptions } from './fetch-options.ts'\nexport type { FetchObservationExporterOptions } from './fetch-options.ts'\nimport { sendBatch } from './fetch-send.ts'\n\n/** A remote-acknowledged exporter using only Fetch and Web streams. */\nexport class FetchObservationExporter implements ObservationExporter {\n readonly id: string\n readonly supportedBoundaries: readonly ObservationBoundary[] = Object.freeze(['remote-acknowledged'])\n private readonly options: ResolvedOptions\n\n constructor(options: FetchObservationExporterOptions) {\n if (typeof options !== 'object' || options === null) {\n throw new TypeError('Fetch observation exporter options are required')\n }\n this.id = options.id ?? 'fetch'\n if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,63})$/.test(this.id)) {\n throw new TypeError('Fetch observation exporter id must be a safe 1-64 character identifier')\n }\n this.options = resolveOptions(options)\n }\n\n async export(batch: ObservationBatch, signal: AbortSignal): Promise<ExportAck> {\n const result = await sendBatch(this.options,\n { id: batch.batchId, count: batch.events.length, value: batch }, signal)\n return Object.freeze({ batchId: batch.batchId, ...result })\n }\n}\n\n/** Recommended inert runtime exporter; transport begins only when core exports a batch. */\nexport function fetchObservationExporter(\n options: FetchObservationExporterOptions,\n): ObservationExporterPlugin {\n if (typeof options !== 'object' || options === null) {\n throw new TypeError('Fetch observation exporter options are required')\n }\n const id = options.id ?? 'fetch'\n if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,63})$/.test(id)) {\n throw new TypeError('Fetch observation exporter id must be a safe 1-64 character identifier')\n }\n const captured = resolveOptions(options)\n return defineObservationExporter({\n id,\n supportedBoundaries: ['remote-acknowledged'],\n async export(batch: ObservationDeliveryBatch, signal: AbortSignal) {\n const result = await sendBatch(\n captured,\n { id: batch.id, count: batch.events.length + batch.runRecords.length, value: batch },\n signal,\n )\n return Object.freeze({\n batchId: batch.id,\n acceptedEventIds: result.accepted ? batch.events.map(event => event.eventId) : [],\n acceptedRunIds: result.accepted ? batch.runRecords.map(record => record.runId) : [],\n })\n },\n })\n}\n","import type { FlushResult, Observability } from '@alvin0/ai-agent-sdk-core/observability'\n\nexport type WaitUntil = (pending: Promise<unknown>) => void\n\n/** Start one flush and explicitly attach it to an Edge host's lifetime. */\nexport function flushObservabilityWithWaitUntil(\n observation: Pick<Observability, 'flush'>,\n waitUntil: WaitUntil,\n signal?: AbortSignal,\n): Promise<FlushResult> {\n if (typeof waitUntil !== 'function') throw new TypeError('waitUntil must be a function')\n const pending = observation.flush(signal)\n waitUntil(pending)\n return pending\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "name": "alvin0 - chaulamdinhai",
5
5
  "email": "chaulamdinhai@gmail.com"
6
6
  },
7
- "version": "0.1.10",
7
+ "version": "0.1.11",
8
8
  "description": "Acknowledged HTTPS observation batch exporter for Edge and Web runtimes",
9
9
  "license": "MIT",
10
10
  "repository": {
@@ -38,10 +38,10 @@
38
38
  "provenance": true
39
39
  },
40
40
  "peerDependencies": {
41
- "@alvin0/ai-agent-sdk-core": "^0.1.10"
41
+ "@alvin0/ai-agent-sdk-core": "^0.1.11"
42
42
  },
43
43
  "devDependencies": {
44
- "@alvin0/ai-agent-sdk-core": "^0.1.10",
44
+ "@alvin0/ai-agent-sdk-core": "^0.1.11",
45
45
  "@arethetypeswrong/cli": "0.18.5",
46
46
  "playwright": "1.62.1",
47
47
  "publint": "0.3.24",