@neon/sdk 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +64 -3
  2. package/dist/client/types.gen.d.ts.map +1 -1
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.js +2 -2
  5. package/dist/neon/config.d.ts +13 -0
  6. package/dist/neon/config.d.ts.map +1 -1
  7. package/dist/neon/config.js +2 -0
  8. package/dist/neon/config.js.map +1 -1
  9. package/dist/neon/context.d.ts +26 -6
  10. package/dist/neon/context.d.ts.map +1 -1
  11. package/dist/neon/context.js +59 -10
  12. package/dist/neon/context.js.map +1 -1
  13. package/dist/neon/deadline.d.ts +81 -0
  14. package/dist/neon/deadline.d.ts.map +1 -0
  15. package/dist/neon/deadline.js +143 -0
  16. package/dist/neon/deadline.js.map +1 -0
  17. package/dist/neon/errors.d.ts +22 -3
  18. package/dist/neon/errors.d.ts.map +1 -1
  19. package/dist/neon/errors.js +22 -2
  20. package/dist/neon/errors.js.map +1 -1
  21. package/dist/neon/paginate.d.ts +6 -1
  22. package/dist/neon/paginate.d.ts.map +1 -1
  23. package/dist/neon/paginate.js +59 -24
  24. package/dist/neon/paginate.js.map +1 -1
  25. package/dist/neon/raw-wrap.d.ts.map +1 -1
  26. package/dist/neon/raw-wrap.js +17 -2
  27. package/dist/neon/raw-wrap.js.map +1 -1
  28. package/dist/neon/resources/account.d.ts.map +1 -1
  29. package/dist/neon/resources/account.js +18 -12
  30. package/dist/neon/resources/account.js.map +1 -1
  31. package/dist/neon/resources/ai-gateway.js +3 -2
  32. package/dist/neon/resources/ai-gateway.js.map +1 -1
  33. package/dist/neon/resources/auth.d.ts.map +1 -1
  34. package/dist/neon/resources/auth.js +42 -28
  35. package/dist/neon/resources/auth.js.map +1 -1
  36. package/dist/neon/resources/branches.d.ts +1 -1
  37. package/dist/neon/resources/branches.d.ts.map +1 -1
  38. package/dist/neon/resources/branches.js +29 -20
  39. package/dist/neon/resources/branches.js.map +1 -1
  40. package/dist/neon/resources/bucket-objects.d.ts.map +1 -1
  41. package/dist/neon/resources/bucket-objects.js +15 -10
  42. package/dist/neon/resources/bucket-objects.js.map +1 -1
  43. package/dist/neon/resources/buckets.d.ts.map +1 -1
  44. package/dist/neon/resources/buckets.js +9 -6
  45. package/dist/neon/resources/buckets.js.map +1 -1
  46. package/dist/neon/resources/consumption.d.ts +4 -4
  47. package/dist/neon/resources/consumption.d.ts.map +1 -1
  48. package/dist/neon/resources/consumption.js +6 -6
  49. package/dist/neon/resources/consumption.js.map +1 -1
  50. package/dist/neon/resources/credentials.d.ts.map +1 -1
  51. package/dist/neon/resources/credentials.js +9 -6
  52. package/dist/neon/resources/credentials.js.map +1 -1
  53. package/dist/neon/resources/dataapi.d.ts.map +1 -1
  54. package/dist/neon/resources/dataapi.js +12 -8
  55. package/dist/neon/resources/dataapi.js.map +1 -1
  56. package/dist/neon/resources/databases.d.ts.map +1 -1
  57. package/dist/neon/resources/databases.js +15 -10
  58. package/dist/neon/resources/databases.js.map +1 -1
  59. package/dist/neon/resources/endpoints.d.ts.map +1 -1
  60. package/dist/neon/resources/endpoints.js +27 -18
  61. package/dist/neon/resources/endpoints.js.map +1 -1
  62. package/dist/neon/resources/functions.d.ts +1 -1
  63. package/dist/neon/resources/functions.d.ts.map +1 -1
  64. package/dist/neon/resources/functions.js +14 -10
  65. package/dist/neon/resources/functions.js.map +1 -1
  66. package/dist/neon/resources/operations.d.ts +12 -3
  67. package/dist/neon/resources/operations.d.ts.map +1 -1
  68. package/dist/neon/resources/operations.js +5 -4
  69. package/dist/neon/resources/operations.js.map +1 -1
  70. package/dist/neon/resources/postgres.d.ts.map +1 -1
  71. package/dist/neon/resources/postgres.js +9 -1
  72. package/dist/neon/resources/postgres.js.map +1 -1
  73. package/dist/neon/resources/projects.d.ts +1 -1
  74. package/dist/neon/resources/projects.d.ts.map +1 -1
  75. package/dist/neon/resources/projects.js +35 -24
  76. package/dist/neon/resources/projects.js.map +1 -1
  77. package/dist/neon/resources/roles.d.ts.map +1 -1
  78. package/dist/neon/resources/roles.js +18 -12
  79. package/dist/neon/resources/roles.js.map +1 -1
  80. package/dist/neon/resources/snapshots.d.ts +10 -1
  81. package/dist/neon/resources/snapshots.d.ts.map +1 -1
  82. package/dist/neon/resources/snapshots.js +37 -19
  83. package/dist/neon/resources/snapshots.js.map +1 -1
  84. package/dist/neon/resources/storage.js +3 -2
  85. package/dist/neon/resources/storage.js.map +1 -1
  86. package/dist/neon/retry.d.ts +30 -8
  87. package/dist/neon/retry.d.ts.map +1 -1
  88. package/dist/neon/retry.js +59 -20
  89. package/dist/neon/retry.js.map +1 -1
  90. package/dist/neon/wait.d.ts +7 -1
  91. package/dist/neon/wait.d.ts.map +1 -1
  92. package/dist/neon/wait.js +53 -34
  93. package/dist/neon/wait.js.map +1 -1
  94. package/package.json +2 -1
