okengine 0.6.1 → 0.8.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 (167) hide show
  1. package/AGENTS.md +2 -2
  2. package/README.md +73 -181
  3. package/package.json +3 -3
  4. package/site/content/docs/console/clock.mdx +25 -5
  5. package/site/content/docs/console/signals.mdx +13 -4
  6. package/site/content/docs/elements/ai.mdx +29 -2
  7. package/site/content/docs/elements/channel.mdx +42 -25
  8. package/site/content/docs/elements/clock.mdx +59 -25
  9. package/site/content/docs/elements/flow.mdx +8 -2
  10. package/site/content/docs/elements/gate.mdx +8 -1
  11. package/site/content/docs/elements/signal.mdx +173 -29
  12. package/site/content/docs/elements/store.mdx +595 -73
  13. package/site/content/docs/elements/vault.mdx +15 -5
  14. package/site/content/docs/get-started/basic-usage.mdx +13 -6
  15. package/site/content/docs/get-started/installation.mdx +52 -14
  16. package/site/content/docs/get-started/introduction.mdx +1 -1
  17. package/site/content/docs/plugins/magic-link.mdx +42 -0
  18. package/site/content/docs/plugins/phone-number.mdx +78 -17
  19. package/site/content/docs/plugins/two-factor.mdx +1 -0
  20. package/site/content/docs/reference/cli.md +32 -2
  21. package/site/content/docs/reference/configuration.mdx +15 -13
  22. package/site/content/docs/reference/environment-variables.mdx +32 -18
  23. package/site/content/docs/reference/errors.mdx +12 -11
  24. package/site/content/docs/reference/fx.mdx +15 -13
  25. package/site/content/docs/reference/security.md +3 -1
  26. package/src/cli/ai-setup/ai-setup.test.ts +144 -0
  27. package/src/cli/ai-setup/apply.ts +214 -0
  28. package/src/cli/ai-setup/catalog.ts +263 -0
  29. package/src/cli/ai-setup/detect-ollama.ts +166 -0
  30. package/src/cli/ai-setup/index.ts +228 -0
  31. package/src/cli/ai-setup/prompts.ts +649 -0
  32. package/src/cli/ai-setup/recommend.test.ts +100 -0
  33. package/src/cli/ai-setup/recommend.ts +203 -0
  34. package/src/cli/ai.ts +38 -0
  35. package/src/cli/db-auto-push.test.ts +6 -1
  36. package/src/cli/db-auto-push.ts +8 -3
  37. package/src/cli/db-seed.ts +359 -0
  38. package/src/cli/db.test.ts +341 -3
  39. package/src/cli/db.ts +75 -8
  40. package/src/cli/dev-db-push.test.ts +59 -0
  41. package/src/cli/dev.test.ts +40 -0
  42. package/src/cli/dev.ts +55 -1
  43. package/src/cli/docker-clean.test.ts +179 -0
  44. package/src/cli/docker-clean.ts +406 -0
  45. package/src/cli/docker.ts +16 -4
  46. package/src/cli/ensure-drizzle-config.ts +1 -1
  47. package/src/cli/hero-meta.test.ts +6 -5
  48. package/src/cli/hero-meta.ts +7 -1
  49. package/src/cli/index.ts +5 -0
  50. package/src/cli/load-config.images.test.ts +22 -0
  51. package/src/cli/load-config.ts +7 -2
  52. package/src/cli/openbao-bootstrap.test.ts +1 -0
  53. package/src/cli/openbao-bootstrap.ts +9 -2
  54. package/src/cli/registry.ts +116 -2
  55. package/src/client/live-gap.test.ts +35 -0
  56. package/src/client/transport.test.ts +21 -0
  57. package/src/client/transport.ts +27 -5
  58. package/src/compiler/effects-infer.ts +1 -0
  59. package/src/compiler/fixtures/skyport/oke.config.ts +1 -1
  60. package/src/config/define-config.test.ts +6 -6
  61. package/src/config/index.ts +5 -1
  62. package/src/console/server/console.test.ts +45 -0
  63. package/src/console/server/flows.ts +39 -9
  64. package/src/console/server/i18n.ts +41 -0
  65. package/src/console/server/vault.ts +12 -38
  66. package/src/console/ui/dist/assets/index-ClX0ZCe5.js +10 -0
  67. package/src/console/ui/dist/assets/{panel-access-BGv45snf.js → panel-access-ri1X9Otj.js} +1 -1
  68. package/src/console/ui/dist/assets/{panel-ai-B2S7LEii.js → panel-ai-DLHjRoJk.js} +1 -1
  69. package/src/console/ui/dist/assets/{panel-architecture-D7UJh91v.js → panel-architecture-DI3bQF3J.js} +1 -1
  70. package/src/console/ui/dist/assets/{panel-channels-9T3ybqRu.js → panel-channels-BDYWX29p.js} +1 -1
  71. package/src/console/ui/dist/assets/{panel-clock-Cb1UXGRQ.js → panel-clock-i-JpTjVB.js} +1 -1
  72. package/src/console/ui/dist/assets/{panel-diff-DmYbKWmN.js → panel-diff-CFuWxiXy.js} +1 -1
  73. package/src/console/ui/dist/assets/{panel-flows-PiHwT55z.js → panel-flows-B8TRhcoe.js} +1 -1
  74. package/src/console/ui/dist/assets/{panel-gates-BQGYXvjT.js → panel-gates-CfkBgco7.js} +1 -1
  75. package/src/console/ui/dist/assets/{panel-overview-BBnRO18l.js → panel-overview-DONDzBd2.js} +1 -1
  76. package/src/console/ui/dist/assets/{panel-plugins-D0PsmVw2.js → panel-plugins-DDJwTehL.js} +1 -1
  77. package/src/console/ui/dist/assets/{panel-runs-CWuRDe0r.js → panel-runs-D5zf-D9c.js} +1 -1
  78. package/src/console/ui/dist/assets/{panel-signals-Bbg4ewpP.js → panel-signals-Dsxdu_AR.js} +1 -1
  79. package/src/console/ui/dist/assets/{panel-store-CPCbsDRa.js → panel-store-hy7O8HOs.js} +1 -1
  80. package/src/console/ui/dist/assets/{panel-traces-DVAzuA_S.js → panel-traces-CBiAe5go.js} +1 -1
  81. package/src/console/ui/dist/assets/{panel-vault-D1_MvOmo.js → panel-vault-Za1GyJfM.js} +1 -1
  82. package/src/console/ui/dist/index.html +1 -1
  83. package/src/console/ui/shell/components/ui.tsx +5 -1
  84. package/src/console/ui/shell/setup/Wizard.tsx +26 -5
  85. package/src/docker/cleanup.test.ts +193 -0
  86. package/src/docker/cleanup.ts +355 -0
  87. package/src/docker/docker.test.ts +4 -0
  88. package/src/docker/index.ts +19 -0
  89. package/src/docker/recipes/ollama.ts +10 -5
  90. package/src/drivers/ai-ollama.ts +45 -2
  91. package/src/drivers/ai-providers.test.ts +31 -0
  92. package/src/drivers/channel-sently.test.ts +8 -0
  93. package/src/drivers/channel-taqnyat-mail.ts +34 -0
  94. package/src/drivers/channel-types.ts +71 -0
  95. package/src/drivers/clock-postgres.test.ts +258 -0
  96. package/src/drivers/clock-postgres.ts +410 -0
  97. package/src/drivers/index.ts +21 -0
  98. package/src/drivers/journal-postgres.test.ts +175 -0
  99. package/src/drivers/journal-postgres.ts +492 -0
  100. package/src/drivers/signal-engine.ts +98 -25
  101. package/src/drivers/signal-nats.ts +4 -4
  102. package/src/drivers/signal-postgres.ts +158 -64
  103. package/src/drivers/signal-redis.ts +4 -4
  104. package/src/drivers/signal-types.ts +61 -2
  105. package/src/drivers/vault-driver-removal.test.ts +5 -1
  106. package/src/elements/channel/runtime.ts +51 -0
  107. package/src/elements/channel.test.ts +71 -0
  108. package/src/elements/clock/chaos-child.ts +389 -0
  109. package/src/elements/clock/chaos.test.ts +204 -0
  110. package/src/elements/clock/durable.ts +7 -0
  111. package/src/elements/clock/reconcile.ts +110 -0
  112. package/src/elements/clock/runtime.ts +13 -0
  113. package/src/elements/clock.test.ts +164 -2
  114. package/src/elements/clock.ts +2 -1
  115. package/src/elements/gate/runtime.ts +6 -0
  116. package/src/elements/signal/chaos-child.ts +41 -4
  117. package/src/elements/signal/declare.ts +4 -1
  118. package/src/elements/signal/delivery-modes.test.ts +179 -0
  119. package/src/elements/signal/key-ordering.test.ts +306 -0
  120. package/src/elements/signal/lease-reclaim.test.ts +123 -0
  121. package/src/elements/signal/optional-emit.test.ts +76 -0
  122. package/src/elements/signal/order-lifecycle.test.ts +130 -0
  123. package/src/elements/signal/orphan-messages.test.ts +152 -0
  124. package/src/elements/signal/runtime.ts +11 -4
  125. package/src/elements/signal/schema-emit.test.ts +107 -0
  126. package/src/elements/signal.test.ts +89 -5
  127. package/src/elements/store/files-fx.ts +104 -0
  128. package/src/elements/store/files-image.test.ts +251 -0
  129. package/src/elements/store/files-image.ts +494 -0
  130. package/src/elements/store/runtime.ts +60 -0
  131. package/src/elements/store/seed.test.ts +27 -0
  132. package/src/elements/store/seed.ts +68 -0
  133. package/src/elements/store/sql-session.test.ts +39 -0
  134. package/src/elements/store/sql-session.ts +55 -0
  135. package/src/elements/store/upsert-app.test.ts +103 -0
  136. package/src/elements/store.ts +29 -0
  137. package/src/elements/vault/boot-chain.ts +150 -0
  138. package/src/elements/vault/runtime.ts +8 -0
  139. package/src/index.ts +15 -0
  140. package/src/kernel/app.ts +168 -15
  141. package/src/kernel/boot-bind/channel.test.ts +16 -0
  142. package/src/kernel/boot-bind/channel.ts +13 -0
  143. package/src/kernel/boot-bind/clock.ts +63 -7
  144. package/src/kernel/boot-bind/gate.ts +71 -3
  145. package/src/kernel/boot-bind/honor-config.test.ts +348 -0
  146. package/src/kernel/boot-bind/journal.ts +89 -0
  147. package/src/kernel/boot-bind/signal.ts +64 -7
  148. package/src/kernel/boot-bind/vault.ts +27 -8
  149. package/src/kernel/boot.test.ts +6 -4
  150. package/src/kernel/boot.ts +63 -15
  151. package/src/kernel/concurrency.ts +1 -1
  152. package/src/kernel/errors.ts +8 -2
  153. package/src/kernel/fx.test.ts +19 -0
  154. package/src/kernel/fx.ts +153 -9
  155. package/src/kernel/index.ts +6 -0
  156. package/src/kernel/journal-boot.test.ts +397 -0
  157. package/src/kernel/journal-suspend.ts +35 -0
  158. package/src/kernel/journal.test.ts +142 -0
  159. package/src/kernel/journal.ts +202 -27
  160. package/src/plugins/auth-methods.security.test.ts +10 -7
  161. package/src/plugins/phone-number.ts +67 -10
  162. package/src/plugins/taqnyat.live.test.ts +174 -0
  163. package/src/runtime/dev-request-log.test.ts +20 -1
  164. package/src/runtime/dev-request-log.ts +38 -0
  165. package/src/term.test.ts +15 -0
  166. package/src/term.ts +8 -3
  167. package/src/console/ui/dist/assets/index-CjxwRGVv.js +0 -10
