aveazul 2.1.7 → 2.1.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.
package/README.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # AveAzul.js
2
2
 
3
+ [![License][license-image]][license-url]
4
+ [![build][build-image]][build-url]
5
+
6
+ [![Downloads][downloads-image]][downloads-url]
7
+
8
+ [![npm badge][npm-badge-png]][package-url]
9
+
10
+ - [API reference](https://fynjs.pages.dev/api/modules/aveazul) - TypeDoc
11
+ - [Markdown reference](docs/reference.md) - the full API and runtime behavior in one file. Also ships in the package.
12
+ - [GitHub](https://github.com/jchip/fynjs/tree/main/packages/aveazul)
13
+
3
14
  AveAzul ("Blue Bird" in Spanish) serves as a near drop-in replacement for Bluebird. It's built on native Promise, by extending it with the familiar utility methods from Bluebird.
4
15
 
5
16
  ## Purpose
@@ -148,6 +159,7 @@ Key differences to be aware of:
148
159
  - `call(propertyName, ...args)` - Call a method on the resolved value with the provided arguments
149
160
  - `asCallback(callback, options?)` - Register a Node-style callback that handles the resolution or rejection
150
161
  - `error(handler)` - Like catch(), but only catches operational errors, letting programmer errors bubble up
162
+ - `catch(filter..., handler)` - Filtered catch: handle only errors matching an Error class, a predicate function, or an object of properties; others are rethrown
151
163
 
152
164
  ### Static Methods
153
165
 
@@ -161,6 +173,7 @@ Key differences to be aware of:
161
173
  - `fromNode(fn, options?)` - Convert Node-style callback functions to promise-returning functions
162
174
  - `fromCallback(fn, options?)` - Alias for fromNode
163
175
  - `each(items, fn)` - Iterate over array elements
176
+ - `filter(items, fn)` - Filter array elements
164
177
  - `reduce(array, fn, initialValue?)` - Reduce array elements
165
178
  - `some(promises, count)` - Wait for a specified number of promises to be fulfilled
166
179
  - `method(fn)` - Creates a method that returns a promise resolving to the value returned by the original function
@@ -206,3 +219,12 @@ Apache-2.0
206
219
  ## Author
207
220
 
208
221
  Joel Chen, with assistant from Cursor Claude-3.7-sonnet
222
+
223
+ [license-image]: https://img.shields.io/npm/l/aveazul.svg
224
+ [license-url]: LICENSE
225
+ [build-image]: https://github.com/jchip/fynjs/actions/workflows/ci.yml/badge.svg
226
+ [build-url]: https://github.com/jchip/fynjs/actions/workflows/ci.yml
227
+ [downloads-image]: https://img.shields.io/npm/dm/aveazul.svg
228
+ [downloads-url]: https://npm-stat.com/charts.html?package=aveazul
229
+ [npm-badge-png]: https://nodei.co/npm/aveazul.png?downloads=true&stars=true
230
+ [package-url]: https://npmjs.com/package/aveazul
package/cjs-entry.cjs CHANGED
@@ -3,5 +3,12 @@
3
3
  // ESM-only build; this shim keeps `require("aveazul")` returning the AveAzul class,
4
4
  // because require(esm) yields the module namespace rather than the default export.
5
5
  const m = require("./dist/index.js");
6
+ const AveAzul = m.default;
6
7
 
7
- module.exports = Object.assign(m.default, m);
8
+ // Add the other named exports without overwriting class statics. The named
9
+ // `promisify`/`promisifyAll` return native promises; the class ones must win.
10
+ for (const key of Object.keys(m)) {
11
+ if (!(key in AveAzul)) AveAzul[key] = m[key];
12
+ }
13
+
14
+ module.exports = AveAzul;
package/dist/aveazul.d.ts CHANGED
@@ -6,6 +6,8 @@ import { OperationalError, isOperationalError, isProgrammerError } from "./opera
6
6
  export interface MapOptions {
7
7
  concurrency?: number;
8
8
  }
9
+ /** A `.catch()` filter: an Error class, a predicate, or an object of properties to match. */
10
+ export type CatchFilter = (new (...args: any[]) => Error) | ((error: any) => unknown) | object;
9
11
  export interface AsCallbackOptions {
10
12
  spread?: boolean;
11
13
  }
@@ -32,6 +34,7 @@ export interface AveAzulClass {
32
34
  }>;
33
35
  defer<T>(): Deferred<T>;
34
36
  each<T>(items: Iterable<T | PromiseLike<T>>, fn: (item: T, index: number, length: number) => unknown): AveAzul<T[]>;
37
+ filter<T>(items: Iterable<T | PromiseLike<T>>, fn: (item: T, index: number, length: number) => unknown): AveAzul<T[]>;
35
38
  reduce<T, U>(array: Iterable<T | PromiseLike<T>>, fn: (value: U, item: T, index: number, length: number) => U | PromiseLike<U>, initialValue?: U): AveAzul<U>;
36
39
  promisify<T = unknown>(fn: (...args: any[]) => void, options?: PromisifyOptions): (...args: any[]) => AveAzul<T>;
37
40
  promisifyAll<T extends object>(target: T, options?: PromisifyAllOptions): T;
@@ -89,8 +92,15 @@ declare class AveAzul<T> extends Promise<T> {
89
92
  * AveAzul is itself a Promise - await and interop are unaffected.
90
93
  */
91
94
  then: <TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null) => AveAzul<TResult1 | TResult2>;
92
- catch: <TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null) => AveAzul<T | TResult>;
93
95
  finally: (onfinally?: (() => void) | undefined | null) => AveAzul<T>;
96
+ /**
97
+ * Bluebird-style filtered catch: `.catch(filter..., handler)`.
98
+ * A filter is an Error class (instanceof), a predicate function, or an object
99
+ * whose own properties must equal the error's. Unmatched errors are rethrown.
100
+ * With a single argument it is the native catch.
101
+ */
102
+ catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): AveAzul<T | TResult>;
103
+ catch<TResult = never>(...filtersAndHandler: [...CatchFilter[], (reason: any) => TResult | PromiseLike<TResult>]): AveAzul<T | TResult>;
94
104
  /**
95
105
  * Bluebird-style tap() method that lets you perform side effects in a chain
96
106
  * Similar to Bluebird's Promise.prototype.tap()
@@ -289,6 +299,13 @@ declare class AveAzul<T> extends Promise<T> {
289
299
  * @returns Promise that resolves when iteration is complete
290
300
  */