@@ -0,0 +1,81 @@
1
+ import { NeonError } from "./errors.js";
2
+
3
+ //#region src/neon/deadline.d.ts
4
+
5
+ /** Why a bounded wait ended. */
6
+ type DelayOutcome = "elapsed" | "cancelled";
7
+ /** What ended a call: the caller's own signal, or the request-timeout budget. */
8
+ type DeadlineSource = "caller" | "timeout";
9
+ interface Deadline {
10
+ /**
11
+ * Attach to every request the call makes. `undefined` when the call is unbounded and
12
+ * the caller passed no signal, so nothing extra is allocated for the common case.
13
+ */
14
+ readonly signal: AbortSignal | undefined;
15
+ /** Budget left in milliseconds; `Infinity` when no request timeout applies. */
16
+ remainingMs(): number;
17
+ /**
18
+ * What ended the call, or `undefined` while it may still proceed.
19
+ *
20
+ * Reads the clock rather than trusting the timer to have run, and trips the deadline
21
+ * itself if the budget is already spent. A loop that only ever awaits
22
+ * already-resolved promises — paginating a cursor the API keeps repeating, say —
23
+ * yields to the microtask queue but never to the timer phase, so a timer-only
24
+ * deadline would never fire and the call would spin forever.
25
+ */
26
+ source(): DeadlineSource | undefined;
27
+ /**
28
+ * Resolves when the deadline fires, and otherwise never settles. Used to bound the
29
+ * phases a request signal cannot reach. Never rejects.
30
+ */
31
+ fired(): Promise<void>;
32
+ /** Release the timer and the caller-signal listener. Safe to call more than once. */
33
+ dispose(): void;
34
+ }
35
+ /**
36
+ * Normalize a `requestTimeoutMs`, rejecting values `setTimeout` would mistreat.
37
+ *
38
+ * Shared by the client config and by per-call overrides — validating only at construction
39
+ * left `requestTimeoutMs: NaN` on a call silently meaning *unbounded*, and a value past
40
+ * {@link MAX_TIMER_MS} silently meaning *1ms*. Both are worse than an error, because the
41
+ * call still returns a plausible-looking result.
42
+ *
43
+ * `undefined` and `Infinity` both mean unbounded; `Infinity` is the documented way to opt
44
+ * a single call out of a client-wide deadline.
45
+ */
46
+ declare function resolveTimeoutMs(value: number | undefined): number;
47
+ /**
48
+ * The typed error for a deadline that has fired, or `undefined` if it has not.
49
+ *
50
+ * Cancellation is classified from the deadline's own state rather than from the shape of
51
+ * the error that came back. The generated client funnels authentication, serialization,
52
+ * interceptor, transport and parsing faults through one channel, so an error merely named
53
+ * `AbortError` is not evidence that the caller cancelled.
54
+ */
55
+ declare function cancelled(deadline: Deadline): NeonError | undefined;
56
+ /**
57
+ * Race `run()` against the deadline, resolving `undefined` when the deadline wins.
58
+ *
59
+ * The signal alone does not bound a call. The generated client awaits authentication and
60
+ * request interceptors before it constructs the `Request`, and a caller-supplied `fetch`
61
+ * need not honour a signal at all, so an `apiKey` function that never resolves would
62
+ * otherwise hang forever even with a deadline set.
63
+ */
64
+ declare function runBounded<T>(deadline: Deadline, run: () => Promise<T>): Promise<T | undefined>;
65
+ /**
66
+ * Wait `ms`, or stop early when `signal` aborts. Resolves either way — an abort is
67
+ * reported as `"cancelled"` rather than thrown, and the listener is always removed so a
68
+ * long-lived caller signal doesn't accumulate one per wait.
69
+ */
70
+ declare function delay(ms: number, signal?: AbortSignal): Promise<DelayOutcome>;
71
+ /**
72
+ * Build the deadline for one call.
73
+ *
74
+ * `timeoutMs` is `Infinity` when no request timeout applies. With no timeout and no caller
75
+ * signal there is nothing to cancel, so a shared no-op deadline is returned and no timer
76
+ * or controller is allocated.
77
+ */
78
+ declare function createDeadline(timeoutMs: number, callerSignal?: AbortSignal): Deadline;
79
+ //#endregion
80
+ export { Deadline, DeadlineSource, DelayOutcome, cancelled, createDeadline, delay, resolveTimeoutMs, runBounded };
81
+ //# sourceMappingURL=deadline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deadline.d.ts","names":[],"sources":["../../src/neon/deadline.ts"],"mappings":";;;;AAsGoC;AAAW,KA9EnC,YAAA,GA8EmC,SAAA,GAAA,WAAA;AAAS;AAqBlC,KAhGV,cAAA,GAgGoB,QAAA,GAAA,SAAA;AAAA,UA9Ff,QAAA,CA8Fe;EACrB;AACS;AAAR;AACD;EAAR,SAAA,MAAA,EA5Fe,WA4Ff,GAAA,SAAA;EAAO;EAcM,WAAK,EAAA,EAAA,MAAA;EAAA;AAAsB;AAAsB;AAAR;AAAO;AAsBhE;AAA8B;AAEd;AACb;EAAQ,MAAA,EAAA,EAvHA,cAuHA,GAAA,SAAA;;;;;WAlHD;;;;;;;;;;;;;;;iBAwBM,gBAAA;;;;;;;;;iBA2BA,SAAA,WAAoB,WAAW;;;;;;;;;iBAqBzB,wBACX,qBACC,QAAQ,KACjB,QAAQ;;;;;;iBAcK,KAAA,sBAA2B,cAAc,QAAQ;;;;;;;;iBAsBjD,cAAA,mCAEA,cACb"}
@@ -0,0 +1,143 @@
1
+ import { NeonAbortError, NeonError, NeonTimeoutError } from "./errors.js";
2
+ //#region src/neon/deadline.ts
3
+ /**
4
+ * Cancellation and deadline plumbing shared by the ergonomic layer.
5
+ *
6
+ * Two facts shape this module. Handing a signal to `fetch` does **not** bound a call: the
7
+ * generated client awaits authentication and request interceptors before it constructs the
8
+ * `Request` (see `client/client/client.gen.ts`), and a caller-supplied `fetch` may ignore
9
+ * the signal entirely. So a deadline both carries a signal *and* offers {@link Deadline.fired}
10
+ * to race the whole execution against.
11
+ *
12
+ * And a cancelled call must still speak the result contract. Anything that waits here
13
+ * reports cancellation as a value rather than rejecting, so a `DOMException` never escapes
14
+ * to a caller who was promised `{ data, error }`.
15
+ */
16
+ /**
17
+ * The largest delay `setTimeout` can represent. Beyond it Node warns
18
+ * (`TimeoutOverflowWarning`) and fires after 1ms instead, which would turn a deliberately
19
+ * generous deadline into an instant timeout.
20
+ */
21
+ const MAX_TIMER_MS = 2 ** 31 - 1;
22
+ const UNBOUNDED = {
23
+ signal: void 0,
24
+ remainingMs: () => Number.POSITIVE_INFINITY,
25
+ source: () => void 0,
26
+ fired: () => new Promise(() => {}),
27
+ dispose: () => {}
28
+ };
29
+ /**
30
+ * Normalize a `requestTimeoutMs`, rejecting values `setTimeout` would mistreat.
31
+ *
32
+ * Shared by the client config and by per-call overrides — validating only at construction
33
+ * left `requestTimeoutMs: NaN` on a call silently meaning *unbounded*, and a value past
34
+ * {@link MAX_TIMER_MS} silently meaning *1ms*. Both are worse than an error, because the
35
+ * call still returns a plausible-looking result.
36
+ *
37
+ * `undefined` and `Infinity` both mean unbounded; `Infinity` is the documented way to opt
38
+ * a single call out of a client-wide deadline.
39
+ */
40
+ function resolveTimeoutMs(value) {
41
+ if (value === void 0 || value === Number.POSITIVE_INFINITY) return Number.POSITIVE_INFINITY;
42
+ if (typeof value !== "number" || Number.isNaN(value) || value <= 0) throw new NeonError(`requestTimeoutMs must be a positive number of milliseconds, or Infinity to disable; received ${String(value)}.`, "client");
43
+ if (value > MAX_TIMER_MS) throw new NeonError(`requestTimeoutMs must be at most ${MAX_TIMER_MS}ms (about 24.8 days); received ${value}. Pass Infinity for no deadline.`, "client");
44
+ return value;
45
+ }
46
+ /**
47
+ * The typed error for a deadline that has fired, or `undefined` if it has not.
48
+ *
49
+ * Cancellation is classified from the deadline's own state rather than from the shape of
50
+ * the error that came back. The generated client funnels authentication, serialization,
51
+ * interceptor, transport and parsing faults through one channel, so an error merely named
52
+ * `AbortError` is not evidence that the caller cancelled.
53
+ */
54
+ function cancelled(deadline) {
55
+ const source = deadline.source();
56
+ if (source === "caller") return new NeonAbortError("The request was aborted by its signal.");
57
+ if (source === "timeout") return new NeonTimeoutError("Timed out waiting for the Neon API to respond (requestTimeoutMs).");
58
+ }
59
+ /**
60
+ * Race `run()` against the deadline, resolving `undefined` when the deadline wins.
61
+ *
62
+ * The signal alone does not bound a call. The generated client awaits authentication and
63
+ * request interceptors before it constructs the `Request`, and a caller-supplied `fetch`
64
+ * need not honour a signal at all, so an `apiKey` function that never resolves would
65
+ * otherwise hang forever even with a deadline set.
66
+ */
67
+ async function runBounded(deadline, run) {
68
+ if (!deadline.signal) return run();
69
+ const execution = run();
70
+ execution.catch(() => {});
71
+ return Promise.race([execution, deadline.fired().then(() => void 0)]);
72
+ }
73
+ /**
74
+ * Wait `ms`, or stop early when `signal` aborts. Resolves either way — an abort is
75
+ * reported as `"cancelled"` rather than thrown, and the listener is always removed so a
76
+ * long-lived caller signal doesn't accumulate one per wait.
77
+ */
78
+ function delay(ms, signal) {
79
+ if (signal?.aborted) return Promise.resolve("cancelled");
80
+ return new Promise((resolve) => {
81
+ const onAbort = () => {
82
+ clearTimeout(timer);
83
+ resolve("cancelled");
84
+ };
85
+ const timer = setTimeout(() => {
86
+ signal?.removeEventListener("abort", onAbort);
87
+ resolve("elapsed");
88
+ }, ms);
89
+ signal?.addEventListener("abort", onAbort, { once: true });
90
+ });
91
+ }
92
+ /**
93
+ * Build the deadline for one call.
94
+ *
95
+ * `timeoutMs` is `Infinity` when no request timeout applies. With no timeout and no caller
96
+ * signal there is nothing to cancel, so a shared no-op deadline is returned and no timer
97
+ * or controller is allocated.
98
+ */
99
+ function createDeadline(timeoutMs, callerSignal) {
100
+ const bounded = Number.isFinite(timeoutMs);
101
+ if (!bounded && !callerSignal) return UNBOUNDED;
102
+ const startedAt = performance.now();
103
+ const controller = new AbortController();
104
+ let source;
105
+ let notify;
106
+ const fired = new Promise((resolve) => {
107
+ notify = resolve;
108
+ });
109
+ const trip = (reason) => {
110
+ if (source) return;
111
+ source = reason;
112
+ controller.abort();
113
+ notify?.();
114
+ };
115
+ if (callerSignal?.aborted) trip("caller");
116
+ const onCallerAbort = () => trip("caller");
117
+ const remainingMs = () => bounded ? Math.max(0, timeoutMs - (performance.now() - startedAt)) : Number.POSITIVE_INFINITY;
118
+ let timer;
119
+ const arm = () => {
120
+ const left = remainingMs();
121
+ if (left === 0) return trip("timeout");
122
+ timer = setTimeout(left > MAX_TIMER_MS ? arm : () => trip("timeout"), Math.min(left, MAX_TIMER_MS));
123
+ };
124
+ if (bounded) arm();
125
+ callerSignal?.addEventListener("abort", onCallerAbort, { once: true });
126
+ return {
127
+ signal: controller.signal,
128
+ remainingMs,
129
+ source: () => {
130
+ if (!source && remainingMs() === 0) trip("timeout");
131
+ return source;
132
+ },
133
+ fired: () => fired,
134
+ dispose: () => {
135
+ clearTimeout(timer);
136
+ callerSignal?.removeEventListener("abort", onCallerAbort);
137
+ }
138
+ };
139
+ }
140
+ //#endregion
141
+ export { cancelled, createDeadline, delay, resolveTimeoutMs, runBounded };
142
+
143
+ //# sourceMappingURL=deadline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deadline.js","names":[],"sources":["../../src/neon/deadline.ts"],"sourcesContent":["/**\n * Cancellation and deadline plumbing shared by the ergonomic layer.\n *\n * Two facts shape this module. Handing a signal to `fetch` does **not** bound a call: the\n * generated client awaits authentication and request interceptors before it constructs the\n * `Request` (see `client/client/client.gen.ts`), and a caller-supplied `fetch` may ignore\n * the signal entirely. So a deadline both carries a signal *and* offers {@link Deadline.fired}\n * to race the whole execution against.\n *\n * And a cancelled call must still speak the result contract. Anything that waits here\n * reports cancellation as a value rather than rejecting, so a `DOMException` never escapes\n * to a caller who was promised `{ data, error }`.\n */\n\nimport { NeonAbortError, NeonError, NeonTimeoutError } from \"./errors.js\";\n\n/**\n * The largest delay `setTimeout` can represent. Beyond it Node warns\n * (`TimeoutOverflowWarning`) and fires after 1ms instead, which would turn a deliberately\n * generous deadline into an instant timeout.\n */\nconst MAX_TIMER_MS = 2 ** 31 - 1;\n\n/** Why a bounded wait ended. */\nexport type DelayOutcome = \"elapsed\" | \"cancelled\";\n\n/** What ended a call: the caller's own signal, or the request-timeout budget. */\nexport type DeadlineSource = \"caller\" | \"timeout\";\n\nexport interface Deadline {\n\t/**\n\t * Attach to every request the call makes. `undefined` when the call is unbounded and\n\t * the caller passed no signal, so nothing extra is allocated for the common case.\n\t */\n\treadonly signal: AbortSignal | undefined;\n\t/** Budget left in milliseconds; `Infinity` when no request timeout applies. */\n\tremainingMs(): number;\n\t/**\n\t * What ended the call, or `undefined` while it may still proceed.\n\t *\n\t * Reads the clock rather than trusting the timer to have run, and trips the deadline\n\t * itself if the budget is already spent. A loop that only ever awaits\n\t * already-resolved promises — paginating a cursor the API keeps repeating, say —\n\t * yields to the microtask queue but never to the timer phase, so a timer-only\n\t * deadline would never fire and the call would spin forever.\n\t */\n\tsource(): DeadlineSource | undefined;\n\t/**\n\t * Resolves when the deadline fires, and otherwise never settles. Used to bound the\n\t * phases a request signal cannot reach. Never rejects.\n\t */\n\tfired(): Promise<void>;\n\t/** Release the timer and the caller-signal listener. Safe to call more than once. */\n\tdispose(): void;\n}\n\nconst UNBOUNDED: Deadline = {\n\tsignal: undefined,\n\tremainingMs: () => Number.POSITIVE_INFINITY,\n\tsource: () => undefined,\n\tfired: () => new Promise<void>(() => {}),\n\tdispose: () => {},\n};\n\n/**\n * Normalize a `requestTimeoutMs`, rejecting values `setTimeout` would mistreat.\n *\n * Shared by the client config and by per-call overrides — validating only at construction\n * left `requestTimeoutMs: NaN` on a call silently meaning *unbounded*, and a value past\n * {@link MAX_TIMER_MS} silently meaning *1ms*. Both are worse than an error, because the\n * call still returns a plausible-looking result.\n *\n * `undefined` and `Infinity` both mean unbounded; `Infinity` is the documented way to opt\n * a single call out of a client-wide deadline.\n */\nexport function resolveTimeoutMs(value: number | undefined): number {\n\tif (value === undefined || value === Number.POSITIVE_INFINITY) {\n\t\treturn Number.POSITIVE_INFINITY;\n\t}\n\tif (typeof value !== \"number\" || Number.isNaN(value) || value <= 0) {\n\t\tthrow new NeonError(\n\t\t\t`requestTimeoutMs must be a positive number of milliseconds, or Infinity to disable; received ${String(value)}.`,\n\t\t\t\"client\",\n\t\t);\n\t}\n\tif (value > MAX_TIMER_MS) {\n\t\tthrow new NeonError(\n\t\t\t`requestTimeoutMs must be at most ${MAX_TIMER_MS}ms (about 24.8 days); received ${value}. Pass Infinity for no deadline.`,\n\t\t\t\"client\",\n\t\t);\n\t}\n\treturn value;\n}\n\n/**\n * The typed error for a deadline that has fired, or `undefined` if it has not.\n *\n * Cancellation is classified from the deadline's own state rather than from the shape of\n * the error that came back. The generated client funnels authentication, serialization,\n * interceptor, transport and parsing faults through one channel, so an error merely named\n * `AbortError` is not evidence that the caller cancelled.\n */\nexport function cancelled(deadline: Deadline): NeonError | undefined {\n\tconst source = deadline.source();\n\tif (source === \"caller\") {\n\t\treturn new NeonAbortError(\"The request was aborted by its signal.\");\n\t}\n\tif (source === \"timeout\") {\n\t\treturn new NeonTimeoutError(\n\t\t\t\"Timed out waiting for the Neon API to respond (requestTimeoutMs).\",\n\t\t);\n\t}\n\treturn undefined;\n}\n\n/**\n * Race `run()` against the deadline, resolving `undefined` when the deadline wins.\n *\n * The signal alone does not bound a call. The generated client awaits authentication and\n * request interceptors before it constructs the `Request`, and a caller-supplied `fetch`\n * need not honour a signal at all, so an `apiKey` function that never resolves would\n * otherwise hang forever even with a deadline set.\n */\nexport async function runBounded<T>(\n\tdeadline: Deadline,\n\trun: () => Promise<T>,\n): Promise<T | undefined> {\n\tif (!deadline.signal) return run();\n\tconst execution = run();\n\t// The losing arm still settles later. Without a handler, its rejection is reported as\n\t// unhandled once the deadline has already answered the caller.\n\texecution.catch(() => {});\n\treturn Promise.race([execution, deadline.fired().then(() => undefined)]);\n}\n\n/**\n * Wait `ms`, or stop early when `signal` aborts. Resolves either way — an abort is\n * reported as `\"cancelled\"` rather than thrown, and the listener is always removed so a\n * long-lived caller signal doesn't accumulate one per wait.\n */\nexport function delay(ms: number, signal?: AbortSignal): Promise<DelayOutcome> {\n\tif (signal?.aborted) return Promise.resolve(\"cancelled\");\n\treturn new Promise<DelayOutcome>((resolve) => {\n\t\tconst onAbort = () => {\n\t\t\tclearTimeout(timer);\n\t\t\tresolve(\"cancelled\");\n\t\t};\n\t\tconst timer = setTimeout(() => {\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\tresolve(\"elapsed\");\n\t\t}, ms);\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n}\n\n/**\n * Build the deadline for one call.\n *\n * `timeoutMs` is `Infinity` when no request timeout applies. With no timeout and no caller\n * signal there is nothing to cancel, so a shared no-op deadline is returned and no timer\n * or controller is allocated.\n */\nexport function createDeadline(\n\ttimeoutMs: number,\n\tcallerSignal?: AbortSignal,\n): Deadline {\n\tconst bounded = Number.isFinite(timeoutMs);\n\tif (!bounded && !callerSignal) return UNBOUNDED;\n\n\t// Monotonic: a wall-clock jump (NTP correction, manual change) would otherwise expire\n\t// a deadline early or extend one whose timer is being starved.\n\tconst startedAt = performance.now();\n\tconst controller = new AbortController();\n\tlet source: DeadlineSource | undefined;\n\tlet notify: (() => void) | undefined;\n\tconst fired = new Promise<void>((resolve) => {\n\t\tnotify = resolve;\n\t});\n\n\tconst trip = (reason: DeadlineSource) => {\n\t\tif (source) return;\n\t\tsource = reason;\n\t\tcontroller.abort();\n\t\tnotify?.();\n\t};\n\n\tif (callerSignal?.aborted) trip(\"caller\");\n\n\tconst onCallerAbort = () => trip(\"caller\");\n\tconst remainingMs = () =>\n\t\tbounded\n\t\t\t? Math.max(0, timeoutMs - (performance.now() - startedAt))\n\t\t\t: Number.POSITIVE_INFINITY;\n\n\t// Deliberately not `unref`ed: every deadline is disposed in a `finally`, so it cannot\n\t// outlive its call, and an unref'd timer is invisible to the event loop's liveness\n\t// accounting — a call whose only pending work is the deadline would starve instead of\n\t// timing out.\n\t//\n\t// Re-armed in chunks rather than scheduled once, because `setTimeout` silently\n\t// collapses any delay above MAX_TIMER_MS to 1ms. `wait.timeoutMs` has always accepted\n\t// arbitrarily large budgets, and a single timer would have turned one into an instant\n\t// timeout.\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tconst arm = () => {\n\t\tconst left = remainingMs();\n\t\tif (left === 0) return trip(\"timeout\");\n\t\ttimer = setTimeout(\n\t\t\tleft > MAX_TIMER_MS ? arm : () => trip(\"timeout\"),\n\t\t\tMath.min(left, MAX_TIMER_MS),\n\t\t);\n\t};\n\tif (bounded) arm();\n\tcallerSignal?.addEventListener(\"abort\", onCallerAbort, { once: true });\n\n\treturn {\n\t\tsignal: controller.signal,\n\t\tremainingMs,\n\t\tsource: () => {\n\t\t\tif (!source && remainingMs() === 0) trip(\"timeout\");\n\t\t\treturn source;\n\t\t},\n\t\tfired: () => fired,\n\t\tdispose: () => {\n\t\t\tclearTimeout(timer);\n\t\t\tcallerSignal?.removeEventListener(\"abort\", onCallerAbort);\n\t\t},\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqBA,MAAM,eAAe,KAAK,KAAK;AAmC/B,MAAM,YAAsB;CAC3B,QAAQ,KAAA;CACR,mBAAmB,OAAO;CAC1B,cAAc,KAAA;CACd,aAAa,IAAI,cAAoB,CAAC,CAAC;CACvC,eAAe,CAAC;AACjB;;;;;;;;;;;;AAaA,SAAgB,iBAAiB,OAAmC;CACnE,IAAI,UAAU,KAAA,KAAa,UAAU,OAAO,mBAC3C,OAAO,OAAO;CAEf,IAAI,OAAO,UAAU,YAAY,OAAO,MAAM,KAAK,KAAK,SAAS,GAChE,MAAM,IAAI,UACT,gGAAgG,OAAO,KAAK,EAAE,IAC9G,QACD;CAED,IAAI,QAAQ,cACX,MAAM,IAAI,UACT,oCAAoC,aAAa,iCAAiC,MAAM,mCACxF,QACD;CAED,OAAO;AACR;;;;;;;;;AAUA,SAAgB,UAAU,UAA2C;CACpE,MAAM,SAAS,SAAS,OAAO;CAC/B,IAAI,WAAW,UACd,OAAO,IAAI,eAAe,wCAAwC;CAEnE,IAAI,WAAW,WACd,OAAO,IAAI,iBACV,mEACD;AAGF;;;;;;;;;AAUA,eAAsB,WACrB,UACA,KACyB;CACzB,IAAI,CAAC,SAAS,QAAQ,OAAO,IAAI;CACjC,MAAM,YAAY,IAAI;CAGtB,UAAU,YAAY,CAAC,CAAC;CACxB,OAAO,QAAQ,KAAK,CAAC,WAAW,SAAS,MAAM,CAAC,CAAC,WAAW,KAAA,CAAS,CAAC,CAAC;AACxE;;;;;;AAOA,SAAgB,MAAM,IAAY,QAA6C;CAC9E,IAAI,QAAQ,SAAS,OAAO,QAAQ,QAAQ,WAAW;CACvD,OAAO,IAAI,SAAuB,YAAY;EAC7C,MAAM,gBAAgB;GACrB,aAAa,KAAK;GAClB,QAAQ,WAAW;EACpB;EACA,MAAM,QAAQ,iBAAiB;GAC9B,QAAQ,oBAAoB,SAAS,OAAO;GAC5C,QAAQ,SAAS;EAClB,GAAG,EAAE;EACL,QAAQ,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAC1D,CAAC;AACF;;;;;;;;AASA,SAAgB,eACf,WACA,cACW;CACX,MAAM,UAAU,OAAO,SAAS,SAAS;CACzC,IAAI,CAAC,WAAW,CAAC,cAAc,OAAO;CAItC,MAAM,YAAY,YAAY,IAAI;CAClC,MAAM,aAAa,IAAI,gBAAgB;CACvC,IAAI;CACJ,IAAI;CACJ,MAAM,QAAQ,IAAI,SAAe,YAAY;EAC5C,SAAS;CACV,CAAC;CAED,MAAM,QAAQ,WAA2B;EACxC,IAAI,QAAQ;EACZ,SAAS;EACT,WAAW,MAAM;EACjB,SAAS;CACV;CAEA,IAAI,cAAc,SAAS,KAAK,QAAQ;CAExC,MAAM,sBAAsB,KAAK,QAAQ;CACzC,MAAM,oBACL,UACG,KAAK,IAAI,GAAG,aAAa,YAAY,IAAI,IAAI,UAAU,IACvD,OAAO;CAWX,IAAI;CACJ,MAAM,YAAY;EACjB,MAAM,OAAO,YAAY;EACzB,IAAI,SAAS,GAAG,OAAO,KAAK,SAAS;EACrC,QAAQ,WACP,OAAO,eAAe,YAAY,KAAK,SAAS,GAChD,KAAK,IAAI,MAAM,YAAY,CAC5B;CACD;CACA,IAAI,SAAS,IAAI;CACjB,cAAc,iBAAiB,SAAS,eAAe,EAAE,MAAM,KAAK,CAAC;CAErE,OAAO;EACN,QAAQ,WAAW;EACnB;EACA,cAAc;GACb,IAAI,CAAC,UAAU,YAAY,MAAM,GAAG,KAAK,SAAS;GAClD,OAAO;EACR;EACA,aAAa;EACb,eAAe;GACd,aAAa,KAAK;GAClB,cAAc,oBAAoB,SAAS,aAAa;EACzD;CACD;AACD"}
@@ -5,7 +5,7 @@
5
5
  * discriminant, so the same value works whether you read it from `{ error }` or `catch`
