@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.
Files changed (283) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +36 -0
  3. package/dist/agent/capabilities.d.ts +62 -0
  4. package/dist/agent/capabilities.d.ts.map +1 -0
  5. package/dist/agent/capabilities.js +89 -0
  6. package/dist/agent/capabilities.js.map +1 -0
  7. package/dist/agent/permissions.d.ts +56 -0
  8. package/dist/agent/permissions.d.ts.map +1 -0
  9. package/dist/agent/permissions.js +209 -0
  10. package/dist/agent/permissions.js.map +1 -0
  11. package/dist/cli.d.ts +3 -0
  12. package/dist/cli.d.ts.map +1 -0
  13. package/dist/cli.js +698 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/codegen/dts.d.ts +3 -0
  16. package/dist/codegen/dts.d.ts.map +1 -0
  17. package/dist/codegen/dts.js +94 -0
  18. package/dist/codegen/dts.js.map +1 -0
  19. package/dist/data/adapter.d.ts +4 -0
  20. package/dist/data/adapter.d.ts.map +1 -0
  21. package/dist/data/adapter.js +18 -0
  22. package/dist/data/adapter.js.map +1 -0
  23. package/dist/data/changeset.d.ts +49 -0
  24. package/dist/data/changeset.d.ts.map +1 -0
  25. package/dist/data/changeset.js +206 -0
  26. package/dist/data/changeset.js.map +1 -0
  27. package/dist/data/expr.d.ts +59 -0
  28. package/dist/data/expr.d.ts.map +1 -0
  29. package/dist/data/expr.js +61 -0
  30. package/dist/data/expr.js.map +1 -0
  31. package/dist/data/fleet.d.ts +28 -0
  32. package/dist/data/fleet.d.ts.map +1 -0
  33. package/dist/data/fleet.js +82 -0
  34. package/dist/data/fleet.js.map +1 -0
  35. package/dist/data/list-search.d.ts +93 -0
  36. package/dist/data/list-search.d.ts.map +1 -0
  37. package/dist/data/list-search.js +268 -0
  38. package/dist/data/list-search.js.map +1 -0
  39. package/dist/data/migrate.d.ts +75 -0
  40. package/dist/data/migrate.d.ts.map +1 -0
  41. package/dist/data/migrate.js +136 -0
  42. package/dist/data/migrate.js.map +1 -0
  43. package/dist/data/pool.d.ts +20 -0
  44. package/dist/data/pool.d.ts.map +1 -0
  45. package/dist/data/pool.js +92 -0
  46. package/dist/data/pool.js.map +1 -0
  47. package/dist/data/query.d.ts +111 -0
  48. package/dist/data/query.d.ts.map +1 -0
  49. package/dist/data/query.js +268 -0
  50. package/dist/data/query.js.map +1 -0
  51. package/dist/data/sqlite.d.ts +3 -0
  52. package/dist/data/sqlite.d.ts.map +1 -0
  53. package/dist/data/sqlite.js +107 -0
  54. package/dist/data/sqlite.js.map +1 -0
  55. package/dist/data/time.d.ts +9 -0
  56. package/dist/data/time.d.ts.map +1 -0
  57. package/dist/data/time.js +107 -0
  58. package/dist/data/time.js.map +1 -0
  59. package/dist/index.d.ts +79 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +51 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/kernel/apps.d.ts +43 -0
  64. package/dist/kernel/apps.d.ts.map +1 -0
  65. package/dist/kernel/apps.js +234 -0
  66. package/dist/kernel/apps.js.map +1 -0
  67. package/dist/kernel/compose.d.ts +6 -0
  68. package/dist/kernel/compose.d.ts.map +1 -0
  69. package/dist/kernel/compose.js +976 -0
  70. package/dist/kernel/compose.js.map +1 -0
  71. package/dist/kernel/define.d.ts +9 -0
  72. package/dist/kernel/define.d.ts.map +1 -0
  73. package/dist/kernel/define.js +140 -0
  74. package/dist/kernel/define.js.map +1 -0
  75. package/dist/kernel/diff.d.ts +11 -0
  76. package/dist/kernel/diff.d.ts.map +1 -0
  77. package/dist/kernel/diff.js +106 -0
  78. package/dist/kernel/diff.js.map +1 -0
  79. package/dist/kernel/errors.d.ts +17 -0
  80. package/dist/kernel/errors.d.ts.map +1 -0
  81. package/dist/kernel/errors.js +43 -0
  82. package/dist/kernel/errors.js.map +1 -0
  83. package/dist/kernel/graph.d.ts +3 -0
  84. package/dist/kernel/graph.d.ts.map +1 -0
  85. package/dist/kernel/graph.js +56 -0
  86. package/dist/kernel/graph.js.map +1 -0
  87. package/dist/kernel/i18n.d.ts +43 -0
  88. package/dist/kernel/i18n.d.ts.map +1 -0
  89. package/dist/kernel/i18n.js +79 -0
  90. package/dist/kernel/i18n.js.map +1 -0
  91. package/dist/kernel/index.d.ts +7 -0
  92. package/dist/kernel/index.d.ts.map +1 -0
  93. package/dist/kernel/index.js +7 -0
  94. package/dist/kernel/index.js.map +1 -0
  95. package/dist/kernel/layout.d.ts +17 -0
  96. package/dist/kernel/layout.d.ts.map +1 -0
  97. package/dist/kernel/layout.js +77 -0
  98. package/dist/kernel/layout.js.map +1 -0
  99. package/dist/kernel/menu.d.ts +27 -0
  100. package/dist/kernel/menu.d.ts.map +1 -0
  101. package/dist/kernel/menu.js +65 -0
  102. package/dist/kernel/menu.js.map +1 -0
  103. package/dist/kernel/modules.d.ts +31 -0
  104. package/dist/kernel/modules.d.ts.map +1 -0
  105. package/dist/kernel/modules.js +322 -0
  106. package/dist/kernel/modules.js.map +1 -0
  107. package/dist/kernel/routes.d.ts +24 -0
  108. package/dist/kernel/routes.d.ts.map +1 -0
  109. package/dist/kernel/routes.js +98 -0
  110. package/dist/kernel/routes.js.map +1 -0
  111. package/dist/kernel/types.d.ts +8 -0
  112. package/dist/kernel/types.d.ts.map +1 -0
  113. package/dist/kernel/types.js +67 -0
  114. package/dist/kernel/types.js.map +1 -0
  115. package/dist/kernel/workspace.d.ts +62 -0
  116. package/dist/kernel/workspace.d.ts.map +1 -0
  117. package/dist/kernel/workspace.js +156 -0
  118. package/dist/kernel/workspace.js.map +1 -0
  119. package/dist/scaffold/index.d.ts +2 -0
  120. package/dist/scaffold/index.d.ts.map +1 -0
  121. package/dist/scaffold/index.js +49 -0
  122. package/dist/scaffold/index.js.map +1 -0
  123. package/dist/scaffold/templates/app.test.ts.tmpl +17 -0
  124. package/dist/scaffold/templates/biome.json.tmpl +30 -0
  125. package/dist/scaffold/templates/dev.mjs.tmpl +16 -0
  126. package/dist/scaffold/templates/gitignore.tmpl +24 -0
  127. package/dist/scaffold/templates/ket.workspace.ts.tmpl +18 -0
  128. package/dist/scaffold/templates/module.ts.tmpl +27 -0
  129. package/dist/scaffold/templates/package.json.tmpl +25 -0
  130. package/dist/scaffold/templates/tsconfig.json.tmpl +15 -0
  131. package/dist/server/boot.d.ts +173 -0
  132. package/dist/server/boot.d.ts.map +1 -0
  133. package/dist/server/boot.js +659 -0
  134. package/dist/server/boot.js.map +1 -0
  135. package/dist/server/config.d.ts +48 -0
  136. package/dist/server/config.d.ts.map +1 -0
  137. package/dist/server/config.js +82 -0
  138. package/dist/server/config.js.map +1 -0
  139. package/dist/server/ctx.d.ts +13 -0
  140. package/dist/server/ctx.d.ts.map +1 -0
  141. package/dist/server/ctx.js +496 -0
  142. package/dist/server/ctx.js.map +1 -0
  143. package/dist/server/fn.d.ts +34 -0
  144. package/dist/server/fn.d.ts.map +1 -0
  145. package/dist/server/fn.js +170 -0
  146. package/dist/server/fn.js.map +1 -0
  147. package/dist/server/http.d.ts +79 -0
  148. package/dist/server/http.d.ts.map +1 -0
  149. package/dist/server/http.js +459 -0
  150. package/dist/server/http.js.map +1 -0
  151. package/dist/server/idem.d.ts +31 -0
  152. package/dist/server/idem.d.ts.map +1 -0
  153. package/dist/server/idem.js +68 -0
  154. package/dist/server/idem.js.map +1 -0
  155. package/dist/server/jobs.d.ts +5 -0
  156. package/dist/server/jobs.d.ts.map +1 -0
  157. package/dist/server/jobs.js +24 -0
  158. package/dist/server/jobs.js.map +1 -0
  159. package/dist/server/multipart.d.ts +18 -0
  160. package/dist/server/multipart.d.ts.map +1 -0
  161. package/dist/server/multipart.js +183 -0
  162. package/dist/server/multipart.js.map +1 -0
  163. package/dist/server/project.d.ts +9 -0
  164. package/dist/server/project.d.ts.map +1 -0
  165. package/dist/server/project.js +67 -0
  166. package/dist/server/project.js.map +1 -0
  167. package/dist/server/queue.d.ts +80 -0
  168. package/dist/server/queue.d.ts.map +1 -0
  169. package/dist/server/queue.js +494 -0
  170. package/dist/server/queue.js.map +1 -0
  171. package/dist/server/respond.d.ts +91 -0
  172. package/dist/server/respond.d.ts.map +1 -0
  173. package/dist/server/respond.js +99 -0
  174. package/dist/server/respond.js.map +1 -0
  175. package/dist/server/runtime.d.ts +14 -0
  176. package/dist/server/runtime.d.ts.map +1 -0
  177. package/dist/server/runtime.js +25 -0
  178. package/dist/server/runtime.js.map +1 -0
  179. package/dist/server/session.d.ts +55 -0
  180. package/dist/server/session.d.ts.map +1 -0
  181. package/dist/server/session.js +172 -0
  182. package/dist/server/session.js.map +1 -0
  183. package/dist/server/sessionstore.d.ts +54 -0
  184. package/dist/server/sessionstore.d.ts.map +1 -0
  185. package/dist/server/sessionstore.js +232 -0
  186. package/dist/server/sessionstore.js.map +1 -0
  187. package/dist/server/storage/index.d.ts +11 -0
  188. package/dist/server/storage/index.d.ts.map +1 -0
  189. package/dist/server/storage/index.js +31 -0
  190. package/dist/server/storage/index.js.map +1 -0
  191. package/dist/server/storage/local.d.ts +5 -0
  192. package/dist/server/storage/local.d.ts.map +1 -0
  193. package/dist/server/storage/local.js +165 -0
  194. package/dist/server/storage/local.js.map +1 -0
  195. package/dist/server/storage/s3.d.ts +11 -0
  196. package/dist/server/storage/s3.d.ts.map +1 -0
  197. package/dist/server/storage/s3.js +133 -0
  198. package/dist/server/storage/s3.js.map +1 -0
  199. package/dist/server/storage/sigv4.d.ts +23 -0
  200. package/dist/server/storage/sigv4.d.ts.map +1 -0
  201. package/dist/server/storage/sigv4.js +79 -0
  202. package/dist/server/storage/sigv4.js.map +1 -0
  203. package/dist/server/storage/types.d.ts +37 -0
  204. package/dist/server/storage/types.d.ts.map +1 -0
  205. package/dist/server/storage/types.js +82 -0
  206. package/dist/server/storage/types.js.map +1 -0
  207. package/dist/server/stream.d.ts +43 -0
  208. package/dist/server/stream.d.ts.map +1 -0
  209. package/dist/server/stream.js +117 -0
  210. package/dist/server/stream.js.map +1 -0
  211. package/dist/server/streamstore.d.ts +29 -0
  212. package/dist/server/streamstore.d.ts.map +1 -0
  213. package/dist/server/streamstore.js +140 -0
  214. package/dist/server/streamstore.js.map +1 -0
  215. package/dist/server/tenants.d.ts +108 -0
  216. package/dist/server/tenants.d.ts.map +1 -0
  217. package/dist/server/tenants.js +172 -0
  218. package/dist/server/tenants.js.map +1 -0
  219. package/dist/server/transport/index.d.ts +5 -0
  220. package/dist/server/transport/index.d.ts.map +1 -0
  221. package/dist/server/transport/index.js +3 -0
  222. package/dist/server/transport/index.js.map +1 -0
  223. package/dist/server/transport/memory.d.ts +14 -0
  224. package/dist/server/transport/memory.d.ts.map +1 -0
  225. package/dist/server/transport/memory.js +36 -0
  226. package/dist/server/transport/memory.js.map +1 -0
  227. package/dist/server/transport/types.d.ts +44 -0
  228. package/dist/server/transport/types.d.ts.map +1 -0
  229. package/dist/server/transport/types.js +79 -0
  230. package/dist/server/transport/types.js.map +1 -0
  231. package/dist/server/worker.d.ts +33 -0
  232. package/dist/server/worker.d.ts.map +1 -0
  233. package/dist/server/worker.js +428 -0
  234. package/dist/server/worker.js.map +1 -0
  235. package/dist/testing.d.ts +146 -0
  236. package/dist/testing.d.ts.map +1 -0
  237. package/dist/testing.js +406 -0
  238. package/dist/testing.js.map +1 -0
  239. package/dist/theme/contracts.d.ts +4 -0
  240. package/dist/theme/contracts.d.ts.map +1 -0
  241. package/dist/theme/contracts.js +87 -0
  242. package/dist/theme/contracts.js.map +1 -0
  243. package/dist/theme/index.d.ts +8 -0
  244. package/dist/theme/index.d.ts.map +1 -0
  245. package/dist/theme/index.js +7 -0
  246. package/dist/theme/index.js.map +1 -0
  247. package/dist/theme/joints.d.ts +19 -0
  248. package/dist/theme/joints.d.ts.map +1 -0
  249. package/dist/theme/joints.js +126 -0
  250. package/dist/theme/joints.js.map +1 -0
  251. package/dist/theme/ktl/compile.d.ts +26 -0
  252. package/dist/theme/ktl/compile.d.ts.map +1 -0
  253. package/dist/theme/ktl/compile.js +226 -0
  254. package/dist/theme/ktl/compile.js.map +1 -0
  255. package/dist/theme/ktl/lexer.d.ts +20 -0
  256. package/dist/theme/ktl/lexer.d.ts.map +1 -0
  257. package/dist/theme/ktl/lexer.js +56 -0
  258. package/dist/theme/ktl/lexer.js.map +1 -0
  259. package/dist/theme/ktl/parser.d.ts +64 -0
  260. package/dist/theme/ktl/parser.d.ts.map +1 -0
  261. package/dist/theme/ktl/parser.js +220 -0
  262. package/dist/theme/ktl/parser.js.map +1 -0
  263. package/dist/theme/render.d.ts +19 -0
  264. package/dist/theme/render.d.ts.map +1 -0
  265. package/dist/theme/render.js +246 -0
  266. package/dist/theme/render.js.map +1 -0
  267. package/dist/theme/templates.d.ts +2 -0
  268. package/dist/theme/templates.d.ts.map +1 -0
  269. package/dist/theme/templates.js +40 -0
  270. package/dist/theme/templates.js.map +1 -0
  271. package/dist/theme/tokens.d.ts +4 -0
  272. package/dist/theme/tokens.d.ts.map +1 -0
  273. package/dist/theme/tokens.js +15 -0
  274. package/dist/theme/tokens.js.map +1 -0
  275. package/dist/theme/viewmodel.d.ts +6 -0
  276. package/dist/theme/viewmodel.d.ts.map +1 -0
  277. package/dist/theme/viewmodel.js +40 -0
  278. package/dist/theme/viewmodel.js.map +1 -0
  279. package/dist/types.d.ts +614 -0
  280. package/dist/types.d.ts.map +1 -0
  281. package/dist/types.js +3 -0
  282. package/dist/types.js.map +1 -0
  283. package/package.json +60 -0