291
301
  static each<T>(items: Iterable<T | PromiseLike<T>>, fn: (item: T, index: number, length: number) => unknown): AveAzul<T[]>;
302
+ /**
303
+ * Bluebird-style filter() for array filtering
304
+ * @param items - Array or iterable to filter
305
+ * @param fn - Filter function (item, index, length)
306
+ * @returns Promise that resolves with the items that passed the filter
307
+ */
308
+ static filter<T>(items: Iterable<T | PromiseLike<T>>, fn: (item: T, index: number, length: number) => unknown): AveAzul<T[]>;
292
309
  /**
293
310
  * Bluebird-style reduce() for array reduction
294
311
  * @param array - Array to reduce
package/dist/aveazul.js CHANGED
@@ -17,6 +17,34 @@ class AveAzul extends Promise {
17
17
  constructor(executor) {
18
18
  super(executor);
19
19
  }
20
+ catch(...args) {
21
+ if (args.length <= 1) {
22
+ return super.catch(args[0]);
23
+ }
24
+ const handler = args.pop();
25
+ if (typeof handler !== "function") {
26
+ throw new TypeError("The last argument to .catch() must be a function, got " + String(handler));
27
+ }
28
+ const filters = args;
29
+ return super.catch((err) => {
30
+ for (const f of filters) {
31
+ if (f === Error || (f != null && f.prototype instanceof Error)) {
32
+ if (err instanceof f)
33
+ return handler(err);
34
+ }
35
+ else if (typeof f === "function") {
36
+ if (f(err))
37
+ return handler(err);
38
+ }
39
+ else if (err !== null && (typeof err === "object" || typeof err === "function")) {
40
+ // loose equality, as Bluebird does
41
+ if (Object.keys(f).every((k) => f[k] == err[k]))
42
+ return handler(err);
43
+ }
44
+ }
45
+ throw err;
46
+ });
47
+ }
20
48
  /**
21
49
  * Bluebird-style tap() method that lets you perform side effects in a chain
22
50
  * Similar to Bluebird's Promise.prototype.tap()
@@ -36,7 +64,18 @@ class AveAzul extends Promise {
36
64
  * @returns Promise that resolves with the filtered array
37
65
  */
38
66
  filter(fn) {
39
- return this.then((value) => xaa.filter(value, fn));
67
+ return this.then(async (value) => {
68
+ const arr = toArray(value);
69
+ const len = arr.length;
70
+ const result = [];
71
+ for (let i = 0; i < len; i++) {
72
+ const x = isPromise(arr[i]) ? await arr[i] : arr[i];
73
+ if (await fn(x, i, len)) {
74
+ result.push(x);
75
+ }
76
+ }
77
+ return result;
78
+ });
40
79
  }
41
80
  /**
42
81
  * Bluebird-style map() method for array operations
@@ -45,7 +84,12 @@ class AveAzul extends Promise {
45
84
  * @returns Promise that resolves with the mapped array
46
85
  */
47
86
  map(fn, options = { concurrency: 50 }) {
48
- return this.then((value) => xaa.map(value, fn, options));
87
+ return this.then((value) => {
88
+ const arr = toArray(value);
89
+ const len = arr.length;
90
+ // xaa passes a context object as the third argument; Bluebird passes the length
91
+ return xaa.map(arr, (item, index) => fn(item, index, len), options);
92
+ });
49
93
  }
50
94
  /**
51
95
  * Bluebird-style mapSeries() method for array operations
@@ -82,7 +126,7 @@ class AveAzul extends Promise {
82
126
  */