6
6
  * it.
7
7
  */
8
- type NeonErrorKind = "api" | "not_found" | "auth" | "rate_limit" | "operation" | "timeout" | "network" | "client";
8
+ type NeonErrorKind = "api" | "not_found" | "auth" | "rate_limit" | "operation" | "timeout" | "aborted" | "network" | "client";
9
9
  /**
10
10
  * Base class for every error the ergonomic layer produces.
11
11
  *
@@ -64,10 +64,29 @@ declare class NeonOperationError extends NeonError {
64
64
  status: string;
65
65
  });
66
66
  }
67
- /** Waiting for operations to finish exceeded the configured timeout. */
67
+ /**
68
+ * A deadline was exceeded — either `requestTimeoutMs` for a request and its retries, or
69
+ * the `wait` budget while polling operations for readiness.
70
+ */
68
71
  declare class NeonTimeoutError extends NeonError {
69
72
  constructor(message: string);
70
73
  }
74
+ /**
75
+ * The caller's `AbortSignal` fired. Distinct from {@link NeonTimeoutError} because nothing
76
+ * went wrong: the caller asked for the work to stop, and the two call for different
77
+ * handling (retry a timeout, don't retry a cancellation).
78
+ *
79
+ * Raised only where the SDK knows the caller cancelled — the call's own deadline, or an
80
+ * already-aborted `signal` on a raw call. A transport failure that merely looks like an
81
+ * abort stays a {@link NeonNetworkError}, since the generated client reports auth,
82
+ * serialization, interceptor and parsing faults through the same channel and an error's
83
+ * name is not evidence about which one occurred.
84
+ */
85
+ declare class NeonAbortError extends NeonError {
86
+ constructor(message: string, options?: {
87
+ cause?: unknown;
88
+ });
89
+ }
71
90
  /** A transport-level failure (DNS, connection, abort) — no HTTP response received. */
