okengine 0.19.3 → 0.19.5

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 (57) hide show
  1. package/package.json +1 -1
  2. package/site/content/docs/elements/channel/index.mdx +1 -1
  3. package/site/content/docs/elements/clock/index.mdx +53 -105
  4. package/site/content/docs/elements/clock/schedules.mdx +39 -11
  5. package/site/content/docs/elements/flow/consumers.mdx +54 -31
  6. package/site/content/docs/elements/flow/index.mdx +6 -9
  7. package/site/content/docs/elements/flow/routing.mdx +11 -15
  8. package/site/content/docs/elements/signal/broadcast.mdx +6 -1
  9. package/site/content/docs/elements/signal/index.mdx +21 -177
  10. package/site/content/docs/elements/signal/once.mdx +6 -1
  11. package/site/content/docs/reference/cli.mdx +14 -1
  12. package/site/content/docs/reference/errors.mdx +7 -0
  13. package/site/content/docs/understand/the-architecture.mdx +2 -2
  14. package/site/content/docs/understand/try-it.mdx +1 -1
  15. package/src/cli/competitor-mention-removal.test.ts +3 -3
  16. package/src/cli/dev-app-runner.ts +23 -2
  17. package/src/cli/dev.test.ts +47 -0
  18. package/src/cli/dev.ts +11 -0
  19. package/src/compiler/extract-skip.test.ts +43 -0
  20. package/src/compiler/extract.test.ts +190 -15
  21. package/src/compiler/extract.ts +57 -7
  22. package/src/compiler/flow-path.test.ts +36 -0
  23. package/src/compiler/flow-path.ts +35 -1
  24. package/src/compiler/generate-adopt.ts +12 -2
  25. package/src/console/ui-next/dist/assets/{access-page-BpugjHHY.js → access-page-BDbw40sZ.js} +1 -1
  26. package/src/console/ui-next/dist/assets/{agent-disclosure-qnsmtJhf.js → agent-disclosure-CVhs5xog.js} +1 -1
  27. package/src/console/ui-next/dist/assets/{cache-glyph-BcpWUM98.js → cache-glyph-CKIaJ1te.js} +1 -1
  28. package/src/console/ui-next/dist/assets/{call-pii-button-Bz5xiNmR.js → call-pii-button-CPH68-4L.js} +1 -1
  29. package/src/console/ui-next/dist/assets/{collapsible-Cuxn2WH8.js → collapsible-DYYX3bKy.js} +1 -1
  30. package/src/console/ui-next/dist/assets/{duration-tone-Bjnl3EaM.js → duration-tone-BnRJ32O5.js} +1 -1
  31. package/src/console/ui-next/dist/assets/{flows-page-DVujp-T2.js → flows-page-DwEDnJqd.js} +1 -1
  32. package/src/console/ui-next/dist/assets/{highlighted-json-Bql0qlqW.js → highlighted-json-BemWpaqn.js} +1 -1
  33. package/src/console/ui-next/dist/assets/{http-method-BljvrfRg.js → http-method-CAboOgAE.js} +1 -1
  34. package/src/console/ui-next/dist/assets/{index-D1vE656k.js → index-C3KoC-mS.js} +3 -3
  35. package/src/console/ui-next/dist/assets/index-VxoEz295.css +2 -0
  36. package/src/console/ui-next/dist/assets/{observability-page-Bdi0bLJl.js → observability-page-C2sNV7Qu.js} +1 -1
  37. package/src/console/ui-next/dist/assets/{replica-lag-CpkPfITG.js → replica-lag-DJQeKIw-.js} +1 -1
  38. package/src/console/ui-next/dist/assets/{request-meta-C4ZVNFVt.js → request-meta-DQ6HY-a4.js} +1 -1
  39. package/src/console/ui-next/dist/assets/{store-page-DAHtnesC.js → store-page-kB4rot2u.js} +1 -1
  40. package/src/console/ui-next/dist/assets/{trace-detail-sheet-B2c9QRBw.js → trace-detail-sheet-B2VrPfhu.js} +1 -1
  41. package/src/console/ui-next/dist/assets/{tree-expand-toggle-BP4tRC98.js → tree-expand-toggle-CdecFS0p.js} +1 -1
  42. package/src/console/ui-next/dist/assets/{units-page-Oi6--n09.js → units-page-B-Y68cys.js} +1 -1
  43. package/src/console/ui-next/dist/assets/{vault-page-Dt-cPkiU.js → vault-page-BcDSaubT.js} +1 -1
  44. package/src/console/ui-next/dist/index.html +2 -2
  45. package/src/kernel/app.ts +23 -1
  46. package/src/kernel/boot.ts +9 -5
  47. package/src/kernel/effects-stamping.test.ts +44 -0
  48. package/src/kernel/errors-flow-name.ts +20 -4
  49. package/src/kernel/errors.registry.test.ts +4 -2
  50. package/src/kernel/errors.ts +1 -1
  51. package/src/kernel/flow-name.test.ts +105 -20
  52. package/src/kernel/flow.ts +3 -3
  53. package/src/kernel/on.ts +0 -5
  54. package/src/kernel/stamp-http.test.ts +2 -1
  55. package/src/kernel/stamp-http.ts +5 -7
  56. package/src/kernel/unit.ts +1 -2
  57. package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +0 -2
@@ -2069,21 +2069,21 @@ export const app = oke({
2069
2069
  });
2070
2070
  });
2071
2071
 
