abxbus 2.4.15 → 2.4.18

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 (50) hide show
  1. package/dist/cjs/event_bus.js +1 -1
  2. package/dist/cjs/event_bus.js.map +2 -2
  3. package/dist/cjs/event_handler.d.ts +1 -0
  4. package/dist/cjs/event_handler.js +14 -1
  5. package/dist/cjs/event_handler.js.map +2 -2
  6. package/dist/cjs/index.d.ts +2 -0
  7. package/dist/cjs/index.js +2 -0
  8. package/dist/cjs/index.js.map +2 -2
  9. package/dist/cjs/middleware_otel_tracing.d.ts +28 -0
  10. package/dist/cjs/middleware_otel_tracing.js +189 -0
  11. package/dist/cjs/middleware_otel_tracing.js.map +7 -0
  12. package/dist/cjs/retry.js +39 -0
  13. package/dist/cjs/retry.js.map +2 -2
  14. package/dist/esm/event_bus.js +1 -1
  15. package/dist/esm/event_bus.js.map +2 -2
  16. package/dist/esm/event_handler.js +14 -1
  17. package/dist/esm/event_handler.js.map +2 -2
  18. package/dist/esm/index.js +2 -0
  19. package/dist/esm/index.js.map +2 -2
  20. package/dist/esm/middleware_otel_tracing.js +169 -0
  21. package/dist/esm/middleware_otel_tracing.js.map +7 -0
  22. package/dist/esm/retry.js +39 -0
  23. package/dist/esm/retry.js.map +2 -2
  24. package/dist/types/event_handler.d.ts +1 -0
  25. package/dist/types/index.d.ts +2 -0
  26. package/dist/types/middleware_otel_tracing.d.ts +28 -0
  27. package/package.json +6 -1
  28. package/src/async_context.ts +70 -0
  29. package/src/base_event.ts +1201 -0
  30. package/src/bridge_jsonl.ts +174 -0
  31. package/src/bridge_nats.ts +104 -0
  32. package/src/bridge_postgres.ts +277 -0
  33. package/src/bridge_redis.ts +194 -0
  34. package/src/bridge_sqlite.ts +289 -0
  35. package/src/bridges.ts +376 -0
  36. package/src/event_bus.ts +1263 -0
  37. package/src/event_handler.ts +379 -0
  38. package/src/event_history.ts +247 -0
  39. package/src/event_result.ts +483 -0
  40. package/src/events_suck.ts +96 -0
  41. package/src/helpers.ts +65 -0
  42. package/src/index.ts +37 -0
  43. package/src/lock_manager.ts +401 -0
  44. package/src/logging.ts +261 -0
  45. package/src/middleware_otel_tracing.ts +201 -0
  46. package/src/middlewares.ts +16 -0
  47. package/src/optional_deps.ts +52 -0
  48. package/src/retry.ts +578 -0
  49. package/src/timing.ts +52 -0
  50. package/src/types.ts +132 -0
