@ekairos/domain 1.22.34-beta.development.0 → 1.22.36-beta.development.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +123 -128
  2. package/dist/cli/bin.d.ts +9 -0
  3. package/dist/cli/bin.d.ts.map +1 -0
  4. package/dist/cli/bin.js +488 -0
  5. package/dist/cli/bin.js.map +1 -0
  6. package/dist/cli/client-runtime.d.ts +25 -0
  7. package/dist/cli/client-runtime.d.ts.map +1 -0
  8. package/dist/cli/client-runtime.js +60 -0
  9. package/dist/cli/client-runtime.js.map +1 -0
  10. package/dist/cli/config.d.ts +5 -0
  11. package/dist/cli/config.d.ts.map +1 -0
  12. package/dist/cli/config.js +44 -0
  13. package/dist/cli/config.js.map +1 -0
  14. package/dist/cli/create-app.d.ts +33 -0
  15. package/dist/cli/create-app.d.ts.map +1 -0
  16. package/dist/cli/create-app.js +1317 -0
  17. package/dist/cli/create-app.js.map +1 -0
  18. package/dist/cli/http.d.ts +28 -0
  19. package/dist/cli/http.d.ts.map +1 -0
  20. package/dist/cli/http.js +117 -0
  21. package/dist/cli/http.js.map +1 -0
  22. package/dist/cli/index.d.ts +8 -0
  23. package/dist/cli/index.d.ts.map +1 -0
  24. package/dist/cli/index.js +7 -0
  25. package/dist/cli/index.js.map +1 -0
  26. package/dist/cli/server.d.ts +3 -0
  27. package/dist/cli/server.d.ts.map +1 -0
  28. package/dist/cli/server.js +437 -0
  29. package/dist/cli/server.js.map +1 -0
  30. package/dist/cli/types.d.ts +60 -0
  31. package/dist/cli/types.d.ts.map +1 -0
  32. package/dist/cli/types.js +2 -0
  33. package/dist/cli/types.js.map +1 -0
  34. package/dist/cli/ui.d.ts +3 -0
  35. package/dist/cli/ui.d.ts.map +1 -0
  36. package/dist/cli/ui.js +136 -0
  37. package/dist/cli/ui.js.map +1 -0
  38. package/dist/index.d.ts +70 -11
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +121 -18
  41. package/dist/index.js.map +1 -1
  42. package/dist/next.d.ts +21 -21
  43. package/dist/next.d.ts.map +1 -1
  44. package/dist/next.js +212 -345
  45. package/dist/next.js.map +1 -1
  46. package/dist/polyfills/dom-events.d.ts +2 -0
  47. package/dist/polyfills/dom-events.d.ts.map +1 -0
  48. package/dist/polyfills/dom-events.js +92 -0
  49. package/dist/polyfills/dom-events.js.map +1 -0
  50. package/dist/runtime-handle.d.ts +34 -0
  51. package/dist/runtime-handle.d.ts.map +1 -0
  52. package/dist/runtime-handle.js +82 -0
  53. package/dist/runtime-handle.js.map +1 -0
  54. package/dist/runtime.d.ts +3 -2
  55. package/dist/runtime.d.ts.map +1 -1
  56. package/dist/runtime.js +72 -19
  57. package/dist/runtime.js.map +1 -1
  58. package/package.json +37 -4