@@ -3,7 +3,11 @@
3
3
  */
4
4
 
5
5
  import { afterEach, describe, expect, test } from "bun:test";
6
- import { isSilentDevRequest, shouldLogDevRequests } from "./dev-request-log.ts";
6
+ import {
7
+ failureDetailFromResponse,
8
+ isSilentDevRequest,
9
+ shouldLogDevRequests,
10
+ } from "./dev-request-log.ts";
7
11
 
8
12
  describe("dev-request-log", () => {
9
13
  const prev = process.env.OKE_DEV_REQUEST_LOG;
@@ -27,4 +31,19 @@ describe("dev-request-log", () => {
27
31
  expect(isSilentDevRequest("GET", "/_oke/client.json")).toBe(true);
28
32
  expect(isSilentDevRequest("POST", "/console/flows")).toBe(false);
29
33
  });
34
+
35
+ test("failureDetailFromResponse reads error.message from envelope", async () => {
36
+ const res = Response.json(
37
+ {
38
+ data: null,
39
+ error: {
40
+ code: "ClaimFailed",
41
+ data: { reason: "password_policy" },
42
+ message: "Password needs at least 12 characters, including a letter and a number.",
43
+ },
44
+ },
45
+ { status: 400 },
46
+ );
47
+ expect(await failureDetailFromResponse(res)).toMatch(/12 characters/);
48
+ });
30
49
  });
