@ketvietlab/ketjs 0.1.2 → 0.1.5
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 +25 -1
- package/dist/data/expr.d.ts.map +1 -1
- package/dist/data/expr.js +47 -6
- 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 +45 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -18
- 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 +174 -38
- package/dist/server/boot.d.ts.map +1 -1
- package/dist/server/boot.js +399 -140
- 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 +284 -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 +82 -3
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +373 -37
- 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/stream.d.ts +8 -2
- package/dist/server/stream.d.ts.map +1 -1
- package/dist/server/stream.js +44 -4
- package/dist/server/stream.js.map +1 -1
- package/dist/server/streamstore.d.ts +10 -0
- package/dist/server/streamstore.d.ts.map +1 -1
- package/dist/server/streamstore.js +72 -6
- package/dist/server/streamstore.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 +18 -0
- package/dist/theme/tokens.d.ts.map +1 -1
- package/dist/theme/tokens.js +33 -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 +320 -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":"development.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/development.ts"],"names":[],"mappings":"AAAA,KAAK,SAAS,GAAG;IAAE,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAA;AAE9C;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CASrG"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stop a combined development process exactly once. HTTP closes first so a
|
|
3
|
+
* watcher can bind the same port while the durable worker finishes draining.
|
|
4
|
+
*/
|
|
5
|
+
export function createDevelopmentCloser(deployment, worker) {
|
|
6
|
+
let closing;
|
|
7
|
+
return () => {
|
|
8
|
+
closing ??= (async () => {
|
|
9
|
+
await deployment.close();
|
|
10
|
+
await worker.close();
|
|
11
|
+
})();
|
|
12
|
+
return closing;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=development.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"development.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/development.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,UAAqB,EAAE,MAAiB;IAC9E,IAAI,OAAkC,CAAA;IACtC,OAAO,GAAG,EAAE;QACV,OAAO,KAAK,CAAC,KAAK,IAAI,EAAE;YACtB,MAAM,UAAU,CAAC,KAAK,EAAE,CAAA;YACxB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;QACtB,CAAC,CAAC,EAAE,CAAA;QACJ,OAAO,OAAO,CAAA;IAChB,CAAC,CAAA;AACH,CAAC"}
|
package/dist/server/fn.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Logger } from './log/logger.ts';
|
|
1
2
|
import type { Adapter, FnSpec, KetModule, Manifest, WriteRecord } from '../types.ts';
|
|
2
3
|
export type CallResult = {
|
|
3
4
|
ok: true;
|
|
@@ -10,12 +11,18 @@ export declare function defineFn(spec: FnSpec): FnSpec;
|
|
|
10
11
|
export declare function registerFunctions(modules: KetModule[]): Map<string, FnSpec>;
|
|
11
12
|
export declare function validateInput(fnKey: string, manifest: Manifest, args: Record<string, unknown>): void;
|
|
12
13
|
export declare const _resetIdempotency: () => void;
|
|
13
|
-
export
|
|
14
|
+
export type CallOptions = {
|
|
14
15
|
adapter: Adapter;
|
|
15
16
|
manifest: Manifest;
|
|
16
17
|
dryRun?: boolean;
|
|
17
18
|
actor?: string | null;
|
|
19
|
+
/** Ephemeral correlation propagated to Ctx; never persisted by the framework. */
|
|
20
|
+
correlationId?: string | null;
|
|
18
21
|
idempotencyKey?: string | null;
|
|
22
|
+
/** Separates public callers that can choose the same client key. */
|
|
23
|
+
idempotencyNamespace?: string | null;
|
|
24
|
+
/** Defaults to a canonical digest of validated function arguments. */
|
|
25
|
+
idempotencyDigest?: string | null;
|
|
19
26
|
scope?: import('../types.ts').Scope;
|
|
20
27
|
/**
|
|
21
28
|
* The functions this caller may invoke. Undefined or null means unrestricted,
|
|
@@ -24,11 +31,23 @@ export declare function callFn(fnKey: string, args: Record<string, unknown>, o:
|
|
|
24
31
|
* business being narrowed by one.
|
|
25
32
|
*
|
|
26
33
|
* A list rather than a predicate so that it can be printed, diffed and stored.
|
|
27
|
-
* The framework enforces it; which list a user gets is the
|
|
34
|
+
* The framework enforces it; which list a user gets is the deployment's decision, the
|
|
28
35
|
* same split as the datastore driver.
|
|
29
36
|
*/
|
|
30
37
|
allow?: readonly string[] | null;
|
|
31
38
|
/** Runtime override for the optional queue wake-up signal. */
|
|
32
39
|
queueNotify?: boolean;
|
|
33
|
-
|
|
40
|
+
/** Where this call's operational log goes. Absent discards. */
|
|
41
|
+
log?: Logger;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Every call arrives here — HTTP, an in-process route, a job's own dispatch, a
|
|
45
|
+
* test — which is why this is the one place that has to record what happened.
|
|
46
|
+
*
|
|
47
|
+
* An anticipated failure is a warning and an unanticipated one is an error: a
|
|
48
|
+
* KetError is a contract this system named and expected to reject, while anything
|
|
49
|
+
* else escaped a `try` nobody wrote. Only the second kind carries a stack, and only
|
|
50
|
+
* the second kind should wake somebody up.
|
|
51
|
+
*/
|
|
52
|
+
export declare function callFn(fnKey: string, args: Record<string, unknown>, o: CallOptions): Promise<CallResult>;
|
|
34
53
|
//# sourceMappingURL=fn.d.ts.map
|
package/dist/server/fn.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fn.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/fn.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fn.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/fn.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAO,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAEzF,MAAM,MAAM,UAAU,GAAG;IACvB,EAAE,EAAE,IAAI,CAAA;IACR,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAID,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7C;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAK3E;AAcD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CA4DpG;AAgBD,eAAO,MAAM,iBAAiB,QAAO,IAEpC,CAAA;AAoCD,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,QAAQ,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,oEAAoE;IACpE,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,KAAK,CAAC,EAAE,OAAO,aAAa,EAAE,KAAK,CAAA;IACnC;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAA;IAChC,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAsB,MAAM,CAC1B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,CAAC,EAAE,WAAW,GACb,OAAO,CAAC,UAAU,CAAC,CA0BrB"}
|
package/dist/server/fn.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
// The atom. One declaration yields an HTTP endpoint, a typed client method, a
|
|
2
2
|
// manifest entry, an agent tool descriptor and a dry-runnable test handle.
|
|
3
3
|
// Written once, never restated.
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
import { KetError } from '../kernel/errors.js';
|
|
4
6
|
import { createContext } from './ctx.js';
|
|
5
7
|
import { createIdempotency } from './idem.js';
|
|
6
|
-
import {
|
|
8
|
+
import { FormValidationError } from './form.js';
|
|
7
9
|
import { project } from './project.js';
|
|
8
10
|
import { isDateText, parseType } from '../kernel/types.js';
|
|
11
|
+
import { DECIMAL_MAX_CHARS, parseDecimal } from '../data/changeset.js';
|
|
9
12
|
import { queueFor } from './queue.js';
|
|
10
13
|
const registry = new Map();
|
|
11
14
|
export function defineFn(spec) {
|
|
@@ -31,37 +34,52 @@ const JS_OF = {
|
|
|
31
34
|
datetime: 'string',
|
|
32
35
|
json: 'object',
|
|
33
36
|
};
|
|
34
|
-
const DECIMAL = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/;
|
|
35
37
|
export function validateInput(fnKey, manifest, args) {
|
|
36
38
|
const sig = manifest.functions[fnKey]?.input ?? {};
|
|
37
39
|
const errors = [];
|
|
40
|
+
const issues = [];
|
|
41
|
+
const add = (field, code, message, params = {}) => {
|
|
42
|
+
errors.push(message);
|
|
43
|
+
issues.push({ field, code, messageKey: `validation.${code}`, params });
|
|
44
|
+
};
|
|
38
45
|
for (const [name, tspec] of Object.entries(sig)) {
|
|
39
46
|
const t = parseType(tspec);
|
|
40
47
|
const v = args?.[name];
|
|
41
48
|
if (v == null) {
|
|
42
49
|
if (t.ok && !t.optional)
|
|
43
|
-
|
|
50
|
+
add(name, 'required', `missing required input "${name}" (${tspec})`, { expected: tspec });
|
|
44
51
|
continue;
|
|
45
52
|
}
|
|
46
53
|
if (!t.ok)
|
|
47
54
|
continue;
|
|
48
55
|
const want = JS_OF[t.base];
|
|
49
|
-
if (want && typeof v !== want)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
if (want && typeof v !== want) {
|
|
57
|
+
add(name, 'type', `input "${name}" expects ${t.base} (${want}), got ${typeof v}`, {
|
|
58
|
+
expected: t.base,
|
|
59
|
+
actual: typeof v,
|
|
60
|
+
});
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (t.base === 'decimal') {
|
|
64
|
+
const parsed = parseDecimal(v);
|
|
65
|
+
if (!parsed.ok)
|
|
66
|
+
add(name, parsed.reason === 'size' ? 'maxLength' : 'decimal', parsed.reason === 'size'
|
|
67
|
+
? `input "${name}" exceeds the ${DECIMAL_MAX_CHARS}-character decimal limit`
|
|
68
|
+
: `input "${name}" expects a finite number or an exact decimal string`, parsed.reason === 'size' ? { max: DECIMAL_MAX_CHARS } : {});
|
|
69
|
+
}
|
|
54
70
|
if (t.base === 'int' && typeof v === 'number' && !Number.isInteger(v))
|
|
55
|
-
|
|
71
|
+
add(name, 'integer', `input "${name}" expects an integer`);
|
|
56
72
|
if (t.base === 'date' && !isDateText(v))
|
|
57
|
-
|
|
73
|
+
add(name, 'date', `input "${name}" expects a calendar date (YYYY-MM-DD)`);
|
|
58
74
|
}
|
|
59
75
|
for (const k of Object.keys(args ?? {})) {
|
|
60
|
-
if (!(k
|
|
61
|
-
|
|
76
|
+
if (!Object.hasOwn(sig, k)) {
|
|
77
|
+
const accepted = Object.keys(sig);
|
|
78
|
+
add(k, 'unknown', `unknown input "${k}" (accepted: ${accepted.join(', ') || 'none'})`, { accepted });
|
|
79
|
+
}
|
|
62
80
|
}
|
|
63
81
|
if (errors.length) {
|
|
64
|
-
throw new
|
|
82
|
+
throw new FormValidationError(issues, {
|
|
65
83
|
code: 'E_INVALID_INPUT',
|
|
66
84
|
message: `${fnKey}: ${errors.join('; ')}`,
|
|
67
85
|
hint: `signature: ${JSON.stringify(sig)}`,
|
|
@@ -80,17 +98,69 @@ const idemFor = (adapter) => {
|
|
|
80
98
|
export const _resetIdempotency = () => {
|
|
81
99
|
/* records are durable; nothing to clear */
|
|
82
100
|
};
|
|
101
|
+
const canonical = (value) => {
|
|
102
|
+
if (value === null || typeof value !== 'object')
|
|
103
|
+
return JSON.stringify(value);
|
|
104
|
+
if (Array.isArray(value))
|
|
105
|
+
return `[${value.map(canonical).join(',')}]`;
|
|
106
|
+
return `{${Object.entries(value)
|
|
107
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
108
|
+
.map(([key, held]) => `${JSON.stringify(key)}:${canonical(held)}`)
|
|
109
|
+
.join(',')}}`;
|
|
110
|
+
};
|
|
111
|
+
const requestDigest = (args) => createHash('sha256').update(canonical(args)).digest('hex');
|
|
112
|
+
const idempotencyKey = (fnKey, key, o) => {
|
|
113
|
+
const digest = requestDigest({
|
|
114
|
+
actor: o.actor ?? null,
|
|
115
|
+
branch: o.scope?.branch ?? null,
|
|
116
|
+
branches: [...(o.scope?.branches ?? [])].sort(),
|
|
117
|
+
companies: [...(o.scope?.companies ?? [])].sort(),
|
|
118
|
+
company: o.scope?.company ?? null,
|
|
119
|
+
fn: fnKey,
|
|
120
|
+
key,
|
|
121
|
+
namespace: o.idempotencyNamespace ?? null,
|
|
122
|
+
});
|
|
123
|
+
return `v2:${digest}`;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Every call arrives here — HTTP, an in-process route, a job's own dispatch, a
|
|
127
|
+
* test — which is why this is the one place that has to record what happened.
|
|
128
|
+
*
|
|
129
|
+
* An anticipated failure is a warning and an unanticipated one is an error: a
|
|
130
|
+
* KetError is a contract this system named and expected to reject, while anything
|
|
131
|
+
* else escaped a `try` nobody wrote. Only the second kind carries a stack, and only
|
|
132
|
+
* the second kind should wake somebody up.
|
|
133
|
+
*/
|
|
83
134
|
export async function callFn(fnKey, args, o) {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
135
|
+
const started = Date.now();
|
|
136
|
+
try {
|
|
137
|
+
const result = await runFn(fnKey, args, o);
|
|
138
|
+
o.log?.log({
|
|
139
|
+
level: 'info',
|
|
140
|
+
event: 'fn_call',
|
|
141
|
+
fn: fnKey,
|
|
142
|
+
durationMs: Date.now() - started,
|
|
143
|
+
dryRun: result.dryRun,
|
|
144
|
+
...(result.replayed ? { replayed: true } : {}),
|
|
145
|
+
});
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
catch (cause) {
|
|
149
|
+
const known = cause instanceof KetError;
|
|
150
|
+
o.log?.log({
|
|
151
|
+
level: known ? 'warn' : 'error',
|
|
152
|
+
// A caller reaching for something it may not have is a security signal, not
|
|
153
|
+
// a malfunction, and it is counted separately for that reason.
|
|
154
|
+
event: known && cause.code === 'E_FN_NOT_PERMITTED' ? 'fn_denied' : 'fn_error',
|
|
155
|
+
fn: fnKey,
|
|
156
|
+
durationMs: Date.now() - started,
|
|
157
|
+
error: cause,
|
|
92
158
|
});
|
|
159
|
+
throw cause;
|
|
93
160
|
}
|
|
161
|
+
}
|
|
162
|
+
async function runFn(fnKey, args, o) {
|
|
163
|
+
const def = registry.get(fnKey);
|
|
94
164
|
if (!def)
|
|
95
165
|
throw new KetError({
|
|
96
166
|
code: 'E_UNKNOWN_FUNCTION',
|
|
@@ -101,6 +171,7 @@ export async function callFn(fnKey, args, o) {
|
|
|
101
171
|
// call this at all learns that and nothing else — not which arguments it takes,
|
|
102
172
|
// and not whether the ones they guessed were right.
|
|
103
173
|
if (o.allow && !o.allow.includes(fnKey)) {
|
|
174
|
+
const owner = fnKey.split('.')[0] ?? fnKey;
|
|
104
175
|
throw new KetError({
|
|
105
176
|
code: 'E_FN_NOT_PERMITTED',
|
|
106
177
|
module: owner,
|
|
@@ -111,27 +182,40 @@ export async function callFn(fnKey, args, o) {
|
|
|
111
182
|
validateInput(fnKey, o.manifest, args);
|
|
112
183
|
const meta = o.manifest.functions[fnKey];
|
|
113
184
|
const dryRun = o.dryRun ?? false;
|
|
185
|
+
if (o.idempotencyKey && !meta.idempotent) {
|
|
186
|
+
throw new KetError({
|
|
187
|
+
code: 'E_NOT_IDEMPOTENT',
|
|
188
|
+
message: `"${fnKey}" is not declared idempotent but was called with an idempotency key`,
|
|
189
|
+
hint: 'declare `idempotent: true` on the function, or drop the key',
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
if (dryRun && !meta.dryRun)
|
|
193
|
+
throw new KetError({ code: 'E_NO_DRY_RUN', message: `"${fnKey}" does not support dry-run` });
|
|
114
194
|
// Create system queue tables on the root adapter before user code can enter a
|
|
115
195
|
// transaction. Lazy DDL inside a rolled-back transaction would otherwise leave
|
|
116
196
|
// an in-memory "initialized" marker pointing at a table that no longer exists.
|
|
117
197
|
if (Object.keys(o.manifest.jobs).length)
|
|
118
198
|
await queueFor(o.adapter);
|
|
119
|
-
|
|
199
|
+
// A dry-run is a preview, not an execution. It neither claims nor completes the
|
|
200
|
+
// caller's durable key: otherwise the following real command would replay the
|
|
201
|
+
// simulated result and never perform the writes it previewed.
|
|
202
|
+
const idemKey = !dryRun && o.idempotencyKey ? idempotencyKey(fnKey, o.idempotencyKey, o) : null;
|
|
203
|
+
const idemDigest = idemKey ? (o.idempotencyDigest ?? requestDigest(args)) : null;
|
|
120
204
|
let idem = null;
|
|
121
205
|
if (idemKey) {
|
|
122
|
-
if (!meta.idempotent) {
|
|
123
|
-
throw new KetError({
|
|
124
|
-
code: 'E_NOT_IDEMPOTENT',
|
|
125
|
-
message: `"${fnKey}" is not declared idempotent but was called with an idempotency key`,
|
|
126
|
-
hint: 'declare `idempotent: true` on the function, or drop the key',
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
206
|
idem = await idemFor(o.adapter);
|
|
130
207
|
// Claim the key before doing any work. Losing the race means another caller is
|
|
131
208
|
// either mid-flight or already finished, and both are answered from the record.
|
|
132
|
-
const claimed = await idem.claim(idemKey, fnKey);
|
|
209
|
+
const claimed = await idem.claim(idemKey, fnKey, 5 * 60_000, idemDigest);
|
|
133
210
|
if (!claimed) {
|
|
134
211
|
const existing = await idem.read(idemKey);
|
|
212
|
+
if (existing?.digest && existing.digest !== idemDigest) {
|
|
213
|
+
throw new KetError({
|
|
214
|
+
code: 'E_IDEMPOTENCY_CONFLICT',
|
|
215
|
+
message: `idempotency key "${o.idempotencyKey}" was already used with a different request`,
|
|
216
|
+
hint: 'reuse a key only when retrying the exact same command',
|
|
217
|
+
});
|
|
218
|
+
}
|
|
135
219
|
if (existing?.state === 'done')
|
|
136
220
|
return { ...existing.result, replayed: true };
|
|
137
221
|
throw new KetError({
|
|
@@ -141,16 +225,16 @@ export async function callFn(fnKey, args, o) {
|
|
|
141
225
|
});
|
|
142
226
|
}
|
|
143
227
|
}
|
|
144
|
-
if (dryRun && !meta.dryRun)
|
|
145
|
-
throw new KetError({ code: 'E_NO_DRY_RUN', message: `"${fnKey}" does not support dry-run` });
|
|
146
228
|
const ctx = createContext({
|
|
147
229
|
adapter: o.adapter,
|
|
148
230
|
manifest: o.manifest,
|
|
149
231
|
fnKey,
|
|
150
232
|
dryRun,
|
|
151
233
|
actor: o.actor ?? null,
|
|
234
|
+
correlationId: o.correlationId ?? null,
|
|
152
235
|
scope: o.scope,
|
|
153
236
|
queueNotify: o.queueNotify,
|
|
237
|
+
...(o.log ? { log: o.log.child({ fn: fnKey, dryRun }) } : {}),
|
|
154
238
|
});
|
|
155
239
|
let result;
|
|
156
240
|
try {
|
package/dist/server/fn.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fn.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/fn.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,2EAA2E;AAC3E,gCAAgC;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"fn.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/fn.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { FormSchema, FormValidationProblem, FormValidationResult, FormValues, ValidationIssue } from '@ketvietlab/ketjs-view';
|
|
2
|
+
import { KetError } from '../kernel/errors.ts';
|
|
3
|
+
import type { RouteResult } from './respond.ts';
|
|
4
|
+
type ValidationSource = readonly ValidationIssue[] | Pick<FormValidationResult, 'issues'>;
|
|
5
|
+
export declare class FormValidationError extends KetError {
|
|
6
|
+
readonly issues: ValidationIssue[];
|
|
7
|
+
readonly fieldErrors: Record<string, ValidationIssue[]>;
|
|
8
|
+
readonly formErrors: ValidationIssue[];
|
|
9
|
+
constructor(source: ValidationSource, options?: {
|
|
10
|
+
code?: string;
|
|
11
|
+
message?: string;
|
|
12
|
+
hint?: string | null;
|
|
13
|
+
module?: string | null;
|
|
14
|
+
});
|
|
15
|
+
toJSON(): ReturnType<KetError['toJSON']> & FormValidationProblem;
|
|
16
|
+
}
|
|
17
|
+
/** Validate untrusted form values and throw a structured error suitable for an HTTP 422 response. */
|
|
18
|
+
export declare function assertForm<TValues extends FormValues = FormValues>(schema: FormSchema<TValues>, input: Readonly<FormValues>): TValues;
|
|
19
|
+
/** Build the standard non-throwing HTTP response for a route that re-renders or returns JSON itself. */
|
|
20
|
+
export declare const invalidForm: (source: ValidationSource, options?: {
|
|
21
|
+
code?: string;
|
|
22
|
+
message?: string;
|
|
23
|
+
}) => RouteResult;
|
|
24
|
+
/** Convert legacy `{ field, message }` changeset errors into the shared form issue contract. */
|
|
25
|
+
export declare const issuesFromFieldErrors: (errors: readonly {
|
|
26
|
+
field: string;
|
|
27
|
+
message: string;
|
|
28
|
+
}[], options?: {
|
|
29
|
+
code?: string;
|
|
30
|
+
messageKey?: string;
|
|
31
|
+
}) => ValidationIssue[];
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/form.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EACV,qBAAqB,EACrB,oBAAoB,EACpB,UAAU,EACV,eAAe,EAChB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAE9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,KAAK,gBAAgB,GAAG,SAAS,eAAe,EAAE,GAAG,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAA;AAEzF,qBAAa,mBAAoB,SAAQ,QAAQ;IAC/C,QAAQ,CAAC,MAAM,EAAE,eAAe,EAAE,CAAA;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;IACvD,QAAQ,CAAC,UAAU,EAAE,eAAe,EAAE,CAAA;IAEtC,YACE,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACpB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAClB,EAaP;IAEQ,MAAM,IAAI,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,qBAAqB,CAQxE;CACF;AAED,qGAAqG;AACrG,wBAAgB,UAAU,CAAC,OAAO,SAAS,UAAU,GAAG,UAAU,EAChE,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,EAC3B,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,GAC1B,OAAO,CAIT;AAED,wGAAwG;AACxG,eAAO,MAAM,WAAW,WACd,gBAAgB,YACf;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,KAC3C,WAAwE,CAAA;AAE3E,gGAAgG;AAChG,eAAO,MAAM,qBAAqB,WACxB,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,YAC5C;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,KAC9C,eAAe,EAMb,CAAA"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { validateForm, validationProblem } from '@ketvietlab/ketjs-view';
|
|
2
|
+
import { KetError } from '../kernel/errors.js';
|
|
3
|
+
import { json } from './respond.js';
|
|
4
|
+
export class FormValidationError extends KetError {
|
|
5
|
+
issues;
|
|
6
|
+
fieldErrors;
|
|
7
|
+
formErrors;
|
|
8
|
+
constructor(source, options = {}) {
|
|
9
|
+
const problem = validationProblem(source, options);
|
|
10
|
+
super({
|
|
11
|
+
code: problem.code,
|
|
12
|
+
message: problem.message,
|
|
13
|
+
hint: options.hint,
|
|
14
|
+
module: options.module,
|
|
15
|
+
});
|
|
16
|
+
this.name = 'FormValidationError';
|
|
17
|
+
this.issues = problem.issues;
|
|
18
|
+
this.fieldErrors = problem.fieldErrors;
|
|
19
|
+
this.formErrors = problem.formErrors;
|
|
20
|
+
}
|
|
21
|
+
toJSON() {
|
|
22
|
+
return {
|
|
23
|
+
...super.toJSON(),
|
|
24
|
+
ok: false,
|
|
25
|
+
issues: this.issues,
|
|
26
|
+
fieldErrors: this.fieldErrors,
|
|
27
|
+
formErrors: this.formErrors,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Validate untrusted form values and throw a structured error suitable for an HTTP 422 response. */
|
|
32
|
+
export function assertForm(schema, input) {
|
|
33
|
+
const result = validateForm(schema, input);
|
|
34
|
+
if (!result.valid)
|
|
35
|
+
throw new FormValidationError(result);
|
|
36
|
+
return result.values;
|
|
37
|
+
}
|
|
38
|
+
/** Build the standard non-throwing HTTP response for a route that re-renders or returns JSON itself. */
|
|
39
|
+
export const invalidForm = (source, options = {}) => json(validationProblem(source, options), { status: 422 });
|
|
40
|
+
/** Convert legacy `{ field, message }` changeset errors into the shared form issue contract. */
|
|
41
|
+
export const issuesFromFieldErrors = (errors, options = {}) => errors.map((error) => ({
|
|
42
|
+
field: error.field,
|
|
43
|
+
code: options.code ?? 'invalid',
|
|
44
|
+
messageKey: options.messageKey ?? 'validation.invalid',
|
|
45
|
+
params: { message: error.message },
|
|
46
|
+
}));
|
|
47
|
+
//# sourceMappingURL=form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/form.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAQxE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAKnC,MAAM,OAAO,mBAAoB,SAAQ,QAAQ;IACtC,MAAM,CAAmB;IACzB,WAAW,CAAmC;IAC9C,UAAU,CAAmB;IAEtC,YACE,MAAwB,EACxB,OAAO,GAKH,EAAE;QAEN,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAClD,KAAK,CAAC;YACJ,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAA;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;QACjC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC5B,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAA;QACtC,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAA;IACtC,CAAC;IAEQ,MAAM;QACb,OAAO;YACL,GAAG,KAAK,CAAC,MAAM,EAAE;YACjB,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAA;IACH,CAAC;CACF;AAED,qGAAqG;AACrG,MAAM,UAAU,UAAU,CACxB,MAA2B,EAC3B,KAA2B;IAE3B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAC1C,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,MAAM,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAA;IACxD,OAAO,MAAM,CAAC,MAAM,CAAA;AACtB,CAAC;AAED,wGAAwG;AACxG,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,MAAwB,EACxB,OAAO,GAAwC,EAAE,EACpC,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;AAE3E,gGAAgG;AAChG,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,MAAqD,EACrD,OAAO,GAA2C,EAAE,EACjC,EAAE,CACrB,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC,KAAK;IAClB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,SAAS;IAC/B,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,oBAAoB;IACtD,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE;CACnC,CAAC,CAAC,CAAA"}
|
package/dist/server/http.d.ts
CHANGED
|
@@ -4,8 +4,20 @@ import type { StreamStore } from './stream.ts';
|
|
|
4
4
|
import type { Adapter, Manifest, Scope } from '../types.ts';
|
|
5
5
|
import type { AdapterPool } from '../data/pool.ts';
|
|
6
6
|
import type { ThemeRuntime } from '../theme/render.ts';
|
|
7
|
+
import type { Logger } from './log/logger.ts';
|
|
8
|
+
import type { RatePolicy } from './ratelimit.ts';
|
|
7
9
|
import type { RouteParams } from '../kernel/routes.ts';
|
|
8
10
|
type HttpRoute = (url: URL, req: IncomingMessage, params: RouteParams) => Promise<RouteResult> | RouteResult;
|
|
11
|
+
/**
|
|
12
|
+
* What an error means over HTTP.
|
|
13
|
+
*
|
|
14
|
+
* Every KetError used to answer 400, which said "you sent something wrong" to a
|
|
15
|
+
* person whose request was fine and whose permissions were not. A monitor cannot
|
|
16
|
+
* tell a missing grant from a malformed body, and neither can a client.
|
|
17
|
+
*/
|
|
18
|
+
export declare const statusForError: (code: string) => number;
|
|
19
|
+
/** True when this request is a browser navigating, rather than a client calling. */
|
|
20
|
+
export declare const wantsHtml: (req: IncomingMessage) => boolean;
|
|
9
21
|
export type ServeOpts = {
|
|
10
22
|
manifest: Manifest;
|
|
11
23
|
/** A single database. Use `pool` + `resolveDatastore` for one database per tenant. */
|
|
@@ -22,8 +34,60 @@ export type ServeOpts = {
|
|
|
22
34
|
/** Browser modules for islands available to this request. */
|
|
23
35
|
islandClients?: ThemeRuntime['clients'] | ((url: URL, req: IncomingMessage) => Promise<ThemeRuntime['clients']>);
|
|
24
36
|
port?: number;
|
|
25
|
-
/** Defaults to a table on the
|
|
37
|
+
/** Defaults to a table on the deployment adapter; swap for memory on a single instance. */
|
|
26
38
|
streamStore?: StreamStore;
|
|
39
|
+
/**
|
|
40
|
+
* Authorize a resumable-stream request and map its public id to the internal,
|
|
41
|
+
* tenant-namespaced topic stored by `streams`.
|
|
42
|
+
*
|
|
43
|
+
* The endpoint is disabled when this resolver is absent. Returning null also
|
|
44
|
+
* refuses the request, so looking up a topic never happens before the deployment
|
|
45
|
+
* has authenticated the caller and chosen its tenant.
|
|
46
|
+
*/
|
|
47
|
+
resolveStream?: (id: string, url: URL, req: IncomingMessage) => string | null | Promise<string | null>;
|
|
48
|
+
/**
|
|
49
|
+
* How long one stream connection is held open, and how long the tail waits
|
|
50
|
+
* before reading again when nothing has woken it.
|
|
51
|
+
*
|
|
52
|
+
* The defaults suit a stream with a producer and an end — a generated answer,
|
|
53
|
+
* a document sync — where the connection lives as long as the work does. A
|
|
54
|
+
* deployment watching something that changes rarely wants the opposite: a long
|
|
55
|
+
* connection so the client is not reconnecting all day, and a long fallback
|
|
56
|
+
* read because the notification, not the read, is how news arrives.
|
|
57
|
+
*/
|
|
58
|
+
streamTimeoutMs?: number;
|
|
59
|
+
streamPollMs?: number;
|
|
60
|
+
/** Maximum buffered JSON body for the generic function transport. Defaults to 1 MiB. */
|
|
61
|
+
maxJsonBodyBytes?: number;
|
|
62
|
+
/**
|
|
63
|
+
* A ceiling on how often one caller may reach a route, or null for no ceiling.
|
|
64
|
+
*
|
|
65
|
+
* Deliberately per-request rather than global: a durable check costs a database
|
|
66
|
+
* round trip, so applying it to everything would hand an attacker a lever rather
|
|
67
|
+
* than take one away. Return a policy for the handful of routes where repetition
|
|
68
|
+
* is the abuse — signing in, refreshing a token, an expensive report — and null
|
|
69
|
+
* everywhere else. Volume belongs to whatever sits in front of this process.
|
|
70
|
+
*/
|
|
71
|
+
rateLimit?: (url: URL, req: IncomingMessage) => RatePolicy | null;
|
|
72
|
+
/**
|
|
73
|
+
* Where request-level records go.
|
|
74
|
+
*
|
|
75
|
+
* Without one, a 500 leaves no trace on the server at all: the catch below turns
|
|
76
|
+
* an exception into a JSON body for the client and the stack is discarded.
|
|
77
|
+
*/
|
|
78
|
+
log?: Logger;
|
|
79
|
+
/**
|
|
80
|
+
* Render an error as a page, for a browser that was navigating.
|
|
81
|
+
*
|
|
82
|
+
* Returning null falls back to JSON, which is what a client calling the API
|
|
83
|
+
* wants and what a person who clicked a link never did.
|
|
84
|
+
*/
|
|
85
|
+
renderErrorPage?: (o: {
|
|
86
|
+
code: string;
|
|
87
|
+
status: number;
|
|
88
|
+
url: URL;
|
|
89
|
+
req: IncomingMessage;
|
|
90
|
+
}) => Promise<string | null>;
|
|
27
91
|
/**
|
|
28
92
|
* Which language this request is in. Resolved in one place, like the datastore,
|
|
29
93
|
* so a handler cannot answer in the wrong one by forgetting to pass it along.
|
|
@@ -47,13 +111,27 @@ export type ServeOpts = {
|
|
|
47
111
|
/** Extra routes, matched before the theme takes the request. */
|
|
48
112
|
routes?: Record<string, HttpRoute>;
|
|
49
113
|
pageScope?: (url: URL, req: IncomingMessage) => Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
114
|
+
/**
|
|
115
|
+
* True for a page nobody but the holder of its link should see — a draft
|
|
116
|
+
* behind a preview token, say. The response then carries the three headers
|
|
117
|
+
* that keep it out of a crawler's index, a shared cache, and the referrer of
|
|
118
|
+
* whatever the reader clicks next.
|
|
119
|
+
*/
|
|
120
|
+
pagePrivate?: (url: URL, req: IncomingMessage) => boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Per-site overrides of the theme's tokens, for the stylesheet the framework
|
|
123
|
+
* already links into every page. They land in `ket.app`, which the published
|
|
124
|
+
* layer order already puts above `ket.theme`, so two sites on one theme can
|
|
125
|
+
* differ without either of them forking it.
|
|
126
|
+
*/
|
|
127
|
+
siteTokens?: (url: URL, req: IncomingMessage) => Promise<Record<string, string> | null>;
|
|
50
128
|
/** Theme region returned for progressive GET navigation. */
|
|
51
129
|
pageRegion?: string;
|
|
52
130
|
};
|
|
53
131
|
/**
|
|
54
132
|
* A mount is either a directory, or a function from the rest of the path to an
|
|
55
|
-
* absolute file — which
|
|
56
|
-
* the
|
|
133
|
+
* absolute file — which lets a composed module resolve its own assets without
|
|
134
|
+
* coupling the server to that module's file layout.
|
|
57
135
|
*/
|
|
58
136
|
export type AssetMount = {
|
|
59
137
|
prefix: string;
|
|
@@ -69,6 +147,7 @@ export declare function createKetServer(o: ServeOpts): Promise<{
|
|
|
69
147
|
tail(id: string, fromSeq?: number, opt?: {
|
|
70
148
|
pollMs?: number;
|
|
71
149
|
timeoutMs?: number;
|
|
150
|
+
signal?: AbortSignal;
|
|
72
151
|
}): AsyncGenerator<import("./stream.ts").Chunk>;
|
|
73
152
|
sweep(olderThanMs?: number): Promise<number>;
|
|
74
153
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/http.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/http.ts"],"names":[],"mappings":"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"}
|