@ketvietlab/ketjs 0.1.2 → 0.1.3
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/LICENSE +1 -1
- package/README.md +8 -2
- package/dist/agent/capabilities.d.ts +1 -3
- package/dist/agent/capabilities.d.ts.map +1 -1
- package/dist/agent/capabilities.js +10 -1
- package/dist/agent/capabilities.js.map +1 -1
- package/dist/agent/permissions.d.ts +43 -1
- package/dist/agent/permissions.d.ts.map +1 -1
- package/dist/agent/permissions.js +50 -2
- package/dist/agent/permissions.js.map +1 -1
- package/dist/cli.js +246 -97
- package/dist/cli.js.map +1 -1
- package/dist/codegen/dts.d.ts.map +1 -1
- package/dist/codegen/dts.js +1 -0
- package/dist/codegen/dts.js.map +1 -1
- package/dist/data/changeset.d.ts +12 -0
- package/dist/data/changeset.d.ts.map +1 -1
- package/dist/data/changeset.js +73 -17
- package/dist/data/changeset.js.map +1 -1
- package/dist/data/expr.d.ts +16 -0
- package/dist/data/expr.d.ts.map +1 -1
- package/dist/data/expr.js +33 -5
- package/dist/data/expr.js.map +1 -1
- package/dist/data/fleet.d.ts +41 -1
- package/dist/data/fleet.d.ts.map +1 -1
- package/dist/data/fleet.js +100 -11
- package/dist/data/fleet.js.map +1 -1
- package/dist/data/migrate.d.ts +20 -0
- package/dist/data/migrate.d.ts.map +1 -1
- package/dist/data/migrate.js +86 -3
- package/dist/data/migrate.js.map +1 -1
- package/dist/data/physical.d.ts +5 -0
- package/dist/data/physical.d.ts.map +1 -0
- package/dist/data/physical.js +196 -0
- package/dist/data/physical.js.map +1 -0
- package/dist/data/pool.d.ts +2 -1
- package/dist/data/pool.d.ts.map +1 -1
- package/dist/data/pool.js +159 -31
- package/dist/data/pool.js.map +1 -1
- package/dist/data/query.d.ts +10 -1
- package/dist/data/query.d.ts.map +1 -1
- package/dist/data/query.js +136 -27
- package/dist/data/query.js.map +1 -1
- package/dist/data/sqlite.d.ts.map +1 -1
- package/dist/data/sqlite.js +350 -52
- package/dist/data/sqlite.js.map +1 -1
- package/dist/data/time.d.ts +13 -0
- package/dist/data/time.d.ts.map +1 -1
- package/dist/data/time.js +61 -17
- package/dist/data/time.js.map +1 -1
- package/dist/index.d.ts +43 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -16
- package/dist/index.js.map +1 -1
- package/dist/kernel/audit.d.ts +27 -0
- package/dist/kernel/audit.d.ts.map +1 -0
- package/dist/kernel/audit.js +67 -0
- package/dist/kernel/audit.js.map +1 -0
- package/dist/kernel/classification.d.ts +26 -0
- package/dist/kernel/classification.d.ts.map +1 -0
- package/dist/kernel/classification.js +73 -0
- package/dist/kernel/classification.js.map +1 -0
- package/dist/kernel/compose.d.ts +6 -2
- package/dist/kernel/compose.d.ts.map +1 -1
- package/dist/kernel/compose.js +269 -15
- package/dist/kernel/compose.js.map +1 -1
- package/dist/kernel/define.d.ts +2 -3
- package/dist/kernel/define.d.ts.map +1 -1
- package/dist/kernel/define.js +22 -12
- package/dist/kernel/define.js.map +1 -1
- package/dist/kernel/diff.d.ts.map +1 -1
- package/dist/kernel/diff.js +28 -4
- package/dist/kernel/diff.js.map +1 -1
- package/dist/kernel/graph.js +1 -1
- package/dist/kernel/graph.js.map +1 -1
- package/dist/kernel/i18n.d.ts +10 -1
- package/dist/kernel/i18n.d.ts.map +1 -1
- package/dist/kernel/i18n.js +34 -1
- package/dist/kernel/i18n.js.map +1 -1
- package/dist/kernel/layout.d.ts +97 -0
- package/dist/kernel/layout.d.ts.map +1 -1
- package/dist/kernel/layout.js +294 -12
- package/dist/kernel/layout.js.map +1 -1
- package/dist/kernel/menu.d.ts +33 -2
- package/dist/kernel/menu.d.ts.map +1 -1
- package/dist/kernel/menu.js +99 -7
- package/dist/kernel/menu.js.map +1 -1
- package/dist/kernel/modules.d.ts +3 -3
- package/dist/kernel/modules.d.ts.map +1 -1
- package/dist/kernel/modules.js +21 -21
- package/dist/kernel/modules.js.map +1 -1
- package/dist/kernel/permissions.d.ts +10 -0
- package/dist/kernel/permissions.d.ts.map +1 -0
- package/dist/kernel/permissions.js +365 -0
- package/dist/kernel/permissions.js.map +1 -0
- package/dist/kernel/schedule.d.ts +23 -0
- package/dist/kernel/schedule.d.ts.map +1 -0
- package/dist/kernel/schedule.js +83 -0
- package/dist/kernel/schedule.js.map +1 -0
- package/dist/kernel/types.d.ts.map +1 -1
- package/dist/kernel/types.js +5 -4
- package/dist/kernel/types.js.map +1 -1
- package/dist/kernel/workspace.d.ts +92 -14
- package/dist/kernel/workspace.d.ts.map +1 -1
- package/dist/kernel/workspace.js +128 -49
- package/dist/kernel/workspace.js.map +1 -1
- package/dist/pdf/assets/Inter-Bold.ttf +0 -0
- package/dist/pdf/assets/Inter-Regular.ttf +0 -0
- package/dist/pdf/assets/Inter-SemiBold.ttf +0 -0
- package/dist/pdf/assets/LICENSE.txt +92 -0
- package/dist/pdf/font.d.ts +10 -0
- package/dist/pdf/font.d.ts.map +1 -0
- package/dist/pdf/font.js +83 -0
- package/dist/pdf/font.js.map +1 -0
- package/dist/pdf/image.d.ts +8 -0
- package/dist/pdf/image.d.ts.map +1 -0
- package/dist/pdf/image.js +94 -0
- package/dist/pdf/image.js.map +1 -0
- package/dist/pdf/index.d.ts +15 -0
- package/dist/pdf/index.d.ts.map +1 -0
- package/dist/pdf/index.js +17 -0
- package/dist/pdf/index.js.map +1 -0
- package/dist/pdf/markup.d.ts +19 -0
- package/dist/pdf/markup.d.ts.map +1 -0
- package/dist/pdf/markup.js +146 -0
- package/dist/pdf/markup.js.map +1 -0
- package/dist/pdf/render.d.ts +14 -0
- package/dist/pdf/render.d.ts.map +1 -0
- package/dist/pdf/render.js +387 -0
- package/dist/pdf/render.js.map +1 -0
- package/dist/scaffold/index.js +6 -6
- package/dist/scaffold/index.js.map +1 -1
- package/dist/scaffold/templates/{app.test.ts.tmpl → deployment.test.ts.tmpl} +3 -3
- package/dist/scaffold/templates/ket.workspace.ts.tmpl +4 -6
- package/dist/scaffold/templates/module.ts.tmpl +1 -4
- package/dist/server/assets.d.ts +23 -0
- package/dist/server/assets.d.ts.map +1 -0
- package/dist/server/assets.js +97 -0
- package/dist/server/assets.js.map +1 -0
- package/dist/server/boot.d.ts +157 -38
- package/dist/server/boot.d.ts.map +1 -1
- package/dist/server/boot.js +360 -138
- package/dist/server/boot.js.map +1 -1
- package/dist/server/config.d.ts +30 -10
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/config.js +73 -17
- package/dist/server/config.js.map +1 -1
- package/dist/server/ctx.d.ts +10 -0
- package/dist/server/ctx.d.ts.map +1 -1
- package/dist/server/ctx.js +266 -48
- package/dist/server/ctx.js.map +1 -1
- package/dist/server/development.d.ts +10 -0
- package/dist/server/development.d.ts.map +1 -0
- package/dist/server/development.js +15 -0
- package/dist/server/development.js.map +1 -0
- package/dist/server/fn.d.ts +22 -3
- package/dist/server/fn.d.ts.map +1 -1
- package/dist/server/fn.js +116 -32
- package/dist/server/fn.js.map +1 -1
- package/dist/server/form.d.ts +33 -0
- package/dist/server/form.d.ts.map +1 -0
- package/dist/server/form.js +47 -0
- package/dist/server/form.js.map +1 -0
- package/dist/server/http.d.ts +55 -3
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +306 -22
- package/dist/server/http.js.map +1 -1
- package/dist/server/idem.d.ts +3 -2
- package/dist/server/idem.d.ts.map +1 -1
- package/dist/server/idem.js +12 -4
- package/dist/server/idem.js.map +1 -1
- package/dist/server/jobs.js +1 -1
- package/dist/server/jobs.js.map +1 -1
- package/dist/server/log/combinators.d.ts +42 -0
- package/dist/server/log/combinators.d.ts.map +1 -0
- package/dist/server/log/combinators.js +270 -0
- package/dist/server/log/combinators.js.map +1 -0
- package/dist/server/log/console.d.ts +12 -0
- package/dist/server/log/console.d.ts.map +1 -0
- package/dist/server/log/console.js +96 -0
- package/dist/server/log/console.js.map +1 -0
- package/dist/server/log/file.d.ts +11 -0
- package/dist/server/log/file.d.ts.map +1 -0
- package/dist/server/log/file.js +61 -0
- package/dist/server/log/file.js.map +1 -0
- package/dist/server/log/index.d.ts +23 -0
- package/dist/server/log/index.d.ts.map +1 -0
- package/dist/server/log/index.js +45 -0
- package/dist/server/log/index.js.map +1 -0
- package/dist/server/log/logger.d.ts +53 -0
- package/dist/server/log/logger.d.ts.map +1 -0
- package/dist/server/log/logger.js +94 -0
- package/dist/server/log/logger.js.map +1 -0
- package/dist/server/log/memory.d.ts +11 -0
- package/dist/server/log/memory.d.ts.map +1 -0
- package/dist/server/log/memory.js +25 -0
- package/dist/server/log/memory.js.map +1 -0
- package/dist/server/log/types.d.ts +112 -0
- package/dist/server/log/types.d.ts.map +1 -0
- package/dist/server/log/types.js +58 -0
- package/dist/server/log/types.js.map +1 -0
- package/dist/server/policy.d.ts +29 -0
- package/dist/server/policy.d.ts.map +1 -0
- package/dist/server/policy.js +29 -0
- package/dist/server/policy.js.map +1 -0
- package/dist/server/queue.d.ts +1 -1
- package/dist/server/queue.d.ts.map +1 -1
- package/dist/server/queue.js.map +1 -1
- package/dist/server/ratelimit.d.ts +48 -0
- package/dist/server/ratelimit.d.ts.map +1 -0
- package/dist/server/ratelimit.js +102 -0
- package/dist/server/ratelimit.js.map +1 -0
- package/dist/server/respond.d.ts.map +1 -1
- package/dist/server/respond.js +16 -1
- package/dist/server/respond.js.map +1 -1
- package/dist/server/runtime.d.ts +18 -3
- package/dist/server/runtime.d.ts.map +1 -1
- package/dist/server/runtime.js +32 -2
- package/dist/server/runtime.js.map +1 -1
- package/dist/server/schedule.d.ts +18 -0
- package/dist/server/schedule.d.ts.map +1 -0
- package/dist/server/schedule.js +70 -0
- package/dist/server/schedule.js.map +1 -0
- package/dist/server/sequence.d.ts +42 -0
- package/dist/server/sequence.d.ts.map +1 -0
- package/dist/server/sequence.js +97 -0
- package/dist/server/sequence.js.map +1 -0
- package/dist/server/session.d.ts +21 -0
- package/dist/server/session.d.ts.map +1 -1
- package/dist/server/session.js +84 -10
- package/dist/server/session.js.map +1 -1
- package/dist/server/sessionstore.d.ts +3 -1
- package/dist/server/sessionstore.d.ts.map +1 -1
- package/dist/server/sessionstore.js +7 -3
- package/dist/server/sessionstore.js.map +1 -1
- package/dist/server/storage/index.d.ts +1 -1
- package/dist/server/storage/index.d.ts.map +1 -1
- package/dist/server/storage/index.js +61 -1
- package/dist/server/storage/index.js.map +1 -1
- package/dist/server/storage/types.d.ts +8 -0
- package/dist/server/storage/types.d.ts.map +1 -1
- package/dist/server/storage/types.js +58 -0
- package/dist/server/storage/types.js.map +1 -1
- package/dist/server/tenants.d.ts +20 -18
- package/dist/server/tenants.d.ts.map +1 -1
- package/dist/server/tenants.js +133 -84
- package/dist/server/tenants.js.map +1 -1
- package/dist/server/transport/types.js +2 -2
- package/dist/server/transport/types.js.map +1 -1
- package/dist/server/worker.d.ts +19 -3
- package/dist/server/worker.d.ts.map +1 -1
- package/dist/server/worker.js +168 -21
- package/dist/server/worker.js.map +1 -1
- package/dist/testing.d.ts +26 -10
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +41 -14
- package/dist/testing.js.map +1 -1
- package/dist/theme/contracts.d.ts +14 -1
- package/dist/theme/contracts.d.ts.map +1 -1
- package/dist/theme/contracts.js +35 -6
- package/dist/theme/contracts.js.map +1 -1
- package/dist/theme/index.d.ts +1 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +1 -1
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/joint-runtime.d.ts +33 -0
- package/dist/theme/joint-runtime.d.ts.map +1 -0
- package/dist/theme/joint-runtime.js +121 -0
- package/dist/theme/joint-runtime.js.map +1 -0
- package/dist/theme/joints.d.ts.map +1 -1
- package/dist/theme/joints.js +15 -97
- package/dist/theme/joints.js.map +1 -1
- package/dist/theme/ktl/compile.d.ts +4 -0
- package/dist/theme/ktl/compile.d.ts.map +1 -1
- package/dist/theme/ktl/compile.js +54 -1
- package/dist/theme/ktl/compile.js.map +1 -1
- package/dist/theme/ktl/parser.d.ts +4 -0
- package/dist/theme/ktl/parser.d.ts.map +1 -1
- package/dist/theme/ktl/parser.js +8 -0
- package/dist/theme/ktl/parser.js.map +1 -1
- package/dist/theme/render.d.ts +8 -0
- package/dist/theme/render.d.ts.map +1 -1
- package/dist/theme/render.js +88 -118
- package/dist/theme/render.js.map +1 -1
- package/dist/theme/tokens.d.ts +6 -0
- package/dist/theme/tokens.d.ts.map +1 -1
- package/dist/theme/tokens.js +6 -0
- package/dist/theme/tokens.js.map +1 -1
- package/dist/theme/viewmodel.d.ts +24 -0
- package/dist/theme/viewmodel.d.ts.map +1 -1
- package/dist/theme/viewmodel.js +75 -6
- package/dist/theme/viewmodel.js.map +1 -1
- package/dist/types.d.ts +304 -56
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -2
- package/dist/kernel/apps.d.ts +0 -43
- package/dist/kernel/apps.d.ts.map +0 -1
- package/dist/kernel/apps.js +0 -234
- package/dist/kernel/apps.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ratelimit.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/ratelimit.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAkB1C;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,OAAO,CAAA;IACX,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAA;IACjB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAKD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,UAAU,EAClB,CAAC,GAAE;IAAE,GAAG,CAAC,EAAE,IAAI,CAAA;CAAO,GACrB,OAAO,CAAC,WAAW,CAAC,CAoDtB;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,CAAC,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,CAAA;CAAO,GAC3C,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ9B"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// A durable ceiling on how often something may be done.
|
|
2
|
+
//
|
|
3
|
+
// Durable, because the alternative is a Map in one process: two replicas then
|
|
4
|
+
// enforce two independent limits and the ceiling is whatever the load balancer
|
|
5
|
+
// decides. The state lives in the tenant's own database for the same reason every
|
|
6
|
+
// other piece of framework state does — a tenant's limits are that tenant's.
|
|
7
|
+
//
|
|
8
|
+
// What this is not: protection from volume. Every check costs a database round
|
|
9
|
+
// trip, so pointing it at all traffic makes an attacker's job easier rather than
|
|
10
|
+
// harder. It exists to bound what one identified caller may repeat — sign-in
|
|
11
|
+
// attempts, token refreshes, an expensive report — and a volumetric flood belongs
|
|
12
|
+
// to whatever sits in front of the process.
|
|
13
|
+
//
|
|
14
|
+
// Fixed window rather than a token bucket, because `limit per windowMs` is what a
|
|
15
|
+
// person means and a bucket quietly changes it. The cost is stated: a caller can
|
|
16
|
+
// spend a full allowance at the end of one window and another at the start of the
|
|
17
|
+
// next, so the real worst case across a boundary is twice the limit.
|
|
18
|
+
import { createHash } from 'node:crypto';
|
|
19
|
+
const DDL = `
|
|
20
|
+
CREATE TABLE IF NOT EXISTS ket_rate (
|
|
21
|
+
id TEXT PRIMARY KEY,
|
|
22
|
+
action TEXT NOT NULL,
|
|
23
|
+
window_start TEXT NOT NULL,
|
|
24
|
+
count INTEGER NOT NULL
|
|
25
|
+
)`;
|
|
26
|
+
const prepared = new WeakSet();
|
|
27
|
+
async function prepare(adapter) {
|
|
28
|
+
if (prepared.has(adapter))
|
|
29
|
+
return;
|
|
30
|
+
await adapter.run(DDL, []);
|
|
31
|
+
prepared.add(adapter);
|
|
32
|
+
}
|
|
33
|
+
const idOf = (action, key) => createHash('sha256').update(`ketrate\n${action}\n${key}`).digest('hex').slice(0, 32);
|
|
34
|
+
/**
|
|
35
|
+
* Spend one slot, or refuse.
|
|
36
|
+
*
|
|
37
|
+
* The read-then-compare-and-set is retried because losing the race is the normal
|
|
38
|
+
* case under exactly the load this exists for: every replica checking the same
|
|
39
|
+
* counter at once is not a fault, it is Tuesday. Running out of attempts refuses
|
|
40
|
+
* rather than allows — under contention the safe answer is the closed one.
|
|
41
|
+
*/
|
|
42
|
+
export async function claimRateSlot(adapter, policy, o = {}) {
|
|
43
|
+
const limit = Math.max(1, Math.floor(policy.limit));
|
|
44
|
+
const windowMs = Math.max(1, Math.floor(policy.windowMs));
|
|
45
|
+
const now = o.now ?? new Date();
|
|
46
|
+
const action = policy.action.slice(0, 120);
|
|
47
|
+
const id = idOf(action, policy.key);
|
|
48
|
+
await prepare(adapter);
|
|
49
|
+
const pg = adapter.name === 'postgres';
|
|
50
|
+
const p = (n) => (pg ? `$${n}` : '?');
|
|
51
|
+
const refused = (startedAt) => ({
|
|
52
|
+
ok: false,
|
|
53
|
+
remaining: 0,
|
|
54
|
+
retryAfterMs: Math.max(1, startedAt + windowMs - now.getTime()),
|
|
55
|
+
});
|
|
56
|
+
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
57
|
+
const rows = await adapter.all(`SELECT window_start, count FROM ket_rate WHERE id = ${p(1)}`, [id]);
|
|
58
|
+
const held = rows[0];
|
|
59
|
+
if (!held) {
|
|
60
|
+
const inserted = await adapter.run(`INSERT INTO ket_rate (id, action, window_start, count) VALUES (${p(1)}, ${p(2)}, ${p(3)}, 1)
|
|
61
|
+
ON CONFLICT DO NOTHING`, [id, action, now.toISOString()]);
|
|
62
|
+
if (inserted.changes > 0)
|
|
63
|
+
return { ok: true, remaining: limit - 1, retryAfterMs: 0 };
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const startedAt = Date.parse(String(held.window_start));
|
|
67
|
+
const count = Number(held.count);
|
|
68
|
+
const inWindow = Number.isFinite(startedAt) && now.getTime() - startedAt < windowMs;
|
|
69
|
+
if (inWindow && count >= limit)
|
|
70
|
+
return refused(startedAt);
|
|
71
|
+
const nextStart = inWindow ? String(held.window_start) : now.toISOString();
|
|
72
|
+
const nextCount = inWindow ? count + 1 : 1;
|
|
73
|
+
const moved = await adapter.run(`UPDATE ket_rate SET window_start = ${p(1)}, count = ${p(2)}
|
|
74
|
+
WHERE id = ${p(3)} AND window_start = ${p(4)} AND count = ${p(5)}`, [nextStart, nextCount, id, String(held.window_start), count]);
|
|
75
|
+
if (moved.changes > 0) {
|
|
76
|
+
return { ok: true, remaining: Math.max(0, limit - nextCount), retryAfterMs: 0 };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Eight lost races means the counter is genuinely hot, which is the situation a
|
|
80
|
+
// limit is for. Refusing is the honest answer; allowing would make contention a
|
|
81
|
+
// way through it. The wait offered is short, though: losing a race is this
|
|
82
|
+
// process's problem, and charging the caller a full window for it would be
|
|
83
|
+
// punishing them for somebody else's traffic.
|
|
84
|
+
return { ok: false, remaining: 0, retryAfterMs: 1_000 };
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Drop counters nobody has touched for a while.
|
|
88
|
+
*
|
|
89
|
+
* A row for an active key is reused rather than added to, so growth comes only
|
|
90
|
+
* from keys never seen again — a one-off address, a deleted account. Left alone
|
|
91
|
+
* that is unbounded, which is why this exists and why the worker calls it.
|
|
92
|
+
*/
|
|
93
|
+
export async function pruneRateSlots(adapter, o = {}) {
|
|
94
|
+
const now = o.now ?? new Date();
|
|
95
|
+
const olderThanMs = Math.max(60_000, o.olderThanMs ?? 24 * 3_600_000);
|
|
96
|
+
await prepare(adapter);
|
|
97
|
+
const pg = adapter.name === 'postgres';
|
|
98
|
+
const cutoff = new Date(now.getTime() - olderThanMs).toISOString();
|
|
99
|
+
const removed = await adapter.run(`DELETE FROM ket_rate WHERE window_start < ${pg ? '$1' : '?'}`, [cutoff]);
|
|
100
|
+
return { removed: removed.changes };
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=ratelimit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ratelimit.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/ratelimit.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"respond.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/respond.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"respond.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/respond.ts"],"names":[],"mappings":"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"}
|
package/dist/server/respond.js
CHANGED
|
@@ -87,6 +87,21 @@ export function raw(body, o = {}) {
|
|
|
87
87
|
export function withHeaders(result, headers) {
|
|
88
88
|
return { ...result, headers: { ...result.headers, ...headers } };
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* The cascade order, declared before the first stylesheet can define a layer.
|
|
92
|
+
*
|
|
93
|
+
* `@layer a, b, c;` is what fixes the order; where the layers are then written no
|
|
94
|
+
* longer matters. Without it the order is first-appearance across whatever
|
|
95
|
+
* stylesheets happened to load, so `ket.theme` could outrank `ket.app` purely
|
|
96
|
+
* because a theme's file came second — and `ket.user`, the layer that is supposed
|
|
97
|
+
* to have the last word, had no guarantee at all. It was documented in three
|
|
98
|
+
* places and emitted in none.
|
|
99
|
+
*/
|
|
100
|
+
// Written out rather than interpolated: a hole would put hydration markers
|
|
101
|
+
// (`<!--k[-->`) inside the stylesheet, and CSS treats `<!--` as a token it then has
|
|
102
|
+
// to recover from — which can swallow the statement it is here to make. The
|
|
103
|
+
// literal is kept honest by a test against LAYER_ORDER_CSS.
|
|
104
|
+
const layerOrder = html `<style>@layer ket.reset, ket.theme, ket.app, ket.user;</style>`;
|
|
90
105
|
/**
|
|
91
106
|
* The document every screen sits in, as markup rather than as a string.
|
|
92
107
|
*
|
|
@@ -94,6 +109,6 @@ export function withHeaders(result, headers) {
|
|
|
94
109
|
* where the old concatenated shell put whatever the query string said.
|
|
95
110
|
*/
|
|
96
111
|
export function document(o) {
|
|
97
|
-
return html `<html lang=${o.lang}><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${when(o.title !== undefined, () => html `<title>${o.title}</title>`)}${o.head ?? ''}</head><body>${o.body}</body></html>`;
|
|
112
|
+
return html `<html lang=${o.lang}><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">${when(o.title !== undefined, () => html `<title>${o.title}</title>`)}${layerOrder}${o.head ?? ''}</head><body>${o.body}</body></html>`;
|
|
98
113
|
}
|
|
99
114
|
//# sourceMappingURL=respond.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"respond.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/respond.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"respond.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/respond.ts"],"names":[],"mappings":"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"}
|
package/dist/server/runtime.d.ts
CHANGED
|
@@ -1,14 +1,29 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LogDriver, LogProcess, Logger, OpenLog } from './log/index.ts';
|
|
2
|
+
import type { DeploymentSpec } from '../kernel/workspace.ts';
|
|
2
3
|
import type { KetModule, Manifest } from '../types.ts';
|
|
3
4
|
import type { RuntimeConfig } from './config.ts';
|
|
4
5
|
export type BootedRuntime = {
|
|
5
|
-
spec:
|
|
6
|
+
spec: DeploymentSpec;
|
|
6
7
|
config: RuntimeConfig;
|
|
7
8
|
modules: KetModule[];
|
|
8
9
|
manifest: Manifest;
|
|
10
|
+
/** The sink, already level-filtered and redacted. Closed last on shutdown. */
|
|
11
|
+
log: LogDriver;
|
|
12
|
+
/** Carries this deployment and process role; narrow it with `child`. */
|
|
13
|
+
logger: Logger;
|
|
9
14
|
};
|
|
10
|
-
export declare function bootRuntime(spec:
|
|
15
|
+
export declare function bootRuntime(spec: DeploymentSpec, options?: {
|
|
11
16
|
env?: Record<string, string | undefined>;
|
|
12
17
|
port?: number;
|
|
18
|
+
/** Which process role this is. A low-cardinality field on every record. */
|
|
19
|
+
role?: LogProcess;
|
|
20
|
+
/**
|
|
21
|
+
* Override the deployment's sink for this process.
|
|
22
|
+
*
|
|
23
|
+
* A host that boots a deployment it did not author — a test harness, an
|
|
24
|
+
* embedding process — can redirect records without editing the spec, the same
|
|
25
|
+
* way it already overrides the port.
|
|
26
|
+
*/
|
|
27
|
+
openLog?: OpenLog;
|
|
13
28
|
}): Promise<BootedRuntime>;
|
|
14
29
|
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/runtime.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAC5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,cAAc,CAAA;IACpB,MAAM,EAAE,aAAa,CAAA;IACrB,OAAO,EAAE,SAAS,EAAE,CAAA;IACpB,QAAQ,EAAE,QAAQ,CAAA;IAClB,8EAA8E;IAC9E,GAAG,EAAE,SAAS,CAAA;IACd,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IACxC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2EAA2E;IAC3E,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CACb,GACL,OAAO,CAAC,aAAa,CAAC,CA+CxB"}
|
package/dist/server/runtime.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// The common process role foundation. HTTP and workers load exactly the same
|
|
2
2
|
// configuration, build artifact, module graph and executable registries; only
|
|
3
3
|
// their outer loops differ.
|
|
4
|
+
import { fingerprintAssets } from './assets.js';
|
|
4
5
|
import { compose } from '../kernel/compose.js';
|
|
5
6
|
import { readConfig } from './config.js';
|
|
6
7
|
import { registerFunctions } from './fn.js';
|
|
7
8
|
import { registerJobs } from './jobs.js';
|
|
9
|
+
import { consoleLog, createLogger, isolatedLog, leveledLog, logFromConfig, redactLog } from './log/index.js';
|
|
8
10
|
export async function bootRuntime(spec, options = {}) {
|
|
9
11
|
const config = readConfig(options.env ?? process.env, {
|
|
10
12
|
sqliteFile: `.ket/${spec.name}.db`,
|
|
@@ -13,13 +15,41 @@ export async function bootRuntime(spec, options = {}) {
|
|
|
13
15
|
});
|
|
14
16
|
if (options.port !== undefined)
|
|
15
17
|
config.port = options.port;
|
|
18
|
+
// Redaction and isolation are applied here rather than left to whoever opened the
|
|
19
|
+
// driver, so a deployment's own sink is held to the same rules as the built-in
|
|
20
|
+
// ones. Isolation sits innermost, against the sink itself: a record is emitted
|
|
21
|
+
// after a function has already committed and after an idempotency key has been
|
|
22
|
+
// marked done, so a throw from a sink would report a failure for work that
|
|
23
|
+
// succeeded. "A sink never breaks the work it describes" has to be structural
|
|
24
|
+
// rather than something every deployment remembers. The level filter is
|
|
25
|
+
// outermost, so a record nobody will keep is never redacted at all.
|
|
26
|
+
const opened = await (options.openLog ?? spec.serve?.openLog ?? logFromConfig)(config);
|
|
27
|
+
const log = leveledLog(redactLog(isolatedLog(opened, consoleLog())), config.logLevel);
|
|
28
|
+
const logger = createLogger(log, { deployment: spec.name, process: options.role ?? 'http' });
|
|
16
29
|
const modules = [...spec.modules, ...(spec.theme ? [spec.theme] : []), ...(spec.themes ?? [])];
|
|
17
30
|
const manifest = compose(modules, {
|
|
18
|
-
|
|
31
|
+
requiredRegions: spec.requires ?? [],
|
|
19
32
|
headless: spec.headless ?? false,
|
|
33
|
+
requirePermissionCoverage: spec.permissions?.requireCoverage,
|
|
34
|
+
modulePermissionDeclarations: spec.permissions?.modules,
|
|
35
|
+
roleTemplates: spec.permissions?.roleTemplates,
|
|
20
36
|
});
|
|
37
|
+
// Asset URLs carry their file's digest from here on, so a browser and
|
|
38
|
+
// anything in front of it may keep them until the bytes change.
|
|
39
|
+
await fingerprintAssets(manifest);
|
|
21
40
|
registerFunctions(modules);
|
|
22
41
|
registerJobs(modules);
|
|
23
|
-
|
|
42
|
+
logger.info('boot', {
|
|
43
|
+
driver: opened.name,
|
|
44
|
+
level: config.logLevel,
|
|
45
|
+
modules: modules.length,
|
|
46
|
+
functions: Object.keys(manifest.functions).length,
|
|
47
|
+
jobs: Object.keys(manifest.jobs).length,
|
|
48
|
+
// False means correlation is hashed with a bare digest instead of a keyed one,
|
|
49
|
+
// so a low-entropy command key is guessable and the web and worker processes
|
|
50
|
+
// cannot derive the same trace for one request.
|
|
51
|
+
traceKeyed: Boolean(config.secret),
|
|
52
|
+
});
|
|
53
|
+
return { spec, config, modules, manifest, log, logger };
|
|
24
54
|
}
|
|
25
55
|
//# sourceMappingURL=runtime.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/runtime.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,8EAA8E;AAC9E,4BAA4B;AAE5B,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Adapter, Manifest } from '../types.ts';
|
|
2
|
+
export type ScheduleClaim = {
|
|
3
|
+
job: string;
|
|
4
|
+
tick: string;
|
|
5
|
+
skipped: number;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Move every due schedule forward in one tenant database, and say which moved.
|
|
9
|
+
*
|
|
10
|
+
* The caller enqueues what comes back. Claiming before enqueueing means a crash
|
|
11
|
+
* between the two loses one tick rather than running it twice, which is the right
|
|
12
|
+
* way round for anything that touches money.
|
|
13
|
+
*/
|
|
14
|
+
export declare function claimDue(adapter: Adapter, manifest: Manifest, o: {
|
|
15
|
+
now: Date;
|
|
16
|
+
timezone: string;
|
|
17
|
+
}): Promise<ScheduleClaim[]>;
|
|
18
|
+
//# sourceMappingURL=schedule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/schedule.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAAe,QAAQ,EAAE,MAAM,aAAa,CAAA;AAmBjE,MAAM,MAAM,aAAa,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1E;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,CAAC,EAAE;IAAE,GAAG,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACjC,OAAO,CAAC,aAAa,EAAE,CAAC,CAsC1B"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Claiming a due tick, which is the one part a queue cannot help with.
|
|
2
|
+
//
|
|
3
|
+
// A schedule does not run anything: it decides that a tick is due and enqueues the
|
|
4
|
+
// ordinary job, which then goes through the machinery that already exists — leases,
|
|
5
|
+
// retries, timeouts, abort signals, records. That reuse is why this file is short.
|
|
6
|
+
//
|
|
7
|
+
// Several worker replicas looking at one schedule at the same moment must still
|
|
8
|
+
// produce exactly one run. The queue's `uniqueKey` is not enough: it holds only
|
|
9
|
+
// while a job is live and is released the moment one completes, so a tick that
|
|
10
|
+
// finished an hour ago would be enqueued again. The claim is therefore durable and
|
|
11
|
+
// monotonic — one row per job per tenant database holding the last tick anybody
|
|
12
|
+
// enqueued, moved forward with a compare-and-set. Whoever's update changes a row
|
|
13
|
+
// won, and there is no leader to elect.
|
|
14
|
+
import { tickAt, ticksBetween } from '../kernel/schedule.js';
|
|
15
|
+
// Text columns and no types either adapter spells differently, so one statement
|
|
16
|
+
// serves both — the same reason ket_job stores its timestamps as ISO text.
|
|
17
|
+
const DDL = `
|
|
18
|
+
CREATE TABLE IF NOT EXISTS ket_schedule (
|
|
19
|
+
job TEXT PRIMARY KEY,
|
|
20
|
+
last_tick TEXT NOT NULL,
|
|
21
|
+
updated_at TEXT NOT NULL
|
|
22
|
+
)`;
|
|
23
|
+
const prepared = new WeakSet();
|
|
24
|
+
async function prepare(adapter) {
|
|
25
|
+
if (prepared.has(adapter))
|
|
26
|
+
return;
|
|
27
|
+
await adapter.run(DDL, []);
|
|
28
|
+
prepared.add(adapter);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Move every due schedule forward in one tenant database, and say which moved.
|
|
32
|
+
*
|
|
33
|
+
* The caller enqueues what comes back. Claiming before enqueueing means a crash
|
|
34
|
+
* between the two loses one tick rather than running it twice, which is the right
|
|
35
|
+
* way round for anything that touches money.
|
|
36
|
+
*/
|
|
37
|
+
export async function claimDue(adapter, manifest, o) {
|
|
38
|
+
const scheduled = Object.entries(manifest.jobs).filter(([, meta]) => meta.schedule);
|
|
39
|
+
if (!scheduled.length)
|
|
40
|
+
return [];
|
|
41
|
+
await prepare(adapter);
|
|
42
|
+
const claims = [];
|
|
43
|
+
const pg = adapter.name === 'postgres';
|
|
44
|
+
const p = (n) => (pg ? `$${n}` : '?');
|
|
45
|
+
for (const [job, meta] of scheduled) {
|
|
46
|
+
const schedule = meta.schedule;
|
|
47
|
+
const tick = tickAt(schedule, o.now, o.timezone);
|
|
48
|
+
const at = o.now.toISOString();
|
|
49
|
+
// A schedule seen for the first time does not fire for the tick it happened to
|
|
50
|
+
// start inside: nobody asked for a run at deploy time, and a nightly job that
|
|
51
|
+
// fires the moment it is installed is a surprise at the worst moment.
|
|
52
|
+
const inserted = await adapter.run(`INSERT INTO ket_schedule (job, last_tick, updated_at) VALUES (${p(1)}, ${p(2)}, ${p(3)})
|
|
53
|
+
ON CONFLICT DO NOTHING`, [job, tick, at]);
|
|
54
|
+
if (inserted.changes > 0)
|
|
55
|
+
continue;
|
|
56
|
+
const rows = await adapter.all(`SELECT last_tick FROM ket_schedule WHERE job = ${p(1)}`, [job]);
|
|
57
|
+
const last = rows[0] === undefined ? null : String(rows[0].last_tick);
|
|
58
|
+
if (last === null || last >= tick)
|
|
59
|
+
continue;
|
|
60
|
+
const moved = await adapter.run(`UPDATE ket_schedule SET last_tick = ${p(1)}, updated_at = ${p(2)}
|
|
61
|
+
WHERE job = ${p(3)} AND last_tick = ${p(4)}`, [tick, at, job, last]);
|
|
62
|
+
// Lost the compare-and-set: another replica claimed this tick. That is the
|
|
63
|
+
// whole mutual exclusion, and losing it is the normal case rather than a fault.
|
|
64
|
+
if (moved.changes === 0)
|
|
65
|
+
continue;
|
|
66
|
+
claims.push({ job, tick, skipped: ticksBetween(schedule, last, tick) });
|
|
67
|
+
}
|
|
68
|
+
return claims;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/schedule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Adapter, Scope } from '../types.ts';
|
|
2
|
+
export type SequenceOptions = {
|
|
3
|
+
/**
|
|
4
|
+
* Where the count starts, the first time anybody asks. Defaults to 1.
|
|
5
|
+
*/
|
|
6
|
+
start?: number;
|
|
7
|
+
/**
|
|
8
|
+
* Count once for the whole tenant instead of once per company.
|
|
9
|
+
*
|
|
10
|
+
* The default is per company because that is what an ERP means by a document
|
|
11
|
+
* number, and because a shared counter reached by forgetting to scope one is a
|
|
12
|
+
* bug nobody sees until two legal entities have issued the same invoice number.
|
|
13
|
+
*/
|
|
14
|
+
shared?: boolean;
|
|
15
|
+
};
|
|
16
|
+
export declare const sequenceKey: (name: string, scope: Scope, shared: boolean) => string;
|
|
17
|
+
/**
|
|
18
|
+
* Take the next number in a named sequence.
|
|
19
|
+
*
|
|
20
|
+
* The read and the compare-and-set are retried with jittered backoff, because
|
|
21
|
+
* every document of one kind funnels through one row: a bulk import is a stampede
|
|
22
|
+
* by design, and losing the race there is normal rather than exceptional. What must
|
|
23
|
+
* not happen is giving up while the row is live, which would turn a perfectly good
|
|
24
|
+
* order into a spurious failure.
|
|
25
|
+
*
|
|
26
|
+
* Whether the numbers are gapless is decided by the caller, not here. Taken inside
|
|
27
|
+
* the transaction that writes the document, a rollback takes the number back with
|
|
28
|
+
* it. Taken outside, a later failure leaves a gap, and no counter can know that
|
|
29
|
+
* happened.
|
|
30
|
+
*/
|
|
31
|
+
export declare function nextSequenceNumber(adapter: Adapter, name: string, o: {
|
|
32
|
+
scope: Scope;
|
|
33
|
+
dryRun?: boolean;
|
|
34
|
+
random?: () => number;
|
|
35
|
+
} & SequenceOptions): Promise<number>;
|
|
36
|
+
/** What a sequence stands at, without taking a number. */
|
|
37
|
+
export declare function peekSequenceNumber(adapter: Adapter, name: string, o: {
|
|
38
|
+
scope: Scope;
|
|
39
|
+
shared?: boolean;
|
|
40
|
+
start?: number;
|
|
41
|
+
}): Promise<number>;
|
|
42
|
+
//# sourceMappingURL=sequence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/sequence.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAgBjD,MAAM,MAAM,eAAe,GAAG;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAID,eAAO,MAAM,WAAW,SAAU,MAAM,SAAS,KAAK,UAAU,OAAO,KAAG,MACd,CAAA;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAA;CAAE,GAAG,eAAe,GAC7E,OAAO,CAAC,MAAM,CAAC,CAkDjB;AAED,0DAA0D;AAC1D,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD,OAAO,CAAC,MAAM,CAAC,CASjB"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Document numbers.
|
|
2
|
+
//
|
|
3
|
+
// Every ERP needs them and every module was writing its own: a counter row, a
|
|
4
|
+
// read, a compare-and-set, a retry loop. Written twice already, correctly both
|
|
5
|
+
// times but not identically — one of the two retries thirty-two times with no
|
|
6
|
+
// backoff, which spins hottest exactly when the counter is contended. That is the
|
|
7
|
+
// shape of a primitive that should exist once.
|
|
8
|
+
//
|
|
9
|
+
// The framework returns a number and never a string. How a number becomes
|
|
10
|
+
// "S00001" or "POS/00042" is the domain's, and a framework that decided it would
|
|
11
|
+
// be deciding an invoice format for a tax authority it has never heard of.
|
|
12
|
+
import { KetError } from '../kernel/errors.js';
|
|
13
|
+
const DDL = `
|
|
14
|
+
CREATE TABLE IF NOT EXISTS ket_sequence (
|
|
15
|
+
id TEXT PRIMARY KEY,
|
|
16
|
+
next INTEGER NOT NULL
|
|
17
|
+
)`;
|
|
18
|
+
const prepared = new WeakSet();
|
|
19
|
+
async function prepare(adapter) {
|
|
20
|
+
if (prepared.has(adapter))
|
|
21
|
+
return;
|
|
22
|
+
await adapter.run(DDL, []);
|
|
23
|
+
prepared.add(adapter);
|
|
24
|
+
}
|
|
25
|
+
const NAME = /^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)*$/;
|
|
26
|
+
export const sequenceKey = (name, scope, shared) => shared ? `-\n${name}` : `${scope.company ?? '-'}\n${name}`;
|
|
27
|
+
/**
|
|
28
|
+
* Take the next number in a named sequence.
|
|
29
|
+
*
|
|
30
|
+
* The read and the compare-and-set are retried with jittered backoff, because
|
|
31
|
+
* every document of one kind funnels through one row: a bulk import is a stampede
|
|
32
|
+
* by design, and losing the race there is normal rather than exceptional. What must
|
|
33
|
+
* not happen is giving up while the row is live, which would turn a perfectly good
|
|
34
|
+
* order into a spurious failure.
|
|
35
|
+
*
|
|
36
|
+
* Whether the numbers are gapless is decided by the caller, not here. Taken inside
|
|
37
|
+
* the transaction that writes the document, a rollback takes the number back with
|
|
38
|
+
* it. Taken outside, a later failure leaves a gap, and no counter can know that
|
|
39
|
+
* happened.
|
|
40
|
+
*/
|
|
41
|
+
export async function nextSequenceNumber(adapter, name, o) {
|
|
42
|
+
if (!NAME.test(name)) {
|
|
43
|
+
throw new KetError({
|
|
44
|
+
code: 'E_SEQUENCE_NAME',
|
|
45
|
+
message: `"${name}" is not a sequence name`,
|
|
46
|
+
hint: 'use a qualified lowercase identifier, for example "sale.order"',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const start = Math.max(1, Math.floor(o.start ?? 1));
|
|
50
|
+
const id = sequenceKey(name, o.scope, o.shared === true);
|
|
51
|
+
await prepare(adapter);
|
|
52
|
+
const pg = adapter.name === 'postgres';
|
|
53
|
+
const p = (n) => (pg ? `$${n}` : '?');
|
|
54
|
+
const random = o.random ?? Math.random;
|
|
55
|
+
const read = async () => {
|
|
56
|
+
const rows = await adapter.all(`SELECT next FROM ket_sequence WHERE id = ${p(1)}`, [id]);
|
|
57
|
+
return rows[0] === undefined ? null : Number(rows[0].next);
|
|
58
|
+
};
|
|
59
|
+
// A preview must not consume a number: the real command that follows would then
|
|
60
|
+
// skip one, and the caller would have been shown a number nobody ever used.
|
|
61
|
+
if (o.dryRun)
|
|
62
|
+
return (await read()) ?? start;
|
|
63
|
+
for (let attempt = 0; attempt < 64; attempt += 1) {
|
|
64
|
+
const current = await read();
|
|
65
|
+
if (current === null) {
|
|
66
|
+
const inserted = await adapter.run(`INSERT INTO ket_sequence (id, next) VALUES (${p(1)}, ${p(2)}) ON CONFLICT DO NOTHING`, [id, start + 1]);
|
|
67
|
+
if (inserted.changes > 0)
|
|
68
|
+
return start;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const moved = await adapter.run(`UPDATE ket_sequence SET next = ${p(1)} WHERE id = ${p(2)} AND next = ${p(3)}`, [current + 1, id, current]);
|
|
72
|
+
if (moved.changes > 0)
|
|
73
|
+
return current;
|
|
74
|
+
// Spread the herd instead of letting it collide again at full speed.
|
|
75
|
+
if (attempt >= 2) {
|
|
76
|
+
const ceiling = Math.min(100, 2 ** (attempt - 2));
|
|
77
|
+
await new Promise((resolve) => setTimeout(resolve, ceiling * (0.5 + random())));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
throw new KetError({
|
|
81
|
+
code: 'E_SEQUENCE_CONTENDED',
|
|
82
|
+
message: `sequence "${name}" did not settle after 64 concurrent updates`,
|
|
83
|
+
hint: 'one row is carrying more concurrent allocation than it can; split the sequence',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/** What a sequence stands at, without taking a number. */
|
|
87
|
+
export async function peekSequenceNumber(adapter, name, o) {
|
|
88
|
+
await prepare(adapter);
|
|
89
|
+
const pg = adapter.name === 'postgres';
|
|
90
|
+
const rows = await adapter.all(`SELECT next FROM ket_sequence WHERE id = ${pg ? '$1' : '?'}`, [
|
|
91
|
+
sequenceKey(name, o.scope, o.shared === true),
|
|
92
|
+
]);
|
|
93
|
+
return rows[0] === undefined
|
|
94
|
+
? Math.max(1, Math.floor(o.start ?? 1))
|
|
95
|
+
: Number(rows[0].next);
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=sequence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequence.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/sequence.ts"],"names":[],"mappings":"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"}
|
package/dist/server/session.d.ts
CHANGED
|
@@ -4,12 +4,16 @@ import type { IncomingMessage } from 'node:http';
|
|
|
4
4
|
export declare const SESSION_COOKIE = "ket_session";
|
|
5
5
|
export type SessionOptions = {
|
|
6
6
|
store?: SessionStore;
|
|
7
|
+
/** Bind records to one tenant when several tenants share the same store. */
|
|
8
|
+
tenant?: string;
|
|
7
9
|
/**
|
|
8
10
|
* Signing key. It MUST be the same on every pod: a cookie signed by one and
|
|
9
11
|
* rejected by another is a login that works only until the load balancer sends
|
|
10
12
|
* you elsewhere. Absent, one is generated and the fact is said out loud.
|
|
11
13
|
*/
|
|
12
14
|
secret?: string;
|
|
15
|
+
/** The supplied secret was generated for this process and must still be reported as ephemeral. */
|
|
16
|
+
ephemeralSecret?: boolean;
|
|
13
17
|
/** How long an idle session lives. Refreshed while it is being used. */
|
|
14
18
|
idleTtlMs?: number;
|
|
15
19
|
/** How long any session may live, however active. Not refreshable. */
|
|
@@ -24,6 +28,8 @@ export type SessionOptions = {
|
|
|
24
28
|
export declare function parseCookies(header: string | undefined): Record<string, string>;
|
|
25
29
|
export type Sessions = {
|
|
26
30
|
readonly store: SessionStore;
|
|
31
|
+
/** Present when records in this session manager are bound to one tenant. */
|
|
32
|
+
readonly tenant?: string;
|
|
27
33
|
/** True when the secret was generated rather than configured — see the banner. */
|
|
28
34
|
readonly ephemeralSecret: boolean;
|
|
29
35
|
start(o: {
|
|
@@ -49,6 +55,21 @@ export type Sessions = {
|
|
|
49
55
|
scopeOf(record: SessionRecord | null): Scope | null;
|
|
50
56
|
sweep(): Promise<number>;
|
|
51
57
|
};
|
|
58
|
+
export type SessionScopePolicy = {
|
|
59
|
+
/** Reject a record issued for a different tenant when session storage is shared. */
|
|
60
|
+
tenant?: string;
|
|
61
|
+
/** Scope used when there is no accepted session record. */
|
|
62
|
+
anonymous?: Scope | null;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Turn session data into a detached request scope.
|
|
66
|
+
*
|
|
67
|
+
* This stays adapter-free so a pooled tenant facade can keep the policy while the
|
|
68
|
+
* manager and its adapter are evicted. Arrays are copied on both paths: callers
|
|
69
|
+
* may narrow a request scope without mutating the stored record or deployment's
|
|
70
|
+
* anonymous policy.
|
|
71
|
+
*/
|
|
72
|
+
export declare function scopeForSession(record: SessionRecord | null, policy?: SessionScopePolicy): Scope | null;
|
|
52
73
|
export declare function createSessions(o?: SessionOptions): Promise<Sessions>;
|
|
53
74
|
export { memorySessionStore, dbSessionStore } from './sessionstore.ts';
|
|
54
75
|
export type { SessionContext, SessionStore, SessionRecord } from './sessionstore.ts';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/session.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACpF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAEhD,eAAO,MAAM,cAAc,gBAAgB,CAAA;AAE3C,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,kFAAkF;IAClF,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,sFAAsF;IACtF,SAAS,CAAC,EAAE,KAAK,GAAG,IAAI,CAAA;IACxB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB,CAAA;AAoBD,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ/E;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAA;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;IACjC,KAAK,CAAC,CAAC,EAAE;QACP,MAAM,EAAE,MAAM,CAAA;QACd,SAAS,EAAE,MAAM,EAAE,CAAA;QACnB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAA;KACzB,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,aAAa,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACtD,qEAAqE;IACrE,EAAE,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IACvD,GAAG,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACxC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9D,sEAAsE;IACtE,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IACrF,0CAA0C;IAC1C,WAAW,IAAI,MAAM,CAAA;IACrB,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,CAAA;IACnD,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;CACzB,CAAA;AAED,wBAAsB,cAAc,CAAC,CAAC,GAAE,cAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/session.ts"],"names":[],"mappings":"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"}
|