@ekairos/story 1.21.36-beta.0 → 1.21.38-beta.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.
@@ -1,4 +1,15 @@
1
1
  import { configureStoryRuntime, configureStoryRuntimeBootstrap, isStoryRuntimeConfigured, } from "./story.config";
2
+ const GLOBAL_EKAIROS_CONFIG = Symbol.for("@ekairos/story.ekairosConfig");
3
+ function setGlobalEkairosConfig(config) {
4
+ try {
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ ;
7
+ globalThis[GLOBAL_EKAIROS_CONFIG] = config;
8
+ }
9
+ catch {
10
+ // ignore
11
+ }
12
+ }
2
13
  /**
3
14
  * Creates a small "framework-style" config object that can be executed in the step runtime.
4
15
  *
@@ -7,7 +18,7 @@ import { configureStoryRuntime, configureStoryRuntimeBootstrap, isStoryRuntimeCo
7
18
  */
8
19
  export function createEkairosConfig(params) {
9
20
  const stories = params.stories ?? [];
10
- return {
21
+ const config = {
11
22
  stories,
12
23
  runtime: params.runtime,
13
24
  setup() {
@@ -23,4 +34,8 @@ export function createEkairosConfig(params) {
23
34
  s.register();
24
35
  },
25
36
  };
37
+ // Register globally (process-level) so libraries/steps can access it transparently.
38
+ // Note: This does NOT call `setup()` (no runtime side-effects).
39
+ setGlobalEkairosConfig(config);
40
+ return config;
26
41
  }
package/dist/next.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ export type NextConfigLike = {
2
+ webpack?: (config: any, options: any) => any;
3
+ };
4
+ type WithEkairosRuntimeOptions = {
5
+ /**
6
+ * Module that registers the story runtime factory (usually `./src/ekairos.ts`).
7
+ *
8
+ * This module should be **runtime-only** (server) and should only register factories/config,
9
+ * not create network/db clients eagerly.
10
+ */
11
+ bootstrapModule: string;
12
+ };
13
+ /**
14
+ * Next.js helper to ensure the story runtime factory is registered in *every* server bundle.
15
+ *
16
+ * This is the most explicit & DX-friendly option:
17
+ * - No per-route/workflow imports
18
+ * - No "magic" root bootstrap file
19
+ * - Works for step runtimes because the server entry will always evaluate your bootstrap module
20
+ */
21
+ export declare function withEkairosRuntime(nextConfig: NextConfigLike, opts: WithEkairosRuntimeOptions): NextConfigLike;
22
+ export {};
package/dist/next.js ADDED
@@ -0,0 +1,61 @@
1
+ import { createRequire } from "node:module";
2
+ function injectBootstrapIntoEntries(entries, bootstrap) {
3
+ for (const key of Object.keys(entries)) {
4
+ const entry = entries[key];
5
+ // Webpack 5 "EntryDescription" form
6
+ if (entry && typeof entry === "object" && !Array.isArray(entry) && "import" in entry) {
7
+ const imports = entry.import;
8
+ if (Array.isArray(imports)) {
9
+ if (!imports.includes(bootstrap))
10
+ entry.import = [bootstrap, ...imports];
11
+ }
12
+ else if (typeof imports === "string") {
13
+ if (imports !== bootstrap)
14
+ entry.import = [bootstrap, imports];
15
+ }
16
+ continue;
17
+ }
18
+ if (Array.isArray(entry)) {
19
+ if (!entry.includes(bootstrap))
20
+ entries[key] = [bootstrap, ...entry];
21
+ continue;
22
+ }
23
+ if (typeof entry === "string") {
24
+ if (entry !== bootstrap)
25
+ entries[key] = [bootstrap, entry];
26
+ }
27
+ }
28
+ }
29
+ /**
30
+ * Next.js helper to ensure the story runtime factory is registered in *every* server bundle.
31
+ *
32
+ * This is the most explicit & DX-friendly option:
33
+ * - No per-route/workflow imports
34
+ * - No "magic" root bootstrap file
35
+ * - Works for step runtimes because the server entry will always evaluate your bootstrap module
36
+ */
37
+ export function withEkairosRuntime(nextConfig, opts) {
38
+ const bootstrapModule = opts.bootstrapModule;
39
+ const userWebpack = nextConfig.webpack;
40
+ return {
41
+ ...nextConfig,
42
+ webpack: (config, options) => {
43
+ const out = userWebpack ? userWebpack(config, options) : config;
44
+ if (!options?.isServer)
45
+ return out;
46
+ const req = createRequire(import.meta.url);
47
+ const contextDir = (out && out.context) || process.cwd();
48
+ // Resolve relative to the app project (webpack context), not to this package.
49
+ const resolvedBootstrap = req.resolve(bootstrapModule, {
50
+ paths: [contextDir],
51
+ });
52
+ const originalEntry = out.entry;
53
+ out.entry = async () => {
54
+ const entries = typeof originalEntry === "function" ? await originalEntry() : originalEntry;
55
+ injectBootstrapIntoEntries(entries, resolvedBootstrap);
56
+ return entries;
57
+ };
58
+ return out;
59
+ },
60
+ };
61
+ }
package/dist/runtime.d.ts CHANGED
@@ -8,5 +8,6 @@
8
8
  * - Do NOT import this entrypoint from client/browser code.
9
9
  * - Keep `@ekairos/story` main entrypoint safe to import from schema/domain modules.
10
10
  */
11
- export { configureStoryRuntime, configureStoryRuntimeBootstrap, isStoryRuntimeConfigured, resolveStoryRuntime, type StoryEnvironment, type StoryRuntime, type StoryRuntimeResolver, } from "./story.config";
11
+ export { configureStoryRuntime, configureStoryRuntimeBootstrap, getEkairosConfig, isStoryRuntimeConfigured, resolveStoryRuntime, type StoryEnvironment, type StoryRuntime, type StoryRuntimeResolver, } from "./story.config";
12
12
  export { createEkairosConfig, type EkairosConfig, type RegistrableStory, } from "./ekairos.config";
13
+ export { withEkairosRuntime } from "./next";
package/dist/runtime.js CHANGED
@@ -8,5 +8,6 @@
8
8
  * - Do NOT import this entrypoint from client/browser code.
9
9
  * - Keep `@ekairos/story` main entrypoint safe to import from schema/domain modules.
10
10
  */
11
- export { configureStoryRuntime, configureStoryRuntimeBootstrap, isStoryRuntimeConfigured, resolveStoryRuntime, } from "./story.config";
11
+ export { configureStoryRuntime, configureStoryRuntimeBootstrap, getEkairosConfig, isStoryRuntimeConfigured, resolveStoryRuntime, } from "./story.config";
12
12
  export { createEkairosConfig, } from "./ekairos.config";
13
+ export { withEkairosRuntime } from "./next";
@@ -1,4 +1,5 @@
1
1
  import type { StoryStore } from "./story.store";
2
+ import type { EkairosConfig } from "./ekairos.config";
2
3
  /**
3
4
  * ## story.config.ts
4
5
  *
@@ -16,6 +17,7 @@ export type StoryRuntime = {
16
17
  store: StoryStore;
17
18
  };
18
19
  export type StoryRuntimeResolver<Env extends StoryEnvironment = StoryEnvironment> = (env: Env) => Promise<StoryRuntime> | StoryRuntime;
20
+ export declare function getEkairosConfig(): EkairosConfig | null;
19
21
  /**
20
22
  * Optional global bootstrap hook for step runtimes.
21
23
  *
@@ -1,12 +1,37 @@
1
- import { pathToFileURL } from "node:url";
2
- import { join } from "node:path";
3
1
  let runtimeResolver = null;
2
+ const GLOBAL_RUNTIME_RESOLVER = Symbol.for("@ekairos/story.runtimeResolver");
3
+ const GLOBAL_RUNTIME_BOOTSTRAP = Symbol.for("@ekairos/story.runtimeBootstrap");
4
+ const GLOBAL_EKAIROS_CONFIG = Symbol.for("@ekairos/story.ekairosConfig");
5
+ function getGlobal(key) {
6
+ try {
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ const v = globalThis?.[key];
9
+ return v ?? null;
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ function setGlobal(key, value) {
16
+ try {
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ ;
19
+ globalThis[key] = value;
20
+ }
21
+ catch {
22
+ // ignore
23
+ }
24
+ }
4
25
  function getRuntimeResolver() {
5
- return runtimeResolver;
26
+ return runtimeResolver ?? getGlobal(GLOBAL_RUNTIME_RESOLVER);
27
+ }
28
+ export function getEkairosConfig() {
29
+ return getGlobal(GLOBAL_EKAIROS_CONFIG);
6
30
  }
7
31
  let runtimeBootstrap = null;
8
32
  export function configureStoryRuntimeBootstrap(bootstrap) {
9
33
  runtimeBootstrap = bootstrap;
34
+ setGlobal(GLOBAL_RUNTIME_BOOTSTRAP, bootstrap);
10
35
  }
11
36
  /**
12
37
  * Configure the story runtime resolver (global).
@@ -16,6 +41,7 @@ export function configureStoryRuntimeBootstrap(bootstrap) {
16
41
  */
17
42
  export function configureStoryRuntime(resolver) {
18
43
  runtimeResolver = resolver;
44
+ setGlobal(GLOBAL_RUNTIME_RESOLVER, runtimeResolver);
19
45
  }
20
46
  export function isStoryRuntimeConfigured() {
21
47
  return Boolean(runtimeResolver);
@@ -23,45 +49,15 @@ export function isStoryRuntimeConfigured() {
23
49
  export async function resolveStoryRuntime(env) {
24
50
  if (!getRuntimeResolver()) {
25
51
  // Best-effort: allow the step runtime to self-bootstrap once.
26
- if (runtimeBootstrap) {
27
- await runtimeBootstrap();
28
- }
29
- // Convention bootstrap (portable, runtime-resolvable):
30
- // If the host app provides an `ekairos.bootstrap.js` at the project root, we can load it
31
- // from the step runtime using a file URL. This avoids relying on bundler-only aliases.
52
+ const bootstrap = runtimeBootstrap ?? getGlobal(GLOBAL_RUNTIME_BOOTSTRAP);
53
+ if (bootstrap)
54
+ await bootstrap();
55
+ // Transparent fallback: if the host app created an `ekairosConfig` (via createEkairosConfig),
56
+ // it is available process-wide. We only call setup() when runtime is actually needed.
32
57
  if (!getRuntimeResolver()) {
33
- const cwd = typeof process !== "undefined" && process.cwd ? process.cwd() : null;
34
- if (cwd) {
35
- const candidates = [
36
- "ekairos.bootstrap.js",
37
- "ekairos.bootstrap.cjs",
38
- "ekairos.bootstrap.mjs",
39
- ];
40
- for (const filename of candidates) {
41
- try {
42
- await import(pathToFileURL(join(cwd, filename)).href);
43
- break;
44
- }
45
- catch {
46
- // ignore
47
- }
48
- }
49
- }
50
- }
51
- // Convention bootstrap (Next.js / monorepo apps):
52
- // If the app exposes `src/ekairos.ts` and uses the `@/` alias, loading that module will
53
- // run `ekairosConfig.setup()` which configures the resolver + bootstrap hook.
54
- //
55
- // This is intentionally ONLY attempted when runtime is missing, and is safe as long as
56
- // `story.config` is not part of client bundles (see `@ekairos/story/runtime`).
57
- if (!getRuntimeResolver()) {
58
- try {
59
- // @ts-expect-error - optional, app-provided convention module
60
- await import("@/ekairos");
61
- }
62
- catch {
63
- // ignore: module missing / alias not configured
64
- }
58
+ const cfg = getEkairosConfig();
59
+ if (cfg?.setup)
60
+ cfg.setup();
65
61
  }
66
62
  // If bootstrap succeeded, proceed.
67
63
  const resolver = getRuntimeResolver();
@@ -70,11 +66,8 @@ export async function resolveStoryRuntime(env) {
70
66
  throw new Error([
71
67
  "Story runtime is not configured.",
72
68
  "",
73
- "Convention:",
74
- "- Create an app-level `ekairos.ts` that exports `ekairosConfig = createEkairosConfig({ runtime })`",
75
- "- Ensure `ekairosConfig.setup()` runs in the step runtime (module load / worker boot).",
76
- "",
77
- "If you already have that file, ensure it is evaluated in the step runtime before calling story store steps.",
69
+ "Ensure your app registers a story runtime factory (global) in the step runtime,",
70
+ "before calling store steps.",
78
71
  ].join("\n"));
79
72
  }
80
73
  return await getRuntimeResolver()(env);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekairos/story",
3
- "version": "1.21.36-beta.0",
3
+ "version": "1.21.38-beta.0",
4
4
  "description": "Pulzar Story - Workflow-based AI Stories",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -28,6 +28,11 @@
28
28
  "import": "./dist/runtime.js",
29
29
  "default": "./dist/runtime.js"
30
30
  },
31
+ "./next": {
32
+ "types": "./dist/next.d.ts",
33
+ "import": "./dist/next.js",
34
+ "default": "./dist/next.js"
35
+ },
31
36
  "./instant": {
32
37
  "types": "./dist/stores/instant.store.d.ts",
33
38
  "import": "./dist/stores/instant.store.js",
@@ -43,7 +48,7 @@
43
48
  },
44
49
  "dependencies": {
45
50
  "@ai-sdk/openai": "^2.0.52",
46
- "@ekairos/domain": "^1.21.36-beta.0",
51
+ "@ekairos/domain": "^1.21.38-beta.0",
47
52
  "@instantdb/admin": "^0.22.13",
48
53
  "@instantdb/core": "^0.22.13",
49
54
  "@vercel/sandbox": "^0.0.23",