@@ -0,0 +1,108 @@
1
+ import type { AdapterPool } from '../data/pool.ts';
2
+ import type { AppRegistry } from '../kernel/apps.ts';
3
+ import type { Adapter, Manifest } from '../types.ts';
4
+ import type { ThemeRuntime } from '../theme/render.ts';
5
+ import type { Sessions } from './session.ts';
6
+ import type { Joints } from '../theme/joints.ts';
7
+ import type { IncomingMessage } from 'node:http';
8
+ import type { RuntimeConfig } from './config.ts';
9
+ export type TenantSpec = {
10
+ /**
11
+ * Which tenant a request belongs to. Null means this deployment does not serve
12
+ * it — answered as such rather than falling back to a default, because a default
13
+ * tenant is how one customer's request quietly reads another's data.
14
+ */
15
+ resolve: (url: URL, req: IncomingMessage) => string | null;
16
+ /** Open the datastore for one tenant. The app's, because drivers are the app's. */
17
+ open: (key: string, config: RuntimeConfig) => Adapter | Promise<Adapter>;
18
+ /**
19
+ * Every tenant this deployment serves. Needed to migrate the fleet, and to fail
20
+ * at boot rather than at 3am if one of them cannot be opened.
21
+ */
22
+ list: () => Promise<string[]>;
23
+ /** How many datastores stay open at once. Postgres has a hard connection ceiling. */
24
+ max?: number;
25
+ idleMs?: number;
26
+ };
27
+ /** What a request resolves to: its database, and what is switched on in it. */
28
+ export type Tenant = {
29
+ key: string;
30
+ adapter: Adapter;
31
+ apps: AppRegistry;
32
+ live: Manifest;
33
+ /** Compiled against what this tenant has installed, and cached with it. */
34
+ theme: ThemeRuntime | null;
35
+ /**
36
+ * Extension points for one locale.
37
+ *
38
+ * KTL binds its `_` filter when it compiles, so a runtime is per language as
39
+ * well as per installed set — one bound to the deployment default made every
40
+ * fill answer in that language while the page around it answered in the
41
+ * reader's, which is what a sidebar entry in the wrong language looks like.
42
+ */
43
+ joints: (locale: string) => Joints;
44
+ /**
45
+ * Whose logins these are.
46
+ *
47
+ * Per tenant when the tenant is known before the cookie is read — which it is
48
+ * when tenants arrive by subdomain, because the Host says so. An app on one
49
+ * domain for every tenant cannot do that (reading the session needs the
50
+ * database, knowing the database needs the session), and supplies one shared
51
+ * store instead. Both are expressible; neither is assumed.
52
+ */
53
+ sessions: Sessions | null;
54
+ };
55
+ export type Tenants = {
56
+ keyOf: (url: URL, req: IncomingMessage) => string;
57
+ /** The pool, when there is one — the HTTP layer leases from it directly. */
58
+ pool: AdapterPool | null;
59
+ /**
60
+ * Lease a tenant's datastore for the duration of `fn`.
61
+ *
62
+ * Scoped rather than handed out, because the pool has a bounded size: an adapter
63
+ * that escapes its lease is a connection nobody gives back.
64
+ */
65
+ with: <T>(key: string, fn: (t: Tenant) => Promise<T>) => Promise<T>;
66
+ ofRequest: <T>(url: URL, req: IncomingMessage, fn: (t: Tenant) => Promise<T>) => Promise<T>;
67
+ keys: () => Promise<string[]>;
68
+ close: () => Promise<void>;
69
+ };
70
+ export declare function createTenants(o: {
71
+ spec: TenantSpec;
72
+ pool: AdapterPool;
73
+ manifest: Manifest;
74
+ autoInstall: boolean;
75
+ /**
76
+ * Run once per datastore, before anything reads it — this is where the schema
77
+ * arrives. A tenant database nobody migrated is a tenant with no tables, and
78
+ * every query against it fails in a way that looks like a bug in the query.
79
+ */
80
+ prepare?: (key: string, adapter: Adapter) => Promise<void>;
81
+ /** Run once, after the registry exists: the bootstrap set for a new tenant. */
82
+ onFirstTouch?: (key: string, apps: AppRegistry, adapter: Adapter) => Promise<void>;
83
+ /**
84
+ * Compiles the theme for one tenant's installed set. Cached, because compiling
85
+ * every template on every request would be the most expensive thing here.
86
+ */
87
+ theme?: (live: Manifest) => ThemeRuntime;
88
+ joints: (live: Manifest, locale: string) => Joints;
89
+ /** Built once per tenant, against that tenant's own datastore. */
90
+ sessions?: (adapter: Adapter) => Promise<Sessions>;
91
+ }): Tenants;
92
+ /**
93
+ * One datastore, expressed as the same interface.
94
+ *
95
+ * Not a special case in the caller: two code paths through the thing that decides
96
+ * whose data a request sees is exactly how one of them rots. Every existing test
97
+ * exercises this implementation, and the pooled one differs only in where the
98
+ * adapter comes from.
99
+ */
100
+ export declare function singleTenant(o: {
101
+ adapter: Adapter;
102
+ apps: AppRegistry;
103
+ manifest: Manifest;
104
+ theme?: (live: Manifest) => ThemeRuntime;
105
+ joints: (live: Manifest, locale: string) => Joints;
106
+ sessions?: Sessions | null;
107
+ }): Tenants;
108
+ //# sourceMappingURL=tenants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenants.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/tenants.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,172 @@
1
+ // One deployment, many databases.
2
+ //
3
+ // This is Odoo's model and it is the one that makes per-tenant module sets work at
4
+ // all: the code ships with the deployment, the decision about what is switched on
5
+ // lives in each database. `ket_app` per database is `ir_module_module` per
6
+ // database, and D7 makes it cheaper here — every schema exists everywhere, so
7
+ // enabling a module for a tenant is one UPDATE rather than a migration. Measured:
8
+ // 400 empty tables cost 17 MB, and adding a column across all of them 43 ms.
9
+ //
10
+ // What this file exists to prevent is subtler than a missing feature. Until now
11
+ // `bootApp` opened one adapter and built one AppRegistry at boot, so `live()` —
12
+ // the restricted manifest — was computed once. Serving two tenants through that
13
+ // would not crash; it would show tenant B the module set of tenant A. Wrong
14
+ // answers are worse than errors, so the registry is per datastore and the manifest
15
+ // is resolved per request.
16
+ import { createAppRegistry, restrictManifest } from '../kernel/apps.js';
17
+ import { KetError } from '../kernel/errors.js';
18
+ export function createTenants(o) {
19
+ // One registry per datastore, kept: building it runs DDL, and doing that per
20
+ // request would put a CREATE TABLE IF NOT EXISTS in front of every page.
21
+ const registries = new Map();
22
+ const registryFor = (key, adapter) => {
23
+ let r = registries.get(key);
24
+ if (!r) {
25
+ r = (async () => {
26
+ await o.prepare?.(key, adapter);
27
+ const made = await createAppRegistry(o.manifest, adapter, { autoInstall: o.autoInstall });
28
+ await o.onFirstTouch?.(key, made, adapter);
29
+ return made;
30
+ })();
31
+ // Cached before it resolves, so two concurrent first requests for one tenant
32
+ // do not both run the DDL and both try to install the bootstrap set.
33
+ registries.set(key, r);
34
+ }
35
+ return r;
36
+ };
37
+ const keyOf = (url, req) => {
38
+ const key = o.spec.resolve(url, req);
39
+ if (!key) {
40
+ throw new KetError({
41
+ code: 'E_UNKNOWN_TENANT',
42
+ message: `no tenant for ${req.headers.host ?? url.host}`,
43
+ hint: 'tenants.resolve returned null — this deployment does not serve that host',
44
+ });
45
+ }
46
+ return key;
47
+ };
48
+ /**
49
+ * Both caches are keyed by tenant AND by what is installed, so switching an app
50
+ * on rebuilds rather than serving a stale answer until restart.
51
+ *
52
+ * The restricted manifest is worth caching for the same reason the theme is,
53
+ * and it always was: 0.015 ms a call against KetSuite's manifest, which is
54
+ * nothing until it is every request, and 0.0003 ms once kept. A deployment with
55
+ * one database benefits most, because its installed set almost never changes.
56
+ */
57
+ const lives = new Map();
58
+ const themes = new Map();
59
+ const jointsBy = new Map();
60
+ const sessions = new Map();
61
+ const sessionsFor = (key, adapter) => {
62
+ if (!o.sessions)
63
+ return null;
64
+ let s = sessions.get(key);
65
+ if (!s) {
66
+ s = o.sessions(adapter);
67
+ sessions.set(key, s);
68
+ }
69
+ return s;
70
+ };
71
+ const themeFor = (key, live) => {
72
+ if (!o.theme)
73
+ return null;
74
+ const stamp = `${key}::${live.order.join(',')}`;
75
+ let t = themes.get(stamp);
76
+ if (!t) {
77
+ t = o.theme(live);
78
+ themes.set(stamp, t);
79
+ }
80
+ return t;
81
+ };
82
+ const withTenant = (key, fn) => o.pool.with(key, async (adapter) => {
83
+ const apps = await registryFor(key, adapter);
84
+ // Resolved per request. The whole reason this file exists: computing it once
85
+ // would show one tenant the module set of another.
86
+ const stamp = `${key}::${[...(await apps.enabled())].sort().join(',')}`;
87
+ let live = lives.get(stamp);
88
+ if (!live) {
89
+ live = restrictManifest(o.manifest, await apps.enabled());
90
+ lives.set(stamp, live);
91
+ }
92
+ const jointsFor = (locale) => {
93
+ const k = `${stamp}::${locale}`;
94
+ let made = jointsBy.get(k);
95
+ if (!made) {
96
+ made = o.joints(live, locale);
97
+ jointsBy.set(k, made);
98
+ }
99
+ return made;
100
+ };
101
+ return fn({
102
+ key,
103
+ adapter,
104
+ apps,
105
+ live,
106
+ theme: themeFor(key, live),
107
+ joints: jointsFor,
108
+ sessions: await (sessionsFor(key, adapter) ?? Promise.resolve(null)),
109
+ });
110
+ });
111
+ return {
112
+ keyOf,
113
+ pool: o.pool,
114
+ with: withTenant,
115
+ ofRequest: (url, req, fn) => withTenant(keyOf(url, req), fn),
116
+ keys: () => o.spec.list(),
117
+ close: () => o.pool.close(),
118
+ };
119
+ }
120
+ /**
121
+ * One datastore, expressed as the same interface.
122
+ *
123
+ * Not a special case in the caller: two code paths through the thing that decides
124
+ * whose data a request sees is exactly how one of them rots. Every existing test
125
+ * exercises this implementation, and the pooled one differs only in where the
126
+ * adapter comes from.
127
+ */
128
+ export function singleTenant(o) {
129
+ const lives = new Map();
130
+ const themes = new Map();
131
+ const jointsBy = new Map();
132
+ const run = async (key, fn) => {
133
+ const stamp = [...(await o.apps.enabled())].sort().join(',');
134
+ let live = lives.get(stamp);
135
+ if (!live) {
136
+ live = restrictManifest(o.manifest, await o.apps.enabled());
137
+ lives.set(stamp, live);
138
+ }
139
+ let theme = null;
140
+ if (o.theme) {
141
+ theme = themes.get(stamp) ?? o.theme(live);
142
+ themes.set(stamp, theme);
143
+ }
144
+ const jointsFor = (locale) => {
145
+ const k = `${stamp}::${locale}`;
146
+ let made = jointsBy.get(k);
147
+ if (!made) {
148
+ made = o.joints(live, locale);
149
+ jointsBy.set(k, made);
150
+ }
151
+ return made;
152
+ };
153
+ return fn({
154
+ key,
155
+ adapter: o.adapter,
156
+ apps: o.apps,
157
+ live,
158
+ theme,
159
+ joints: jointsFor,
160
+ sessions: o.sessions ?? null,
161
+ });
162
+ };
163
+ return {
164
+ keyOf: () => '',
165
+ pool: null,
166
+ with: run,
167
+ ofRequest: (_url, _req, fn) => run('', fn),
168
+ keys: async () => [''],
169
+ close: async () => { },
170
+ };
171
+ }
172
+ //# sourceMappingURL=tenants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenants.js","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/tenants.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { effectTransport, unavailableTransport, validateOutboundMessage } from './types.ts';
2
+ export { memoryTransport } from './memory.ts';
3
+ export type { OpenTransport, OutboundMessage, OutboundTransport, TransportAddress, TransportEffect, TransportReceipt, } from './types.ts';
4
+ export type { MemoryTransport } from './memory.ts';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/transport/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,YAAY,EACV,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { effectTransport, unavailableTransport, validateOutboundMessage } from './types.js';
2
+ export { memoryTransport } from './memory.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../packages/ketjs/src/server/transport/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAC3F,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,14 @@
1
+ import type { OutboundMessage, OutboundTransport, TransportReceipt } from './types.ts';
2
+ export type MemoryTransport = OutboundTransport & {
3
+ deliveries(): Array<{
4
+ message: OutboundMessage;
5
+ receipt: TransportReceipt;
6
+ }>;
7
+ attempts(idempotencyKey: string): number;
8
+ };
9
+ /** Deterministic provider double with retry failure injection and provider-side deduplication. */
10
+ export declare function memoryTransport(options?: {
11
+ now?: () => Date;
12
+ fail?: (message: OutboundMessage, attempt: number) => Error | null;
13
+ }): MemoryTransport;
14
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/transport/memory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAEtF,MAAM,MAAM,eAAe,GAAG,iBAAiB,GAAG;IAChD,UAAU,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,eAAe,CAAC;QAAC,OAAO,EAAE,gBAAgB,CAAA;KAAE,CAAC,CAAA;IAC5E,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAA;CACzC,CAAA;AAED,kGAAkG;AAClG,wBAAgB,eAAe,CAC7B,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,KAAK,KAAK,GAAG,IAAI,CAAA;CAAO,GACrG,eAAe,CA+BjB"}
@@ -0,0 +1,36 @@
1
+ import { validateOutboundMessage } from './types.js';
2
+ /** Deterministic provider double with retry failure injection and provider-side deduplication. */
3
+ export function memoryTransport(options = {}) {
4
+ const receipts = new Map();
5
+ const attemptCounts = new Map();
6
+ const now = options.now ?? (() => new Date());
7
+ return {
8
+ name: 'memory',
9
+ async send(message, sendOptions) {
10
+ validateOutboundMessage(message);
11
+ if (sendOptions?.signal?.aborted)
12
+ throw sendOptions.signal.reason ?? new Error('transport send aborted');
13
+ const attempt = (attemptCounts.get(message.idempotencyKey) ?? 0) + 1;
14
+ attemptCounts.set(message.idempotencyKey, attempt);
15
+ const previous = receipts.get(message.idempotencyKey);
16
+ if (previous)
17
+ return { ...previous.receipt, deduplicated: true };
18
+ const failure = options.fail?.(message, attempt);
19
+ if (failure)
20
+ throw failure;
21
+ const accepted = [...message.to, ...(message.cc ?? []), ...(message.bcc ?? [])].map((recipient) => recipient.address);
22
+ const receipt = {
23
+ providerMessageId: `memory:${message.idempotencyKey}`,
24
+ acceptedAt: now().toISOString(),
25
+ accepted,
26
+ rejected: [],
27
+ deduplicated: false,
28
+ };
29
+ receipts.set(message.idempotencyKey, { message: structuredClone(message), receipt });
30
+ return receipt;
31
+ },
32
+ deliveries: () => [...receipts.values()].map((delivery) => structuredClone(delivery)),
33
+ attempts: (idempotencyKey) => attemptCounts.get(idempotencyKey) ?? 0,
34
+ };
35
+ }
36
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../../../../../packages/ketjs/src/server/transport/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAQpD,kGAAkG;AAClG,MAAM,UAAU,eAAe,CAC7B,OAAO,GAA6F,EAAE;IAEtG,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAmE,CAAA;IAC3F,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;IAC7C,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW;YAC7B,uBAAuB,CAAC,OAAO,CAAC,CAAA;YAChC,IAAI,WAAW,EAAE,MAAM,EAAE,OAAO;gBAAE,MAAM,WAAW,CAAC,MAAM,CAAC,MAAM,IAAI,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAA;YACxG,MAAM,OAAO,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;YACpE,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA;YAClD,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;YACrD,IAAI,QAAQ;gBAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,CAAA;YAChE,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;YAChD,IAAI,OAAO;gBAAE,MAAM,OAAO,CAAA;YAC1B,MAAM,QAAQ,GAAG,CAAC,GAAG,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CACjF,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,CACjC,CAAA;YACD,MAAM,OAAO,GAAqB;gBAChC,iBAAiB,EAAE,UAAU,OAAO,CAAC,cAAc,EAAE;gBACrD,UAAU,EAAE,GAAG,EAAE,CAAC,WAAW,EAAE;gBAC/B,QAAQ;gBACR,QAAQ,EAAE,EAAE;gBACZ,YAAY,EAAE,KAAK;aACpB,CAAA;YACD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,CAAA;YACpF,OAAO,OAAO,CAAA;QAChB,CAAC;QACD,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QACrF,QAAQ,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC;KACrE,CAAA;AACH,CAAC"}
@@ -0,0 +1,44 @@
1
+ export type TransportAddress = {
2
+ address: string;
3
+ name?: string;
4
+ };
5
+ export type OutboundMessage = {
6
+ /** Stable across retries; a provider that supports idempotency must use it verbatim. */
7
+ idempotencyKey: string;
8
+ from: TransportAddress;
9
+ to: TransportAddress[];
10
+ cc?: TransportAddress[];
11
+ bcc?: TransportAddress[];
12
+ replyTo?: TransportAddress;
13
+ subject: string;
14
+ text: string;
15
+ html?: string;
16
+ headers?: Record<string, string>;
17
+ };
18
+ export type TransportReceipt = {
19
+ providerMessageId: string;
20
+ acceptedAt: string;
21
+ accepted: string[];
22
+ rejected: Array<{
23
+ address: string;
24
+ reason: string;
25
+ }>;
26
+ /** True when the provider returned the result of an earlier call with the same key. */
27
+ deduplicated: boolean;
28
+ };
29
+ export type OutboundTransport = {
30
+ name: string;
31
+ send(message: OutboundMessage, options?: {
32
+ signal?: AbortSignal;
33
+ }): Promise<TransportReceipt>;
34
+ close?(): Promise<void>;
35
+ };
36
+ export type OpenTransport = (config: import('../config.ts').RuntimeConfig) => OutboundTransport | Promise<OutboundTransport>;
37
+ export type TransportEffect = 'transport:send';
38
+ /** Validate the provider boundary independently of any particular email SDK. */
39
+ export declare function validateOutboundMessage(message: OutboundMessage): void;
40
+ /** Apply the declared-effect boundary before an external side effect begins. */
41
+ export declare function effectTransport(transport: OutboundTransport, effects: readonly string[], operation: string): OutboundTransport;
42
+ /** Default keeps apps without email bootable and fails only if a job actually sends. */
43
+ export declare function unavailableTransport(): OutboundTransport;
44
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../packages/ketjs/src/server/transport/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEjE,MAAM,MAAM,eAAe,GAAG;IAC5B,wFAAwF;IACxF,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,gBAAgB,CAAA;IACtB,EAAE,EAAE,gBAAgB,EAAE,CAAA;IACtB,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAA;IACvB,GAAG,CAAC,EAAE,gBAAgB,EAAE,CAAA;IACxB,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iBAAiB,EAAE,MAAM,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,QAAQ,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACpD,uFAAuF;IACvF,YAAY,EAAE,OAAO,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAC7F,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,CAC1B,MAAM,EAAE,OAAO,cAAc,EAAE,aAAa,KACzC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;AAEnD,MAAM,MAAM,eAAe,GAAG,gBAAgB,CAAA;AAW9C,gFAAgF;AAChF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAsCtE;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAC7B,SAAS,EAAE,iBAAiB,EAC5B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,SAAS,EAAE,MAAM,GAChB,iBAAiB,CAcnB;AAED,wFAAwF;AACxF,wBAAgB,oBAAoB,IAAI,iBAAiB,CAWxD"}
@@ -0,0 +1,79 @@
1
+ import { KetError } from '../../kernel/errors.js';
2
+ const noNewline = (label, value) => {
3
+ if (value.includes('\r') || value.includes('\n'))
4
+ throw new KetError({
5
+ code: 'E_TRANSPORT_MESSAGE',
6
+ message: `${label} contains a newline`,
7
+ hint: 'transport envelope headers must be single-line values',
8
+ });
9
+ };
10
+ /** Validate the provider boundary independently of any particular email SDK. */
11
+ export function validateOutboundMessage(message) {
12
+ if (!message || typeof message !== 'object')
13
+ throw new KetError({ code: 'E_TRANSPORT_MESSAGE', message: 'outbound message must be an object' });
14
+ if (typeof message.idempotencyKey !== 'string' || !message.idempotencyKey.trim())
15
+ throw new KetError({
16
+ code: 'E_TRANSPORT_MESSAGE',
17
+ message: 'outbound message needs a non-empty idempotencyKey',
18
+ });
19
+ if (message.idempotencyKey.length > 200)
20
+ throw new KetError({
21
+ code: 'E_TRANSPORT_MESSAGE',
22
+ message: 'outbound idempotencyKey exceeds 200 characters',
23
+ });
24
+ noNewline('idempotencyKey', message.idempotencyKey);
25
+ if (typeof message.subject !== 'string' || typeof message.text !== 'string')
26
+ throw new KetError({ code: 'E_TRANSPORT_MESSAGE', message: 'outbound subject and text must be strings' });
27
+ noNewline('subject', message.subject);
28
+ const recipients = [...(message.to ?? []), ...(message.cc ?? []), ...(message.bcc ?? [])];
29
+ if (!recipients.length)
30
+ throw new KetError({
31
+ code: 'E_TRANSPORT_MESSAGE',
32
+ message: 'outbound message needs at least one recipient',
33
+ });
34
+ const addresses = [message.from, ...recipients, ...(message.replyTo ? [message.replyTo] : [])];
35
+ for (const [index, recipient] of addresses.entries()) {
36
+ if (!recipient || typeof recipient.address !== 'string' || !recipient.address.trim())
37
+ throw new KetError({
38
+ code: 'E_TRANSPORT_MESSAGE',
39
+ message: `outbound address ${index} is empty`,
40
+ });
41
+ noNewline(`address ${index}`, recipient.address);
42
+ if (recipient.name !== undefined)
43
+ noNewline(`address name ${index}`, recipient.name);
44
+ }
45
+ for (const [name, value] of Object.entries(message.headers ?? {})) {
46
+ noNewline('header name', name);
47
+ noNewline(`header ${name}`, value);
48
+ }
49
+ }
50
+ /** Apply the declared-effect boundary before an external side effect begins. */
51
+ export function effectTransport(transport, effects, operation) {
52
+ return {
53
+ name: transport.name,
54
+ send(message, options) {
55
+ if (!effects.includes('transport:send'))
56
+ throw new KetError({
57
+ code: 'E_EFFECT_NOT_DECLARED',
58
+ message: `"${operation}" attempted transport:send but declares effects [${effects.join(', ') || 'none'}]`,
59
+ hint: 'add "transport:send" to the job effects, or stop sending through the outbound transport',
60
+ });
61
+ validateOutboundMessage(message);
62
+ return transport.send(message, options);
63
+ },
64
+ };
65
+ }
66
+ /** Default keeps apps without email bootable and fails only if a job actually sends. */
67
+ export function unavailableTransport() {
68
+ return {
69
+ name: 'unavailable',
70
+ async send() {
71
+ throw new KetError({
72
+ code: 'E_TRANSPORT_UNAVAILABLE',
73
+ message: 'no outbound transport is configured for this app',
74
+ hint: 'provide serve.openTransport in the app deployment',
75
+ });
76
+ },
77
+ };
78
+ }
79
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../packages/ketjs/src/server/transport/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { AppSpec } from '../kernel/workspace.ts';
2
+ import type { Manifest } from '../types.ts';
3
+ export type WorkerLog = {
4
+ event: 'started' | 'completed' | 'retrying' | 'discarded' | 'cancelled' | 'handler_ignored_abort';
5
+ workerId: string;
6
+ tenant: string;
7
+ jobId: string;
8
+ job: string;
9
+ queue: string;
10
+ attempt: number;
11
+ durationMs?: number;
12
+ error?: string;
13
+ };
14
+ export type BootedWorker = {
15
+ workerId: string;
16
+ manifest: Manifest;
17
+ /** Claim one fair pass without starting a permanent loop. */
18
+ runOnce(): Promise<number>;
19
+ /** Keep claiming until no due work and all claimed jobs have settled. */
20
+ drain(): Promise<number>;
21
+ /** Start adaptive polling. Idempotent. */
22
+ start(): void;
23
+ close(): Promise<void>;
24
+ };
25
+ export declare function bootWorker(spec: AppSpec, options?: {
26
+ env?: Record<string, string | undefined>;
27
+ workerId?: string;
28
+ now?: () => Date;
29
+ random?: () => number;
30
+ log?: (entry: WorkerLog) => void;
31
+ }): Promise<BootedWorker>;
32
+ export declare function serveWorker(spec: AppSpec, options?: Parameters<typeof bootWorker>[1]): Promise<BootedWorker>;
33
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../../../packages/ketjs/src/server/worker.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,KAAK,EAAuB,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGhE,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,GAAG,uBAAuB,CAAA;IACjG,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,QAAQ,CAAA;IAClB,6DAA6D;IAC7D,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IAC1B,yEAAyE;IACzE,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IACxB,0CAA0C;IAC1C,KAAK,IAAI,IAAI,CAAA;IACb,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB,CAAA;AAkED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,OAAO,EACb,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,MAAM,CAAA;IACrB,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAA;CAC5B,GACL,OAAO,CAAC,YAAY,CAAC,CAwWvB;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAM,GAC7C,OAAO,CAAC,YAAY,CAAC,CAMvB"}