abxbus 2.5.4 → 2.5.9

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 (41) hide show
  1. package/dist/cjs/BaseEvent.d.ts +53 -28
  2. package/dist/cjs/BaseEvent.js +148 -28
  3. package/dist/cjs/BaseEvent.js.map +2 -2
  4. package/dist/cjs/LockManager.js +1 -1
  5. package/dist/cjs/LockManager.js.map +2 -2
  6. package/dist/cjs/events_suck.d.ts +8 -15
  7. package/dist/cjs/events_suck.js +1 -1
  8. package/dist/cjs/events_suck.js.map +2 -2
  9. package/dist/cjs/jsonschema.d.ts +6 -0
  10. package/dist/cjs/jsonschema.js +155 -0
  11. package/dist/cjs/jsonschema.js.map +7 -0
  12. package/dist/cjs/retry.d.ts +2 -0
  13. package/dist/cjs/retry.js +110 -35
  14. package/dist/cjs/retry.js.map +3 -3
  15. package/dist/cjs/types.d.ts +6 -10
  16. package/dist/cjs/types.js +9 -16
  17. package/dist/cjs/types.js.map +2 -2
  18. package/dist/esm/BaseEvent.js +148 -28
  19. package/dist/esm/BaseEvent.js.map +2 -2
  20. package/dist/esm/LockManager.js +1 -1
  21. package/dist/esm/LockManager.js.map +2 -2
  22. package/dist/esm/events_suck.js +1 -1
  23. package/dist/esm/events_suck.js.map +2 -2
  24. package/dist/esm/jsonschema.js +135 -0
  25. package/dist/esm/jsonschema.js.map +7 -0
  26. package/dist/esm/retry.js +110 -35
  27. package/dist/esm/retry.js.map +3 -3
  28. package/dist/esm/types.js +8 -15
  29. package/dist/esm/types.js.map +2 -2
  30. package/dist/types/BaseEvent.d.ts +53 -28
  31. package/dist/types/events_suck.d.ts +8 -15
  32. package/dist/types/jsonschema.d.ts +6 -0
  33. package/dist/types/retry.d.ts +2 -0
  34. package/dist/types/types.d.ts +6 -10
  35. package/package.json +1 -1
  36. package/src/BaseEvent.ts +321 -80
  37. package/src/LockManager.ts +1 -1
  38. package/src/events_suck.ts +20 -22
  39. package/src/jsonschema.ts +146 -0
  40. package/src/retry.ts +132 -38
  41. package/src/types.ts +10 -19
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/events_suck.ts"],
4
- "sourcesContent": ["import { EventBus } from './EventBus.js'\nimport { BaseEvent } from './BaseEvent.js'\n\nimport type { EventClass, EventResultType } from './types.js'\n\ntype EventMap = Record<string, EventClass<BaseEvent>>\ntype AnyFn = (...args: any[]) => any\ntype FunctionMap = Record<string, AnyFn>\ntype ExtraDict = Record<string, unknown>\n\ntype EventFieldsFromFn<TFunc extends AnyFn> =\n Parameters<TFunc> extends [infer TArg] ? (TArg extends Record<string, unknown> ? TArg : ExtraDict) : ExtraDict\n\ntype GeneratedEvent<TFunc extends AnyFn> = {\n (\n data: EventFieldsFromFn<TFunc> & ExtraDict\n ): BaseEvent & EventFieldsFromFn<TFunc> & { __event_result_type__?: Awaited<ReturnType<TFunc>> }\n new (\n data: EventFieldsFromFn<TFunc> & ExtraDict\n ): BaseEvent & EventFieldsFromFn<TFunc> & { __event_result_type__?: Awaited<ReturnType<TFunc>> }\n event_type?: string\n}\n\nexport type GeneratedEvents<TEvents extends FunctionMap> = {\n by_name: { [K in keyof TEvents]: GeneratedEvent<TEvents[K]> }\n} & {\n [K in keyof TEvents]: GeneratedEvent<TEvents[K]>\n}\n\ntype EventInit<TEventClass extends EventClass<BaseEvent>> =\n ConstructorParameters<TEventClass> extends [infer TInit, ...unknown[]] ? TInit : never\n\ntype EventMethodArgs<TEventClass extends EventClass<BaseEvent>> =\n {} extends EventInit<TEventClass>\n ? [init?: EventInit<TEventClass>, extra?: Record<string, unknown>]\n : [init: EventInit<TEventClass>, extra?: Record<string, unknown>]\n\ntype EventMethodResult<TEventClass extends EventClass<BaseEvent>> = EventResultType<InstanceType<TEventClass>> | undefined\n\nexport type EventsSuckClient<TEvents extends EventMap> = {\n bus: EventBus\n} & {\n [K in keyof TEvents]: (...args: EventMethodArgs<TEvents[K]>) => Promise<EventMethodResult<TEvents[K]>>\n}\n\nexport type EventsSuckClientClass<TEvents extends EventMap> = new (bus?: EventBus) => EventsSuckClient<TEvents>\n\ntype DynamicWrappedClient = {\n bus: EventBus\n} & Record<string, (...args: unknown[]) => Promise<unknown>>\n\nexport const make_events = <TEvents extends FunctionMap>(events: TEvents): GeneratedEvents<TEvents> => {\n const by_name = {} as { [K in keyof TEvents]: GeneratedEvent<TEvents[K]> }\n for (const [event_name] of Object.entries(events) as Array<[keyof TEvents, TEvents[keyof TEvents]]>) {\n if (!/^[A-Za-z_$][\\w$]*$/.test(String(event_name))) {\n throw new Error(`Invalid event name: ${String(event_name)}`)\n }\n by_name[event_name] = BaseEvent.extend(String(event_name), {}) as unknown as GeneratedEvent<TEvents[keyof TEvents]>\n }\n return Object.assign({ by_name }, by_name) as GeneratedEvents<TEvents>\n}\n\nexport const wrap = <TEvents extends EventMap>(class_name: string, methods: TEvents): EventsSuckClientClass<TEvents> => {\n class WrappedClient {\n bus: EventBus\n\n constructor(bus?: EventBus) {\n this.bus = bus ?? new EventBus(`${class_name}Bus`)\n }\n }\n\n Object.defineProperty(WrappedClient, 'name', { value: class_name })\n\n for (const [method_name, EventCtor] of Object.entries(methods)) {\n Object.defineProperty(WrappedClient.prototype, method_name, {\n value: async function (this: DynamicWrappedClient, init?: Record<string, unknown>, extra?: Record<string, unknown>) {\n const payload = { ...(init ?? {}), ...(extra ?? {}) }\n return await this.bus.emit(new EventCtor(payload)).now({ first_result: true }).eventResult()\n },\n writable: true,\n configurable: true,\n })\n }\n\n return WrappedClient as unknown as EventsSuckClientClass<TEvents>\n}\n\n// Intentionally no make_event()/make_handler() helpers in TypeScript.\n// Prefer the explicit inline pattern:\n// const FooCreateEvent = BaseEvent.extend('FooCreateEvent', {\n// id: z.string().nullable().optional(),\n// name: z.string(),\n// age: z.number(),\n// })\n// bus.on(FooCreateEvent, ({ id, name, age, ...extra }) => impl.create(id, { name, age }))\nexport const events_suck = { make_events, wrap } as const\n"],
5
- "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAkDnB,MAAM,cAAc,CAA8B,WAA8C;AACrG,QAAM,UAAU,CAAC;AACjB,aAAW,CAAC,UAAU,KAAK,OAAO,QAAQ,MAAM,GAAqD;AACnG,QAAI,CAAC,qBAAqB,KAAK,OAAO,UAAU,CAAC,GAAG;AAClD,YAAM,IAAI,MAAM,uBAAuB,OAAO,UAAU,CAAC,EAAE;AAAA,IAC7D;AACA,YAAQ,UAAU,IAAI,UAAU,OAAO,OAAO,UAAU,GAAG,CAAC,CAAC;AAAA,EAC/D;AACA,SAAO,OAAO,OAAO,EAAE,QAAQ,GAAG,OAAO;AAC3C;AAEO,MAAM,OAAO,CAA2B,YAAoB,YAAqD;AAAA,EACtH,MAAM,cAAc;AAAA,IAClB;AAAA,IAEA,YAAY,KAAgB;AAC1B,WAAK,MAAM,OAAO,IAAI,SAAS,GAAG,UAAU,KAAK;AAAA,IACnD;AAAA,EACF;AAEA,SAAO,eAAe,eAAe,QAAQ,EAAE,OAAO,WAAW,CAAC;AAElE,aAAW,CAAC,aAAa,SAAS,KAAK,OAAO,QAAQ,OAAO,GAAG;AAC9D,WAAO,eAAe,cAAc,WAAW,aAAa;AAAA,MAC1D,OAAO,eAA4C,MAAgC,OAAiC;AAClH,cAAM,UAAU,EAAE,GAAI,QAAQ,CAAC,GAAI,GAAI,SAAS,CAAC,EAAG;AACpD,eAAO,MAAM,KAAK,IAAI,KAAK,IAAI,UAAU,OAAO,CAAC,EAAE,IAAI,EAAE,cAAc,KAAK,CAAC,EAAE,YAAY;AAAA,MAC7F;AAAA,MACA,UAAU;AAAA,MACV,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAUO,MAAM,cAAc,EAAE,aAAa,KAAK;",
4
+ "sourcesContent": ["import { EventBus } from './EventBus.js'\nimport { BaseEvent } from './BaseEvent.js'\n\nimport type { EventClass, EventResultType } from './types.js'\n\ntype EventMap = Record<string, EventClass<BaseEvent, never>>\ntype FunctionMap = Record<string, (...args: never[]) => unknown>\ntype ExtraDict = Record<string, unknown>\n\ntype EventFieldsFromFn<TFunc extends FunctionMap[string]> =\n Parameters<TFunc> extends [infer TArg, ...unknown[]] ? (TArg extends Record<string, unknown> ? TArg : ExtraDict) : ExtraDict\n\ntype EventFromFn<TFunc extends FunctionMap[string]> = BaseEvent &\n EventFieldsFromFn<TFunc> & {\n __event_result_type__?: Awaited<ReturnType<TFunc>>\n }\n\nexport type GeneratedEvents<TEvents extends FunctionMap> = {\n by_name: { [K in keyof TEvents]: EventClass<EventFromFn<TEvents[K]>, EventFieldsFromFn<TEvents[K]> & ExtraDict> }\n} & {\n [K in keyof TEvents]: EventClass<EventFromFn<TEvents[K]>, EventFieldsFromFn<TEvents[K]> & ExtraDict>\n}\n\ntype EventInit<TEventClass extends EventClass<BaseEvent>> = [ConstructorParameters<TEventClass>[0]] extends [undefined]\n ? {}\n : NonNullable<ConstructorParameters<TEventClass>[0]>\n\ntype EventMethodArgs<TEventClass extends EventClass<BaseEvent>> =\n {} extends EventInit<TEventClass>\n ? [init?: EventInit<TEventClass>, extra?: Record<string, unknown>]\n : [init: EventInit<TEventClass>, extra?: Record<string, unknown>]\n\ntype EventMethodResult<TEventClass extends EventClass<BaseEvent>> = EventResultType<InstanceType<TEventClass>> | undefined\n\nexport type EventsSuckClient<TEvents extends EventMap> = {\n bus: EventBus\n} & {\n [K in keyof TEvents]: (...args: EventMethodArgs<TEvents[K]>) => Promise<EventMethodResult<TEvents[K]>>\n}\n\nexport type EventsSuckClientClass<TEvents extends EventMap> = new (bus?: EventBus) => EventsSuckClient<TEvents>\n\ntype DynamicWrappedClient = {\n bus: EventBus\n} & Record<string, (...args: unknown[]) => Promise<unknown>>\n\nexport const make_events = <TEvents extends FunctionMap>(events: TEvents): GeneratedEvents<TEvents> => {\n const by_name = {} as GeneratedEvents<TEvents>['by_name']\n for (const [event_name] of Object.entries(events) as Array<[keyof TEvents, TEvents[keyof TEvents]]>) {\n if (!/^[A-Za-z_$][\\w$]*$/.test(String(event_name))) {\n throw new Error(`Invalid event name: ${String(event_name)}`)\n }\n by_name[event_name] = BaseEvent.extend(String(event_name), {}) as unknown as GeneratedEvents<TEvents>['by_name'][typeof event_name]\n }\n return Object.assign({ by_name }, by_name) as GeneratedEvents<TEvents>\n}\n\nexport const wrap = <TEvents extends EventMap>(class_name: string, methods: TEvents): EventsSuckClientClass<TEvents> => {\n class WrappedClient {\n bus: EventBus\n\n constructor(bus?: EventBus) {\n this.bus = bus ?? new EventBus(`${class_name}Bus`)\n }\n }\n\n Object.defineProperty(WrappedClient, 'name', { value: class_name })\n\n for (const [method_name, EventCtor] of Object.entries(methods)) {\n Object.defineProperty(WrappedClient.prototype, method_name, {\n value: async function (this: DynamicWrappedClient, init?: Record<string, unknown>, extra?: Record<string, unknown>) {\n const payload = { ...(init ?? {}), ...(extra ?? {}) }\n return await this.bus\n .emit((EventCtor as EventClass<BaseEvent, Record<string, unknown>>)(payload))\n .now({ first_result: true })\n .eventResult()\n },\n writable: true,\n configurable: true,\n })\n }\n\n return WrappedClient as unknown as EventsSuckClientClass<TEvents>\n}\n\n// Intentionally no make_event()/make_handler() helpers in TypeScript.\n// Prefer the explicit inline pattern:\n// const FooCreateEvent = BaseEvent.extend('FooCreateEvent', {\n// id: z.string().nullable().optional(),\n// name: z.string(),\n// age: z.number(),\n// })\n// bus.on(FooCreateEvent, ({ id, name, age, ...extra }) => impl.create(id, { name, age }))\nexport const events_suck = { make_events, wrap } as const\n"],
5
+ "mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AA6CnB,MAAM,cAAc,CAA8B,WAA8C;AACrG,QAAM,UAAU,CAAC;AACjB,aAAW,CAAC,UAAU,KAAK,OAAO,QAAQ,MAAM,GAAqD;AACnG,QAAI,CAAC,qBAAqB,KAAK,OAAO,UAAU,CAAC,GAAG;AAClD,YAAM,IAAI,MAAM,uBAAuB,OAAO,UAAU,CAAC,EAAE;AAAA,IAC7D;AACA,YAAQ,UAAU,IAAI,UAAU,OAAO,OAAO,UAAU,GAAG,CAAC,CAAC;AAAA,EAC/D;AACA,SAAO,OAAO,OAAO,EAAE,QAAQ,GAAG,OAAO;AAC3C;AAEO,MAAM,OAAO,CAA2B,YAAoB,YAAqD;AAAA,EACtH,MAAM,cAAc;AAAA,IAClB;AAAA,IAEA,YAAY,KAAgB;AAC1B,WAAK,MAAM,OAAO,IAAI,SAAS,GAAG,UAAU,KAAK;AAAA,IACnD;AAAA,EACF;AAEA,SAAO,eAAe,eAAe,QAAQ,EAAE,OAAO,WAAW,CAAC;AAElE,aAAW,CAAC,aAAa,SAAS,KAAK,OAAO,QAAQ,OAAO,GAAG;AAC9D,WAAO,eAAe,cAAc,WAAW,aAAa;AAAA,MAC1D,OAAO,eAA4C,MAAgC,OAAiC;AAClH,cAAM,UAAU,EAAE,GAAI,QAAQ,CAAC,GAAI,GAAI,SAAS,CAAC,EAAG;AACpD,eAAO,MAAM,KAAK,IACf,KAAM,UAA6D,OAAO,CAAC,EAC3E,IAAI,EAAE,cAAc,KAAK,CAAC,EAC1B,YAAY;AAAA,MACjB;AAAA,MACA,UAAU;AAAA,MACV,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAUO,MAAM,cAAc,EAAE,aAAa,KAAK;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,135 @@
1
+ import { z } from "zod";
2
+ const isJsonSchemaObject = (value) => {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ };
5
+ const isJsonSchema = (value) => {
6
+ if (typeof value === "boolean") {
7
+ return true;
8
+ }
9
+ if (!isJsonSchemaObject(value)) {
10
+ return false;
11
+ }
12
+ if ("_zod" in value || "_def" in value || "~standard" in value) {
13
+ return false;
14
+ }
15
+ return true;
16
+ };
17
+ const nullUnionCandidates = (schema) => {
18
+ if (Array.isArray(schema.type) && schema.type.includes("null")) {
19
+ const non_null_types = schema.type.filter((item) => typeof item === "string" && item !== "null");
20
+ if (non_null_types.length > 0) {
21
+ return [{ type: non_null_types.length === 1 ? non_null_types[0] : non_null_types }, { type: "null" }];
22
+ }
23
+ }
24
+ return null;
25
+ };
26
+ const normalizeJsonSchema = (schema) => {
27
+ const normalized = normalizeJsonSchemaValue(schema);
28
+ if (!isJsonSchemaObject(normalized)) {
29
+ return normalized;
30
+ }
31
+ const schema_record = { ...normalized };
32
+ const definitions = schema_record.$defs;
33
+ const root_ref = rootRefForSchema(schema_record, definitions);
34
+ if (!root_ref || !definitions) {
35
+ schema_record.$schema ??= "https://json-schema.org/draft/2020-12/schema";
36
+ return schema_record;
37
+ }
38
+ const root_name = root_ref.slice("#/$defs/".length);
39
+ const root_schema = definitions[root_name];
40
+ if (!isJsonSchemaObject(root_schema)) {
41
+ schema_record.$schema ??= "https://json-schema.org/draft/2020-12/schema";
42
+ return schema_record;
43
+ }
44
+ const rewritten_root = rewriteJsonSchemaRefs(root_schema, { [root_ref]: "#" });
45
+ const remaining_defs = Object.fromEntries(Object.entries(definitions).filter(([name]) => name !== root_name));
46
+ if (Object.keys(remaining_defs).length > 0) {
47
+ rewritten_root.$defs = rewriteJsonSchemaRefs(remaining_defs, { [root_ref]: "#" });
48
+ }
49
+ rewritten_root.$schema ??= schema_record.$schema ?? "https://json-schema.org/draft/2020-12/schema";
50
+ setTitleFromInlinedRootDefinition(rewritten_root, root_name);
51
+ return rewritten_root;
52
+ };
53
+ const rootRefForSchema = (schema, definitions) => {
54
+ if (typeof schema.$ref === "string" && schema.$ref.startsWith("#/$defs/")) {
55
+ return schema.$ref;
56
+ }
57
+ if (!definitions) {
58
+ return null;
59
+ }
60
+ const root = schemaWithoutSchemaAndDefinitions(schema);
61
+ for (const [name, definition] of Object.entries(definitions)) {
62
+ if (JSON.stringify(definition) === JSON.stringify(root)) {
63
+ return `#/$defs/${name}`;
64
+ }
65
+ }
66
+ return null;
67
+ };
68
+ const schemaWithoutSchemaAndDefinitions = (schema) => {
69
+ const root = {};
70
+ for (const [key, value] of Object.entries(schema)) {
71
+ if (key !== "$schema" && key !== "$defs") {
72
+ root[key] = value;
73
+ }
74
+ }
75
+ return root;
76
+ };
77
+ const setTitleFromInlinedRootDefinition = (schema, root_name) => {
78
+ if (root_name.startsWith("__schema")) return;
79
+ schema.title ??= root_name;
80
+ };
81
+ const rewriteJsonSchemaRefs = (schema, refs) => {
82
+ if (Array.isArray(schema)) {
83
+ return schema.map((item) => rewriteJsonSchemaRefs(item, refs));
84
+ }
85
+ if (!isJsonSchemaObject(schema)) {
86
+ return schema;
87
+ }
88
+ const rewritten = {};
89
+ for (const [key, value] of Object.entries(schema)) {
90
+ rewritten[key] = rewriteJsonSchemaRefs(value, refs);
91
+ }
92
+ if (typeof rewritten.$ref === "string" && rewritten.$ref in refs) {
93
+ rewritten.$ref = refs[rewritten.$ref];
94
+ }
95
+ return rewritten;
96
+ };
97
+ const normalizeJsonSchemaValue = (schema) => {
98
+ if (Array.isArray(schema)) {
99
+ return schema.map((item) => normalizeJsonSchemaValue(item));
100
+ }
101
+ if (!isJsonSchemaObject(schema)) {
102
+ return schema;
103
+ }
104
+ const normalized = {};
105
+ for (const [key, value] of Object.entries(schema)) {
106
+ normalized[key] = normalizeJsonSchemaValue(value);
107
+ }
108
+ if (Array.isArray(normalized.required) && normalized.required.every((item) => typeof item === "string")) {
109
+ normalized.required = [...normalized.required].sort();
110
+ }
111
+ const null_union_candidates = nullUnionCandidates(normalized);
112
+ if (null_union_candidates !== null) {
113
+ const merged = { anyOf: normalizeJsonSchemaValue(null_union_candidates) };
114
+ for (const [key, value] of Object.entries(normalized)) {
115
+ if (key !== "type") {
116
+ merged[key] = value;
117
+ }
118
+ }
119
+ return merged;
120
+ }
121
+ return normalized;
122
+ };
123
+ const toJsonSchema = (schema) => {
124
+ return normalizeJsonSchema(z.toJSONSchema(schema));
125
+ };
126
+ const fromJsonSchema = (schema) => {
127
+ return z.fromJSONSchema(schema);
128
+ };
129
+ export {
130
+ fromJsonSchema,
131
+ isJsonSchema,
132
+ normalizeJsonSchema,
133
+ toJsonSchema
134
+ };
135
+ //# sourceMappingURL=jsonschema.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/jsonschema.ts"],
4
+ "sourcesContent": ["import { z } from 'zod'\n\nexport type JsonSchema = boolean | z.core.JSONSchema.JSONSchema\ntype JsonSchemaObject = z.core.JSONSchema.JSONSchema\n\nconst isJsonSchemaObject = (value: unknown): value is JsonSchemaObject => {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nexport const isJsonSchema = (value: unknown): value is JsonSchema => {\n if (typeof value === 'boolean') {\n return true\n }\n if (!isJsonSchemaObject(value)) {\n return false\n }\n if ('_zod' in value || '_def' in value || '~standard' in value) {\n return false\n }\n return true\n}\n\nconst nullUnionCandidates = (schema: Record<string, unknown>): Record<string, unknown>[] | null => {\n if (Array.isArray(schema.type) && schema.type.includes('null')) {\n const non_null_types = schema.type.filter((item): item is string => typeof item === 'string' && item !== 'null')\n if (non_null_types.length > 0) {\n return [{ type: non_null_types.length === 1 ? non_null_types[0] : non_null_types }, { type: 'null' }]\n }\n }\n\n return null\n}\n\nexport const normalizeJsonSchema = (schema: JsonSchema): JsonSchema => {\n const normalized = normalizeJsonSchemaValue(schema)\n if (!isJsonSchemaObject(normalized)) {\n return normalized as JsonSchema\n }\n const schema_record = { ...normalized } as JsonSchemaObject\n const definitions = schema_record.$defs\n const root_ref = rootRefForSchema(schema_record, definitions)\n if (!root_ref || !definitions) {\n schema_record.$schema ??= 'https://json-schema.org/draft/2020-12/schema'\n return schema_record\n }\n const root_name = root_ref.slice('#/$defs/'.length)\n const root_schema = definitions[root_name]\n if (!isJsonSchemaObject(root_schema)) {\n schema_record.$schema ??= 'https://json-schema.org/draft/2020-12/schema'\n return schema_record\n }\n const rewritten_root = rewriteJsonSchemaRefs(root_schema, { [root_ref]: '#' }) as JsonSchemaObject\n const remaining_defs = Object.fromEntries(Object.entries(definitions).filter(([name]) => name !== root_name))\n if (Object.keys(remaining_defs).length > 0) {\n rewritten_root.$defs = rewriteJsonSchemaRefs(remaining_defs, { [root_ref]: '#' }) as Record<string, JsonSchemaObject>\n }\n rewritten_root.$schema ??= schema_record.$schema ?? 'https://json-schema.org/draft/2020-12/schema'\n setTitleFromInlinedRootDefinition(rewritten_root, root_name)\n return rewritten_root\n}\n\nconst rootRefForSchema = (schema: JsonSchemaObject, definitions: Record<string, JsonSchemaObject> | undefined): string | null => {\n if (typeof schema.$ref === 'string' && schema.$ref.startsWith('#/$defs/')) {\n return schema.$ref\n }\n if (!definitions) {\n return null\n }\n const root = schemaWithoutSchemaAndDefinitions(schema)\n for (const [name, definition] of Object.entries(definitions)) {\n if (JSON.stringify(definition) === JSON.stringify(root)) {\n return `#/$defs/${name}`\n }\n }\n return null\n}\n\nconst schemaWithoutSchemaAndDefinitions = (schema: JsonSchemaObject): Record<string, unknown> => {\n const root: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(schema)) {\n if (key !== '$schema' && key !== '$defs') {\n root[key] = value\n }\n }\n return root\n}\n\nconst setTitleFromInlinedRootDefinition = (schema: JsonSchemaObject, root_name: string): void => {\n if (root_name.startsWith('__schema')) return\n schema.title ??= root_name\n}\n\nconst rewriteJsonSchemaRefs = (schema: unknown, refs: Record<string, string>): unknown => {\n if (Array.isArray(schema)) {\n return schema.map((item) => rewriteJsonSchemaRefs(item, refs))\n }\n if (!isJsonSchemaObject(schema)) {\n return schema\n }\n const rewritten: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(schema)) {\n rewritten[key] = rewriteJsonSchemaRefs(value, refs)\n }\n if (typeof rewritten.$ref === 'string' && rewritten.$ref in refs) {\n rewritten.$ref = refs[rewritten.$ref]\n }\n return rewritten\n}\n\nconst normalizeJsonSchemaValue = (schema: unknown): unknown => {\n if (Array.isArray(schema)) {\n return schema.map((item) => normalizeJsonSchemaValue(item))\n }\n if (!isJsonSchemaObject(schema)) {\n return schema\n }\n\n const normalized: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(schema)) {\n normalized[key] = normalizeJsonSchemaValue(value)\n }\n if (Array.isArray(normalized.required) && normalized.required.every((item) => typeof item === 'string')) {\n normalized.required = [...normalized.required].sort()\n }\n\n const null_union_candidates = nullUnionCandidates(normalized)\n if (null_union_candidates !== null) {\n const merged: Record<string, unknown> = { anyOf: normalizeJsonSchemaValue(null_union_candidates) }\n for (const [key, value] of Object.entries(normalized)) {\n if (key !== 'type') {\n merged[key] = value\n }\n }\n return merged\n }\n\n return normalized\n}\n\nexport const toJsonSchema = (schema: z.core.$ZodType): JsonSchema => {\n return normalizeJsonSchema(z.toJSONSchema(schema) as JsonSchema)\n}\n\nexport const fromJsonSchema = (schema: JsonSchema): z.ZodTypeAny => {\n return z.fromJSONSchema(schema)\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAKlB,MAAM,qBAAqB,CAAC,UAA8C;AACxE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEO,MAAM,eAAe,CAAC,UAAwC;AACnE,MAAI,OAAO,UAAU,WAAW;AAC9B,WAAO;AAAA,EACT;AACA,MAAI,CAAC,mBAAmB,KAAK,GAAG;AAC9B,WAAO;AAAA,EACT;AACA,MAAI,UAAU,SAAS,UAAU,SAAS,eAAe,OAAO;AAC9D,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,MAAM,sBAAsB,CAAC,WAAsE;AACjG,MAAI,MAAM,QAAQ,OAAO,IAAI,KAAK,OAAO,KAAK,SAAS,MAAM,GAAG;AAC9D,UAAM,iBAAiB,OAAO,KAAK,OAAO,CAAC,SAAyB,OAAO,SAAS,YAAY,SAAS,MAAM;AAC/G,QAAI,eAAe,SAAS,GAAG;AAC7B,aAAO,CAAC,EAAE,MAAM,eAAe,WAAW,IAAI,eAAe,CAAC,IAAI,eAAe,GAAG,EAAE,MAAM,OAAO,CAAC;AAAA,IACtG;AAAA,EACF;AAEA,SAAO;AACT;AAEO,MAAM,sBAAsB,CAAC,WAAmC;AACrE,QAAM,aAAa,yBAAyB,MAAM;AAClD,MAAI,CAAC,mBAAmB,UAAU,GAAG;AACnC,WAAO;AAAA,EACT;AACA,QAAM,gBAAgB,EAAE,GAAG,WAAW;AACtC,QAAM,cAAc,cAAc;AAClC,QAAM,WAAW,iBAAiB,eAAe,WAAW;AAC5D,MAAI,CAAC,YAAY,CAAC,aAAa;AAC7B,kBAAc,YAAY;AAC1B,WAAO;AAAA,EACT;AACA,QAAM,YAAY,SAAS,MAAM,WAAW,MAAM;AAClD,QAAM,cAAc,YAAY,SAAS;AACzC,MAAI,CAAC,mBAAmB,WAAW,GAAG;AACpC,kBAAc,YAAY;AAC1B,WAAO;AAAA,EACT;AACA,QAAM,iBAAiB,sBAAsB,aAAa,EAAE,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC7E,QAAM,iBAAiB,OAAO,YAAY,OAAO,QAAQ,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,MAAM,SAAS,SAAS,CAAC;AAC5G,MAAI,OAAO,KAAK,cAAc,EAAE,SAAS,GAAG;AAC1C,mBAAe,QAAQ,sBAAsB,gBAAgB,EAAE,CAAC,QAAQ,GAAG,IAAI,CAAC;AAAA,EAClF;AACA,iBAAe,YAAY,cAAc,WAAW;AACpD,oCAAkC,gBAAgB,SAAS;AAC3D,SAAO;AACT;AAEA,MAAM,mBAAmB,CAAC,QAA0B,gBAA6E;AAC/H,MAAI,OAAO,OAAO,SAAS,YAAY,OAAO,KAAK,WAAW,UAAU,GAAG;AACzE,WAAO,OAAO;AAAA,EAChB;AACA,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AACA,QAAM,OAAO,kCAAkC,MAAM;AACrD,aAAW,CAAC,MAAM,UAAU,KAAK,OAAO,QAAQ,WAAW,GAAG;AAC5D,QAAI,KAAK,UAAU,UAAU,MAAM,KAAK,UAAU,IAAI,GAAG;AACvD,aAAO,WAAW,IAAI;AAAA,IACxB;AAAA,EACF;AACA,SAAO;AACT;AAEA,MAAM,oCAAoC,CAAC,WAAsD;AAC/F,QAAM,OAAgC,CAAC;AACvC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,QAAI,QAAQ,aAAa,QAAQ,SAAS;AACxC,WAAK,GAAG,IAAI;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;AAEA,MAAM,oCAAoC,CAAC,QAA0B,cAA4B;AAC/F,MAAI,UAAU,WAAW,UAAU,EAAG;AACtC,SAAO,UAAU;AACnB;AAEA,MAAM,wBAAwB,CAAC,QAAiB,SAA0C;AACxF,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,OAAO,IAAI,CAAC,SAAS,sBAAsB,MAAM,IAAI,CAAC;AAAA,EAC/D;AACA,MAAI,CAAC,mBAAmB,MAAM,GAAG;AAC/B,WAAO;AAAA,EACT;AACA,QAAM,YAAqC,CAAC;AAC5C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,cAAU,GAAG,IAAI,sBAAsB,OAAO,IAAI;AAAA,EACpD;AACA,MAAI,OAAO,UAAU,SAAS,YAAY,UAAU,QAAQ,MAAM;AAChE,cAAU,OAAO,KAAK,UAAU,IAAI;AAAA,EACtC;AACA,SAAO;AACT;AAEA,MAAM,2BAA2B,CAAC,WAA6B;AAC7D,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,OAAO,IAAI,CAAC,SAAS,yBAAyB,IAAI,CAAC;AAAA,EAC5D;AACA,MAAI,CAAC,mBAAmB,MAAM,GAAG;AAC/B,WAAO;AAAA,EACT;AAEA,QAAM,aAAsC,CAAC;AAC7C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,eAAW,GAAG,IAAI,yBAAyB,KAAK;AAAA,EAClD;AACA,MAAI,MAAM,QAAQ,WAAW,QAAQ,KAAK,WAAW,SAAS,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ,GAAG;AACvG,eAAW,WAAW,CAAC,GAAG,WAAW,QAAQ,EAAE,KAAK;AAAA,EACtD;AAEA,QAAM,wBAAwB,oBAAoB,UAAU;AAC5D,MAAI,0BAA0B,MAAM;AAClC,UAAM,SAAkC,EAAE,OAAO,yBAAyB,qBAAqB,EAAE;AACjG,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,UAAU,GAAG;AACrD,UAAI,QAAQ,QAAQ;AAClB,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,MAAM,eAAe,CAAC,WAAwC;AACnE,SAAO,oBAAoB,EAAE,aAAa,MAAM,CAAe;AACjE;AAEO,MAAM,iBAAiB,CAAC,WAAqC;AAClE,SAAO,EAAE,eAAe,MAAM;AAChC;",
6
+ "names": []
7
+ }
package/dist/esm/retry.js CHANGED
@@ -2,6 +2,8 @@ import { createAsyncLocalStorage } from "./async_context.js";
2
2
  import { isNodeRuntime } from "./optional_deps.js";