@@ -52,6 +52,8 @@ export type DevRequestLogInput = {
52
52
  readonly flow?: string;
53
53
  readonly status: number;
54
54
  readonly ms: number;
55
+ /** Human failure detail (error.message / code) for 4xx/5xx. */
56
+ readonly detail?: string;
55
57
  };
56
58
 
57
59
  /**
@@ -70,6 +72,39 @@ export function isSilentDevRequest(method: string, path: string): boolean {
70
72
  return /\.(?:js|css|map|svg|png|ico|woff2?|ttf|webp)$/i.test(path);
71
73
  }
72
74
 
75
+ /**
76
+ * Extract a short failure detail from an OKE JSON envelope body.
77
+ *
78
+ * @param response - HTTP response (cloned; original body stays readable)
79
+ */
80
+ export async function failureDetailFromResponse(response: Response): Promise<string | undefined> {
81
+ if (response.status < 400) return undefined;
82
+ try {
83
+ const body: unknown = await response.clone().json();
84
+ if (body === null || typeof body !== "object" || !("error" in body)) return undefined;
85
+ const error = (body as { error: unknown }).error;
86
+ if (error === null || typeof error !== "object") return undefined;
87
+ const rec = error as { message?: unknown; code?: unknown; data?: unknown };
88
+ if (typeof rec.message === "string" && rec.message.trim().length > 0) {
89
+ return rec.message.trim();
90
+ }
91
+ if (
92
+ rec.data !== null &&
93
+ typeof rec.data === "object" &&
94
+ "reason" in rec.data &&
95
+ typeof (rec.data as { reason: unknown }).reason === "string"
96
+ ) {
97
+ const reason = (rec.data as { reason: string }).reason;
98
+ const code = typeof rec.code === "string" ? rec.code : "Error";
99
+ return `${code}: ${reason}`;
100
+ }
101
+ if (typeof rec.code === "string") return rec.code;
102
+ } catch {
103
+ // non-JSON error bodies stay status-only
104
+ }
105
+ return undefined;
106
+ }
107
+
73
108
  /**
74
109
  * Print one request line when {@link shouldLogDevRequests} is on.
75
110
  *
@@ -86,6 +121,7 @@ export function logDevRequest(input: DevRequestLogInput): void {
86
121
  flow: input.flow,
87
122
  status: input.status,
88
123
  ms: input.ms,
124
+ detail: input.detail,
89
125
  }),
90
126
  );
91
127
  }
@@ -115,6 +151,7 @@ export async function timedDevFetch(
115
151
  const url = new URL(request.url);
116
152
  const method = request.method.toUpperCase();
117
153
  const response = await handle(request);
154
+ const detail = await failureDetailFromResponse(response);
118
155
  logDevRequest({
119
156
  surface: options.surface ?? currentDevSurface(),
120
157
  method,
@@ -122,6 +159,7 @@ export async function timedDevFetch(
122
159
  flow: options.resolveFlow?.(request, response),
123
160
  status: response.status,
124
161
  ms: Math.round(performance.now() - started),
162
+ detail,
125
163
  });
126
164
  return response;
127
165
  }
package/src/term.test.ts CHANGED
@@ -125,6 +125,21 @@ describe("term", () => {
125
125
  expect(out).not.toMatch(/\u001b\[/);
126
126
  });
127
127
 
128
+ test("formatRequestLine prints failure detail under 4xx/5xx", () => {
129
+ const out = formatRequestLine({
130
+ surface: "Console",
131
+ method: "POST",
132
+ path: "/console/setup/claim",
133
+ flow: "console.setup.claim",
134
+ status: 400,
135
+ ms: 1,
136
+ detail: "Password needs at least 12 characters, including a letter and a number.",
137
+ color: false,
138
+ });
139
+ expect(out).toContain("400");
140
+ expect(out).toContain("↳ Password needs at least 12 characters");
141
+ });
142
+
128
143
  test("formatStackSummary is scannable", () => {
129
144
  const out = formatStackSummary({
130
145
  project: "oke-dev-a3f791",
package/src/term.ts CHANGED
@@ -300,6 +300,8 @@ export function formatRequestLine(options: {
300
300
  /** Instant for date/time columns (default now). */