package/dist/next.d.ts CHANGED
@@ -1,25 +1,25 @@
1
- export type NextConfigLike = {
2
- webpack?: ((config: any, options: any) => any) | null;
3
- turbopack?: any;
1
+ import { type RuntimeDomainSource, type RuntimeResolveOptions } from "./runtime.js";
2
+ type RuntimeLike = {
3
+ env?: Record<string, unknown>;
4
+ db(options?: RuntimeResolveOptions): Promise<any>;
5
+ meta(): {
6
+ domain?: RuntimeDomainSource | null;
7
+ schema?: unknown;
8
+ context?: unknown;
9
+ contextString?: string;
10
+ };
4
11
  };
5
- type WithRuntimeOptions = {
6
- /**
7
- * Module that registers the runtime resolver (usually `./src/runtime.ts`).
8
- *
9
- * This module should be **runtime-only** (server) and should only register factories/config,
10
- * not create network/db clients eagerly.
11
- */
12
- bootstrapModule?: string;
12
+ export type CreateRuntimeRouteHandlerOptions<Env extends Record<string, unknown> = Record<string, unknown>, Runtime extends RuntimeLike = RuntimeLike> = {
13
+ createRuntime: (env: Env) => Runtime | Promise<Runtime>;
14
+ resolveEnv?: (input: {
15
+ req: Request;
16
+ body: unknown;
17
+ }) => Env | Promise<Env>;
13
18
  };
14
- type NextConfigFnLike = (phase: string, ctx: any) => Promise<any> | any;
15
- /**
16
- * Next.js helper to ensure the runtime bootstrap is registered in *every* server bundle.
17
- *
18
- * This is the most explicit & DX-friendly option:
19
- * - No per-route/workflow imports
20
- * - No "magic" root bootstrap file
21
- * - Works for step runtimes because the server entry will always evaluate your bootstrap module
22
- */
23
- export declare function withRuntime(nextConfigOrFn: NextConfigLike | NextConfigFnLike, opts?: WithRuntimeOptions): any;
19
+ export type RuntimeRouteHandlers = {
20
+ GET(req: Request): Promise<Response>;
21
+ POST(req: Request): Promise<Response>;
22
+ };
23
+ export declare function createRuntimeRouteHandler<Env extends Record<string, unknown> = Record<string, unknown>, Runtime extends RuntimeLike = RuntimeLike>(options: CreateRuntimeRouteHandlerOptions<Env, Runtime>): RuntimeRouteHandlers;
24
24
  export {};
25
25
  //# sourceMappingURL=next.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../src/next.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,KAAK,GAAG,CAAC,GAAG,IAAI,CAAA;IACrD,SAAS,CAAC,EAAE,GAAG,CAAA;CAChB,CAAA;AAED,KAAK,kBAAkB,GAAG;IACxB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,KAAK,gBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAA;AAsTvE;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,cAAc,EAAE,cAAc,GAAG,gBAAgB,EACjD,IAAI,GAAE,kBAAuB,GAC5B,GAAG,CAoDL"}
1
+ {"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../src/next.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC3B,MAAM,cAAc,CAAA;AAGrB,KAAK,WAAW,GAAG;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,EAAE,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;IACjD,IAAI,IAAI;QACN,MAAM,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAA;QACnC,MAAM,CAAC,EAAE,OAAO,CAAA;QAChB,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,aAAa,CAAC,EAAE,MAAM,CAAA;KACvB,CAAA;CACF,CAAA;AAED,MAAM,MAAM,gCAAgC,CAC1C,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7D,OAAO,SAAS,WAAW,GAAG,WAAW,IACvC;IACF,aAAa,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACvD,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QACnB,GAAG,EAAE,OAAO,CAAA;QACZ,IAAI,EAAE,OAAO,CAAA;KACd,KAAK,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IACpC,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CACtC,CAAA;AA+ID,wBAAgB,yBAAyB,CACvC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7D,OAAO,SAAS,WAAW,GAAG,WAAW,EACzC,OAAO,EAAE,gCAAgC,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,oBAAoB,CA4G/E"}
package/dist/next.js CHANGED
@@ -1,358 +1,225 @@
1
- import { createRequire } from "node:module";
2
- import { existsSync, mkdirSync, rmSync, readFileSync, writeFileSync } from "node:fs";
3
- import { dirname, relative, resolve } from "node:path";
4
- function patchWorkflowStepRouteToImportBootstrap(bootstrapModule) {
5
- const cwd = process.cwd();
6
- const candidates = [
7
- // legacy app-dir without /src
8
- resolve(cwd, "app/.well-known/workflow/v1/step/route.js"),
9
- resolve(cwd, "app/.well-known/workflow/v1/step/route.ts"),
10
- // app-dir under /src
11
- resolve(cwd, "src/app/.well-known/workflow/v1/step/route.js"),
12
- resolve(cwd, "src/app/.well-known/workflow/v1/step/route.ts"),
13
- ];
14
- const bootstrapAbs = resolve(cwd, bootstrapModule);
15
- for (const routeFile of candidates) {
16
- let contents;
17
- try {
18
- contents = readFileSync(routeFile, "utf8");
19
- }
20
- catch {
21
- continue;
22
- }
23
- const routeDir = dirname(routeFile);
24
- let spec = relative(routeDir, bootstrapAbs).replace(/\\/g, "/");
25
- if (!spec.startsWith("."))
26
- spec = `./${spec}`;
27
- const importLine = `import * as __ekairosBootstrap from "${spec}";`;
28
- const touchLine = `__ekairosBootstrap?.runtimeConfig?.setup?.();`;
29
- const hasImport = contents.includes(importLine);
30
- const hasTouch = contents.includes(touchLine);
31
- if (hasImport && hasTouch)
32
- continue;
33
- const lines = contents.split(/\r?\n/);
34
- // Insert the import above the first real statement (skip comments/empty lines).
35
- let insertAt = 0;
36
- for (let i = 0; i < lines.length; i++) {
37
- const t = lines[i].trim();
38
- const isComment = t.startsWith("//") ||
39
- t.startsWith("/*") ||
40
- t.startsWith("*") ||
41
- t.startsWith("*/");
42
- if (t === "" || isComment)
43
- continue;
44
- insertAt = i;
45
- break;
46
- }
47
- if (!hasImport) {
48
- lines.splice(insertAt, 0, importLine);
49
- }
50
- if (!hasTouch) {
51
- let lastImport = -1;
52
- for (let i = 0; i < lines.length; i++) {
53
- if (lines[i].trim().startsWith("import "))
54
- lastImport = i;
55
- }
56
- const touchAt = lastImport >= 0 ? lastImport + 1 : insertAt + 1;
57
- lines.splice(touchAt, 0, touchLine);
58
- }
59
- writeFileSync(routeFile, lines.join("\n"));
60
- }
1
+ import { executeRuntimeAction, } from "./runtime.js";
2
+ import { getDomainActionBinding, getDomainActions } from "./index.js";
3
+ function json(data, init) {
4
+ return Response.json(data, init);
61
5
  }
62
- function resolveAppDir(cwd) {
63
- const srcAppDir = resolve(cwd, "src/app");
64
- if (existsSync(srcAppDir))
65
- return srcAppDir;
66
- const appDir = resolve(cwd, "app");
67
- if (existsSync(appDir))
68
- return appDir;
69
- const srcDir = resolve(cwd, "src");
70
- if (existsSync(srcDir))
71
- return resolve(srcDir, "app");
72
- return appDir;
6
+ function asRecord(value) {
7
+ return value && typeof value === "object" ? value : {};
73
8
  }
74
- const generatedDomainRoutes = new Set();
75
- const domainRouteMarker = "@ekairos/domain-route";
76
- function ensureDomainRouteFile(bootstrapModule) {
77
- const cwd = process.cwd();
78
- const appDir = resolveAppDir(cwd);
79
- const routeDir = resolve(appDir, ".well-known/ekairos/v1/domain");
80
- const routeTs = resolve(routeDir, "route.ts");
81
- const routeJs = resolve(routeDir, "route.js");
82
- if (existsSync(routeTs))
83
- rmSync(routeTs, { force: true });
84
- if (existsSync(routeJs))
85
- rmSync(routeJs, { force: true });
86
- const ext = existsSync(resolve(cwd, "tsconfig.json")) ? "ts" : "js";
87
- const routeFile = resolve(routeDir, `route.${ext}`);
88
- const bootstrapAbs = resolve(cwd, bootstrapModule);
89
- let spec = relative(routeDir, bootstrapAbs).replace(/\\/g, "/");
90
- if (!spec.startsWith("."))
91
- spec = `./${spec}`;
92
- mkdirSync(routeDir, { recursive: true });
93
- const contents = [
94
- `// ${domainRouteMarker}`,
95
- `import * as __ekairosBootstrap from "${spec}"`,
96
- `__ekairosBootstrap?.runtimeConfig?.setup?.()`,
97
- `import { NextResponse } from "next/server"`,
98
- `import { getRuntimeConfig, resolveRuntime } from "@ekairos/domain/runtime"`,
99
- `import { verifyOidcToken } from "@ekairos/events/oidc"`,
100
- ``,
101
- `function listKeys(value) {`,
102
- ` return value ? Object.keys(value) : []`,
103
- `}`,
104
- ``,
105
- `function resolveSource(config) {`,
106
- ` return config?.domain ?? null`,
107
- `}`,
108
- ``,
109
- `function buildSchema(source) {`,
110
- ` if (!source) return null`,
111
- ` if (typeof source.toInstantSchema === "function") return source.toInstantSchema()`,
112
- ` if (typeof source.schema === "function") return source.schema()`,
113
- ` return {`,
114
- ` entities: source.entities ?? {},`,
115
- ` links: source.links ?? {},`,
116
- ` rooms: source.rooms ?? {},`,
117
- ` }`,
118
- `}`,
119
- ``,
120
- `function buildSummary(config, source) {`,
121
- ` return {`,
122
- ` available: Boolean(source),`,
123
- ` entities: listKeys(source?.entities),`,
124
- ` links: listKeys(source?.links),`,
125
- ` rooms: listKeys(source?.rooms),`,
126
- ` meta: config?.meta ?? {},`,
127
- ` }`,
128
- `}`,
129
- ``,
130
- `function buildContext(config, source) {`,
131
- ` if (!source || typeof source.context !== "function") return null`,
132
- ` return source.context({`,
133
- ` meta: config?.meta,`,
134
- ` })`,
135
- `}`,
136
- ``,
137
- `function buildContextString(config, source) {`,
138
- ` if (!source || typeof source.contextString !== "function") return null`,
139
- ` return source.contextString({`,
140
- ` meta: config?.meta,`,
141
- ` })`,
142
- `}`,
143
- ``,
144
- `const DEFAULT_OIDC_JWKS = "https://oidc.vercel.com/.well-known/jwks.json"`,
145
- `const DEFAULT_OIDC_ISSUER = "https://oidc.vercel.com"`,
146
- ``,
147
- `function parseOptionalBoolean(value) {`,
148
- ` const normalized = String(value ?? "").trim().toLowerCase()`,
149
- ` if (!normalized) return undefined`,
150
- ` if (["1", "true", "yes", "y", "on"].includes(normalized)) return true`,
151
- ` if (["0", "false", "no", "n", "off"].includes(normalized)) return false`,
152
- ` return undefined`,
153
- `}`,
154
- ``,
155
- `function resolveBearerToken(req) {`,
156
- ` const header = req.headers.get("authorization") || ""`,
157
- ` if (!header.startsWith("Bearer ")) return null`,
158
- ` return header.slice("Bearer ".length).trim()`,
159
- `}`,
160
- ``,
161
- `function resolveOidcJwksUrl() {`,
162
- ` return String(process.env.EKAIROS_DOMAIN_JWKS_URL ?? "").trim() || DEFAULT_OIDC_JWKS`,
163
- `}`,
164
- ``,
165
- `function resolveOidcIssuer() {`,
166
- ` return String(process.env.EKAIROS_DOMAIN_ISSUER ?? "").trim() || DEFAULT_OIDC_ISSUER`,
167
- `}`,
168
- ``,
169
- `function resolveOidcAudience() {`,
170
- ` const explicit = String(process.env.EKAIROS_DOMAIN_AUDIENCE ?? "").trim()`,
171
- ` return explicit || null`,
172
- `}`,
173
- ``,
174
- `function isAuthRequired() {`,
175
- ` const explicit = parseOptionalBoolean(process.env.EKAIROS_DOMAIN_AUTH_REQUIRED)`,
176
- ` if (explicit !== undefined) return explicit`,
177
- ` return Boolean(`,
178
- ` process.env.EKAIROS_DOMAIN_TOKEN ||`,
179
- ` process.env.EKAIROS_DOMAIN_JWKS_URL ||`,
180
- ` process.env.EKAIROS_DOMAIN_ISSUER ||`,
181
- ` process.env.EKAIROS_DOMAIN_AUDIENCE`,
182
- ` )`,
183
- `}`,
184
- ``,
185
- `async function isAuthorized(req) {`,
186
- ` if (!isAuthRequired()) return true`,
187
- ` const token = resolveBearerToken(req)`,
188
- ` if (!token) return false`,
189
- ` const staticToken = process.env.EKAIROS_DOMAIN_TOKEN`,
190
- ` if (staticToken && token === staticToken) return true`,
191
- ` try {`,
192
- ` return await verifyOidcToken(token, {`,
193
- ` jwksUrl: resolveOidcJwksUrl(),`,
194
- ` issuer: resolveOidcIssuer(),`,
195
- ` audience: resolveOidcAudience(),`,
196
- ` })`,
197
- ` } catch {`,
198
- ` return false`,
199
- ` }`,
200
- `}`,
201
- ``,
202
- `export async function GET(req) {`,
203
- ` if (!(await isAuthorized(req))) {`,
204
- ` return new NextResponse("Unauthorized", { status: 401 })`,
205
- ` }`,
206
- ` const config = getRuntimeConfig()`,
207
- ` const source = resolveSource(config)`,
208
- ` const context = buildContext(config, source)`,
209
- ` const schema = context?.schema ?? buildSchema(source)`,
210
- ` const contextString = buildContextString(config, source)`,
211
- ` return NextResponse.json({`,
212
- ` mode: "full",`,
213
- ` domain: context ?? buildSummary(config, source),`,
214
- ` schema,`,
215
- ` contextString,`,
216
- ` })`,
217
- `}`,
218
- ``,
219
- `function truncateQueryResult(result) {`,
220
- ` const MAX_QUERY_ROWS = 50`,
221
- ` const output = {}`,
222
- ` const truncation = {}`,
223
- ``,
224
- ` for (const [key, value] of Object.entries(result ?? {})) {`,
225
- ` if (Array.isArray(value)) {`,
226
- ` const total = value.length`,
227
- ` const returned = Math.min(total, MAX_QUERY_ROWS)`,
228
- ` output[key] = value.slice(0, returned)`,
229
- ` if (total > returned) {`,
230
- ` truncation[key] = { returned, total }`,
231
- ` }`,
232
- ` continue`,
233
- ` }`,
234
- ` output[key] = value`,
235
- ` }`,
236
- ``,
237
- ` return {`,
238
- ` data: output,`,
239
- ` truncated: Object.keys(truncation).length > 0 ? truncation : null,`,
240
- ` }`,
241
- `}`,
242
- ``,
243
- `export async function POST(req) {`,
244
- ` if (!(await isAuthorized(req))) {`,
245
- ` return new NextResponse("Unauthorized", { status: 401 })`,
246
- ` }`,
247
- ` let body = null`,
248
- ` try {`,
249
- ` body = await req.json()`,
250
- ` } catch {`,
251
- ` body = null`,
252
- ` }`,
253
- ``,
254
- ` const orgId = String(body?.orgId ?? "").trim()`,
255
- ` const query = body?.query ?? null`,
256
- ``,
257
- ` if (!orgId || !query) {`,
258
- ` return new NextResponse("Missing orgId or query", { status: 400 })`,
259
- ` }`,
260
- ``,
261
- ` const config = getRuntimeConfig()`,
262
- ` const source = resolveSource(config)`,
263
- ` if (!source) {`,
264
- ` return new NextResponse("Runtime domain not configured", { status: 500 })`,
265
- ` }`,
266
- ` const runtime = await resolveRuntime(source, { orgId })`,
267
- ` const result = await runtime.db.query(query)`,
268
- ` return NextResponse.json({`,
269
- ` ok: true,`,
270
- ` ...truncateQueryResult(result),`,
271
- ` })`,
272
- `}`,
273
- ``,
274
- ].join("\n");
275
- writeFileSync(routeFile, contents);
276
- generatedDomainRoutes.add(routeFile);
9
+ function listKeys(value) {
10
+ if (!value || typeof value !== "object")
11
+ return [];
12
+ return Object.keys(value);
277
13
  }
278
- function injectBootstrapIntoEntries(entries, bootstrap) {
279
- for (const key of Object.keys(entries)) {
280
- const entry = entries[key];
281
- // Webpack 5 "EntryDescription" form
282
- if (entry && typeof entry === "object" && !Array.isArray(entry) && "import" in entry) {
283
- const imports = entry.import;
284
- if (Array.isArray(imports)) {
285
- if (!imports.includes(bootstrap))
286
- entry.import = [bootstrap, ...imports];
287
- }
288
- else if (typeof imports === "string") {
289
- if (imports !== bootstrap)
290
- entry.import = [bootstrap, imports];
291
- }
292
- continue;
293
- }
294
- if (Array.isArray(entry)) {
295
- if (!entry.includes(bootstrap))
296
- entries[key] = [bootstrap, ...entry];
14
+ async function readBody(req) {
15
+ try {
16
+ return await req.json();
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ function serializeActionInputSchema(value) {
23
+ if (value === undefined)
24
+ return undefined;
25
+ try {
26
+ return JSON.parse(JSON.stringify(value));
27
+ }
28
+ catch {
29
+ return undefined;
30
+ }
31
+ }
32
+ function resolveActionKey(domain, action) {
33
+ const binding = getDomainActionBinding(action);
34
+ if (typeof binding?.key === "string" && binding.key.trim()) {
35
+ return binding.key.trim();
36
+ }
37
+ if (!domain || typeof domain.getActions !== "function") {
38
+ return undefined;
39
+ }
40
+ const actionName = String(action?.name ?? "").trim();
41
+ const actions = domain.getActions();
42
+ for (const candidate of actions) {
43
+ if (String(candidate?.name ?? "").trim() !== actionName)
297
44
  continue;
298
- }
299
- if (typeof entry === "string") {
300
- if (entry !== bootstrap)
301
- entries[key] = [bootstrap, entry];
45
+ const candidateBinding = getDomainActionBinding(candidate);
46
+ if (typeof candidateBinding?.key === "string" && candidateBinding.key.trim()) {
47
+ return candidateBinding.key.trim();
302
48
  }
303
49
  }
50
+ return undefined;
51
+ }
52
+ function listRuntimeActions(domain) {
53
+ return getDomainActions(domain).map((action) => ({
54
+ name: String(action.name ?? "").trim(),
55
+ key: resolveActionKey(domain, action),
56
+ description: typeof action.description === "string" ? action.description : null,
57
+ inputSchema: serializeActionInputSchema(action.inputSchema),
58
+ }));
304
59
  }
305
- /**
306
- * Next.js helper to ensure the runtime bootstrap is registered in *every* server bundle.
307
- *
308
- * This is the most explicit & DX-friendly option:
309
- * - No per-route/workflow imports
310
- * - No "magic" root bootstrap file
311
- * - Works for step runtimes because the server entry will always evaluate your bootstrap module
312
- */
313
- export function withRuntime(nextConfigOrFn, opts = {}) {
314
- const bootstrapModule = opts.bootstrapModule ?? "./src/runtime";
315
- const apply = (nextConfig) => {
316
- const userWebpack = nextConfig.webpack ?? undefined;
317
- ensureDomainRouteFile(bootstrapModule);
60
+ function findRuntimeAction(domain, name) {
61
+ const normalized = String(name ?? "").trim();
62
+ if (!normalized)
63
+ return null;
64
+ return (getDomainActions(domain).find((action) => {
65
+ if (String(action.name ?? "").trim() === normalized)
66
+ return true;
67
+ const key = resolveActionKey(domain, action);
68
+ return typeof key === "string" && key === normalized;
69
+ }) ?? null);
70
+ }
71
+ function buildDomainSummary(domain) {
72
+ if (!domain) {
318
73
  return {
319
- ...nextConfig,
320
- webpack: (config, options) => {
321
- const out = userWebpack ? userWebpack(config, options) : config;
322
- // NOTE:
323
- // - We still attempt the patch here for webpack builds.
324
- // - But for Turbopack builds, this hook may never run, so we ALSO patch
325
- // in the config-function wrapper below (after withWorkflow generates the file).
326
- patchWorkflowStepRouteToImportBootstrap(bootstrapModule);
327
- ensureDomainRouteFile(bootstrapModule);
328
- if (!options?.isServer)
329
- return out;
330
- const req = createRequire(import.meta.url);
331
- const contextDir = (out && out.context) || process.cwd();
332
- // Resolve relative to the app project (webpack context), not to this package.
333
- const resolvedBootstrap = req.resolve(bootstrapModule, { paths: [contextDir] });
334
- const originalEntry = out.entry;
335
- out.entry = async () => {
336
- const entries = typeof originalEntry === "function" ? await originalEntry() : originalEntry;
337
- injectBootstrapIntoEntries(entries, resolvedBootstrap);
338
- return entries;
339
- };
340
- return out;
341
- },
74
+ available: false,
75
+ entities: [],
76
+ links: [],
77
+ rooms: [],
78
+ meta: {},
342
79
  };
80
+ }
81
+ if (typeof domain.context === "function") {
82
+ return domain.context();
83
+ }
84
+ return {
85
+ available: true,
86
+ entities: listKeys(domain.entities),
87
+ links: listKeys(domain.links),
88
+ rooms: listKeys(domain.rooms),
89
+ meta: domain.meta ?? {},
343
90
  };
344
- // Critical path for Vercel/Turbopack:
345
- // `@workflow/next` generates `.well-known/workflow/.../route.(ts|js)` inside its config function.
346
- // So we must patch AFTER that function runs (not inside webpack).
347
- if (typeof nextConfigOrFn === "function") {
348
- return async (phase, ctx) => {
349
- const cfg = await nextConfigOrFn(phase, ctx);
350
- patchWorkflowStepRouteToImportBootstrap(bootstrapModule);
351
- ensureDomainRouteFile(bootstrapModule);
352
- return apply(cfg);
353
- };
91
+ }
92
+ function resolveBearerToken(req) {
93
+ const header = req.headers.get("authorization") || "";
94
+ if (!header.startsWith("Bearer "))
95
+ return null;
96
+ return header.slice("Bearer ".length).trim();
97
+ }
98
+ function resolveImpersonatedDb(db, req, body) {
99
+ if (typeof db?.asUser !== "function")
100
+ return db;
101
+ const token = resolveBearerToken(req);
102
+ if (token)
103
+ return db.asUser({ token });
104
+ const asEmail = String(body?.asEmail ?? "").trim();
105
+ if (asEmail)
106
+ return db.asUser({ email: asEmail });
107
+ if (Boolean(body?.asGuest))
108
+ return db.asUser({ guest: true });
109
+ return db;
110
+ }
111
+ function truncateQueryResult(result) {
112
+ const MAX_QUERY_ROWS = 50;
113
+ const output = {};
114
+ const truncation = {};
115
+ for (const [key, value] of Object.entries(result ?? {})) {
116
+ if (Array.isArray(value)) {
117
+ const total = value.length;
118
+ const returned = Math.min(total, MAX_QUERY_ROWS);
119
+ output[key] = value.slice(0, returned);
120
+ if (total > returned)
121
+ truncation[key] = { returned, total };
122
+ continue;
123
+ }
124
+ output[key] = value;
125
+ }
126
+ return {
127
+ data: output,
128
+ truncated: Object.keys(truncation).length > 0 ? truncation : null,
129
+ };
130
+ }
131
+ export function createRuntimeRouteHandler(options) {
132
+ async function createRuntimeFor(req, body) {
133
+ const env = options.resolveEnv
134
+ ? await options.resolveEnv({ req, body })
135
+ : asRecord(body?.env);
136
+ return await options.createRuntime(env);
354
137
  }
355
- // Object config: best-effort patch (file may not exist yet here)
356
- return apply(nextConfigOrFn);
138
+ return {
139
+ async GET(req) {
140
+ const runtime = await createRuntimeFor(req, null);
141
+ const meta = runtime.meta();
142
+ const domain = (meta.domain ?? null);
143
+ return json({
144
+ ok: true,
145
+ mode: "full",
146
+ instant: {
147
+ appId: String(runtime.env?.appId ?? process.env.NEXT_PUBLIC_INSTANT_APP_ID ?? "") || null,
148
+ apiURI: String(process.env.EKAIROS_DOMAIN_API_URI ?? process.env.INSTANT_API_URI ?? "https://api.instantdb.com"),
149
+ projectId: String(process.env.EKAIROS_PROJECT_ID ?? "") || null,
150
+ },
151
+ auth: {
152
+ required: false,
153
+ supportsRefreshToken: true,
154
+ supportsBearerToken: true,
155
+ },
156
+ domain: buildDomainSummary(domain),
157
+ schema: meta.schema,
158
+ contextString: meta.contextString ?? (typeof domain?.contextString === "function" ? domain.contextString() : null),
159
+ actions: listRuntimeActions(domain),
160
+ });
161
+ },
162
+ async POST(req) {
163
+ const body = await readBody(req);
164
+ const runtime = await createRuntimeFor(req, body);
165
+ const meta = runtime.meta();
166
+ const domain = (meta.domain ?? null);
167
+ const op = String(body?.op ?? (body?.action ? "action" : "query")).trim();
168
+ const db = resolveImpersonatedDb(await runtime.db(), req, body);
169
+ if (op === "action") {
170
+ const actionName = String(body?.action ?? "");
171
+ const action = findRuntimeAction(domain, actionName);
172
+ if (!action) {
173
+ return json({
174
+ ok: false,
175
+ error: `runtime_action_not_found:${actionName}`,
176
+ }, { status: 404 });
177
+ }
178
+ try {
179
+ const output = await executeRuntimeAction({
180
+ action: action,
181
+ runtime: {
182
+ ...runtime,
183
+ async db() {
184
+ return db;
185
+ },
186
+ },
187
+ input: body?.input ?? {},
188
+ });
189
+ return json({
190
+ ok: true,
191
+ action: action.name,
192
+ output,
193
+ source: "runtime-route",
194
+ });
195
+ }
196
+ catch (error) {
197
+ return json({
198
+ ok: false,
199
+ error: error instanceof Error ? error.message : String(error),
200
+ source: "runtime-route",
201
+ }, { status: 500 });
202
+ }
203
+ }
204
+ const query = body?.query ?? null;
205
+ if (!query)
206
+ return new Response("Missing query", { status: 400 });
207
+ try {
208
+ const result = await db.query(query);
209
+ return json({
210
+ ok: true,
211
+ source: "runtime-route",
212
+ ...truncateQueryResult(asRecord(result)),
213
+ });
214
+ }
215
+ catch (error) {
216
+ return json({
217
+ ok: false,
218
+ error: error instanceof Error ? error.message : String(error),
219
+ source: "runtime-route",
220
+ }, { status: 500 });
221
+ }
222
+ },
223
+ };
357
224
  }
358
225
  //# sourceMappingURL=next.js.map