72
91
  declare class NeonNetworkError extends NeonError {
73
92
  /**
@@ -97,5 +116,5 @@ declare function describeTransportFailure(error: unknown): string;
97
116
  */
98
117
  declare function toNeonError(error: unknown, response: Response | undefined): NeonError;
99
118
  //#endregion
100
- export { NeonApiError, NeonAuthError, NeonError, NeonErrorKind, NeonNetworkError, NeonNotFoundError, NeonOperationError, NeonRateLimitError, NeonTimeoutError, describeTransportFailure, toNeonError };
119
+ export { NeonAbortError, NeonApiError, NeonAuthError, NeonError, NeonErrorKind, NeonNetworkError, NeonNotFoundError, NeonOperationError, NeonRateLimitError, NeonTimeoutError, describeTransportFailure, toNeonError };
101
120
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","names":[],"sources":["../../src/neon/errors.ts"],"mappings":";;AAUA;AAkBA;AAAuB;AACP;AAIR;AALuB,KAlBnB,aAAA,GAkBmB,KAAA,GAAA,WAAA,GAAA,MAAA,GAAA,YAAA,GAAA,WAAA,GAAA,SAAA,GAAA,SAAA,GAAA,QAAA;AAAK;AAepC;AAA0B;AAQL;AAOX;AAII;AAnBoB;AAAS;AAkC9B,cAjDA,SAAA,SAAkB,KAAA,CAiDA;EAAA,SAAA,IAAA,EAhDf,aAgDe;EAGM,WAAA,CAAA,OAAA,EAAA,MAAA,EAAA,IAAA,EA/C7B,aA+C6B,EAAA,OAHE,CAGF,EAAA;IAA7B,KAAA,CAAA,EAAA,OAAA;EAH+B,CAAA;AAAY;AAWnD;AAA2B,cA7Cd,YAAA,SAAqB,SAAA,CA6CP;EAGU;EAA7B,SAAA,MAAA,EAAA,MAAA;EAH2B;EAAY,SAAA,IAAA,CAAA,EAAA,MAAA;EAWlC;EAAmB,SAAA,SAAA,CAAA,EAAA,MAAA;EAGK;EAA7B,SAAA,QAAA,CAAA,EAnDa,QAmDb;EAHgC;EAAY,SAAA,IAAA,EAAA,OAAA;EAWvC,WAAA,CAAA,OAAA,EAAmB,MAAA,EAAA,IAAA,EAAQ;IAkB3B,IAAA,CAAA,EAtEH,aAsEoB;IAQjB,MAAA,EAAA,MAAA;IA4CG,IAAA,CAAA,EAAA,MAAA;IAsBA,SAAA,CAAW,EAAA,MAAA;IAAA,QAAA,CAAA,EA5Ib,QA4Ia;IAEhB,IAAA,CAAA,EAAA,OAAA;EACR,CAAA;AAAS;;cAhIC,iBAAA,SAA0B,YAAA;qCAG/B,6BAA6B;;;cAQxB,aAAA,SAAsB,YAAA;qCAG3B,6BAA6B;;;cAQxB,kBAAA,SAA2B,YAAA;qCAGhC,6BAA6B;;;cAQxB,kBAAA,SAA2B,SAAS;;;;;;;;;;;cAkBpC,gBAAA,SAAyB,SAAS;;;;cAQlC,gBAAA,SAAyB,SAAS;;;;;;;;;;;;;;;;;;;;iBA4C/B,wBAAA;;;;;;iBAsBA,WAAA,2BAEL,uBACR"}
1
+ {"version":3,"file":"errors.d.ts","names":[],"sources":["../../src/neon/errors.ts"],"mappings":";;AAUA;AAmBA;AAAuB;AACP;AAIR;AALuB,KAnBnB,aAAA,GAmBmB,KAAA,GAAA,WAAA,GAAA,MAAA,GAAA,YAAA,GAAA,WAAA,GAAA,SAAA,GAAA,SAAA,GAAA,SAAA,GAAA,QAAA;AAAK;AAepC;AAA0B;AAQL;AAOX;AAII;AAnBoB;AAAS;AAkC9B,cAjDA,SAAA,SAAkB,KAAA,CAiDA;EAAA,SAAA,IAAA,EAhDf,aAgDe;EAGM,WAAA,CAAA,OAAA,EAAA,MAAA,EAAA,IAAA,EA/C7B,aA+C6B,EAAA,OAHE,CAGF,EAAA;IAA7B,KAAA,CAAA,EAAA,OAAA;EAH+B,CAAA;AAAY;AAWnD;AAA2B,cA7Cd,YAAA,SAAqB,SAAA,CA6CP;EAGU;EAA7B,SAAA,MAAA,EAAA,MAAA;EAH2B;EAAY,SAAA,IAAA,CAAA,EAAA,MAAA;EAWlC;EAAmB,SAAA,SAAA,CAAA,EAAA,MAAA;EAGK;EAA7B,SAAA,QAAA,CAAA,EAnDa,QAmDb;EAHgC;EAAY,SAAA,IAAA,EAAA,OAAA;EAWvC,WAAA,CAAA,OAAA,EAAmB,MAAA,EAAA,IAAA,EAAQ;IAqB3B,IAAA,CAAA,EAzEH,aAyEoB;IAkBjB,MAAA,EAAA,MAAe;IAQf,IAAA,CAAA,EAAA,MAAA;IA4CG,SAAA,CAAA,EAAA,MAAA;IAsBA,QAAA,CAAA,EAjKF,QAiKa;IAAA,IAAA,CAAA,EAAA,OAAA;EAEhB,CAAA;AACR;AAAS;cArJC,iBAAA,SAA0B,YAAA;qCAG/B,6BAA6B;;;cAQxB,aAAA,SAAsB,YAAA;qCAG3B,6BAA6B;;;cAQxB,kBAAA,SAA2B,YAAA;qCAGhC,6BAA6B;;;cAQxB,kBAAA,SAA2B,SAAS;;;;;;;;;;;;;;cAqBpC,gBAAA,SAAyB,SAAS;;;;;;;;;;;;;;cAkBlC,cAAA,SAAuB,SAAS;;;;;;cAQhC,gBAAA,SAAyB,SAAS;;;;;;;;;;;;;;;;;;;;iBA4C/B,wBAAA;;;;;;iBAsBA,WAAA,2BAEL,uBACR"}
@@ -88,13 +88,33 @@ var NeonOperationError = class extends NeonError {
88
88
  this.status = init.status;
89
89
  }
90
90
  };
91
- /** Waiting for operations to finish exceeded the configured timeout. */
91
+ /**
92
+ * A deadline was exceeded — either `requestTimeoutMs` for a request and its retries, or
93
+ * the `wait` budget while polling operations for readiness.
94
+ */
92
95
  var NeonTimeoutError = class extends NeonError {
93
96
  constructor(message) {
94
97
  super(message, "timeout");
95
98
  this.name = "NeonTimeoutError";
96
99
  }
97
100
  };
101
+ /**
102
+ * The caller's `AbortSignal` fired. Distinct from {@link NeonTimeoutError} because nothing
103
+ * went wrong: the caller asked for the work to stop, and the two call for different
104
+ * handling (retry a timeout, don't retry a cancellation).
105
+ *
106
+ * Raised only where the SDK knows the caller cancelled — the call's own deadline, or an
107
+ * already-aborted `signal` on a raw call. A transport failure that merely looks like an
108
+ * abort stays a {@link NeonNetworkError}, since the generated client reports auth,
109
+ * serialization, interceptor and parsing faults through the same channel and an error's
110
+ * name is not evidence about which one occurred.
111
+ */
112
+ var NeonAbortError = class extends NeonError {
113
+ constructor(message, options) {
114
+ super(message, "aborted", options);
115
+ this.name = "NeonAbortError";
116
+ }
117
+ };
98
118
  /** A transport-level failure (DNS, connection, abort) — no HTTP response received. */