2072
- describe("extractManifest — inline Signal/Clock + name inheritance", () => {
2072
+ describe("extractManifest — inline Signal/Clock + explicit / tree names", () => {
2073
2073
  test("inline signal.once / clock.every stamp element maps and flow.trigger", async () => {
2074
2074
  const source = `
2075
2075
  import { on, flow, signal, clock } from "okengine";
2076
2076
 
2077
2077
  on(
2078
2078
  signal.once("link-clicked", { retries: 3, deadLetter: true }),
2079
- flow({ do: async (input, fx) => {
2079
+ flow("hooks.linkClicked", { do: async (input, fx) => {
2080
2080
  await fx.store("sql:links").set("x", input);
2081
2081
  } }),
2082
2082
  );
2083
2083
 
2084
2084
  on(
2085
2085
  clock.every("cleanup", "10m"),
2086
- flow({ do: async (_input, fx) => {
2086
+ flow("ops.cleanup", { do: async (_input, fx) => {
2087
2087
  await fx.store("sql:links").set("y", 1);
2088
2088
  } }),
2089
2089
  );
@@ -2095,16 +2095,16 @@ on(
2095
2095
  deadLetter: true,
2096
2096
  });
2097
2097
  expect(manifest.clocks?.cleanup).toMatchObject({ every: "10m" });
2098
- expect(manifest.flows?.["link-clicked"]?.trigger).toEqual({ signal: "link-clicked" });
2099
- expect(manifest.flows?.cleanup?.trigger).toEqual({ every: "10m" });
2098
+ expect(manifest.flows?.["hooks.linkClicked"]?.trigger).toEqual({ signal: "link-clicked" });
2099
+ expect(manifest.flows?.["ops.cleanup"]?.trigger).toEqual({ every: "10m" });
2100
2100
  });
2101
2101
 
2102
- test("nameless flow inherits the named trigger; explicit flow name wins", async () => {
2102
+ test("explicit flow name is independent of the trigger name", async () => {
2103
2103
  const source = `
2104
2104
  import { on, flow, signal, clock } from "okengine";
2105
2105
 
2106
2106
  export const orderPlaced = signal.once("order-placed");
2107
- on(orderPlaced, flow({ do: () => ({ ok: true }) }));
2107
+ on(orderPlaced, flow("orders.fulfill", { do: () => ({ ok: true }) }));
2108
2108
 
2109
2109
  on(
2110
2110
  clock.every("metrics.cleanup", "1h"),
@@ -2112,12 +2112,13 @@ on(
2112
2112
  );
2113
2113
  `;
2114
2114
  const manifest = await extractFromSources({ "workers.ts": source });
2115
- expect(manifest.flows?.["order-placed"]?.trigger).toEqual({ signal: "order-placed" });
2115
+ expect(manifest.flows?.["orders.fulfill"]?.trigger).toEqual({ signal: "order-placed" });
2116
2116
  expect(manifest.flows?.["ops.sweep"]?.trigger).toEqual({ every: "1h" });
2117
2117
  expect(manifest.flows?.["metrics.cleanup"]).toBeUndefined();
2118
+ expect(manifest.flows?.["order-placed"]).toBeUndefined();
2118
2119
  });
2119
2120
 
2120
- test("file-tree unit.export wins over trigger-name inheritance", async () => {
2121
+ test("file-tree unit.export stamps a nameless Signal consumer", async () => {
2121
2122
  const source = `
2122
2123
  import { on, flow, signal } from "okengine";
2123
2124
  export const onCreated = on(
@@ -2132,15 +2133,189 @@ export const onCreated = on(
2132
2133
  expect(manifest.flows?.["note-created"]).toBeUndefined();
2133
2134
  });
2134
2135
 
2135
- test("two nameless inheritances of the same trigger name fail extract", async () => {
2136
+ test("two differently-named flows on the same clock extract cleanly", async () => {
2137
+ const source = `
2138
+ import { on, flow, clock } from "okengine";
2139
+ export const tick = clock.every("metrics.tick", "1h");
2140
+ on(tick, flow("ops.sweep", { do: () => ({ a: true }) }));
2141
+ on(tick, flow("ops.report", { do: () => ({ b: true }) }));
2142
+ `;
2143
+ const manifest = await extractFromSources({ "clock-fanout.ts": source });
2144
+ expect(manifest.clocks?.["metrics.tick"]).toMatchObject({ every: "1h" });
2145
+ expect(manifest.flows?.["ops.sweep"]?.trigger).toEqual({ every: "1h" });
2146
+ expect(manifest.flows?.["ops.report"]?.trigger).toEqual({ every: "1h" });
2147
+ });
2148
+
2149
+ // Exact Clock docs Inline sample — explicit flow name, trigger written inline.
2150
+ const clockInlineExplicitDocsSample = `
2151
+ import { on, flow, clock } from "okengine";
2152
+
2153
+ export const pingExternal = on(
2154
+ clock.every("health.pingExternal", "30s"),
2155
+ flow("health.pingExternal", {
2156
+ plane: "operator",
2157
+ do: async (_, fx) => {
2158
+ await fx.call(pingUpstream);
2159
+ },
2160
+ }),
2161
+ );
2162
+ `;
2163
+
2164
+ test("docs Clock Inline (explicit name) extracts outside src/flows/<unit>/", async () => {
2165
+ const manifest = await extractFromSources({ "ping.ts": clockInlineExplicitDocsSample });
2166
+ expect(manifest.clocks?.["health.pingExternal"]?.every).toBe("30s");
2167
+ expect(manifest.flows?.["health.pingExternal"]?.trigger).toEqual({ every: "30s" });
2168
+ expect(manifest.flows?.["pingExternal"]).toBeUndefined();
2169
+ });
2170
+
2171
+ test("docs Clock named-export (shared schedule) extracts two explicit flows", async () => {
2172
+ const clockSource = `
2173
+ import { clock } from "okengine";
2174
+
2175
+ export const tickClock = clock.every("metrics.tick", "1h");
2176
+ `;
2177
+ const flowsSource = `
2178
+ import { on, flow } from "okengine";
2179
+ import { tickClock } from "@/clocks/metrics";
2180
+
2181
+ export const sweep = on(
2182
+ tickClock,
2183
+ flow("ops.sweep", {
2184
+ plane: "operator",
2185
+ do: async (_, fx) => {
2186
+ await fx.call(sweepMetrics);
2187
+ },
2188
+ }),
2189
+ );
2190
+
2191
+ export const report = on(
2192
+ tickClock,
2193
+ flow("ops.report", {
2194
+ plane: "operator",
2195
+ do: async (_, fx) => {
2196
+ await fx.call(reportMetrics);
2197
+ },
2198
+ }),
2199
+ );
2200
+ `;
2201
+ const manifest = await extractFromSources({
2202
+ "src/clocks/metrics.ts": clockSource,
2203
+ "src/flows/ops/metrics.ts": flowsSource,
2204
+ });
2205
+ expect(manifest.clocks?.["metrics.tick"]).toMatchObject({ every: "1h" });
2206
+ expect(manifest.flows?.["ops.sweep"]?.trigger).toEqual({ every: "1h" });
2207
+ expect(manifest.flows?.["ops.report"]?.trigger).toEqual({ every: "1h" });
2208
+ });
2209
+ });
2210
+
2211
+ describe("extractManifest — nameless Signal/Clock consumers fail OKE1072", () => {
2212
+ test("nameless flow({ do }) on signal.once fails OKE1072", async () => {
2213
+ const source = `
2214
+ import { on, flow, signal } from "okengine";
2215
+ on(signal.once("link-clicked"), flow({ do: () => ({ ok: true }) }));
2216
+ `;
2217
+ await expect(extractFromSources({ "once.ts": source })).rejects.toThrow(/OKE1072/);
2218
+ });
2219
+
2220
+ test("nameless flow({ do }) on signal.broadcast fails OKE1072", async () => {
2221
+ const source = `
2222
+ import { on, flow, signal } from "okengine";
2223
+ on(signal.broadcast("catalog.changed"), flow({ do: () => ({ ok: true }) }));
2224
+ `;
2225
+ await expect(extractFromSources({ "broadcast.ts": source })).rejects.toThrow(/OKE1072/);
2226
+ });
2227
+
2228
+ test("nameless flow({ do }) on signal.live fails OKE1072", async () => {
2136
2229
  const source = `
2137
2230
  import { on, flow, signal } from "okengine";
2138
- const ping = signal.once("health.ping");
2139
- on(ping, flow({ do: () => ({ a: true }) }));
2140
- on(ping, flow({ do: () => ({ b: true }) }));
2231
+ on(signal.live("order-status", { optional: true }), flow({ do: () => ({ ok: true }) }));
2232
+ `;
2233
+ await expect(extractFromSources({ "live.ts": source })).rejects.toThrow(/OKE1072/);
2234
+ });
2235
+
2236
+ test("nameless flow({ do }) on clock.every fails OKE1072", async () => {
2237
+ const source = `
2238
+ import { on, flow, clock } from "okengine";
2239
+ on(clock.every("cleanup", "10m"), flow({ do: () => ({ ok: true }) }));
2141
2240
  `;
2142
- await expect(extractFromSources({ "dup.ts": source })).rejects.toThrow(
2143
- /duplicate flow name "health.ping"/,
2241
+ await expect(extractFromSources({ "clock.ts": source })).rejects.toThrow(/OKE1072/);
2242
+ });
2243
+
2244
+ // Exact Signal docs Inline sample — tree path vs anywhere else.
2245
+ const signalInlineDocsSample = `
2246
+ import { on, flow, signal } from "okengine";
2247
+ import { z } from "zod";
2248
+
2249
+ export const ingestWebhook = on(
2250
+ signal.once("hooks.inbound", {
2251
+ schema: z.object({ id: z.string() }),
2252
+ retries: 3,
2253
+ deadLetter: true,
2254
+ }),
2255
+ flow({
2256
+ do: async ({ id }, fx) => {
2257
+ await fx.call(persistHook, { id });
2258
+ },
2259
+ }),
2260
+ );
2261
+ `;
2262
+
2263
+ test("docs Inline sample at src/flows/hooks/inbound.ts stamps hooks.ingestWebhook", async () => {
2264
+ const manifest = await extractFromSources({
2265
+ "src/flows/hooks/inbound.ts": signalInlineDocsSample,
2266
+ });
2267
+ expect(manifest.flows?.["hooks.ingestWebhook"]?.trigger).toEqual({ signal: "hooks.inbound" });
2268
+ expect(manifest.signals?.["hooks.inbound"]?.delivery).toBe("once");
2269
+ expect(manifest.flows?.["ingestWebhook"]).toBeUndefined();
2270
+ expect(manifest.flows?.["hooks.inbound"]).toBeUndefined();
2271
+ });
2272
+
2273
+ test("docs Inline sample outside src/flows/<unit>/ fails OKE1072", async () => {
2274
+ try {
2275
+ await extractFromSources({ "inbound.ts": signalInlineDocsSample });
2276
+ expect.unreachable("extract should throw OKE1072");
2277
+ } catch (err) {
2278
+ expect(err).toBeInstanceOf(Error);
2279
+ const message = (err as Error).message;
2280
+ expect(message).toMatch(/OKE1072/);
2281
+ expect(message).toContain("hooks.inbound");
2282
+ expect(message).toContain('flow("unit.export"');
2283
+ expect(message).toContain("src/flows/<unit>/");
2284
+ }
2285
+ });
2286
+
2287
+ test("docs Inline sample under src/signals/ fails OKE1072", async () => {
2288
+ await expect(
2289
+ extractFromSources({ "src/signals/inbound.ts": signalInlineDocsSample }),
2290
+ ).rejects.toThrow(/OKE1072/);
2291
+ });
2292
+
2293
+ const clockInlineDocsSample = `
2294
+ import { on, flow, clock } from "okengine";
2295
+
2296
+ export const pingExternal = on(
2297
+ clock.every("health.pingExternal", "30s"),
2298
+ flow({
2299
+ plane: "operator",
2300
+ do: async (_, fx) => {
2301
+ await fx.call(pingUpstream);
2302
+ },
2303
+ }),
2304
+ );
2305
+ `;
2306
+
2307
+ test("docs Clock Inline sample at src/flows/health/ping.ts stamps health.pingExternal", async () => {
2308
+ const manifest = await extractFromSources({
2309
+ "src/flows/health/ping.ts": clockInlineDocsSample,
2310
+ });
2311
+ expect(manifest.flows?.["health.pingExternal"]?.trigger).toEqual({ every: "30s" });
2312
+ expect(manifest.clocks?.["health.pingExternal"]?.every).toBe("30s");
2313
+ expect(manifest.flows?.["pingExternal"]).toBeUndefined();
2314
+ });
2315
+
2316
+ test("docs Clock Inline sample outside src/flows/<unit>/ fails OKE1072", async () => {
2317
+ await expect(extractFromSources({ "ping.ts": clockInlineDocsSample })).rejects.toThrow(
2318
+ /OKE1072/,
2144
2319
  );
2145
2320
  });
2146
2321
  });
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import { parseSync } from "oxc-parser";
10
+ import { join } from "node:path";
10
11
 
11
12
  import {
12
13
  AI_NATIVE_DRIVER_IDS,
@@ -55,7 +56,13 @@ import {
55
56
  type InferBinding,
56
57
  type Literal,
57
58
  } from "./effects-infer.ts";
58
- import { nameFromFlowFile, pathFromFlowFile } from "./flow-path.ts";
59
+ import {
60
+ isFlowsTreeFile,
61
+ isSkippedExtractSource,
62
+ nameFromFlowFile,
63
+ pathFromFlowFile,
64
+ toPosixPath,
65
+ } from "./flow-path.ts";
59
66
  import {
60
67
  defaultListInSchema,
61
68
  jsonSchemaFromAst,
@@ -295,9 +302,9 @@ async function readSources(rootDir: string, pattern: string): Promise<SourceFile
295
302
  cwd: rootDir,
296
303
  onlyFiles: true,
297
304
  })) {
298
- if (path.includes("node_modules/") || path.endsWith(".test.ts")) continue;
299
- const abs = `${rootDir.replace(/\/$/, "")}/${path}`;
300
- files.push({ path, source: await Bun.file(abs).text() });
305
+ if (isSkippedExtractSource(path)) continue;
306
+ const abs = join(rootDir, path);
307
+ files.push({ path: toPosixPath(path), source: await Bun.file(abs).text() });
301
308
  }
302
309
  files.sort((a, b) => a.path.localeCompare(b.path));
303
310
  return files;
@@ -1852,13 +1859,21 @@ function registerFlow(args: {
1852
1859
  const trigger = args.triggerNode
1853
1860
  ? parseTrigger(args.triggerNode, args.scope, args.file.path)
1854
1861
  : undefined;
1855
- const inherited = elementTriggerName(args.triggerNode, args.scope);
1856
1862
 
1863
+ const signalOrClock = isSignalOrClockTrigger(trigger);
1864
+ const treeName =
1865
+ !signalOrClock || isFlowsTreeFile(args.file.path)
1866
+ ? nameFromFlowFile(args.file.path, args.exportName)
1867
+ : undefined;
1868
+
1869
+ // Signal / Clock: explicit `flow("name")` or a real `src/flows/<unit>/`
1870
+ // tree stamp. A bare `export const` outside that folder is not a name —
1871
+ // **OKE1072**, same as `oke()`. HTTP still falls through to exportName.
1857
1872
  const name =
1858
1873
  stringArg(args.flowCall.arguments[0]) ??
1859
- nameFromFlowFile(args.file.path, args.exportName) ??
1874
+ treeName ??
1875
+ (signalOrClock ? unnamedElementFlowName(args.triggerNode, args.scope, trigger) : undefined) ??
1860
1876
  args.exportName ??
1861
- inherited ??
1862
1877
  `flow_${Object.keys(args.scope.flows).length + 1}`;
1863
1878
 
1864
1879
  if (args.exportName) {
@@ -2414,10 +2429,22 @@ function assertOnceSignalSingleFlow(scope: ProjectScope): void {
2414
2429
  }
2415
2430
  }
2416
2431
 
2432
+ /**
2433
+ * True when the parsed trigger is a Signal or Clock (cron / every).
2434
+ *
2435
+ * @param parsed - Parsed `on()` trigger
2436
+ */
2437
+ function isSignalOrClockTrigger(parsed: ParsedTrigger | undefined): boolean {
2438
+ const t = parsed?.trigger;
2439
+ return Boolean(t && (t.signal || t.cron || t.every));
2440
+ }
2441
+
2417
2442
  /**
2418
2443
  * Stable Signal / Clock name on `on()`'s first argument, when one exists.
2419
2444
  * HTTP has no inherent name of this kind — returns undefined.
2420
2445
  *
2446
+ * Used only for **OKE1072** diagnostics — never as a Flow name.
2447
+ *
2421
2448
  * @param node - Trigger AST
2422
2449
  * @param scope - Project scope
2423
2450
  */
@@ -2450,6 +2477,29 @@ function elementTriggerName(node: AstNode | undefined, scope: ProjectScope): str
2450
2477
  return undefined;
2451
2478
  }
2452
2479
 
2480
+ /**
2481
+ * Fail loud when a Signal / Clock consumer has no explicit or tree-derived name.
2482
+ * HTTP still falls through to the generic `flow_*` placeholder (OKE1045 at boot).
2483
+ *
2484
+ * @param triggerNode - Trigger AST
2485
+ * @param scope - Project scope
2486
+ * @param parsed - Parsed trigger
2487
+ * @returns Never for Signal / Clock; `undefined` otherwise
2488
+ */
2489
+ function unnamedElementFlowName(
2490
+ triggerNode: AstNode | undefined,
2491
+ scope: ProjectScope,
2492
+ parsed: ParsedTrigger | undefined,
2493
+ ): undefined {
2494
+ if (!isSignalOrClockTrigger(parsed)) return undefined;
2495
+ const triggerName = elementTriggerName(triggerNode, scope);
2496
+ const kind = parsed?.trigger?.signal ? "signal" : "clock";
2497
+ const target = triggerName ? `${kind} "${triggerName}"` : kind;
2498
+ throw new Error(
2499
+ `OKE1072: nameless flow({ do }) bound to ${target}. Use flow("unit.export", { do }) or export it from a src/flows/<unit>/ file so the tree can stamp unit.export.`,
2500
+ );
2501
+ }
2502
+
2453
2503
  /**
2454
2504
  * Inline `signal.once(…)` / `clock.every(…)` as `on()`'s first argument.
2455
2505
  *
@@ -5,6 +5,8 @@
5
5
  import { describe, expect, test } from "bun:test";
6
6
  import {
7
7
  importSpecifierFromWalked,
8
+ isFlowsTreeFile,
9
+ isSkippedExtractSource,
8
10
  nameFromFlowFile,
9
11
  pathFromFlowFile,
10
12
  toPosixPath,
@@ -93,4 +95,38 @@ describe("nameFromFlowFile / unitFromFlowFile", () => {
93
95
  expect(nameFromFlowFile("main/health.ts", "health")).toBe("main.health");
94
96
  expect(nameFromFlowFile("main/route.ts", "root")).toBe("main.root");
95
97
  });
98
+
99
+ test("Signal Inline docs path stamps hooks.ingestWebhook; a bare file does not", () => {
100
+ expect(nameFromFlowFile("src/flows/hooks/inbound.ts", "ingestWebhook")).toBe(
101
+ "hooks.ingestWebhook",
102
+ );
103
+ expect(unitFromFlowFile("src/flows/hooks/inbound.ts")).toBe("hooks");
104
+ expect(nameFromFlowFile("inbound.ts", "ingestWebhook")).toBeUndefined();
105
+ expect(unitFromFlowFile("inbound.ts")).toBeUndefined();
106
+ });
107
+ });
108
+
109
+ describe("isFlowsTreeFile", () => {
110
+ test("src/flows/<unit>/ and /flows/ mark a tree file; other folders do not", () => {
111
+ expect(isFlowsTreeFile("src/flows/hooks/inbound.ts")).toBe(true);
112
+ expect(isFlowsTreeFile("src/flows/health/ping.ts")).toBe(true);
113
+ expect(isFlowsTreeFile("app/src/flows/notes/on-created.ts")).toBe(true);
114
+ expect(isFlowsTreeFile("flows/hooks/inbound.ts")).toBe(true);
115
+ expect(isFlowsTreeFile("inbound.ts")).toBe(false);
116
+ expect(isFlowsTreeFile("src/signals/inbound.ts")).toBe(false);
117
+ expect(isFlowsTreeFile("src/clocks/digest.ts")).toBe(false);
118
+ expect(isFlowsTreeFile("lib/inbound.ts")).toBe(false);
119
+ });
120
+ });
121
+
122
+ describe("isSkippedExtractSource", () => {
123
+ test("skips node_modules as a path segment, including Windows separators", () => {
124
+ expect(isSkippedExtractSource("node_modules/okengine/src/index.ts")).toBe(true);
125
+ expect(isSkippedExtractSource("node_modules\\okengine\\src\\index.ts")).toBe(true);
126
+ expect(isSkippedExtractSource("web/node_modules/vite/index.ts")).toBe(true);
127
+ expect(isSkippedExtractSource(".git/hooks/pre-commit.ts")).toBe(true);
128
+ expect(isSkippedExtractSource("src/flows/main/health.test.ts")).toBe(true);
129
+ expect(isSkippedExtractSource("src/flows/main/health.ts")).toBe(false);
130
+ expect(isSkippedExtractSource("src/core.ts")).toBe(false);
131
+ });
96
132
  });
@@ -131,7 +131,9 @@ export function pathFromFlowFile(relFromFlowsDirOrSource: string): string | unde
131
131
  /**
132
132
  * Infer `unit.export` from a flow file + export name.
133
133
  *
134
- * `[id]` / `(group)` never enter the name.
134
+ * `[id]` / `(group)` never enter the name. A path that is not under a unit
135
+ * folder (bare `inbound.ts`, or `src/flows/inbound.ts` with no unit) returns
136
+ * `undefined` — Signal / Clock extract then fails **OKE1072**.
135
137
  *
136
138
  * @param filePath - Source path under `flows/`
137
139
  * @param exportName - `export const` binding
@@ -146,6 +148,38 @@ export function nameFromFlowFile(
146
148
  return `${unit}.${exportName}`;
147
149
  }
148
150
 
151
+ /**
152
+ * True when a walked source should be omitted from Manifest extract.
153
+ *
154
+ * `node_modules` / `.git` are path *segments* (POSIX-normalized) so Windows
155
+ * `node_modules\okengine\…` is skipped the same as `node_modules/okengine/…`.
156
+ * Scanning dependency trees would otherwise parse framework fixtures and
157
+ * throw during extract — Docker-first `oke dev` then hard-fails **OKE1020**.
158
+ *
159
+ * @param relPath - Glob-relative path (any separator)
160
+ */
161
+ export function isSkippedExtractSource(relPath: string): boolean {
162
+ const posix = toPosixPath(relPath);
163
+ const parts = posix.split("/").filter(Boolean);
164
+ if (parts.includes("node_modules") || parts.includes(".git")) return true;
165
+ const base = parts[parts.length - 1] ?? "";
166
+ return base.endsWith(".test.ts") || base.endsWith(".test.tsx");
167
+ }
168
+
169
+ /**
170
+ * True when the path is under a flows tree (`src/flows/…` or `…/flows/…`).
171
+ *
172
+ * Adopt-relative `unit/file.ts` (no prefix) is not a tree path — generate-adopt
173
+ * prefixes the unit before {@link nameFromFlowFile}. Without this gate, a
174
+ * nameless Signal worker in `src/signals/inbound.ts` would stamp `src.ingestWebhook`.
175
+ *
176
+ * @param filePath - Source path
177
+ */
178
+ export function isFlowsTreeFile(filePath: string): boolean {
179
+ const posix = toPosixPath(filePath);
180
+ return posix.includes("/flows/") || posix.startsWith("src/flows/") || posix.startsWith("flows/");
181
+ }
182
+
149
183
  /**
150
184
  * First-level folder under `src/flows` — the client unit.
151
185
  *
@@ -14,7 +14,7 @@
14
14
  * `index` is also a reserved leaf).
15
15
  */
16
16
 
17
- import { mkdir, readdir, readFile, rename, writeFile } from "node:fs/promises";
17
+ import { mkdir, readdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
18
18
  import { join } from "node:path";
19
19
 
20
20
  import {
@@ -110,7 +110,17 @@ export async function writeAdoptBarrel(
110
110
  // missing — write
111
111
  }
112
112
  await writeFile(tmp, source);
113
- await rename(tmp, target);
113
+ try {
114
+ await rename(tmp, target);
115
+ } catch {
116
+ // Windows cannot rename onto an existing path (EEXIST / EPERM).
117
+ await writeFile(target, source);
118
+ try {
119
+ await unlink(tmp);
120
+ } catch {
121
+ // tmp already replaced or removed
122
+ }
123
+ }
114
124
  return { written: true };
115
125
  }
116
126
 
@@ -1,4 +1,4 @@
1
- import{r as e}from"./rolldown-runtime-hePW80VL.js";import{r as t}from"./react-dom-Ddte4I-Q.js";import{A as n}from"./xyflow-yApv7D4e.js";import{Cr as r,Dr as i,E as a,Er as o,F as s,Fr as c,I as l,Ir as u,Lr as d,Nr as f,Pr as p,R as m,Rr as h,Sr as g,Tr as _,Vr as v,Yi as y,_r as b,ar as x,br as S,c as C,cr as w,dr as T,ha as ee,i as E,kr as D,l as O,lr as k,mr as A,nr as j,o as M,pr as N,rr as P,s as F,sr as I,tr as L,u as te,ur as R,vr as z,wr as B,x as V,xr as H}from"./shortcut-keys-3ILd8oGn.js";import{i as ne,t as re}from"./http-method-BljvrfRg.js";import{a as ie,c as ae,h as oe,i as se,n as ce,o as le,r as ue,s as U,t as de}from"./element-icons-BI8cJgdh.js";import{t as fe}from"./UserIcon-DaE2PB5_.js";import{t as pe}from"./PlusSignIcon-CwG3nxfu.js";import{bt as W,ct as me,it as he}from"./index-D1vE656k.js";import{t as ge}from"./explorer-empty-CJs5A-wm.js";import{a as G,c as _e,l as K,n as q,o as ve,r as ye,s as be,t as xe}from"./detail-header-DVWNjWjg.js";import{n as Se,t as J}from"./copy-inline-button-CAYD18cr.js";var Ce=[[`path`,{d:`M5 21H19`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`1.5`,key:`0`}],[`path`,{d:`M12.125 12.75H12M12.25 12.75C12.25 12.8881 12.1381 13 12 13C11.8619 13 11.75 12.8881 11.75 12.75C11.75 12.6119 11.8619 12.5 12 12.5C12.1381 12.5 12.25 12.6119 12.25 12.75Z`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`1.5`,key:`1`}],[`path`,{d:`M14.9152 7.61089L13.8078 5.38179C13.019 3.79393 12.6246 3 12 3C11.3754 3 10.981 3.79393 10.1922 5.38179L9.08483 7.61089C8.58107 8.62494 8.32919 9.13197 7.87976 9.24608C7.8485 9.25401 7.81689 9.26043 7.78503 9.26533C7.32682 9.3357 6.89919 8.96678 6.04393 8.22895C4.0124 6.47635 2.99663 5.60004 2.38034 5.94899C2.34045 5.97157 2.30213 5.99686 2.26565 6.02467C1.70197 6.45439 2.09541 7.74136 2.88229 10.3153L4.04783 14.1279C4.47098 15.5121 4.68255 16.2042 5.21787 16.6021C5.75318 17 6.47261 17 7.91147 17L16.0886 16.9999C17.5274 16.9999 18.2468 16.9999 18.7821 16.602C19.3175 16.2041 19.529 15.512 19.9522 14.1279L21.1177 10.3153C21.9046 7.74137 22.298 6.4544 21.7344 6.02468C21.6979 5.99687 21.6595 5.97158 21.6197 5.94899C21.0034 5.60006 19.9876 6.47636 17.9561 8.22896C17.1008 8.96679 16.6732 9.3357 16.215 9.26533C16.1831 9.26043 16.1515 9.25401 16.1202 9.24607C15.6708 9.13197 15.4189 8.62494 14.9152 7.61089Z`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`1.5`,key:`2`}]],Y=e(t(),1);function we(e,t){if(e==null)return`never`;let n=e-t;if(Math.abs(n)<6e4)return`just now`;let r=Ee(Math.abs(n));return n<0?`${r} ago`:`in ${r}`}function Te(e,t){return e==null?`never`:e<=t?`expired`:we(e,t)}function Ee(e){if(e<36e5)return`${Math.floor(e/6e4)}m`;if(e<864e5)return`${Math.floor(e/36e5)}h`;let t=Math.floor(e/864e5);return t<100?`${t}d`:`${Math.floor(t/30)}mo`}var X=864e5;function De(e){let t=/^(\d+)(ms|s|m|h|d)$/.exec(e.trim());if(!t)return 0;let n=Number(t[1]);switch(t[2]){case`ms`:return n;case`s`:return n*1e3;case`m`:return n*6e4;case`h`:return n*36e5;case`d`:return n*X;default:return 0}}function Oe(e,t,n=``){if(e===`never`)return null;if(e===`30d`)return t+30*X;if(e===`90d`)return t+90*X;let r=De(n);return r>0?t+r:null}var Z=36e5;function ke(e,t){if(e==null)return{choice:`never`,custom:``};let n=e-t;return n<=0?{choice:`never`,custom:``}:Math.abs(n-30*X)<Z?{choice:`30d`,custom:``}:Math.abs(n-90*X)<Z?{choice:`90d`,custom:``}:{choice:`custom`,custom:Me(n)}}var Ae=7*X;function je(e,t){if(e==null||e<=t)return{choice:`90d`,custom:``};let n=e-t;return Math.abs(n-30*X)<=Ae?{choice:`30d`,custom:``}:Math.abs(n-90*X)<=Ae?{choice:`90d`,custom:``}:{choice:`custom`,custom:Me(n)}}function Me(e){return e<=0?``:e>=X&&e%X===0?`${e/X}d`:e>=Z&&e%Z===0?`${e/Z}h`:e>=6e4&&e%6e4==0?`${e/6e4}m`:e>=X?`${Math.max(1,Math.round(e/X))}d`:e>=Z?`${Math.max(1,Math.round(e/Z))}h`:`${Math.max(1,Math.round(e/6e4))}m`}var Ne=[`s`,`m`,`h`,`d`,`ms`],Pe={s:`Seconds`,m:`Minutes`,h:`Hours`,d:`Days`,ms:`Milliseconds`};function Fe(e,t,n){let r=e.trim(),i=t.trim();if(r.length===0&&i.length===0)return null;if(r.length===0||i.length===0||!/^\d+$/.test(r)||!/^\d+$/.test(i))return;let a=Number(r),o=Number(i);if(a<=0||o<=0)return;let s=`${o}${n}`;if(!(De(s)<=0))return{max:a,per:s}}function Ie(e){let t=/^(\d+)(ms|s|m|h|d)$/.exec(e.trim());return t?{count:t[1],unit:t[2]}:{count:``,unit:`m`}}function Le(e){let t=ze(e);return t.length===0?null:Be(t)?`ip`:Ve(t)?`host`:null}function Re(e){let t=new Set,n=[];for(let r of e.split(/[\s,]+/)){let e=ze(r);e.length===0||t.has(e)||Le(e)!=null&&(t.add(e),n.push(e))}return n}function ze(e){let t=e.trim().toLowerCase();if(t=t.replace(/^https?:\/\//,``),t.startsWith(`[`)&&t.includes(`]`)){let e=t.indexOf(`]`),n=t.slice(1,e),r=t.slice(e+1);t=r.startsWith(`:`)||r.startsWith(`/`)?n:`${n}${r}`}let n=t.indexOf(`/`);return n>=0&&(t=t.slice(0,n)),t.endsWith(`.`)&&(t=t.slice(0,-1)),t}function Be(e){return/^\d{1,3}(?:\.\d{1,3}){3}$/.test(e)?e.split(`.`).every(e=>Number(e)<=255):!e.includes(`:`)||!/^[0-9a-f:]+$/.test(e)||e.split(`::`).length>2?!1:e.split(`:`).filter(e=>e.length>0).length>=1}function Ve(e){if(e===`localhost`)return!0;if(e.length>253||e.includes(`:`))return!1;let t=e.split(`.`);return t.length<2?!1:t.every((e,n)=>!(e.length===0||e.length>63||!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(e)||n===t.length-1&&!/^[a-z]{2,63}$/.test(e)))}function He(e){let t=[],n=new Map;for(let r of e){let e=r.indexOf(`:`),i=e<=0?r:r.slice(0,e),a=e<=0?r:r.slice(e+1),o=n.get(i);if(o){o.push({scope:r,action:a});continue}t.push(i),n.set(i,[{scope:r,action:a}])}return t.map(e=>({group:e,items:n.get(e)??[]}))}var Q=n(),Ue=`GET /secure
1
+ import{r as e}from"./rolldown-runtime-hePW80VL.js";import{r as t}from"./react-dom-Ddte4I-Q.js";import{A as n}from"./xyflow-yApv7D4e.js";import{Cr as r,Dr as i,E as a,Er as o,F as s,Fr as c,I as l,Ir as u,Lr as d,Nr as f,Pr as p,R as m,Rr as h,Sr as g,Tr as _,Vr as v,Yi as y,_r as b,ar as x,br as S,c as C,cr as w,dr as T,ha as ee,i as E,kr as D,l as O,lr as k,mr as A,nr as j,o as M,pr as N,rr as P,s as F,sr as I,tr as L,u as te,ur as R,vr as z,wr as B,x as V,xr as H}from"./shortcut-keys-3ILd8oGn.js";import{i as ne,t as re}from"./http-method-CAboOgAE.js";import{a as ie,c as ae,h as oe,i as se,n as ce,o as le,r as ue,s as U,t as de}from"./element-icons-BI8cJgdh.js";import{t as fe}from"./UserIcon-DaE2PB5_.js";import{t as pe}from"./PlusSignIcon-CwG3nxfu.js";import{bt as W,ct as me,it as he}from"./index-C3KoC-mS.js";import{t as ge}from"./explorer-empty-CJs5A-wm.js";import{a as G,c as _e,l as K,n as q,o as ve,r as ye,s as be,t as xe}from"./detail-header-DVWNjWjg.js";import{n as Se,t as J}from"./copy-inline-button-CAYD18cr.js";var Ce=[[`path`,{d:`M5 21H19`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`1.5`,key:`0`}],[`path`,{d:`M12.125 12.75H12M12.25 12.75C12.25 12.8881 12.1381 13 12 13C11.8619 13 11.75 12.8881 11.75 12.75C11.75 12.6119 11.8619 12.5 12 12.5C12.1381 12.5 12.25 12.6119 12.25 12.75Z`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`1.5`,key:`1`}],[`path`,{d:`M14.9152 7.61089L13.8078 5.38179C13.019 3.79393 12.6246 3 12 3C11.3754 3 10.981 3.79393 10.1922 5.38179L9.08483 7.61089C8.58107 8.62494 8.32919 9.13197 7.87976 9.24608C7.8485 9.25401 7.81689 9.26043 7.78503 9.26533C7.32682 9.3357 6.89919 8.96678 6.04393 8.22895C4.0124 6.47635 2.99663 5.60004 2.38034 5.94899C2.34045 5.97157 2.30213 5.99686 2.26565 6.02467C1.70197 6.45439 2.09541 7.74136 2.88229 10.3153L4.04783 14.1279C4.47098 15.5121 4.68255 16.2042 5.21787 16.6021C5.75318 17 6.47261 17 7.91147 17L16.0886 16.9999C17.5274 16.9999 18.2468 16.9999 18.7821 16.602C19.3175 16.2041 19.529 15.512 19.9522 14.1279L21.1177 10.3153C21.9046 7.74137 22.298 6.4544 21.7344 6.02468C21.6979 5.99687 21.6595 5.97158 21.6197 5.94899C21.0034 5.60006 19.9876 6.47636 17.9561 8.22896C17.1008 8.96679 16.6732 9.3357 16.215 9.26533C16.1831 9.26043 16.1515 9.25401 16.1202 9.24607C15.6708 9.13197 15.4189 8.62494 14.9152 7.61089Z`,stroke:`currentColor`,strokeLinecap:`round`,strokeLinejoin:`round`,strokeWidth:`1.5`,key:`2`}]],Y=e(t(),1);function we(e,t){if(e==null)return`never`;let n=e-t;if(Math.abs(n)<6e4)return`just now`;let r=Ee(Math.abs(n));return n<0?`${r} ago`:`in ${r}`}function Te(e,t){return e==null?`never`:e<=t?`expired`:we(e,t)}function Ee(e){if(e<36e5)return`${Math.floor(e/6e4)}m`;if(e<864e5)return`${Math.floor(e/36e5)}h`;let t=Math.floor(e/864e5);return t<100?`${t}d`:`${Math.floor(t/30)}mo`}var X=864e5;function De(e){let t=/^(\d+)(ms|s|m|h|d)$/.exec(e.trim());if(!t)return 0;let n=Number(t[1]);switch(t[2]){case`ms`:return n;case`s`:return n*1e3;case`m`:return n*6e4;case`h`:return n*36e5;case`d`:return n*X;default:return 0}}function Oe(e,t,n=``){if(e===`never`)return null;if(e===`30d`)return t+30*X;if(e===`90d`)return t+90*X;let r=De(n);return r>0?t+r:null}var Z=36e5;function ke(e,t){if(e==null)return{choice:`never`,custom:``};let n=e-t;return n<=0?{choice:`never`,custom:``}:Math.abs(n-30*X)<Z?{choice:`30d`,custom:``}:Math.abs(n-90*X)<Z?{choice:`90d`,custom:``}:{choice:`custom`,custom:Me(n)}}var Ae=7*X;function je(e,t){if(e==null||e<=t)return{choice:`90d`,custom:``};let n=e-t;return Math.abs(n-30*X)<=Ae?{choice:`30d`,custom:``}:Math.abs(n-90*X)<=Ae?{choice:`90d`,custom:``}:{choice:`custom`,custom:Me(n)}}function Me(e){return e<=0?``:e>=X&&e%X===0?`${e/X}d`:e>=Z&&e%Z===0?`${e/Z}h`:e>=6e4&&e%6e4==0?`${e/6e4}m`:e>=X?`${Math.max(1,Math.round(e/X))}d`:e>=Z?`${Math.max(1,Math.round(e/Z))}h`:`${Math.max(1,Math.round(e/6e4))}m`}var Ne=[`s`,`m`,`h`,`d`,`ms`],Pe={s:`Seconds`,m:`Minutes`,h:`Hours`,d:`Days`,ms:`Milliseconds`};function Fe(e,t,n){let r=e.trim(),i=t.trim();if(r.length===0&&i.length===0)return null;if(r.length===0||i.length===0||!/^\d+$/.test(r)||!/^\d+$/.test(i))return;let a=Number(r),o=Number(i);if(a<=0||o<=0)return;let s=`${o}${n}`;if(!(De(s)<=0))return{max:a,per:s}}function Ie(e){let t=/^(\d+)(ms|s|m|h|d)$/.exec(e.trim());return t?{count:t[1],unit:t[2]}:{count:``,unit:`m`}}function Le(e){let t=ze(e);return t.length===0?null:Be(t)?`ip`:Ve(t)?`host`:null}function Re(e){let t=new Set,n=[];for(let r of e.split(/[\s,]+/)){let e=ze(r);e.length===0||t.has(e)||Le(e)!=null&&(t.add(e),n.push(e))}return n}function ze(e){let t=e.trim().toLowerCase();if(t=t.replace(/^https?:\/\//,``),t.startsWith(`[`)&&t.includes(`]`)){let e=t.indexOf(`]`),n=t.slice(1,e),r=t.slice(e+1);t=r.startsWith(`:`)||r.startsWith(`/`)?n:`${n}${r}`}let n=t.indexOf(`/`);return n>=0&&(t=t.slice(0,n)),t.endsWith(`.`)&&(t=t.slice(0,-1)),t}function Be(e){return/^\d{1,3}(?:\.\d{1,3}){3}$/.test(e)?e.split(`.`).every(e=>Number(e)<=255):!e.includes(`:`)||!/^[0-9a-f:]+$/.test(e)||e.split(`::`).length>2?!1:e.split(`:`).filter(e=>e.length>0).length>=1}function Ve(e){if(e===`localhost`)return!0;if(e.length>253||e.includes(`:`))return!1;let t=e.split(`.`);return t.length<2?!1:t.every((e,n)=>!(e.length===0||e.length>63||!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(e)||n===t.length-1&&!/^[a-z]{2,63}$/.test(e)))}function He(e){let t=[],n=new Map;for(let r of e){let e=r.indexOf(`:`),i=e<=0?r:r.slice(0,e),a=e<=0?r:r.slice(e+1),o=n.get(i);if(o){o.push({scope:r,action:a});continue}t.push(i),n.set(i,[{scope:r,action:a}])}return t.map(e=>({group:e,items:n.get(e)??[]}))}var Q=n(),Ue=`GET /secure
2
2
  Authorization: Bearer <secret>`,We=`{ "ok": true }`;function Ge({keyRow:e,blast:t,now:n,leading:r,onEdit:a,onRefresh:s,onRevoke:c,onRotate:l,rotatePending:u}){let d=e.revokedAt!==null,f=e.expiresAt!==null&&e.expiresAt<=n,p=t?.lastUsedAt??e.lastUsedAt,m=t?.callVolume??0,h=Te(e.expiresAt,n),g=we(p,n),_=e.rateLimit?`${e.rateLimit.max} / ${e.rateLimit.per}`:`none`,v=(0,Y.useMemo)(()=>He(e.scopes),[e.scopes]),y=e.creatorScopes.length,b=y>0&&e.scopes.length<y;return(0,Q.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col overflow-y-auto`,"data-slot":`access-detail`,"aria-label":`Access key detail`,"aria-live":`polite`,children:[(0,Q.jsx)(xe,{dataSlot:`access-detail-header`,leading:r,icon:(0,Q.jsx)(i,{icon:oe,className:`size-4`}),title:e.name,badge:(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsxs)(`span`,{className:`inline-flex items-center gap-1 font-mono text-[10px] font-medium tracking-[0.08em] text-muted-foreground uppercase`,children:[(0,Q.jsx)(i,{icon:e.plane===`operator`?Ce:fe,className:`size-3`,"aria-hidden":!0}),e.plane]}),d?(0,Q.jsx)(`span`,{className:`font-mono text-[10px] text-destructive`,children:`revoked`}):null,f&&!d?(0,Q.jsx)(`span`,{className:`font-mono text-[10px] text-amber-700 dark:text-amber-400`,children:`expired`}):null,e.unused90d&&!d&&!f?(0,Q.jsx)(`span`,{className:`font-mono text-[10px] text-amber-700 dark:text-amber-400`,children:`unused`}):null]}),subtitle:(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`code`,{className:`min-w-0 truncate font-mono text-[11px] leading-none text-foreground/80`,children:e.id}),(0,Q.jsx)(J,{value:e.id,label:`Copy ${e.id}`})]}),actions:(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(U,{label:`Rename or re-attenuate scopes`,className:`flex self-stretch`,children:(0,Q.jsx)(V,{type:`button`,variant:`ghost`,size:`sm`,className:`h-full rounded-none`,disabled:d,onClick:a,children:`Edit`})}),(0,Q.jsx)(U,{label:`Reset expiry from now. The secret stays the same.`,className:`flex self-stretch`,children:(0,Q.jsx)(V,{type:`button`,variant:`ghost`,size:`sm`,className:`h-full rounded-none`,"data-slot":`access-refresh`,disabled:d,onClick:s,children:`Refresh`})}),(0,Q.jsx)(U,{label:`Mint a new secret. The current secret stops working after residual TTL.`,className:`flex self-stretch`,children:(0,Q.jsx)(V,{type:`button`,variant:`ghost`,size:`sm`,className:`h-full rounded-none`,disabled:u||d,onClick:l,children:`Rotate`})}),(0,Q.jsx)(U,{label:`Irreversible. Residual sessions may continue for the access TTL.`,className:`flex self-stretch`,children:(0,Q.jsx)(V,{type:`button`,variant:`destructive`,size:`sm`,className:`h-full rounded-none`,disabled:d,onClick:c,children:`Revoke`})})]})}),(0,Q.jsx)(Ke,{revoked:d,expired:f,unused:e.unused90d,residual:t?.residualAccessNote}),(0,Q.jsxs)(`div`,{className:z,"data-slot":`access-briefing`,role:`group`,"aria-label":`Usage`,children:[(0,Q.jsx)(Xe,{label:`calls`,value:String(m)}),(0,Q.jsx)(Xe,{label:`used`,value:g,hint:p?new Date(p).toISOString():`No recorded call`,warn:p==null&&!d}),(0,Q.jsx)(Xe,{label:`expires`,value:h,hint:e.expiresAt?new Date(e.expiresAt).toISOString():`No expiry`,warn:f&&!d}),(0,Q.jsx)(Xe,{label:`rate`,value:_})]}),(0,Q.jsxs)(`section`,{className:`shrink-0 border-b border-border/60`,"aria-label":`Scopes`,children:[(0,Q.jsx)($,{title:`Scopes`,meta:b?`${e.scopes.length} of ${y}`:String(e.scopes.length),children:e.scopes.length>0?(0,Q.jsx)(J,{value:e.scopes.join(`
3
3
  `),label:`Copy scopes`}):null}),v.length===0?(0,Q.jsx)(`p`,{className:`px-2 py-1.5 text-[11px] text-muted-foreground`,children:`No scopes granted.`}):(0,Q.jsx)(`ul`,{"data-slot":`access-scopes`,children:v.map(e=>(0,Q.jsxs)(`li`,{className:A,"aria-label":e.group,children:[(0,Q.jsx)(`span`,{className:o(B,`w-[5.5rem] shrink-0`),children:e.group}),(0,Q.jsx)(`div`,{className:`flex min-w-0 flex-1 flex-wrap items-center gap-x-2`,children:e.items.map(e=>(0,Q.jsx)(`span`,{title:e.scope,className:`font-mono text-[11px] text-foreground`,children:e.action},e.scope))}),(0,Q.jsx)(Ze,{value:e.items.map(e=>e.scope).join(`
4
4
  `),label:`Copy ${e.group} scopes`})]},e.group))})]}),(0,Q.jsxs)(`section`,{className:`shrink-0 border-b border-border/60`,"aria-label":`Key`,children:[(0,Q.jsx)($,{title:`Key`}),(0,Q.jsxs)(`dl`,{"data-slot":`access-key-facts`,children:[(0,Q.jsx)(Qe,{label:`Issuer`,value:e.creatorId,copy:e.creatorId,copyLabel:`Copy ${e.creatorId}`}),(0,Q.jsx)(Qe,{label:`Created`,value:we(e.createdAt,n),hint:new Date(e.createdAt).toISOString()}),(0,Q.jsx)(Qe,{label:`Expires`,value:h,hint:e.expiresAt?new Date(e.expiresAt).toISOString():void 0,warn:f&&!d}),(0,Q.jsx)(Qe,{label:`Rate`,value:_})]})]}),(0,Q.jsx)(qe,{entries:e.ipAllowlist}),(0,Q.jsx)(Je,{sourceAddresses:t?.sourceAddresses??[],residual:t?.residualAccessNote,lastUsed:p,now:n}),(0,Q.jsx)(Ye,{scopes:e.scopes})]})}function Ke({revoked:e,expired:t,unused:n,residual:r}){return e?(0,Q.jsx)(`section`,{className:o(z,`border-destructive/25 bg-destructive/5`),"aria-label":`Revoked`,role:`status`,children:(0,Q.jsxs)(`p`,{className:`flex min-w-0 flex-1 items-center px-2 text-[12px] text-destructive`,children:[`Revoked`,(0,Q.jsxs)(`span`,{className:`text-muted-foreground`,children:[` `,`· `,r??`This secret no longer authenticates.`]})]})}):t?(0,Q.jsx)(`section`,{className:o(z,`border-amber-500/25 bg-amber-500/5`),"aria-label":`Expired`,role:`status`,children:(0,Q.jsxs)(`p`,{className:`flex min-w-0 flex-1 items-center px-2 text-[12px] text-amber-900 dark:text-amber-300`,children:[`Expired`,r?(0,Q.jsxs)(`span`,{className:`text-muted-foreground`,children:[` · `,r]}):null]})}):n?(0,Q.jsx)(`section`,{className:o(z,`border-amber-500/25 bg-amber-500/5`),"aria-label":`Unused`,role:`status`,children:(0,Q.jsxs)(`p`,{className:`flex min-w-0 flex-1 items-center px-2 text-[12px] text-amber-900 dark:text-amber-300`,children:[`No calls in 90 days`,(0,Q.jsx)(`span`,{className:`text-muted-foreground`,children:` · rotate or revoke`})]})}):null}function qe({entries:e}){return(0,Q.jsxs)(`section`,{className:`shrink-0 border-b border-border/60`,"aria-label":`Allow`,children:[(0,Q.jsx)($,{title:`Allow`,meta:e.length>0?String(e.length):`any`}),e.length===0?(0,Q.jsx)(`p`,{className:`px-2 py-1.5 text-[11px] text-muted-foreground`,children:`Any origin.`}):(0,Q.jsx)(`ul`,{"data-slot":`access-allow`,children:e.map(e=>{let t=Le(e);return(0,Q.jsxs)(`li`,{className:A,children:[(0,Q.jsx)(`span`,{className:o(B,`w-[5.5rem] shrink-0`),children:t===`ip`?`IP`:t===`host`?`Host`:`—`}),(0,Q.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[11px]`,children:e}),(0,Q.jsx)(Ze,{value:e,label:`Copy ${e}`})]},e)})})]})}function Je({sourceAddresses:e,residual:t,lastUsed:n,now:r}){return(0,Q.jsxs)(`section`,{className:`shrink-0 border-b border-border/60`,"aria-label":`Usage`,children:[(0,Q.jsx)($,{title:`Usage`,meta:n?we(n,r):`never`}),e.length===0?(0,Q.jsx)(`p`,{className:`px-2 py-1.5 text-[11px] text-muted-foreground`,children:`No observed source IPs.`}):(0,Q.jsx)(`ul`,{"data-slot":`access-sources`,children:e.map(e=>(0,Q.jsxs)(`li`,{className:A,children:[(0,Q.jsx)(`span`,{className:o(B,`w-[5.5rem] shrink-0`),children:`IP`}),(0,Q.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[11px]`,children:e}),(0,Q.jsx)(Ze,{value:e,label:`Copy ${e}`})]},e))}),t?(0,Q.jsx)(`p`,{className:`border-t border-border/60 px-2 py-1.5 text-[11px] text-muted-foreground`,children:t}):null]})}function Ye({scopes:e}){return(0,Q.jsxs)(`section`,{"data-slot":`access-call-example`,children:[(0,Q.jsx)($,{title:`Request`,children:(0,Q.jsx)(J,{value:Ue,label:`Copy request`})}),(0,Q.jsxs)(`div`,{className:`flex min-w-0 border-b border-border/60`,children:[(0,Q.jsx)(`div`,{className:o(`w-1 shrink-0 self-stretch`,ne(`GET`)),"aria-hidden":!0}),(0,Q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,Q.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2 px-2.5 py-2`,children:[(0,Q.jsx)(`span`,{className:o(`shrink-0 font-mono text-[10px] font-semibold tracking-[0.08em] uppercase`,_(re(`GET`))),children:`GET`}),(0,Q.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-xs text-foreground select-all`,children:`/secure`})]}),(0,Q.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2 border-t border-border/60 px-2.5 py-2`,children:[(0,Q.jsx)(`span`,{className:`w-[7.5rem] shrink-0 truncate font-mono text-[11px] font-medium text-sky-600 dark:text-sky-400`,children:`Authorization`}),(0,Q.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[11px] text-muted-foreground`,children:`Bearer <secret>`})]})]})]}),(0,Q.jsx)($,{title:`Response`,children:(0,Q.jsx)(J,{value:We,label:`Copy response`})}),(0,Q.jsxs)(`div`,{className:`flex min-w-0 border-b border-border/60`,children:[(0,Q.jsx)(`div`,{className:`w-1 shrink-0 self-stretch bg-emerald-500`,"aria-hidden":!0}),(0,Q.jsx)(`p`,{className:`min-w-0 flex-1 px-2.5 py-2 font-mono text-[11px] text-foreground/80 select-all`,children:We})]}),(0,Q.jsxs)(`p`,{className:`px-2 py-1.5 text-[11px] text-muted-foreground`,children:[`Seed the Bearer secret from create / rotate. The key is the issuer; gates see`,` `,e.join(`, `)||`its scopes`,`.`]})]})}function $({title:e,meta:t,children:n}){return(0,Q.jsxs)(`header`,{className:o(z,`items-center gap-2 px-2`),children:[(0,Q.jsx)(`h3`,{className:o(B,`shrink-0 leading-none`),children:e}),t?(0,Q.jsx)(`span`,{className:o(x,!n&&`ml-auto`),children:t}):null,n?(0,Q.jsx)(`div`,{className:`ml-auto flex items-center`,children:n}):null]})}function Xe({label:e,value:t,hint:n,warn:r=!1}){return(0,Q.jsxs)(`span`,{title:n,className:o(S,H,`gap-1.5`),children:[(0,Q.jsx)(`span`,{className:`tracking-[0.08em] uppercase`,children:e}),(0,Q.jsx)(`span`,{className:o(`font-mono tabular-nums text-foreground`,r&&`text-amber-800 dark:text-amber-400`),children:t})]})}function Ze({value:e,label:t}){return(0,Q.jsx)(`div`,{className:`opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100`,children:(0,Q.jsx)(J,{value:e,label:t})})}function Qe({label:e,value:t,hint:n,copy:r,copyLabel:i,warn:a=!1}){return(0,Q.jsxs)(`div`,{className:A,children:[(0,Q.jsx)(`dt`,{className:o(B,`w-[5.5rem] shrink-0`),children:e}),(0,Q.jsx)(`dd`,{className:o(`min-w-0 flex-1 truncate font-mono text-[11px]`,a&&`text-amber-800 dark:text-amber-400`),title:n,children:t}),r?(0,Q.jsx)(Ze,{value:r,label:i??`Copy ${e}`}):null]})}var $e=[`console.access.list`];function et(){return y({queryKey:$e,queryFn:async()=>{let e=await c();if(e.error||!e.data)throw Error(e.error?.message??`Empty access list`);return e.data}})}function tt({rows:e,selectedKey:t,query:n,loading:r=!1,onSelect:i}){let a=e.filter(e=>e.plane===`user`),o=e.filter(e=>e.plane===`operator`);return(0,Q.jsxs)(`div`,{id:`access-list`,"data-slot":`access-list`,className:`min-h-0 flex-1 overflow-y-auto`,children:[r&&e.length===0?(0,Q.jsx)(`p`,{className:R,children:`Loading…`}):null,!r&&e.length===0&&n.trim().length>0?(0,Q.jsx)(`p`,{className:R,children:`No keys match.`}):null,(0,Q.jsx)(nt,{label:`User`,icon:fe,rows:a,selectedKey:t,onSelect:i}),(0,Q.jsx)(nt,{label:`Operator`,icon:Ce,rows:o,selectedKey:t,onSelect:i})]})}function nt(e){return(0,Q.jsxs)(`section`,{className:L,"aria-label":e.label,children:[(0,Q.jsxs)(`div`,{className:j,children:[(0,Q.jsx)(i,{icon:e.icon,className:o(k,`text-muted-foreground`),"aria-hidden":!0}),(0,Q.jsx)(`span`,{className:o(P,`flex-1`),children:e.label}),(0,Q.jsx)(`span`,{className:x,children:e.rows.length})]}),e.rows.map(t=>{let n=t.id===e.selectedKey,r=t.revokedAt!==null;return(0,Q.jsxs)(`button`,{type:`button`,"data-slot":`access-key-row`,className:o(A,n&&`bg-muted/70 text-foreground`),onClick:()=>e.onSelect(t.id),children:[(0,Q.jsx)(`span`,{className:o(N,n&&`bg-sky-500`)}),(0,Q.jsx)(i,{icon:oe,className:o(k,`text-muted-foreground`)}),(0,Q.jsx)(`span`,{className:o(`min-w-0 truncate`,r&&`text-muted-foreground line-through`),children:t.name}),r?(0,Q.jsx)(`span`,{className:`ml-auto text-[10px] text-muted-foreground`,children:`revoked`}):t.unused90d?(0,Q.jsx)(`span`,{className:`ml-auto text-[10px] text-amber-700 dark:text-amber-400`,children:`unused`}):(0,Q.jsx)(`span`,{className:o(`ml-auto tabular-nums text-[10px] text-muted-foreground`),children:t.scopes.length})]},t.id)})]})}function rt({entries:e,rateMax:t,rateCount:n,rateUnit:r,onEntries:c,onRateMax:u,onRateCount:d,onRateUnit:f}){let[p,h]=(0,Y.useState)(``),_=Re(p),v=p.trim().length>0&&_.length===0,y=()=>{if(_.length===0)return;let t=new Set(e),n=[...e];for(let e of _)t.has(e)||(t.add(e),n.push(e));c(n),h(``)};return(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsxs)(`div`,{className:`border-b border-border/50`,"data-slot":`access-allow-field`,children:[(0,Q.jsxs)(`div`,{className:`flex items-stretch`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Allow`}),(0,Q.jsx)(a,{value:p,onChange:e=>h(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),y())},placeholder:`203.0.113.4 or ci.example.com`,autoComplete:`off`,"aria-label":`Add allow entry`,"aria-invalid":v,flat:!0,className:o(q,`min-w-0 flex-1 font-mono`)}),e.length>0?(0,Q.jsx)(`span`,{className:o(x,`flex h-8 items-center pr-2`),children:e.length}):null,(0,Q.jsx)(`button`,{type:`button`,className:o(w,`h-8`),"aria-label":`Add allow entry`,disabled:_.length===0,onClick:y,children:(0,Q.jsx)(i,{icon:pe,className:`size-3.5`,"aria-hidden":!0})})]}),v?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-2 text-[11px] text-destructive`,children:`Need an IP or host — 203.0.113.4, ::1, localhost, or ci.example.com.`}):e.length===0?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-2 text-[11px] text-muted-foreground`,children:`Any client. Add an IP or host.`}):(0,Q.jsx)(`div`,{role:`list`,"aria-label":`Allow list`,children:e.map(t=>{let n=Le(t);return(0,Q.jsxs)(`div`,{role:`listitem`,"data-slot":`access-allow-entry`,"data-kind":n??`invalid`,className:o(A,`last:border-b-0`),children:[(0,Q.jsx)(`span`,{className:o(B,`w-[5.5rem] shrink-0 px-1.5`,n==null&&`text-destructive`),children:n===`ip`?`IP`:n===`host`?`Host`:`Bad`}),(0,Q.jsx)(`span`,{className:o(`min-w-0 truncate font-mono text-[11px]`,n==null&&`text-destructive`),children:t}),(0,Q.jsx)(`button`,{type:`button`,className:o(I,`ml-auto opacity-0 group-hover:opacity-100 focus-visible:opacity-100`),"aria-label":`Remove ${t}`,onClick:()=>c(e.filter(e=>e!==t)),children:(0,Q.jsx)(i,{icon:D,className:`size-3`,"aria-hidden":!0})})]},t)})})]}),(0,Q.jsxs)(`div`,{className:`flex items-stretch border-b border-border/50`,"data-slot":`access-rate-field`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Rate`}),(0,Q.jsxs)(`label`,{className:`flex min-w-0 flex-1 items-stretch border-r border-border/50`,children:[(0,Q.jsx)(`span`,{className:`flex h-8 shrink-0 items-center pl-1 text-[10px] font-semibold tracking-[0.08em] text-muted-foreground uppercase`,children:`Max`}),(0,Q.jsx)(a,{value:t,onChange:e=>u(e.target.value),placeholder:`none`,inputMode:`numeric`,autoComplete:`off`,"aria-label":`Rate max`,flat:!0,className:o(q,`min-w-0 flex-1 px-2 font-mono tabular-nums`)})]}),(0,Q.jsxs)(`label`,{className:`flex min-w-0 flex-1 items-stretch`,children:[(0,Q.jsx)(`span`,{className:`flex h-8 shrink-0 items-center pl-2 text-[10px] font-semibold tracking-[0.08em] text-muted-foreground uppercase`,children:`Every`}),(0,Q.jsx)(a,{value:n,onChange:e=>d(e.target.value),placeholder:`1`,inputMode:`numeric`,autoComplete:`off`,"aria-label":`Rate window`,flat:!0,className:o(q,`min-w-0 flex-1 px-2 font-mono tabular-nums`)})]}),(0,Q.jsx)(`div`,{className:`flex h-8 shrink-0 items-stretch`,role:`group`,"aria-label":`Rate unit`,children:Ne.map(e=>(0,Q.jsxs)(s,{children:[(0,Q.jsx)(m,{render:t=>(0,Q.jsx)(`button`,{...t,type:`button`,"aria-pressed":r===e,"aria-label":Pe[e],onClick:n=>{t.onClick?.(n),f(e)},className:o(S,`h-8 px-1.5 font-mono font-semibold`,r===e?g:H),children:e})}),(0,Q.jsx)(l,{side:`bottom`,className:`text-[11px]`,children:Pe[e]})]},e))})]})]})}function it({expires:e,customExpires:t,onExpires:n,onCustomExpires:r}){return(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsxs)(ve,{label:`Expires`,children:[(0,Q.jsx)(G,{active:e===`never`,onClick:()=>n(`never`),children:`never`}),(0,Q.jsx)(G,{active:e===`30d`,onClick:()=>n(`30d`),children:`30d`}),(0,Q.jsx)(G,{active:e===`90d`,onClick:()=>n(`90d`),children:`90d`}),(0,Q.jsx)(G,{active:e===`custom`,onClick:()=>n(`custom`),children:`custom`})]}),e===`custom`?(0,Q.jsx)(_e,{label:`Duration`,hint:`7d · 12h · 30m`,children:(0,Q.jsx)(a,{value:t,onChange:e=>r(e.target.value),placeholder:`7d`,autoComplete:`off`,"aria-label":`Custom expiry duration`,flat:!0,className:o(q,`font-mono`)})}):null]})}function at({value:e,placeholder:t,label:n,onChange:r}){return(0,Q.jsxs)(`label`,{className:`relative min-w-0 flex-1`,children:[(0,Q.jsx)(i,{icon:he,className:`pointer-events-none absolute top-1/2 left-3 size-3.5 -translate-y-1/2 text-muted-foreground`,"aria-hidden":!0}),(0,Q.jsx)(a,{value:e,onChange:e=>r(e.target.value),placeholder:t,"aria-label":n,autoComplete:`off`,flat:!0,className:o(ye)})]})}function ot({scopes:e,selected:t,empty:n,onChange:r}){let[i,a]=(0,Y.useState)(``),s=new Set(t),c=(0,Y.useMemo)(()=>st(e,i),[e,i]),l=(0,Y.useMemo)(()=>He(c),[c]),u=e.join(`\0`);return(0,Y.useEffect)(()=>{a(``)},[u]),(0,Q.jsxs)(`div`,{className:`border-b border-border/50`,"data-slot":`access-scope-field`,children:[(0,Q.jsxs)(`div`,{className:`flex items-stretch`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Scopes`}),e.length>0?(0,Q.jsx)(at,{value:i,placeholder:`Search scopes`,label:`Search scopes`,onChange:a}):null]}),e.length===0?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-3 text-[11px] text-muted-foreground`,children:n}):c.length===0?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-3 text-[11px] text-muted-foreground`,children:`No scopes match.`}):(0,Q.jsx)(`div`,{className:`max-h-56 overflow-y-auto`,role:`group`,"aria-label":`Scopes`,children:l.map(e=>(0,Q.jsxs)(`div`,{className:`flex items-stretch border-t border-border/50`,role:`group`,"aria-label":e.group,children:[(0,Q.jsx)(`p`,{className:`flex w-[5.5rem] shrink-0 items-center px-4 font-mono text-[10px] font-semibold tracking-[0.08em] text-muted-foreground uppercase`,children:e.group}),(0,Q.jsx)(`div`,{className:`flex min-w-0 flex-1 flex-wrap items-stretch`,children:e.items.map(e=>{let n=s.has(e.scope);return(0,Q.jsx)(`button`,{type:`button`,"aria-pressed":n,"aria-label":e.scope,"data-slot":`access-scope-chip`,title:e.scope,onClick:()=>{r(n?t.filter(t=>t!==e.scope):[...t,e.scope])},className:o(`inline-flex h-8 min-w-0 items-center px-2 font-mono text-[10px] font-semibold outline-none select-none`,`focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-inset`,n?`bg-muted text-foreground`:`text-muted-foreground hover:text-foreground`),children:e.action},e.scope)})})]},e.group))})]})}function st(e,t){let n=t.trim().toLowerCase();return n.length===0?e:e.filter(e=>e.toLowerCase().includes(n))}function ct({open:e,users:t,userScopes:n,operatorScopes:r,pending:i,error:s,onOpenChange:c,onSubmit:l}){let[u,d]=(0,Y.useState)(`user`),[f,p]=(0,Y.useState)(``),[m,h]=(0,Y.useState)(``),[g,_]=(0,Y.useState)([]),[v,y]=(0,Y.useState)(`never`),[b,x]=(0,Y.useState)(``),[S,w]=(0,Y.useState)([]),[T,ee]=(0,Y.useState)(``),[D,k]=(0,Y.useState)(``),[j,P]=(0,Y.useState)(`m`),[I,L]=(0,Y.useState)(``),R=t.find(e=>e.id===m)??null,z=(0,Y.useMemo)(()=>{let e=I.trim().toLowerCase(),n=e.length===0?t:t.filter(t=>t.name.toLowerCase().includes(e)||t.id.toLowerCase().includes(e)||t.email.toLowerCase().includes(e));return R&&!n.some(e=>e.id===R.id)?[R,...n]:n},[t,I,R]),B=(0,Y.useMemo)(()=>u===`operator`?r:R==null?[]:R.scopes.length>0?R.scopes:n,[u,n,r,R]);(0,Y.useEffect)(()=>{e||(d(`user`),p(``),h(``),_([]),y(`never`),x(``),w([]),ee(``),k(``),P(`m`),L(``))},[e]),(0,Y.useEffect)(()=>{_(e=>{let t=e.filter(e=>B.includes(e));if(t.length>0)return t;let n=B[0];return n?[n]:[]})},[B]);let V=De(b),H=Fe(T,D,j),ne=f.trim().length>0&&g.length>0&&!i&&H!==void 0&&(u===`operator`||m.length>0)&&(v!==`custom`||V>0);return(0,Q.jsx)(E,{open:e,modal:!1,disablePointerDismissal:!0,onOpenChange:c,children:(0,Q.jsxs)(M,{side:`right`,showOverlay:!1,className:`gap-0 p-0 data-[side=right]:sm:max-w-md`,"data-slot":`access-create-sheet`,children:[(0,Q.jsxs)(O,{className:`gap-1 border-b border-border/50`,children:[(0,Q.jsx)(te,{className:`text-sm`,children:`Create API key`}),(0,Q.jsx)(F,{className:`text-[11px]`,children:u===`user`?`User-plane keys require an issuer. The key cannot exceed that user's grants.`:`Operator keys inherit the actor ceiling. Absence is impossible — only grantable scopes appear.`})]}),(0,Q.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto`,children:[(0,Q.jsxs)(`div`,{className:`flex items-stretch border-b border-border/50`,"data-slot":`access-name-field`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Name`}),(0,Q.jsx)(a,{value:f,onChange:e=>p(e.target.value),placeholder:`CI deploy`,autoComplete:`off`,"aria-label":`Key name`,flat:!0,className:o(q,`min-w-0 flex-1`)})]}),(0,Q.jsxs)(ve,{label:`Plane`,children:[(0,Q.jsx)(G,{active:u===`user`,icon:fe,onClick:()=>{d(`user`)},children:`user`}),(0,Q.jsx)(G,{active:u===`operator`,icon:Ce,onClick:()=>{d(`operator`),h(``),L(``)},children:`operator`})]}),(0,Q.jsx)(it,{expires:v,customExpires:b,onExpires:y,onCustomExpires:x}),(0,Q.jsx)(rt,{entries:S,rateMax:T,rateCount:D,rateUnit:j,onEntries:w,onRateMax:ee,onRateCount:k,onRateUnit:P}),u===`user`?(0,Q.jsxs)(`div`,{className:`border-b border-border/50`,"data-slot":`access-issuer-field`,children:[(0,Q.jsxs)(`div`,{className:`flex items-stretch`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Issuer`}),t.length>0?(0,Q.jsx)(at,{value:I,placeholder:`Search users`,label:`Search users`,onChange:L}):null]}),t.length===0?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-3 text-[11px] text-muted-foreground`,children:`No users on this plane.`}):z.length===0?(0,Q.jsx)(`p`,{className:`border-t border-border/50 px-4 py-3 text-[11px] text-muted-foreground`,children:`No users match.`}):(0,Q.jsx)(`div`,{className:`max-h-56 overflow-y-auto`,children:z.map(e=>{let t=e.id===m;return(0,Q.jsxs)(`button`,{type:`button`,"data-slot":`access-creator-user`,"aria-pressed":t,className:o(A,t&&`bg-muted/70 text-foreground`),onClick:()=>h(e.id),children:[(0,Q.jsx)(`span`,{className:o(N,t&&`bg-sky-500`)}),(0,Q.jsx)(`span`,{className:`min-w-0 truncate`,children:e.name}),(0,Q.jsx)(`span`,{className:`ml-auto shrink-0 font-mono text-[10px] text-muted-foreground`,children:e.id})]},e.id)})})]}):null,(0,Q.jsx)(ot,{scopes:B,selected:g,empty:u===`user`&&m.length===0?`Select an issuer to see grantable scopes.`:u===`user`?`This user has no grants.`:`No grantable scopes on this plane.`,onChange:_}),s?(0,Q.jsx)(be,{slot:`access-create-error`,children:s}):null]}),(0,Q.jsxs)(C,{children:[(0,Q.jsx)(K,{split:!0,onClick:()=>c(!1),disabled:i,children:`Cancel`}),(0,Q.jsx)(K,{variant:`default`,disabled:!ne,"data-slot":`access-create-submit`,onClick:()=>{if(H===void 0)return;let e=Oe(v,Date.now(),b);l({plane:u,name:f.trim(),scopes:g,...u===`user`?{creatorUserId:m}:{},...e==null?{}:{expiresAt:e},...H==null?{}:{rateLimit:H},...S.length>0?{ipAllowlist:S}:{}})},children:i?`Creating…`:`Create`})]})]})})}function lt({open:e,keyRow:t,users:n,operators:r,operatorScopes:s,pending:c,error:l,now:u=Date.now(),onOpenChange:d,onSubmit:f}){let p=ke(t.expiresAt,u),[m,h]=(0,Y.useState)(t.name),[g,_]=(0,Y.useState)(t.scopes),[v,y]=(0,Y.useState)(p.choice),[b,x]=(0,Y.useState)(p.custom),[S,w]=(0,Y.useState)(t.ipAllowlist),T=Ie(t.rateLimit?.per??``),[ee,D]=(0,Y.useState)(t.rateLimit?String(t.rateLimit.max):``),[k,A]=(0,Y.useState)(T.count),[j,N]=(0,Y.useState)(T.unit);(0,Y.useEffect)(()=>{if(!e)return;let n=ke(t.expiresAt,u);h(t.name),_(t.scopes),y(n.choice),x(n.custom),w(t.ipAllowlist);let r=Ie(t.rateLimit?.per??``);D(t.rateLimit?String(t.rateLimit.max):``),A(r.count),N(r.unit)},[e,t.id]);let P=t.creatorId??``,I=(0,Y.useMemo)(()=>P.length===0?null:n.find(e=>e.id===P)??r.find(e=>e.id===P)??null,[P,r,n]),L=I?I.name.trim()||I.email.trim()||I.id:P||`Unknown`,R=(0,Y.useMemo)(()=>{let e=t.creatorScopes??[];return e.length>0?e:t.plane===`operator`?I&&I.scopes.length>0?I.scopes:s:I?.scopes??[]},[I,t.creatorScopes,t.plane,s]),z=Array.from(new Set([...R,...t.scopes])),B=De(b),V=Fe(ee,k,j),H=m.trim().length>0&&g.length>0&&!c&&V!==void 0&&(v!==`custom`||B>0);return(0,Q.jsx)(E,{open:e,modal:!1,disablePointerDismissal:!0,onOpenChange:d,children:(0,Q.jsxs)(M,{side:`right`,showOverlay:!1,className:`gap-0 p-0 data-[side=right]:sm:max-w-md`,"data-slot":`access-edit-sheet`,children:[(0,Q.jsxs)(O,{className:`gap-1 border-b border-border/50`,children:[(0,Q.jsx)(te,{className:`text-sm`,children:`Edit key`}),(0,Q.jsx)(F,{className:`text-[11px]`,children:`Change name, expiry, allow, rate, and scopes. Issuer stays frozen.`})]}),(0,Q.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto`,children:[(0,Q.jsxs)(`div`,{className:`flex items-stretch border-b border-border/50`,"data-slot":`access-name-field`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Name`}),(0,Q.jsx)(a,{value:m,onChange:e=>h(e.target.value),placeholder:`CI deploy`,autoComplete:`off`,"aria-label":`Key name`,flat:!0,className:o(q,`min-w-0 flex-1`)})]}),(0,Q.jsxs)(`div`,{className:`flex items-stretch border-b border-border/50`,"data-slot":`access-issuer-field`,children:[(0,Q.jsx)(`p`,{className:`flex h-8 w-[5.5rem] shrink-0 items-center px-4 text-[10px] font-semibold tracking-[0.12em] text-muted-foreground uppercase`,children:`Issuer`}),(0,Q.jsxs)(`p`,{className:`flex min-w-0 flex-1 items-center gap-1.5 px-4 text-[12px] text-muted-foreground`,"aria-label":`Issuer ${L}`,children:[(0,Q.jsx)(i,{icon:t.plane===`operator`?Ce:fe,className:`size-3 shrink-0`,"aria-hidden":!0}),(0,Q.jsx)(`span`,{className:`min-w-0 truncate text-foreground`,children:L})]}),P.length>0&&P!==L?(0,Q.jsx)(`span`,{className:`flex h-8 shrink-0 items-center pr-4 font-mono text-[10px] text-muted-foreground`,children:P}):null]}),(0,Q.jsx)(it,{expires:v,customExpires:b,onExpires:y,onCustomExpires:x}),(0,Q.jsx)(rt,{entries:S,rateMax:ee,rateCount:k,rateUnit:j,onEntries:w,onRateMax:D,onRateCount:A,onRateUnit:N}),(0,Q.jsx)(ot,{scopes:z,selected:g,empty:t.plane===`user`&&I==null?`Issuer is gone. Only scopes already on this key remain.`:t.plane===`user`?`This issuer has no grants.`:`No grantable scopes on this plane.`,onChange:_}),l?(0,Q.jsx)(be,{slot:`access-edit-error`,children:l}):null]}),(0,Q.jsxs)(C,{children:[(0,Q.jsx)(K,{split:!0,onClick:()=>d(!1),disabled:c,children:`Cancel`}),(0,Q.jsx)(K,{variant:`default`,disabled:!H,"data-slot":`access-edit-submit`,onClick:()=>{V!==void 0&&f({name:m.trim(),scopes:g,expiresAt:Oe(v,Date.now(),b),rateLimit:V,ipAllowlist:S})},children:c?`Saving…`:`Save`})]})]})})}function ut({open:e,keyRow:t,pending:n,error:r,now:i=Date.now(),onOpenChange:a,onSubmit:o}){let s=je(t.expiresAt,i),[c,l]=(0,Y.useState)(s.choice),[u,d]=(0,Y.useState)(s.custom);(0,Y.useEffect)(()=>{if(!e)return;let n=je(t.expiresAt,i);l(n.choice),d(n.custom)},[e,t.id]);let f=De(u);return(0,Q.jsx)(E,{open:e,modal:!1,disablePointerDismissal:!0,onOpenChange:a,children:(0,Q.jsxs)(M,{side:`right`,showOverlay:!1,className:`gap-0 p-0 data-[side=right]:sm:max-w-md`,"data-slot":`access-refresh-sheet`,children:[(0,Q.jsxs)(O,{className:`gap-1 border-b border-border/50`,children:[(0,Q.jsx)(te,{className:`text-sm`,children:`Refresh expiry`}),(0,Q.jsx)(F,{className:`text-[11px]`,children:`Reset the deadline from now. The secret does not change.`})]}),(0,Q.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto`,children:[(0,Q.jsx)(it,{expires:c,customExpires:u,onExpires:l,onCustomExpires:d}),r?(0,Q.jsx)(be,{slot:`access-refresh-error`,children:r}):null]}),(0,Q.jsxs)(C,{children:[(0,Q.jsx)(K,{split:!0,onClick:()=>a(!1),disabled:n,children:`Cancel`}),(0,Q.jsx)(K,{variant:`default`,disabled:!(!n&&(c!==`custom`||f>0)),"data-slot":`access-refresh-submit`,onClick:()=>{o(Oe(c,Date.now(),u))},children:n?`Refreshing…`:`Refresh`})]})]})})}function dt({secret:e,title:t=`New API key`,onDismiss:n}){let[r,i]=(0,Y.useState)(!1);return(0,Q.jsx)(E,{open:e!==null,onOpenChange:e=>{e||n()},children:(0,Q.jsxs)(M,{side:`right`,showOverlay:!1,className:`gap-0 p-0 data-[side=right]:sm:max-w-md`,"data-slot":`access-secret-sheet`,children:[(0,Q.jsxs)(O,{className:`gap-1 border-b border-border/50`,children:[(0,Q.jsx)(te,{className:`text-sm`,children:t}),(0,Q.jsx)(F,{className:`text-[11px]`,children:`Shown once. Store it offline. This Console process does not keep it for you.`})]}),(0,Q.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto`,children:[(0,Q.jsx)(`p`,{className:`border-b border-border/50 px-4 py-3 font-mono text-[11px] break-all`,children:e}),(0,Q.jsx)(`p`,{className:`px-4 py-3 text-[11px] text-muted-foreground`,role:`status`,children:`Copying puts the secret on the clipboard. Anyone with this device can read it until you clear it.`})]}),(0,Q.jsxs)(C,{children:[(0,Q.jsx)(K,{split:!0,disabled:!e,onClick:()=>{e&&(navigator.clipboard?.writeText(e),i(!0))},children:r?`Copied`:`Copy (clipboard warning)`}),(0,Q.jsx)(K,{variant:`destructive`,onClick:()=>{i(!1),n()},children:`I have stored this key`})]})]})})}function ft(){let e=et(),t=ee(),{query:n,selectedKey:a,action:o,setQuery:s,setSelectedKey:c,setAction:l}=me(),m=ce(),[g]=(0,Y.useState)(()=>Date.now()),[_,x]=(0,Y.useState)(null),[S,C]=(0,Y.useState)(`New API key`),E=(0,Y.useMemo)(()=>{let t=e.data?.userPlane.keys??[],n=e.data?.operatorPlane.keys??[];return[...t,...n]},[e.data]),D=(0,Y.useMemo)(()=>{let e=n.trim().toLowerCase();return e?E.filter(t=>t.name.toLowerCase().includes(e)||t.id.toLowerCase().includes(e)||t.scopes.some(t=>t.toLowerCase().includes(e))):E},[E,n]),O=D.find(e=>e.id===a)??E.find(e=>e.id===a),k=y({queryKey:[`console.access.blast`,O?.id],queryFn:async()=>{if(!O)throw Error(`no key`);let e=await p(O.id);if(e.error||!e.data)throw Error(e.error?.message??`blast failed`);return e.data},enabled:O!==void 0});(0,Y.useEffect)(()=>{let e=e=>{if(e.key!==`/`||e.metaKey||e.ctrlKey||e.altKey)return;let t=e.target;if(t instanceof HTMLElement){let e=t.tagName;if(e===`INPUT`||e===`TEXTAREA`||t.isContentEditable)return}e.preventDefault(),document.querySelector(`[data-slot='access-search-input']`)?.focus()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[]);let A=()=>{t.invalidateQueries({queryKey:$e})},j=W({mutationFn:f,onSuccess:e=>{if(e.error||!e.data)throw Error(e.error?v(e.error):`create failed`);C(`New API key`),x(e.data.secret),c(e.data.key.id),l(null),A()}}),M=W({mutationFn:e=>d({keyId:O.id,confirmation:e.confirmation,reason:e.reason}),onSuccess:e=>{if(e.error||!e.data)throw Error(e.error?v(e.error):`rotate failed`);C(`Rotated API key`),x(e.data.secret),l(null),A()}}),N=W({mutationFn:e=>u({keyId:O.id,confirmation:e.confirmation,reason:e.reason}),onSuccess:e=>{if(e.error||!e.data)throw Error(e.error?v(e.error):`revoke failed`);l(null),A()}}),P=W({mutationFn:h,onSuccess:e=>{if(e.error||!e.data)throw Error(e.error?v(e.error):`update failed`);l(null),A()}}),F=W({mutationFn:e=>h({keyId:O.id,expiresAt:e}),onSuccess:e=>{if(e.error||!e.data)throw Error(e.error?v(e.error):`refresh failed`);l(null),A()}}),I=(0,Q.jsx)(le,{open:m.open,onToggle:m.toggle,noun:`keys`,controlsId:`access-list`,dataSlot:`access-list-toggle`});return(0,Q.jsxs)(`div`,{className:T,"data-slot":`access-page`,children:[(0,Q.jsxs)(ie,{orientation:`horizontal`,className:`min-h-0 flex-1`,children:[(0,Q.jsx)(se,{panelRef:m.panelRef,collapsible:!0,collapsedSize:0,defaultSize:b.start.defaultSize,minSize:b.start.minSize,onResize:m.onResize,className:`min-h-0 overflow-hidden`,children:(0,Q.jsxs)(`div`,{className:`flex h-full min-h-0 flex-col overflow-hidden`,children:[(0,Q.jsxs)(`div`,{className:r,children:[(0,Q.jsx)(ae,{"data-slot":`access-search-input`,placeholder:`Search keys`,"aria-label":`Search keys`,value:n,onChange:e=>s(e.target.value)}),(0,Q.jsx)(U,{label:`Create key`,className:`flex self-stretch`,children:(0,Q.jsx)(`button`,{type:`button`,className:w,"data-slot":`access-create`,"aria-label":`Create key`,onClick:()=>l(`create`),children:(0,Q.jsx)(i,{icon:pe,className:`size-3.5`})})})]}),(0,Q.jsx)(tt,{rows:D,selectedKey:a,query:n,loading:e.isLoading,onSelect:c})]})}),m.open?(0,Q.jsx)(ue,{withHandle:!0}):null,(0,Q.jsx)(se,{defaultSize:b.end.defaultSize,minSize:b.end.minSize,className:`min-h-0 overflow-hidden`,children:O?(0,Q.jsx)(Ge,{keyRow:O,blast:k.data,now:g,leading:I,onEdit:()=>l(`edit`),onRefresh:()=>l(`refresh`),onRevoke:()=>l(`revoke`),onRotate:()=>l(`rotate`),rotatePending:M.isPending}):(0,Q.jsx)(ge,{icon:de.gate.icon,iconClassName:`border-border/70`,title:e.isLoading?`Loading keys…`:E.length>0?`Select a key`:`No keys yet`,leading:I,description:e.isLoading?`Reading planes and grantable scopes.`:E.length>0&&n.trim().length>0?(0,Q.jsxs)(Q.Fragment,{children:[`Nothing matches `,(0,Q.jsx)(`span`,{className:`font-mono`,children:n}),`.`,` `,(0,Q.jsx)(`button`,{type:`button`,className:`underline underline-offset-2 hover:text-foreground`,onClick:()=>s(``),children:`Clear search`})]}):`Create one to mint a secret once.`})})]}),(0,Q.jsx)(ct,{open:o===`create`,users:e.data?.userPlane.users??[],userScopes:e.data?.userPlane.grantableScopes??[],operatorScopes:e.data?.operatorPlane.grantableScopes??[],pending:j.isPending,error:j.error instanceof Error?j.error.message:null,onOpenChange:e=>{e||l(null)},onSubmit:e=>j.mutate(e)}),O?(0,Q.jsx)(lt,{open:o===`edit`,keyRow:O,users:e.data?.userPlane.users??[],operators:e.data?.operatorPlane.operators??[],operatorScopes:e.data?.operatorPlane.grantableScopes??[],pending:P.isPending,error:P.error instanceof Error?P.error.message:null,onOpenChange:e=>{e||l(null)},onSubmit:e=>P.mutate({keyId:O.id,...e})}):null,O?(0,Q.jsx)(ut,{open:o===`refresh`,keyRow:O,pending:F.isPending,error:F.error instanceof Error?F.error.message:null,onOpenChange:e=>{e||l(null)},onSubmit:e=>F.mutate(e)}):null,O?(0,Q.jsx)(Se,{open:o===`revoke`,onOpenChange:e=>{e||l(null)},phrase:`REVOKE`,title:`Revoke ${O.name}`,description:`Irreversible. Residual sessions may continue for the access TTL.`,pending:N.isPending,error:N.error instanceof Error?N.error.message:null,confirmLabel:`Revoke key`,slot:`access-revoke-sheet`,onConfirm:e=>N.mutate({confirmation:`REVOKE`,reason:e.reason})}):null,O?(0,Q.jsx)(Se,{open:o===`rotate`,onOpenChange:e=>{e||l(null)},phrase:`ROTATE`,title:`Rotate ${O.name}`,description:`Mints a new secret once. The current secret stops after residual TTL.`,pending:M.isPending,error:M.error instanceof Error?M.error.message:null,confirmLabel:`Rotate key`,confirmVariant:`ghost`,slot:`access-rotate-sheet`,onConfirm:e=>M.mutate({confirmation:`ROTATE`,reason:e.reason})}):null,(0,Q.jsx)(dt,{secret:_,title:S,onDismiss:()=>x(null)})]})}export{ft as AccessPage};
@@ -1 +1 @@
1
- import{A as e}from"./xyflow-yApv7D4e.js";import{Er as t}from"./shortcut-keys-3ILd8oGn.js";import{X as n,c as r,l as i}from"./index-D1vE656k.js";var a=e();function o({open:e,openHeight:o=`auto`,className:s,style:c,transition:l,...u}){let d=i()??!1;return(0,a.jsx)(r.div,{...u,"aria-hidden":!e,inert:!e||void 0,initial:!1,animate:d?{opacity:+!!e}:{opacity:+!!e,clipPath:e?`inset(0 0 0% 0)`:`inset(0 0 100% 0)`,y:e?0:-4},transition:l??{duration:d?0:e?.22:.14,ease:n},className:t(`overflow-hidden`,s),style:{...c,height:e?o:0,pointerEvents:e?void 0:`none`,transformOrigin:`top`}})}export{o as t};
1
+ import{A as e}from"./xyflow-yApv7D4e.js";import{Er as t}from"./shortcut-keys-3ILd8oGn.js";import{X as n,c as r,l as i}from"./index-C3KoC-mS.js";var a=e();function o({open:e,openHeight:o=`auto`,className:s,style:c,transition:l,...u}){let d=i()??!1;return(0,a.jsx)(r.div,{...u,"aria-hidden":!e,inert:!e||void 0,initial:!1,animate:d?{opacity:+!!e}:{opacity:+!!e,clipPath:e?`inset(0 0 0% 0)`:`inset(0 0 100% 0)`,y:e?0:-4},transition:l??{duration:d?0:e?.22:.14,ease:n},className:t(`overflow-hidden`,s),style:{...c,height:e?o:0,pointerEvents:e?void 0:`none`,transformOrigin:`top`}})}export{o as t};