pipework 0.264.3 → 0.266.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 (54) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/REFERENCE.md +23 -4
  3. package/dist/data/migrate/internal-definitions.d.ts.map +1 -1
  4. package/dist/data/migrate/internal-definitions.js +2 -1
  5. package/dist/data/migrate/internal-definitions.js.map +1 -1
  6. package/dist/index.d.ts +2 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/infra/alerts/sources.d.ts +1 -1
  11. package/dist/infra/alerts/sources.d.ts.map +1 -1
  12. package/dist/infra/alerts/sources.js +27 -10
  13. package/dist/infra/alerts/sources.js.map +1 -1
  14. package/dist/infra/quota/handle.d.ts +27 -3
  15. package/dist/infra/quota/handle.d.ts.map +1 -1
  16. package/dist/infra/quota/handle.js +128 -31
  17. package/dist/infra/quota/handle.js.map +1 -1
  18. package/dist/infra/quota/index.d.ts +1 -1
  19. package/dist/infra/quota/index.d.ts.map +1 -1
  20. package/dist/infra/quota/index.js.map +1 -1
  21. package/dist/infra/quota/schema.d.ts +20 -0
  22. package/dist/infra/quota/schema.d.ts.map +1 -1
  23. package/dist/infra/quota/schema.js +12 -0
  24. package/dist/infra/quota/schema.js.map +1 -1
  25. package/dist/request/context/types.d.ts +2 -0
  26. package/dist/request/context/types.d.ts.map +1 -1
  27. package/dist/request/di/resolve.d.ts +1 -1
  28. package/dist/request/di/resolve.d.ts.map +1 -1
  29. package/dist/request/http/aborted.d.ts +12 -0
  30. package/dist/request/http/aborted.d.ts.map +1 -0
  31. package/dist/request/http/aborted.js +14 -0
  32. package/dist/request/http/aborted.js.map +1 -0
  33. package/dist/request/http/namespace.d.ts +3 -1
  34. package/dist/request/http/namespace.d.ts.map +1 -1
  35. package/dist/request/http/namespace.js +3 -1
  36. package/dist/request/http/namespace.js.map +1 -1
  37. package/dist/request/http/server.d.ts.map +1 -1
  38. package/dist/request/http/server.js +23 -3
  39. package/dist/request/http/server.js.map +1 -1
  40. package/dist/request/http/types.d.ts +1 -0
  41. package/dist/request/http/types.d.ts.map +1 -1
  42. package/package.json +1 -1
  43. package/src/data/migrate/internal-definitions.ts +2 -1
  44. package/src/index.ts +3 -1
  45. package/src/infra/alerts/sources.ts +27 -10
  46. package/src/infra/quota/handle.ts +157 -35
  47. package/src/infra/quota/index.ts +1 -0
  48. package/src/infra/quota/schema.ts +13 -0
  49. package/src/request/context/types.ts +2 -0
  50. package/src/request/di/resolve.ts +1 -1
  51. package/src/request/http/aborted.ts +15 -0
  52. package/src/request/http/namespace.ts +3 -1
  53. package/src/request/http/server.ts +21 -1
  54. package/src/request/http/types.ts +1 -0
@@ -52,12 +52,40 @@ function logRecordFailure(key, err) {
52
52
  getBaseLogger().error({ err, key }, 'quota could not record the budget from a response');
53
53
  void recordFault('quota-record', faultMessage(err), { key });
54
54
  }