99
119
  var NeonNetworkError = class extends NeonError {
100
120
  /**
@@ -166,6 +186,6 @@ function toNeonError(error, response) {
166
186
  return new NeonApiError(message, init);
167
187
  }
168
188
  //#endregion
169
- export { NeonApiError, NeonAuthError, NeonError, NeonNetworkError, NeonNotFoundError, NeonOperationError, NeonRateLimitError, NeonTimeoutError, describeTransportFailure, toNeonError };
189
+ export { NeonAbortError, NeonApiError, NeonAuthError, NeonError, NeonNetworkError, NeonNotFoundError, NeonOperationError, NeonRateLimitError, NeonTimeoutError, describeTransportFailure, toNeonError };
170
190
 
171
191
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","names":[],"sources":["../../src/neon/errors.ts"],"sourcesContent":["/**\n * Typed error hierarchy surfaced on the `error` channel of every ergonomic call (and\n * thrown when `throwOnError` is set). All are `Error` subclasses with a `kind`\n * discriminant, so the same value works whether you read it from `{ error }` or `catch`\n * it.\n */\n\n/** Used when a transport failure carries neither an `errno` code nor any message. */\nconst UNKNOWN_TRANSPORT_REASON = \"cause unavailable\";\n\nexport type NeonErrorKind =\n\t| \"api\"\n\t| \"not_found\"\n\t| \"auth\"\n\t| \"rate_limit\"\n\t| \"operation\"\n\t| \"timeout\"\n\t| \"network\"\n\t| \"client\";\n\n/**\n * Base class for every error the ergonomic layer produces.\n *\n * Every subclass assigns `this.name` as a string literal rather than reading it from the\n * constructor. Bundlers rename classes, so deriving the name at runtime leaves consumers\n * of a minified build with errors called `s` and `r` — unreadable in logs and impossible\n * to group on in an error tracker.\n */\nexport class NeonError extends Error {\n\treadonly kind: NeonErrorKind;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tkind: NeonErrorKind,\n\t\toptions?: { cause?: unknown },\n\t) {\n\t\tsuper(message, options);\n\t\tthis.name = \"NeonError\";\n\t\tthis.kind = kind;\n\t}\n}\n\n/** A non-2xx HTTP response from the Neon API. */\nexport class NeonApiError extends NeonError {\n\t/** HTTP status code. */\n\treadonly status: number;\n\t/** Machine-readable Neon error code (`GeneralError.code`), when present. */\n\treadonly code?: string;\n\t/** Neon request id (`X-Request-Id` / `GeneralError.request_id`), when present. */\n\treadonly requestId?: string;\n\t/** The raw response, when one was received. */\n\treadonly response?: Response;\n\t/** The parsed error body, as returned by the API. */\n\treadonly body: unknown;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tinit: {\n\t\t\tkind?: NeonErrorKind;\n\t\t\tstatus: number;\n\t\t\tcode?: string;\n\t\t\trequestId?: string;\n\t\t\tresponse?: Response;\n\t\t\tbody?: unknown;\n\t\t},\n\t) {\n\t\tsuper(message, init.kind ?? \"api\");\n\t\tthis.name = \"NeonApiError\";\n\t\tthis.status = init.status;\n\t\tthis.code = init.code;\n\t\tthis.requestId = init.requestId;\n\t\tthis.response = init.response;\n\t\tthis.body = init.body;\n\t}\n}\n\n/** 404 — the resource does not exist. */\nexport class NeonNotFoundError extends NeonApiError {\n\tconstructor(\n\t\tmessage: string,\n\t\tinit: ConstructorParameters<typeof NeonApiError>[1],\n\t) {\n\t\tsuper(message, { ...init, kind: \"not_found\" });\n\t\tthis.name = \"NeonNotFoundError\";\n\t}\n}\n\n/** 401/403 — the API key is missing, invalid, or lacks permission. */\nexport class NeonAuthError extends NeonApiError {\n\tconstructor(\n\t\tmessage: string,\n\t\tinit: ConstructorParameters<typeof NeonApiError>[1],\n\t) {\n\t\tsuper(message, { ...init, kind: \"auth\" });\n\t\tthis.name = \"NeonAuthError\";\n\t}\n}\n\n/** 429 — rate limited (after retries, if enabled, were exhausted). */\nexport class NeonRateLimitError extends NeonApiError {\n\tconstructor(\n\t\tmessage: string,\n\t\tinit: ConstructorParameters<typeof NeonApiError>[1],\n\t) {\n\t\tsuper(message, { ...init, kind: \"rate_limit\" });\n\t\tthis.name = \"NeonRateLimitError\";\n\t}\n}\n\n/** An awaited Neon operation ended in a non-success terminal state. */\nexport class NeonOperationError extends NeonError {\n\t/** The id of the operation that failed. */\n\treadonly operationId: string;\n\t/** The terminal status reported by the API (`failed` / `error` / `cancelled`). */\n\treadonly status: string;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tinit: { operationId: string; status: string },\n\t) {\n\t\tsuper(message, \"operation\");\n\t\tthis.name = \"NeonOperationError\";\n\t\tthis.operationId = init.operationId;\n\t\tthis.status = init.status;\n\t}\n}\n\n/** Waiting for operations to finish exceeded the configured timeout. */\nexport class NeonTimeoutError extends NeonError {\n\tconstructor(message: string) {\n\t\tsuper(message, \"timeout\");\n\t\tthis.name = \"NeonTimeoutError\";\n\t}\n}\n\n/** A transport-level failure (DNS, connection, abort) — no HTTP response received. */\nexport class NeonNetworkError extends NeonError {\n\t/**\n\t * The most specific reason the platform gave for the failure — an `errno` code such as\n\t * `ECONNRESET` when one is available, otherwise the innermost non-empty message. Read\n\t * this instead of matching on {@link message}.\n\t */\n\treadonly reason: string;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: { cause?: unknown; reason?: string },\n\t) {\n\t\tsuper(message, \"network\", { cause: options?.cause });\n\t\tthis.name = \"NeonNetworkError\";\n\t\tthis.reason = options?.reason ?? UNKNOWN_TRANSPORT_REASON;\n\t}\n}\n\ninterface ApiErrorBody {\n\tmessage?: string;\n\tcode?: string;\n\trequest_id?: string;\n}\n\nfunction readApiErrorBody(body: unknown): ApiErrorBody {\n\tif (typeof body !== \"object\" || body === null) return {};\n\tconst out: ApiErrorBody = {};\n\tif (\"message\" in body && typeof body.message === \"string\")\n\t\tout.message = body.message;\n\tif (\"code\" in body && typeof body.code === \"string\") out.code = body.code;\n\tif (\"request_id\" in body && typeof body.request_id === \"string\") {\n\t\tout.request_id = body.request_id;\n\t}\n\treturn out;\n}\n\n/**\n * Walk a transport failure's `cause` chain for the most specific description available.\n *\n * `fetch` reports every transport fault as `TypeError: fetch failed` and puts the real\n * reason underneath, sometimes several levels down and sometimes with an empty message and\n * only an `errno` code. Without this, a DNS failure, a reset connection and a redirect the\n * client refused to follow all produce the same sentence.\n */\nexport function describeTransportFailure(error: unknown): string {\n\tconst seen = new Set<unknown>();\n\tlet current: unknown = error;\n\tlet deepestMessage: string | undefined;\n\n\twhile (current instanceof Error && !seen.has(current)) {\n\t\tseen.add(current);\n\t\tif (\"code\" in current && typeof current.code === \"string\") {\n\t\t\treturn current.code;\n\t\t}\n\t\tif (current.message) deepestMessage = current.message;\n\t\tcurrent = current.cause;\n\t}\n\n\treturn deepestMessage ?? UNKNOWN_TRANSPORT_REASON;\n}\n\n/**\n * Build the right {@link NeonError} subclass from a raw client result. `error` is the\n * decoded error body (Neon `GeneralError`); `response` is present unless the failure was\n * transport-level.\n */\nexport function toNeonError(\n\terror: unknown,\n\tresponse: Response | undefined,\n): NeonError {\n\tif (!response) {\n\t\tconst reason = describeTransportFailure(error);\n\t\treturn new NeonNetworkError(\n\t\t\t`Network error: no response received from the Neon API (${reason}).`,\n\t\t\t{ cause: error, reason },\n\t\t);\n\t}\n\n\tconst parsed = readApiErrorBody(error);\n\tconst status = response.status;\n\tconst message =\n\t\tparsed.message ?? `Neon API request failed with status ${status}.`;\n\tconst init = {\n\t\tstatus,\n\t\tcode: parsed.code,\n\t\trequestId:\n\t\t\tparsed.request_id ??\n\t\t\tresponse.headers.get(\"x-request-id\") ??\n\t\t\tundefined,\n\t\tresponse,\n\t\tbody: error,\n\t};\n\n\tif (status === 404) return new NeonNotFoundError(message, init);\n\tif (status === 401 || status === 403)\n\t\treturn new NeonAuthError(message, init);\n\tif (status === 429) return new NeonRateLimitError(message, init);\n\treturn new NeonApiError(message, init);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../../src/neon/errors.ts"],"sourcesContent":["/**\n * Typed error hierarchy surfaced on the `error` channel of every ergonomic call (and\n * thrown when `throwOnError` is set). All are `Error` subclasses with a `kind`\n * discriminant, so the same value works whether you read it from `{ error }` or `catch`\n * it.\n */\n\n/** Used when a transport failure carries neither an `errno` code nor any message. */\nconst UNKNOWN_TRANSPORT_REASON = \"cause unavailable\";\n\nexport type NeonErrorKind =\n\t| \"api\"\n\t| \"not_found\"\n\t| \"auth\"\n\t| \"rate_limit\"\n\t| \"operation\"\n\t| \"timeout\"\n\t| \"aborted\"\n\t| \"network\"\n\t| \"client\";\n\n/**\n * Base class for every error the ergonomic layer produces.\n *\n * Every subclass assigns `this.name` as a string literal rather than reading it from the\n * constructor. Bundlers rename classes, so deriving the name at runtime leaves consumers\n * of a minified build with errors called `s` and `r` — unreadable in logs and impossible\n * to group on in an error tracker.\n */\nexport class NeonError extends Error {\n\treadonly kind: NeonErrorKind;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tkind: NeonErrorKind,\n\t\toptions?: { cause?: unknown },\n\t) {\n\t\tsuper(message, options);\n\t\tthis.name = \"NeonError\";\n\t\tthis.kind = kind;\n\t}\n}\n\n/** A non-2xx HTTP response from the Neon API. */\nexport class NeonApiError extends NeonError {\n\t/** HTTP status code. */\n\treadonly status: number;\n\t/** Machine-readable Neon error code (`GeneralError.code`), when present. */\n\treadonly code?: string;\n\t/** Neon request id (`X-Request-Id` / `GeneralError.request_id`), when present. */\n\treadonly requestId?: string;\n\t/** The raw response, when one was received. */\n\treadonly response?: Response;\n\t/** The parsed error body, as returned by the API. */\n\treadonly body: unknown;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tinit: {\n\t\t\tkind?: NeonErrorKind;\n\t\t\tstatus: number;\n\t\t\tcode?: string;\n\t\t\trequestId?: string;\n\t\t\tresponse?: Response;\n\t\t\tbody?: unknown;\n\t\t},\n\t) {\n\t\tsuper(message, init.kind ?? \"api\");\n\t\tthis.name = \"NeonApiError\";\n\t\tthis.status = init.status;\n\t\tthis.code = init.code;\n\t\tthis.requestId = init.requestId;\n\t\tthis.response = init.response;\n\t\tthis.body = init.body;\n\t}\n}\n\n/** 404 — the resource does not exist. */\nexport class NeonNotFoundError extends NeonApiError {\n\tconstructor(\n\t\tmessage: string,\n\t\tinit: ConstructorParameters<typeof NeonApiError>[1],\n\t) {\n\t\tsuper(message, { ...init, kind: \"not_found\" });\n\t\tthis.name = \"NeonNotFoundError\";\n\t}\n}\n\n/** 401/403 — the API key is missing, invalid, or lacks permission. */\nexport class NeonAuthError extends NeonApiError {\n\tconstructor(\n\t\tmessage: string,\n\t\tinit: ConstructorParameters<typeof NeonApiError>[1],\n\t) {\n\t\tsuper(message, { ...init, kind: \"auth\" });\n\t\tthis.name = \"NeonAuthError\";\n\t}\n}\n\n/** 429 — rate limited (after retries, if enabled, were exhausted). */\nexport class NeonRateLimitError extends NeonApiError {\n\tconstructor(\n\t\tmessage: string,\n\t\tinit: ConstructorParameters<typeof NeonApiError>[1],\n\t) {\n\t\tsuper(message, { ...init, kind: \"rate_limit\" });\n\t\tthis.name = \"NeonRateLimitError\";\n\t}\n}\n\n/** An awaited Neon operation ended in a non-success terminal state. */\nexport class NeonOperationError extends NeonError {\n\t/** The id of the operation that failed. */\n\treadonly operationId: string;\n\t/** The terminal status reported by the API (`failed` / `error` / `cancelled`). */\n\treadonly status: string;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tinit: { operationId: string; status: string },\n\t) {\n\t\tsuper(message, \"operation\");\n\t\tthis.name = \"NeonOperationError\";\n\t\tthis.operationId = init.operationId;\n\t\tthis.status = init.status;\n\t}\n}\n\n/**\n * A deadline was exceeded — either `requestTimeoutMs` for a request and its retries, or\n * the `wait` budget while polling operations for readiness.\n */\nexport class NeonTimeoutError extends NeonError {\n\tconstructor(message: string) {\n\t\tsuper(message, \"timeout\");\n\t\tthis.name = \"NeonTimeoutError\";\n\t}\n}\n\n/**\n * The caller's `AbortSignal` fired. Distinct from {@link NeonTimeoutError} because nothing\n * went wrong: the caller asked for the work to stop, and the two call for different\n * handling (retry a timeout, don't retry a cancellation).\n *\n * Raised only where the SDK knows the caller cancelled — the call's own deadline, or an\n * already-aborted `signal` on a raw call. A transport failure that merely looks like an\n * abort stays a {@link NeonNetworkError}, since the generated client reports auth,\n * serialization, interceptor and parsing faults through the same channel and an error's\n * name is not evidence about which one occurred.\n */\nexport class NeonAbortError extends NeonError {\n\tconstructor(message: string, options?: { cause?: unknown }) {\n\t\tsuper(message, \"aborted\", options);\n\t\tthis.name = \"NeonAbortError\";\n\t}\n}\n\n/** A transport-level failure (DNS, connection, abort) — no HTTP response received. */\nexport class NeonNetworkError extends NeonError {\n\t/**\n\t * The most specific reason the platform gave for the failure — an `errno` code such as\n\t * `ECONNRESET` when one is available, otherwise the innermost non-empty message. Read\n\t * this instead of matching on {@link message}.\n\t */\n\treadonly reason: string;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: { cause?: unknown; reason?: string },\n\t) {\n\t\tsuper(message, \"network\", { cause: options?.cause });\n\t\tthis.name = \"NeonNetworkError\";\n\t\tthis.reason = options?.reason ?? UNKNOWN_TRANSPORT_REASON;\n\t}\n}\n\ninterface ApiErrorBody {\n\tmessage?: string;\n\tcode?: string;\n\trequest_id?: string;\n}\n\nfunction readApiErrorBody(body: unknown): ApiErrorBody {\n\tif (typeof body !== \"object\" || body === null) return {};\n\tconst out: ApiErrorBody = {};\n\tif (\"message\" in body && typeof body.message === \"string\")\n\t\tout.message = body.message;\n\tif (\"code\" in body && typeof body.code === \"string\") out.code = body.code;\n\tif (\"request_id\" in body && typeof body.request_id === \"string\") {\n\t\tout.request_id = body.request_id;\n\t}\n\treturn out;\n}\n\n/**\n * Walk a transport failure's `cause` chain for the most specific description available.\n *\n * `fetch` reports every transport fault as `TypeError: fetch failed` and puts the real\n * reason underneath, sometimes several levels down and sometimes with an empty message and\n * only an `errno` code. Without this, a DNS failure, a reset connection and a redirect the\n * client refused to follow all produce the same sentence.\n */\nexport function describeTransportFailure(error: unknown): string {\n\tconst seen = new Set<unknown>();\n\tlet current: unknown = error;\n\tlet deepestMessage: string | undefined;\n\n\twhile (current instanceof Error && !seen.has(current)) {\n\t\tseen.add(current);\n\t\tif (\"code\" in current && typeof current.code === \"string\") {\n\t\t\treturn current.code;\n\t\t}\n\t\tif (current.message) deepestMessage = current.message;\n\t\tcurrent = current.cause;\n\t}\n\n\treturn deepestMessage ?? UNKNOWN_TRANSPORT_REASON;\n}\n\n/**\n * Build the right {@link NeonError} subclass from a raw client result. `error` is the\n * decoded error body (Neon `GeneralError`); `response` is present unless the failure was\n * transport-level.\n */\nexport function toNeonError(\n\terror: unknown,\n\tresponse: Response | undefined,\n): NeonError {\n\tif (!response) {\n\t\tconst reason = describeTransportFailure(error);\n\t\treturn new NeonNetworkError(\n\t\t\t`Network error: no response received from the Neon API (${reason}).`,\n\t\t\t{ cause: error, reason },\n\t\t);\n\t}\n\n\tconst parsed = readApiErrorBody(error);\n\tconst status = response.status;\n\tconst message =\n\t\tparsed.message ?? `Neon API request failed with status ${status}.`;\n\tconst init = {\n\t\tstatus,\n\t\tcode: parsed.code,\n\t\trequestId:\n\t\t\tparsed.request_id ??\n\t\t\tresponse.headers.get(\"x-request-id\") ??\n\t\t\tundefined,\n\t\tresponse,\n\t\tbody: error,\n\t};\n\n\tif (status === 404) return new NeonNotFoundError(message, init);\n\tif (status === 401 || status === 403)\n\t\treturn new NeonAuthError(message, init);\n\tif (status === 429) return new NeonRateLimitError(message, init);\n\treturn new NeonApiError(message, init);\n}\n"],"mappings":";;;;;;;;AAQA,MAAM,2BAA2B;;;;;;;;;AAqBjC,IAAa,YAAb,cAA+B,MAAM;CACpC;CAEA,YACC,SACA,MACA,SACC;EACD,MAAM,SAAS,OAAO;EACtB,KAAK,OAAO;EACZ,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,eAAb,cAAkC,UAAU;;CAE3C;;CAEA;;CAEA;;CAEA;;CAEA;CAEA,YACC,SACA,MAQC;EACD,MAAM,SAAS,KAAK,QAAQ,KAAK;EACjC,KAAK,OAAO;EACZ,KAAK,SAAS,KAAK;EACnB,KAAK,OAAO,KAAK;EACjB,KAAK,YAAY,KAAK;EACtB,KAAK,WAAW,KAAK;EACrB,KAAK,OAAO,KAAK;CAClB;AACD;;AAGA,IAAa,oBAAb,cAAuC,aAAa;CACnD,YACC,SACA,MACC;EACD,MAAM,SAAS;GAAE,GAAG;GAAM,MAAM;EAAY,CAAC;EAC7C,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,gBAAb,cAAmC,aAAa;CAC/C,YACC,SACA,MACC;EACD,MAAM,SAAS;GAAE,GAAG;GAAM,MAAM;EAAO,CAAC;EACxC,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,qBAAb,cAAwC,aAAa;CACpD,YACC,SACA,MACC;EACD,MAAM,SAAS;GAAE,GAAG;GAAM,MAAM;EAAa,CAAC;EAC9C,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,qBAAb,cAAwC,UAAU;;CAEjD;;CAEA;CAEA,YACC,SACA,MACC;EACD,MAAM,SAAS,WAAW;EAC1B,KAAK,OAAO;EACZ,KAAK,cAAc,KAAK;EACxB,KAAK,SAAS,KAAK;CACpB;AACD;;;;;AAMA,IAAa,mBAAb,cAAsC,UAAU;CAC/C,YAAY,SAAiB;EAC5B,MAAM,SAAS,SAAS;EACxB,KAAK,OAAO;CACb;AACD;;;;;;;;;;;;AAaA,IAAa,iBAAb,cAAoC,UAAU;CAC7C,YAAY,SAAiB,SAA+B;EAC3D,MAAM,SAAS,WAAW,OAAO;EACjC,KAAK,OAAO;CACb;AACD;;AAGA,IAAa,mBAAb,cAAsC,UAAU;;;;;;CAM/C;CAEA,YACC,SACA,SACC;EACD,MAAM,SAAS,WAAW,EAAE,OAAO,SAAS,MAAM,CAAC;EACnD,KAAK,OAAO;EACZ,KAAK,SAAS,SAAS,UAAU;CAClC;AACD;AAQA,SAAS,iBAAiB,MAA6B;CACtD,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM,OAAO,CAAC;CACvD,MAAM,MAAoB,CAAC;CAC3B,IAAI,aAAa,QAAQ,OAAO,KAAK,YAAY,UAChD,IAAI,UAAU,KAAK;CACpB,IAAI,UAAU,QAAQ,OAAO,KAAK,SAAS,UAAU,IAAI,OAAO,KAAK;CACrE,IAAI,gBAAgB,QAAQ,OAAO,KAAK,eAAe,UACtD,IAAI,aAAa,KAAK;CAEvB,OAAO;AACR;;;;;;;;;AAUA,SAAgB,yBAAyB,OAAwB;CAChE,MAAM,uBAAO,IAAI,IAAa;CAC9B,IAAI,UAAmB;CACvB,IAAI;CAEJ,OAAO,mBAAmB,SAAS,CAAC,KAAK,IAAI,OAAO,GAAG;EACtD,KAAK,IAAI,OAAO;EAChB,IAAI,UAAU,WAAW,OAAO,QAAQ,SAAS,UAChD,OAAO,QAAQ;EAEhB,IAAI,QAAQ,SAAS,iBAAiB,QAAQ;EAC9C,UAAU,QAAQ;CACnB;CAEA,OAAO,kBAAkB;AAC1B;;;;;;AAOA,SAAgB,YACf,OACA,UACY;CACZ,IAAI,CAAC,UAAU;EACd,MAAM,SAAS,yBAAyB,KAAK;EAC7C,OAAO,IAAI,iBACV,0DAA0D,OAAO,KACjE;GAAE,OAAO;GAAO;EAAO,CACxB;CACD;CAEA,MAAM,SAAS,iBAAiB,KAAK;CACrC,MAAM,SAAS,SAAS;CACxB,MAAM,UACL,OAAO,WAAW,uCAAuC,OAAO;CACjE,MAAM,OAAO;EACZ;EACA,MAAM,OAAO;EACb,WACC,OAAO,cACP,SAAS,QAAQ,IAAI,cAAc,KACnC,KAAA;EACD;EACA,MAAM;CACP;CAEA,IAAI,WAAW,KAAK,OAAO,IAAI,kBAAkB,SAAS,IAAI;CAC9D,IAAI,WAAW,OAAO,WAAW,KAChC,OAAO,IAAI,cAAc,SAAS,IAAI;CACvC,IAAI,WAAW,KAAK,OAAO,IAAI,mBAAmB,SAAS,IAAI;CAC/D,OAAO,IAAI,aAAa,SAAS,IAAI;AACtC"}
@@ -1,3 +1,4 @@
1
+ import { Deadline } from "./deadline.js";
1
2
  import { NeonResult } from "./result.js";
