@substrat-run/kernel 0.158.0 → 0.160.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.
- package/dist/billing-retention.d.ts +46 -0
- package/dist/billing-retention.d.ts.map +1 -0
- package/dist/billing-retention.js +78 -0
- package/dist/billing-retention.js.map +1 -0
- package/dist/byte-stream.d.ts +102 -0
- package/dist/byte-stream.d.ts.map +1 -0
- package/dist/byte-stream.js +153 -0
- package/dist/byte-stream.js.map +1 -0
- package/dist/connection-landings.d.ts +15 -3
- package/dist/connection-landings.d.ts.map +1 -1
- package/dist/connection-landings.js +10 -2
- package/dist/connection-landings.js.map +1 -1
- package/dist/deadline-fetch.d.ts +34 -0
- package/dist/deadline-fetch.d.ts.map +1 -0
- package/dist/deadline-fetch.js +231 -0
- package/dist/deadline-fetch.js.map +1 -0
- package/dist/deployment-wire-auth.d.ts +82 -0
- package/dist/deployment-wire-auth.d.ts.map +1 -0
- package/dist/deployment-wire-auth.js +150 -0
- package/dist/deployment-wire-auth.js.map +1 -0
- package/dist/entity-trash.d.ts +65 -8
- package/dist/entity-trash.d.ts.map +1 -1
- package/dist/entity-trash.js +80 -12
- package/dist/entity-trash.js.map +1 -1
- package/dist/export-break.d.ts +6 -0
- package/dist/export-break.d.ts.map +1 -1
- package/dist/export-break.js +11 -0
- package/dist/export-break.js.map +1 -1
- package/dist/index.d.ts +18 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -7
- package/dist/index.js.map +1 -1
- package/dist/invocation-line.d.ts +3 -2
- package/dist/invocation-line.d.ts.map +1 -1
- package/dist/invocation-line.js +2 -0
- package/dist/invocation-line.js.map +1 -1
- package/dist/meter-days.d.ts +107 -0
- package/dist/meter-days.d.ts.map +1 -0
- package/dist/meter-days.js +230 -0
- package/dist/meter-days.js.map +1 -0
- package/dist/meters.d.ts +19 -1
- package/dist/meters.d.ts.map +1 -1
- package/dist/meters.js +0 -0
- package/dist/meters.js.map +1 -1
- package/dist/ops-failure-reference.d.ts +31 -0
- package/dist/ops-failure-reference.d.ts.map +1 -0
- package/dist/ops-failure-reference.js +32 -0
- package/dist/ops-failure-reference.js.map +1 -0
- package/dist/platform-request-cap.d.ts +9 -0
- package/dist/platform-request-cap.d.ts.map +1 -0
- package/dist/platform-request-cap.js +42 -0
- package/dist/platform-request-cap.js.map +1 -0
- package/dist/platform-sweep.d.ts +170 -7
- package/dist/platform-sweep.d.ts.map +1 -1
- package/dist/platform-sweep.js +375 -45
- package/dist/platform-sweep.js.map +1 -1
- package/dist/request-rollup.d.ts +161 -0
- package/dist/request-rollup.d.ts.map +1 -0
- package/dist/request-rollup.js +273 -0
- package/dist/request-rollup.js.map +1 -0
- package/dist/reserved-roles.d.ts +157 -4
- package/dist/reserved-roles.d.ts.map +1 -1
- package/dist/reserved-roles.js +216 -2
- package/dist/reserved-roles.js.map +1 -1
- package/dist/schedule-state.d.ts +5 -0
- package/dist/schedule-state.d.ts.map +1 -1
- package/dist/scope-host.d.ts +260 -15
- package/dist/scope-host.d.ts.map +1 -1
- package/dist/scope-host.js +53 -2
- package/dist/scope-host.js.map +1 -1
- package/dist/scope-lifecycle.d.ts +7 -0
- package/dist/scope-lifecycle.d.ts.map +1 -1
- package/dist/scope-lifecycle.js +7 -0
- package/dist/scope-lifecycle.js.map +1 -1
- package/dist/scope-record.d.ts +16 -5
- package/dist/scope-record.d.ts.map +1 -1
- package/dist/scope-record.js +72 -7
- package/dist/scope-record.js.map +1 -1
- package/dist/spine-restore.d.ts +7 -3
- package/dist/spine-restore.d.ts.map +1 -1
- package/dist/spine-restore.js +14 -3
- package/dist/spine-restore.js.map +1 -1
- package/dist/storage-gauge.d.ts +47 -13
- package/dist/storage-gauge.d.ts.map +1 -1
- package/dist/storage-gauge.js +84 -27
- package/dist/storage-gauge.js.map +1 -1
- package/dist/subject-redaction.d.ts +9 -3
- package/dist/subject-redaction.d.ts.map +1 -1
- package/dist/subject-redaction.js +24 -12
- package/dist/subject-redaction.js.map +1 -1
- package/dist/vertical-owners.d.ts +69 -0
- package/dist/vertical-owners.d.ts.map +1 -0
- package/dist/vertical-owners.js +108 -0
- package/dist/vertical-owners.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How long a streamed response body may go without a byte before it errors. 30 s, the default
|
|
3
|
+
* `timeoutMs` of a connector call: a provider that has been silent for as long as a whole call
|
|
4
|
+
* may take has stalled, and a slower link than that is still delivering within it. The window
|
|
5
|
+
* runs only while the stream waits on the provider: a consumer that is slow to take the next
|
|
6
|
+
* chunk (a store writing the last one) does not spend it.
|
|
7
|
+
*/
|
|
8
|
+
export const STREAM_IDLE_TIMEOUT_MS = 30_000;
|
|
9
|
+
/**
|
|
10
|
+
* The most a streamed body may take from its first read to its end, however steadily it flows:
|
|
11
|
+
* 10 minutes. Finite because a hosted run lives under the platform's wall limits and a trickle
|
|
12
|
+
* that never stops would otherwise hold a connection (and a run) for ever; generous because the
|
|
13
|
+
* idle window, not this, is what cuts a stalled transfer. At the 10 minutes a steady 1 MB/s
|
|
14
|
+
* link still moves about 600 MB.
|
|
15
|
+
*/
|
|
16
|
+
export const STREAM_MAX_DURATION_MS = 10 * 60_000;
|
|
17
|
+
/**
|
|
18
|
+
* How many empty chunks in a row a stream may deliver before it is treated as making no progress.
|
|
19
|
+
* Generous: a real source sends a few at most. It is a count, not a time, because a source that
|
|
20
|
+
* answers only with empty chunks answers in microtasks and no timer would ever get to run.
|
|
21
|
+
*/
|
|
22
|
+
const MAX_CONSECUTIVE_EMPTY_READS = 1_000;
|
|
23
|
+
/** The runtime's timers, called bare — workerd throws `Illegal invocation` on `obj.setTimeout(…)`. */
|
|
24
|
+
const RUNTIME_TIMERS = {
|
|
25
|
+
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
26
|
+
clearTimeout: (handle) => clearTimeout(handle),
|
|
27
|
+
};
|
|
28
|
+
/** The error every bound ends in. Neutral: it names neither the provider nor the URL. */
|
|
29
|
+
const timeoutError = (message) => new DOMException(message, 'TimeoutError');
|
|
30
|
+
/** The three reads that buffer the whole body; the call's total deadline covers them. */
|
|
31
|
+
const BUFFERED_READS = new Set(['text', 'json', 'arrayBuffer']);
|
|
32
|
+
/**
|
|
33
|
+
* `fetchImpl`, with `timeoutMs` on the call and an idle window plus an absolute cap on a streamed
|
|
34
|
+
* body (see the module header). The signal it hands the runtime is its own; a `signal` in `init`
|
|
35
|
+
* aborts it, so wrapping a `fetch` that is itself wrapped (a connector's timeout around a host's)
|
|
36
|
+
* lets the outer bound reach the runtime.
|
|
37
|
+
*/
|
|
38
|
+
export function deadlineFetch(fetchImpl, timeoutMs, options = {}) {
|
|
39
|
+
const idleMs = options.idleMs ?? STREAM_IDLE_TIMEOUT_MS;
|
|
40
|
+
const maxStreamMs = options.maxStreamMs ?? STREAM_MAX_DURATION_MS;
|
|
41
|
+
const timers = options.timers ?? RUNTIME_TIMERS;
|
|
42
|
+
return async (input, init) => {
|
|
43
|
+
const controller = new AbortController();
|
|
44
|
+
let timedOut;
|
|
45
|
+
const upstream = init?.signal;
|
|
46
|
+
// The caller's own abort ends the call: its deadline is released, so it cannot fire later and
|
|
47
|
+
// pass a cancel off as a timeout.
|
|
48
|
+
const onUpstreamAbort = () => {
|
|
49
|
+
releaseTotal();
|
|
50
|
+
controller.abort(upstream?.reason);
|
|
51
|
+
};
|
|
52
|
+
if (upstream?.aborted)
|
|
53
|
+
controller.abort(upstream.reason);
|
|
54
|
+
else
|
|
55
|
+
upstream?.addEventListener?.('abort', onUpstreamAbort, { once: true });
|
|
56
|
+
const total = timers.setTimeout(() => {
|
|
57
|
+
timedOut ??= timeoutError('The operation was aborted due to timeout');
|
|
58
|
+
controller.abort(timedOut);
|
|
59
|
+
finish();
|
|
60
|
+
}, timeoutMs);
|
|
61
|
+
// Not held against the process: `AbortSignal.timeout`'s timer was not either.
|
|
62
|
+
unref(total);
|
|
63
|
+
const releaseTotal = () => timers.clearTimeout(total);
|
|
64
|
+
/** The call is over: its deadline and its hold on the caller's signal go. Idempotent. */
|
|
65
|
+
function finish() {
|
|
66
|
+
releaseTotal();
|
|
67
|
+
upstream?.removeEventListener?.('abort', onUpstreamAbort);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* What a failed read reports. A runtime may fail a read the call's deadline aborted with a
|
|
71
|
+
* generic abort rather than the reason; that one is the deadline's `TimeoutError`. Any other
|
|
72
|
+
* failure (a caller's cancel, a network error) keeps its own class.
|
|
73
|
+
*/
|
|
74
|
+
const reported = (err) => timedOut && err?.name === 'AbortError' ? timedOut : err;
|
|
75
|
+
let res;
|
|
76
|
+
try {
|
|
77
|
+
res = await fetchImpl(input, { ...init, signal: controller.signal });
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
finish();
|
|
81
|
+
throw reported(err);
|
|
82
|
+
}
|
|
83
|
+
// A response that has no body at all (`null`, as on a web `Response`) has nothing to bound.
|
|
84
|
+
// A stand-in with no `body` field (`undefined`) may still be read buffered, so it keeps the deadline.
|
|
85
|
+
if (res.body === null)
|
|
86
|
+
finish();
|
|
87
|
+
let guarded;
|
|
88
|
+
return new Proxy(res, {
|
|
89
|
+
get(target, prop) {
|
|
90
|
+
const value = Reflect.get(target, prop, target);
|
|
91
|
+
if (prop === 'body') {
|
|
92
|
+
if (!value)
|
|
93
|
+
return value;
|
|
94
|
+
// Looking at the body takes nothing: the native stream stays unlocked and the call's
|
|
95
|
+
// deadline stays armed until the first read of the stream handed out here.
|
|
96
|
+
guarded ??= guardedBody(value, {
|
|
97
|
+
idleMs,
|
|
98
|
+
maxStreamMs,
|
|
99
|
+
timers,
|
|
100
|
+
releaseTotal,
|
|
101
|
+
finish,
|
|
102
|
+
abortCall: (reason) => controller.abort(reason),
|
|
103
|
+
reported,
|
|
104
|
+
});
|
|
105
|
+
return guarded;
|
|
106
|
+
}
|
|
107
|
+
if (typeof value !== 'function')
|
|
108
|
+
return value;
|
|
109
|
+
// Called on the response itself, never the proxy: a native method refuses any other receiver.
|
|
110
|
+
if (BUFFERED_READS.has(prop)) {
|
|
111
|
+
return async (...args) => {
|
|
112
|
+
try {
|
|
113
|
+
return await value.apply(target, args);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
// A runtime may fail a read the call's deadline aborted with a generic abort.
|
|
117
|
+
throw reported(err);
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
finish();
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return value.bind(target);
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** A timer that does not hold a Node process open, where the runtime lets it say so. */
|
|
130
|
+
function unref(handle) {
|
|
131
|
+
handle?.unref?.();
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* `body`, passed through chunk by chunk. The native reader is taken on the FIRST pull, not here,
|
|
135
|
+
* so a stream that is only looked at, or taken and never read, leaves the native body unlocked
|
|
136
|
+
* and the call's deadline in force. From the first read: the stream errors when the provider is
|
|
137
|
+
* silent for `idleMs` (empty chunks are not bytes and do not reset the window) or when `maxStreamMs`
|
|
138
|
+
* has passed in all. Pull-driven with no queue of its own, so the idle window runs only while a
|
|
139
|
+
* read waits on the provider. Whichever bound ends it cancels the source reader, aborts the call
|
|
140
|
+
* (which releases the connection) and errors the stream: nothing is left reading, nothing buffered.
|
|
141
|
+
*
|
|
142
|
+
* The bounds are TIMERS that end the stream, never promises raced against each read: a promise
|
|
143
|
+
* that outlives a read keeps a reaction for every race it was in, and through it the chunk the
|
|
144
|
+
* race resolved with. Nothing long-lived here holds a chunk once it has been delivered.
|
|
145
|
+
*/
|
|
146
|
+
function guardedBody(body, o) {
|
|
147
|
+
let reader;
|
|
148
|
+
let ctl;
|
|
149
|
+
let capHandle;
|
|
150
|
+
let over = false;
|
|
151
|
+
/** End the stream with `err`, once: error it, let go of the call, cancel the source. */
|
|
152
|
+
const stop = async (err) => {
|
|
153
|
+
if (over)
|
|
154
|
+
return;
|
|
155
|
+
over = true;
|
|
156
|
+
o.timers.clearTimeout(capHandle);
|
|
157
|
+
try {
|
|
158
|
+
ctl?.error(err);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// already closed or errored
|
|
162
|
+
}
|
|
163
|
+
o.abortCall(err);
|
|
164
|
+
o.finish();
|
|
165
|
+
await reader?.cancel(err).catch(() => { });
|
|
166
|
+
try {
|
|
167
|
+
reader?.releaseLock();
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// a read the cancel has not yet settled: the lock goes with the stream
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
/** The first read: the call's deadline hands over to the idle window and the absolute cap. */
|
|
174
|
+
const begin = () => {
|
|
175
|
+
o.releaseTotal();
|
|
176
|
+
capHandle = o.timers.setTimeout(() => void stop(timeoutError('The transfer exceeded its maximum duration')), o.maxStreamMs);
|
|
177
|
+
unref(capHandle);
|
|
178
|
+
return body.getReader();
|
|
179
|
+
};
|
|
180
|
+
return new ReadableStream({
|
|
181
|
+
start(controller) {
|
|
182
|
+
ctl = controller;
|
|
183
|
+
},
|
|
184
|
+
async pull(controller) {
|
|
185
|
+
if (over)
|
|
186
|
+
return;
|
|
187
|
+
let idle;
|
|
188
|
+
let empties = 0;
|
|
189
|
+
try {
|
|
190
|
+
reader ??= begin();
|
|
191
|
+
idle = o.timers.setTimeout(() => void stop(timeoutError(`The response body stalled: no bytes for ${o.idleMs} ms`)), o.idleMs);
|
|
192
|
+
unref(idle);
|
|
193
|
+
for (;;) {
|
|
194
|
+
const { done, value } = await reader.read();
|
|
195
|
+
// A bound (or the consumer) ended the stream while this read waited: it has answered.
|
|
196
|
+
if (over)
|
|
197
|
+
return;
|
|
198
|
+
if (done) {
|
|
199
|
+
over = true;
|
|
200
|
+
o.timers.clearTimeout(capHandle);
|
|
201
|
+
o.finish();
|
|
202
|
+
controller.close();
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (!value)
|
|
206
|
+
throw new Error('the byte stream yielded a read with neither a chunk nor its end');
|
|
207
|
+
// An empty chunk carries nothing: it is read past under the same window, not counted as progress.
|
|
208
|
+
// A source that answers only with empty chunks, all in microtasks, would never let a timer
|
|
209
|
+
// run, so the run of them is itself bounded.
|
|
210
|
+
if (value.byteLength === 0) {
|
|
211
|
+
if (++empties > MAX_CONSECUTIVE_EMPTY_READS) {
|
|
212
|
+
throw timeoutError('The response body made no progress');
|
|
213
|
+
}
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
controller.enqueue(value);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
// A runtime may end a read the call's deadline aborted with a generic abort.
|
|
222
|
+
await stop(o.reported(err));
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
o.timers.clearTimeout(idle);
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
cancel: (reason) => stop(reason),
|
|
229
|
+
}, { highWaterMark: 0 });
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=deadline-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deadline-fetch.js","sourceRoot":"","sources":["../src/deadline-fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The capability record (RFC wire-signing §7, Q8), as statements both adapters run against their
|
|
3
|
+
* directory: one row per deployment, the script an upload went to (a version's archive script or a
|
|
4
|
+
* vertical's serving script), holding what that upload gave it. Every upload of the script replaces
|
|
5
|
+
* its row, so the row is the last upload's: the one the running script was built from. Written once
|
|
6
|
+
* so the two adapters cannot keep different records of the same fleet.
|
|
7
|
+
*
|
|
8
|
+
* The uploader writes it from what it built and injected; a vertical never declares it, since a
|
|
9
|
+
* claim a version makes about itself proves nothing. The readiness report (follow-on 4) reads it.
|
|
10
|
+
* A vertical's rows go with the vertical (`forgetVerticalWireAuth`), so none outlives what it
|
|
11
|
+
* describes.
|
|
12
|
+
*/
|
|
13
|
+
import { type DeploymentWireAuth, type TenantId } from '@substrat-run/contracts';
|
|
14
|
+
import type { SwitchSql } from './system-switch.js';
|
|
15
|
+
export type { DeploymentWireAuthInput } from '@substrat-run/contracts';
|
|
16
|
+
/** Interpolated into both adapters' directory DDL, so the two spell one table. */
|
|
17
|
+
export declare const DEPLOYMENT_WIRE_AUTH_DDL = "\n CREATE TABLE IF NOT EXISTS vertical_wire_auth (\n deployment_ref TEXT PRIMARY KEY,\n vertical_slug TEXT NOT NULL,\n version_id TEXT,\n record TEXT NOT NULL,\n recorded_at TEXT NOT NULL\n );\n CREATE INDEX IF NOT EXISTS vertical_wire_auth_slug ON vertical_wire_auth (vertical_slug);\n";
|
|
18
|
+
/**
|
|
19
|
+
* Whose records a read may return: the verticals one tenant owns now (`verticals.owner_tenant`), or
|
|
20
|
+
* the whole fleet, said in so many words. There is no default, so a reader that forgets to confine
|
|
21
|
+
* itself is refused rather than handed every tenant's deployments: a record names scripts, versions
|
|
22
|
+
* and key ids, and a tenant reads only its own. A record whose vertical no tenant owns, or that the
|
|
23
|
+
* registry does not know, is reached only by the fleet.
|
|
24
|
+
*
|
|
25
|
+
* A tenant reach follows the vertical's current owner: it is resolved at read time, so whoever owns
|
|
26
|
+
* the slug then reads every record the table holds for it, and a tenant that no longer owns it reads
|
|
27
|
+
* none. Apart from a whole-directory restore (`restoreDirectory`), which replaces the owners and the
|
|
28
|
+
* records together from one dump, no host path moves the owner of a registered vertical today: an
|
|
29
|
+
* owner changes by deleting the vertical, which removes its records, and registering the slug again.
|
|
30
|
+
* A record written while no tenant owned the slug is read by the tenant that owns it at read time. Key
|
|
31
|
+
* ids are not secrets.
|
|
32
|
+
*/
|
|
33
|
+
export type DeploymentWireAuthReach = {
|
|
34
|
+
readonly tenantId: TenantId;
|
|
35
|
+
} | {
|
|
36
|
+
readonly fleet: true;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Which records a read returns, one page of them: the keyset convention by script name, `cursor` the
|
|
40
|
+
* last name of the page before. A version's script keeps its record for as long as its vertical
|
|
41
|
+
* exists, so a read is always a page: `limit` is required, at most `LIST_PAGE_MAX`.
|
|
42
|
+
*/
|
|
43
|
+
export interface DeploymentWireAuthFilter {
|
|
44
|
+
readonly reach: DeploymentWireAuthReach;
|
|
45
|
+
readonly verticalSlug?: string;
|
|
46
|
+
readonly limit: number;
|
|
47
|
+
readonly cursor?: string;
|
|
48
|
+
readonly order?: 'asc' | 'desc';
|
|
49
|
+
}
|
|
50
|
+
/** The longest `verticalSlug` or `cursor` a read takes. A script name is far shorter. */
|
|
51
|
+
export declare const WIRE_AUTH_FILTER_TEXT_MAX = 256;
|
|
52
|
+
/**
|
|
53
|
+
* The filter a read is allowed to run, or a `validation_failed` refusal: only the filter's own keys;
|
|
54
|
+
* a reach that is exactly one tenant (a tenant id) or exactly the fleet; a limit from 1 to
|
|
55
|
+
* `LIST_PAGE_MAX`; a vertical and a cursor of 1 to `WIRE_AUTH_FILTER_TEXT_MAX` characters; an order
|
|
56
|
+
* of `asc` or `desc`. Both adapters judge it before the read, and the Cloudflare host before the call
|
|
57
|
+
* into the directory's object, so the refusal keeps its code across the RPC.
|
|
58
|
+
*
|
|
59
|
+
* Answers a NEW object built from the judged fields alone, never the caller's, so nothing else crosses
|
|
60
|
+
* the RPC or reaches the access log. `reach` is its first key: the log keeps a read's params cut to a
|
|
61
|
+
* bounded length, and nothing after the reach can push it out of what is kept.
|
|
62
|
+
*/
|
|
63
|
+
export declare function assertWireAuthFilter(filter: unknown): DeploymentWireAuthFilter;
|
|
64
|
+
/** The access-log target of a read: the tenant a tenant reach names, none for the fleet. */
|
|
65
|
+
export declare function wireAuthAccessTarget(filter: DeploymentWireAuthFilter): {
|
|
66
|
+
tenantId: TenantId | null;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Record an upload's capability for its script, replacing the script's earlier record. Takes the row
|
|
70
|
+
* the adapter parsed (`deploymentWireAuth`) before it reached here: on Cloudflare that parse runs
|
|
71
|
+
* before the call into the directory's object, so a refusal keeps its code across the RPC.
|
|
72
|
+
*/
|
|
73
|
+
export declare function writeDeploymentWireAuth(db: SwitchSql, row: DeploymentWireAuth): void;
|
|
74
|
+
/**
|
|
75
|
+
* One page of the stored records the filter reaches, by script name. The filter is judged here too
|
|
76
|
+
* (`assertWireAuthFilter`), so no caller reaches the table unconfined or unbounded. A row that does
|
|
77
|
+
* not parse throws: it is a corrupt directory, not a fact.
|
|
78
|
+
*/
|
|
79
|
+
export declare function deploymentWireAuthOf(db: SwitchSql, input: DeploymentWireAuthFilter): DeploymentWireAuth[];
|
|
80
|
+
/** Forget a vertical's records, with the vertical. */
|
|
81
|
+
export declare function forgetVerticalWireAuth(db: SwitchSql, verticalSlug: string): void;
|
|
82
|
+
//# sourceMappingURL=deployment-wire-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment-wire-auth.d.ts","sourceRoot":"","sources":["../src/deployment-wire-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAA8D,KAAK,kBAAkB,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAC7I,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,YAAY,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAEvE,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,qUASpC,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,uBAAuB,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CAAE,CAAC;AAEjG;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;IACxC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CACjC;AAID,yFAAyF;AACzF,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAS7C;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,wBAAwB,CA0C9E;AAED,4FAA4F;AAC5F,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,wBAAwB,GAAG;IAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;CAAE,CAEpG;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,kBAAkB,GAAG,IAAI,CAepF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,wBAAwB,GAAG,kBAAkB,EAAE,CAiCzG;AAED,sDAAsD;AACtD,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAEhF"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The capability record (RFC wire-signing §7, Q8), as statements both adapters run against their
|
|
3
|
+
* directory: one row per deployment, the script an upload went to (a version's archive script or a
|
|
4
|
+
* vertical's serving script), holding what that upload gave it. Every upload of the script replaces
|
|
5
|
+
* its row, so the row is the last upload's: the one the running script was built from. Written once
|
|
6
|
+
* so the two adapters cannot keep different records of the same fleet.
|
|
7
|
+
*
|
|
8
|
+
* The uploader writes it from what it built and injected; a vertical never declares it, since a
|
|
9
|
+
* claim a version makes about itself proves nothing. The readiness report (follow-on 4) reads it.
|
|
10
|
+
* A vertical's rows go with the vertical (`forgetVerticalWireAuth`), so none outlives what it
|
|
11
|
+
* describes.
|
|
12
|
+
*/
|
|
13
|
+
import { deploymentWireAuth, LIST_PAGE_MAX, substratError, tenantId } from '@substrat-run/contracts';
|
|
14
|
+
/** Interpolated into both adapters' directory DDL, so the two spell one table. */
|
|
15
|
+
export const DEPLOYMENT_WIRE_AUTH_DDL = `
|
|
16
|
+
CREATE TABLE IF NOT EXISTS vertical_wire_auth (
|
|
17
|
+
deployment_ref TEXT PRIMARY KEY,
|
|
18
|
+
vertical_slug TEXT NOT NULL,
|
|
19
|
+
version_id TEXT,
|
|
20
|
+
record TEXT NOT NULL,
|
|
21
|
+
recorded_at TEXT NOT NULL
|
|
22
|
+
);
|
|
23
|
+
CREATE INDEX IF NOT EXISTS vertical_wire_auth_slug ON vertical_wire_auth (vertical_slug);
|
|
24
|
+
`;
|
|
25
|
+
const refused = (message) => substratError('validation_failed', message);
|
|
26
|
+
/** The longest `verticalSlug` or `cursor` a read takes. A script name is far shorter. */
|
|
27
|
+
export const WIRE_AUTH_FILTER_TEXT_MAX = 256;
|
|
28
|
+
const FILTER_KEYS = new Set(['reach', 'verticalSlug', 'limit', 'cursor', 'order']);
|
|
29
|
+
/** The longest caller-supplied key name a refusal echoes, so its text stays bounded. */
|
|
30
|
+
const ECHOED_KEY_MAX = 64;
|
|
31
|
+
const echoedKey = (key) => (key.length > ECHOED_KEY_MAX ? `${key.slice(0, ECHOED_KEY_MAX)}…` : key);
|
|
32
|
+
const REACH_REFUSAL = 'a capability-record read names its reach: one tenant ({ tenantId }) or the fleet ({ fleet: true }), exactly one';
|
|
33
|
+
/**
|
|
34
|
+
* The filter a read is allowed to run, or a `validation_failed` refusal: only the filter's own keys;
|
|
35
|
+
* a reach that is exactly one tenant (a tenant id) or exactly the fleet; a limit from 1 to
|
|
36
|
+
* `LIST_PAGE_MAX`; a vertical and a cursor of 1 to `WIRE_AUTH_FILTER_TEXT_MAX` characters; an order
|
|
37
|
+
* of `asc` or `desc`. Both adapters judge it before the read, and the Cloudflare host before the call
|
|
38
|
+
* into the directory's object, so the refusal keeps its code across the RPC.
|
|
39
|
+
*
|
|
40
|
+
* Answers a NEW object built from the judged fields alone, never the caller's, so nothing else crosses
|
|
41
|
+
* the RPC or reaches the access log. `reach` is its first key: the log keeps a read's params cut to a
|
|
42
|
+
* bounded length, and nothing after the reach can push it out of what is kept.
|
|
43
|
+
*/
|
|
44
|
+
export function assertWireAuthFilter(filter) {
|
|
45
|
+
if (typeof filter !== 'object' || filter === null || Array.isArray(filter)) {
|
|
46
|
+
throw refused('a capability-record read needs a filter naming its reach and its limit');
|
|
47
|
+
}
|
|
48
|
+
// Own properties only: a field inherited from a prototype, a polluted one included, is not the caller's.
|
|
49
|
+
const own = (o, key) => (Object.hasOwn(o, key) ? o[key] : undefined);
|
|
50
|
+
const extra = Object.keys(filter).filter((key) => !FILTER_KEYS.has(key));
|
|
51
|
+
if (extra.length > 0) {
|
|
52
|
+
throw refused(`a capability-record read takes reach, verticalSlug, limit, cursor and order; not ${extra.slice(0, 3).map(echoedKey).join(', ')}`);
|
|
53
|
+
}
|
|
54
|
+
const r = own(filter, 'reach');
|
|
55
|
+
if (typeof r !== 'object' || r === null || Array.isArray(r))
|
|
56
|
+
throw refused(REACH_REFUSAL);
|
|
57
|
+
const keys = Object.keys(r);
|
|
58
|
+
if (keys.length !== 1)
|
|
59
|
+
throw refused(REACH_REFUSAL);
|
|
60
|
+
const value = own(r, keys[0]);
|
|
61
|
+
let reach;
|
|
62
|
+
if (keys[0] === 'fleet' && value === true)
|
|
63
|
+
reach = { fleet: true };
|
|
64
|
+
else if (keys[0] === 'tenantId' && tenantId.safeParse(value).success)
|
|
65
|
+
reach = { tenantId: tenantId.parse(value) };
|
|
66
|
+
else
|
|
67
|
+
throw refused(REACH_REFUSAL);
|
|
68
|
+
const limit = own(filter, 'limit');
|
|
69
|
+
if (typeof limit !== 'number' || !Number.isInteger(limit) || limit < 1 || limit > LIST_PAGE_MAX) {
|
|
70
|
+
throw refused(`limit must be an integer from 1 to ${LIST_PAGE_MAX}, got ${typeof limit === 'number' ? String(limit) : typeof limit}`);
|
|
71
|
+
}
|
|
72
|
+
const text = (name) => {
|
|
73
|
+
const v = own(filter, name);
|
|
74
|
+
if (v === undefined)
|
|
75
|
+
return undefined;
|
|
76
|
+
if (typeof v !== 'string' || v.length === 0 || v.length > WIRE_AUTH_FILTER_TEXT_MAX) {
|
|
77
|
+
throw refused(`${name} must be a string of 1 to ${WIRE_AUTH_FILTER_TEXT_MAX} characters`);
|
|
78
|
+
}
|
|
79
|
+
return v;
|
|
80
|
+
};
|
|
81
|
+
const verticalSlug = text('verticalSlug');
|
|
82
|
+
const cursor = text('cursor');
|
|
83
|
+
const order = own(filter, 'order');
|
|
84
|
+
if (order !== undefined && order !== 'asc' && order !== 'desc')
|
|
85
|
+
throw refused('order must be asc or desc');
|
|
86
|
+
return {
|
|
87
|
+
reach,
|
|
88
|
+
...(verticalSlug !== undefined ? { verticalSlug } : {}),
|
|
89
|
+
limit,
|
|
90
|
+
...(cursor !== undefined ? { cursor } : {}),
|
|
91
|
+
...(order !== undefined ? { order } : {}),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/** The access-log target of a read: the tenant a tenant reach names, none for the fleet. */
|
|
95
|
+
export function wireAuthAccessTarget(filter) {
|
|
96
|
+
return { tenantId: 'tenantId' in filter.reach ? filter.reach.tenantId : null };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Record an upload's capability for its script, replacing the script's earlier record. Takes the row
|
|
100
|
+
* the adapter parsed (`deploymentWireAuth`) before it reached here: on Cloudflare that parse runs
|
|
101
|
+
* before the call into the directory's object, so a refusal keeps its code across the RPC.
|
|
102
|
+
*/
|
|
103
|
+
export function writeDeploymentWireAuth(db, row) {
|
|
104
|
+
db.run(`INSERT INTO vertical_wire_auth (deployment_ref, vertical_slug, version_id, record, recorded_at)
|
|
105
|
+
VALUES (?, ?, ?, ?, ?)
|
|
106
|
+
ON CONFLICT (deployment_ref) DO UPDATE SET
|
|
107
|
+
vertical_slug = excluded.vertical_slug,
|
|
108
|
+
version_id = excluded.version_id,
|
|
109
|
+
record = excluded.record,
|
|
110
|
+
recorded_at = excluded.recorded_at`, row.deploymentRef, row.verticalSlug, row.versionId, JSON.stringify(row.record), row.recordedAt);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* One page of the stored records the filter reaches, by script name. The filter is judged here too
|
|
114
|
+
* (`assertWireAuthFilter`), so no caller reaches the table unconfined or unbounded. A row that does
|
|
115
|
+
* not parse throws: it is a corrupt directory, not a fact.
|
|
116
|
+
*/
|
|
117
|
+
export function deploymentWireAuthOf(db, input) {
|
|
118
|
+
const filter = assertWireAuthFilter(input);
|
|
119
|
+
const desc = filter.order === 'desc';
|
|
120
|
+
const where = [];
|
|
121
|
+
const params = [];
|
|
122
|
+
if ('tenantId' in filter.reach) {
|
|
123
|
+
where.push('vertical_slug IN (SELECT slug FROM verticals WHERE owner_tenant = ?)');
|
|
124
|
+
params.push(filter.reach.tenantId);
|
|
125
|
+
}
|
|
126
|
+
if (filter.verticalSlug !== undefined) {
|
|
127
|
+
where.push('vertical_slug = ?');
|
|
128
|
+
params.push(filter.verticalSlug);
|
|
129
|
+
}
|
|
130
|
+
if (filter.cursor) {
|
|
131
|
+
where.push(desc ? 'deployment_ref < ?' : 'deployment_ref > ?');
|
|
132
|
+
params.push(filter.cursor);
|
|
133
|
+
}
|
|
134
|
+
params.push(filter.limit);
|
|
135
|
+
const rows = db.all('SELECT deployment_ref, vertical_slug, version_id, record, recorded_at FROM vertical_wire_auth' +
|
|
136
|
+
(where.length ? ` WHERE ${where.join(' AND ')}` : '') +
|
|
137
|
+
` ORDER BY deployment_ref ${desc ? 'DESC' : 'ASC'} LIMIT ?`, ...params);
|
|
138
|
+
return rows.map((r) => deploymentWireAuth.parse({
|
|
139
|
+
deploymentRef: r['deployment_ref'],
|
|
140
|
+
verticalSlug: r['vertical_slug'],
|
|
141
|
+
versionId: r['version_id'],
|
|
142
|
+
record: JSON.parse(String(r['record'])),
|
|
143
|
+
recordedAt: r['recorded_at'],
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
/** Forget a vertical's records, with the vertical. */
|
|
147
|
+
export function forgetVerticalWireAuth(db, verticalSlug) {
|
|
148
|
+
db.run('DELETE FROM vertical_wire_auth WHERE vertical_slug = ?', verticalSlug);
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=deployment-wire-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment-wire-auth.js","sourceRoot":"","sources":["../src/deployment-wire-auth.ts"],"names":[],"mappings":"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"}
|
package/dist/entity-trash.d.ts
CHANGED
|
@@ -24,7 +24,15 @@ import { type EntityRef, type EntityStateDeclaration, type OperationTarget, type
|
|
|
24
24
|
import { type EntityStatePlan, type StateCheck } from './entity-state.js';
|
|
25
25
|
import type { ScopedSql } from './scope-host.js';
|
|
26
26
|
import type { SystemScheduleState } from './system-switch.js';
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* How many entities one purge pass deletes per entity type. A full batch leaves the schedule due.
|
|
29
|
+
*
|
|
30
|
+
* A CEILING, not a promise: a purge that enqueues a platform request is held to the scope's
|
|
31
|
+
* `MAX_PENDING_PLATFORM_REQUESTS` as well, which is smaller. The two are not reconciled by a
|
|
32
|
+
* second number — the cap is the one authority and decides how many such purges a pass commits.
|
|
33
|
+
* Past the head of its pass, a pass that meets the cap's refusal stops there; at the head the
|
|
34
|
+
* refusal is a failure like any other (`runPurgePass`, #2506).
|
|
35
|
+
*/
|
|
28
36
|
export declare const PURGE_BATCH = 50;
|
|
29
37
|
/**
|
|
30
38
|
* Is `entity` out of reach as a parent (#119): its type declares trash, and it is in the trash or
|
|
@@ -104,9 +112,11 @@ export declare function purgeCandidates(sql: ScopedSql, plan: EntityStatePlan, c
|
|
|
104
112
|
/**
|
|
105
113
|
* A purge LAP in progress (#2096) — what a schedule's cadence row holds in `purge_cursor` between
|
|
106
114
|
* passes. A lap walks the whole due bin, oldest first, `PURGE_BATCH` at a time; each pass resumes
|
|
107
|
-
* after the last entity the one before it tried, whatever became of that entity
|
|
115
|
+
* after the last entity the one before it tried, whatever became of that entity — except one the
|
|
116
|
+
* scope's platform-request cap turned away past the head of its pass (#2506), which was not tried
|
|
117
|
+
* in any sense that matters: it rolled back whole, and the next pass starts at it. So entities that
|
|
108
118
|
* keep failing cannot hold the head of the walk: the walk moves past them, reaches everything due
|
|
109
|
-
* behind them in the same lap, and tries them again in the next.
|
|
119
|
+
* behind them in the same lap, and tries them again in the next. A refused head is one of them.
|
|
110
120
|
*
|
|
111
121
|
* `failed` counts the purges that failed in the lap's earlier passes, so the pass that closes the
|
|
112
122
|
* lap — the one that writes the cadence row — records the lap `failed` even when its own batch
|
|
@@ -132,6 +142,12 @@ export interface PurgeDue {
|
|
|
132
142
|
readonly idFrom: string;
|
|
133
143
|
/** The ids this pass tries, in the walk's order. */
|
|
134
144
|
readonly ids: string[];
|
|
145
|
+
/**
|
|
146
|
+
* #2506: the walk position of each of `ids`, in the same order — what lets a pass that stops
|
|
147
|
+
* part-way resume after the last entity it actually tried. Absent from a hand-built `PurgeDue`,
|
|
148
|
+
* which a pass then cannot cut short (see `runPurgePass`).
|
|
149
|
+
*/
|
|
150
|
+
readonly keys?: readonly PurgeKey[];
|
|
135
151
|
/** The lap as this pass found it. */
|
|
136
152
|
readonly lap: PurgeLap;
|
|
137
153
|
/** Where the next pass resumes when more is due after these ids — or null: this pass closes the lap. */
|
|
@@ -190,8 +206,21 @@ export interface PurgePass {
|
|
|
190
206
|
* Absent, like `more`, from a scope running code older than the lap, which ran no lap.
|
|
191
207
|
*/
|
|
192
208
|
lapFailed?: number;
|
|
209
|
+
/**
|
|
210
|
+
* #2517: the cap refused the head because the purge passes before this one in the same tick filled
|
|
211
|
+
* the queue (`runPurgePass`), so the pass tried nothing and waits for the next tick. A host reports
|
|
212
|
+
* the run `skipped` and counts it in `ScheduleRunReport.deferred`, never `fired`. Absent otherwise,
|
|
213
|
+
* and from a scope running code older than the field, which fails such a head instead.
|
|
214
|
+
*/
|
|
215
|
+
deferred?: true;
|
|
193
216
|
/** Why the scope ran no purge at all this pass (`purgeHeldBy`), when its gate held it. */
|
|
194
217
|
held?: string;
|
|
218
|
+
/**
|
|
219
|
+
* #2440: platform requests the purges that committed enqueued, when a scope that runs the purges
|
|
220
|
+
* out of the caller's sight reports them (the Durable Object does; the SQLite host counts through
|
|
221
|
+
* the stub it invokes with). Absent means none, or a scope running code older than this field.
|
|
222
|
+
*/
|
|
223
|
+
platformRequests?: number;
|
|
195
224
|
}
|
|
196
225
|
/** A pass the scope's gate held: nothing selected, nothing tried, the lap where it was. */
|
|
197
226
|
export declare function heldPurgePass(held: string): PurgePass;
|
|
@@ -206,15 +235,43 @@ export declare function heldPurgePass(held: string): PurgePass;
|
|
|
206
235
|
* batch with its failures added while more is due, or close the lap. After the pass, so a pass cut
|
|
207
236
|
* short repeats its batch rather than skipping it. `inScope` runs the write against the scope's
|
|
208
237
|
* spine, in the turn the adapter's storage needs.
|
|
238
|
+
*
|
|
239
|
+
* The one exception to "whatever its purges did" is the scope's platform-request cap (#2506): a
|
|
240
|
+
* purge the cap refuses (`isPlatformRequestRefusal`) AFTER the pass has got past its head is
|
|
241
|
+
* deferred rather than failed, and the lap resumes at it. A pass always moves the lap strictly
|
|
242
|
+
* forward, so neither a deferral nor a refused head can hold the head of the walk.
|
|
243
|
+
*
|
|
244
|
+
* One more case (#2517): a head the cap refuses is deferred, not failed, when
|
|
245
|
+
* `earlierPurgeRequests` says that the PURGE passes run before this one in the same scheduled tick
|
|
246
|
+
* (this module's or an earlier module's) enqueued requests. Nothing drains the scope between the
|
|
247
|
+
* schedules of a tick, so that head met a queue the tick's own purges filled, and failing it would
|
|
248
|
+
* make the run wait its whole cadence for nothing. The pass then ends having tried nothing
|
|
249
|
+
* (`deferred`): the lap is left exactly as it was, `more` is true so the schedule stays due, and
|
|
250
|
+
* the next tick tries the same head again.
|
|
251
|
+
*
|
|
252
|
+
* Only purge passes count, never an ordinary schedule's requests or any other traffic, because
|
|
253
|
+
* that is what bounds the deferral. Each tick that defers this head needs a purge ahead of it to
|
|
254
|
+
* have COMMITTED a purge that enqueued a request, and that entity has left its bin for good; an
|
|
255
|
+
* ordinary schedule can enqueue every tick forever, which would hold the head, and everything
|
|
256
|
+
* behind it, for ever (#2096). So the head is deferred only while the purges ahead of it keep
|
|
257
|
+
* committing requests, and on the first tick none does (their laps closed, their cadence not due,
|
|
258
|
+
* or the queue still full so they could enqueue nothing) it runs like any head: it purges if it
|
|
259
|
+
* fits, and a head that cannot fit, or a queue other traffic holds full, fails it as before. It
|
|
260
|
+
* cannot spin: the scheduled tick runs each schedule once.
|
|
209
261
|
*/
|
|
210
|
-
export declare function runPurgePass(operation: string, due: PurgeDue, purgeOne: (entityId: string) => Promise<void>, inScope: (write: (sql: ScopedSql) => void) => unknown): Promise<PurgePass>;
|
|
262
|
+
export declare function runPurgePass(operation: string, due: PurgeDue, purgeOne: (entityId: string) => Promise<void>, inScope: (write: (sql: ScopedSql) => void) => unknown, earlierPurgeRequests?: number): Promise<PurgePass>;
|
|
211
263
|
/**
|
|
212
264
|
* Whether a purge pass leaves its schedule due, so the next sweep pass continues its lap rather
|
|
213
265
|
* than waiting the cadence: more is due after its batch (#2096). It cannot spin (#2087): every pass
|
|
214
|
-
* moves the lap strictly forward, whatever its purges did,
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
266
|
+
* moves the lap strictly forward, whatever its purges did, bar one — the pass that defers its head
|
|
267
|
+
* to the next tick because the tick's earlier purge passes filled the queue (#2517), which needs a
|
|
268
|
+
* purge ahead of it to have committed a request (so the tick made progress) and which nothing
|
|
269
|
+
* re-runs within the tick. A pass that defers an entity the platform-request cap turned away (#2506) has
|
|
270
|
+
* already got past its head, and the entity is the head of the next pass, where a refusal is a
|
|
271
|
+
* failure like any other — and the pass that runs out
|
|
272
|
+
* of due entities closes the lap and records the run. So a cadence window holds one lap, and an
|
|
273
|
+
* entity that keeps failing is tried once per window, not once per sweep tick. A scope running
|
|
274
|
+
* code older than the lap answers no `more`, and its pass waits its cadence.
|
|
218
275
|
*/
|
|
219
276
|
export declare function purgeStillDue(pass: PurgePass): boolean;
|
|
220
277
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-trash.d.ts","sourceRoot":"","sources":["../src/entity-trash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAML,KAAK,SAAS,EACd,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACpB,KAAK,YAAY,EAClB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"entity-trash.d.ts","sourceRoot":"","sources":["../src/entity-trash.ts"],"names":[],"mappings":"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"}
|