cursedbelt-server 4.9.0 → 4.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/analytics/webAnalytics.d.ts +32 -3
- package/dist/server/analytics/webAnalytics.js +40 -6
- package/dist/server/bench/cpuClock.d.ts +4 -0
- package/dist/server/bench/cpuClock.js +57 -3
- package/dist/server/bench/runBench.d.ts +27 -0
- package/dist/server/bench/runBench.js +42 -2
- package/dist/server/d1/index.d.ts +1 -1
- package/dist/server/d1/index.js +1 -1
- package/dist/server/d1/invocation.d.ts +72 -0
- package/dist/server/d1/invocation.js +65 -0
- package/dist/server/master-lock/guard.d.ts +8 -3
- package/dist/server/master-lock/guard.js +8 -3
- package/package.json +1 -1
- package/src/nodeBuiltinsAreProbedByCalling.spec.ts +233 -0
- package/src/publicSurface.spec.ts +88 -0
- package/src/server/analytics/injectedScripts.spec.ts +11 -7
- package/src/server/analytics/webAnalytics.spec.ts +26 -7
- package/src/server/analytics/webAnalytics.ts +43 -6
- package/src/server/bench/cpuBudget.spec.ts +191 -1
- package/src/server/bench/cpuClock.spec.ts +141 -0
- package/src/server/bench/cpuClock.ts +55 -2
- package/src/server/bench/runBench.ts +73 -2
- package/src/server/d1/index.ts +1 -1
- package/src/server/d1/invocation.spec.ts +65 -1
- package/src/server/d1/invocation.ts +86 -0
- package/src/server/incidents/incidents.spec.ts +5 -1
- package/src/server/master-lock/guard.ts +8 -3
|
@@ -39,6 +39,14 @@
|
|
|
39
39
|
* It wraps either driver, because it sits ABOVE the seam and only counts. That is what
|
|
40
40
|
* makes the local gate able to prove a production-only limit: wrap a local database in a
|
|
41
41
|
* test, run the loop, and the laptop fails exactly where the Worker would.
|
|
42
|
+
*
|
|
43
|
+
* ## The other thing that is true for the span of one request: {@link createPendingWrites}
|
|
44
|
+
*
|
|
45
|
+
* A Worker port's synchronous stores answer from a snapshot and queue their durable writes
|
|
46
|
+
* as promises, which the entry point awaits BEFORE the response leaves. That collector has
|
|
47
|
+
* the same lifetime as the budget above — one per invocation, constructed by the caller in
|
|
48
|
+
* the same breath — so it lives in the same file. See its own header for why it was moved
|
|
49
|
+
* here on 2026-09-19.
|
|
42
50
|
*/
|
|
43
51
|
|
|
44
52
|
import { LIMITS } from './limits';
|
|
@@ -205,3 +213,81 @@ export function perInvocation(db: D1LikeDatabase, opts: { max?: number } = {}):
|
|
|
205
213
|
},
|
|
206
214
|
};
|
|
207
215
|
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Where a durable write goes on its way out of one invocation.
|
|
219
|
+
*
|
|
220
|
+
* Deliberately two members, and the narrower `add`-only half is what a STORE takes. A store
|
|
221
|
+
* that also held `settle` could end the request's writes from inside the request, which is
|
|
222
|
+
* the entry point's job and nobody else's. `cursedauth/d1-stores` declares exactly this
|
|
223
|
+
* two-method shape under its own name (`WriteCollector`) because that package sits UNDER
|
|
224
|
+
* this one and may not import it — structural typing means an object made here satisfies it
|
|
225
|
+
* verbatim, with no dependency edge in either direction.
|
|
226
|
+
*/
|
|
227
|
+
export interface WriteCollector {
|
|
228
|
+
add(promise: Promise<unknown>): void;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** A write that must land before the response is returned. See {@link createPendingWrites}. */
|
|
232
|
+
export interface PendingWrites extends WriteCollector {
|
|
233
|
+
/** Await every collected write. Called BEFORE the response is returned, never after. */
|
|
234
|
+
settle(): Promise<void>;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Collect the durable writes of ONE invocation, to be awaited before the response leaves.
|
|
239
|
+
*
|
|
240
|
+
* ## Why this is the Worker-write primitive and not a convenience
|
|
241
|
+
*
|
|
242
|
+
* A ported app's synchronous stores cannot await — their signatures are somebody else's
|
|
243
|
+
* published contract — so the shape every port lands on is: one read fills a snapshot, every
|
|
244
|
+
* sync call answers from it, and every mutation both updates the snapshot and pushes its
|
|
245
|
+
* statement's promise in here. The entry point then does the awaiting:
|
|
246
|
+
*
|
|
247
|
+
* ```ts
|
|
248
|
+
* export default {
|
|
249
|
+
* async fetch(req: Request, env: Env) {
|
|
250
|
+
* const db = perInvocation(createRemoteD1(env.DB));
|
|
251
|
+
* const writes = createPendingWrites();
|
|
252
|
+
* const res = await app.fetch(req, { db, writes });
|
|
253
|
+
* await writes.settle(); // 🔴 BEFORE the response, never after
|
|
254
|
+
* return res;
|
|
255
|
+
* },
|
|
256
|
+
* };
|
|
257
|
+
* ```
|
|
258
|
+
*
|
|
259
|
+
* 🔴 **`settle()` before the response, never `ctx.waitUntil`.** A Worker isolate is per-colo
|
|
260
|
+
* and short-lived; a write acknowledged by a 200 and then dropped means "sign out" reported
|
|
261
|
+
* success and left the credential live — a failure invisible to any single-process test and
|
|
262
|
+
* indistinguishable, to the person, from the feature being broken.
|
|
263
|
+
*
|
|
264
|
+
* 🔴 **`Promise.all`, not `allSettled`.** A failed durable write must not be reported as a
|
|
265
|
+
* success. It surfaces as a 500 from the entry point, which is the honest answer to "did my
|
|
266
|
+
* sign-out take". `allSettled` here would convert every lost write into a silent 200 — the
|
|
267
|
+
* same outcome as not collecting them at all, reached by a road that looks careful.
|
|
268
|
+
*
|
|
269
|
+
* ## Why it lives here
|
|
270
|
+
*
|
|
271
|
+
* It was written three times before it was published once — `apps/patterns/worker/stores.ts`,
|
|
272
|
+
* `apps/collections/worker/stores.ts` and `libs/cursedauth/src/d1Stores.ts`, byte-identical
|
|
273
|
+
* but for a comment, with six more ports queued behind them. It is a D1-INVOCATION primitive
|
|
274
|
+
* rather than an auth one, so it belongs beside {@link perInvocation}: both are constructed
|
|
275
|
+
* per request, both describe what is true for the span of one, and neither knows anything
|
|
276
|
+
* about who is signed in.
|
|
277
|
+
*
|
|
278
|
+
* Ordering is NOT what this gives you. Everything added is already in flight, so two writes
|
|
279
|
+
* that must land in order go in one `batch()`, never in two `add`s — a DELETE that must
|
|
280
|
+
* precede its INSERT will otherwise race and trip a unique index.
|
|
281
|
+
*/
|
|
282
|
+
export function createPendingWrites(): PendingWrites {
|
|
283
|
+
const pending: Promise<unknown>[] = [];
|
|
284
|
+
return {
|
|
285
|
+
add: (promise) => void pending.push(promise),
|
|
286
|
+
async settle() {
|
|
287
|
+
// `all`, not `allSettled`: a failed durable write must not be reported as a
|
|
288
|
+
// success. It surfaces as a 500 from the entry point, which is the honest answer
|
|
289
|
+
// to "did my sign-out take".
|
|
290
|
+
await Promise.all(pending);
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
}
|
|
@@ -30,7 +30,11 @@ const stuckIngest = (failed = 42): IncidentReport => ({
|
|
|
30
30
|
title: "collections: every queued upload is failing",
|
|
31
31
|
whatBroke: "The scheduled ingest ran and every one of its items failed.",
|
|
32
32
|
whatItBlocks: "Nothing new reaches the collections app, and the queue keeps growing.",
|
|
33
|
-
|
|
33
|
+
// 🔴 Not a `cd ~/…`. This is a PUBLISHED library: a fixture here is read by whoever
|
|
34
|
+
// installs it, and the string that stood until 2026-09-22 named a directory on one
|
|
35
|
+
// machine that had not existed for days. `check-paths`'s `deadCd` rule is what found
|
|
36
|
+
// it, and a fixture is the one kind of violation that can simply be reworded.
|
|
37
|
+
whatToDo: "Run the storage-drift sweep for this tenant and clear the failed uploads.",
|
|
34
38
|
facts: { failed, pending: failed },
|
|
35
39
|
});
|
|
36
40
|
|
|
@@ -80,9 +80,14 @@ const noStore = { "cache-control": "no-store, no-cache, must-revalidate", pragma
|
|
|
80
80
|
* loosening it: nothing loads from anywhere but this origin, the form posts nowhere (the
|
|
81
81
|
* script does the POST), and the page cannot be framed.
|
|
82
82
|
*
|
|
83
|
-
* 🔴 **EXPORTED so that nothing has to copy it
|
|
84
|
-
*
|
|
85
|
-
*
|
|
83
|
+
* 🔴 **EXPORTED so that nothing has to copy it** — and exporting it is not the same as nothing
|
|
84
|
+
* copying it. This sentence used to read *"`apps/collections` had a hand-typed duplicate … until
|
|
85
|
+
* 2026-09-18"*, and it was false the day it was written: the export landed, and BOTH re-typed
|
|
86
|
+
* copies stayed — one in `apps/collections/scripts/injectedScripts.test.ts` and one three
|
|
87
|
+
* directories from here in `../analytics/injectedScripts.spec.ts`. They were collapsed onto this
|
|
88
|
+
* constant on 2026-09-21. A policy that is typed twice can be loosened in one place and stay
|
|
89
|
+
* green in the other, which is a wall that no longer refuses what its own test says it does.
|
|
90
|
+
* It is also what
|
|
86
91
|
* `beaconNeverReachesTheWall.spec.ts` measures the beacon against: the wall refuses
|
|
87
92
|
* `static.cloudflareinsights.com`, so the analytics tag and this response are mutually
|
|
88
93
|
* exclusive BY CONSTRUCTION rather than by anyone remembering. The owner's reason, 2026-09-18:
|