3
3
  const MULTIPROCESS_SEMAPHORE_DIRNAME = "browser_use_semaphores";
4
4
  const MULTIPROCESS_STALE_LOCK_MS = 5 * 60 * 1e3;
5
+ const RETRY_SLOW_WARNING_THROTTLE_MS = 2e3;
6
+ const RETRY_SLOW_WARNING_ARGS_MAX_LENGTH = 80;
5
7
  let multiprocess_fallback_reason_logged = null;
6
8
  class RetryTimeoutError extends Error {
7
9
  timeout_seconds;
@@ -107,16 +109,20 @@ function retry(options = {}) {
107
109
  retry_backoff_factor = 1,
108
110
  retry_on_errors,
109
111
  timeout,
112
+ slow_timeout,
110
113
  semaphore_limit,
111
114
  semaphore_name: semaphore_name_option,
112
115
  semaphore_lax = true,
113
116
  semaphore_scope = "global",
114
117
  semaphore_timeout
115
118
  } = options;
116
- const decorateFunction = (target, _context) => {
117
- const fn_name = target.name || _context?.name || "anonymous";
119
+ const decorateFunction = (target, _context, owner_name) => {
120
+ const base_fn_name = target.name || _context?.name || "anonymous";
121
+ let fn_name = owner_name ? `${owner_name}.${base_fn_name}` : base_fn_name;
118
122
  const effective_max_attempts = Math.max(1, max_attempts);
119
123
  const effective_retry_after = Math.max(0, retry_after);
124
+ const effective_slow_timeout_ms = slow_timeout != null && slow_timeout > 0 ? slow_timeout * 1e3 : null;
125
+ let last_slow_warning_at = 0;
120
126
  const shouldRetry = (error) => {
121
127
  if (!retry_on_errors || retry_on_errors.length === 0) return true;
122
128
  return retry_on_errors.some(
@@ -135,6 +141,13 @@ function retry(options = {}) {
135
141
  sleepSync(delay_seconds * 1e3);
136
142
  }
137
143
  };
144
+ const emitSlowWarningIfDue = (args, start_time) => {
145
+ if (effective_slow_timeout_ms == null) return;
146
+ const now = Date.now();
147
+ if (now - last_slow_warning_at < RETRY_SLOW_WARNING_THROTTLE_MS) return;
148
+ last_slow_warning_at = now;
149
+ console.warn(`Warning: ${fn_name}(${formatRetrySlowWarningArgs(args)}) slow (${((now - start_time) / 1e3).toFixed(1)}s)`);
150
+ };
138
151
  const runRetryLoopFromThenable = async (this_arg, args, first_thenable, first_attempt) => {
139
152
  let current_result = first_thenable;
140
153
  for (let attempt = first_attempt; attempt <= effective_max_attempts; attempt++) {
@@ -214,20 +227,35 @@ function retry(options = {}) {
214
227
  new_held.add(scoped_key);
215
228
  }
216
229
  const runRetryLoop = async () => {
217
- for (let attempt = 1; attempt <= effective_max_attempts; attempt++) {
218
- try {
219
- if (timeout != null && timeout > 0) {
220
- return await _runWithTimeout(() => Promise.resolve(target.apply(this, args)), timeout * 1e3, attempt);
221
- } else {
222
- return await Promise.resolve(target.apply(this, args));
230
+ const call_started_at = Date.now();
231
+ const warning_args = [...args];
232
+ const slow_warning_timer = effective_slow_timeout_ms == null ? null : setTimeout(() => emitSlowWarningIfDue(warning_args, call_started_at), effective_slow_timeout_ms);
233
+ const finishSlowWarning = () => {
234
+ if (slow_warning_timer !== null) {
235
+ clearTimeout(slow_warning_timer);
236
+ }
237
+ if (effective_slow_timeout_ms != null && Date.now() - call_started_at >= effective_slow_timeout_ms) {
238
+ emitSlowWarningIfDue(warning_args, call_started_at);
239
+ }
240
+ };
241
+ try {
242
+ for (let attempt = 1; attempt <= effective_max_attempts; attempt++) {
243
+ try {
244
+ if (timeout != null && timeout > 0) {
245
+ return await _runWithTimeout(() => Promise.resolve(target.apply(this, args)), timeout * 1e3, attempt);
246
+ } else {
247
+ return await Promise.resolve(target.apply(this, args));
248
+ }
249
+ } catch (error) {
250
+ if (!shouldRetry(error)) throw error;
251
+ if (attempt >= effective_max_attempts) throw error;
252
+ await asyncRetryDelay(attempt);
223
253
  }
224
- } catch (error) {
225
- if (!shouldRetry(error)) throw error;
226
- if (attempt >= effective_max_attempts) throw error;
227
- await asyncRetryDelay(attempt);
228
254
  }
255
+ throw new Error(`retry(${fn_name}): unexpected end of retry loop`);
256
+ } finally {
257
+ finishSlowWarning();
229
258
  }
230
- throw new Error(`retry(${fn_name}): unexpected end of retry loop`);
231
259
  };
232
260
  try {
233
261
  return await runWithHeldSemaphores(new_held, runRetryLoop);
@@ -277,27 +305,48 @@ function retry(options = {}) {
277
305
  }
278
306
  };
279
307
  const runRetryLoop = () => {
280
- for (let attempt = 1; attempt <= effective_max_attempts; attempt++) {
281
- const attempt_started_at = Date.now();
282
- try {
283
- const result = target.apply(this, args);
284
- if (isThenable(result)) {
285
- return runRetryLoopFromThenable(this, args, result, attempt);
286
- }
287
- if (timeout != null && timeout > 0 && Date.now() - attempt_started_at > timeout * 1e3) {
288
- throw new RetryTimeoutError(`Timed out after ${timeout}s (attempt ${attempt})`, {
289
- timeout_seconds: timeout,
290
- attempt
291
- });
308
+ const call_started_at = Date.now();
309
+ const warning_args = [...args];
310
+ const slow_warning_timer = effective_slow_timeout_ms == null ? null : setTimeout(() => emitSlowWarningIfDue(warning_args, call_started_at), effective_slow_timeout_ms);
311
+ const finishSlowWarning = () => {
312
+ if (slow_warning_timer !== null) {
313
+ clearTimeout(slow_warning_timer);
314
+ }
315
+ if (effective_slow_timeout_ms != null && Date.now() - call_started_at >= effective_slow_timeout_ms) {
316
+ emitSlowWarningIfDue(warning_args, call_started_at);
317
+ }
318
+ };
319
+ let finish_on_return = true;
320
+ try {
321
+ for (let attempt = 1; attempt <= effective_max_attempts; attempt++) {
322
+ const attempt_started_at = Date.now();
323
+ try {
324
+ const result = target.apply(this, args);
325
+ if (isThenable(result)) {
326
+ finish_on_return = false;
327
+ return runRetryLoopFromThenable(this, args, result, attempt).finally(finishSlowWarning);
328
+ }
329
+ if (timeout != null && timeout > 0 && Date.now() - attempt_started_at > timeout * 1e3) {
330
+ throw new RetryTimeoutError(`Timed out after ${timeout}s (attempt ${attempt})`, {
331
+ timeout_seconds: timeout,
332
+ attempt
333
+ });
334
+ }
335
+ return result;
336
+ } catch (error) {
337
+ if (!shouldRetry(error)) throw error;
338
+ if (attempt >= effective_max_attempts) {
339
+ throw error;
340
+ }
341
+ syncRetryDelay(attempt);
292
342
  }
293
- return result;
294
- } catch (error) {
295
- if (!shouldRetry(error)) throw error;
296
- if (attempt >= effective_max_attempts) throw error;
297
- syncRetryDelay(attempt);
343
+ }
344
+ throw new Error(`retry(${fn_name}): unexpected end of retry loop`);
345
+ } finally {
346
+ if (finish_on_return) {
347
+ finishSlowWarning();
298
348
  }
299
349
  }
300
- throw new Error(`retry(${fn_name}): unexpected end of retry loop`);
301
350
  };
302
351
  try {
303
352
  const result = runWithHeldSemaphores(new_held, runRetryLoop);
@@ -315,9 +364,10 @@ function retry(options = {}) {
315
364
  Object.defineProperty(retryWrapper, "name", { value: fn_name, configurable: true });
316
365
  if (_context?.kind === "method" && typeof _context.addInitializer === "function") {
317
366
  _context.addInitializer(function() {
318
- const owner_name = findDecoratedMethodOwnerName(this, _context, retryWrapper);
319
- if (owner_name) {
320
- Object.defineProperty(retryWrapper, "name", { value: `${owner_name}.${fn_name}`, configurable: true });
367
+ const owner_name2 = findDecoratedMethodOwnerName(this, _context, retryWrapper);
368
+ if (owner_name2) {
369
+ fn_name = `${owner_name2}.${target.name || _context.name || "anonymous"}`;
370
+ Object.defineProperty(retryWrapper, "name", { value: fn_name, configurable: true });
321
371
  }
322
372
  });
323
373
  }
@@ -325,7 +375,8 @@ function retry(options = {}) {
325
375
  };
326
376
  function decorator(target, context_or_property_key, descriptor) {
327
377
  if (descriptor?.value && typeof descriptor.value === "function") {
328
- descriptor.value = decorateFunction(descriptor.value);
378
+ const owner_name = target && (typeof target === "object" || typeof target === "function") ? typeof target === "function" ? target.name : target.constructor?.name : null;
379
+ descriptor.value = decorateFunction(descriptor.value, void 0, owner_name);
329
380
  return descriptor;
330
381
  }
331
382
  if (typeof target === "function") {
@@ -372,6 +423,30 @@ function isAsyncFunction(fn) {
372
423
  function isThenable(value) {
373
424
  return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
374
425
  }
426
+ function formatRetrySlowWarningArgs(args) {
427
+ const preview = args.map(formatRetrySlowWarningValue).join(", ");
428
+ if (preview.length > RETRY_SLOW_WARNING_ARGS_MAX_LENGTH) {
429
+ return `${preview.slice(0, RETRY_SLOW_WARNING_ARGS_MAX_LENGTH - 3).replace(/,?\s*$/, "")}...`;
430
+ }
431
+ return preview;
432
+ }
433
+ function formatRetrySlowWarningValue(value) {
434
+ let text;
435
+ if (typeof value === "string") {
436
+ text = value;
437
+ } else if (value === null || value === void 0) {
438
+ text = String(value);
439
+ } else if (typeof value === "object") {
440
+ try {
441
+ text = JSON.stringify(value);
442
+ } catch {
443
+ text = String(value);
444
+ }
445
+ } else {
446
+ text = String(value);
447
+ }
448
+ return text.replace(/['"]/g, "").slice(0, 3);
449
+ }
375
450
  async function acquireWithTimeout(semaphore, timeout_ms) {
376
451
  return new Promise((resolve) => {
377
452
  let settled = false;