301
301
  readonly at?: Date;
302
302
  readonly color?: boolean;
303
+ /** Failure detail printed on a follow-up line (4xx/5xx). */
304
+ readonly detail?: string;
303
305
  }): string {
304
306
  const s = termStyle(options.color ?? termColorEnabled());
305
307
  const at = options.at ?? new Date();
@@ -323,7 +325,7 @@ export function formatRequestLine(options: {
323
325
  const path = options.path.length > 28 ? `${options.path.slice(0, 27)}…` : options.path.padEnd(28);
324
326
  const flow = (options.flow ?? "—").padEnd(22);
325
327
  const ms = `${options.ms}ms`.padStart(6);
326
- return (
328
+ const main =
327
329
  `${surfaceColor}●${s.reset} ` +
328
330
  `${surfaceColor}${options.surface.padEnd(7)}${s.reset} ` +
329
331
  `${methodColor}${method}${s.reset} ` +
@@ -332,8 +334,11 @@ export function formatRequestLine(options: {
332
334
  `${s.dim}${ms}${s.reset} ` +
333
335
  `${statusColor}${options.status}${s.reset} ` +
334
336
  `${s.dim}${date}${s.reset} ` +
335
- `${s.dim}${time}${s.reset}\n`
336
- );
337
+ `${s.dim}${time}${s.reset}\n`;
338
+ const detail = options.detail?.trim();
339
+ if (!detail || options.status < 400) return main;
340
+ const clipped = detail.length > 120 ? `${detail.slice(0, 119)}…` : detail;
341
+ return `${main}${s.dim} ↳ ${clipped}${s.reset}\n`;
337
342
  }
338
343
 
339
344
  /**