@@ -0,0 +1,189 @@
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 middleware_otel_tracing_exports = {};
20
+ __export(middleware_otel_tracing_exports, {
21
+ OtelTracingMiddleware: () => OtelTracingMiddleware
22
+ });
23
+ module.exports = __toCommonJS(middleware_otel_tracing_exports);
24
+ var import_api = require("@opentelemetry/api");
25
+ class OtelTracingMiddleware {
26
+ tracer;
27
+ trace_api;
28
+ event_spans = /* @__PURE__ */ new Map();
29
+ event_contexts = /* @__PURE__ */ new Map();
30
+ handler_spans = /* @__PURE__ */ new Map();
31
+ handler_contexts = /* @__PURE__ */ new Map();
32
+ constructor(options = {}) {
33
+ this.trace_api = options.trace_api ?? import_api.trace;
34
+ this.tracer = options.tracer ?? this.trace_api.getTracer("abxbus");
35
+ }
36
+ onEventChange(eventbus, event, status) {
37
+ if (status === "started") {
38
+ this.startEventSpan(eventbus, event);
39
+ return;
40
+ }
41
+ if (status === "completed") {
42
+ this.completeEventSpan(eventbus, event);
43
+ }
44
+ }
45
+ onEventResultChange(eventbus, event, event_result, status) {
46
+ if (status === "started") {
47
+ this.startHandlerSpan(eventbus, event, event_result);
48
+ return;
49
+ }
50
+ if (status === "completed") {
51
+ this.completeHandlerSpan(event_result);
52
+ }
53
+ }
54
+ startEventSpan(eventbus, event) {
55
+ const existing = this.event_spans.get(event.event_id);
56
+ if (existing) {
57
+ return existing;
58
+ }
59
+ const parent_context = this.parentContextForEvent(event) ?? import_api.ROOT_CONTEXT;
60
+ const span = this.tracer.startSpan(
61
+ `abxbus.event ${event.event_type}`,
62
+ {
63
+ attributes: compactAttributes({
64
+ "abxbus.bus.id": eventbus.id,
65
+ "abxbus.bus.name": eventbus.name,
66
+ "abxbus.event.id": event.event_id,
67
+ "abxbus.event.type": event.event_type,
68
+ "abxbus.event.version": event.event_version,
69
+ "abxbus.event.parent_id": event.event_parent_id,
70
+ "abxbus.event.emitted_by_handler_id": event.event_emitted_by_handler_id,
71
+ "abxbus.event.path": event.event_path.join(" ")
72
+ }),
73
+ startTime: dateFromIso(event.event_started_at)
74
+ },
75
+ parent_context
76
+ );
77
+ const span_context = this.trace_api.setSpan(parent_context, span);
78
+ this.event_spans.set(event.event_id, span);
79
+ this.event_contexts.set(event.event_id, span_context);
80
+ return span;
81
+ }
82
+ completeEventSpan(eventbus, event) {
83
+ const span = this.event_spans.get(event.event_id) ?? this.startEventSpan(eventbus, event);
84
+ if (event.event_errors.length > 0) {
85
+ recordSpanError(span, event.event_errors[0]);
86
+ } else {
87
+ span.setStatus({ code: import_api.SpanStatusCode.OK });
88
+ }
89
+ span.setAttributes(
90
+ compactAttributes({
91
+ "abxbus.event.status": event.event_status,
92
+ "abxbus.event.result_count": event.event_results.size,
93
+ "abxbus.event.error_count": event.event_errors.length,
94
+ "abxbus.event.child_count": event.event_children.length
95
+ })
96
+ );
97
+ span.end(dateFromIso(event.event_completed_at));
98
+ this.event_spans.delete(event.event_id);
99
+ this.event_contexts.delete(event.event_id);
100
+ }
101
+ startHandlerSpan(eventbus, event, event_result) {
102
+ const existing = this.handler_spans.get(event_result.id);
103
+ if (existing) {
104
+ return existing;
105
+ }
106
+ const parent_context = this.event_contexts.get(event.event_id) ?? this.trace_api.setSpan(import_api.ROOT_CONTEXT, this.startEventSpan(eventbus, event));
107
+ const span = this.tracer.startSpan(
108
+ `abxbus.handler ${event.event_type} ${event_result.handler_name}`,
109
+ {
110
+ attributes: compactAttributes({
111
+ "abxbus.bus.id": eventbus.id,
112
+ "abxbus.bus.name": eventbus.name,
113
+ "abxbus.event.id": event.event_id,
114
+ "abxbus.event.type": event.event_type,
115
+ "abxbus.handler.id": event_result.handler_id,
116
+ "abxbus.handler.name": event_result.handler_name,
117
+ "abxbus.handler.file_path": event_result.handler_file_path,
118
+ "abxbus.handler.event_pattern": event_result.handler.event_pattern,
119
+ "abxbus.event_result.id": event_result.id
120
+ }),
121
+ startTime: dateFromIso(event_result.started_at)
122
+ },
123
+ parent_context
124
+ );
125
+ const span_context = this.trace_api.setSpan(parent_context, span);
126
+ this.handler_spans.set(event_result.id, span);
127
+ this.handler_contexts.set(handlerSpanKey(event_result.event_id, event_result.handler_id), span_context);
128
+ return span;
129
+ }
130
+ completeHandlerSpan(event_result) {
131
+ const span = this.handler_spans.get(event_result.id);
132
+ if (!span) {
133
+ return;
134
+ }
135
+ if (event_result.error !== void 0) {
136
+ recordSpanError(span, event_result.error);
137
+ } else {
138
+ span.setStatus({ code: import_api.SpanStatusCode.OK });
139
+ }
140
+ span.setAttributes(
141
+ compactAttributes({
142
+ "abxbus.event_result.status": event_result.status,
143
+ "abxbus.handler.child_count": event_result.event_children.length
144
+ })
145
+ );
146
+ span.end(dateFromIso(event_result.completed_at));
147
+ this.handler_spans.delete(event_result.id);
148
+ this.handler_contexts.delete(handlerSpanKey(event_result.event_id, event_result.handler_id));
149
+ }
150
+ parentContextForEvent(event) {
151
+ if (event.event_parent_id && event.event_emitted_by_handler_id) {
152
+ const handler_context = this.handler_contexts.get(handlerSpanKey(event.event_parent_id, event.event_emitted_by_handler_id));
153
+ if (handler_context) {
154
+ return handler_context;
155
+ }
156
+ }
157
+ return event.event_parent_id ? this.event_contexts.get(event.event_parent_id) : void 0;
158
+ }
159
+ }
160
+ function handlerSpanKey(event_id, handler_id) {
161
+ return `${event_id}:${handler_id}`;
162
+ }
163
+ function dateFromIso(value) {
164
+ if (value == null) {
165
+ return void 0;
166
+ }
167
+ const date = new Date(value);
168
+ return Number.isNaN(date.getTime()) ? void 0 : date;
169
+ }
170
+ function compactAttributes(attributes) {
171
+ const compacted = {};
172
+ for (const [key, value] of Object.entries(attributes)) {
173
+ if (value !== null && value !== void 0) {
174
+ compacted[key] = value;
175
+ }
176
+ }
177
+ return compacted;
178
+ }
179
+ function recordSpanError(span, error) {
180
+ if (error instanceof Error) {
181
+ span.recordException(error);
182
+ span.setStatus({ code: import_api.SpanStatusCode.ERROR, message: error.message });
183
+ return;
184
+ }
185
+ const message = typeof error === "string" ? error : "Unknown abxbus handler error";
186
+ span.recordException(message);
187
+ span.setStatus({ code: import_api.SpanStatusCode.ERROR, message });
188
+ }
189
+ //# sourceMappingURL=middleware_otel_tracing.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/middleware_otel_tracing.ts"],
4
+ "sourcesContent": ["import { ROOT_CONTEXT, SpanStatusCode, trace, type Context, type Span, type Tracer } from '@opentelemetry/api'\n\nimport type { BaseEvent } from './base_event.js'\nimport type { EventBus } from './event_bus.js'\nimport type { EventResult } from './event_result.js'\nimport type { EventBusMiddleware } from './middlewares.js'\nimport type { EventStatus } from './types.js'\n\ntype OpenTelemetryTraceApi = Pick<typeof trace, 'getTracer' | 'setSpan'>\n\nexport type OtelTracingMiddlewareOptions = {\n tracer?: Tracer\n trace_api?: OpenTelemetryTraceApi\n}\n\nexport class OtelTracingMiddleware implements EventBusMiddleware {\n private readonly tracer: Tracer\n private readonly trace_api: OpenTelemetryTraceApi\n private readonly event_spans = new Map<string, Span>()\n private readonly event_contexts = new Map<string, Context>()\n private readonly handler_spans = new Map<string, Span>()\n private readonly handler_contexts = new Map<string, Context>()\n\n constructor(options: OtelTracingMiddlewareOptions = {}) {\n this.trace_api = options.trace_api ?? trace\n this.tracer = options.tracer ?? this.trace_api.getTracer('abxbus')\n }\n\n onEventChange(eventbus: EventBus, event: BaseEvent, status: EventStatus): void {\n if (status === 'started') {\n this.startEventSpan(eventbus, event)\n return\n }\n\n if (status === 'completed') {\n this.completeEventSpan(eventbus, event)\n }\n }\n\n onEventResultChange(eventbus: EventBus, event: BaseEvent, event_result: EventResult, status: EventStatus): void {\n if (status === 'started') {\n this.startHandlerSpan(eventbus, event, event_result)\n return\n }\n\n if (status === 'completed') {\n this.completeHandlerSpan(event_result)\n }\n }\n\n private startEventSpan(eventbus: EventBus, event: BaseEvent): Span {\n const existing = this.event_spans.get(event.event_id)\n if (existing) {\n return existing\n }\n\n const parent_context = this.parentContextForEvent(event) ?? ROOT_CONTEXT\n const span = this.tracer.startSpan(\n `abxbus.event ${event.event_type}`,\n {\n attributes: compactAttributes({\n 'abxbus.bus.id': eventbus.id,\n 'abxbus.bus.name': eventbus.name,\n 'abxbus.event.id': event.event_id,\n 'abxbus.event.type': event.event_type,\n 'abxbus.event.version': event.event_version,\n 'abxbus.event.parent_id': event.event_parent_id,\n 'abxbus.event.emitted_by_handler_id': event.event_emitted_by_handler_id,\n 'abxbus.event.path': event.event_path.join(' '),\n }),\n startTime: dateFromIso(event.event_started_at),\n },\n parent_context\n )\n const span_context = this.trace_api.setSpan(parent_context, span)\n this.event_spans.set(event.event_id, span)\n this.event_contexts.set(event.event_id, span_context)\n return span\n }\n\n private completeEventSpan(eventbus: EventBus, event: BaseEvent): void {\n const span = this.event_spans.get(event.event_id) ?? this.startEventSpan(eventbus, event)\n if (event.event_errors.length > 0) {\n recordSpanError(span, event.event_errors[0])\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n span.setAttributes(\n compactAttributes({\n 'abxbus.event.status': event.event_status,\n 'abxbus.event.result_count': event.event_results.size,\n 'abxbus.event.error_count': event.event_errors.length,\n 'abxbus.event.child_count': event.event_children.length,\n })\n )\n span.end(dateFromIso(event.event_completed_at))\n this.event_spans.delete(event.event_id)\n this.event_contexts.delete(event.event_id)\n }\n\n private startHandlerSpan(eventbus: EventBus, event: BaseEvent, event_result: EventResult): Span {\n const existing = this.handler_spans.get(event_result.id)\n if (existing) {\n return existing\n }\n\n const parent_context =\n this.event_contexts.get(event.event_id) ?? this.trace_api.setSpan(ROOT_CONTEXT, this.startEventSpan(eventbus, event))\n const span = this.tracer.startSpan(\n `abxbus.handler ${event.event_type} ${event_result.handler_name}`,\n {\n attributes: compactAttributes({\n 'abxbus.bus.id': eventbus.id,\n 'abxbus.bus.name': eventbus.name,\n 'abxbus.event.id': event.event_id,\n 'abxbus.event.type': event.event_type,\n 'abxbus.handler.id': event_result.handler_id,\n 'abxbus.handler.name': event_result.handler_name,\n 'abxbus.handler.file_path': event_result.handler_file_path,\n 'abxbus.handler.event_pattern': event_result.handler.event_pattern,\n 'abxbus.event_result.id': event_result.id,\n }),\n startTime: dateFromIso(event_result.started_at),\n },\n parent_context\n )\n const span_context = this.trace_api.setSpan(parent_context, span)\n this.handler_spans.set(event_result.id, span)\n this.handler_contexts.set(handlerSpanKey(event_result.event_id, event_result.handler_id), span_context)\n return span\n }\n\n private completeHandlerSpan(event_result: EventResult): void {\n const span = this.handler_spans.get(event_result.id)\n if (!span) {\n return\n }\n\n if (event_result.error !== undefined) {\n recordSpanError(span, event_result.error)\n } else {\n span.setStatus({ code: SpanStatusCode.OK })\n }\n span.setAttributes(\n compactAttributes({\n 'abxbus.event_result.status': event_result.status,\n 'abxbus.handler.child_count': event_result.event_children.length,\n })\n )\n span.end(dateFromIso(event_result.completed_at))\n this.handler_spans.delete(event_result.id)\n this.handler_contexts.delete(handlerSpanKey(event_result.event_id, event_result.handler_id))\n }\n\n private parentContextForEvent(event: BaseEvent): Context | undefined {\n if (event.event_parent_id && event.event_emitted_by_handler_id) {\n const handler_context = this.handler_contexts.get(handlerSpanKey(event.event_parent_id, event.event_emitted_by_handler_id))\n if (handler_context) {\n return handler_context\n }\n }\n\n return event.event_parent_id ? this.event_contexts.get(event.event_parent_id) : undefined\n }\n}\n\nfunction handlerSpanKey(event_id: string, handler_id: string): string {\n return `${event_id}:${handler_id}`\n}\n\nfunction dateFromIso(value: string | null | undefined): Date | undefined {\n if (value == null) {\n return undefined\n }\n const date = new Date(value)\n return Number.isNaN(date.getTime()) ? undefined : date\n}\n\nfunction compactAttributes(\n attributes: Record<string, string | number | boolean | null | undefined>\n): Record<string, string | number | boolean> {\n const compacted: Record<string, string | number | boolean> = {}\n for (const [key, value] of Object.entries(attributes)) {\n if (value !== null && value !== undefined) {\n compacted[key] = value\n }\n }\n return compacted\n}\n\nfunction recordSpanError(span: Span, error: unknown): void {\n if (error instanceof Error) {\n span.recordException(error)\n span.setStatus({ code: SpanStatusCode.ERROR, message: error.message })\n return\n }\n\n const message = typeof error === 'string' ? error : 'Unknown abxbus handler error'\n span.recordException(message)\n span.setStatus({ code: SpanStatusCode.ERROR, message })\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/dist/cjs/retry.js CHANGED
@@ -228,9 +228,48 @@ function retry(options = {}) {
228
228
  }
229
229
  }