2
3
 
3
4
  //#region src/neon/paginate.d.ts
@@ -27,8 +28,12 @@ interface Paginated<T> extends AsyncIterable<T> {
27
28
  /**
28
29
  * Build a {@link Paginated} list from a page fetcher and a page mapper. The response-body
29
30
  * type `D` is inferred and erased from the public `Paginated<T>` return.
31
+ *
32
+ * `newDeadline` is called once per consumption — each `page()`, each `all()`, each
33
+ * iteration — because a `Paginated` is lazy and may be consumed more than once, so a
34
+ * deadline created when the list was built would already be spent.
30
35
  */
31
- declare function paginate<T, D>(fetchPage: (cursor: string | undefined, signal?: AbortSignal) => Promise<RawResult<D>>, mapPage: (data: D) => Page<T>, signal?: AbortSignal): Paginated<T>;
36
+ declare function paginate<T, D>(fetchPage: (cursor: string | undefined, signal?: AbortSignal) => Promise<RawResult<D>>, mapPage: (data: D) => Page<T>, newDeadline: () => Deadline): Paginated<T>;
32
37
  //#endregion
33
38
  export { Page, Paginated, paginate };
34
39
  //# sourceMappingURL=paginate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paginate.d.ts","names":[],"sources":["../../src/neon/paginate.ts"],"mappings":";;;UAGiB;SACT;EADS;EAMP,MAAA,CAAA,EAAA,MAAS;AAAA;AACX,UADE,SACF,CAAA,CAAA,CAAA,CAAA;EAEI,IAAA,CAAA,EAFJ,CAEI,GAAA,SAAA;EAAQ,KAAA,CAAA,EAAA,OAAA;EAUH,QAAA,CAAA,EAVL,QAUc,GAAA,SAAA;AAAA;AAA0B;AAEJ;AAAL;AAAX;AAAR;AAEG;AAAX;AAAR,UAJS,SAIT,CAAA,CAAA,CAAA,SAJ8B,aAI9B,CAJ4C,CAI5C,CAAA,CAAA;EAJ8B;EAAa,IAAA,CAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EAE3B,OAF2B,CAEnB,UAFmB,CAER,IAFQ,CAEH,CAFG,CAAA,CAAA,CAAA;EAiEnC;EAAQ,GAAA,EAAA,EA7DhB,OA6DgB,CA7DR,UA6DQ,CA7DG,CA6DH,EAAA,CAAA,CAAA;AAGb;AACa;AAAV;AAAR;AACW;AAAW,iBALZ,QAKY,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,SAAA,EAAA,CAAA,MAAA,EAAA,MAAA,GAAA,SAAA,EAAA,MAAA,CAAA,EAFjB,WAEiB,EAAA,GADtB,OACsB,CADd,SACc,CADJ,CACI,CAAA,CAAA,EAAA,OAAA,EAAA,CAAA,IAAA,EAAX,CAAW,EAAA,GAAL,IAAK,CAAA,CAAA,CAAA,EAAA,MAAA,CAAA,EAClB,WADkB,CAAA,EAEzB,SAFyB,CAEf,CAFe,CAAA"}
1
+ {"version":3,"file":"paginate.d.ts","names":[],"sources":["../../src/neon/paginate.ts"],"mappings":";;;;UAIiB;SACT;EADS;EAMP,MAAA,CAAA,EAAA,MAAS;AAAA;AACX,UADE,SACF,CAAA,CAAA,CAAA,CAAA;EAEI,IAAA,CAAA,EAFJ,CAEI,GAAA,SAAA;EAAQ,KAAA,CAAA,EAAA,OAAA;EAUH,QAAA,CAAA,EAVL,QAUc,GAAA,SAAA;AAAA;AAA0B;AAEJ;AAAL;AAAX;AAAR;AAEG;AAAX;AAAR,UAJS,SAIT,CAAA,CAAA,CAAA,SAJ8B,aAI9B,CAJ4C,CAI5C,CAAA,CAAA;EAJ8B;EAAa,IAAA,CAAA,MAAA,CAAA,EAAA,MAAA,CAAA,EAE3B,OAF2B,CAEnB,UAFmB,CAER,IAFQ,CAEH,CAFG,CAAA,CAAA,CAAA;EA8GnC;EAAQ,GAAA,EAAA,EA1GhB,OA0GgB,CA1GR,UA0GQ,CA1GG,CA0GH,EAAA,CAAA,CAAA;AAGb;AACa;AAAV;AAAR;AACW;AAAW;AAAL;AACH;AACP;AAAV,iBAPa,QAOb,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,SAAA,EAAA,CAAA,MAAA,EAAA,MAAA,GAAA,SAAA,EAAA,MAAA,CAAA,EAJQ,WAIR,EAAA,GAHG,OAGH,CAHW,SAGX,CAHqB,CAGrB,CAAA,CAAA,EAAA,OAAA,EAAA,CAAA,IAAA,EAFc,CAEd,EAAA,GAFoB,IAEpB,CAFyB,CAEzB,CAAA,EAAA,WAAA,EAAA,GAAA,GADiB,QACjB,CAAA,EAAA,SAAA,CAAU,CAAV,CAAA"}
@@ -1,49 +1,84 @@
1
1
  import { toNeonError } from "./errors.js";
2
+ import { cancelled, runBounded } from "./deadline.js";
2
3
  import { err, ok } from "./result.js";
3
4
  //#region src/neon/paginate.ts
4
5
  var PaginatedList = class {
5
6
  #fetchPage;
6
7
  #mapPage;
7
- #signal;
8
- constructor(fetchPage, mapPage, signal) {
8
+ #newDeadline;
9
+ constructor(fetchPage, mapPage, newDeadline) {
9
10
  this.#fetchPage = fetchPage;
10
11
  this.#mapPage = mapPage;
11
- this.#signal = signal;
12
+ this.#newDeadline = newDeadline;
12
13
  }
13
- async page(cursor) {
14
- const raw = await this.#fetchPage(cursor, this.#signal);
15
- if (raw.error || raw.data === void 0) return err(toNeonError(raw.error, raw.response));
14
+ async #page(cursor, deadline) {
15
+ let raw;
16
+ try {
17
+ raw = await runBounded(deadline, () => this.#fetchPage(cursor, deadline.signal));
18
+ } catch (error) {
19
+ return err(cancelled(deadline) ?? toNeonError(error, void 0));
20
+ }
21
+ const cancellation = cancelled(deadline);
22
+ if (cancellation) return err(cancellation);
23
+ if (raw === void 0 || raw.error || raw.data === void 0) return err(toNeonError(raw?.error, raw?.response));
16
24
  return ok(this.#mapPage(raw.data));
17
25
  }
26
+ async page(cursor) {
27
+ const deadline = this.#newDeadline();
28
+ try {
29
+ return await this.#page(cursor, deadline);
30
+ } finally {
31
+ deadline.dispose();
32
+ }
33
+ }
34
+ /**
35
+ * One deadline covers the whole walk, not each page: `all()` is a single operation
36
+ * from the caller's side, and a per-page budget would leave an unbounded number of
37
+ * pages unbounded in total.
38
+ */
18
39
  async all() {
19
- const items = [];
20
- let cursor;
21
- while (true) {
22
- const result = await this.page(cursor);
23
- if (result.error) return err(result.error);
24
- items.push(...result.data.items);
25
- if (!result.data.cursor || result.data.items.length === 0) break;
26
- cursor = result.data.cursor;
40
+ const deadline = this.#newDeadline();
41
+ try {
42
+ const items = [];
43
+ let cursor;
44
+ while (true) {
45
+ const result = await this.#page(cursor, deadline);
46
+ if (result.error) return err(result.error);
47
+ items.push(...result.data.items);
48
+ if (!result.data.cursor || result.data.items.length === 0) break;
49
+ cursor = result.data.cursor;
50
+ }
51
+ return ok(items);
52
+ } finally {
53
+ deadline.dispose();
27
54
  }
28
- return ok(items);
29
55
  }
30
56
  async *[Symbol.asyncIterator]() {
31
- let cursor;
32
- while (true) {
33
- const result = await this.page(cursor);
34
- if (result.error) throw result.error;
35
- yield* result.data.items;
36
- if (!result.data.cursor || result.data.items.length === 0) break;
37
- cursor = result.data.cursor;
57
+ const deadline = this.#newDeadline();
58
+ try {
59
+ let cursor;
60
+ while (true) {
61
+ const result = await this.#page(cursor, deadline);
62
+ if (result.error) throw result.error;
63
+ yield* result.data.items;
64
+ if (!result.data.cursor || result.data.items.length === 0) break;
65
+ cursor = result.data.cursor;
66
+ }
67
+ } finally {
68
+ deadline.dispose();
38
69
  }
39
70
  }
40
71
  };
41
72
  /**
42
73
  * Build a {@link Paginated} list from a page fetcher and a page mapper. The response-body
43
74
  * type `D` is inferred and erased from the public `Paginated<T>` return.
75
+ *
76
+ * `newDeadline` is called once per consumption — each `page()`, each `all()`, each
77
+ * iteration — because a `Paginated` is lazy and may be consumed more than once, so a
78
+ * deadline created when the list was built would already be spent.
44
79
  */
45
- function paginate(fetchPage, mapPage, signal) {
46
- return new PaginatedList(fetchPage, mapPage, signal);
80
+ function paginate(fetchPage, mapPage, newDeadline) {
81
+ return new PaginatedList(fetchPage, mapPage, newDeadline);
47
82
  }
48
83
  //#endregion
49
84
  export { paginate };
@@ -1 +1 @@
1
- {"version":3,"file":"paginate.js","names":["#fetchPage","#mapPage","#signal"],"sources":["../../src/neon/paginate.ts"],"sourcesContent":["import { toNeonError } from \"./errors.js\";\nimport { err, type NeonResult, ok } from \"./result.js\";\n\nexport interface Page<T> {\n\titems: T[];\n\t/** Cursor for the next page, when more results exist. */\n\tcursor?: string;\n}\n\ninterface RawResult<D> {\n\tdata?: D | undefined;\n\terror?: unknown;\n\tresponse?: Response | undefined;\n}\n\n/**\n * A lazy, cursor-paginated list. `all()` / `page()` return the `{ data, error }` envelope;\n * the async iterator streams items lazily and throws on a page-fetch error.\n *\n * Note: pagination helpers always use the result envelope (the iterator is the throwing\n * form) regardless of the client's `throwOnError` setting.\n */\nexport interface Paginated<T> extends AsyncIterable<T> {\n\t/** Fetch a single page (optionally from a cursor). */\n\tpage(cursor?: string): Promise<NeonResult<Page<T>>>;\n\t/** Fetch and concatenate every page. */\n\tall(): Promise<NeonResult<T[]>>;\n}\n\nclass PaginatedList<T, D> implements Paginated<T> {\n\treadonly #fetchPage: (\n\t\tcursor: string | undefined,\n\t\tsignal?: AbortSignal,\n\t) => Promise<RawResult<D>>;\n\treadonly #mapPage: (data: D) => Page<T>;\n\treadonly #signal?: AbortSignal;\n\n\tconstructor(\n\t\tfetchPage: (\n\t\t\tcursor: string | undefined,\n\t\t\tsignal?: AbortSignal,\n\t\t) => Promise<RawResult<D>>,\n\t\tmapPage: (data: D) => Page<T>,\n\t\tsignal?: AbortSignal,\n\t) {\n\t\tthis.#fetchPage = fetchPage;\n\t\tthis.#mapPage = mapPage;\n\t\tthis.#signal = signal;\n\t}\n\n\tasync page(cursor?: string): Promise<NeonResult<Page<T>>> {\n\t\tconst raw = await this.#fetchPage(cursor, this.#signal);\n\t\tif (raw.error || raw.data === undefined) {\n\t\t\treturn err(toNeonError(raw.error, raw.response));\n\t\t}\n\t\treturn ok(this.#mapPage(raw.data));\n\t}\n\n\tasync all(): Promise<NeonResult<T[]>> {\n\t\tconst items: T[] = [];\n\t\tlet cursor: string | undefined;\n\t\twhile (true) {\n\t\t\tconst result = await this.page(cursor);\n\t\t\tif (result.error) return err(result.error);\n\t\t\titems.push(...result.data.items);\n\t\t\tif (!result.data.cursor || result.data.items.length === 0) break;\n\t\t\tcursor = result.data.cursor;\n\t\t}\n\t\treturn ok(items);\n\t}\n\n\tasync *[Symbol.asyncIterator](): AsyncIterator<T> {\n\t\tlet cursor: string | undefined;\n\t\twhile (true) {\n\t\t\tconst result = await this.page(cursor);\n\t\t\tif (result.error) throw result.error;\n\t\t\tyield* result.data.items;\n\t\t\tif (!result.data.cursor || result.data.items.length === 0) break;\n\t\t\tcursor = result.data.cursor;\n\t\t}\n\t}\n}\n\n/**\n * Build a {@link Paginated} list from a page fetcher and a page mapper. The response-body\n * type `D` is inferred and erased from the public `Paginated<T>` return.\n */\nexport function paginate<T, D>(\n\tfetchPage: (\n\t\tcursor: string | undefined,\n\t\tsignal?: AbortSignal,\n\t) => Promise<RawResult<D>>,\n\tmapPage: (data: D) => Page<T>,\n\tsignal?: AbortSignal,\n): Paginated<T> {\n\treturn new PaginatedList(fetchPage, mapPage, signal);\n}\n"],"mappings":";;;AA6BA,IAAM,gBAAN,MAAkD;CACjD;CAIA;CACA;CAEA,YACC,WAIA,SACA,QACC;EACD,KAAKA,aAAa;EAClB,KAAKC,WAAW;EAChB,KAAKC,UAAU;CAChB;CAEA,MAAM,KAAK,QAA+C;EACzD,MAAM,MAAM,MAAM,KAAKF,WAAW,QAAQ,KAAKE,OAAO;EACtD,IAAI,IAAI,SAAS,IAAI,SAAS,KAAA,GAC7B,OAAO,IAAI,YAAY,IAAI,OAAO,IAAI,QAAQ,CAAC;EAEhD,OAAO,GAAG,KAAKD,SAAS,IAAI,IAAI,CAAC;CAClC;CAEA,MAAM,MAAgC;EACrC,MAAM,QAAa,CAAC;EACpB,IAAI;EACJ,OAAO,MAAM;GACZ,MAAM,SAAS,MAAM,KAAK,KAAK,MAAM;GACrC,IAAI,OAAO,OAAO,OAAO,IAAI,OAAO,KAAK;GACzC,MAAM,KAAK,GAAG,OAAO,KAAK,KAAK;GAC/B,IAAI,CAAC,OAAO,KAAK,UAAU,OAAO,KAAK,MAAM,WAAW,GAAG;GAC3D,SAAS,OAAO,KAAK;EACtB;EACA,OAAO,GAAG,KAAK;CAChB;CAEA,QAAQ,OAAO,iBAAmC;EACjD,IAAI;EACJ,OAAO,MAAM;GACZ,MAAM,SAAS,MAAM,KAAK,KAAK,MAAM;GACrC,IAAI,OAAO,OAAO,MAAM,OAAO;GAC/B,OAAO,OAAO,KAAK;GACnB,IAAI,CAAC,OAAO,KAAK,UAAU,OAAO,KAAK,MAAM,WAAW,GAAG;GAC3D,SAAS,OAAO,KAAK;EACtB;CACD;AACD;;;;;AAMA,SAAgB,SACf,WAIA,SACA,QACe;CACf,OAAO,IAAI,cAAc,WAAW,SAAS,MAAM;AACpD"}
1
+ {"version":3,"file":"paginate.js","names":["#fetchPage","#mapPage","#newDeadline","#page"],"sources":["../../src/neon/paginate.ts"],"sourcesContent":["import { cancelled, type Deadline, runBounded } from \"./deadline.js\";\nimport { toNeonError } from \"./errors.js\";\nimport { err, type NeonResult, ok } from \"./result.js\";\n\nexport interface Page<T> {\n\titems: T[];\n\t/** Cursor for the next page, when more results exist. */\n\tcursor?: string;\n}\n\ninterface RawResult<D> {\n\tdata?: D | undefined;\n\terror?: unknown;\n\tresponse?: Response | undefined;\n}\n\n/**\n * A lazy, cursor-paginated list. `all()` / `page()` return the `{ data, error }` envelope;\n * the async iterator streams items lazily and throws on a page-fetch error.\n *\n * Note: pagination helpers always use the result envelope (the iterator is the throwing\n * form) regardless of the client's `throwOnError` setting.\n */\nexport interface Paginated<T> extends AsyncIterable<T> {\n\t/** Fetch a single page (optionally from a cursor). */\n\tpage(cursor?: string): Promise<NeonResult<Page<T>>>;\n\t/** Fetch and concatenate every page. */\n\tall(): Promise<NeonResult<T[]>>;\n}\n\nclass PaginatedList<T, D> implements Paginated<T> {\n\treadonly #fetchPage: (\n\t\tcursor: string | undefined,\n\t\tsignal?: AbortSignal,\n\t) => Promise<RawResult<D>>;\n\treadonly #mapPage: (data: D) => Page<T>;\n\treadonly #newDeadline: () => Deadline;\n\n\tconstructor(\n\t\tfetchPage: (\n\t\t\tcursor: string | undefined,\n\t\t\tsignal?: AbortSignal,\n\t\t) => Promise<RawResult<D>>,\n\t\tmapPage: (data: D) => Page<T>,\n\t\tnewDeadline: () => Deadline,\n\t) {\n\t\tthis.#fetchPage = fetchPage;\n\t\tthis.#mapPage = mapPage;\n\t\tthis.#newDeadline = newDeadline;\n\t}\n\n\tasync #page(\n\t\tcursor: string | undefined,\n\t\tdeadline: Deadline,\n\t): Promise<NeonResult<Page<T>>> {\n\t\tlet raw: RawResult<D> | undefined;\n\t\ttry {\n\t\t\t// Bounded the same way the execution core bounds a request: the signal alone\n\t\t\t// does not cover the phases before `fetch` is reached, so a slow auth provider\n\t\t\t// would otherwise outlast the deadline.\n\t\t\traw = await runBounded(deadline, () =>\n\t\t\t\tthis.#fetchPage(cursor, deadline.signal),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\treturn err(cancelled(deadline) ?? toNeonError(error, undefined));\n\t\t}\n\t\tconst cancellation = cancelled(deadline);\n\t\tif (cancellation) return err(cancellation);\n\t\tif (raw === undefined || raw.error || raw.data === undefined) {\n\t\t\treturn err(toNeonError(raw?.error, raw?.response));\n\t\t}\n\t\treturn ok(this.#mapPage(raw.data));\n\t}\n\n\tasync page(cursor?: string): Promise<NeonResult<Page<T>>> {\n\t\tconst deadline = this.#newDeadline();\n\t\ttry {\n\t\t\treturn await this.#page(cursor, deadline);\n\t\t} finally {\n\t\t\tdeadline.dispose();\n\t\t}\n\t}\n\n\t/**\n\t * One deadline covers the whole walk, not each page: `all()` is a single operation\n\t * from the caller's side, and a per-page budget would leave an unbounded number of\n\t * pages unbounded in total.\n\t */\n\tasync all(): Promise<NeonResult<T[]>> {\n\t\tconst deadline = this.#newDeadline();\n\t\ttry {\n\t\t\tconst items: T[] = [];\n\t\t\tlet cursor: string | undefined;\n\t\t\twhile (true) {\n\t\t\t\tconst result = await this.#page(cursor, deadline);\n\t\t\t\tif (result.error) return err(result.error);\n\t\t\t\titems.push(...result.data.items);\n\t\t\t\tif (!result.data.cursor || result.data.items.length === 0)\n\t\t\t\t\tbreak;\n\t\t\t\tcursor = result.data.cursor;\n\t\t\t}\n\t\t\treturn ok(items);\n\t\t} finally {\n\t\t\tdeadline.dispose();\n\t\t}\n\t}\n\n\tasync *[Symbol.asyncIterator](): AsyncIterator<T> {\n\t\tconst deadline = this.#newDeadline();\n\t\ttry {\n\t\t\tlet cursor: string | undefined;\n\t\t\twhile (true) {\n\t\t\t\tconst result = await this.#page(cursor, deadline);\n\t\t\t\tif (result.error) throw result.error;\n\t\t\t\tyield* result.data.items;\n\t\t\t\tif (!result.data.cursor || result.data.items.length === 0)\n\t\t\t\t\tbreak;\n\t\t\t\tcursor = result.data.cursor;\n\t\t\t}\n\t\t} finally {\n\t\t\tdeadline.dispose();\n\t\t}\n\t}\n}\n\n/**\n * Build a {@link Paginated} list from a page fetcher and a page mapper. The response-body\n * type `D` is inferred and erased from the public `Paginated<T>` return.\n *\n * `newDeadline` is called once per consumption — each `page()`, each `all()`, each\n * iteration — because a `Paginated` is lazy and may be consumed more than once, so a\n * deadline created when the list was built would already be spent.\n */\nexport function paginate<T, D>(\n\tfetchPage: (\n\t\tcursor: string | undefined,\n\t\tsignal?: AbortSignal,\n\t) => Promise<RawResult<D>>,\n\tmapPage: (data: D) => Page<T>,\n\tnewDeadline: () => Deadline,\n): Paginated<T> {\n\treturn new PaginatedList(fetchPage, mapPage, newDeadline);\n}\n"],"mappings":";;;;AA8BA,IAAM,gBAAN,MAAkD;CACjD;CAIA;CACA;CAEA,YACC,WAIA,SACA,aACC;EACD,KAAKA,aAAa;EAClB,KAAKC,WAAW;EAChB,KAAKC,eAAe;CACrB;CAEA,MAAMC,MACL,QACA,UAC+B;EAC/B,IAAI;EACJ,IAAI;GAIH,MAAM,MAAM,WAAW,gBACtB,KAAKH,WAAW,QAAQ,SAAS,MAAM,CACxC;EACD,SAAS,OAAO;GACf,OAAO,IAAI,UAAU,QAAQ,KAAK,YAAY,OAAO,KAAA,CAAS,CAAC;EAChE;EACA,MAAM,eAAe,UAAU,QAAQ;EACvC,IAAI,cAAc,OAAO,IAAI,YAAY;EACzC,IAAI,QAAQ,KAAA,KAAa,IAAI,SAAS,IAAI,SAAS,KAAA,GAClD,OAAO,IAAI,YAAY,KAAK,OAAO,KAAK,QAAQ,CAAC;EAElD,OAAO,GAAG,KAAKC,SAAS,IAAI,IAAI,CAAC;CAClC;CAEA,MAAM,KAAK,QAA+C;EACzD,MAAM,WAAW,KAAKC,aAAa;EACnC,IAAI;GACH,OAAO,MAAM,KAAKC,MAAM,QAAQ,QAAQ;EACzC,UAAU;GACT,SAAS,QAAQ;EAClB;CACD;;;;;;CAOA,MAAM,MAAgC;EACrC,MAAM,WAAW,KAAKD,aAAa;EACnC,IAAI;GACH,MAAM,QAAa,CAAC;GACpB,IAAI;GACJ,OAAO,MAAM;IACZ,MAAM,SAAS,MAAM,KAAKC,MAAM,QAAQ,QAAQ;IAChD,IAAI,OAAO,OAAO,OAAO,IAAI,OAAO,KAAK;IACzC,MAAM,KAAK,GAAG,OAAO,KAAK,KAAK;IAC/B,IAAI,CAAC,OAAO,KAAK,UAAU,OAAO,KAAK,MAAM,WAAW,GACvD;IACD,SAAS,OAAO,KAAK;GACtB;GACA,OAAO,GAAG,KAAK;EAChB,UAAU;GACT,SAAS,QAAQ;EAClB;CACD;CAEA,QAAQ,OAAO,iBAAmC;EACjD,MAAM,WAAW,KAAKD,aAAa;EACnC,IAAI;GACH,IAAI;GACJ,OAAO,MAAM;IACZ,MAAM,SAAS,MAAM,KAAKC,MAAM,QAAQ,QAAQ;IAChD,IAAI,OAAO,OAAO,MAAM,OAAO;IAC/B,OAAO,OAAO,KAAK;IACnB,IAAI,CAAC,OAAO,KAAK,UAAU,OAAO,KAAK,MAAM,WAAW,GACvD;IACD,SAAS,OAAO,KAAK;GACtB;EACD,UAAU;GACT,SAAS,QAAQ;EAClB;CACD;AACD;;;;;;;;;AAUA,SAAgB,SACf,WAIA,SACA,aACe;CACf,OAAO,IAAI,cAAc,WAAW,SAAS,WAAW;AACzD"}
@@ -1 +1 @@
1
- {"version":3,"file":"raw-wrap.d.ts","names":[],"sources":["../../src/neon/raw-wrap.ts"],"mappings":";;;;AA4CgE;AAAC;AAGjE;AAAsB;AAAW;AACT;AAAX,KAtBD,QAAA,GAsBC,CAAA,OAAA,EAAA,GAAA,EAAA,GAtB4B,OAsB5B,CAAA,GAAA,CAAA;AAAZ;AAD4C,KAVxC,UAUwC,CAAA,CAAA,CAAA,GAVxB,CAUwB,SAAA;EAAI,KAAA,EAAA,SAAA,GAAA,IAAA;AAUjD,CAAA,GApB6D,CAoBjD,GAAA,KAAA;AAAS;AACV;AAAgC;AAAoB;AAGrD,KAlBE,OAkBF,CAAA,UAlBoB,QAkBpB,CAAA,GAjBT,UAiBS,CAjBE,OAiBF,CAjBU,UAiBV,CAjBqB,CAiBrB,CAAA,CAAA,CAAA,SAAA;EACI,IAAA,EAAA,KAAA,EAAA;AACD,CAAA,GAnBmD,CAmBnD,GAAA,KAAA;AAAO;AAeJ,KA/BJ,UA+BW,CAAA,UA/BU,QA+BV,CAAA,GA/BsB,IA+BtB,CA9BtB,WA8BsB,CA9BV,UA8BU,CA9BC,CA8BD,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,cAAA,GAAA,eAAA,CAAA;AAAA;AAAW;AAAc;AAAI;AAE9B;AAAX,KAvBC,SAuBD,CAAA,CAAA,CAAA,GAAA;EACS,IAAA,EAvBT,CAuBS;EAAR,KAAA,EAAA,SAAA;EAAR,QAAA,CAAA,EAvBuC,QAuBvC;EAEkB,OAAA,CAAA,EAzByC,OAyBzC;AAAX,CAAA,GAAA;EACmB,IAAA,EAAA,SAAA;EAAR,KAAA,EAvBZ,SAuBY;EAAV,QAAA,CAAA,EAtBE,QAsBF;EAAR,OAAA,CAAA,EArBS,OAqBT;AAAO,CAAA;;;;;;;;;;;;;iBANK,kBAAkB,cAAc,IAAI;YAEzC,WAAW;;MAClB,QAAQ,QAAQ;YAET,WAAW;;MAClB,QAAQ,UAAU,QAAQ"}
1
+ {"version":3,"file":"raw-wrap.d.ts","names":[],"sources":["../../src/neon/raw-wrap.ts"],"mappings":";;;;AA+DgE;AAAC;AAGjE;AAAsB;AAAW;AACT;AAAX,KAtBD,QAAA,GAsBC,CAAA,OAAA,EAAA,GAAA,EAAA,GAtB4B,OAsB5B,CAAA,GAAA,CAAA;AAAZ;AAD4C,KAVxC,UAUwC,CAAA,CAAA,CAAA,GAVxB,CAUwB,SAAA;EAAI,KAAA,EAAA,SAAA,GAAA,IAAA;AAUjD,CAAA,GApB6D,CAoBjD,GAAA,KAAA;AAAS;AACV;AAAgC;AAAoB;AAGrD,KAlBE,OAkBF,CAAA,UAlBoB,QAkBpB,CAAA,GAjBT,UAiBS,CAjBE,OAiBF,CAjBU,UAiBV,CAjBqB,CAiBrB,CAAA,CAAA,CAAA,SAAA;EACI,IAAA,EAAA,KAAA,EAAA;AACD,CAAA,GAnBmD,CAmBnD,GAAA,KAAA;AAAO;AAeJ,KA/BJ,UA+BW,CAAA,UA/BU,QA+BV,CAAA,GA/BsB,IA+BtB,CA9BtB,WA8BsB,CA9BV,UA8BU,CA9BC,CA8BD,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,cAAA,GAAA,eAAA,CAAA;AAAA;AAAW;AAAc;AAAI;AAE9B;AAAX,KAvBC,SAuBD,CAAA,CAAA,CAAA,GAAA;EACS,IAAA,EAvBT,CAuBS;EAAR,KAAA,EAAA,SAAA;EAAR,QAAA,CAAA,EAvBuC,QAuBvC;EAEkB,OAAA,CAAA,EAzByC,OAyBzC;AAAX,CAAA,GAAA;EACmB,IAAA,EAAA,SAAA;EAAR,KAAA,EAvBZ,SAuBY;EAAV,QAAA,CAAA,EAtBE,QAsBF;EAAR,OAAA,CAAA,EArBS,OAqBT;AAAO,CAAA;;;;;;;;;;;;;iBANK,kBAAkB,cAAc,IAAI;YAEzC,WAAW;;MAClB,QAAQ,QAAQ;YAET,WAAW;;MAClB,QAAQ,UAAU,QAAQ"}
@@ -1,6 +1,21 @@
1
- import { toNeonError } from "./errors.js";
1
+ import { NeonAbortError, toNeonError } from "./errors.js";
2
2
  //#region src/neon/raw-wrap.ts
3
3
  /**
4
+ * Did the caller's own signal end this call?
5
+ *
6
+ * Read from the signal rather than the error, because the generated client reports
7
+ * authentication, serialization, interceptor, transport and parsing faults through one
8
+ * channel — an error named `AbortError` is not evidence about which occurred. A response
9
+ * having arrived rules cancellation out.
10
+ *
11
+ * This deliberately says nothing about a signal the SDK never saw: the Neon CLI installs
12
+ * its own request timeout inside a custom `fetch` rather than passing `signal`, so its
13
+ * timeouts keep classifying as {@link NeonNetworkError} exactly as before.
14
+ */
15
+ function abortedBy(signal, response) {
16
+ return response === void 0 && signal?.aborted === true;
17
+ }
18
+ /**
4
19
  * Wrap a generated raw function so it speaks the ergonomic result contract.
5
20
  *
6
21
  * @example
@@ -21,7 +36,7 @@ function wrapRaw(fn) {
21
36
  responseStyle: "fields"
22
37
  });
23
38
  if (raw.error !== void 0 && raw.error !== null) {
24
- const error = toNeonError(raw.error, raw.response);
39
+ const error = abortedBy(options.signal, raw.response) ? new NeonAbortError("The request was aborted by its signal.", { cause: raw.error }) : toNeonError(raw.error, raw.response);
25
40
  if (shouldThrow) throw error;
26
41
  return {
27
42
  data: void 0,