55
+ const DEFAULT_RETAIN_WINDOWS = 48;
56
+ const UNLABELLED = 'unlabelled';
57
+ const toDate = (v) => new Date(v);
55
58
  export function createQuota(config = {}) {
59
+ const retain = config.retainWindows ?? DEFAULT_RETAIN_WINDOWS;
60
+ if (!Number.isInteger(retain) || retain < 1) {
61
+ throw new Error(`[pipework] quota.create retainWindows must be a positive integer, got ${String(config.retainWindows)}.`);
62
+ }
56
63
  if (config.connection !== undefined && config.database !== undefined) {
57
64
  throw new Error('[pipework] quota.create takes connection or database, not both.');
58
65
  }
59
66
  const read = config.read ?? defaultRead;
60
67
  const db = () => config.connection !== undefined ? config.connection.drizzle : resolveDb(config.database);
68
+ /** A new live window began: calls counted before any window was known move into it, and windows past the retention are deleted. */
69
+ async function startWindow(tx, key) {
70
+ await tx.execute(sql `
71
+ WITH moved AS (
72
+ DELETE FROM outbound_quota_spend WHERE key = ${key} AND window_end = 'infinity'::timestamptz
73
+ RETURNING caller, sent, refused)
74
+ INSERT INTO outbound_quota_spend (key, caller, window_end, sent, refused)
75
+ SELECT ${key}, caller, (SELECT reset_at FROM outbound_quota WHERE key = ${key}), sent, refused FROM moved
76
+ ON CONFLICT (key, caller, window_end) DO UPDATE SET
77
+ sent = outbound_quota_spend.sent + EXCLUDED.sent,
78
+ refused = outbound_quota_spend.refused + EXCLUDED.refused,
79
+ updated_at = clock_timestamp()`);
80
+ await tx.execute(sql `
81
+ DELETE FROM outbound_quota_spend
82
+ WHERE key = ${key} AND window_end <> ALL (
83
+ SELECT window_end FROM (
84
+ SELECT window_end FROM outbound_quota_spend WHERE key = ${key} AND window_end <> 'infinity'::timestamptz
85
+ UNION SELECT reset_at FROM outbound_quota WHERE key = ${key}
86
+ ORDER BY window_end DESC LIMIT ${retain}) kept)
87
+ AND window_end <> 'infinity'::timestamptz`);
88
+ }
61
89
  async function record(key, input) {
62
90
  const headers = toHeaders(input);
63
91
  const budget = read(headers);
@@ -68,26 +96,38 @@ export function createQuota(config = {}) {
68
96
  if (budget !== null) {
69
97
  // Same window: lowest remaining. Different window: a live response (reset in the future) replaces the row; a past reset is ignored.
70
98
  const limit = budget.limit ?? null;
71
- await conn.execute(sql `
72
- INSERT INTO outbound_quota (key, remaining, "limit", reset_at, updated_at)
73
- VALUES (${key}, ${budget.remaining}, ${limit}, ${iso(budget.resetAt)}::timestamptz, clock_timestamp())
74
- ON CONFLICT (key) DO UPDATE SET
75
- remaining = CASE
76
- WHEN date_trunc('second', outbound_quota.reset_at) = date_trunc('second', EXCLUDED.reset_at)
77
- THEN LEAST(outbound_quota.remaining, EXCLUDED.remaining)
78
- WHEN EXCLUDED.reset_at > now() THEN EXCLUDED.remaining
79
- ELSE outbound_quota.remaining END,
80
- "limit" = CASE
81
- WHEN date_trunc('second', outbound_quota.reset_at) = date_trunc('second', EXCLUDED.reset_at)
82
- OR EXCLUDED.reset_at > now()
83
- THEN COALESCE(EXCLUDED."limit", outbound_quota."limit")
84
- ELSE outbound_quota."limit" END,
85
- reset_at = CASE
86
- WHEN date_trunc('second', outbound_quota.reset_at) = date_trunc('second', EXCLUDED.reset_at)
87
- THEN outbound_quota.reset_at
88
- WHEN EXCLUDED.reset_at > now() THEN EXCLUDED.reset_at
89
- ELSE outbound_quota.reset_at END,
90
- updated_at = clock_timestamp()`);
99
+ await conn.transaction(async (tx) => {
100
+ const before = await tx.execute(sql `SELECT reset_at FROM outbound_quota WHERE key = ${key} FOR UPDATE`);
101
+ const prior = before[0] === undefined ? null : toDate(before[0]['reset_at']);
102
+ const after = await tx.execute(sql `
103
+ INSERT INTO outbound_quota (key, remaining, "limit", reset_at, updated_at)
104
+ VALUES (${key}, ${budget.remaining}, ${limit}, ${iso(budget.resetAt)}::timestamptz, clock_timestamp())
105
+ ON CONFLICT (key) DO UPDATE SET
106
+ remaining = CASE
107
+ WHEN date_trunc('second', outbound_quota.reset_at) = date_trunc('second', EXCLUDED.reset_at)
108
+ THEN LEAST(outbound_quota.remaining, EXCLUDED.remaining)
109
+ WHEN EXCLUDED.reset_at > now() THEN EXCLUDED.remaining
110
+ ELSE outbound_quota.remaining END,
111
+ "limit" = CASE
112
+ WHEN date_trunc('second', outbound_quota.reset_at) = date_trunc('second', EXCLUDED.reset_at)
113
+ OR EXCLUDED.reset_at > now()
114
+ THEN COALESCE(EXCLUDED."limit", outbound_quota."limit")
115
+ ELSE outbound_quota."limit" END,
116
+ reset_at = CASE
117
+ WHEN date_trunc('second', outbound_quota.reset_at) = date_trunc('second', EXCLUDED.reset_at)
118
+ THEN outbound_quota.reset_at
119
+ WHEN EXCLUDED.reset_at > now() THEN EXCLUDED.reset_at
120
+ ELSE outbound_quota.reset_at END,
121
+ updated_at = clock_timestamp()
122
+ RETURNING reset_at, reset_at > now() AS live`);
123
+ const row = after[0];
124
+ if (row === undefined || row['live'] !== true)
125
+ return;
126
+ const reset = toDate(row['reset_at']);
127
+ if (prior !== null && Math.floor(prior.getTime() / 1000) === Math.floor(reset.getTime() / 1000))
128
+ return;
129
+ await startWindow(tx, key);
130
+ });
91
131
  }
92
132
  if (retryAfter !== null) {
93
133
  await conn.execute(sql `
@@ -111,33 +151,90 @@ export function createQuota(config = {}) {
111
151
  resetAt: new Date(row['reset_at']),
112
152
  };
113
153
  }
114
- async function take(key, cls) {
154
+ async function take(key, cls, caller) {
115
155
  const conn = db();
116
156
  const reserve = config.reserve?.[cls] ?? 0;
157
+ // The unit and its count are one statement, so a count and a spend cannot disagree.
117
158
  const taken = await conn.execute(sql `
118
- UPDATE outbound_quota SET remaining = remaining - 1, updated_at = clock_timestamp()
119
- WHERE key = ${key} AND reset_at > now() AND remaining > ${reserve}
120
- RETURNING remaining`);
159
+ WITH taken AS (
160
+ UPDATE outbound_quota SET remaining = remaining - 1, updated_at = clock_timestamp()
161
+ WHERE key = ${key} AND reset_at > now() AND remaining > ${reserve}
162
+ RETURNING key, reset_at)
163
+ INSERT INTO outbound_quota_spend (key, caller, window_end, sent)
164
+ SELECT key, ${caller}, reset_at, 1 FROM taken
165
+ ON CONFLICT (key, caller, window_end) DO UPDATE SET
166
+ sent = outbound_quota_spend.sent + 1, updated_at = clock_timestamp()
167
+ RETURNING 1 AS counted`);
121
168
  if (taken.length > 0)
122
169
  return;
123
170
  const rows = await conn.execute(sql `
124
- UPDATE outbound_quota SET refused_at = clock_timestamp()
125
- WHERE key = ${key} AND reset_at > now()
126
- RETURNING remaining, reset_at`);
171
+ WITH asked AS (
172
+ UPDATE outbound_quota SET refused_at = clock_timestamp()
173
+ WHERE key = ${key} AND reset_at > now()
174
+ RETURNING key, remaining, reset_at),
175
+ counted AS (
176
+ INSERT INTO outbound_quota_spend (key, caller, window_end, refused)
177
+ SELECT key, ${caller}, reset_at, 1 FROM asked
178
+ ON CONFLICT (key, caller, window_end) DO UPDATE SET
179
+ refused = outbound_quota_spend.refused + 1, updated_at = clock_timestamp()
180
+ RETURNING 1)
181
+ SELECT remaining, reset_at FROM asked`);
127
182
  const row = rows[0];
128
- if (row === undefined)
129
- return; // unknown budget: send optimistically
183
+ if (row === undefined) {
184
+ // unknown budget: send optimistically, counted until a response places the window
185
+ await conn.execute(sql `
186
+ INSERT INTO outbound_quota_spend (key, caller, window_end, sent)
187
+ VALUES (${key}, ${caller}, 'infinity'::timestamptz, 1)
188
+ ON CONFLICT (key, caller, window_end) DO UPDATE SET
189
+ sent = outbound_quota_spend.sent + 1, updated_at = clock_timestamp()`);
190
+ return;
191
+ }
130
192
  throw new QuotaExhaustedError({
131
193
  key, class: cls, reserve,
132
194
  remaining: Number(row['remaining']),
133
- resetAt: new Date(row['reset_at']),
195
+ resetAt: toDate(row['reset_at']),
134
196
  });
135
197
  }
198
+ async function spend(key) {
199
+ const conn = db();
200
+ const live = await conn.execute(sql `SELECT reset_at FROM outbound_quota WHERE key = ${key} AND reset_at > now()`);
201
+ const liveAt = live[0] === undefined ? null : toDate(live[0]['reset_at']).getTime();
202
+ const rows = await conn.execute(sql `
203
+ SELECT caller, sent, refused,
204
+ CASE WHEN window_end = 'infinity'::timestamptz THEN NULL ELSE window_end END AS window_end
205
+ FROM outbound_quota_spend WHERE key = ${key}`);
206
+ const byWindow = new Map();
207
+ const unplaced = [];
208
+ for (const r of rows) {
209
+ const entry = { caller: String(r['caller']), sent: Number(r['sent']), refused: Number(r['refused']) };
210
+ if (r['window_end'] === null) {
211
+ unplaced.push(entry);
212
+ continue;
213
+ }
214
+ const at = toDate(r['window_end']).getTime();
215
+ const list = byWindow.get(at);
216
+ if (list === undefined)
217
+ byWindow.set(at, [entry]);
218
+ else
219
+ list.push(entry);
220
+ }
221
+ const order = (list) => list.sort((a, b) => (b.sent + b.refused) - (a.sent + a.refused) || (a.caller < b.caller ? -1 : a.caller > b.caller ? 1 : 0));
222
+ const windowOf = (at) => at === null ? null : { resetAt: new Date(at), callers: order(byWindow.get(at) ?? []) };
223
+ const finite = [...byWindow.keys()].sort((a, b) => b - a);
224
+ const currentAt = liveAt;
225
+ const previousAt = finite.find(at => currentAt === null || at < currentAt) ?? null;
226
+ return {
227
+ current: currentAt === null ? null : windowOf(currentAt),
228
+ previous: windowOf(previousAt),
229
+ unplaced: order(unplaced),
230
+ };
231
+ }
136
232
  return {
137
233
  record,
138
234
  state,
235
+ spend,
139
236
  async call(target, send, opts = {}) {
140
- await take(target.key, target.class);
237
+ await take(target.key, target.class, target.caller ?? UNLABELLED);
141
238
  let result;
142
239
  try {
143
240
  const o = opts.retryUnsent;
@@ -1 +1 @@
1
- {"version":3,"file":"handle.js","sourceRoot":"","sources":["../../../src/infra/quota/handle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAE1C,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAA;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACjD,OAAO,EAAE,WAAW,EAA4B,MAAM,2BAA2B,CAAA;AAgDjF,SAAS,SAAS,CAAC,OAAqB,EAAE,IAAY;IACpD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7B,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAC7B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;IAC5B,OAAO,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACvE,CAAC;AAED,SAAS,WAAW,CAAC,OAAqB;IACxC,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAA;IAC7D,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAA;IACrD,IAAI,SAAS,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IACrD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAA;IACrD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAA;AAC7F,CAAC;AAED,SAAS,SAAS,CAAC,KAAuB;IACxC,IAAI,OAAQ,KAAsB,CAAC,GAAG,KAAK,UAAU;QAAE,OAAO,KAAqB,CAAA;IACnF,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAA;IACrC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAA+D,CAAC,EAAE,CAAC;QAC5G,IAAI,KAAK,KAAK,SAAS;YAAE,SAAQ;QACjC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IACnF,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,EAAE,CAAA;AAC/D,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAC5D,MAAM,OAAO,GAAI,KAA+B,CAAC,OAAO,CAAA;IACxD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAChE,OAAO,OAA2B,CAAA;AACpC,CAAC;AAED,SAAS,SAAS,CAAC,QAA4B;IAC7C,MAAM,GAAG,GAAG,UAAU,EAAE,CAAA;IACxB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,kEAAkE;YAClE,uDAAuD,CACxD,CAAA;IACH,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAA;IAClE,OAAO,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAA;AAClF,CAAC;AAED,MAAM,GAAG,GAAG,CAAC,CAAO,EAAU,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;AAEhD,SAAS,gBAAgB,CAAC,GAAW,EAAE,GAAY;IACjD,aAAa,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,mDAAmD,CAAC,CAAA;IACxF,KAAK,WAAW,CAAC,cAAc,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAA;AAC9D,CAAC;AAED,MAAM,UAAU,WAAW,CAAmB,SAAyB,EAAE;IACvE,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAA;IACpF,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,WAAW,CAAA;IACvC,MAAM,EAAE,GAAG,GAAO,EAAE,CAAC,MAAM,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAE7G,KAAK,UAAU,MAAM,CAAC,GAAW,EAAE,KAAuB;QACxD,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAA;QAC5B,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;QACpD,IAAI,MAAM,KAAK,IAAI,IAAI,UAAU,KAAK,IAAI;YAAE,OAAM;QAClD,MAAM,IAAI,GAAG,EAAE,EAAE,CAAA;QACjB,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,oIAAoI;YACpI,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,IAAI,CAAA;YAClC,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAA;;kBAEV,GAAG,KAAK,MAAM,CAAC,SAAS,KAAK,KAAK,KAAK,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;;;;;;;;;;;;;;;;;yCAiBnC,CAAC,CAAA;QACtC,CAAC;QACD,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAA;;kBAEV,GAAG,4CAA4C,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;;;uFAGD,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;yCACrE,CAAC,CAAA;QACtC,CAAC;IACH,CAAC;IAED,KAAK,UAAU,KAAK,CAAC,GAAW;QAC9B,MAAM,IAAI,GAAG,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA;4EACqC,GAAG,uBAAuB,CAAC,CAAA;QACnG,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,IAAI,CAAA;QAClC,OAAO;YACL,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACnC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC1D,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAkB,CAAC;SACpD,CAAA;IACH,CAAC;IAED,KAAK,UAAU,IAAI,CAAC,GAAW,EAAE,GAAW;QAC1C,MAAM,IAAI,GAAG,EAAE,EAAE,CAAA;QACjB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,GAAQ,CAAC,IAAI,CAAC,CAAA;QAC/C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAA;;oBAEpB,GAAG,yCAAyC,OAAO;0BAC7C,CAAC,CAAA;QACvB,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAM;QAC5B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAA;;oBAEnB,GAAG;oCACa,CAAC,CAAA;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,IAAI,GAAG,KAAK,SAAS;YAAE,OAAM,CAAC,sCAAsC;QACpE,MAAM,IAAI,mBAAmB,CAAC;YAC5B,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO;YACxB,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACnC,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAkB,CAAC;SACpD,CAAC,CAAA;IACJ,CAAC;IAED,OAAO;QACL,MAAM;QACN,KAAK;QACL,KAAK,CAAC,IAAI,CAAI,MAAiC,EAAE,IAAsB,EAAE,OAA4B,EAAE;YACrG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;YACpC,IAAI,MAAS,CAAA;YACb,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,CAAA;gBAC1B,MAAM,GAAG,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACxF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,GAAG,GAAoC,CAAA;gBAC9C,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,CAAA;gBACtD,IAAI,KAAK,KAAK,IAAI;oBAAE,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,SAAkB,EAAE,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;gBAC9H,MAAM,GAAG,CAAA;YACX,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,KAAK,SAAS;gBACtC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;gBACtB,CAAC,CAAC,CAAC,GAAG,EAAE;oBACJ,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;oBAC3B,OAAO,CAAC,KAAK,IAAI,IAAI,OAAQ,CAAkB,CAAC,GAAG,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;gBAC/E,CAAC,CAAC,EAAE,CAAA;YACR,6FAA6F;YAC7F,IAAI,KAAK,KAAK,IAAI;gBAAE,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,SAAkB,EAAE,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;YAC9H,OAAO,MAAM,CAAA;QACf,CAAC;KACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"handle.js","sourceRoot":"","sources":["../../../src/infra/quota/handle.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  export { createQuota } from './handle.js';
2
- export type { Quota, QuotaConfig, QuotaHeaders, QuotaHeaderInput, QuotaBudget, QuotaState, QuotaCallOptions, } from './handle.js';
2
+ export type { Quota, QuotaConfig, QuotaHeaders, QuotaHeaderInput, QuotaBudget, QuotaState, QuotaCallOptions, QuotaSpend, QuotaWindowSpend, QuotaCallerSpend, } from './handle.js';
3
3
  export { QuotaExhaustedError } from './errors.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/infra/quota/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,YAAY,EACV,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,GAC9F,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/infra/quota/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,YAAY,EACV,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAC7F,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,GAC/C,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/infra/quota/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAIzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/infra/quota/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAKzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA"}
@@ -23,4 +23,24 @@ export declare const outboundQuota: import("../../data/domain/types.js").Defined
23
23
  nullable: true;
24
24
  }>;
25
25
  }, "outbound_quota">;
26
+ export declare const outboundQuotaSpend: import("../../data/domain/types.js").DefinedTable<{
27
+ key: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
28
+ caller: import("../../data/domain/types.js").FieldDescriptor<string, {}> & import("../../data/domain/field.js").FieldModifiers<string, {}>;
29
+ windowEnd: import("../../data/domain/types.js").FieldDescriptor<Date, {}> & import("../../data/domain/field.js").FieldModifiers<Date, {}>;
30
+ sent: import("../../data/domain/types.js").FieldDescriptor<number, {
31
+ hasDefault: true;
32
+ }> & import("../../data/domain/field.js").FieldModifiers<number, {
33
+ hasDefault: true;
34
+ }>;
35
+ refused: import("../../data/domain/types.js").FieldDescriptor<number, {
36
+ hasDefault: true;
37
+ }> & import("../../data/domain/field.js").FieldModifiers<number, {
38
+ hasDefault: true;
39
+ }>;
40
+ updatedAt: import("../../data/domain/types.js").FieldDescriptor<Date, {
41
+ hasDefault: true;
42
+ }> & import("../../data/domain/field.js").FieldModifiers<Date, {
43
+ hasDefault: true;
44
+ }>;
45
+ }, "outbound_quota_spend">;
26
46
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/infra/quota/schema.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;IAMxB,uGAAuG;;;;;;oBAEvG,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/infra/quota/schema.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;IAMxB,uGAAuG;;;;;;oBAEvG,CAAA;AAIF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;0BAS7B,CAAA"}
@@ -11,4 +11,16 @@ export const outboundQuota = define('outbound_quota', {
11
11
  /** When a call was last refused against this row; it counts while it is not older than `updatedAt`. */
12
12
  refusedAt: field.timestamp().nullable(),
13
13
  });
14
+ // Calls per (key, caller, window): `window_end` is the budget row's reset_at; 'infinity' holds calls made
15
+ // before any window was known, moved into the first window a response records.
16
+ export const outboundQuotaSpend = define('outbound_quota_spend', {
17
+ key: field.text(),
18
+ caller: field.text(),
19
+ windowEnd: field.timestamp(),
20
+ sent: field.integer().default(0),
21
+ refused: field.integer().default(0),
22
+ updatedAt: field.timestamp().default('now'),
23
+ }, {
24
+ primaryKey: ['key', 'caller', 'windowEnd'],
25
+ });
14
26
  //# sourceMappingURL=schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/infra/quota/schema.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,oEAAoE;AAEpE,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAElD,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,EAAE;IACpD,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,EAAE;IAC9B,SAAS,EAAE,KAAK,CAAC,OAAO,EAAE;IAC1B,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACjC,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE;IAC1B,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC3C,uGAAuG;IACvG,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE;CACxC,CAAC,CAAA"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/infra/quota/schema.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,oEAAoE;AAEpE,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAElD,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,EAAE;IACpD,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,UAAU,EAAE;IAC9B,SAAS,EAAE,KAAK,CAAC,OAAO,EAAE;IAC1B,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACjC,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE;IAC1B,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC3C,uGAAuG;IACvG,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE;CACxC,CAAC,CAAA;AAEF,0GAA0G;AAC1G,+EAA+E;AAC/E,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,sBAAsB,EAAE;IAC/D,GAAG,EAAE,KAAK,CAAC,IAAI,EAAE;IACjB,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE;IACpB,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE;IAC5B,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAChC,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACnC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CAC5C,EAAE;IACD,UAAU,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC;CAC3C,CAAC,CAAA"}
@@ -38,6 +38,8 @@ export interface Flow<TAuth = unknown> {
38
38
  readonly transactions: Map<string, BoundTransaction>;
39
39
  /** The trace opened at this entry, or `null` when the entry ran untraced. */
40
40
  readonly trace: TraceContext | null;
41
+ /** Aborted when the HTTP client closes the connection before the response is finished; pass it to outbound calls. Unset outside an HTTP request. */
42
+ readonly signal?: AbortSignal;
41
43
  }
42
44
  /** HTTP request metadata stored in a Flow — method, path, trace ID, session ID. */
43
45
  export interface RequestMetadata {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/request/context/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAA;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AAEtE,+GAA+G;AAC/G,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAA;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAC9B;AAED,8HAA8H;AAC9H,MAAM,WAAW,IAAI,CAAC,KAAK,GAAG,OAAO;IACnC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,4FAA4F;IAC5F,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,sHAAsH;IACtH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAA;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,0HAA0H;IAC1H,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,kFAAkF;IAClF,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IACtC;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAA;IAC1C,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;IACpD,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAA;CACpC;AAED,mFAAmF;AACnF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAClC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/request/context/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,wBAAwB,CAAA;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AAEtE,+GAA+G;AAC/G,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAA;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAC9B;AAED,8HAA8H;AAC9H,MAAM,WAAW,IAAI,CAAC,KAAK,GAAG,OAAO;IACnC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,4FAA4F;IAC5F,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,sHAAsH;IACtH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAA;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,0HAA0H;IAC1H,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,kFAAkF;IAClF,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IACtC;;;;;;OAMG;IACH,QAAQ,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAA;IAC1C,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;IACpD,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAA;IACnC,oJAAoJ;IACpJ,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAC9B;AAED,mFAAmF;AACnF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAClC"}
@@ -17,7 +17,7 @@ export interface ResolveOptions {
17
17
  * would be a footgun.
18
18
  */
19
19
  readonly checkpoint?: CheckpointFn;
20
- /** A job's own signal, injected as the `signal` dep. */
20
+ /** A job's own signal, or an HTTP request's abort signal, injected as the `signal` dep. */
21
21
  readonly signal?: AbortSignal;
22
22
  }
23
23
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/request/di/resolve.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../../src/request/di/resolve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { PipeworkError } from '../../core/errors/index.js';
2
+ /**
3
+ * The reason a request's `signal` aborts with when the client closes the
4
+ * connection before the response is finished. Not an internal error: nothing
5
+ * is sent (the socket is gone) and `onInternalError` is not called.
6
+ */
7
+ export declare class RequestAbortedError extends PipeworkError {
8
+ readonly code: "REQUEST_ABORTED";
9
+ readonly httpStatus: 499;
10
+ constructor(method: string, route: string);
11
+ }
12
+ //# sourceMappingURL=aborted.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aborted.d.ts","sourceRoot":"","sources":["../../../src/request/http/aborted.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAE1D;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,aAAa;IACpD,QAAQ,CAAC,IAAI,EAAG,iBAAiB,CAAS;IAC1C,QAAQ,CAAC,UAAU,EAAG,GAAG,CAAS;gBAEtB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAG1C"}
@@ -0,0 +1,14 @@
1
+ import { PipeworkError } from '../../core/errors/index.js';
2
+ /**
3
+ * The reason a request's `signal` aborts with when the client closes the
4
+ * connection before the response is finished. Not an internal error: nothing
5
+ * is sent (the socket is gone) and `onInternalError` is not called.
6
+ */
7
+ export class RequestAbortedError extends PipeworkError {
8
+ code = 'REQUEST_ABORTED';
9
+ httpStatus = 499;
10
+ constructor(method, route) {
11
+ super(`[pipework] The client closed the connection before the response was sent (${method} ${route}).`, { method, route });
12
+ }
13
+ }
14
+ //# sourceMappingURL=aborted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aborted.js","sourceRoot":"","sources":["../../../src/request/http/aborted.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAE1D;;;;GAIG;AACH,MAAM,OAAO,mBAAoB,SAAQ,aAAa;IAC3C,IAAI,GAAG,iBAA0B,CAAA;IACjC,UAAU,GAAG,GAAY,CAAA;IAElC,YAAY,MAAc,EAAE,KAAa;QACvC,KAAK,CAAC,6EAA6E,MAAM,IAAI,KAAK,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;IAC5H,CAAC;CACF"}
@@ -1,6 +1,8 @@
1
1
  import { file } from './file.js';
2
2
  import { detectMediaType, resolveMediaType } from './sniff.js';
3
- /** HTTP namespace: `http.file()` builds a file response; `http.detectMediaType()` names bytes the way uploads do; the server itself is managed by manifold.start(). */
3
+ /** HTTP namespace: `http.file()` builds a file response; `http.detectMediaType()` names bytes the way uploads do; the server itself is managed by manifold.start().
4
+ *
5
+ * A client that disconnects before its response is finished aborts the request: the in-flight statement is cancelled, the transaction rolled back and the connection released. The context's `signal` (`flow.require().signal`) aborts with a `RequestAbortedError` (499, `REQUEST_ABORTED`); pass it to the handler's own outbound calls (`fetch(url, { signal })`, a `quota.call` send). The aborted request is not an internal error: `onInternalError` is not called and nothing is sent. */
4
6
  export declare const http: {
5
7
  readonly file: typeof file;
6
8
  readonly detectMediaType: typeof detectMediaType;
@@ -1 +1 @@
1
- {"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../../src/request/http/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAe,MAAM,YAAY,CAAA;AAE3E,uKAAuK;AACvK,eAAO,MAAM,IAAI;;;;;CAAoE,CAAA"}
1
+ {"version":3,"file":"namespace.d.ts","sourceRoot":"","sources":["../../../src/request/http/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAe,MAAM,YAAY,CAAA;AAE3E;;ieAEie;AACje,eAAO,MAAM,IAAI;;;;;CAAoE,CAAA"}
@@ -1,5 +1,7 @@
1
1
  import { file } from './file.js';
2
2
  import { detectMediaType, resolveMediaType, SNIFF_BYTES } from './sniff.js';
3
- /** HTTP namespace: `http.file()` builds a file response; `http.detectMediaType()` names bytes the way uploads do; the server itself is managed by manifold.start(). */
3
+ /** HTTP namespace: `http.file()` builds a file response; `http.detectMediaType()` names bytes the way uploads do; the server itself is managed by manifold.start().
4
+ *
5
+ * A client that disconnects before its response is finished aborts the request: the in-flight statement is cancelled, the transaction rolled back and the connection released. The context's `signal` (`flow.require().signal`) aborts with a `RequestAbortedError` (499, `REQUEST_ABORTED`); pass it to the handler's own outbound calls (`fetch(url, { signal })`, a `quota.call` send). The aborted request is not an internal error: `onInternalError` is not called and nothing is sent. */
4
6
  export const http = { file, detectMediaType, resolveMediaType, SNIFF_BYTES };
5
7
  //# sourceMappingURL=namespace.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../../src/request/http/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE3E,uKAAuK;AACvK,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAW,CAAA"}
1
+ {"version":3,"file":"namespace.js","sourceRoot":"","sources":["../../../src/request/http/namespace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE3E;;ieAEie;AACje,MAAM,CAAC,MAAM,IAAI,GAAG,EAAE,IAAI,EAAE,eAAe,EAAE,gBAAgB,EAAE,WAAW,EAAW,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/request/http/server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AACzD,OAAO,KAAK,EAAc,YAAY,EAAsC,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AA4B7H,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAGnD,qGAAqG;AACrG,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACjG,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,CAAA;IAC7E,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;IACnD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;IACpD,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB;;;OAGG;IACH,IAAI,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACzC;AAED,wHAAwH;AACxH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAE,YAAiB,GAAG,cAAc,CA+oB1F"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/request/http/server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AACzD,OAAO,KAAK,EAAc,YAAY,EAAsC,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AA6B7H,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAGnD,qGAAqG;AACrG,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACjG,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI,CAAA;IAC7E,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,CAAA;IACnD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;IACpD,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB;;;OAGG;IACH,IAAI,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACzC;AAED,wHAAwH;AACxH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAE,YAAiB,GAAG,cAAc,CAkqB1F"}
@@ -10,6 +10,7 @@ import { createRequestContext } from '../context/index.js';
10
10
  import { executeInTransaction } from '../context/run-in-transaction.js';
11
11
  import { resolveAndExecute, parseRouteInputs, resolveHandlerDatabases, buildCheckpoint } from '../di/resolve.js';
12
12
  import { createRateLimitClasses } from './rate-limit-classes.js';
13
+ import { RequestAbortedError } from './aborted.js';
13
14
  import { buildContext } from './middleware.js';
14
15
  import { closeTrace } from '../../trace/entry/close-trace.js';
15
16
  import { recordErrorStep } from './error-step.js';
@@ -382,13 +383,21 @@ export function createServer(instance, config = {}) {
382
383
  let ctx;
383
384
  let uploaded;
384
385
  const track = newUploadTrack();
386
+ // Aborted when the client closes the connection before the response is finished.
387
+ const abort = new AbortController();
388
+ const onClose = () => {
389
+ if (!reply.raw.writableEnded && !abort.signal.aborted)
390
+ abort.abort(new RequestAbortedError(method, path));
391
+ };
392
+ reply.raw.once('close', onClose);
393
+ reply.raw.once('finish', () => { reply.raw.removeListener('close', onClose); });
385
394
  // Ends the upload stream and closes the connection if the body was left unread.
386
395
  const finishUpload = (failed) => {
387
396
  if (settleUpload(uploaded?.stream) || (failed && upload !== null))
388
397
  void reply.header('connection', 'close');
389
398
  };
390
399
  try {
391
- ctx = await buildContext(req, contextOptions, handler.meta.authRequirement);
400
+ ctx = { ...(await buildContext(req, contextOptions, handler.meta.authRequirement)), signal: abort.signal };
392
401
  req.pipeworkTraceId = ctx.trace?.id ?? null;
393
402
  requestFlows.set(req, ctx);
394
403
  if (rateLimitClasses !== null)
@@ -418,6 +427,7 @@ export function createServer(instance, config = {}) {
418
427
  },
419
428
  ...(rawBodyBuffer !== undefined ? { rawBody: rawBodyBuffer } : {}),
420
429
  ...(uploaded !== undefined ? { upload: uploaded } : {}),
430
+ signal: abort.signal,
421
431
  };
422
432
  // Fastify hands a missing body over as null; the input sees undefined.
423
433
  // A body that is literally JSON null names a content-type and stays null.
@@ -430,11 +440,11 @@ export function createServer(instance, config = {}) {
430
440
  // be written and committed, a network call made, and the outcome
431
441
  // written again, all under the request's own tenant with RLS
432
442
  // enforced. What it costs is stated on `.transaction('manual')`.
433
- const checkpoint = buildCheckpoint(handler, ctx, resolveHandlerDatabases(handler, instance), tenantConfig, txTimeoutMs);
443
+ const checkpoint = buildCheckpoint(handler, ctx, resolveHandlerDatabases(handler, instance), tenantConfig, txTimeoutMs, abort.signal);
434
444
  result = await runInContext(ctx, () => resolveAndExecute(handler, body, req.query, req.params, { ...httpOptions, checkpoint }));
435
445
  }
436
446
  else if (txDatabases !== null && txDatabases.length > 0) {
437
- result = await executeInTransaction(ctx, txDatabases, tenantConfig, txTimeoutMs, () => resolveAndExecute(handler, body, req.query, req.params, httpOptions));
447
+ result = await executeInTransaction(ctx, txDatabases, tenantConfig, txTimeoutMs, () => resolveAndExecute(handler, body, req.query, req.params, httpOptions), abort.signal);
438
448
  }
439
449
  else {
440
450
  result = await runInContext(ctx, () => resolveAndExecute(handler, body, req.query, req.params, httpOptions));
@@ -445,6 +455,16 @@ export function createServer(instance, config = {}) {
445
455
  }
446
456
  catch (error) {
447
457
  finishUpload(true);
458
+ // The client is gone, whatever the error was (a cancelled statement, the abort itself):
459
+ // not a fault, nothing to send.
460
+ if (abort.signal.aborted) {
461
+ const reason = abort.signal.reason;
462
+ recordErrorStep(ctx, { method, route: path, status: 499, code: 'REQUEST_ABORTED', error: reason });
463
+ if (ctx !== undefined)
464
+ void closeTrace(instance, ctx.trace, 'error');
465
+ req.log.info({ route: `${method} ${path}`, requestId: String(req.id) }, 'request aborted by client');
466
+ return reply;
467
+ }
448
468
  // Records the error step, runs `refused` (the route's onRefused hook) while the
449
469
  // trace is still open, then closes the trace.
450
470
  const failWith = async (status, code, refused) => {