230
230
  Object.defineProperty(retryWrapper, "name", { value: fn_name, configurable: true });
231
+ if (_context?.kind === "method" && typeof _context.addInitializer === "function") {
232
+ _context.addInitializer(function() {
233
+ const owner_name = findDecoratedMethodOwnerName(this, _context, retryWrapper);
234
+ if (owner_name) {
235
+ Object.defineProperty(retryWrapper, "name", { value: `${owner_name}.${fn_name}`, configurable: true });
236
+ }
237
+ });
238
+ }
231
239
  return retryWrapper;
232
240
  };
233
241
  }
242
+ function findDecoratedMethodOwnerName(context_this, context, replacement) {
243
+ const method_name = context.name;
244
+ if (typeof method_name !== "string") {
245
+ return null;
246
+ }
247
+ if (context.static) {
248
+ let ctor = typeof context_this === "function" ? context_this : null;
249
+ while (ctor && ctor !== Function.prototype) {
250
+ const descriptor = Object.getOwnPropertyDescriptor(ctor, method_name);
251
+ if (descriptor?.value === replacement) {
252
+ return ctor.name || null;
253
+ }
254
+ const parent = Object.getPrototypeOf(ctor);
255
+ ctor = typeof parent === "function" ? parent : null;
256
+ }
257
+ return null;
258
+ }
259
+ if (typeof context_this !== "object" && typeof context_this !== "function" || context_this === null) {
260
+ return null;
261
+ }
262
+ let prototype = Object.getPrototypeOf(context_this);
263
+ while (prototype && prototype !== Object.prototype) {
264
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, method_name);
265
+ if (descriptor?.value === replacement) {
266
+ const ctor_name = prototype.constructor?.name;
267
+ return ctor_name || null;
268
+ }
269
+ prototype = Object.getPrototypeOf(prototype);
270
+ }
271
+ return null;
272
+ }
234
273
  async function acquireWithTimeout(semaphore, timeout_ms) {
235
274
  return new Promise((resolve) => {
236
275
  let settled = false;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/retry.ts"],
4
- "sourcesContent": ["import { createAsyncLocalStorage, type AsyncLocalStorageLike } from './async_context.js'\nimport { isNodeRuntime } from './optional_deps.js'\n\ntype SemaphoreScope = 'multiprocess' | 'global' | 'class' | 'instance'\n\ntype MultiprocessLockHandle = {\n release: () => Promise<void>\n}\n\nconst MULTIPROCESS_SEMAPHORE_DIRNAME = 'browser_use_semaphores'\nconst MULTIPROCESS_STALE_LOCK_MS = 5 * 60 * 1000\n\nlet multiprocess_fallback_reason_logged: string | null = null\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface RetryOptions {\n /** Total number of attempts including the initial call (1 = no retry, 3 = up to 2 retries). Default: 1 */\n max_attempts?: number\n\n /** Seconds to wait between retries. Default: 0 */\n retry_after?: number\n\n /** Multiplier applied to retry_after after each attempt for exponential backoff. Default: 1.0 (constant delay) */\n retry_backoff_factor?: number\n\n /** Only retry when the thrown error matches one of these matchers. Accepts error class constructors,\n * string error names (matched against error.name), or RegExp patterns (tested against String(error)).\n * Default: undefined (retry on any error) */\n retry_on_errors?: Array<(new (...args: any[]) => Error) | string | RegExp>\n\n /** Per-attempt timeout in seconds. Default: undefined (no per-attempt timeout) */\n timeout?: number | null\n\n /** Maximum concurrent executions sharing this semaphore. Default: undefined (no concurrency limit) */\n semaphore_limit?: number | null\n\n /** Semaphore identifier. Functions with the same name share the same concurrency slot pool. Default: function name.\n * If a function is provided, it receives the same arguments as the wrapped function. */\n semaphore_name?: string | ((...args: any[]) => string) | null\n\n /** If true, proceed without concurrency limit when semaphore acquisition times out. Default: true */\n semaphore_lax?: boolean\n\n /** Semaphore scoping strategy. Default: 'global'\n * - 'multiprocess': all processes on the machine share one semaphore (Node.js only)\n * - 'global': all calls share one semaphore (keyed by semaphore_name)\n * - 'class': all instances of the same class share one semaphore (keyed by className.semaphore_name)\n * - 'instance': each object instance gets its own semaphore (keyed by instanceId.semaphore_name)\n * 'class' and 'instance' require `this` to be an object; they fall back to 'global' for standalone calls. */\n semaphore_scope?: SemaphoreScope\n\n /** Maximum seconds to wait for semaphore acquisition. Default: undefined \u2192 timeout * max(1, limit - 1) */\n semaphore_timeout?: number | null\n}\n\n// \u2500\u2500\u2500 Errors \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Thrown when a single attempt exceeds the per-attempt timeout. */\nexport class RetryTimeoutError extends Error {\n timeout_seconds: number\n attempt: number\n\n constructor(message: string, params: { timeout_seconds: number; attempt: number }) {\n super(message)\n this.name = 'RetryTimeoutError'\n this.timeout_seconds = params.timeout_seconds\n this.attempt = params.attempt\n }\n}\n\n/** Thrown (when semaphore_lax=false) if the semaphore cannot be acquired within the timeout. */\nexport class SemaphoreTimeoutError extends Error {\n semaphore_name: string\n semaphore_limit: number\n timeout_seconds: number\n\n constructor(message: string, params: { semaphore_name: string; semaphore_limit: number; timeout_seconds: number }) {\n super(message)\n this.name = 'SemaphoreTimeoutError'\n this.semaphore_name = params.semaphore_name\n this.semaphore_limit = params.semaphore_limit\n this.timeout_seconds = params.timeout_seconds\n }\n}\n\n// \u2500\u2500\u2500 Re-entrancy tracking via AsyncLocalStorage \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Prevents deadlocks when a retry()-wrapped function calls another retry()-wrapped\n// function that shares the same semaphore (or calls itself recursively).\n//\n// Each async call stack tracks which semaphore names it currently holds. When a\n// nested call encounters a semaphore it already holds, it skips acquisition and\n// runs directly within the parent's slot.\n//\n// Uses the same AsyncLocalStorage polyfill as the rest of abxbus (see async_context.ts)\n// so it works in Node.js and gracefully degrades to a no-op in browsers.\n\ntype ReentrantStore = Set<string>\n\n// Separate AsyncLocalStorage instance for retry re-entrancy tracking.\n// Created via the shared factory in async_context.ts (returns null in browsers).\nconst retry_context_storage: AsyncLocalStorageLike | null = createAsyncLocalStorage()\n\nfunction getHeldSemaphores(): ReentrantStore {\n return (retry_context_storage?.getStore() as ReentrantStore | undefined) ?? new Set()\n}\n\nfunction runWithHeldSemaphores<T>(held: ReentrantStore, fn: () => T): T {\n if (!retry_context_storage) return fn()\n return retry_context_storage.run(held, fn)\n}\n\n// \u2500\u2500\u2500 Semaphore scope helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nlet _next_instance_id = 1\nconst _instance_ids = new WeakMap<object, number>()\n\nfunction scopedSemaphoreKey(base_name: string, scope: SemaphoreScope, context: unknown): string {\n if (scope === 'class' && context && typeof context === 'object') {\n return `${(context as object).constructor?.name ?? 'Object'}.${base_name}`\n }\n if (scope === 'instance' && context && typeof context === 'object') {\n let id = _instance_ids.get(context as object)\n if (id === undefined) {\n id = _next_instance_id++\n _instance_ids.set(context as object, id)\n }\n return `${id}.${base_name}`\n }\n return base_name\n}\n\n// \u2500\u2500\u2500 Global semaphore registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nclass RetrySemaphore {\n readonly size: number\n private inUse: number\n private waiters: Array<() => void>\n\n constructor(size: number) {\n this.size = size\n this.inUse = 0\n this.waiters = []\n }\n\n async acquire(): Promise<void> {\n if (this.size === Infinity) {\n return\n }\n if (this.inUse < this.size) {\n this.inUse += 1\n return\n }\n await new Promise<void>((resolve) => {\n this.waiters.push(resolve)\n })\n }\n\n release(): void {\n if (this.size === Infinity) {\n return\n }\n const next = this.waiters.shift()\n if (next) {\n // Handoff: keep the permit accounted for and transfer it directly to the waiter.\n next()\n return\n }\n this.inUse = Math.max(0, this.inUse - 1)\n }\n}\n\nconst SEMAPHORE_REGISTRY = new Map<string, RetrySemaphore>()\n\nfunction getOrCreateSemaphore(name: string, limit: number): RetrySemaphore {\n const existing = SEMAPHORE_REGISTRY.get(name)\n if (existing && existing.size === limit) return existing\n const sem = new RetrySemaphore(limit)\n SEMAPHORE_REGISTRY.set(name, sem)\n return sem\n}\n\n/** Reset the global semaphore registry. Useful in tests. */\nexport function clearSemaphoreRegistry(): void {\n SEMAPHORE_REGISTRY.clear()\n multiprocess_fallback_reason_logged = null\n}\n\n// \u2500\u2500\u2500 retry() decorator / higher-order wrapper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Usage as a higher-order function (works on any async function):\n//\n// const fetchWithRetry = retry({ max_attempts: 3, retry_after: 1 })(async (url: string) => {\n// return await fetch(url)\n// })\n//\n// Usage as a TC39 Stage 3 decorator on class methods (TS 5.0+):\n//\n// class ApiClient {\n// @retry({ max_attempts: 3, retry_after: 1 })\n// async fetchData(): Promise<Data> { ... }\n// }\n//\n// Usage on event bus handlers:\n//\n// bus.on(MyEvent, retry({ max_attempts: 3 })(async (event) => {\n// await riskyOperation(event.data)\n// }))\n\nexport function retry(options: RetryOptions = {}) {\n const {\n max_attempts = 1,\n retry_after = 0,\n retry_backoff_factor = 1.0,\n retry_on_errors,\n timeout,\n semaphore_limit,\n semaphore_name: semaphore_name_option,\n semaphore_lax = true,\n semaphore_scope = 'global',\n semaphore_timeout,\n } = options\n\n return function decorator<T extends (...args: any[]) => any>(target: T, _context?: ClassMethodDecoratorContext): T {\n const fn_name = target.name || (_context?.name as string) || 'anonymous'\n const effective_max_attempts = Math.max(1, max_attempts)\n const effective_retry_after = Math.max(0, retry_after)\n\n async function retryWrapper(this: any, ...args: any[]): Promise<any> {\n const base_name = typeof semaphore_name_option === 'function' ? semaphore_name_option(...args) : (semaphore_name_option ?? fn_name)\n const sem_name = typeof base_name === 'string' ? base_name : String(base_name)\n // \u2500\u2500 Resolve scoped semaphore key at call time (uses `this` for class/instance scopes) \u2500\u2500\n const scoped_key = scopedSemaphoreKey(sem_name, semaphore_scope, this)\n\n // \u2500\u2500 Check re-entrancy: skip semaphore if we already hold it in this async context \u2500\u2500\n const held = getHeldSemaphores()\n const needs_semaphore = semaphore_limit != null && semaphore_limit > 0\n const is_reentrant = needs_semaphore && held.has(scoped_key)\n\n // \u2500\u2500 Semaphore acquisition (held across all retry attempts, skipped if re-entrant) \u2500\u2500\n let semaphore: RetrySemaphore | null = null\n let multiprocess_lock: MultiprocessLockHandle | null = null\n let semaphore_acquired = false\n\n if (needs_semaphore && !is_reentrant) {\n const effective_sem_timeout =\n semaphore_timeout != null ? semaphore_timeout : timeout != null ? timeout * Math.max(1, semaphore_limit! - 1) : null\n\n if (semaphore_scope === 'multiprocess') {\n if (isNodeRuntime()) {\n multiprocess_lock = await acquireMultiprocessSemaphore(scoped_key, semaphore_limit!, effective_sem_timeout, semaphore_lax)\n semaphore_acquired = multiprocess_lock !== null\n } else {\n logMultiprocessFallbackOnce('multiprocess semaphores require a Node.js runtime; falling back to in-process global scope')\n semaphore = getOrCreateSemaphore(scoped_key, semaphore_limit!)\n if (effective_sem_timeout != null && effective_sem_timeout > 0) {\n semaphore_acquired = await acquireWithTimeout(semaphore, effective_sem_timeout * 1000)\n if (!semaphore_acquired) {\n if (!semaphore_lax) {\n throw new SemaphoreTimeoutError(\n `Failed to acquire semaphore \"${scoped_key}\" within ${effective_sem_timeout}s (limit=${semaphore_limit})`,\n { semaphore_name: scoped_key, semaphore_limit: semaphore_limit!, timeout_seconds: effective_sem_timeout }\n )\n }\n }\n } else {\n await semaphore.acquire()\n semaphore_acquired = true\n }\n }\n } else {\n semaphore = getOrCreateSemaphore(scoped_key, semaphore_limit!)\n\n if (effective_sem_timeout != null && effective_sem_timeout > 0) {\n semaphore_acquired = await acquireWithTimeout(semaphore, effective_sem_timeout * 1000)\n if (!semaphore_acquired) {\n if (!semaphore_lax) {\n throw new SemaphoreTimeoutError(\n `Failed to acquire semaphore \"${scoped_key}\" within ${effective_sem_timeout}s (limit=${semaphore_limit})`,\n { semaphore_name: scoped_key, semaphore_limit: semaphore_limit!, timeout_seconds: effective_sem_timeout }\n )\n }\n }\n } else {\n await semaphore.acquire()\n semaphore_acquired = true\n }\n }\n }\n\n // \u2500\u2500 Build the set of held semaphores for nested calls \u2500\u2500\n const new_held = new Set(held)\n if (semaphore_acquired) {\n new_held.add(scoped_key)\n }\n\n // \u2500\u2500 Retry loop (runs inside the semaphore and re-entrancy context) \u2500\u2500\n const runRetryLoop = async (): Promise<any> => {\n for (let attempt = 1; attempt <= effective_max_attempts; attempt++) {\n try {\n if (timeout != null && timeout > 0) {\n return await _runWithTimeout(() => Promise.resolve(target.apply(this, args)), timeout * 1000, attempt)\n } else {\n return await Promise.resolve(target.apply(this, args))\n }\n } catch (error) {\n // Check if this error type should trigger a retry\n if (retry_on_errors && retry_on_errors.length > 0) {\n const is_retryable = retry_on_errors.some((matcher) =>\n typeof matcher === 'string'\n ? (error as Error)?.name === matcher\n : matcher instanceof RegExp\n ? matcher.test(String(error))\n : error instanceof matcher\n )\n if (!is_retryable) throw error\n }\n\n // Last attempt: rethrow\n if (attempt >= effective_max_attempts) throw error\n\n // Wait before next attempt with exponential backoff\n const delay_seconds = effective_retry_after * Math.pow(retry_backoff_factor, attempt - 1)\n if (delay_seconds > 0) {\n await sleep(delay_seconds * 1000)\n }\n }\n }\n\n // Unreachable, but satisfies the type checker\n throw new Error(`retry(${fn_name}): unexpected end of retry loop`)\n }\n\n try {\n return await runWithHeldSemaphores(new_held, runRetryLoop)\n } finally {\n if (semaphore_acquired && multiprocess_lock) {\n await multiprocess_lock.release()\n } else if (semaphore_acquired && semaphore) {\n semaphore.release()\n }\n }\n }\n\n Object.defineProperty(retryWrapper, 'name', { value: fn_name, configurable: true })\n return retryWrapper as unknown as T\n }\n}\n\n// \u2500\u2500\u2500 Internal helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Try to acquire a semaphore within a timeout. Returns true if acquired, false if timed out.\n * If the semaphore is acquired after the timeout (due to the waiter remaining queued),\n * it is immediately released to avoid leaking slots.\n */\nasync function acquireWithTimeout(semaphore: RetrySemaphore, timeout_ms: number): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n let settled = false\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true\n resolve(false)\n }\n }, timeout_ms)\n\n semaphore.acquire().then(() => {\n if (!settled) {\n settled = true\n clearTimeout(timer)\n resolve(true)\n } else {\n // Acquired after timeout fired \u2014 release immediately to avoid slot leak\n semaphore.release()\n }\n })\n })\n}\n\nfunction logMultiprocessFallbackOnce(reason: string): void {\n if (multiprocess_fallback_reason_logged === reason) return\n multiprocess_fallback_reason_logged = reason\n console.warn(`[abxbus.retry] ${reason}`)\n}\n\nasync function importNodeModule(specifier: string): Promise<any> {\n const dynamic_import = Function('module_name', 'return import(module_name)') as (module_name: string) => Promise<unknown>\n return dynamic_import(specifier) as Promise<any>\n}\n\nasync function acquireMultiprocessSemaphore(\n scoped_key: string,\n semaphore_limit: number,\n semaphore_timeout_seconds: number | null,\n semaphore_lax: boolean\n): Promise<MultiprocessLockHandle | null> {\n const [crypto, fs, os, path] = await Promise.all([\n importNodeModule('node:crypto'),\n importNodeModule('node:fs'),\n importNodeModule('node:os'),\n importNodeModule('node:path'),\n ])\n const semaphore_directory = path.join(os.tmpdir(), MULTIPROCESS_SEMAPHORE_DIRNAME)\n const lock_prefix = crypto.createHash('sha256').update(scoped_key).digest('hex').slice(0, 40)\n fs.mkdirSync(semaphore_directory, { recursive: true })\n\n const start = Date.now()\n let retry_delay_ms = 100\n\n while (true) {\n const elapsed_ms = Date.now() - start\n const remaining_ms =\n semaphore_timeout_seconds != null && semaphore_timeout_seconds > 0 ? semaphore_timeout_seconds * 1000 - elapsed_ms : null\n\n if (remaining_ms != null && remaining_ms <= 0) {\n break\n }\n\n for (let slot = 0; slot < semaphore_limit; slot++) {\n const slot_file = path.join(semaphore_directory, `${lock_prefix}.${String(slot).padStart(2, '0')}.lock`)\n const token = `${process.pid}:${Date.now()}:${Math.random().toString(16).slice(2)}`\n\n try {\n const fd = fs.openSync(slot_file, 'wx', 0o600)\n try {\n fs.writeFileSync(\n fd,\n JSON.stringify({\n token,\n pid: process.pid,\n semaphore_name: scoped_key,\n created_at_ms: Date.now(),\n }),\n 'utf8'\n )\n } finally {\n fs.closeSync(fd)\n }\n return {\n release: async () => {\n try {\n const raw = String(fs.readFileSync(slot_file, 'utf8') || '').trim()\n const current_owner = raw ? (JSON.parse(raw) as { token?: unknown }) : null\n if (current_owner?.token === token) {\n fs.unlinkSync(slot_file)\n }\n } catch {}\n },\n }\n } catch (error) {\n if (!(error instanceof Error) || (error as NodeJS.ErrnoException).code !== 'EEXIST') {\n throw error\n }\n\n try {\n const raw = String(fs.readFileSync(slot_file, 'utf8') || '').trim()\n const current_owner = raw ? (JSON.parse(raw) as { pid?: unknown }) : null\n const current_pid = typeof current_owner?.pid === 'number' ? current_owner.pid : null\n if (current_pid != null) {\n try {\n process.kill(current_pid, 0)\n continue\n } catch {}\n }\n\n const slot_age_ms = Date.now() - fs.statSync(slot_file).mtimeMs\n if (current_pid != null || slot_age_ms >= MULTIPROCESS_STALE_LOCK_MS) {\n fs.unlinkSync(slot_file)\n }\n } catch {}\n }\n }\n\n const sleep_ms = Math.min(retry_delay_ms, remaining_ms ?? retry_delay_ms)\n if (sleep_ms > 0) {\n await sleep(sleep_ms)\n }\n retry_delay_ms = Math.min(retry_delay_ms * 2, 1000)\n }\n\n if (!semaphore_lax) {\n throw new SemaphoreTimeoutError(\n `Failed to acquire semaphore \"${scoped_key}\" within ${semaphore_timeout_seconds}s (limit=${semaphore_limit})`,\n { semaphore_name: scoped_key, semaphore_limit, timeout_seconds: semaphore_timeout_seconds ?? 0 }\n )\n }\n\n return null\n}\n\n/** Run fn() with a timeout. Rejects with RetryTimeoutError if the timeout fires first. */\nasync function _runWithTimeout<T>(fn: () => Promise<T>, timeout_ms: number, attempt: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let settled = false\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true\n reject(\n new RetryTimeoutError(`Timed out after ${timeout_ms / 1000}s (attempt ${attempt})`, {\n timeout_seconds: timeout_ms / 1000,\n attempt,\n })\n )\n }\n }, timeout_ms)\n\n fn().then(\n (value) => {\n if (!settled) {\n settled = true\n clearTimeout(timer)\n resolve(value)\n }\n },\n (error) => {\n if (!settled) {\n settled = true\n clearTimeout(timer)\n reject(error)\n }\n }\n )\n })\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { createAsyncLocalStorage, type AsyncLocalStorageLike } from './async_context.js'\nimport { isNodeRuntime } from './optional_deps.js'\n\ntype SemaphoreScope = 'multiprocess' | 'global' | 'class' | 'instance'\n\ntype MultiprocessLockHandle = {\n release: () => Promise<void>\n}\n\nconst MULTIPROCESS_SEMAPHORE_DIRNAME = 'browser_use_semaphores'\nconst MULTIPROCESS_STALE_LOCK_MS = 5 * 60 * 1000\n\nlet multiprocess_fallback_reason_logged: string | null = null\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface RetryOptions {\n /** Total number of attempts including the initial call (1 = no retry, 3 = up to 2 retries). Default: 1 */\n max_attempts?: number\n\n /** Seconds to wait between retries. Default: 0 */\n retry_after?: number\n\n /** Multiplier applied to retry_after after each attempt for exponential backoff. Default: 1.0 (constant delay) */\n retry_backoff_factor?: number\n\n /** Only retry when the thrown error matches one of these matchers. Accepts error class constructors,\n * string error names (matched against error.name), or RegExp patterns (tested against String(error)).\n * Default: undefined (retry on any error) */\n retry_on_errors?: Array<(new (...args: any[]) => Error) | string | RegExp>\n\n /** Per-attempt timeout in seconds. Default: undefined (no per-attempt timeout) */\n timeout?: number | null\n\n /** Maximum concurrent executions sharing this semaphore. Default: undefined (no concurrency limit) */\n semaphore_limit?: number | null\n\n /** Semaphore identifier. Functions with the same name share the same concurrency slot pool. Default: function name.\n * If a function is provided, it receives the same arguments as the wrapped function. */\n semaphore_name?: string | ((...args: any[]) => string) | null\n\n /** If true, proceed without concurrency limit when semaphore acquisition times out. Default: true */\n semaphore_lax?: boolean\n\n /** Semaphore scoping strategy. Default: 'global'\n * - 'multiprocess': all processes on the machine share one semaphore (Node.js only)\n * - 'global': all calls share one semaphore (keyed by semaphore_name)\n * - 'class': all instances of the same class share one semaphore (keyed by className.semaphore_name)\n * - 'instance': each object instance gets its own semaphore (keyed by instanceId.semaphore_name)\n * 'class' and 'instance' require `this` to be an object; they fall back to 'global' for standalone calls. */\n semaphore_scope?: SemaphoreScope\n\n /** Maximum seconds to wait for semaphore acquisition. Default: undefined \u2192 timeout * max(1, limit - 1) */\n semaphore_timeout?: number | null\n}\n\n// \u2500\u2500\u2500 Errors \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Thrown when a single attempt exceeds the per-attempt timeout. */\nexport class RetryTimeoutError extends Error {\n timeout_seconds: number\n attempt: number\n\n constructor(message: string, params: { timeout_seconds: number; attempt: number }) {\n super(message)\n this.name = 'RetryTimeoutError'\n this.timeout_seconds = params.timeout_seconds\n this.attempt = params.attempt\n }\n}\n\n/** Thrown (when semaphore_lax=false) if the semaphore cannot be acquired within the timeout. */\nexport class SemaphoreTimeoutError extends Error {\n semaphore_name: string\n semaphore_limit: number\n timeout_seconds: number\n\n constructor(message: string, params: { semaphore_name: string; semaphore_limit: number; timeout_seconds: number }) {\n super(message)\n this.name = 'SemaphoreTimeoutError'\n this.semaphore_name = params.semaphore_name\n this.semaphore_limit = params.semaphore_limit\n this.timeout_seconds = params.timeout_seconds\n }\n}\n\n// \u2500\u2500\u2500 Re-entrancy tracking via AsyncLocalStorage \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Prevents deadlocks when a retry()-wrapped function calls another retry()-wrapped\n// function that shares the same semaphore (or calls itself recursively).\n//\n// Each async call stack tracks which semaphore names it currently holds. When a\n// nested call encounters a semaphore it already holds, it skips acquisition and\n// runs directly within the parent's slot.\n//\n// Uses the same AsyncLocalStorage polyfill as the rest of abxbus (see async_context.ts)\n// so it works in Node.js and gracefully degrades to a no-op in browsers.\n\ntype ReentrantStore = Set<string>\n\n// Separate AsyncLocalStorage instance for retry re-entrancy tracking.\n// Created via the shared factory in async_context.ts (returns null in browsers).\nconst retry_context_storage: AsyncLocalStorageLike | null = createAsyncLocalStorage()\n\nfunction getHeldSemaphores(): ReentrantStore {\n return (retry_context_storage?.getStore() as ReentrantStore | undefined) ?? new Set()\n}\n\nfunction runWithHeldSemaphores<T>(held: ReentrantStore, fn: () => T): T {\n if (!retry_context_storage) return fn()\n return retry_context_storage.run(held, fn)\n}\n\n// \u2500\u2500\u2500 Semaphore scope helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nlet _next_instance_id = 1\nconst _instance_ids = new WeakMap<object, number>()\n\nfunction scopedSemaphoreKey(base_name: string, scope: SemaphoreScope, context: unknown): string {\n if (scope === 'class' && context && typeof context === 'object') {\n return `${(context as object).constructor?.name ?? 'Object'}.${base_name}`\n }\n if (scope === 'instance' && context && typeof context === 'object') {\n let id = _instance_ids.get(context as object)\n if (id === undefined) {\n id = _next_instance_id++\n _instance_ids.set(context as object, id)\n }\n return `${id}.${base_name}`\n }\n return base_name\n}\n\n// \u2500\u2500\u2500 Global semaphore registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nclass RetrySemaphore {\n readonly size: number\n private inUse: number\n private waiters: Array<() => void>\n\n constructor(size: number) {\n this.size = size\n this.inUse = 0\n this.waiters = []\n }\n\n async acquire(): Promise<void> {\n if (this.size === Infinity) {\n return\n }\n if (this.inUse < this.size) {\n this.inUse += 1\n return\n }\n await new Promise<void>((resolve) => {\n this.waiters.push(resolve)\n })\n }\n\n release(): void {\n if (this.size === Infinity) {\n return\n }\n const next = this.waiters.shift()\n if (next) {\n // Handoff: keep the permit accounted for and transfer it directly to the waiter.\n next()\n return\n }\n this.inUse = Math.max(0, this.inUse - 1)\n }\n}\n\nconst SEMAPHORE_REGISTRY = new Map<string, RetrySemaphore>()\n\nfunction getOrCreateSemaphore(name: string, limit: number): RetrySemaphore {\n const existing = SEMAPHORE_REGISTRY.get(name)\n if (existing && existing.size === limit) return existing\n const sem = new RetrySemaphore(limit)\n SEMAPHORE_REGISTRY.set(name, sem)\n return sem\n}\n\n/** Reset the global semaphore registry. Useful in tests. */\nexport function clearSemaphoreRegistry(): void {\n SEMAPHORE_REGISTRY.clear()\n multiprocess_fallback_reason_logged = null\n}\n\n// \u2500\u2500\u2500 retry() decorator / higher-order wrapper \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Usage as a higher-order function (works on any async function):\n//\n// const fetchWithRetry = retry({ max_attempts: 3, retry_after: 1 })(async (url: string) => {\n// return await fetch(url)\n// })\n//\n// Usage as a TC39 Stage 3 decorator on class methods (TS 5.0+):\n//\n// class ApiClient {\n// @retry({ max_attempts: 3, retry_after: 1 })\n// async fetchData(): Promise<Data> { ... }\n// }\n//\n// Usage on event bus handlers:\n//\n// bus.on(MyEvent, retry({ max_attempts: 3 })(async (event) => {\n// await riskyOperation(event.data)\n// }))\n\nexport function retry(options: RetryOptions = {}) {\n const {\n max_attempts = 1,\n retry_after = 0,\n retry_backoff_factor = 1.0,\n retry_on_errors,\n timeout,\n semaphore_limit,\n semaphore_name: semaphore_name_option,\n semaphore_lax = true,\n semaphore_scope = 'global',\n semaphore_timeout,\n } = options\n\n return function decorator<T extends (...args: any[]) => any>(target: T, _context?: ClassMethodDecoratorContext): T {\n const fn_name = target.name || (_context?.name as string) || 'anonymous'\n const effective_max_attempts = Math.max(1, max_attempts)\n const effective_retry_after = Math.max(0, retry_after)\n\n async function retryWrapper(this: any, ...args: any[]): Promise<any> {\n const base_name = typeof semaphore_name_option === 'function' ? semaphore_name_option(...args) : (semaphore_name_option ?? fn_name)\n const sem_name = typeof base_name === 'string' ? base_name : String(base_name)\n // \u2500\u2500 Resolve scoped semaphore key at call time (uses `this` for class/instance scopes) \u2500\u2500\n const scoped_key = scopedSemaphoreKey(sem_name, semaphore_scope, this)\n\n // \u2500\u2500 Check re-entrancy: skip semaphore if we already hold it in this async context \u2500\u2500\n const held = getHeldSemaphores()\n const needs_semaphore = semaphore_limit != null && semaphore_limit > 0\n const is_reentrant = needs_semaphore && held.has(scoped_key)\n\n // \u2500\u2500 Semaphore acquisition (held across all retry attempts, skipped if re-entrant) \u2500\u2500\n let semaphore: RetrySemaphore | null = null\n let multiprocess_lock: MultiprocessLockHandle | null = null\n let semaphore_acquired = false\n\n if (needs_semaphore && !is_reentrant) {\n const effective_sem_timeout =\n semaphore_timeout != null ? semaphore_timeout : timeout != null ? timeout * Math.max(1, semaphore_limit! - 1) : null\n\n if (semaphore_scope === 'multiprocess') {\n if (isNodeRuntime()) {\n multiprocess_lock = await acquireMultiprocessSemaphore(scoped_key, semaphore_limit!, effective_sem_timeout, semaphore_lax)\n semaphore_acquired = multiprocess_lock !== null\n } else {\n logMultiprocessFallbackOnce('multiprocess semaphores require a Node.js runtime; falling back to in-process global scope')\n semaphore = getOrCreateSemaphore(scoped_key, semaphore_limit!)\n if (effective_sem_timeout != null && effective_sem_timeout > 0) {\n semaphore_acquired = await acquireWithTimeout(semaphore, effective_sem_timeout * 1000)\n if (!semaphore_acquired) {\n if (!semaphore_lax) {\n throw new SemaphoreTimeoutError(\n `Failed to acquire semaphore \"${scoped_key}\" within ${effective_sem_timeout}s (limit=${semaphore_limit})`,\n { semaphore_name: scoped_key, semaphore_limit: semaphore_limit!, timeout_seconds: effective_sem_timeout }\n )\n }\n }\n } else {\n await semaphore.acquire()\n semaphore_acquired = true\n }\n }\n } else {\n semaphore = getOrCreateSemaphore(scoped_key, semaphore_limit!)\n\n if (effective_sem_timeout != null && effective_sem_timeout > 0) {\n semaphore_acquired = await acquireWithTimeout(semaphore, effective_sem_timeout * 1000)\n if (!semaphore_acquired) {\n if (!semaphore_lax) {\n throw new SemaphoreTimeoutError(\n `Failed to acquire semaphore \"${scoped_key}\" within ${effective_sem_timeout}s (limit=${semaphore_limit})`,\n { semaphore_name: scoped_key, semaphore_limit: semaphore_limit!, timeout_seconds: effective_sem_timeout }\n )\n }\n }\n } else {\n await semaphore.acquire()\n semaphore_acquired = true\n }\n }\n }\n\n // \u2500\u2500 Build the set of held semaphores for nested calls \u2500\u2500\n const new_held = new Set(held)\n if (semaphore_acquired) {\n new_held.add(scoped_key)\n }\n\n // \u2500\u2500 Retry loop (runs inside the semaphore and re-entrancy context) \u2500\u2500\n const runRetryLoop = async (): Promise<any> => {\n for (let attempt = 1; attempt <= effective_max_attempts; attempt++) {\n try {\n if (timeout != null && timeout > 0) {\n return await _runWithTimeout(() => Promise.resolve(target.apply(this, args)), timeout * 1000, attempt)\n } else {\n return await Promise.resolve(target.apply(this, args))\n }\n } catch (error) {\n // Check if this error type should trigger a retry\n if (retry_on_errors && retry_on_errors.length > 0) {\n const is_retryable = retry_on_errors.some((matcher) =>\n typeof matcher === 'string'\n ? (error as Error)?.name === matcher\n : matcher instanceof RegExp\n ? matcher.test(String(error))\n : error instanceof matcher\n )\n if (!is_retryable) throw error\n }\n\n // Last attempt: rethrow\n if (attempt >= effective_max_attempts) throw error\n\n // Wait before next attempt with exponential backoff\n const delay_seconds = effective_retry_after * Math.pow(retry_backoff_factor, attempt - 1)\n if (delay_seconds > 0) {\n await sleep(delay_seconds * 1000)\n }\n }\n }\n\n // Unreachable, but satisfies the type checker\n throw new Error(`retry(${fn_name}): unexpected end of retry loop`)\n }\n\n try {\n return await runWithHeldSemaphores(new_held, runRetryLoop)\n } finally {\n if (semaphore_acquired && multiprocess_lock) {\n await multiprocess_lock.release()\n } else if (semaphore_acquired && semaphore) {\n semaphore.release()\n }\n }\n }\n\n Object.defineProperty(retryWrapper, 'name', { value: fn_name, configurable: true })\n if (_context?.kind === 'method' && typeof _context.addInitializer === 'function') {\n _context.addInitializer(function (this: unknown) {\n const owner_name = findDecoratedMethodOwnerName(this, _context, retryWrapper)\n if (owner_name) {\n Object.defineProperty(retryWrapper, 'name', { value: `${owner_name}.${fn_name}`, configurable: true })\n }\n })\n }\n return retryWrapper as unknown as T\n }\n}\n\n// \u2500\u2500\u2500 Internal helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction findDecoratedMethodOwnerName(\n context_this: unknown,\n context: ClassMethodDecoratorContext,\n replacement: (...args: any[]) => any\n): string | null {\n const method_name = context.name\n if (typeof method_name !== 'string') {\n return null\n }\n\n if (context.static) {\n let ctor = typeof context_this === 'function' ? context_this : null\n while (ctor && ctor !== Function.prototype) {\n const descriptor = Object.getOwnPropertyDescriptor(ctor, method_name)\n if (descriptor?.value === replacement) {\n return ctor.name || null\n }\n const parent = Object.getPrototypeOf(ctor)\n ctor = typeof parent === 'function' ? parent : null\n }\n return null\n }\n\n if ((typeof context_this !== 'object' && typeof context_this !== 'function') || context_this === null) {\n return null\n }\n\n let prototype = Object.getPrototypeOf(context_this)\n while (prototype && prototype !== Object.prototype) {\n const descriptor = Object.getOwnPropertyDescriptor(prototype, method_name)\n if (descriptor?.value === replacement) {\n const ctor_name = (prototype as { constructor?: { name?: string } }).constructor?.name\n return ctor_name || null\n }\n prototype = Object.getPrototypeOf(prototype)\n }\n return null\n}\n\n/**\n * Try to acquire a semaphore within a timeout. Returns true if acquired, false if timed out.\n * If the semaphore is acquired after the timeout (due to the waiter remaining queued),\n * it is immediately released to avoid leaking slots.\n */\nasync function acquireWithTimeout(semaphore: RetrySemaphore, timeout_ms: number): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n let settled = false\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true\n resolve(false)\n }\n }, timeout_ms)\n\n semaphore.acquire().then(() => {\n if (!settled) {\n settled = true\n clearTimeout(timer)\n resolve(true)\n } else {\n // Acquired after timeout fired \u2014 release immediately to avoid slot leak\n semaphore.release()\n }\n })\n })\n}\n\nfunction logMultiprocessFallbackOnce(reason: string): void {\n if (multiprocess_fallback_reason_logged === reason) return\n multiprocess_fallback_reason_logged = reason\n console.warn(`[abxbus.retry] ${reason}`)\n}\n\nasync function importNodeModule(specifier: string): Promise<any> {\n const dynamic_import = Function('module_name', 'return import(module_name)') as (module_name: string) => Promise<unknown>\n return dynamic_import(specifier) as Promise<any>\n}\n\nasync function acquireMultiprocessSemaphore(\n scoped_key: string,\n semaphore_limit: number,\n semaphore_timeout_seconds: number | null,\n semaphore_lax: boolean\n): Promise<MultiprocessLockHandle | null> {\n const [crypto, fs, os, path] = await Promise.all([\n importNodeModule('node:crypto'),\n importNodeModule('node:fs'),\n importNodeModule('node:os'),\n importNodeModule('node:path'),\n ])\n const semaphore_directory = path.join(os.tmpdir(), MULTIPROCESS_SEMAPHORE_DIRNAME)\n const lock_prefix = crypto.createHash('sha256').update(scoped_key).digest('hex').slice(0, 40)\n fs.mkdirSync(semaphore_directory, { recursive: true })\n\n const start = Date.now()\n let retry_delay_ms = 100\n\n while (true) {\n const elapsed_ms = Date.now() - start\n const remaining_ms =\n semaphore_timeout_seconds != null && semaphore_timeout_seconds > 0 ? semaphore_timeout_seconds * 1000 - elapsed_ms : null\n\n if (remaining_ms != null && remaining_ms <= 0) {\n break\n }\n\n for (let slot = 0; slot < semaphore_limit; slot++) {\n const slot_file = path.join(semaphore_directory, `${lock_prefix}.${String(slot).padStart(2, '0')}.lock`)\n const token = `${process.pid}:${Date.now()}:${Math.random().toString(16).slice(2)}`\n\n try {\n const fd = fs.openSync(slot_file, 'wx', 0o600)\n try {\n fs.writeFileSync(\n fd,\n JSON.stringify({\n token,\n pid: process.pid,\n semaphore_name: scoped_key,\n created_at_ms: Date.now(),\n }),\n 'utf8'\n )\n } finally {\n fs.closeSync(fd)\n }\n return {\n release: async () => {\n try {\n const raw = String(fs.readFileSync(slot_file, 'utf8') || '').trim()\n const current_owner = raw ? (JSON.parse(raw) as { token?: unknown }) : null\n if (current_owner?.token === token) {\n fs.unlinkSync(slot_file)\n }\n } catch {}\n },\n }\n } catch (error) {\n if (!(error instanceof Error) || (error as NodeJS.ErrnoException).code !== 'EEXIST') {\n throw error\n }\n\n try {\n const raw = String(fs.readFileSync(slot_file, 'utf8') || '').trim()\n const current_owner = raw ? (JSON.parse(raw) as { pid?: unknown }) : null\n const current_pid = typeof current_owner?.pid === 'number' ? current_owner.pid : null\n if (current_pid != null) {\n try {\n process.kill(current_pid, 0)\n continue\n } catch {}\n }\n\n const slot_age_ms = Date.now() - fs.statSync(slot_file).mtimeMs\n if (current_pid != null || slot_age_ms >= MULTIPROCESS_STALE_LOCK_MS) {\n fs.unlinkSync(slot_file)\n }\n } catch {}\n }\n }\n\n const sleep_ms = Math.min(retry_delay_ms, remaining_ms ?? retry_delay_ms)\n if (sleep_ms > 0) {\n await sleep(sleep_ms)\n }\n retry_delay_ms = Math.min(retry_delay_ms * 2, 1000)\n }\n\n if (!semaphore_lax) {\n throw new SemaphoreTimeoutError(\n `Failed to acquire semaphore \"${scoped_key}\" within ${semaphore_timeout_seconds}s (limit=${semaphore_limit})`,\n { semaphore_name: scoped_key, semaphore_limit, timeout_seconds: semaphore_timeout_seconds ?? 0 }\n )\n }\n\n return null\n}\n\n/** Run fn() with a timeout. Rejects with RetryTimeoutError if the timeout fires first. */\nasync function _runWithTimeout<T>(fn: () => Promise<T>, timeout_ms: number, attempt: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let settled = false\n\n const timer = setTimeout(() => {\n if (!settled) {\n settled = true\n reject(\n new RetryTimeoutError(`Timed out after ${timeout_ms / 1000}s (attempt ${attempt})`, {\n timeout_seconds: timeout_ms / 1000,\n attempt,\n })\n )\n }\n }, timeout_ms)\n\n fn().then(\n (value) => {\n if (!settled) {\n settled = true\n clearTimeout(timer)\n resolve(value)\n }\n },\n (error) => {\n if (!settled) {\n settled = true\n clearTimeout(timer)\n reject(error)\n }\n }\n )\n })\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -509,7 +509,7 @@ class EventBus {
509
509
  }
510
510
  on(event_pattern, handler, options = {}) {
511
511
  const normalized_key = normalizeEventPattern(event_pattern);
512
- const handler_name = handler.name || "anonymous";
512
+ const handler_name = EventHandler.handlerNameFromCallable(handler);
513
513
  const handler_entry = new EventHandler({
514
514
  handler,
515
515
  handler_name,