83
127
  each(fn) {
84
128
  return this.then(async (value) => {
85
- const arr = value;
129
+ const arr = toArray(value);
86
130
  const result = [];
87
131
  for (let i = 0; i < arr.length; i++) {
88
132
  let x = arr[i];
@@ -156,7 +200,7 @@ class AveAzul extends Promise {
156
200
  reduce(fn, initialValue) {
157
201
  const hasInitial = arguments.length > 1;
158
202
  return this.then(async (array) => {
159
- const arr = array;
203
+ const arr = toArray(array);
160
204
  const len = arr.length;
161
205
  let value;
162
206
  let idx;
@@ -238,12 +282,13 @@ class AveAzul extends Promise {
238
282
  }
239
283
  return this.then(async (args) => {
240
284
  if (Array.isArray(args)) {
241
- for (let i = 0; i < args.length; i++) {
242
- if (isPromise(args[i])) {
243
- args[i] = await args[i];
285
+ const values = args.slice();
286
+ for (let i = 0; i < values.length; i++) {
287
+ if (isPromise(values[i])) {
288
+ values[i] = await values[i];
244
289
  }
245
290
  }
246
- return fn(...args);
291
+ return fn(...values);
247
292
  }
248
293
  else {
249
294
  return fn(args);
@@ -459,6 +504,15 @@ class AveAzul extends Promise {
459
504
  static each(items, fn) {
460
505
  return AveAzul.resolve(items).each(fn);
461
506
  }
507
+ /**
508
+ * Bluebird-style filter() for array filtering
509
+ * @param items - Array or iterable to filter
510
+ * @param fn - Filter function (item, index, length)
511
+ * @returns Promise that resolves with the items that passed the filter
512
+ */
513
+ static filter(items, fn) {
514
+ return AveAzul.resolve(items).filter(fn);
515
+ }
462
516
  /**
463
517
  * Bluebird-style reduce() for array reduction
464
518
  * @param array - Array to reduce
@@ -524,7 +578,7 @@ class AveAzul extends Promise {
524
578
  */
525
579
  static using(resources, ...args) {
526
580
  if (args.length === 0) {
527
- throw new TypeError("resrouces and handler function required");
581
+ throw new TypeError("resources and handler function required");
528
582
  }
529
583
  if (Array.isArray(resources)) {
530
584
  if (args.length > 1) {
@@ -0,0 +1,506 @@
1
+ # aveazul reference
2
+
3
+ `aveazul` is a Bluebird-style drop-in layer on top of native `Promise`. `AveAzul<T>` is a class that `extends Promise<T>`, so `then`, `catch`, `finally`, `race`, `allSettled` and the rest are the native implementations, and `await` and interop work unchanged. Runtime dependencies: `xaa` (map, filter, delay, timeout, defer, wrap) and `@jchip/error` (`AggregateError`). The package is ESM (`"type": "module"`) with a CJS shim.
4
+
5
+ ## Imports
6
+
7
+ ```js
8
+ // ESM
9
+ import AveAzul from "aveazul";
10
+ import { AveAzul, Disposer, OperationalError, isOperationalError, isProgrammerError, promisify, promisifyAll } from "aveazul";
11
+
12
+ // CJS
13
+ const AveAzul = require("aveazul");
14
+ ```
15
+
16
+ ESM runtime exports: `default` (the `AveAzul` class), `AveAzul`, `Disposer`, `OperationalError`, `isOperationalError`, `isProgrammerError`, `promisify`, `promisifyAll`.
17
+
18
+ Type-only exports: `MapOptions`, `AsCallbackOptions`, `FromCallbackOptions`, `Deferred`, `AveAzulClass`, `AveAzulInstance`, `PromisifyOptions`, `PromisifyAllOptions`.
19
+
20
+ CJS entry (`cjs-entry.cjs`, `main` and the `require` condition): `module.exports = Object.assign(m.default, m)` where `m` is the ESM module. `require("aveazul")` is the `AveAzul` class itself, with the named exports above copied on as static properties, plus `AveAzul` (the class), `default` (the class) and `__esModule`. There are no subpaths other than `aveazul/package.json`.
21
+
22
+ CJS caveat: `Object.assign` overwrites the class statics `promisify` and `promisifyAll` with the standalone functions of the same name. In CJS, and in an ESM process that has also loaded the CJS entry (both share one class object), `AveAzul.promisify` and `AveAzul.promisifyAll` use the global `Promise` instead of `AveAzul`. Results are then native promises without the Bluebird methods. In pure ESM the static versions return `AveAzul`. See `promisify` and `promisifyAll`.
23
+
24
+ Not exported: the `using` function and `addStaticAny` are internal, and so are the not-implemented helper functions. `Deferred` is a type only.
25
+
26
+ Behaviors shared by most methods:
27
+
28
+ - Static `resolve`, `reject`, `all`, `race`, `allSettled` and instance `then`, `catch`, `finally` are native. They construct through `this`, so they return `AveAzul` instances.
29
+ - The internal promise check (`isPromise`) is true for `instanceof Promise`, or an object with both `then` and `catch` functions. A thenable with only `then` is treated as a plain value by `each`, `reduce`, `spread`, `some`, `any` and `using`.
30
+ - Methods that take a collection are typed `Iterable`, but several only work for arrays at runtime. Details per method.
31
+
32
+ ## `AveAzul` class
33
+
34
+ ```ts
35
+ class AveAzul<T> extends Promise<T> {
36
+ constructor(executor: (resolve: (v: T | PromiseLike<T>) => void, reject: (r?: unknown) => void) => void);
37
+ }
38
+ ```
39
+
40
+ Same as `new Promise`. Instances are `instanceof Promise`.
41
+
42
+ ## Static: native and re-declared
43
+
44
+ ```ts
45
+ static resolve<U>(value: U | PromiseLike<U>): AveAzul<U>; static resolve(): AveAzul<void>;
46
+ static reject<U = never>(reason?: unknown): AveAzul<U>;
47
+ static all<U>(values: Iterable<U | PromiseLike<U>>): AveAzul<Awaited<U>[]>;
48
+ ```
49
+
50
+ Inherited from `Promise`. They are re-declared with `declare static` (nothing emitted) so the return type is `AveAzul`. `race`, `allSettled`, `withResolvers` and any other native static in your Node are inherited the same way, with native semantics. `Promise.all` rejects with the first rejection.
51
+
52
+ ## `AveAzul.delay(ms, value?)`
53
+
54
+ ```ts
55
+ static delay<U>(ms: number, value?: U): AveAzul<U>
56
+ ```
57
+
58
+ Resolves with `value` after `ms` using `xaa.delay`. With `value === undefined` it resolves with `undefined`. A function `value` is handled by xaa as a producer: `delay(1, () => 5)` resolves with `5` (observed).
59
+
60
+ ## `AveAzul.map(items, fn, options?)`
61
+
62
+ ```ts
63
+ static map<T, U>(
64
+ value: Iterable<T | PromiseLike<T>>,
65
+ fn: (item: T, index: number, length: number) => U | PromiseLike<U>,
66
+ options?: MapOptions
67
+ ): AveAzul<U[]>
68
+ interface MapOptions { concurrency?: number }
69
+ ```
70
+
71
+ Same as `AveAzul.resolve(value).map(fn, options)`, so `value` may itself be a promise of an array.
72
+
73
+ | option | type | default | behavior |
74
+ |---|---|---|---|
75
+ | `concurrency` | `number` | `50` | `> 1` runs up to that many `fn` calls at once through xaa. Any other value (`0`, `1`, negative, or an `options` object without `concurrency`) runs one at a time in order. Bluebird's default is unbounded. |
76
+
77
+ The default applies only when `options` is `undefined`. Passing `{}` is serial.
78
+
79
+ Rules:
80
+
81
+ - The input must be an actual array at runtime. Anything else (`Set`, generator, number, `null`) rejects with an `AssertionError` from xaa: `xaa.map expecting an array but got object`.
82
+ - Promise items are awaited before `fn` is called. A rejected item rejects the result.
83
+ - Result order matches input order.
84
+ - The first error rejects the result and gets a `partial` property (array of results so far, possibly with holes). In-flight calls are not cancelled.
85
+ - The third `fn` argument is NOT `length` despite the type. It is xaa's context object `{ array, failed, assertNoFailure }`.
86
+ - `fn` is called with no `this`.
87
+
88
+ ## `AveAzul.mapSeries(items, fn)`
89
+
90
+ ```ts
91
+ static mapSeries<T, U>(value: Iterable<T | PromiseLike<T>>, fn: (item: T, index: number, length: number) => U | PromiseLike<U>): AveAzul<U[]>
92
+ ```
93
+
94
+ `AveAzul.map(value, fn, { concurrency: 1 })`. Same array-only rule and third-argument caveat as `map`.
95
+
96
+ ## `AveAzul.try(fn)`
97
+
98
+ ```ts
99
+ static try<T>(fn: () => T | PromiseLike<T>): AveAzul<T>
100
+ ```
101
+
102
+ Calls `fn` through `xaa.wrap`. A sync throw or rejected return becomes a rejection. A non-function `fn` rejects with `TypeError: func is not a function` (observed), it does not throw synchronously. No extra arguments or `this` are accepted.
103
+
104
+ ## `AveAzul.props(obj)`
105
+
106
+ ```ts
107
+ static props<T extends object>(obj: T): AveAzul<{ [K in keyof T]: Awaited<T[K]> }>
108
+ ```
109
+
110
+ Resolves every own enumerable string-keyed value (`Object.keys`) with `AveAzul.all` and returns a new plain object with the same keys. A `Map` is not supported: it yields `{}`. `null` or `undefined` throws a `TypeError` synchronously (from `Object.keys`), not a rejection.
111
+
112
+ ## `AveAzul.defer()`
113
+
114
+ ```ts
115
+ static defer<T>(): Deferred<T>
116
+ interface Deferred<T> { promise: AveAzul<T>; resolve(value: T | PromiseLike<T>): void; reject(reason?: unknown): void }
117
+ ```
118
+
119
+ Returns an `xaa` `Defer` built with `AveAzul` as the promise class. At runtime it also has a `done(err, value)` Node-callback property that is not in the type.
120
+
121
+ ## `AveAzul.each(items, fn)`
122
+
123
+ ```ts
124
+ static each<T>(items: Iterable<T | PromiseLike<T>>, fn: (item: T, index: number, length: number) => unknown): AveAzul<T[]>
125
+ ```
126
+
127
+ `AveAzul.resolve(items).each(fn)`. See instance `each`.
128
+
129
+ ## `AveAzul.reduce(array, fn, initialValue?)`
130
+
131
+ ```ts
132
+ static reduce<T, U>(array: Iterable<T | PromiseLike<T>>, fn: (value: U, item: T, index: number, length: number) => U | PromiseLike<U>, initialValue?: U): AveAzul<U>
133
+ ```
134
+
135
+ With 3 or more arguments `initialValue` is used even if it is `undefined`. With 2 arguments see instance `reduce`.
136
+
137
+ ## `AveAzul.some(promises, count)`
138
+
139
+ ```ts
140
+ static some<T>(promises: Iterable<T | PromiseLike<T>>, count: number): AveAzul<T[]>
141
+ ```
142
+
143
+ `AveAzul.resolve(promises).some(count)`. See instance `some`.
144
+
145
+ ## `AveAzul.any(promises)`
146
+
147
+ ```ts
148
+ static any<T>(args: Iterable<T | PromiseLike<T>>): AveAzul<T>
149
+ ```
150
+
151
+ Replaces native `Promise.any` (overwritten at module load).
152
+
153
+ - A non-iterable returns a rejected promise with `TypeError: expecting an array or an iterable object but got <x>`. `Set` input works.
154
+ - Empty input rejects with `RangeError: Input array must contain at least 1 items but contains only 0 items`.
155
+ - Resolves with the first fulfilled value. Non-promise items count as already fulfilled.
156
+ - If all reject, rejects with `new AggregateError(errors)` from `@jchip/error`. It has no message (empty string observed). Errors are in rejection order.
157
+
158
+ ## `AveAzul.join(...args)`
159
+
160
+ ```ts
161
+ static join(...args: any[]): AveAzul<any>
162
+ ```
163
+
164
+ If there is more than one argument and the last is a function, awaits the earlier arguments with `AveAzul.all` and resolves with `handler(...results)`. Otherwise it resolves with `AveAzul.all(args)`. So `join(fn)` with a single function resolves to `[fn]` and `join()` resolves to `[]`.
165
+
166
+ ## `AveAzul.method(fn)`
167
+
168
+ ```ts
169
+ static method<T, Args extends any[]>(fn: (...args: Args) => T | PromiseLike<T>): (...args: Args) => AveAzul<T>
170
+ ```
171
+
172
+ Returns a function that calls `fn` with the caller's `this` and arguments, giving an `AveAzul`. Sync throws become rejections. A non-function `fn` fails only when the wrapper is called, as a rejection.
173
+
174
+ ## `AveAzul.promisify(fn, options?)`
175
+
176
+ ```ts
177
+ static promisify<T = unknown>(fn: (...args: any[]) => void, options?: PromisifyOptions): (...args: any[]) => AveAzul<T>
178
+ ```
179
+
180
+ Calls the standalone `promisify` with `Promise` forced to `AveAzul` (overrides `options.Promise`). Options and rules are in the standalone `promisify` section. In the CJS entry this static is replaced by the standalone function (see Imports).
181
+
182
+ ## `AveAzul.promisifyAll(target, options?)`
183
+
184
+ ```ts
185
+ static promisifyAll<T extends object>(target: T, options?: PromisifyAllOptions): T
186
+ ```
187
+
188
+ Calls the standalone `promisifyAll` with `Promise` forced to `AveAzul`. Same CJS caveat as `promisify`.
189
+
190
+ ## `AveAzul.using(...)`
191
+
192
+ ```ts
193
+ static using<R>(resources: any, ...args: any[]): AveAzul<R>
194
+ ```
195
+
196
+ The last argument is the handler. Two call forms:
197
+
198
+ - Variadic: `using(r1, r2, ..., handler)`, handler is called as `handler(...resolvedResources)`.
199
+ - Array: `using([r1, r2], handler)`, handler is called as `handler(resolvedArray)`. An array plus more than one trailing argument throws `TypeError: only two arguments are allowed when passing an array of resources`.
200
+
201
+ Each resource may be a `Disposer` (from `.disposer()`), a promise of a value or of a `Disposer`, or a plain value (no cleanup). Rules:
202
+
203
+ - No handler argument throws synchronously `TypeError: resrouces and handler function required` (the typo is in the source). A non-function handler throws synchronously `TypeError: handler must be a function`.
204
+ - Resources are acquired through `AveAzul.map` (default concurrency 50), so acquisition is concurrent.
205
+ - If any acquisition rejects, all successfully acquired resources are disposed, then the first acquisition error rejects the result. The handler is not called.
206
+ - After the handler settles (resolve, reject, or sync throw), resources are disposed in input order, one at a time, through `AveAzul.each`. Bluebird disposes in reverse order.
207
+ - A dispose function that throws does not reject the result. The errors are collected and thrown as `AggregateError("cleanup resources failed")` on `setTimeout(0)` via `___throwUncaughtError`, which crashes the process unless an `uncaughtException` handler exists.
208
+ - A rejected handler result is rethrown after disposal.
209
+
210
+ ## `AveAzul.fromCallback(fn, options?)` and `AveAzul.fromNode`
211
+
212
+ ```ts
213
+ static fromCallback<T>(fn: (callback: (err: Error | null, result?: T) => void) => void, options?: FromCallbackOptions): AveAzul<T>
214
+ static fromNode: typeof AveAzul.fromCallback // same function
215
+ interface FromCallbackOptions { multiArgs?: boolean }
216
+ ```
217
+
218
+ Calls `fn` with a Node callback. A truthy `err` rejects. Otherwise it resolves with the first value, or with the array of all values when `options.multiArgs` is truthy. A sync throw from `fn` rejects.
219
+
220
+ ## `AveAzul.isOperationalError`, `AveAzul.isProgrammerError`, `AveAzul.OperationalError`, `AveAzul.Disposer`
221
+
222
+ Static aliases of the standalone exports of the same names.
223
+
224
+ ## `AveAzul.___throwUncaughtError(error)`
225
+
226
+ ```ts
227
+ static ___throwUncaughtError(error: unknown): void
228
+ ```
229
+
230
+ Internal. Schedules `setTimeout(() => { throw err }, 0)`. A non-`Error` is wrapped with `new Error(String(error))`. Used by `asCallback` and `using` for errors that must not be swallowed.
231
+
232
+ ## `AveAzul.__notImplementedInstance`, `AveAzul.__notImplementedStatic`
233
+
234
+ ```ts
235
+ static __notImplementedInstance?: string[]
236
+ static __notImplementedStatic?: string[]
237
+ ```
238
+
239
+ Set at load by `setupNotImplemented`. They list the names from a fixed Bluebird list that the class lacked and that were replaced by throwing stubs. Observed values:
240
+
241
+ - Instance: `bind`, `isFulfilled`, `isRejected`, `isPending`, `isCancelled`, `value`, `reason`, `cancel`, `reflect`, `suppressUnhandledRejections`, `done`.
242
+ - Static: `filter`, `coroutine`, `coroutine.addYieldHandler`, `getNewLibraryCopy`, `noConflict`, `setScheduler`.
243
+
244
+ Calling a stub logs `console.error("<instance|static> <name> Not implemented in aveazul")` and throws an `Error` with the same text. `coroutine.addYieldHandler` is a single property literally named with a dot, not a nested member.
245
+
246
+ ## Instance methods
247
+
248
+ ### `then`, `catch`, `finally`
249
+
250
+ Native, typed to return `AveAzul`. `catch` takes only a handler. Bluebird's filtered catch `.catch(ErrorClass, handler)` is NOT supported: the class is used as the handler and called as a function. For example `.catch(TypeError, h)` resolves with a new `TypeError` object and never calls `h`.
251
+
252
+ ### `tap(fn)`
253
+
254
+ ```ts
255
+ tap(fn: (value: T) => unknown): AveAzul<T>
256
+ ```
257
+
258
+ Awaits `fn(value)`, ignores its result and resolves with the original value. A throw or rejection from `fn` rejects the chain.
259
+
260
+ ### `tapCatch(fn)`
261
+
262
+ ```ts
263
+ tapCatch(fn: (err: Error) => unknown): AveAzul<T>
264
+ ```
265
+
266
+ On rejection awaits `fn(err)` then rethrows the original error. A throw from `fn` replaces it. No filter overloads.
267
+
268
+ ### `return(value)`
269
+
270
+ ```ts
271
+ return<U>(value: U): AveAzul<U>
272
+ ```
273
+
274
+ `.then(() => value)`.
275
+
276
+ ### `throw(reason)`
277
+
278
+ ```ts
279
+ throw(reason: unknown): AveAzul<never>
280
+ ```
281
+
282
+ `.then(() => { throw reason })`. Skipped when this promise rejects.
283
+
284
+ ### `catchReturn(value)`, `catchThrow(reason)`
285
+
286
+ ```ts
287
+ catchReturn<U>(value: U): AveAzul<T | U>
288
+ catchThrow(reason: unknown): AveAzul<T>
289
+ ```
290
+
291
+ `.catch(() => value)` and `.catch(() => { throw reason })`. No filter overloads.
292
+
293
+ ### `error(handler)`
294
+
295
+ ```ts
296
+ error(handler: (err: Error) => unknown): AveAzul<T>
297
+ ```
298
+
299
+ Catches only operational errors (`isOperationalError(err)`: an `OperationalError` instance or an object with `isOperational === true`) and passes them to `handler`. Other errors are rethrown. `AGENTS.md` lists `error` as not implemented, but the code implements it.
300
+
301
+ ### `get(key)`
302
+
303
+ ```ts
304
+ get<K extends keyof T>(key: K): AveAzul<T[K]>
305
+ ```
306
+
307
+ `.then(v => v[key])`. A `null` or `undefined` value rejects with a `TypeError`. Negative indexes are not special.
308
+
309
+ ### `call(methodName, ...args)`
310
+
311
+ ```ts
312
+ call(methodName: string, ...args: any[]): AveAzul<any>
313
+ ```
314
+
315
+ Calls `value[methodName](...args)` with `this` set to the value. A missing or non-function member rejects with `TypeError: <name> is not a function`.
316
+
317
+ ### `spread(fn)`
318
+
319
+ ```ts
320
+ spread<U>(fn: (...args: any[]) => U | PromiseLike<U>): AveAzul<U>
321
+ ```
322
+
323
+ For an array value: awaits promise elements one by one, replacing them in the original array in place, then calls `fn(...array)`. A non-array value calls `fn(value)`. A non-function `fn` returns a rejected promise with `TypeError: expecting a function but got <fn>` (no sync throw).
324
+
325
+ ### `map(fn, options?)` and `mapSeries(fn)`
326
+
327
+ ```ts
328
+ map<U>(fn: (item: any, index: number, length: number) => U | PromiseLike<U>, options?: MapOptions): AveAzul<U[]>
329
+ mapSeries<U>(fn: (item: any, index: number, length: number) => U | PromiseLike<U>): AveAzul<U[]>
330
+ ```
331
+
332
+ The resolved value goes to `xaa.map` with `options`, default `{ concurrency: 50 }`. See `AveAzul.map` for the option table and rules. `mapSeries` is `map(fn, { concurrency: 1 })`. A non-array resolved value rejects with an `AssertionError`.
333
+
334
+ ### `filter(fn)`
335
+
336
+ ```ts
337
+ filter(fn: (item: any, index: number, length: number) => any): AveAzul<any[]>
338
+ ```
339
+
340
+ Uses `xaa.filter`. Strictly sequential, no options (Bluebird has `concurrency`). It calls `fn(item, index)` only, so the third argument is `undefined`, not `length`. Items are not unwrapped first: `fn` receives the raw element (a promise element is passed as a promise) and the kept value is the raw element. Keeps elements whose awaited result is truthy. A value without `length` (such as a `Set`) resolves to `[]`. The static `AveAzul.filter` is a throwing stub, so use `AveAzul.resolve(arr).filter(fn)`.
341
+
342
+ ### `each(fn)`
343
+
344
+ ```ts
345
+ each(fn: (item: any, index: number, length: number) => unknown): AveAzul<any[]>
346
+ ```
347
+
348
+ Sequential. For each element: awaits it if it is a promise, then awaits `fn(item, index, arr.length)`. Resolves with a new array of the awaited items. The `fn` results are ignored. Stops at the first rejection. A value without `length` (such as a `Set`) resolves to `[]`.
349
+
350
+ ### `reduce(fn, initialValue?)`
351
+
352
+ ```ts
353
+ reduce<U>(fn: (value: U, item: any, index: number, length: number) => U | PromiseLike<U>, initialValue?: U): AveAzul<U>
354
+ ```
355
+
356
+ Sequential. Initial value detection is `arguments.length > 1`, so an explicit `undefined` counts as supplied. Without one, the first element is the accumulator and iteration starts at index 1. So an empty array resolves with `undefined` and a one-element array resolves with that element, with `fn` never called. A promise accumulator or element is awaited. A value without `length` (such as a `Set`) resolves to the initial value, or `undefined`.
357
+
358
+ ### `props()`
359
+
360
+ ```ts
361
+ props(): AveAzul<any>
362
+ ```
363
+
364
+ Same as `AveAzul.props` applied to the resolved value.
365
+
366
+ ### `all()`, `any()`, `some(count)`
367
+
368
+ ```ts
369
+ all(): AveAzul<any[]>
370
+ any(): AveAzul<any>
371
+ some(count: number): AveAzul<any[]>
372
+ ```
373
+
374
+ Apply `AveAzul.all`, `AveAzul.any` or the `some` algorithm to the resolved value, which must be an array or iterable (else rejects with `TypeError: expecting an array or an iterable object but got <x>`).
375
+
376
+ `some(count)` rules:
377
+
378
+ - `count` must satisfy `(count | 0) === count && count >= 0`, else returns a rejected promise with `TypeError: expecting a non-negative integer`.
379
+ - `count === 0` resolves with `[]` without waiting for this promise.
380
+ - `count` greater than the input length rejects with `RangeError: Input array must contain at least <count> items but contains only <len> items`.
381
+ - Resolves with exactly `count` values in fulfillment order. Non-promise items count as already fulfilled.
382
+ - Rejects with `AggregateError` (message `aggregate error`) once fewer than `count` items can still fulfil. Errors are in rejection order.
383
+
384
+ ### `delay(ms)`
385
+
386
+ ```ts
387
+ delay(ms: number): AveAzul<T>
388
+ ```
389
+
390
+ After fulfillment waits `ms`, then passes the value through. Rejections pass through without the delay.
391
+
392
+ ### `timeout(ms, message?)`
393
+
394
+ ```ts
395
+ timeout(ms: number, message?: string): AveAzul<T> // message defaults to "operation timed out"
396
+ ```
397
+
398
+ Races this promise against a timer using `xaa.timeout(ms, message, ...).run(this)`. On timeout it rejects with `OperationalError(message)` (name `OperationalError`, `isOperational === true`). There is no `TimeoutError` class, and `message` is a string only. The timer is cleared when the promise settles. The underlying work is not cancelled.
399
+
400
+ ### `disposer(fn)`
401
+
402
+ ```ts
403
+ disposer(fn: (resource: T) => void | Promise<void>): Disposer<T>
404
+ ```
405
+
406
+ Returns `new Disposer(fn, this)`, not a promise. Throws synchronously `TypeError: Expected a function` for a non-function `fn`. Use with `AveAzul.using`.
407
+
408
+ ### `asCallback(cb, options?)` and `nodeify(cb, options?)`
409
+
410
+ ```ts
411
+ asCallback(cb: ((err: Error | null, value?: T) => void) | ((err: Error | null, ...values: any[]) => void) | undefined | null, options?: AsCallbackOptions): AveAzul<T>
412
+ nodeify(cb, options?): AveAzul<T> // calls asCallback
413
+ interface AsCallbackOptions { spread?: boolean }
414
+ ```
415
+
416
+ | option | type | default | behavior |
417
+ |---|---|---|---|
418
+ | `spread` | `boolean` | `false` | Only `=== true` counts. An array value is passed as separate arguments `cb(null, ...value)`. A non-array value is passed as `cb(null, value)`. |
419
+
420
+ - A non-function `cb` is ignored and the same promise is returned.
421
+ - On success calls `cb(null, value)`. On rejection calls `cb(reason)`.
422
+ - An exception thrown by `cb` is rethrown asynchronously through `___throwUncaughtError`.
423
+ - Returns `this`, not a new promise.
424
+
425
+ ## Standalone exports
426
+
427
+ ### `AveAzul` and `default`
428
+
429
+ The class above. The named and default exports are the same object.
430
+
431
+ ### `promisify(fn, options?)`
432
+
433
+ ```ts
434
+ function promisify<T = unknown>(fn: NodeStyleFunction, options?: PromisifyOptions): (...args: unknown[]) => Promise<T>
435
+ interface PromisifyOptions { Promise?: PromiseConstructor; multiArgs?: boolean; copyProps?: boolean; suffix?: string; context?: unknown }
436
+ ```
437
+
438
+ | option | type | default | behavior |
439
+ |---|---|---|---|
440
+ | `Promise` | `PromiseConstructor` | `globalThis.Promise` | Class that builds the result. The standalone default returns a native promise, not `AveAzul`. Use `AveAzul.promisify` or pass `{ Promise: AveAzul }`. |
441
+ | `multiArgs` | `boolean` | `false` | Truthy resolves with the array of all callback values after `err`. Otherwise only the first value. |
442
+ | `copyProps` | `boolean` | `true` | Copies own properties of `fn` onto the wrapper, except `arity`, `length`, `name`, `arguments`, `caller`, `callee`, `prototype`, `__isPromisified__`. |
443
+ | `suffix` | `string` | `""` | Appended to the wrapper's `name` only (`fn.name + suffix`). |
444
+ | `context` | `unknown` | `undefined` | `this` for `fn` when truthy. Otherwise the wrapper's own `this`. |
445
+
446
+ Rules:
447
+
448
+ - A non-function `fn` throws synchronously `TypeError: expecting a function but got [object X]`.
449
+ - A function already promisified (`__isPromisified__ === true`) is returned unchanged and the options are ignored.
450
+ - The wrapper appends a Node callback as the last argument. A truthy `err` rejects, otherwise it resolves. A sync throw from `fn` rejects, because `fn` runs inside the promise executor.
451
+ - The wrapper's `length` is `fn.length` (not reduced by one). Its `name` is `fn.name + suffix`.
452
+ - The wrapper is marked with a non-enumerable `__isPromisified__` property.
453
+
454
+ ### `promisifyAll(target, options?)`
455
+
456
+ ```ts
457
+ function promisifyAll<T extends object>(target: T, options?: PromisifyAllOptions): T
458
+ interface PromisifyAllOptions extends PromisifyOptions { suffix?: string; filter?: FilterFunction; promisifier?: PromisifierFunction }
459
+ type FilterFunction = (name: string, value: unknown, target: object, passesDefaultFilter?: boolean) => boolean
460
+ type PromisifierFunction = (fn, defaultPromisifier, options: PromisifyAllOptions) => (...args: any[]) => Promise<unknown>
461
+ ```
462
+
463
+ Adds `<name><suffix>` promisified siblings in place and returns `target`. Defaults: `suffix: "Async"`, `filter` is the default filter, `promisifier` is the default promisifier, plus the `promisify` defaults (`Promise` global, `multiArgs` false, `copyProps` true, `context` undefined).
464
+
465
+ - Throws `TypeError: the target of promisifyAll must be an object or a function` when `typeof target` is neither. `null` passes that check and is returned unchanged.
466
+ - Throws `RangeError: suffix must be a valid identifier ...` when `suffix` does not match `/^[a-z$_][a-z$_0-9]*$/i`.
467
+ - Default filter: valid identifier, not starting with `_`, not `constructor`, not ending with `Sync`. Only data properties (no getters or setters) on the object and its prototype chain are considered, excluding the `Object`, `Array` and `Function` prototypes. Non-functions, already-promisified functions, and names whose `<name><suffix>` is already set are skipped.
468
+ - A custom `filter` replaces the default one entirely. It gets `passesDefaultFilter` as the fourth argument.
469
+ - Throws `TypeError: Cannot promisify an API that has normal methods with 'Async'-suffix ...` when a candidate method name already ends with the suffix.
470
+ - Any property whose value looks like a class gets its `prototype` and its own statics promisified too (keys starting with `_` and `constructor` are skipped). A function is treated as a class if its prototype has more than one own name, or any non-`constructor` member, or its source text matches `this.x =` and it has own properties.
471
+ - The default promisifier calls `promisify(fn, { ...options, copyProps: false })`. `context` is not bound to the target, so promisified methods use the call-site `this`.
472
+
473
+ ### `OperationalError`
474
+
475
+ ```ts
476
+ class OperationalError extends Error { isOperational: boolean; constructor(message: string) }
477
+ ```
478
+
479
+ `name` is `"OperationalError"`, `isOperational` is `true`, and a stack is captured. Thrown by `.timeout()`. There is no `RejectionError`.
480
+
481
+ ### `isOperationalError(error)` and `isProgrammerError(error)`
482
+
483
+ ```ts
484
+ function isOperationalError(error: unknown): boolean
485
+ function isProgrammerError(error: unknown): boolean
486
+ ```
487
+
488
+ `isOperationalError` is false for non-objects and `null`, true for an `OperationalError` instance or any object with `isOperational === true`. `isProgrammerError` is false for non-objects and `null` (a thrown string is NOT a programmer error), otherwise `!isOperationalError(error)`.
489
+
490
+ ### `Disposer`
491
+
492
+ ```ts
493
+ class Disposer<T> { _data: (resource: T) => void | Promise<void>; _promise: Promise<T>; constructor(fn, promise) }
494
+ ```
495
+
496
+ Marker returned by `.disposer()` and consumed by `AveAzul.using`. `using` also accepts any object with a defined `_promise` and a function `_data`.
497
+
498
+ ## Not implemented from Bluebird
499
+
500
+ Throwing stubs, instance: `bind`, `isFulfilled`, `isRejected`, `isPending`, `isCancelled`, `value`, `reason`, `cancel`, `reflect`, `suppressUnhandledRejections`, `done`.
501
+
502
+ Throwing stubs, static: `filter`, `coroutine`, `coroutine.addYieldHandler`, `getNewLibraryCopy`, `noConflict`, `setScheduler`.
503
+
504
+ Absent (property is `undefined`, no stub), static: `TimeoutError`, `CancellationError`, `AggregateError`, `RejectionError`, `onPossiblyUnhandledRejection`, `onUnhandledRejectionHandled`, `config`, `is`, `fulfilled`, `rejected`, `cast`, `pending`, `longStackTraces`, `hasLongStackTraces`, `spawn`. Absent, instance: `caught`, `lastly`, `thenReturn`, `thenThrow`, `isResolved`, `toJSON`.
505
+
506
+ Differences from Bluebird behavior: filtered `catch` is unsupported, `timeout` rejects with `OperationalError`, `map` defaults to concurrency 50, `each` resolves with the awaited items (a new array), `using` disposes in input order, `filter` is sequential and its callback gets no `length`, the `map` callback's third argument is a context object, `tapCatch` and `catchReturn` have no filter overloads, `props` takes plain objects only, and native Promise resolution and unhandled-rejection behavior apply.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aveazul",
3
- "version": "2.1.7",
3
+ "version": "2.1.9",
4
4
  "description": "Bluebird drop-in replacement built on native Promise",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "./package.json": "./package.json"
15
15
  },
16
- "homepage": "https://github.com/jchip/fynjs/tree/main/packages/aveazul",
16
+ "homepage": "https://fynjs.pages.dev/api/modules/aveazul",
17
17
  "license": "Apache-2.0",
18
18
  "scripts": {
19
19
  "build": "rm -rf dist && tsc -p tsconfig.json",
@@ -34,7 +34,8 @@
34
34
  ],
35
35
  "files": [
36
36
  "cjs-entry.cjs",
37
- "dist"
37
+ "dist",
38
+ "docs/reference.md"
38
39
  ],
39
40
  "keywords": [
40
41
  "promise",
@@ -80,16 +81,16 @@
80
81
  "directory": "packages/aveazul"
81
82
  },
82
83
  "dependencies": {
83
- "@jchip/error": "^2.1.6",
84
- "xaa": "^3.1.6"
84
+ "@jchip/error": "^2.1.8",
85
+ "xaa": "^3.1.8"
85
86
  },
86
87
  "devDependencies": {
87
- "@fynjs/ts-resolve": "^1.0.3",
88
+ "@fynjs/ts-resolve": "^1.0.4",
88
89
  "@types/node": "^26.4.1",
89
90
  "@vitest/coverage-v8": "^5.0.0",
90
91
  "bluebird": "^3.7.2",
91
- "publish-util": "^3.1.6",
92
- "run-verify": "^2.1.7",
92
+ "publish-util": "^3.1.8",
93
+ "run-verify": "^2.2.0",
93
94
  "typescript": "^7.0.2",
94
95
  "vite": "^8.2.2",
95
96
  "vitest": "^5.0.0"