station-kit 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/packages/station-kit/.next/BUILD_ID +1 -1
- package/.next/standalone/packages/station-kit/.next/app-build-manifest.json +55 -34
- package/.next/standalone/packages/station-kit/.next/app-path-routes-manifest.json +11 -8
- package/.next/standalone/packages/station-kit/.next/build-manifest.json +2 -2
- package/.next/standalone/packages/station-kit/.next/prerender-manifest.json +73 -25
- package/.next/standalone/packages/station-kit/.next/routes-manifest.json +20 -0
- package/.next/standalone/packages/station-kit/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/_not-found.rsc +8 -8
- package/.next/standalone/packages/station-kit/.next/server/app/beacons/[name]/page.js +2 -0
- package/.next/standalone/packages/station-kit/.next/server/app/beacons/[name]/page.js.nft.json +1 -0
- package/.next/standalone/packages/station-kit/.next/server/app/beacons/[name]/page_client-reference-manifest.js +1 -0
- package/.next/standalone/packages/station-kit/.next/server/app/beacons/page.js +2 -0
- package/.next/standalone/packages/station-kit/.next/server/app/beacons/page.js.nft.json +1 -0
- package/.next/standalone/packages/station-kit/.next/server/app/beacons/page_client-reference-manifest.js +1 -0
- package/.next/standalone/packages/station-kit/.next/server/app/beacons.html +1 -0
- package/.next/standalone/packages/station-kit/.next/server/app/beacons.meta +7 -0
- package/.next/standalone/packages/station-kit/.next/server/app/beacons.rsc +25 -0
- package/.next/standalone/packages/station-kit/.next/server/app/broadcasts/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/broadcasts/dyn/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/broadcasts/dyn/[name]/v/[n]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/broadcasts/new/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/broadcasts/new.html +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/broadcasts/new.rsc +9 -9
- package/.next/standalone/packages/station-kit/.next/server/app/broadcasts/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/broadcasts.html +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/broadcasts.rsc +9 -9
- package/.next/standalone/packages/station-kit/.next/server/app/environment/page.js +2 -0
- package/.next/standalone/packages/station-kit/.next/server/app/environment/page.js.nft.json +1 -0
- package/.next/standalone/packages/station-kit/.next/server/app/environment/page_client-reference-manifest.js +1 -0
- package/.next/standalone/packages/station-kit/.next/server/app/environment.html +1 -0
- package/.next/standalone/packages/station-kit/.next/server/app/environment.meta +7 -0
- package/.next/standalone/packages/station-kit/.next/server/app/environment.rsc +25 -0
- package/.next/standalone/packages/station-kit/.next/server/app/index.html +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/index.rsc +9 -9
- package/.next/standalone/packages/station-kit/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/playground/expression/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/playground/expression.html +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/playground/expression.rsc +9 -9
- package/.next/standalone/packages/station-kit/.next/server/app/runs/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/schedules/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/schedules/new/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/schedules/new.html +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/schedules/new.rsc +9 -9
- package/.next/standalone/packages/station-kit/.next/server/app/schedules/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/schedules.html +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/schedules.rsc +9 -9
- package/.next/standalone/packages/station-kit/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/settings.html +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/settings.rsc +9 -9
- package/.next/standalone/packages/station-kit/.next/server/app/signals/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/signals/page_client-reference-manifest.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/signals.html +1 -1
- package/.next/standalone/packages/station-kit/.next/server/app/signals.rsc +9 -9
- package/.next/standalone/packages/station-kit/.next/server/app-paths-manifest.json +11 -8
- package/.next/standalone/packages/station-kit/.next/server/chunks/102.js +1 -1
- package/.next/standalone/packages/station-kit/.next/server/pages/404.html +1 -1
- package/.next/standalone/packages/station-kit/.next/server/pages/500.html +1 -1
- package/.next/standalone/packages/station-kit/.next/server/pages-manifest.json +1 -1
- package/.next/standalone/packages/station-kit/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/285-583f23ee7827983f.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/561-05a7ef9669e3921a.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/beacons/[name]/page-eb1f82847734e145.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/beacons/page-64e296346197e44b.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/broadcasts/dyn/[name]/v/[n]/page-15edf07ab26241c9.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/broadcasts/page-b23a03097c8f75c4.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/environment/page-111242bec067fdee.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/layout-e9ac56fcaf7a5ea7.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/page-ef78692958c2fc01.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/playground/expression/page-29294a705dd8f471.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/runs/[id]/page-287bbb8f6dec2e23.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/schedules/page-c869218da203e3b4.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/settings/page-05cf43b6ae6b3187.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/signals/[name]/page-4027803be00c695a.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/signals/page-8e076fc5d0188d72.js +1 -0
- package/.next/standalone/packages/station-kit/.next/static/css/ddb1646dc25ed100.css +1 -0
- package/.next/standalone/packages/station-kit/.next/static/vTGEzSqxhR_E57YAFn9DC/_buildManifest.js +1 -0
- package/.next/standalone/packages/station-kit/package.json +4 -1
- package/dist/config/schema.d.ts +18 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +3 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/server/auth/keys.d.ts +18 -1
- package/dist/server/auth/keys.d.ts.map +1 -1
- package/dist/server/auth/keys.js +38 -6
- package/dist/server/auth/keys.js.map +1 -1
- package/dist/server/auth/session.d.ts.map +1 -1
- package/dist/server/auth/session.js +34 -11
- package/dist/server/auth/session.js.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +135 -18
- package/dist/server/index.js.map +1 -1
- package/dist/server/metadata.d.ts +2 -0
- package/dist/server/metadata.d.ts.map +1 -1
- package/dist/server/metadata.js.map +1 -1
- package/dist/server/middleware/rate-limit.d.ts.map +1 -1
- package/dist/server/middleware/rate-limit.js +22 -1
- package/dist/server/middleware/rate-limit.js.map +1 -1
- package/dist/server/routes/beacons.d.ts +10 -0
- package/dist/server/routes/beacons.d.ts.map +1 -0
- package/dist/server/routes/beacons.js +98 -0
- package/dist/server/routes/beacons.js.map +1 -0
- package/dist/server/routes/broadcasts.d.ts.map +1 -1
- package/dist/server/routes/broadcasts.js +6 -2
- package/dist/server/routes/broadcasts.js.map +1 -1
- package/dist/server/routes/runs.d.ts.map +1 -1
- package/dist/server/routes/runs.js +19 -59
- package/dist/server/routes/runs.js.map +1 -1
- package/dist/server/routes/signals.d.ts.map +1 -1
- package/dist/server/routes/signals.js +17 -13
- package/dist/server/routes/signals.js.map +1 -1
- package/dist/server/routes/v1/env.d.ts +10 -0
- package/dist/server/routes/v1/env.d.ts.map +1 -0
- package/dist/server/routes/v1/env.js +132 -0
- package/dist/server/routes/v1/env.js.map +1 -0
- package/dist/server/routes/v1/events.js +2 -2
- package/dist/server/routes/v1/events.js.map +1 -1
- package/dist/server/routes/v1/runs.d.ts.map +1 -1
- package/dist/server/routes/v1/runs.js +10 -31
- package/dist/server/routes/v1/runs.js.map +1 -1
- package/dist/server/sse.d.ts +2 -1
- package/dist/server/sse.d.ts.map +1 -1
- package/dist/server/sse.js +5 -1
- package/dist/server/sse.js.map +1 -1
- package/dist/server/subscriber.d.ts +56 -0
- package/dist/server/subscriber.d.ts.map +1 -1
- package/dist/server/subscriber.js +94 -0
- package/dist/server/subscriber.js.map +1 -1
- package/dist/server/ws.d.ts +8 -2
- package/dist/server/ws.d.ts.map +1 -1
- package/dist/server/ws.js +28 -3
- package/dist/server/ws.js.map +1 -1
- package/package.json +11 -8
- package/src/app/beacons/[name]/beacon-detail.tsx +253 -0
- package/src/app/beacons/[name]/page.tsx +6 -0
- package/src/app/beacons/page.tsx +98 -0
- package/src/app/components/shell.tsx +24 -0
- package/src/app/components/status-badge.tsx +13 -1
- package/src/app/environment/page.tsx +415 -0
- package/src/app/globals.css +48 -0
- package/src/app/hooks/use-api.ts +80 -0
- package/src/config/schema.ts +21 -0
- package/src/index.ts +12 -0
- package/src/server/auth/keys.ts +50 -5
- package/src/server/auth/session.ts +38 -11
- package/src/server/index.ts +144 -18
- package/src/server/metadata.ts +2 -0
- package/src/server/middleware/rate-limit.ts +20 -1
- package/src/server/routes/beacons.ts +112 -0
- package/src/server/routes/broadcasts.ts +6 -2
- package/src/server/routes/runs.ts +20 -67
- package/src/server/routes/signals.ts +17 -13
- package/src/server/routes/v1/env.ts +144 -0
- package/src/server/routes/v1/events.ts +2 -2
- package/src/server/routes/v1/runs.ts +11 -35
- package/src/server/sse.ts +7 -2
- package/src/server/subscriber.ts +111 -0
- package/src/server/ws.ts +38 -4
- package/.next/standalone/packages/station-kit/.next/static/THKSkCipW_pj0F6DRXYEG/_buildManifest.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/285-ff198f0a909c4fdd.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/561-33d912169940283e.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/broadcasts/dyn/[name]/v/[n]/page-5eac0507f49a00ec.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/broadcasts/page-dee500ccc01f0821.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/layout-e14e14f3e5b0b8a9.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/page-aac41ef7a470daab.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/playground/expression/page-dc9d91f3f50f4716.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/runs/[id]/page-9e4c4f751a4bea72.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/schedules/page-738d98dc0b63166e.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/settings/page-fc5654b31f57ac21.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/signals/[name]/page-4b1c09a539a1ebcd.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/chunks/app/signals/page-d2f2403dfede87cc.js +0 -1
- package/.next/standalone/packages/station-kit/.next/static/css/0be0e65a5f561f37.css +0 -1
- /package/.next/standalone/packages/station-kit/.next/static/{THKSkCipW_pj0F6DRXYEG → vTGEzSqxhR_E57YAFn9DC}/_ssgManifest.js +0 -0
|
@@ -43,17 +43,17 @@ export function signalRoutes(deps: SignalDeps) {
|
|
|
43
43
|
}> = [];
|
|
44
44
|
|
|
45
45
|
for (const sig of recurring) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
.
|
|
50
|
-
.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
// Two bounded queries instead of loading the signal's full history:
|
|
47
|
+
// the current pending run and the most recent non-pending run.
|
|
48
|
+
const [pendingRuns, lastRuns] = await Promise.all([
|
|
49
|
+
deps.signalAdapter.listRuns(sig.name, { limit: 1, statuses: ["pending"] }),
|
|
50
|
+
deps.signalAdapter.listRuns(sig.name, {
|
|
51
|
+
limit: 1,
|
|
52
|
+
statuses: ["running", "completed", "failed", "cancelled"],
|
|
53
|
+
}),
|
|
54
|
+
]);
|
|
55
|
+
const pendingRun = pendingRuns.find((r) => r.kind === "recurring");
|
|
56
|
+
const lastRun = lastRuns[0];
|
|
57
57
|
|
|
58
58
|
result.push({
|
|
59
59
|
name: sig.name,
|
|
@@ -131,10 +131,14 @@ export function signalRoutes(deps: SignalDeps) {
|
|
|
131
131
|
if (!deps.signalRunner) {
|
|
132
132
|
return c.json({ data: [], meta: { total: 0 } });
|
|
133
133
|
}
|
|
134
|
-
const
|
|
134
|
+
const limitRaw = parseInt(c.req.query("limit") ?? "100", 10);
|
|
135
|
+
const limit = Math.min(Number.isNaN(limitRaw) ? 100 : Math.max(limitRaw, 1), 500);
|
|
136
|
+
const offsetRaw = parseInt(c.req.query("offset") ?? "0", 10);
|
|
137
|
+
const offset = Number.isNaN(offsetRaw) ? 0 : Math.max(offsetRaw, 0);
|
|
138
|
+
const runs = await deps.signalRunner.listRuns(name, { limit, offset });
|
|
135
139
|
return c.json({
|
|
136
140
|
data: runs.map(serializeRun),
|
|
137
|
-
meta: {
|
|
141
|
+
meta: { count: runs.length, limit, offset },
|
|
138
142
|
});
|
|
139
143
|
});
|
|
140
144
|
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import type { Context } from "hono";
|
|
3
|
+
import {
|
|
4
|
+
EnvStore,
|
|
5
|
+
EnvValidationError,
|
|
6
|
+
toPublic,
|
|
7
|
+
type EnvTarget,
|
|
8
|
+
type EnvVarPublic,
|
|
9
|
+
} from "station-env";
|
|
10
|
+
|
|
11
|
+
export interface V1EnvDeps {
|
|
12
|
+
envStore?: EnvStore;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parse the request body and return it only if it's a JSON object. Returns
|
|
17
|
+
* null for a parse error or a non-object body (e.g. `null`, a string, a
|
|
18
|
+
* number) so callers can respond 400 instead of throwing a 500 on
|
|
19
|
+
* `"key" in body`.
|
|
20
|
+
*/
|
|
21
|
+
async function readJsonObject(c: Context): Promise<Record<string, unknown> | null> {
|
|
22
|
+
const raw = await c.req.json().catch(() => undefined);
|
|
23
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
24
|
+
return raw as Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Read-scope routes: list / get. Secret values are redacted. */
|
|
28
|
+
export function v1EnvReadRoutes(deps: V1EnvDeps) {
|
|
29
|
+
const app = new Hono();
|
|
30
|
+
|
|
31
|
+
app.get("/env", async (c) => {
|
|
32
|
+
if (!deps.envStore) return c.json({ data: [] });
|
|
33
|
+
const list = await deps.envStore.listPublic();
|
|
34
|
+
return c.json({ data: list.map(serialize) });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
app.get("/env/:id", async (c) => {
|
|
38
|
+
if (!deps.envStore) return c.json({ error: "unavailable" }, 503);
|
|
39
|
+
const v = await deps.envStore.getPublic(c.req.param("id"));
|
|
40
|
+
if (!v) return c.json({ error: "not_found" }, 404);
|
|
41
|
+
return c.json({ data: serialize(v) });
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return app;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Admin-scope routes: create / update / delete. */
|
|
48
|
+
export function v1EnvRoutes(deps: V1EnvDeps) {
|
|
49
|
+
const app = new Hono();
|
|
50
|
+
|
|
51
|
+
app.post("/env", async (c) => {
|
|
52
|
+
if (!deps.envStore) return c.json({ error: "unavailable" }, 503);
|
|
53
|
+
const body = await readJsonObject(c);
|
|
54
|
+
if (!body) return c.json({ error: "bad_request", message: "body must be a JSON object" }, 400);
|
|
55
|
+
const { key, value, secret, targets } = body as {
|
|
56
|
+
key?: unknown;
|
|
57
|
+
value?: unknown;
|
|
58
|
+
secret?: unknown;
|
|
59
|
+
targets?: unknown;
|
|
60
|
+
};
|
|
61
|
+
if (typeof key !== "string") {
|
|
62
|
+
return c.json({ error: "bad_request", message: "key is required" }, 400);
|
|
63
|
+
}
|
|
64
|
+
if (typeof value !== "string") {
|
|
65
|
+
return c.json({ error: "bad_request", message: "value is required" }, 400);
|
|
66
|
+
}
|
|
67
|
+
const apiKeyId = c.get("apiKeyId" as never) as string | undefined;
|
|
68
|
+
try {
|
|
69
|
+
const created = await deps.envStore.create({
|
|
70
|
+
key,
|
|
71
|
+
value,
|
|
72
|
+
secret: secret === true,
|
|
73
|
+
targets: normalizeTargets(targets),
|
|
74
|
+
createdBy: apiKeyId,
|
|
75
|
+
});
|
|
76
|
+
// Echo back the redacted view — a secret value is never returned, even
|
|
77
|
+
// to its creator, to keep the "write-only" contract uniform.
|
|
78
|
+
return c.json({ data: serialize(toPublic(created)) }, 201);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
if (err instanceof EnvValidationError) {
|
|
81
|
+
return c.json({ error: "bad_request", message: err.message }, 400);
|
|
82
|
+
}
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
app.patch("/env/:id", async (c) => {
|
|
88
|
+
if (!deps.envStore) return c.json({ error: "unavailable" }, 503);
|
|
89
|
+
const id = c.req.param("id");
|
|
90
|
+
const existing = await deps.envStore.get(id);
|
|
91
|
+
if (!existing) return c.json({ error: "not_found" }, 404);
|
|
92
|
+
|
|
93
|
+
const body = await readJsonObject(c);
|
|
94
|
+
if (!body) return c.json({ error: "bad_request", message: "body must be a JSON object" }, 400);
|
|
95
|
+
const patch: { value?: string; secret?: boolean; targets?: EnvTarget[] } = {};
|
|
96
|
+
if ("value" in body) {
|
|
97
|
+
if (typeof body.value !== "string") {
|
|
98
|
+
return c.json({ error: "bad_request", message: "value must be a string" }, 400);
|
|
99
|
+
}
|
|
100
|
+
patch.value = body.value;
|
|
101
|
+
}
|
|
102
|
+
if ("secret" in body) patch.secret = body.secret === true;
|
|
103
|
+
if ("targets" in body) patch.targets = normalizeTargets(body.targets);
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const updated = await deps.envStore.update(id, patch);
|
|
107
|
+
if (!updated) return c.json({ error: "not_found" }, 404);
|
|
108
|
+
return c.json({ data: serialize(toPublic(updated)) });
|
|
109
|
+
} catch (err) {
|
|
110
|
+
if (err instanceof EnvValidationError) {
|
|
111
|
+
return c.json({ error: "bad_request", message: err.message }, 400);
|
|
112
|
+
}
|
|
113
|
+
throw err;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
app.delete("/env/:id", async (c) => {
|
|
118
|
+
if (!deps.envStore) return c.json({ error: "unavailable" }, 503);
|
|
119
|
+
const ok = await deps.envStore.delete(c.req.param("id"));
|
|
120
|
+
if (!ok) return c.json({ error: "not_found" }, 404);
|
|
121
|
+
return c.json({ data: { deleted: true } });
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return app;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function normalizeTargets(raw: unknown): EnvTarget[] {
|
|
128
|
+
if (!Array.isArray(raw)) return [];
|
|
129
|
+
const out: EnvTarget[] = [];
|
|
130
|
+
for (const t of raw) {
|
|
131
|
+
if (t && typeof t === "object" && "kind" in t && "name" in t) {
|
|
132
|
+
out.push({ kind: (t as EnvTarget).kind, name: (t as EnvTarget).name });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function serialize(v: EnvVarPublic): Record<string, unknown> {
|
|
139
|
+
return {
|
|
140
|
+
...v,
|
|
141
|
+
createdAt: v.createdAt.toISOString(),
|
|
142
|
+
updatedAt: v.updatedAt.toISOString(),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
@@ -31,11 +31,11 @@ export function v1EventRoutes(deps: V1EventDeps) {
|
|
|
31
31
|
signalFilter,
|
|
32
32
|
broadcastFilter,
|
|
33
33
|
eventFilter,
|
|
34
|
-
send(event: StationEvent) {
|
|
34
|
+
send(event: StationEvent, serializedData: string) {
|
|
35
35
|
eventCounter++;
|
|
36
36
|
stream.writeSSE({
|
|
37
37
|
event: event.type,
|
|
38
|
-
data:
|
|
38
|
+
data: serializedData,
|
|
39
39
|
id: `evt_${eventCounter}`,
|
|
40
40
|
});
|
|
41
41
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import type { SignalRunner, SignalQueueAdapter, Run } from "station-signal";
|
|
2
|
+
import type { SignalRunner, SignalQueueAdapter, Run, RunStatus } from "station-signal";
|
|
3
3
|
import type { LogBuffer } from "../../log-buffer.js";
|
|
4
4
|
import type { LogStore } from "../../log-store.js";
|
|
5
5
|
|
|
@@ -19,42 +19,18 @@ export function v1RunRoutes(deps: V1RunDeps) {
|
|
|
19
19
|
app.get("/runs", async (c) => {
|
|
20
20
|
const status = c.req.query("status");
|
|
21
21
|
const signalName = c.req.query("signalName");
|
|
22
|
-
const
|
|
22
|
+
const limitRaw = parseInt(c.req.query("limit") ?? "50", 10);
|
|
23
|
+
const limit = Math.min(Number.isNaN(limitRaw) ? 50 : Math.max(limitRaw, 1), 200);
|
|
24
|
+
const offsetRaw = parseInt(c.req.query("offset") ?? "0", 10);
|
|
25
|
+
const offset = Number.isNaN(offsetRaw) ? 0 : Math.max(offsetRaw, 0);
|
|
26
|
+
const statuses = status ? ([status] as RunStatus[]) : undefined;
|
|
23
27
|
|
|
24
|
-
|
|
28
|
+
// Filtering/ordering/limiting happen in the adapter, not in memory.
|
|
29
|
+
const runs: Run[] = signalName
|
|
30
|
+
? await deps.signalAdapter.listRuns(signalName, { limit, offset, statuses })
|
|
31
|
+
: await deps.signalAdapter.listAllRuns({ limit, offset, statuses });
|
|
25
32
|
|
|
26
|
-
|
|
27
|
-
runs = await deps.signalAdapter.listRuns(signalName);
|
|
28
|
-
} else if (deps.signalRunner) {
|
|
29
|
-
const seen = new Set<string>();
|
|
30
|
-
for (const { name } of deps.signalRunner.listRegistered()) {
|
|
31
|
-
const signalRuns = await deps.signalAdapter.listRuns(name);
|
|
32
|
-
for (const r of signalRuns) {
|
|
33
|
-
if (!seen.has(r.id)) {
|
|
34
|
-
seen.add(r.id);
|
|
35
|
-
runs.push(r);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (status) {
|
|
42
|
-
runs = runs.filter((r) => r.status === status);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
runs.sort((a, b) => {
|
|
46
|
-
const aTime = a.createdAt instanceof Date
|
|
47
|
-
? a.createdAt.getTime()
|
|
48
|
-
: new Date(a.createdAt as unknown as string).getTime();
|
|
49
|
-
const bTime = b.createdAt instanceof Date
|
|
50
|
-
? b.createdAt.getTime()
|
|
51
|
-
: new Date(b.createdAt as unknown as string).getTime();
|
|
52
|
-
return bTime - aTime;
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
runs = runs.slice(0, limit);
|
|
56
|
-
|
|
57
|
-
return c.json({ data: runs.map(serializeRun), meta: { total: runs.length } });
|
|
33
|
+
return c.json({ data: runs.map(serializeRun), meta: { count: runs.length, limit, offset } });
|
|
58
34
|
});
|
|
59
35
|
|
|
60
36
|
app.get("/runs/:id", async (c) => {
|
package/src/server/sse.ts
CHANGED
|
@@ -2,7 +2,8 @@ import type { StationEvent } from "./ws.js";
|
|
|
2
2
|
|
|
3
3
|
export interface SSEClient {
|
|
4
4
|
id: string;
|
|
5
|
-
|
|
5
|
+
/** `serializedData` is `JSON.stringify(event.data)`, computed once per broadcast. */
|
|
6
|
+
send(event: StationEvent, serializedData: string): void;
|
|
6
7
|
close(): void;
|
|
7
8
|
readonly signalFilter: Set<string> | null;
|
|
8
9
|
readonly broadcastFilter: Set<string> | null;
|
|
@@ -25,9 +26,13 @@ export class SSEHub {
|
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
broadcast(event: StationEvent): void {
|
|
29
|
+
// Serialize once per event, not once per client — log-chunk events fan
|
|
30
|
+
// out to every connected dashboard.
|
|
31
|
+
let serialized: string | null = null;
|
|
28
32
|
for (const client of this.clients.values()) {
|
|
29
33
|
if (this.matchesFilter(client, event)) {
|
|
30
|
-
|
|
34
|
+
serialized ??= JSON.stringify(event.data);
|
|
35
|
+
client.send(event, serialized);
|
|
31
36
|
}
|
|
32
37
|
}
|
|
33
38
|
}
|
package/src/server/subscriber.ts
CHANGED
|
@@ -2,12 +2,31 @@ import { isSignal } from "station-signal";
|
|
|
2
2
|
import { isBroadcast } from "station-broadcast";
|
|
3
3
|
import type { SignalSubscriber, Run, Step } from "station-signal";
|
|
4
4
|
import type { BroadcastSubscriber, BroadcastRun, BroadcastNodeRun } from "station-broadcast";
|
|
5
|
+
import type { BeaconSubscriber, BeaconInstance, ExitReason } from "station-beacon";
|
|
5
6
|
import type { WebSocketHub } from "./ws.js";
|
|
6
7
|
import type { SSEHub } from "./sse.js";
|
|
7
8
|
import type { LogBuffer } from "./log-buffer.js";
|
|
8
9
|
import type { LogStore } from "./log-store.js";
|
|
9
10
|
import { serializeZodSchema, type SignalMeta, type BroadcastMeta } from "./metadata.js";
|
|
10
11
|
|
|
12
|
+
/** LogStore/LogBuffer key under which a beacon's log lines are stored. */
|
|
13
|
+
export function beaconLogKey(beaconName: string): string {
|
|
14
|
+
return `beacon:${beaconName}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function serializeInstance(inst: BeaconInstance): Record<string, unknown> {
|
|
18
|
+
return {
|
|
19
|
+
...inst,
|
|
20
|
+
startedAt: inst.startedAt?.toISOString(),
|
|
21
|
+
readyAt: inst.readyAt?.toISOString(),
|
|
22
|
+
lastHeartbeatAt: inst.lastHeartbeatAt?.toISOString(),
|
|
23
|
+
lastExitAt: inst.lastExitAt?.toISOString(),
|
|
24
|
+
nextRestartAt: inst.nextRestartAt?.toISOString(),
|
|
25
|
+
createdAt: inst.createdAt?.toISOString(),
|
|
26
|
+
updatedAt: inst.updatedAt?.toISOString(),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
function serializeRun(run: Run): Record<string, unknown> {
|
|
12
31
|
return {
|
|
13
32
|
...run,
|
|
@@ -87,6 +106,7 @@ export class StationSignalSubscriber implements SignalSubscriber {
|
|
|
87
106
|
maxConcurrency: sig.maxConcurrency ?? null,
|
|
88
107
|
hasSteps: Array.isArray(sig.steps) && sig.steps.length > 0,
|
|
89
108
|
stepNames: sig.steps?.map((s: { name: string }) => s.name) ?? [],
|
|
109
|
+
requiredEnv: Array.isArray(sig.requiredEnv) ? sig.requiredEnv : [],
|
|
90
110
|
});
|
|
91
111
|
break;
|
|
92
112
|
}
|
|
@@ -286,3 +306,94 @@ export class StationBroadcastSubscriber implements BroadcastSubscriber {
|
|
|
286
306
|
});
|
|
287
307
|
}
|
|
288
308
|
}
|
|
309
|
+
|
|
310
|
+
export class StationBeaconSubscriber implements BeaconSubscriber {
|
|
311
|
+
private logBuffer?: LogBuffer;
|
|
312
|
+
private logStore?: LogStore;
|
|
313
|
+
private sseHub?: SSEHub;
|
|
314
|
+
private discovered = new Map<string, { beaconName: string; filePath: string }>();
|
|
315
|
+
|
|
316
|
+
constructor(private hub: WebSocketHub, logBuffer?: LogBuffer, logStore?: LogStore) {
|
|
317
|
+
this.logBuffer = logBuffer;
|
|
318
|
+
this.logStore = logStore;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** Attach an SSE hub so events are also pushed to SSE clients. */
|
|
322
|
+
setSSEHub(sseHub: SSEHub): void {
|
|
323
|
+
this.sseHub = sseHub;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
private emit(type: string, data: Record<string, unknown>): void {
|
|
327
|
+
const event = { type, timestamp: new Date().toISOString(), data };
|
|
328
|
+
this.hub.broadcast(event);
|
|
329
|
+
this.sseHub?.broadcast(event);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
private emitInstance(type: string, inst: BeaconInstance, extra?: Record<string, unknown>): void {
|
|
333
|
+
this.emit(type, { instance: serializeInstance(inst), ...extra });
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
onBeaconDiscovered(event: { beaconName: string; filePath: string }): void {
|
|
337
|
+
this.discovered.set(event.beaconName, event);
|
|
338
|
+
this.emit("beacon:discovered", event);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
onBeaconStarting(event: { instance: BeaconInstance }): void {
|
|
342
|
+
this.emitInstance("beacon:starting", event.instance);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
onBeaconStarted(event: { instance: BeaconInstance }): void {
|
|
346
|
+
this.emitInstance("beacon:started", event.instance);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
onBeaconReady(event: { instance: BeaconInstance }): void {
|
|
350
|
+
this.emitInstance("beacon:ready", event.instance);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
onBeaconHeartbeat(event: { instance: BeaconInstance }): void {
|
|
354
|
+
this.emitInstance("beacon:heartbeat", event.instance);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
onBeaconExited(event: { instance: BeaconInstance; reason: ExitReason; code: number | null }): void {
|
|
358
|
+
this.emitInstance("beacon:exited", event.instance, { reason: event.reason, code: event.code });
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
onBeaconRestartScheduled(event: { instance: BeaconInstance; delayMs: number; nextRestartAt: Date }): void {
|
|
362
|
+
this.emitInstance("beacon:restart-scheduled", event.instance, {
|
|
363
|
+
delayMs: event.delayMs,
|
|
364
|
+
nextRestartAt: event.nextRestartAt.toISOString(),
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
onBeaconStopped(event: { instance: BeaconInstance }): void {
|
|
369
|
+
this.emitInstance("beacon:stopped", event.instance);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
onBeaconErrored(event: { instance: BeaconInstance; error?: string }): void {
|
|
373
|
+
this.emitInstance("beacon:errored", event.instance, { error: event.error ?? "" });
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
onBeaconStalled(event: { instance: BeaconInstance }): void {
|
|
377
|
+
this.emitInstance("beacon:stalled", event.instance);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
onBeaconLog(event: { instance: BeaconInstance; level: "log" | "stdout" | "stderr"; message: string }): void {
|
|
381
|
+
const timestamp = new Date().toISOString();
|
|
382
|
+
const entry = {
|
|
383
|
+
runId: beaconLogKey(event.instance.beaconName),
|
|
384
|
+
signalName: event.instance.beaconName,
|
|
385
|
+
level: event.level === "stderr" ? ("stderr" as const) : ("stdout" as const),
|
|
386
|
+
message: event.message,
|
|
387
|
+
timestamp,
|
|
388
|
+
};
|
|
389
|
+
this.logBuffer?.add(entry);
|
|
390
|
+
this.logStore?.add(entry);
|
|
391
|
+
this.emit("beacon:log", {
|
|
392
|
+
beaconName: event.instance.beaconName,
|
|
393
|
+
incarnation: event.instance.incarnation,
|
|
394
|
+
level: event.level,
|
|
395
|
+
message: event.message,
|
|
396
|
+
timestamp,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
}
|
package/src/server/ws.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WebSocketServer, WebSocket } from "ws";
|
|
2
|
-
import type { Server } from "node:http";
|
|
2
|
+
import type { IncomingMessage, Server } from "node:http";
|
|
3
3
|
|
|
4
4
|
export interface StationEvent {
|
|
5
5
|
type: string;
|
|
@@ -7,14 +7,25 @@ export interface StationEvent {
|
|
|
7
7
|
data: Record<string, unknown>;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Async guard run before completing a WebSocket upgrade. Return false to
|
|
12
|
+
* reject with 401. Event payloads include run inputs/outputs and full job
|
|
13
|
+
* logs, so the stream must enforce the same auth as the HTTP API.
|
|
14
|
+
*/
|
|
15
|
+
export type WsVerifyFn = (req: IncomingMessage) => Promise<boolean> | boolean;
|
|
16
|
+
|
|
10
17
|
export class WebSocketHub {
|
|
11
18
|
private wss: WebSocketServer | null = null;
|
|
12
19
|
private clients = new Set<WebSocket>();
|
|
13
20
|
|
|
14
|
-
attach(server: Server): void {
|
|
15
|
-
|
|
21
|
+
attach(server: Server, verify?: WsVerifyFn): void {
|
|
22
|
+
// noServer + manual upgrade handling: the `ws` path-matching shortcut
|
|
23
|
+
// would complete the handshake before any auth check could run (Hono
|
|
24
|
+
// middleware never sees upgrade requests).
|
|
25
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
26
|
+
this.wss = wss;
|
|
16
27
|
|
|
17
|
-
|
|
28
|
+
wss.on("connection", (ws: WebSocket) => {
|
|
18
29
|
this.clients.add(ws);
|
|
19
30
|
ws.on("close", () => {
|
|
20
31
|
this.clients.delete(ws);
|
|
@@ -23,6 +34,29 @@ export class WebSocketHub {
|
|
|
23
34
|
this.clients.delete(ws);
|
|
24
35
|
});
|
|
25
36
|
});
|
|
37
|
+
|
|
38
|
+
server.on("upgrade", async (req, socket, head) => {
|
|
39
|
+
const pathname = new URL(req.url ?? "", "http://localhost").pathname;
|
|
40
|
+
if (pathname !== "/api/events") {
|
|
41
|
+
socket.destroy();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
if (verify && !(await verify(req))) {
|
|
47
|
+
socket.write("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\n\r\n");
|
|
48
|
+
socket.destroy();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
socket.destroy();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
57
|
+
wss.emit("connection", ws, req);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
26
60
|
}
|
|
27
61
|
|
|
28
62
|
get clientCount(): number {
|
package/.next/standalone/packages/station-kit/.next/static/THKSkCipW_pj0F6DRXYEG/_buildManifest.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
self.__BUILD_MANIFEST=function(e,r,t,_){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},__routerFilterStatic:{numItems:9,errorRate:1e-4,numBits:173,numHashes:14,bitArray:[0,0,r,1,1,e,r,e,r,e,e,r,e,e,e,e,e,e,e,e,e,e,e,e,e,r,r,e,e,e,r,e,e,r,r,r,e,e,r,e,e,e,e,r,e,e,r,e,e,r,r,e,r,r,e,r,e,r,r,r,r,e,e,e,r,r,r,e,r,e,e,e,e,e,e,r,r,e,e,r,e,r,r,e,r,r,e,r,r,e,e,r,r,r,r,r,e,e,e,e,r,r,r,r,e,e,r,e,e,e,e,r,e,r,e,e,e,r,e,r,r,e,e,e,e,e,r,e,r,r,r,e,e,r,r,r,r,r,e,r,r,e,e,e,r,r,r,e,r,r,e,r,r,e,r,e,e,e,r,e,e,r,r,r,e,e,e,e,e,r,r,r,e]},__routerFilterDynamic:{numItems:5,errorRate:1e-4,numBits:96,numHashes:14,bitArray:[e,e,e,r,e,r,e,e,r,r,e,r,r,e,r,r,r,e,e,e,e,r,r,e,e,r,e,e,e,r,r,r,e,r,r,e,r,e,r,r,r,r,e,e,r,r,e,e,r,e,e,e,e,r,r,e,r,e,e,e,e,e,e,e,e,e,e,e,r,e,e,r,e,e,r,e,r,e,e,r,r,r,r,e,r,r,r,r,e,r,r,e,e,r,e,r]},"/_error":["static/chunks/pages/_error-273a093c18b5ed0f.js"],sortedPages:["/_app","/_error"]}}(1,0,1e-4,14),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[285],{593:(e,t,n)=>{async function a(e,t){let n=await fetch("".concat("","/api").concat(e),{...t,credentials:"include",headers:{"Content-Type":"application/json",...null==t?void 0:t.headers}});if(!n.ok)throw Error((await n.json().catch(()=>({error:"unknown",message:"Request failed."}))).message);return n.json()}async function o(){let e=await fetch("".concat("","/api/auth/check"),{credentials:"include"});return(await e.json()).data}async function r(e,t){return(await fetch("".concat("","/api/auth/login"),{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:e,password:t})})).ok}async function s(){await fetch("".concat("","/api/auth/logout"),{method:"POST",credentials:"include"})}function i(){return{getHealth:()=>a("/health"),getSignals:()=>a("/signals"),getScheduledSignals:()=>a("/signals/scheduled"),getSignal:e=>a("/signals/".concat(encodeURIComponent(e))),getSignalRuns:e=>a("/signals/".concat(encodeURIComponent(e),"/runs")),triggerSignal:(e,t)=>a("/signals/".concat(encodeURIComponent(e),"/trigger"),{method:"POST",body:JSON.stringify({input:null!=t?t:{}})}),getRuns:e=>{let t=new URLSearchParams;(null==e?void 0:e.status)&&t.set("status",e.status),(null==e?void 0:e.signalName)&&t.set("signalName",e.signalName);let n=t.toString();return a("/runs".concat(n?"?".concat(n):""))},getRunStats:()=>a("/runs/stats"),getRun:e=>a("/runs/".concat(e)),getRunSteps:e=>a("/runs/".concat(e,"/steps")),getRunLogs:e=>a("/runs/".concat(e,"/logs")),cancelRun:e=>a("/runs/".concat(e,"/cancel"),{method:"POST"}),rerunRun:e=>a("/runs/".concat(e,"/rerun"),{method:"POST"}),retryRun:e=>a("/runs/".concat(e,"/retry"),{method:"POST"}),getBroadcasts:()=>a("/broadcasts"),getBroadcast:e=>a("/broadcasts/".concat(encodeURIComponent(e))),triggerBroadcast:(e,t)=>a("/broadcasts/".concat(encodeURIComponent(e),"/trigger"),{method:"POST",body:JSON.stringify({input:null!=t?t:{}})}),getBroadcastRuns:e=>a("/broadcasts/".concat(encodeURIComponent(e),"/runs")),getBroadcastRun:e=>a("/broadcast-runs/".concat(e)),getBroadcastRunNodes:e=>a("/broadcast-runs/".concat(e,"/nodes")),getBroadcastRunLogs:e=>a("/broadcast-runs/".concat(e,"/logs")),cancelBroadcastRun:e=>a("/broadcast-runs/".concat(e,"/cancel"),{method:"POST"}),rerunBroadcastRun:e=>a("/broadcast-runs/".concat(e,"/rerun"),{method:"POST"}),getBroadcastDefinitions:()=>a("/v1/broadcast-definitions"),getBroadcastDefinition:e=>a("/v1/broadcast-definitions/".concat(encodeURIComponent(e))),getBroadcastDefinitionVersions:e=>a("/v1/broadcast-definitions/".concat(encodeURIComponent(e),"/versions")),saveBroadcastDefinition:e=>a("/v1/broadcast-definitions",{method:"POST",body:JSON.stringify(e)}),validateBroadcastDefinition:e=>a("/v1/broadcast-definitions/validate",{method:"POST",body:JSON.stringify(e)}),deleteBroadcastDefinition:e=>a("/v1/broadcast-definitions/".concat(encodeURIComponent(e)),{method:"DELETE"}),triggerDynamicBroadcast:(e,t)=>a("/v1/trigger-dynamic-broadcast",{method:"POST",body:JSON.stringify({broadcastName:e,input:null!=t?t:{}})}),getSchedules:e=>{let t=new URLSearchParams;(null==e?void 0:e.kind)&&t.set("kind",e.kind),(null==e?void 0:e.enabled)!==void 0&&t.set("enabled",String(e.enabled));let n=t.toString();return a("/v1/schedules".concat(n?"?".concat(n):""))},getSchedule:e=>a("/v1/schedules/".concat(e)),createSchedule:e=>a("/v1/schedules",{method:"POST",body:JSON.stringify(e)}),updateSchedule:(e,t)=>a("/v1/schedules/".concat(e),{method:"PATCH",body:JSON.stringify(t)}),deleteSchedule:e=>a("/v1/schedules/".concat(e),{method:"DELETE"}),previewSchedule:function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:5;return a("/v1/schedules/".concat(e,"/preview"),{method:"POST",body:JSON.stringify({count:t})})},evaluateExpression:(e,t)=>a("/v1/expressions/evaluate",{method:"POST",body:JSON.stringify({node:e,context:t})}),validateExpression:(e,t)=>a("/v1/expressions/validate",{method:"POST",body:JSON.stringify({node:e,schemaContext:t})}),parseExpression:e=>a("/v1/expressions/parse",{method:"POST",body:JSON.stringify({source:e})}),getApiKeys:()=>a("/v1/keys"),createApiKey:(e,t)=>a("/v1/keys",{method:"POST",body:JSON.stringify({name:e,scopes:t})}),revokeApiKey:e=>a("/v1/keys/".concat(e),{method:"DELETE"})}}n.d(t,{T5:()=>o,gf:()=>i,iD:()=>r,ri:()=>s})},4736:(e,t,n)=>{var a=n(1504);n.o(a,"useParams")&&n.d(t,{useParams:function(){return a.useParams}}),n.o(a,"usePathname")&&n.d(t,{usePathname:function(){return a.usePathname}}),n.o(a,"useRouter")&&n.d(t,{useRouter:function(){return a.useRouter}})},7646:(e,t,n)=>{n.d(t,{Hc:()=>o,iQ:()=>s,rT:()=>r});var a=n(5271);let o=(0,a.createContext)({segments:[],activeSection:null,setSegments:()=>{},setActiveSection:()=>{}});function r(e,t){let n=(0,a.useContext)(o);(0,a.useEffect)(()=>{n.setSegments(e),n.setActiveSection(t)},[JSON.stringify(e),t])}function s(){return(0,a.useContext)(o)}},9129:(e,t,n)=>{n.d(t,{D:()=>s,ThemeProvider:()=>c});var a=n(8111),o=n(5271);let r=(0,o.createContext)({theme:"light",toggle:()=>{}});function s(){return(0,o.useContext)(r)}function i(){let e=localStorage.getItem("station-theme");return"light"===e||"dark"===e?e:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function c(e){let{children:t}=e,[n,s]=(0,o.useState)(i);(0,o.useEffect)(()=>{document.documentElement.setAttribute("data-theme",n),localStorage.setItem("station-theme",n)},[n]);let c=(0,o.useCallback)(()=>{s(e=>"light"===e?"dark":"light")},[]);return(0,a.jsx)(r.Provider,{value:{theme:n,toggle:c},children:t})}},9711:(e,t,n)=>{n.d(t,{C0:()=>d,QK:()=>u,WZ:()=>l});var a=n(8111),o=n(9129);let r={completed:{bar:"#4A6741",fill:"rgba(74, 103, 65, 0.06)",stroke:"#4A6741",text:"#4A6741"},running:{bar:"#6B9962",fill:"rgba(107, 153, 98, 0.08)",stroke:"#6B9962",text:"#4A6741"},failed:{bar:"#8B5A2B",fill:"rgba(139, 90, 43, 0.06)",stroke:"#8B5A2B",text:"#8B5A2B"},pending:{bar:"#D4CEBF",fill:"#F9F7F3",stroke:"#D4CEBF",text:"#8A8A8E"},cancelled:{bar:"#AEAEB2",fill:"rgba(139, 90, 43, 0.03)",stroke:"#AEAEB2",text:"#8A8A8E"},skipped:{bar:"#AEAEB2",fill:"transparent",stroke:"#AEAEB2",text:"#8A8A8E"}},s={completed:{bar:"#6B9962",fill:"rgba(107, 153, 98, 0.12)",stroke:"#6B9962",text:"#8BB882"},running:{bar:"#8BB882",fill:"rgba(139, 185, 130, 0.1)",stroke:"#8BB882",text:"#8BB882"},failed:{bar:"#C4834A",fill:"rgba(196, 131, 74, 0.1)",stroke:"#C4834A",text:"#D4975C"},pending:{bar:"#4A4A4C",fill:"#252527",stroke:"#4A4A4C",text:"#8A8A8E"},cancelled:{bar:"#6A6A6E",fill:"rgba(60, 60, 62, 0.3)",stroke:"#6A6A6E",text:"#8A8A8E"},skipped:{bar:"#6A6A6E",fill:"transparent",stroke:"#6A6A6E",text:"#8A8A8E"}},i={bar:"#4A6741",fill:"#FFFFFF",stroke:"#D4CEBF",text:"#1C1C1E"},c={bar:"#6B9962",fill:"#222224",stroke:"#4A4A4C",text:"#E8E4DC"};function l(){let{theme:e}=(0,o.D)();return"dark"===e?s:r}function d(e){var t,n;if(0===e.length)return[];let a=new Map;for(let t of e)a.set(t.name,t);let o=new Map;for(let t of e)!function e(t,n){if(o.has(t))return o.get(t);if(n.has(t))return 0;n.add(t);let r=a.get(t);if(!r||0===r.dependsOn.length)return o.set(t,0),0;let s=0;for(let t of r.dependsOn)a.has(t)&&(s=Math.max(s,e(t,n)+1));return o.set(t,s),s}(t.name,new Set);let r=new Map;for(let n of e){let e=null!=(t=o.get(n.name))?t:0;r.has(e)||r.set(e,[]),r.get(e).push(n)}let s=Math.max(...Array.from(r.keys()),0),i=[];for(let e=0;e<=s;e++)i.push(null!=(n=r.get(e))?n:[]);return i.filter(e=>e.length>0)}function u(e){let{nodes:t,onNodeClick:n,selectedNode:l,compact:u}=e,{theme:g}=(0,o.D)(),f="dark"===g,h=f?s:r,m=f?c:i;if(0===t.length)return(0,a.jsx)("div",{className:"empty-state",children:(0,a.jsx)("p",{className:"empty-state-text",children:"No nodes."})});let p=u?140:184,x=u?36:60,{positions:y,svgWidth:v,svgHeight:S}=function(e,t){let n=new Map;if(0===e.length)return{positions:n,svgWidth:0,svgHeight:0};let{nodeWidth:a,nodeHeight:o,gapX:r,gapY:s,paddingX:i,paddingY:c}=t,l=Math.max(1,...e.map(e=>e.length))*(a+r)-r+2*i,d=e.length*(o+s)-s+2*c;for(let t=0;t<e.length;t++){let i=e[t],d=(l-(i.length*(a+r)-r))/2,u=c+t*(o+s);for(let e=0;e<i.length;e++){let t=d+e*(a+r);n.set(i[e].name,{x:t,y:u,node:i[e]})}}return{positions:n,svgWidth:l,svgHeight:d}}(d(t),{nodeWidth:p,nodeHeight:x,gapX:u?32:48,gapY:u?28:40,paddingX:u?20:32,paddingY:u?16:24}),b=t.some(e=>void 0!==e.status),A=new Map;for(let e of t)e.status&&A.set(e.name,e.status);let k=[];for(let e of t)for(let t of e.dependsOn)y.has(t)&&k.push({from:t,to:e.name});return(0,a.jsx)("div",{className:"dag-container",children:(0,a.jsxs)("svg",{width:v,height:S,viewBox:"0 0 ".concat(v," ").concat(S),style:{display:"block",margin:"0 auto"},children:[(0,a.jsxs)("defs",{children:[(0,a.jsx)("marker",{id:"dag-arrow",viewBox:"0 0 6 6",refX:"6",refY:"3",markerWidth:"6",markerHeight:"6",orient:"auto-start-reverse",children:(0,a.jsx)("path",{d:"M 0 0 L 6 3 L 0 6 z",fill:f?"#4A4A4C":"#D4CEBF"})}),(0,a.jsx)("marker",{id:"dag-arrow-active",viewBox:"0 0 6 6",refX:"6",refY:"3",markerWidth:"6",markerHeight:"6",orient:"auto-start-reverse",children:(0,a.jsx)("path",{d:"M 0 0 L 6 3 L 0 6 z",fill:f?"#6B9962":"#4A6741"})})]}),k.map(e=>{let t=y.get(e.from),n=y.get(e.to);if(!t||!n)return null;let o="completed"===A.get(e.from),r="skipped"===A.get(e.to),s=t.x+p/2,i=t.y+x,c=n.x+p/2,l=n.y,d=(i+l)/2,u="M ".concat(s," ").concat(i," C ").concat(s," ").concat(d,", ").concat(c," ").concat(d,", ").concat(c," ").concat(l);return(0,a.jsx)("path",{d:u,className:"dag-edge".concat(o?" dag-edge--active":""),strokeDasharray:r?"4 3":void 0,markerEnd:"url(#".concat(o?"dag-arrow-active":"dag-arrow",")")},"".concat(e.from,"->").concat(e.to))}),Array.from(y.values()).map(e=>{var t;let{x:o,y:r,node:s}=e,i=void 0!==s.status&&null!==s.status,c=i&&null!=(t=h[s.status])?t:m,d="skipped"===s.status,g=l===s.name,y="running"===s.status,v=function(e,t){if(!e)return null;let n=new Date(e).getTime(),a=(t?new Date(t).getTime():Date.now())-n;return a<1e3?"".concat(a,"ms"):a<6e4?"".concat((a/1e3).toFixed(1),"s"):"".concat((a/6e4).toFixed(1),"m")}(s.startedAt,s.completedAt),S=u?14:18,A=s.name.length>S?s.name.slice(0,S-1)+"…":s.name,k=s.signalName.length>22?s.signalName.slice(0,21)+"…":s.signalName;return(0,a.jsxs)("g",{className:"dag-node".concat(g?" dag-node--selected":""),onClick:()=>null==n?void 0:n(s.name),style:{cursor:n?"pointer":"default"},role:n?"button":void 0,tabIndex:n?0:void 0,"aria-label":"".concat(s.name).concat(i?", "+s.status:""),onKeyDown:e=>{n&&("Enter"===e.key||" "===e.key)&&(e.preventDefault(),n(s.name))},children:[y&&(0,a.jsx)("rect",{x:o-3,y:r-3,width:p+6,height:x+6,rx:7,fill:"none",stroke:f?"#8BB882":"#6B9962",strokeWidth:2,children:(0,a.jsx)("animate",{attributeName:"opacity",values:"0;0.5;0",dur:"2.4s",repeatCount:"indefinite"})}),(0,a.jsx)("rect",{x:o,y:r,width:p,height:x,rx:4,fill:c.fill,stroke:c.stroke,strokeWidth:g?2.5:1.5,strokeDasharray:d?"4 3":void 0}),(0,a.jsx)("rect",{x:o,y:r,width:p,height:4,rx:4,fill:c.bar}),(0,a.jsx)("rect",{x:o,y:r+2,width:p,height:2,fill:c.bar}),(0,a.jsx)("text",{x:o+8,y:u?r+x/2+2:r+4+16,fill:c.text,dominantBaseline:"middle",style:{fontSize:u?"10px":"11px",fontFamily:"var(--font-mono)",fontWeight:500},children:A}),u&&b&&i&&(0,a.jsx)("text",{x:o+p-8,y:r+x/2+2,fill:c.text,opacity:.5,dominantBaseline:"middle",textAnchor:"end",style:{fontSize:"8px",fontFamily:"var(--font-mono)",textTransform:"uppercase",letterSpacing:"0.05em"},children:null!=v?v:s.status}),!u&&(0,a.jsxs)(a.Fragment,{children:[b&&v&&(0,a.jsx)("text",{x:o+p-10,y:r+4+16,fill:c.text,opacity:.6,dominantBaseline:"middle",textAnchor:"end",style:{fontSize:"9px",fontFamily:"var(--font-mono)"},children:v}),(0,a.jsx)("text",{x:o+10,y:r+x-10,fill:c.text,opacity:.45,dominantBaseline:"middle",style:{fontSize:"9px",fontFamily:"var(--font-mono)"},children:k}),b&&i&&(0,a.jsx)("text",{x:o+p-10,y:r+x-10,fill:c.text,opacity:.5,dominantBaseline:"middle",textAnchor:"end",style:{fontSize:"8px",fontFamily:"var(--font-mono)",textTransform:"uppercase",letterSpacing:"0.05em"},children:s.status})]})]},s.name)})]})})}}}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[561],{593:(e,t,n)=>{async function a(e,t){let n=await fetch("".concat("","/api").concat(e),{...t,credentials:"include",headers:{"Content-Type":"application/json",...null==t?void 0:t.headers}});if(!n.ok)throw Error((await n.json().catch(()=>({error:"unknown",message:"Request failed."}))).message);return n.json()}async function o(){let e=await fetch("".concat("","/api/auth/check"),{credentials:"include"});return(await e.json()).data}async function s(e,t){return(await fetch("".concat("","/api/auth/login"),{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:e,password:t})})).ok}async function r(){await fetch("".concat("","/api/auth/logout"),{method:"POST",credentials:"include"})}function i(){return{getHealth:()=>a("/health"),getSignals:()=>a("/signals"),getScheduledSignals:()=>a("/signals/scheduled"),getSignal:e=>a("/signals/".concat(encodeURIComponent(e))),getSignalRuns:e=>a("/signals/".concat(encodeURIComponent(e),"/runs")),triggerSignal:(e,t)=>a("/signals/".concat(encodeURIComponent(e),"/trigger"),{method:"POST",body:JSON.stringify({input:null!=t?t:{}})}),getRuns:e=>{let t=new URLSearchParams;(null==e?void 0:e.status)&&t.set("status",e.status),(null==e?void 0:e.signalName)&&t.set("signalName",e.signalName);let n=t.toString();return a("/runs".concat(n?"?".concat(n):""))},getRunStats:()=>a("/runs/stats"),getRun:e=>a("/runs/".concat(e)),getRunSteps:e=>a("/runs/".concat(e,"/steps")),getRunLogs:e=>a("/runs/".concat(e,"/logs")),cancelRun:e=>a("/runs/".concat(e,"/cancel"),{method:"POST"}),rerunRun:e=>a("/runs/".concat(e,"/rerun"),{method:"POST"}),retryRun:e=>a("/runs/".concat(e,"/retry"),{method:"POST"}),getBroadcasts:()=>a("/broadcasts"),getBroadcast:e=>a("/broadcasts/".concat(encodeURIComponent(e))),triggerBroadcast:(e,t)=>a("/broadcasts/".concat(encodeURIComponent(e),"/trigger"),{method:"POST",body:JSON.stringify({input:null!=t?t:{}})}),getBroadcastRuns:e=>a("/broadcasts/".concat(encodeURIComponent(e),"/runs")),getBroadcastRun:e=>a("/broadcast-runs/".concat(e)),getBroadcastRunNodes:e=>a("/broadcast-runs/".concat(e,"/nodes")),getBroadcastRunLogs:e=>a("/broadcast-runs/".concat(e,"/logs")),cancelBroadcastRun:e=>a("/broadcast-runs/".concat(e,"/cancel"),{method:"POST"}),rerunBroadcastRun:e=>a("/broadcast-runs/".concat(e,"/rerun"),{method:"POST"}),getBroadcastDefinitions:()=>a("/v1/broadcast-definitions"),getBroadcastDefinition:e=>a("/v1/broadcast-definitions/".concat(encodeURIComponent(e))),getBroadcastDefinitionVersions:e=>a("/v1/broadcast-definitions/".concat(encodeURIComponent(e),"/versions")),saveBroadcastDefinition:e=>a("/v1/broadcast-definitions",{method:"POST",body:JSON.stringify(e)}),validateBroadcastDefinition:e=>a("/v1/broadcast-definitions/validate",{method:"POST",body:JSON.stringify(e)}),deleteBroadcastDefinition:e=>a("/v1/broadcast-definitions/".concat(encodeURIComponent(e)),{method:"DELETE"}),triggerDynamicBroadcast:(e,t)=>a("/v1/trigger-dynamic-broadcast",{method:"POST",body:JSON.stringify({broadcastName:e,input:null!=t?t:{}})}),getSchedules:e=>{let t=new URLSearchParams;(null==e?void 0:e.kind)&&t.set("kind",e.kind),(null==e?void 0:e.enabled)!==void 0&&t.set("enabled",String(e.enabled));let n=t.toString();return a("/v1/schedules".concat(n?"?".concat(n):""))},getSchedule:e=>a("/v1/schedules/".concat(e)),createSchedule:e=>a("/v1/schedules",{method:"POST",body:JSON.stringify(e)}),updateSchedule:(e,t)=>a("/v1/schedules/".concat(e),{method:"PATCH",body:JSON.stringify(t)}),deleteSchedule:e=>a("/v1/schedules/".concat(e),{method:"DELETE"}),previewSchedule:function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:5;return a("/v1/schedules/".concat(e,"/preview"),{method:"POST",body:JSON.stringify({count:t})})},evaluateExpression:(e,t)=>a("/v1/expressions/evaluate",{method:"POST",body:JSON.stringify({node:e,context:t})}),validateExpression:(e,t)=>a("/v1/expressions/validate",{method:"POST",body:JSON.stringify({node:e,schemaContext:t})}),parseExpression:e=>a("/v1/expressions/parse",{method:"POST",body:JSON.stringify({source:e})}),getApiKeys:()=>a("/v1/keys"),createApiKey:(e,t)=>a("/v1/keys",{method:"POST",body:JSON.stringify({name:e,scopes:t})}),revokeApiKey:e=>a("/v1/keys/".concat(e),{method:"DELETE"})}}n.d(t,{T5:()=>o,gf:()=>i,iD:()=>s,ri:()=>r})},4736:(e,t,n)=>{var a=n(1504);n.o(a,"useParams")&&n.d(t,{useParams:function(){return a.useParams}}),n.o(a,"usePathname")&&n.d(t,{usePathname:function(){return a.usePathname}}),n.o(a,"useRouter")&&n.d(t,{useRouter:function(){return a.useRouter}})},6990:(e,t,n)=>{n.d(t,{F:()=>s});var a=n(8111),o=n(5271);function s(e){let{title:t="API equivalent",snippets:n}=e,[s,r]=(0,o.useState)(!1),[i,c]=(0,o.useState)(null),[l,d]=(0,o.useState)(null);if(0===n.length)return null;async function u(e,t){try{var n;if(null==(n=navigator.clipboard)?void 0:n.writeText){await navigator.clipboard.writeText(e),c(t),setTimeout(()=>c(e=>e===t?null:e),1500);return}throw Error("clipboard API unavailable")}catch(n){try{let n=document.createElement("textarea");n.value=e,n.style.position="fixed",n.style.left="-9999px",document.body.appendChild(n),n.select();let a=document.execCommand("copy");if(document.body.removeChild(n),a)c(t),setTimeout(()=>c(e=>e===t?null:e),1500);else throw Error("execCommand copy returned false")}catch(e){d(t),setTimeout(()=>d(e=>e===t?null:e),2e3)}}}return(0,a.jsxs)("details",{open:s,onToggle:e=>r(e.target.open),style:{marginTop:"1.5rem",border:"1px solid var(--border)",borderRadius:"4px",background:"var(--surface)"},children:[(0,a.jsxs)("summary",{style:{padding:"0.5rem 0.75rem",fontSize:"0.75rem",fontFamily:"var(--mono-font, monospace)",color:"var(--muted)",textTransform:"uppercase",letterSpacing:"0.05em",cursor:"pointer",listStyle:"none"},children:["▸ ",t]}),(0,a.jsx)("div",{style:{padding:"0.5rem 0.75rem 0.75rem"},children:n.map((e,t)=>{let o=function(e){var t;let n=[];if(e.query)for(let[t,a]of Object.entries(e.query))void 0!==a&&n.push("".concat(encodeURIComponent(t),"=").concat(encodeURIComponent(String(a))));let a="".concat(e.path).concat(n.length?"?".concat(n.join("&")):""),o=(null==(t=window.location)?void 0:t.origin)?window.location.origin:"https://your-station.example.com",s=[];if(s.push("curl -X ".concat(e.method," \\")),s.push(" ".concat(o).concat(a," \\")),s.push(" -H 'Authorization: Bearer sk_live_…' \\"),void 0!==e.body){s.push(" -H 'Content-Type: application/json' \\");let t="string"==typeof e.body?e.body:JSON.stringify(e.body,null,2);s.push(" -d ".concat(JSON.stringify(t)))}else s[s.length-1]=s[s.length-1].replace(/ \\$/,"");return s.join("\n")}(e);return(0,a.jsxs)("div",{style:{marginBottom:t===n.length-1?0:"0.75rem"},children:[(0,a.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:"0.25rem"},children:[(0,a.jsx)("div",{className:"mono",style:{fontSize:"0.75rem",color:"var(--muted)"},children:e.label}),(0,a.jsx)("button",{type:"button",className:"btn btn--sm",onClick:()=>u(o,t),title:l===t?"Copy failed — select the text manually":"",children:i===t?"Copied":l===t?"Copy failed":"Copy"})]}),(0,a.jsx)("pre",{className:"mono",style:{margin:0,padding:"0.5rem 0.75rem",background:"var(--bg, #fff)",border:"1px solid var(--border)",borderRadius:"4px",fontSize:"0.75rem",overflowX:"auto",whiteSpace:"pre"},children:o})]},t)})})]})}},7388:(e,t,n)=>{n.d(t,{Q:()=>r});var a=n(8111),o=n(5271),s=n(593);function r(e){let{value:t,onChange:n,locked:r}=e,d=(0,s.gf)(),[u,m]=(0,o.useState)([]),[g,h]=(0,o.useState)([]),[p,y]=(0,o.useState)([]);(0,o.useEffect)(()=>{Promise.all([d.getSignals().catch(()=>({data:[]})),d.getBroadcasts().catch(()=>({data:[]})),d.getBroadcastDefinitions().catch(()=>({data:[]}))]).then(e=>{let[t,n,a]=e;m(t.data.map(e=>e.name)),h(n.data.map(e=>e.name)),y(a.data.map(e=>e.name))})},[]);let f="signal"===t.kind?u:"broadcast-static"===t.kind?g:p;return(0,a.jsxs)("div",{style:{display:"grid",gap:"1rem",maxWidth:"640px"},children:[(0,a.jsx)(i,{label:"Kind",children:(0,a.jsxs)("select",{value:t.kind,disabled:r,onChange:e=>n({...t,kind:e.target.value,target:""}),className:"mono",style:l,children:[(0,a.jsx)("option",{value:"signal",children:"signal"}),(0,a.jsx)("option",{value:"broadcast-static",children:"broadcast-static"}),(0,a.jsx)("option",{value:"broadcast-dynamic",children:"broadcast-dynamic"})]})}),(0,a.jsxs)(i,{label:"Target",hint:"".concat(f.length," available"),children:[r?(0,a.jsx)("input",{className:"mono",value:t.target,readOnly:!0,style:c}):(0,a.jsx)("input",{className:"mono",value:t.target,list:"schedule-targets-".concat(t.kind),onChange:e=>n({...t,target:e.target.value}),placeholder:"signal or broadcast name",style:c}),(0,a.jsx)("datalist",{id:"schedule-targets-".concat(t.kind),children:f.map(e=>(0,a.jsx)("option",{value:e},e))})]}),(0,a.jsx)(i,{label:"Interval",hint:'e.g. "30s", "5m", "1h", "1d"',children:(0,a.jsx)("input",{className:"mono",value:t.interval,onChange:e=>n({...t,interval:e.target.value}),placeholder:"5m",style:c})}),(0,a.jsx)(i,{label:"Input (JSON)",children:(0,a.jsx)("textarea",{className:"mono",value:t.input,onChange:e=>n({...t,input:e.target.value}),rows:6,spellCheck:!1,style:{...c,fontFamily:"var(--mono-font, monospace)",fontSize:"0.8125rem"}})}),(0,a.jsxs)("label",{style:{display:"flex",alignItems:"center",gap:"0.5rem"},children:[(0,a.jsx)("input",{type:"checkbox",checked:t.enabled,onChange:e=>n({...t,enabled:e.target.checked})}),(0,a.jsx)("span",{className:"mono",style:{fontSize:"0.875rem"},children:"Enabled"})]})]})}function i(e){let{label:t,hint:n,children:o}=e;return(0,a.jsxs)("div",{children:[(0,a.jsxs)("div",{style:{display:"flex",alignItems:"baseline",justifyContent:"space-between",marginBottom:"0.25rem"},children:[(0,a.jsx)("label",{className:"mono",style:{fontSize:"0.75rem",color:"var(--muted)"},children:t}),n&&(0,a.jsx)("span",{className:"mono",style:{fontSize:"0.6875rem",color:"var(--muted)"},children:n})]}),o]})}let c={width:"100%",padding:"0.5rem 0.625rem",border:"1px solid var(--border)",borderRadius:"4px",background:"var(--surface)",color:"var(--text)",fontSize:"0.875rem"},l={...c,appearance:"auto"}},7646:(e,t,n)=>{n.d(t,{Hc:()=>o,iQ:()=>r,rT:()=>s});var a=n(5271);let o=(0,a.createContext)({segments:[],activeSection:null,setSegments:()=>{},setActiveSection:()=>{}});function s(e,t){let n=(0,a.useContext)(o);(0,a.useEffect)(()=>{n.setSegments(e),n.setActiveSection(t)},[JSON.stringify(e),t])}function r(){return(0,a.useContext)(o)}}}]);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[719],{593:(e,t,n)=>{"use strict";async function o(e,t){let n=await fetch("".concat("","/api").concat(e),{...t,credentials:"include",headers:{"Content-Type":"application/json",...null==t?void 0:t.headers}});if(!n.ok)throw Error((await n.json().catch(()=>({error:"unknown",message:"Request failed."}))).message);return n.json()}async function a(){let e=await fetch("".concat("","/api/auth/check"),{credentials:"include"});return(await e.json()).data}async function s(e,t){return(await fetch("".concat("","/api/auth/login"),{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:e,password:t})})).ok}async function r(){await fetch("".concat("","/api/auth/logout"),{method:"POST",credentials:"include"})}function i(){return{getHealth:()=>o("/health"),getSignals:()=>o("/signals"),getScheduledSignals:()=>o("/signals/scheduled"),getSignal:e=>o("/signals/".concat(encodeURIComponent(e))),getSignalRuns:e=>o("/signals/".concat(encodeURIComponent(e),"/runs")),triggerSignal:(e,t)=>o("/signals/".concat(encodeURIComponent(e),"/trigger"),{method:"POST",body:JSON.stringify({input:null!=t?t:{}})}),getRuns:e=>{let t=new URLSearchParams;(null==e?void 0:e.status)&&t.set("status",e.status),(null==e?void 0:e.signalName)&&t.set("signalName",e.signalName);let n=t.toString();return o("/runs".concat(n?"?".concat(n):""))},getRunStats:()=>o("/runs/stats"),getRun:e=>o("/runs/".concat(e)),getRunSteps:e=>o("/runs/".concat(e,"/steps")),getRunLogs:e=>o("/runs/".concat(e,"/logs")),cancelRun:e=>o("/runs/".concat(e,"/cancel"),{method:"POST"}),rerunRun:e=>o("/runs/".concat(e,"/rerun"),{method:"POST"}),retryRun:e=>o("/runs/".concat(e,"/retry"),{method:"POST"}),getBroadcasts:()=>o("/broadcasts"),getBroadcast:e=>o("/broadcasts/".concat(encodeURIComponent(e))),triggerBroadcast:(e,t)=>o("/broadcasts/".concat(encodeURIComponent(e),"/trigger"),{method:"POST",body:JSON.stringify({input:null!=t?t:{}})}),getBroadcastRuns:e=>o("/broadcasts/".concat(encodeURIComponent(e),"/runs")),getBroadcastRun:e=>o("/broadcast-runs/".concat(e)),getBroadcastRunNodes:e=>o("/broadcast-runs/".concat(e,"/nodes")),getBroadcastRunLogs:e=>o("/broadcast-runs/".concat(e,"/logs")),cancelBroadcastRun:e=>o("/broadcast-runs/".concat(e,"/cancel"),{method:"POST"}),rerunBroadcastRun:e=>o("/broadcast-runs/".concat(e,"/rerun"),{method:"POST"}),getBroadcastDefinitions:()=>o("/v1/broadcast-definitions"),getBroadcastDefinition:e=>o("/v1/broadcast-definitions/".concat(encodeURIComponent(e))),getBroadcastDefinitionVersions:e=>o("/v1/broadcast-definitions/".concat(encodeURIComponent(e),"/versions")),saveBroadcastDefinition:e=>o("/v1/broadcast-definitions",{method:"POST",body:JSON.stringify(e)}),validateBroadcastDefinition:e=>o("/v1/broadcast-definitions/validate",{method:"POST",body:JSON.stringify(e)}),deleteBroadcastDefinition:e=>o("/v1/broadcast-definitions/".concat(encodeURIComponent(e)),{method:"DELETE"}),triggerDynamicBroadcast:(e,t)=>o("/v1/trigger-dynamic-broadcast",{method:"POST",body:JSON.stringify({broadcastName:e,input:null!=t?t:{}})}),getSchedules:e=>{let t=new URLSearchParams;(null==e?void 0:e.kind)&&t.set("kind",e.kind),(null==e?void 0:e.enabled)!==void 0&&t.set("enabled",String(e.enabled));let n=t.toString();return o("/v1/schedules".concat(n?"?".concat(n):""))},getSchedule:e=>o("/v1/schedules/".concat(e)),createSchedule:e=>o("/v1/schedules",{method:"POST",body:JSON.stringify(e)}),updateSchedule:(e,t)=>o("/v1/schedules/".concat(e),{method:"PATCH",body:JSON.stringify(t)}),deleteSchedule:e=>o("/v1/schedules/".concat(e),{method:"DELETE"}),previewSchedule:function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:5;return o("/v1/schedules/".concat(e,"/preview"),{method:"POST",body:JSON.stringify({count:t})})},evaluateExpression:(e,t)=>o("/v1/expressions/evaluate",{method:"POST",body:JSON.stringify({node:e,context:t})}),validateExpression:(e,t)=>o("/v1/expressions/validate",{method:"POST",body:JSON.stringify({node:e,schemaContext:t})}),parseExpression:e=>o("/v1/expressions/parse",{method:"POST",body:JSON.stringify({source:e})}),getApiKeys:()=>o("/v1/keys"),createApiKey:(e,t)=>o("/v1/keys",{method:"POST",body:JSON.stringify({name:e,scopes:t})}),revokeApiKey:e=>o("/v1/keys/".concat(e),{method:"DELETE"})}}n.d(t,{T5:()=>a,gf:()=>i,iD:()=>s,ri:()=>r})},2311:(e,t,n)=>{Promise.resolve().then(n.bind(n,5617))},5617:(e,t,n)=>{"use strict";n.d(t,{VersionView:()=>d});var o=n(8111),a=n(5271),s=n(5935),r=n.n(s),i=n(593),l=n(7646),c=n(6990);function d(e){var t,n;let{name:s,version:d}=e,p=(0,i.gf)(),[h,f]=(0,a.useState)([]),[v,y]=(0,a.useState)(null),[b,S]=(0,a.useState)(null),[x,j]=(0,a.useState)(!0),[N,O]=(0,a.useState)(null);(0,l.rT)([{label:"Broadcasts",href:"/broadcasts"},{label:s,href:"/broadcasts/dyn/".concat(encodeURIComponent(s))},{label:"v".concat(d)}],"broadcasts"),(0,a.useEffect)(()=>{Promise.all([p.getBroadcastDefinitionVersions(s),p.getBroadcastDefinition(s).then(e=>e.data,()=>null)]).then(e=>{var t;let[n]=e;f(n.data);let o=n.data.find(e=>e.version===d);y(null!=o?o:null);let a=n.data.find(e=>e.version===d-1);S(null!=(t=null==a?void 0:a.version)?t:null)}).catch(e=>O(e instanceof Error?e.message:String(e))).finally(()=>j(!1))},[s,d]);let T=(0,a.useMemo)(()=>{var e;return null!=(e=h.find(e=>e.version===b))?e:null},[h,b]),w=(0,a.useMemo)(()=>v&&T?function(e,t){let n=JSON.stringify(e,null,2).split("\n"),o=JSON.stringify(t,null,2).split("\n"),a=new Map;for(let e=0;e<n.length;e++){let t=a.get(n[e]);t?t.push(e):a.set(n[e],[e])}let s=new Map;for(let e=0;e<o.length;e++){let t=s.get(o[e]);t?t.push(e):s.set(o[e],[e])}let r=new Set,i=new Set;for(let e=0;e<o.length;e++){let t=a.get(o[e]);t&&0!==t.length?t.shift():r.add(e)}for(let e=0;e<n.length;e++){let t=s.get(n[e]);t&&0!==t.length?t.shift():i.add(e)}return{addedLines:r,removedLines:i}}(m(T),m(v)):null,[v,T]);return x?(0,o.jsxs)("div",{children:[(0,o.jsxs)("h1",{className:"page-title",children:[s," v",d]}),(0,o.jsx)("div",{className:"loading-bar",children:(0,o.jsx)("div",{className:"loading-bar-fill"})})]}):v?(0,o.jsxs)("div",{children:[(0,o.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:"1rem"},children:[(0,o.jsxs)("h1",{className:"page-title",style:{margin:0},children:[(0,o.jsx)("span",{className:"mono",children:s}),(0,o.jsxs)("span",{style:{marginLeft:"0.5rem",color:"var(--muted)",fontSize:"0.875rem"},children:["v",d]}),v.deletedAt&&(0,o.jsx)("span",{style:{marginLeft:"0.75rem",fontSize:"0.6875rem",padding:"0.125rem 0.375rem",borderRadius:"3px",background:"var(--error-bg, #fee)",color:"var(--error, #b00)"},children:"deleted"})]}),(0,o.jsx)(r(),{href:"/broadcasts/dyn/".concat(encodeURIComponent(s)),className:"btn",children:"Back to current"})]}),(0,o.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"minmax(0, 1fr) minmax(0, 1fr)",gap:"1rem",marginBottom:"1rem"},children:[(0,o.jsxs)("div",{children:[(0,o.jsx)("div",{className:"mono",style:g,children:"Compare to"}),(0,o.jsxs)("select",{className:"mono",value:null!=b?b:"",onChange:e=>S(e.target.value?Number(e.target.value):null),style:{width:"100%",padding:"0.5rem 0.625rem",border:"1px solid var(--border)",borderRadius:"4px",background:"var(--surface)",color:"var(--text)",fontSize:"0.875rem"},children:[(0,o.jsx)("option",{value:"",children:"— No comparison —"}),h.filter(e=>e.version!==d).map(e=>(0,o.jsxs)("option",{value:e.version,children:["v",e.version,e.deletedAt?" (deleted)":""," — ",new Date(e.updatedAt).toLocaleString()]},e.version))]})]}),(0,o.jsx)("div",{className:"mono",style:{fontSize:"0.75rem",color:"var(--muted)",alignSelf:"end"},children:T?"Diffing v".concat(T.version," → v").concat(v.version):"Showing the spec as-saved (no diff)."})]}),(0,o.jsxs)("div",{style:{display:"grid",gridTemplateColumns:T?"minmax(0, 1fr) minmax(0, 1fr)":"1fr",gap:"1rem"},children:[T&&(0,o.jsx)(u,{title:"v".concat(T.version),spec:T,highlight:null!=(t=null==w?void 0:w.removedLines)?t:new Set,side:"left"}),(0,o.jsx)(u,{title:"v".concat(v.version),spec:v,highlight:null!=(n=null==w?void 0:w.addedLines)?n:new Set,side:"right"})]}),(0,o.jsx)(c.F,{title:"Inspect this version",snippets:[{label:"Get this version",method:"GET",path:"/api/v1/broadcast-definitions/".concat(encodeURIComponent(s),"/versions/").concat(d)},{label:"List all versions",method:"GET",path:"/api/v1/broadcast-definitions/".concat(encodeURIComponent(s),"/versions")}]})]}):(0,o.jsxs)("div",{children:[(0,o.jsxs)("h1",{className:"page-title",children:[s," v",d]}),(0,o.jsx)("div",{className:"empty-state",children:(0,o.jsx)("p",{className:"empty-state-text",children:null!=N?N:"Version not found."})})]})}function u(e){let{title:t,spec:n,highlight:a,side:s}=e,r=JSON.stringify(m(n),null,2).split("\n");return(0,o.jsxs)("div",{children:[(0,o.jsx)("div",{className:"mono",style:g,children:t}),(0,o.jsx)("pre",{className:"mono",style:{margin:0,padding:"0.5rem",background:"var(--surface)",border:"1px solid var(--border)",borderRadius:"4px",fontSize:"0.75rem",lineHeight:1.5,overflowX:"auto",maxHeight:"640px",overflowY:"auto"},children:r.map((e,t)=>(0,o.jsx)("div",{style:{padding:"0 0.25rem",background:a.has(t)?"left"===s?"rgba(196, 131, 74, 0.18)":"rgba(107, 153, 98, 0.18)":"transparent",whiteSpace:"pre"},children:e||" "},t))})]})}function m(e){let{createdAt:t,updatedAt:n,deletedAt:o,createdBy:a,...s}=e;return function e(t){if(Array.isArray(t))return t.map(t=>e(t));if(t&&"object"==typeof t){let n={};for(let o of Object.keys(t).sort())n[o]=e(t[o]);return n}return t}(s)}let g={display:"block",fontSize:"0.75rem",color:"var(--muted)",textTransform:"uppercase",letterSpacing:"0.05em",marginBottom:"0.375rem"}},6990:(e,t,n)=>{"use strict";n.d(t,{F:()=>s});var o=n(8111),a=n(5271);function s(e){let{title:t="API equivalent",snippets:n}=e,[s,r]=(0,a.useState)(!1),[i,l]=(0,a.useState)(null),[c,d]=(0,a.useState)(null);if(0===n.length)return null;async function u(e,t){try{var n;if(null==(n=navigator.clipboard)?void 0:n.writeText){await navigator.clipboard.writeText(e),l(t),setTimeout(()=>l(e=>e===t?null:e),1500);return}throw Error("clipboard API unavailable")}catch(n){try{let n=document.createElement("textarea");n.value=e,n.style.position="fixed",n.style.left="-9999px",document.body.appendChild(n),n.select();let o=document.execCommand("copy");if(document.body.removeChild(n),o)l(t),setTimeout(()=>l(e=>e===t?null:e),1500);else throw Error("execCommand copy returned false")}catch(e){d(t),setTimeout(()=>d(e=>e===t?null:e),2e3)}}}return(0,o.jsxs)("details",{open:s,onToggle:e=>r(e.target.open),style:{marginTop:"1.5rem",border:"1px solid var(--border)",borderRadius:"4px",background:"var(--surface)"},children:[(0,o.jsxs)("summary",{style:{padding:"0.5rem 0.75rem",fontSize:"0.75rem",fontFamily:"var(--mono-font, monospace)",color:"var(--muted)",textTransform:"uppercase",letterSpacing:"0.05em",cursor:"pointer",listStyle:"none"},children:["▸ ",t]}),(0,o.jsx)("div",{style:{padding:"0.5rem 0.75rem 0.75rem"},children:n.map((e,t)=>{let a=function(e){var t;let n=[];if(e.query)for(let[t,o]of Object.entries(e.query))void 0!==o&&n.push("".concat(encodeURIComponent(t),"=").concat(encodeURIComponent(String(o))));let o="".concat(e.path).concat(n.length?"?".concat(n.join("&")):""),a=(null==(t=window.location)?void 0:t.origin)?window.location.origin:"https://your-station.example.com",s=[];if(s.push("curl -X ".concat(e.method," \\")),s.push(" ".concat(a).concat(o," \\")),s.push(" -H 'Authorization: Bearer sk_live_…' \\"),void 0!==e.body){s.push(" -H 'Content-Type: application/json' \\");let t="string"==typeof e.body?e.body:JSON.stringify(e.body,null,2);s.push(" -d ".concat(JSON.stringify(t)))}else s[s.length-1]=s[s.length-1].replace(/ \\$/,"");return s.join("\n")}(e);return(0,o.jsxs)("div",{style:{marginBottom:t===n.length-1?0:"0.75rem"},children:[(0,o.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:"0.25rem"},children:[(0,o.jsx)("div",{className:"mono",style:{fontSize:"0.75rem",color:"var(--muted)"},children:e.label}),(0,o.jsx)("button",{type:"button",className:"btn btn--sm",onClick:()=>u(a,t),title:c===t?"Copy failed — select the text manually":"",children:i===t?"Copied":c===t?"Copy failed":"Copy"})]}),(0,o.jsx)("pre",{className:"mono",style:{margin:0,padding:"0.5rem 0.75rem",background:"var(--bg, #fff)",border:"1px solid var(--border)",borderRadius:"4px",fontSize:"0.75rem",overflowX:"auto",whiteSpace:"pre"},children:a})]},t)})})]})}},7646:(e,t,n)=>{"use strict";n.d(t,{Hc:()=>a,iQ:()=>r,rT:()=>s});var o=n(5271);let a=(0,o.createContext)({segments:[],activeSection:null,setSegments:()=>{},setActiveSection:()=>{}});function s(e,t){let n=(0,o.useContext)(a);(0,o.useEffect)(()=>{n.setSegments(e),n.setActiveSection(t)},[JSON.stringify(e),t])}function r(){return(0,o.useContext)(a)}}},e=>{e.O(0,[935,814,743,358],()=>e(e.s=2311)),_N_E=e.O()}]);
|