@ketvietlab/ketjs 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/agent/capabilities.d.ts +62 -0
- package/dist/agent/capabilities.d.ts.map +1 -0
- package/dist/agent/capabilities.js +89 -0
- package/dist/agent/capabilities.js.map +1 -0
- package/dist/agent/permissions.d.ts +56 -0
- package/dist/agent/permissions.d.ts.map +1 -0
- package/dist/agent/permissions.js +209 -0
- package/dist/agent/permissions.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +698 -0
- package/dist/cli.js.map +1 -0
- package/dist/codegen/dts.d.ts +3 -0
- package/dist/codegen/dts.d.ts.map +1 -0
- package/dist/codegen/dts.js +94 -0
- package/dist/codegen/dts.js.map +1 -0
- package/dist/data/adapter.d.ts +4 -0
- package/dist/data/adapter.d.ts.map +1 -0
- package/dist/data/adapter.js +18 -0
- package/dist/data/adapter.js.map +1 -0
- package/dist/data/changeset.d.ts +49 -0
- package/dist/data/changeset.d.ts.map +1 -0
- package/dist/data/changeset.js +206 -0
- package/dist/data/changeset.js.map +1 -0
- package/dist/data/expr.d.ts +59 -0
- package/dist/data/expr.d.ts.map +1 -0
- package/dist/data/expr.js +61 -0
- package/dist/data/expr.js.map +1 -0
- package/dist/data/fleet.d.ts +28 -0
- package/dist/data/fleet.d.ts.map +1 -0
- package/dist/data/fleet.js +82 -0
- package/dist/data/fleet.js.map +1 -0
- package/dist/data/list-search.d.ts +93 -0
- package/dist/data/list-search.d.ts.map +1 -0
- package/dist/data/list-search.js +268 -0
- package/dist/data/list-search.js.map +1 -0
- package/dist/data/migrate.d.ts +75 -0
- package/dist/data/migrate.d.ts.map +1 -0
- package/dist/data/migrate.js +136 -0
- package/dist/data/migrate.js.map +1 -0
- package/dist/data/pool.d.ts +20 -0
- package/dist/data/pool.d.ts.map +1 -0
- package/dist/data/pool.js +92 -0
- package/dist/data/pool.js.map +1 -0
- package/dist/data/query.d.ts +111 -0
- package/dist/data/query.d.ts.map +1 -0
- package/dist/data/query.js +268 -0
- package/dist/data/query.js.map +1 -0
- package/dist/data/sqlite.d.ts +3 -0
- package/dist/data/sqlite.d.ts.map +1 -0
- package/dist/data/sqlite.js +107 -0
- package/dist/data/sqlite.js.map +1 -0
- package/dist/data/time.d.ts +9 -0
- package/dist/data/time.d.ts.map +1 -0
- package/dist/data/time.js +107 -0
- package/dist/data/time.js.map +1 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/apps.d.ts +43 -0
- package/dist/kernel/apps.d.ts.map +1 -0
- package/dist/kernel/apps.js +234 -0
- package/dist/kernel/apps.js.map +1 -0
- package/dist/kernel/compose.d.ts +6 -0
- package/dist/kernel/compose.d.ts.map +1 -0
- package/dist/kernel/compose.js +976 -0
- package/dist/kernel/compose.js.map +1 -0
- package/dist/kernel/define.d.ts +9 -0
- package/dist/kernel/define.d.ts.map +1 -0
- package/dist/kernel/define.js +140 -0
- package/dist/kernel/define.js.map +1 -0
- package/dist/kernel/diff.d.ts +11 -0
- package/dist/kernel/diff.d.ts.map +1 -0
- package/dist/kernel/diff.js +106 -0
- package/dist/kernel/diff.js.map +1 -0
- package/dist/kernel/errors.d.ts +17 -0
- package/dist/kernel/errors.d.ts.map +1 -0
- package/dist/kernel/errors.js +43 -0
- package/dist/kernel/errors.js.map +1 -0
- package/dist/kernel/graph.d.ts +3 -0
- package/dist/kernel/graph.d.ts.map +1 -0
- package/dist/kernel/graph.js +56 -0
- package/dist/kernel/graph.js.map +1 -0
- package/dist/kernel/i18n.d.ts +43 -0
- package/dist/kernel/i18n.d.ts.map +1 -0
- package/dist/kernel/i18n.js +79 -0
- package/dist/kernel/i18n.js.map +1 -0
- package/dist/kernel/index.d.ts +7 -0
- package/dist/kernel/index.d.ts.map +1 -0
- package/dist/kernel/index.js +7 -0
- package/dist/kernel/index.js.map +1 -0
- package/dist/kernel/layout.d.ts +17 -0
- package/dist/kernel/layout.d.ts.map +1 -0
- package/dist/kernel/layout.js +77 -0
- package/dist/kernel/layout.js.map +1 -0
- package/dist/kernel/menu.d.ts +27 -0
- package/dist/kernel/menu.d.ts.map +1 -0
- package/dist/kernel/menu.js +65 -0
- package/dist/kernel/menu.js.map +1 -0
- package/dist/kernel/modules.d.ts +31 -0
- package/dist/kernel/modules.d.ts.map +1 -0
- package/dist/kernel/modules.js +322 -0
- package/dist/kernel/modules.js.map +1 -0
- package/dist/kernel/routes.d.ts +24 -0
- package/dist/kernel/routes.d.ts.map +1 -0
- package/dist/kernel/routes.js +98 -0
- package/dist/kernel/routes.js.map +1 -0
- package/dist/kernel/types.d.ts +8 -0
- package/dist/kernel/types.d.ts.map +1 -0
- package/dist/kernel/types.js +67 -0
- package/dist/kernel/types.js.map +1 -0
- package/dist/kernel/workspace.d.ts +62 -0
- package/dist/kernel/workspace.d.ts.map +1 -0
- package/dist/kernel/workspace.js +156 -0
- package/dist/kernel/workspace.js.map +1 -0
- package/dist/scaffold/index.d.ts +2 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +49 -0
- package/dist/scaffold/index.js.map +1 -0
- package/dist/scaffold/templates/app.test.ts.tmpl +17 -0
- package/dist/scaffold/templates/biome.json.tmpl +30 -0
- package/dist/scaffold/templates/dev.mjs.tmpl +16 -0
- package/dist/scaffold/templates/gitignore.tmpl +24 -0
- package/dist/scaffold/templates/ket.workspace.ts.tmpl +18 -0
- package/dist/scaffold/templates/module.ts.tmpl +27 -0
- package/dist/scaffold/templates/package.json.tmpl +25 -0
- package/dist/scaffold/templates/tsconfig.json.tmpl +15 -0
- package/dist/server/boot.d.ts +173 -0
- package/dist/server/boot.d.ts.map +1 -0
- package/dist/server/boot.js +659 -0
- package/dist/server/boot.js.map +1 -0
- package/dist/server/config.d.ts +48 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +82 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/ctx.d.ts +13 -0
- package/dist/server/ctx.d.ts.map +1 -0
- package/dist/server/ctx.js +496 -0
- package/dist/server/ctx.js.map +1 -0
- package/dist/server/fn.d.ts +34 -0
- package/dist/server/fn.d.ts.map +1 -0
- package/dist/server/fn.js +170 -0
- package/dist/server/fn.js.map +1 -0
- package/dist/server/http.d.ts +79 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +459 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server/idem.d.ts +31 -0
- package/dist/server/idem.d.ts.map +1 -0
- package/dist/server/idem.js +68 -0
- package/dist/server/idem.js.map +1 -0
- package/dist/server/jobs.d.ts +5 -0
- package/dist/server/jobs.d.ts.map +1 -0
- package/dist/server/jobs.js +24 -0
- package/dist/server/jobs.js.map +1 -0
- package/dist/server/multipart.d.ts +18 -0
- package/dist/server/multipart.d.ts.map +1 -0
- package/dist/server/multipart.js +183 -0
- package/dist/server/multipart.js.map +1 -0
- package/dist/server/project.d.ts +9 -0
- package/dist/server/project.d.ts.map +1 -0
- package/dist/server/project.js +67 -0
- package/dist/server/project.js.map +1 -0
- package/dist/server/queue.d.ts +80 -0
- package/dist/server/queue.d.ts.map +1 -0
- package/dist/server/queue.js +494 -0
- package/dist/server/queue.js.map +1 -0
- package/dist/server/respond.d.ts +91 -0
- package/dist/server/respond.d.ts.map +1 -0
- package/dist/server/respond.js +99 -0
- package/dist/server/respond.js.map +1 -0
- package/dist/server/runtime.d.ts +14 -0
- package/dist/server/runtime.d.ts.map +1 -0
- package/dist/server/runtime.js +25 -0
- package/dist/server/runtime.js.map +1 -0
- package/dist/server/session.d.ts +55 -0
- package/dist/server/session.d.ts.map +1 -0
- package/dist/server/session.js +172 -0
- package/dist/server/session.js.map +1 -0
- package/dist/server/sessionstore.d.ts +54 -0
- package/dist/server/sessionstore.d.ts.map +1 -0
- package/dist/server/sessionstore.js +232 -0
- package/dist/server/sessionstore.js.map +1 -0
- package/dist/server/storage/index.d.ts +11 -0
- package/dist/server/storage/index.d.ts.map +1 -0
- package/dist/server/storage/index.js +31 -0
- package/dist/server/storage/index.js.map +1 -0
- package/dist/server/storage/local.d.ts +5 -0
- package/dist/server/storage/local.d.ts.map +1 -0
- package/dist/server/storage/local.js +165 -0
- package/dist/server/storage/local.js.map +1 -0
- package/dist/server/storage/s3.d.ts +11 -0
- package/dist/server/storage/s3.d.ts.map +1 -0
- package/dist/server/storage/s3.js +133 -0
- package/dist/server/storage/s3.js.map +1 -0
- package/dist/server/storage/sigv4.d.ts +23 -0
- package/dist/server/storage/sigv4.d.ts.map +1 -0
- package/dist/server/storage/sigv4.js +79 -0
- package/dist/server/storage/sigv4.js.map +1 -0
- package/dist/server/storage/types.d.ts +37 -0
- package/dist/server/storage/types.d.ts.map +1 -0
- package/dist/server/storage/types.js +82 -0
- package/dist/server/storage/types.js.map +1 -0
- package/dist/server/stream.d.ts +43 -0
- package/dist/server/stream.d.ts.map +1 -0
- package/dist/server/stream.js +117 -0
- package/dist/server/stream.js.map +1 -0
- package/dist/server/streamstore.d.ts +29 -0
- package/dist/server/streamstore.d.ts.map +1 -0
- package/dist/server/streamstore.js +140 -0
- package/dist/server/streamstore.js.map +1 -0
- package/dist/server/tenants.d.ts +108 -0
- package/dist/server/tenants.d.ts.map +1 -0
- package/dist/server/tenants.js +172 -0
- package/dist/server/tenants.js.map +1 -0
- package/dist/server/transport/index.d.ts +5 -0
- package/dist/server/transport/index.d.ts.map +1 -0
- package/dist/server/transport/index.js +3 -0
- package/dist/server/transport/index.js.map +1 -0
- package/dist/server/transport/memory.d.ts +14 -0
- package/dist/server/transport/memory.d.ts.map +1 -0
- package/dist/server/transport/memory.js +36 -0
- package/dist/server/transport/memory.js.map +1 -0
- package/dist/server/transport/types.d.ts +44 -0
- package/dist/server/transport/types.d.ts.map +1 -0
- package/dist/server/transport/types.js +79 -0
- package/dist/server/transport/types.js.map +1 -0
- package/dist/server/worker.d.ts +33 -0
- package/dist/server/worker.d.ts.map +1 -0
- package/dist/server/worker.js +428 -0
- package/dist/server/worker.js.map +1 -0
- package/dist/testing.d.ts +146 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +406 -0
- package/dist/testing.js.map +1 -0
- package/dist/theme/contracts.d.ts +4 -0
- package/dist/theme/contracts.d.ts.map +1 -0
- package/dist/theme/contracts.js +87 -0
- package/dist/theme/contracts.js.map +1 -0
- package/dist/theme/index.d.ts +8 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +7 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/joints.d.ts +19 -0
- package/dist/theme/joints.d.ts.map +1 -0
- package/dist/theme/joints.js +126 -0
- package/dist/theme/joints.js.map +1 -0
- package/dist/theme/ktl/compile.d.ts +26 -0
- package/dist/theme/ktl/compile.d.ts.map +1 -0
- package/dist/theme/ktl/compile.js +226 -0
- package/dist/theme/ktl/compile.js.map +1 -0
- package/dist/theme/ktl/lexer.d.ts +20 -0
- package/dist/theme/ktl/lexer.d.ts.map +1 -0
- package/dist/theme/ktl/lexer.js +56 -0
- package/dist/theme/ktl/lexer.js.map +1 -0
- package/dist/theme/ktl/parser.d.ts +64 -0
- package/dist/theme/ktl/parser.d.ts.map +1 -0
- package/dist/theme/ktl/parser.js +220 -0
- package/dist/theme/ktl/parser.js.map +1 -0
- package/dist/theme/render.d.ts +19 -0
- package/dist/theme/render.d.ts.map +1 -0
- package/dist/theme/render.js +246 -0
- package/dist/theme/render.js.map +1 -0
- package/dist/theme/templates.d.ts +2 -0
- package/dist/theme/templates.d.ts.map +1 -0
- package/dist/theme/templates.js +40 -0
- package/dist/theme/templates.js.map +1 -0
- package/dist/theme/tokens.d.ts +4 -0
- package/dist/theme/tokens.d.ts.map +1 -0
- package/dist/theme/tokens.js +15 -0
- package/dist/theme/tokens.js.map +1 -0
- package/dist/theme/viewmodel.d.ts +6 -0
- package/dist/theme/viewmodel.d.ts.map +1 -0
- package/dist/theme/viewmodel.js +40 -0
- package/dist/theme/viewmodel.js.map +1 -0
- package/dist/types.d.ts +614 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Umbrella layout: one repository, many deployable apps, shared modules.
|
|
2
|
+
//
|
|
3
|
+
// Elixir's umbrella works because apps declare their dependencies explicitly and
|
|
4
|
+
// share one build. Ket already has the first half — `depends` between modules is
|
|
5
|
+
// `in_umbrella` by another name. This adds the second: several apps composed from
|
|
6
|
+
// overlapping module sets, each with its own routes, theme and agent surface.
|
|
7
|
+
//
|
|
8
|
+
// The classic umbrella failure is the shared database becoming an invisible
|
|
9
|
+
// coupling. Here it is made visible: apps bound to the same datastore get a single
|
|
10
|
+
// union schema, computed and checked at build time, and any disagreement between
|
|
11
|
+
// two apps about the same model is an error rather than a 3am surprise.
|
|
12
|
+
import { compose } from './compose.js';
|
|
13
|
+
import { Diagnostics } from './errors.js';
|
|
14
|
+
import { schemaFromManifest } from '../data/migrate.js';
|
|
15
|
+
export function defineApp(spec) {
|
|
16
|
+
if (!/^[a-z][a-z0-9_]*$/.test(spec.name))
|
|
17
|
+
throw new Error(`invalid app name "${spec.name}"`);
|
|
18
|
+
if (spec.headless && (spec.theme || spec.themes?.length))
|
|
19
|
+
throw new Error(`app "${spec.name}" is headless but installs a theme`);
|
|
20
|
+
const themeNames = [spec.theme, ...(spec.themes ?? [])]
|
|
21
|
+
.filter((theme) => theme !== undefined)
|
|
22
|
+
.map((theme) => (typeof theme === 'string' ? theme : theme.name));
|
|
23
|
+
if (new Set(themeNames).size !== themeNames.length)
|
|
24
|
+
throw new Error(`app "${spec.name}" selects the same theme more than once`);
|
|
25
|
+
if (spec.headless && spec.serve?.pages)
|
|
26
|
+
throw new Error(`app "${spec.name}" is headless but resolves pages`);
|
|
27
|
+
const pageRegion = spec.serve?.pages?.region;
|
|
28
|
+
if (pageRegion && !/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/.test(pageRegion))
|
|
29
|
+
throw new Error(`app "${spec.name}" declares invalid page region "${pageRegion}"`);
|
|
30
|
+
if (spec.worker && !Object.keys(spec.worker.queues).length)
|
|
31
|
+
throw new Error(`app "${spec.name}" declares a worker with no queues`);
|
|
32
|
+
for (const [queue, concurrency] of Object.entries(spec.worker?.queues ?? {})) {
|
|
33
|
+
if (!/^[a-z][a-z0-9_-]*$/.test(queue))
|
|
34
|
+
throw new Error(`app "${spec.name}" has invalid queue "${queue}"`);
|
|
35
|
+
if (!Number.isInteger(concurrency) || concurrency < 1)
|
|
36
|
+
throw new Error(`app "${spec.name}" queue "${queue}" needs concurrency >= 1`);
|
|
37
|
+
}
|
|
38
|
+
return spec;
|
|
39
|
+
}
|
|
40
|
+
export function defineWorkspace(spec) {
|
|
41
|
+
if (!spec || typeof spec !== 'object')
|
|
42
|
+
throw new Error('defineWorkspace() expects an object');
|
|
43
|
+
if (!Array.isArray(spec.apps))
|
|
44
|
+
throw new Error('workspace apps must be an array');
|
|
45
|
+
if (spec.modulePaths !== undefined && !Array.isArray(spec.modulePaths))
|
|
46
|
+
throw new Error('workspace modulePaths must be an array');
|
|
47
|
+
return spec;
|
|
48
|
+
}
|
|
49
|
+
export function composeWorkspace(apps) {
|
|
50
|
+
const diag = new Diagnostics();
|
|
51
|
+
const manifests = {};
|
|
52
|
+
const usedBy = new Map();
|
|
53
|
+
for (const app of apps) {
|
|
54
|
+
const mods = [...app.modules, ...(app.theme ? [app.theme] : []), ...(app.themes ?? [])];
|
|
55
|
+
try {
|
|
56
|
+
manifests[app.name] = compose(mods, {
|
|
57
|
+
appRequires: app.requires ?? [],
|
|
58
|
+
headless: app.headless ?? false,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
diag.add({
|
|
63
|
+
code: 'E_APP_COMPOSE_FAILED',
|
|
64
|
+
module: app.name,
|
|
65
|
+
message: `app "${app.name}" failed to compose: ${e.message}`,
|
|
66
|
+
});
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const configured = app.worker?.queues ?? {};
|
|
70
|
+
for (const [job, meta] of Object.entries(manifests[app.name].jobs)) {
|
|
71
|
+
if (configured[meta.queue])
|
|
72
|
+
continue;
|
|
73
|
+
diag.add({
|
|
74
|
+
code: 'E_APP_JOB_QUEUE_UNCONFIGURED',
|
|
75
|
+
module: app.name,
|
|
76
|
+
message: `app "${app.name}" ships job "${job}" on queue "${meta.queue}" but does not configure that worker queue`,
|
|
77
|
+
hint: `add worker.queues.${meta.queue}, or remove the module that contributes the job`,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
for (const m of mods) {
|
|
81
|
+
const list = usedBy.get(m.name) ?? [];
|
|
82
|
+
list.push(app.name);
|
|
83
|
+
usedBy.set(m.name, list);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
diag.throwIfAny();
|
|
87
|
+
// One union schema per datastore, so the coupling is explicit and checkable.
|
|
88
|
+
const datastores = {};
|
|
89
|
+
for (const app of apps) {
|
|
90
|
+
const store = app.datastore ?? 'main';
|
|
91
|
+
const manifest = manifests[app.name];
|
|
92
|
+
const schema = schemaFromManifest(manifest);
|
|
93
|
+
const slot = (datastores[store] ??= { schema: { version: 1, tables: {} }, apps: [], modules: [] });
|
|
94
|
+
slot.apps.push(app.name);
|
|
95
|
+
for (const m of manifest.order)
|
|
96
|
+
if (!slot.modules.includes(m))
|
|
97
|
+
slot.modules.push(m);
|
|
98
|
+
for (const [tname, table] of Object.entries(schema.tables)) {
|
|
99
|
+
const existing = slot.schema.tables[tname];
|
|
100
|
+
if (!existing) {
|
|
101
|
+
slot.schema.tables[tname] = structuredClone(table);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (existing.model !== table.model) {
|
|
105
|
+
diag.add({
|
|
106
|
+
code: 'E_DATASTORE_MODEL_CLASH',
|
|
107
|
+
module: app.name,
|
|
108
|
+
message: `datastore "${store}": table "${tname}" is "${existing.model}" in another app but "${table.model}" in "${app.name}"`,
|
|
109
|
+
hint: 'rename one of the models, or bind the apps to different datastores',
|
|
110
|
+
});
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
for (const [cname, col] of Object.entries(table.columns)) {
|
|
114
|
+
const before = existing.columns[cname];
|
|
115
|
+
if (!before) {
|
|
116
|
+
existing.columns[cname] = { ...col };
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (before.base !== col.base || before.by !== col.by) {
|
|
120
|
+
diag.add({
|
|
121
|
+
code: 'E_DATASTORE_COLUMN_CLASH',
|
|
122
|
+
module: app.name,
|
|
123
|
+
message: `datastore "${store}": column "${tname}.${cname}" is ${before.base} (from ${before.by}) elsewhere but ${col.base} (from ${col.by}) in "${app.name}"`,
|
|
124
|
+
hint: 'both apps must install the same version of the contributing module',
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
diag.throwIfAny();
|
|
131
|
+
const shared = [];
|
|
132
|
+
const soloed = {};
|
|
133
|
+
for (const [mod, list] of usedBy) {
|
|
134
|
+
if (list.length > 1)
|
|
135
|
+
shared.push(mod);
|
|
136
|
+
else
|
|
137
|
+
(soloed[list[0]] ??= []).push(mod);
|
|
138
|
+
}
|
|
139
|
+
return { apps: manifests, datastores, shared: shared.sort(), soloed };
|
|
140
|
+
}
|
|
141
|
+
export function explainWorkspace(ws) {
|
|
142
|
+
const lines = [];
|
|
143
|
+
lines.push('apps:');
|
|
144
|
+
for (const [name, m] of Object.entries(ws.apps)) {
|
|
145
|
+
lines.push(` ${name.padEnd(14)} modules=${m.order.length} fns=${Object.keys(m.functions).length} jobs=${Object.keys(m.jobs).length} regions=${m.regions.required.length}`);
|
|
146
|
+
}
|
|
147
|
+
lines.push('datastores:');
|
|
148
|
+
for (const [name, ds] of Object.entries(ws.datastores)) {
|
|
149
|
+
lines.push(` ${name.padEnd(14)} tables=${Object.keys(ds.schema.tables).length} shared by: ${ds.apps.join(', ')}`);
|
|
150
|
+
}
|
|
151
|
+
lines.push(`shared modules: ${ws.shared.join(', ') || '(none)'}`);
|
|
152
|
+
for (const [app, mods] of Object.entries(ws.soloed))
|
|
153
|
+
lines.push(` only in ${app}: ${mods.join(', ')}`);
|
|
154
|
+
return lines.join('\n');
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/kernel/workspace.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/scaffold/index.ts"],"names":[],"mappings":"AAmCA,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAqB5D"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// `ket new` — the smallest thing that is still a real app.
|
|
2
|
+
//
|
|
3
|
+
// A scaffold earns its place only if what it emits runs unedited, so this writes a
|
|
4
|
+
// module with a model and a function, an app that serves it, and a workspace file
|
|
5
|
+
// the CLI finds by convention. Nothing is a placeholder waiting to be filled in.
|
|
6
|
+
//
|
|
7
|
+
// The templates are files rather than string literals on purpose. A literal
|
|
8
|
+
// containing `from '@ketvietlab/ketjs'` is indistinguishable, to anything reading the source,
|
|
9
|
+
// from an actual import — and the dependency audit reads the source. Keeping them
|
|
10
|
+
// out of the .ts files makes "this is data, not code" a shape rather than an
|
|
11
|
+
// exception someone has to remember.
|
|
12
|
+
import { mkdirSync, writeFileSync, existsSync, readFileSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
const VERSION = '0.1.1';
|
|
15
|
+
const TEMPLATES = new URL('./templates/', import.meta.url);
|
|
16
|
+
/** Template file → path it is written to, relative to the new app's directory. */
|
|
17
|
+
const LAYOUT = [
|
|
18
|
+
['package.json.tmpl', () => 'package.json'],
|
|
19
|
+
['module.ts.tmpl', (n) => `modules/${n}.ts`],
|
|
20
|
+
['ket.workspace.ts.tmpl', () => 'ket.workspace.ts'],
|
|
21
|
+
['tsconfig.json.tmpl', () => 'tsconfig.json'],
|
|
22
|
+
['biome.json.tmpl', () => 'biome.json'],
|
|
23
|
+
['dev.mjs.tmpl', () => 'tools/dev.mjs'],
|
|
24
|
+
['app.test.ts.tmpl', () => 'test/app.test.ts'],
|
|
25
|
+
['gitignore.tmpl', () => '.gitignore'],
|
|
26
|
+
];
|
|
27
|
+
const render = (template, name) => readFileSync(new URL(template, TEMPLATES), 'utf8')
|
|
28
|
+
.replaceAll('__NAME__', name)
|
|
29
|
+
.replaceAll('__VERSION__', VERSION);
|
|
30
|
+
export function scaffold(name, dir) {
|
|
31
|
+
if (!/^[a-z][a-z0-9_]*$/.test(name)) {
|
|
32
|
+
throw new Error(`invalid app name "${name}" — lowercase letters, digits and underscore, starting with a letter`);
|
|
33
|
+
}
|
|
34
|
+
const written = LAYOUT.map(([tpl, to]) => [to(name), render(tpl, name)]);
|
|
35
|
+
// Refuse rather than overwrite: a scaffold that can eat work is not a scaffold.
|
|
36
|
+
const clashes = written.map(([p]) => p).filter((p) => existsSync(join(dir, p)));
|
|
37
|
+
if (clashes.length)
|
|
38
|
+
throw new Error(`refusing to overwrite: ${clashes.map((p) => join(dir, p)).join(', ')}`);
|
|
39
|
+
const out = [];
|
|
40
|
+
for (const [path, body] of written) {
|
|
41
|
+
const full = join(dir, path);
|
|
42
|
+
mkdirSync(join(full, '..'), { recursive: true });
|
|
43
|
+
writeFileSync(full, body);
|
|
44
|
+
out.push(` wrote ${full}`);
|
|
45
|
+
}
|
|
46
|
+
out.push('', ` cd ${dir} && npm install && npm run dev`);
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/scaffold/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { test } from 'node:test'
|
|
3
|
+
import { createTestApp } from '@ketvietlab/ketjs/testing'
|
|
4
|
+
import { app } from '../ket.workspace.ts'
|
|
5
|
+
|
|
6
|
+
test('__NAME__: the function is reachable through real HTTP', async () => {
|
|
7
|
+
const e2e = await createTestApp(app, {
|
|
8
|
+
worker: false,
|
|
9
|
+
client: { company: 'test' },
|
|
10
|
+
})
|
|
11
|
+
try {
|
|
12
|
+
const result = await e2e.client.call<unknown[]>('__NAME__.list')
|
|
13
|
+
assert.deepEqual(result.value, [])
|
|
14
|
+
} finally {
|
|
15
|
+
await e2e.close()
|
|
16
|
+
}
|
|
17
|
+
})
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.5.9/schema.json",
|
|
3
|
+
"vcs": {
|
|
4
|
+
"enabled": true,
|
|
5
|
+
"clientKind": "git",
|
|
6
|
+
"useIgnoreFile": true
|
|
7
|
+
},
|
|
8
|
+
"files": {
|
|
9
|
+
"includes": ["**"],
|
|
10
|
+
"ignoreUnknown": true
|
|
11
|
+
},
|
|
12
|
+
"formatter": {
|
|
13
|
+
"indentStyle": "space",
|
|
14
|
+
"indentWidth": 2,
|
|
15
|
+
"lineWidth": 110
|
|
16
|
+
},
|
|
17
|
+
"javascript": {
|
|
18
|
+
"jsxRuntime": "transparent",
|
|
19
|
+
"formatter": {
|
|
20
|
+
"quoteStyle": "single",
|
|
21
|
+
"semicolons": "asNeeded",
|
|
22
|
+
"trailingCommas": "all"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"linter": {
|
|
26
|
+
"rules": {
|
|
27
|
+
"preset": "recommended"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// `tsx watch` reruns this entry in memory; production still uses built artifacts.
|
|
2
|
+
import { spawnSync } from 'node:child_process'
|
|
3
|
+
|
|
4
|
+
const check = spawnSync(
|
|
5
|
+
process.execPath,
|
|
6
|
+
['node_modules/typescript/bin/tsc', '-p', 'tsconfig.json', '--noEmit'],
|
|
7
|
+
{ stdio: 'inherit' },
|
|
8
|
+
)
|
|
9
|
+
if (check.error) throw check.error
|
|
10
|
+
if (check.status !== 0) {
|
|
11
|
+
process.exitCode = check.status ?? 1
|
|
12
|
+
} else {
|
|
13
|
+
process.env.KET_DEV = '1'
|
|
14
|
+
process.env.KET_DEV_SOURCE = '1'
|
|
15
|
+
await import('../node_modules/ketjs/dist/cli.js')
|
|
16
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
|
|
4
|
+
# Build artifacts
|
|
5
|
+
dist/
|
|
6
|
+
|
|
7
|
+
# Ket runtime state
|
|
8
|
+
.ket/
|
|
9
|
+
*.db
|
|
10
|
+
*.db-journal
|
|
11
|
+
*.db-shm
|
|
12
|
+
*.db-wal
|
|
13
|
+
*.sqlite
|
|
14
|
+
|
|
15
|
+
# Local configuration and logs
|
|
16
|
+
.env
|
|
17
|
+
.env.*
|
|
18
|
+
!.env.example
|
|
19
|
+
*.log
|
|
20
|
+
|
|
21
|
+
# Editors and operating systems
|
|
22
|
+
.idea/
|
|
23
|
+
.vscode/
|
|
24
|
+
.DS_Store
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineApp, json } from '@ketvietlab/ketjs'
|
|
2
|
+
import __NAME__ from './modules/__NAME__.ts'
|
|
3
|
+
|
|
4
|
+
// One codebase, many apps. `ket serve` runs the first one that declares `serve`.
|
|
5
|
+
export const app = defineApp({
|
|
6
|
+
name: '__NAME__',
|
|
7
|
+
modules: [__NAME__],
|
|
8
|
+
headless: true,
|
|
9
|
+
serve: {
|
|
10
|
+
// Installed on an empty database so a first run has something to look at.
|
|
11
|
+
bootstrap: ['__NAME__'],
|
|
12
|
+
routes: (ctx) => ({
|
|
13
|
+
'/': async (url, req) => json(await ctx.call('__NAME__.list', {}, url, req)),
|
|
14
|
+
}),
|
|
15
|
+
},
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export const apps = [app]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineModule, from } from '@ketvietlab/ketjs'
|
|
2
|
+
|
|
3
|
+
// A module is the unit of contribution: models, functions, sections and messages
|
|
4
|
+
// declared together, composable with anyone else's. `install` is the boundary it
|
|
5
|
+
// draws — 'manual' means nothing installs it but a person asking for it by name.
|
|
6
|
+
export default defineModule({
|
|
7
|
+
name: '__NAME__',
|
|
8
|
+
app: true,
|
|
9
|
+
title: '__NAME__',
|
|
10
|
+
install: 'manual',
|
|
11
|
+
models: {
|
|
12
|
+
Note: {
|
|
13
|
+
scope: 'company',
|
|
14
|
+
fields: { id: 'id', title: 'text', body: 'text?' },
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
functions: {
|
|
18
|
+
list: {
|
|
19
|
+
agent: true,
|
|
20
|
+
effects: ['read:__NAME__.Note'],
|
|
21
|
+
handler: (ctx) => ctx.db.all(from(ctx.table('__NAME__.Note'))),
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
messages: {
|
|
25
|
+
en: { 'app.title': '__NAME__', 'page.notFound': 'Page not found' },
|
|
26
|
+
},
|
|
27
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"version": "0.0.0",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc -p tsconfig.json",
|
|
8
|
+
"dev": "tsx watch --clear-screen=false tools/dev.mjs serve --workspace ket.workspace.ts",
|
|
9
|
+
"start": "npm run build && ket serve --workspace dist/ket.workspace.js",
|
|
10
|
+
"test": "npm run build && ket test dist/test",
|
|
11
|
+
"test:watch": "ket test dist/test --watch",
|
|
12
|
+
"check": "tsc -p tsconfig.json --noEmit && biome check . && npm run build && ket check --workspace dist/ket.workspace.js",
|
|
13
|
+
"format": "biome format --write .",
|
|
14
|
+
"lint": "biome lint ."
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@ketvietlab/ketjs": "^__VERSION__"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@biomejs/biome": "2.5.9",
|
|
21
|
+
"@types/node": "^26.2.0",
|
|
22
|
+
"tsx": "4.23.12",
|
|
23
|
+
"typescript": "^7.0.2"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"module": "nodenext",
|
|
5
|
+
"moduleResolution": "nodenext",
|
|
6
|
+
"rootDir": ".",
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"verbatimModuleSyntax": true,
|
|
10
|
+
"rewriteRelativeImportExtensions": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"types": ["node"]
|
|
13
|
+
},
|
|
14
|
+
"include": ["ket.workspace.ts", "modules/**/*.ts", "modules/**/*.tsx", "test/**/*.ts"]
|
|
15
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type { MenuNode } from '../kernel/menu.ts';
|
|
2
|
+
import type { Markup } from '@ketvietlab/ketjs-view';
|
|
3
|
+
import type { Tenants, TenantSpec } from './tenants.ts';
|
|
4
|
+
import type { AppInfo } from '../kernel/apps.ts';
|
|
5
|
+
import type { SessionContext, Sessions, SessionOptions, SessionRecord } from './session.ts';
|
|
6
|
+
import type { RuntimeConfig, OpenStore } from './config.ts';
|
|
7
|
+
import type { OpenStorage, Storage } from './storage/index.ts';
|
|
8
|
+
import type { OpenTransport } from './transport/index.ts';
|
|
9
|
+
import type { AppSpec } from '../kernel/workspace.ts';
|
|
10
|
+
import type { AppRegistry } from '../kernel/apps.ts';
|
|
11
|
+
import type { Translator } from '../kernel/i18n.ts';
|
|
12
|
+
import type { Adapter, Manifest, Scope } from '../types.ts';
|
|
13
|
+
import type { IncomingMessage } from 'node:http';
|
|
14
|
+
import type { RouteParams } from '../kernel/routes.ts';
|
|
15
|
+
export type { Html, RouteResult } from './respond.ts';
|
|
16
|
+
export { page, fragment, navigablePage, isNavigationRequest, text, bytes, streamed, raw, withHeaders, } from './respond.ts';
|
|
17
|
+
export { json } from './respond.ts';
|
|
18
|
+
import type { Html, RouteResult } from './respond.ts';
|
|
19
|
+
export type Route = (url: URL, req: IncomingMessage, params: RouteParams) => Promise<RouteResult> | RouteResult;
|
|
20
|
+
/**
|
|
21
|
+
* What a route needs that only the running server has. Handed to `serve.routes` so
|
|
22
|
+
* an app's screens can read live state without reaching for module-level globals.
|
|
23
|
+
*/
|
|
24
|
+
export type ServeContext = {
|
|
25
|
+
/** Everything this deployment ships, installed or not. */
|
|
26
|
+
manifest: Manifest;
|
|
27
|
+
/**
|
|
28
|
+
* Restricted to what is switched on for THIS request's tenant.
|
|
29
|
+
*
|
|
30
|
+
* It takes the request because the answer depends on it. Computing it once at
|
|
31
|
+
* boot is what would show one tenant the module set of another — and that does
|
|
32
|
+
* not fail, it answers wrongly, which is worse.
|
|
33
|
+
*/
|
|
34
|
+
live: (req: IncomingMessage) => Promise<Manifest>;
|
|
35
|
+
/** The app list for this request's tenant. The registry itself stays leased. */
|
|
36
|
+
appsOf: (req: IncomingMessage) => Promise<AppInfo[]>;
|
|
37
|
+
config: RuntimeConfig;
|
|
38
|
+
scopeOf: (url: URL, req: IncomingMessage) => Promise<Scope>;
|
|
39
|
+
localeOf: (url: URL, req: IncomingMessage) => string;
|
|
40
|
+
translate: (locale: string) => Translator;
|
|
41
|
+
/** A function call carrying this request's tenant, live manifest and scope. */
|
|
42
|
+
call: (name: string, input: Record<string, unknown>, url: URL, req: IncomingMessage) => Promise<unknown>;
|
|
43
|
+
/**
|
|
44
|
+
* The same call with the permission check off.
|
|
45
|
+
*
|
|
46
|
+
* Named so it is one word to grep for, like `raw`. It exists because deciding
|
|
47
|
+
* *what* a caller may do is itself a question someone has to be allowed to ask:
|
|
48
|
+
* a permission resolver that went through the check would be asking permission
|
|
49
|
+
* to find out whether it has permission. Nothing else has that excuse.
|
|
50
|
+
*/
|
|
51
|
+
callUnchecked: (name: string, input: Record<string, unknown>, url: URL, req: IncomingMessage) => Promise<unknown>;
|
|
52
|
+
/** The document every screen sits in. Markup, not a string — see respond.ts. */
|
|
53
|
+
document: (o: {
|
|
54
|
+
lang: string;
|
|
55
|
+
title?: string;
|
|
56
|
+
head?: Html;
|
|
57
|
+
body: Html;
|
|
58
|
+
}) => Html;
|
|
59
|
+
/** Installed modules' stylesheets for this tenant, in dependency order. */
|
|
60
|
+
styles: (req: IncomingMessage) => Promise<Html>;
|
|
61
|
+
/**
|
|
62
|
+
* Render an extension point: every installed module's fills, in dependency
|
|
63
|
+
* order, as markup a template inserts verbatim.
|
|
64
|
+
*
|
|
65
|
+
* Empty when nobody fills it, and empty when an installed module omitted it.
|
|
66
|
+
*/
|
|
67
|
+
joint: (url: URL, req: IncomingMessage, key: string, props?: Record<string, unknown>) => Promise<Markup>;
|
|
68
|
+
/** False when an installed module omitted this joint — see jointShows in screens. */
|
|
69
|
+
jointShows: (url: URL, req: IncomingMessage, key: string) => Promise<boolean>;
|
|
70
|
+
/**
|
|
71
|
+
* The navigation tree as this viewer sees it: what the deployment ships, what
|
|
72
|
+
* this database has switched on, and what this request may call — in that order,
|
|
73
|
+
* because each filter depends on the one before.
|
|
74
|
+
*/
|
|
75
|
+
menu: (url: URL, req: IncomingMessage) => Promise<MenuNode[]>;
|
|
76
|
+
/**
|
|
77
|
+
* This request's sessions. A function because with subdomain tenants they live
|
|
78
|
+
* in that tenant's database — one per tenant, not one per deployment.
|
|
79
|
+
*/
|
|
80
|
+
sessionsOf: (url: URL, req: IncomingMessage) => Promise<Sessions | null>;
|
|
81
|
+
/** Blob storage isolated to this request's tenant. */
|
|
82
|
+
storageOf: (url: URL, req: IncomingMessage) => Promise<Storage>;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* How a path becomes a page. The resolver is named rather than passed, so the
|
|
86
|
+
* framework never learns which module provides pages — swap the module and this
|
|
87
|
+
* one string changes.
|
|
88
|
+
*
|
|
89
|
+
* The named function takes `{ path }` and returns null, or a row with `title` and
|
|
90
|
+
* `layout` (the sections, as an array or as the JSON the database gave back).
|
|
91
|
+
*/
|
|
92
|
+
export type PagesSpec = {
|
|
93
|
+
resolve: string;
|
|
94
|
+
/** Optional function taking `{ host }` and returning site id, title, locale and theme. */
|
|
95
|
+
siteResolve?: string;
|
|
96
|
+
/** Theme region whose host carries the same data-ket-slot name. */
|
|
97
|
+
region?: string;
|
|
98
|
+
/** Message key for the title of a path that has no page. */
|
|
99
|
+
notFound?: string;
|
|
100
|
+
siteTitle?: string;
|
|
101
|
+
};
|
|
102
|
+
export type SessionResolveContext = {
|
|
103
|
+
adapter: Adapter;
|
|
104
|
+
manifest: Manifest;
|
|
105
|
+
record: SessionRecord;
|
|
106
|
+
url: URL;
|
|
107
|
+
req: IncomingMessage;
|
|
108
|
+
};
|
|
109
|
+
export type ServeSpec = {
|
|
110
|
+
pages?: PagesSpec;
|
|
111
|
+
assets?: {
|
|
112
|
+
prefix: string;
|
|
113
|
+
dir: string;
|
|
114
|
+
};
|
|
115
|
+
/** Installed on an empty database so a first run has something to look at. */
|
|
116
|
+
bootstrap?: string[];
|
|
117
|
+
routes?: (ctx: ServeContext) => Record<string, Route>;
|
|
118
|
+
/** Anything other than SQLite; the framework cannot depend on a driver. */
|
|
119
|
+
openStore?: OpenStore;
|
|
120
|
+
/** Override the built-in local/S3 storage selected by RuntimeConfig. */
|
|
121
|
+
openStorage?: OpenStorage;
|
|
122
|
+
/** Inject a deployment-owned outbound provider for durable worker jobs. */
|
|
123
|
+
openTransport?: OpenTransport;
|
|
124
|
+
/**
|
|
125
|
+
* Turn on sessions. Present means the X-Ket-Company shim is gone and identity
|
|
126
|
+
* comes from a signed cookie; absent means the shim stays and the banner says so.
|
|
127
|
+
*/
|
|
128
|
+
sessions?: Omit<SessionOptions, 'store'> & {
|
|
129
|
+
store?: SessionOptions['store'];
|
|
130
|
+
};
|
|
131
|
+
/** Revalidate live account state and memberships before scope and permissions. */
|
|
132
|
+
resolveSession?: (ctx: SessionResolveContext) => Promise<SessionContext | null>;
|
|
133
|
+
/**
|
|
134
|
+
* Serve several tenants, one database each — Odoo's model, and the one that
|
|
135
|
+
* makes per-tenant module sets work. Absent, the app has a single datastore.
|
|
136
|
+
*/
|
|
137
|
+
tenants?: TenantSpec;
|
|
138
|
+
/**
|
|
139
|
+
* Which functions a signed-in user may call. Absent means no restriction, which
|
|
140
|
+
* is what an app without roles is. Returning a list restricts every call the
|
|
141
|
+
* request makes, including the ones a route makes on its behalf.
|
|
142
|
+
*/
|
|
143
|
+
permissions?: (ctx: ServeContext, userId: string) => Promise<readonly string[] | null>;
|
|
144
|
+
defaults?: Partial<RuntimeConfig>;
|
|
145
|
+
};
|
|
146
|
+
export type BootedApp = {
|
|
147
|
+
name: string;
|
|
148
|
+
manifest: Manifest;
|
|
149
|
+
/** The datastore, when there is exactly one. Null when the app serves tenants. */
|
|
150
|
+
adapter: Adapter | null;
|
|
151
|
+
/** Likewise: with tenants, "which apps" is a question about a tenant. */
|
|
152
|
+
apps: AppRegistry | null;
|
|
153
|
+
/** Per-tenant access, and the only form that works in both modes. */
|
|
154
|
+
tenants: Tenants;
|
|
155
|
+
config: RuntimeConfig;
|
|
156
|
+
port: number;
|
|
157
|
+
banner: () => Promise<string>;
|
|
158
|
+
close: () => Promise<void>;
|
|
159
|
+
};
|
|
160
|
+
export type BootAppOptions = {
|
|
161
|
+
env?: Record<string, string | undefined>;
|
|
162
|
+
port?: number;
|
|
163
|
+
/** Boot progress. Long-running serve keeps its banner separate. */
|
|
164
|
+
log?: (line: string) => void;
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Opens, migrates, installs, serves. Returns before listening is announced so a
|
|
168
|
+
* caller can print its own banner, or a test can boot on port 0 and never print.
|
|
169
|
+
*/
|
|
170
|
+
export declare function bootApp(spec: AppSpec, o?: BootAppOptions): Promise<BootedApp>;
|
|
171
|
+
/** bootApp, plus the banner and the signal handling a long-running process wants. */
|
|
172
|
+
export declare function serveApp(spec: AppSpec, o?: BootAppOptions): Promise<BootedApp>;
|
|
173
|
+
//# sourceMappingURL=boot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/boot.ts"],"names":[],"mappings":"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"}
|