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.
- package/package.json +1 -1
- package/site/content/docs/elements/channel/index.mdx +1 -1
- package/site/content/docs/elements/clock/index.mdx +53 -105
- package/site/content/docs/elements/clock/schedules.mdx +39 -11
- package/site/content/docs/elements/flow/consumers.mdx +54 -31
- package/site/content/docs/elements/flow/index.mdx +6 -9
- package/site/content/docs/elements/flow/routing.mdx +11 -15
- package/site/content/docs/elements/signal/broadcast.mdx +6 -1
- package/site/content/docs/elements/signal/index.mdx +21 -177
- package/site/content/docs/elements/signal/once.mdx +6 -1
- package/site/content/docs/reference/cli.mdx +14 -1
- package/site/content/docs/reference/errors.mdx +7 -0
- package/site/content/docs/understand/the-architecture.mdx +2 -2
- package/site/content/docs/understand/try-it.mdx +1 -1
- package/src/cli/competitor-mention-removal.test.ts +3 -3
- package/src/cli/dev-app-runner.ts +23 -2
- package/src/cli/dev.test.ts +47 -0
- package/src/cli/dev.ts +11 -0
- package/src/compiler/extract-skip.test.ts +43 -0
- package/src/compiler/extract.test.ts +190 -15
- package/src/compiler/extract.ts +57 -7
- package/src/compiler/flow-path.test.ts +36 -0
- package/src/compiler/flow-path.ts +35 -1
- package/src/compiler/generate-adopt.ts +12 -2
- package/src/console/ui-next/dist/assets/{access-page-BpugjHHY.js → access-page-BDbw40sZ.js} +1 -1
- package/src/console/ui-next/dist/assets/{agent-disclosure-qnsmtJhf.js → agent-disclosure-CVhs5xog.js} +1 -1
- package/src/console/ui-next/dist/assets/{cache-glyph-BcpWUM98.js → cache-glyph-CKIaJ1te.js} +1 -1
- package/src/console/ui-next/dist/assets/{call-pii-button-Bz5xiNmR.js → call-pii-button-CPH68-4L.js} +1 -1
- package/src/console/ui-next/dist/assets/{collapsible-Cuxn2WH8.js → collapsible-DYYX3bKy.js} +1 -1
- package/src/console/ui-next/dist/assets/{duration-tone-Bjnl3EaM.js → duration-tone-BnRJ32O5.js} +1 -1
- package/src/console/ui-next/dist/assets/{flows-page-DVujp-T2.js → flows-page-DwEDnJqd.js} +1 -1
- package/src/console/ui-next/dist/assets/{highlighted-json-Bql0qlqW.js → highlighted-json-BemWpaqn.js} +1 -1
- package/src/console/ui-next/dist/assets/{http-method-BljvrfRg.js → http-method-CAboOgAE.js} +1 -1
- package/src/console/ui-next/dist/assets/{index-D1vE656k.js → index-C3KoC-mS.js} +3 -3
- package/src/console/ui-next/dist/assets/index-VxoEz295.css +2 -0
- package/src/console/ui-next/dist/assets/{observability-page-Bdi0bLJl.js → observability-page-C2sNV7Qu.js} +1 -1
- package/src/console/ui-next/dist/assets/{replica-lag-CpkPfITG.js → replica-lag-DJQeKIw-.js} +1 -1
- package/src/console/ui-next/dist/assets/{request-meta-C4ZVNFVt.js → request-meta-DQ6HY-a4.js} +1 -1
- package/src/console/ui-next/dist/assets/{store-page-DAHtnesC.js → store-page-kB4rot2u.js} +1 -1
- package/src/console/ui-next/dist/assets/{trace-detail-sheet-B2c9QRBw.js → trace-detail-sheet-B2VrPfhu.js} +1 -1
- package/src/console/ui-next/dist/assets/{tree-expand-toggle-BP4tRC98.js → tree-expand-toggle-CdecFS0p.js} +1 -1
- package/src/console/ui-next/dist/assets/{units-page-Oi6--n09.js → units-page-B-Y68cys.js} +1 -1
- package/src/console/ui-next/dist/assets/{vault-page-Dt-cPkiU.js → vault-page-BcDSaubT.js} +1 -1
- package/src/console/ui-next/dist/index.html +2 -2
- package/src/kernel/app.ts +23 -1
- package/src/kernel/boot.ts +9 -5
- package/src/kernel/effects-stamping.test.ts +44 -0
- package/src/kernel/errors-flow-name.ts +20 -4
- package/src/kernel/errors.registry.test.ts +4 -2
- package/src/kernel/errors.ts +1 -1
- package/src/kernel/flow-name.test.ts +105 -20
- package/src/kernel/flow.ts +3 -3
- package/src/kernel/on.ts +0 -5
- package/src/kernel/stamp-http.test.ts +2 -1
- package/src/kernel/stamp-http.ts +5 -7
- package/src/kernel/unit.ts +1 -2
- 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 +
|
|
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?.["
|
|
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("
|
|
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?.["
|
|
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
|
|
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
|
|
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
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
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({ "
|
|
2143
|
-
|
|
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
|
});
|
package/src/compiler/extract.ts
CHANGED
|
@@ -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 {
|
|
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 (
|
|
299
|
-
const abs =
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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};
|