ankka-console 0.10.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/README.md +32 -0
- package/dist/auth/oidc.d.ts +64 -0
- package/dist/auth/oidc.js +199 -0
- package/dist/client/control-plane.d.ts +67 -0
- package/dist/client/control-plane.js +208 -0
- package/dist/client/errors.d.ts +26 -0
- package/dist/client/errors.js +59 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.js +3 -0
- package/dist/client/schemas.d.ts +365 -0
- package/dist/client/schemas.js +221 -0
- package/dist/context.d.ts +83 -0
- package/dist/context.js +156 -0
- package/dist/extensions/render.d.ts +20 -0
- package/dist/extensions/render.js +49 -0
- package/dist/extensions/types.d.ts +44 -0
- package/dist/extensions/types.js +30 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/middleware.d.ts +14 -0
- package/dist/middleware.js +48 -0
- package/dist/options.d.ts +45 -0
- package/dist/options.js +39 -0
- package/dist/routes/auth.callback.d.ts +11 -0
- package/dist/routes/auth.callback.js +43 -0
- package/dist/routes/auth.sign-in.d.ts +11 -0
- package/dist/routes/auth.sign-in.js +29 -0
- package/dist/routes/auth.sign-out.d.ts +19 -0
- package/dist/routes/auth.sign-out.js +37 -0
- package/dist/routes/front.d.ts +41 -0
- package/dist/routes/front.js +25 -0
- package/dist/routes/logs.d.ts +67 -0
- package/dist/routes/logs.js +72 -0
- package/dist/routes/members.d.ts +45 -0
- package/dist/routes/members.js +59 -0
- package/dist/routes/organization-new.d.ts +14 -0
- package/dist/routes/organization-new.js +30 -0
- package/dist/routes/organization.d.ts +43 -0
- package/dist/routes/organization.js +82 -0
- package/dist/routes/project-new.d.ts +27 -0
- package/dist/routes/project-new.js +27 -0
- package/dist/routes/project.d.ts +59 -0
- package/dist/routes/project.js +61 -0
- package/dist/routes/service-apply.d.ts +44 -0
- package/dist/routes/service-apply.js +65 -0
- package/dist/routes/service.d.ts +71 -0
- package/dist/routes/service.js +73 -0
- package/dist/routes/stream.project.d.ts +3 -0
- package/dist/routes/stream.project.js +25 -0
- package/dist/routes/stream.service.d.ts +9 -0
- package/dist/routes/stream.service.js +68 -0
- package/dist/routes/tokens.d.ts +47 -0
- package/dist/routes/tokens.js +50 -0
- package/dist/routes.d.ts +28 -0
- package/dist/routes.js +48 -0
- package/dist/runtime.d.ts +28 -0
- package/dist/runtime.js +77 -0
- package/dist/server/create-console-server.d.ts +33 -0
- package/dist/server/create-console-server.js +203 -0
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.js +13 -0
- package/dist/server/transport.d.ts +25 -0
- package/dist/server/transport.js +97 -0
- package/dist/session/cookie-store.d.ts +51 -0
- package/dist/session/cookie-store.js +66 -0
- package/dist/session/cookies.d.ts +15 -0
- package/dist/session/cookies.js +33 -0
- package/dist/session/seal.d.ts +12 -0
- package/dist/session/seal.js +38 -0
- package/dist/session/token-cache.d.ts +21 -0
- package/dist/session/token-cache.js +47 -0
- package/dist/session/token-source.d.ts +41 -0
- package/dist/session/token-source.js +63 -0
- package/dist/stream/log-follow.d.ts +18 -0
- package/dist/stream/log-follow.js +40 -0
- package/dist/stream/registry.d.ts +6 -0
- package/dist/stream/registry.js +34 -0
- package/dist/stream/sse.d.ts +14 -0
- package/dist/stream/sse.js +87 -0
- package/dist/styles.css +481 -0
- package/dist/testing/fake-control-plane.d.ts +161 -0
- package/dist/testing/fake-control-plane.js +715 -0
- package/dist/testing/fake-issuer.d.ts +66 -0
- package/dist/testing/fake-issuer.js +303 -0
- package/dist/testing/index.d.ts +5 -0
- package/dist/testing/index.js +3 -0
- package/dist/testing/scenarios.d.ts +6 -0
- package/dist/testing/scenarios.js +44 -0
- package/dist/ui/console.d.ts +60 -0
- package/dist/ui/console.js +73 -0
- package/dist/ui/errors.d.ts +6 -0
- package/dist/ui/errors.js +30 -0
- package/dist/ui/refused.d.ts +6 -0
- package/dist/ui/refused.js +12 -0
- package/dist/ui/status.d.ts +5 -0
- package/dist/ui/status.js +23 -0
- package/dist/ui/use-stream.d.ts +59 -0
- package/dist/ui/use-stream.js +67 -0
- package/package.json +79 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* A service's lifecycle as a word and a shape. The shape carries the state as well as the colour
|
|
4
|
+
* does, so nothing depends on seeing colour: filled for running, half for partly, hollow for not
|
|
5
|
+
* yet, a bar for stopped on purpose, a triangle for trouble.
|
|
6
|
+
*/
|
|
7
|
+
const known = {
|
|
8
|
+
Ready: { mark: "●", tone: "ready", words: "Ready" },
|
|
9
|
+
PartiallyReady: { mark: "◐", tone: "partial", words: "Partially ready" },
|
|
10
|
+
UpdateInProgress: { mark: "◌", tone: "moving", words: "Updating" },
|
|
11
|
+
NotDeployed: { mark: "○", tone: "idle", words: "Not deployed" },
|
|
12
|
+
Paused: { mark: "▮▮", tone: "stopped", words: "Paused" },
|
|
13
|
+
Suspended: { mark: "▮▮", tone: "stopped", words: "Suspended" },
|
|
14
|
+
Unavailable: { mark: "▲", tone: "trouble", words: "Unavailable" },
|
|
15
|
+
Failed: { mark: "▲", tone: "trouble", words: "Failed" },
|
|
16
|
+
};
|
|
17
|
+
export function lifecycleWords(lifecycle) {
|
|
18
|
+
return known[lifecycle]?.words ?? lifecycle;
|
|
19
|
+
}
|
|
20
|
+
export function Lifecycle({ lifecycle, confirmed = true }) {
|
|
21
|
+
const k = known[lifecycle] ?? { mark: "○", tone: "idle", words: lifecycle };
|
|
22
|
+
return (_jsxs("span", { className: `ac-status ac-status-${k.tone}`, "data-lifecycle": lifecycle, children: [_jsx("span", { className: "ac-status-mark", "aria-hidden": "true", children: k.mark }), k.words, confirmed ? null : _jsx("span", { className: "ac-status-note", children: " (last known)" })] }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ServiceStatus } from "../client/schemas.ts";
|
|
2
|
+
export type StreamState = "connecting" | "live" | "gone" | "off";
|
|
3
|
+
export declare function useProjectStream(projectId: string, initial: ServiceStatus[]): {
|
|
4
|
+
services: {
|
|
5
|
+
name: string;
|
|
6
|
+
projectId: string;
|
|
7
|
+
lifecycle: string;
|
|
8
|
+
generation: number;
|
|
9
|
+
image: string;
|
|
10
|
+
readyInstances: number;
|
|
11
|
+
desiredInstances: number;
|
|
12
|
+
detail: string | undefined;
|
|
13
|
+
confirmed: boolean;
|
|
14
|
+
database: string | undefined;
|
|
15
|
+
hostname: string | undefined;
|
|
16
|
+
exposed: boolean;
|
|
17
|
+
suspended: boolean;
|
|
18
|
+
paused: boolean;
|
|
19
|
+
hosting: string;
|
|
20
|
+
protocol: string | undefined;
|
|
21
|
+
}[];
|
|
22
|
+
state: StreamState;
|
|
23
|
+
};
|
|
24
|
+
export interface LogsState {
|
|
25
|
+
byInstance: Record<string, {
|
|
26
|
+
lines: string[];
|
|
27
|
+
error?: string;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
export declare function useServiceStream(projectId: string, name: string, initial: ServiceStatus, logs?: {
|
|
31
|
+
follow: boolean;
|
|
32
|
+
query: string;
|
|
33
|
+
tail: number;
|
|
34
|
+
initial: LogsState["byInstance"];
|
|
35
|
+
}): {
|
|
36
|
+
status: {
|
|
37
|
+
name: string;
|
|
38
|
+
projectId: string;
|
|
39
|
+
lifecycle: string;
|
|
40
|
+
generation: number;
|
|
41
|
+
image: string;
|
|
42
|
+
readyInstances: number;
|
|
43
|
+
desiredInstances: number;
|
|
44
|
+
detail: string | undefined;
|
|
45
|
+
confirmed: boolean;
|
|
46
|
+
database: string | undefined;
|
|
47
|
+
hostname: string | undefined;
|
|
48
|
+
exposed: boolean;
|
|
49
|
+
suspended: boolean;
|
|
50
|
+
paused: boolean;
|
|
51
|
+
hosting: string;
|
|
52
|
+
protocol: string | undefined;
|
|
53
|
+
};
|
|
54
|
+
byInstance: Record<string, {
|
|
55
|
+
lines: string[];
|
|
56
|
+
error?: string;
|
|
57
|
+
}>;
|
|
58
|
+
state: StreamState;
|
|
59
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser's side of the update streams. A stream opens only after hydration, in an effect, so a
|
|
3
|
+
* page with scripts off opens none and shows the state as of its last request. `EventSource`
|
|
4
|
+
* reconnects on its own when an instance closes the stream, and every stream starts by sending the
|
|
5
|
+
* current state, so nothing has to be carried across.
|
|
6
|
+
*/
|
|
7
|
+
import { useEffect, useRef, useState } from "react";
|
|
8
|
+
import { useConsole } from "./console.js";
|
|
9
|
+
function useEvents(path, handlers) {
|
|
10
|
+
const { mount } = useConsole();
|
|
11
|
+
const [state, setState] = useState(path ? "connecting" : "off");
|
|
12
|
+
const ref = useRef(handlers);
|
|
13
|
+
ref.current = handlers;
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (!path) {
|
|
16
|
+
setState("off");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const href = (p) => mount + p.replace(/^\/+/, "");
|
|
20
|
+
const source = new EventSource(href(path));
|
|
21
|
+
setState("connecting");
|
|
22
|
+
source.onopen = () => setState("live");
|
|
23
|
+
const on = (name, f) => source.addEventListener(name, (e) => f(JSON.parse(e.data)));
|
|
24
|
+
for (const name of ["status", "services", "logs"])
|
|
25
|
+
on(name, (d) => ref.current[name]?.(d));
|
|
26
|
+
on("session-ended", () => {
|
|
27
|
+
source.close();
|
|
28
|
+
window.location.assign(href(`auth/sign-in?returnTo=${encodeURIComponent(window.location.pathname + window.location.search)}`));
|
|
29
|
+
});
|
|
30
|
+
on("gone", () => {
|
|
31
|
+
source.close();
|
|
32
|
+
setState("gone");
|
|
33
|
+
});
|
|
34
|
+
on("server-closing", () => setState("connecting"));
|
|
35
|
+
source.onerror = () => setState(source.readyState === EventSource.CLOSED ? "off" : "connecting");
|
|
36
|
+
return () => source.close();
|
|
37
|
+
}, [path, mount]);
|
|
38
|
+
return state;
|
|
39
|
+
}
|
|
40
|
+
export function useProjectStream(projectId, initial) {
|
|
41
|
+
const [services, setServices] = useState(initial);
|
|
42
|
+
useEffect(() => setServices(initial), [initial]);
|
|
43
|
+
const state = useEvents(`stream/projects/${encodeURIComponent(projectId)}`, {
|
|
44
|
+
services: (d) => setServices(d),
|
|
45
|
+
});
|
|
46
|
+
return { services, state };
|
|
47
|
+
}
|
|
48
|
+
export function useServiceStream(projectId, name, initial, logs) {
|
|
49
|
+
const [status, setStatus] = useState(initial);
|
|
50
|
+
useEffect(() => setStatus(initial), [initial]);
|
|
51
|
+
const [byInstance, setByInstance] = useState(logs?.initial ?? {});
|
|
52
|
+
useEffect(() => setByInstance(logs?.initial ?? {}), [logs?.initial]);
|
|
53
|
+
const base = `stream/services/${encodeURIComponent(projectId)}/${encodeURIComponent(name)}`;
|
|
54
|
+
const path = logs?.follow ? `${base}?logs&${logs.query}` : base;
|
|
55
|
+
const state = useEvents(path, {
|
|
56
|
+
status: (d) => setStatus(d),
|
|
57
|
+
logs: (d) => {
|
|
58
|
+
const e = d;
|
|
59
|
+
setByInstance((prev) => {
|
|
60
|
+
const kept = e.reset ? [] : (prev[e.instance]?.lines ?? []);
|
|
61
|
+
const next = e.error ? { lines: kept, error: e.error } : { lines: [...kept, ...(e.lines ?? [])].slice(-(logs?.tail ?? 200)) };
|
|
62
|
+
return { ...prev, [e.instance]: next };
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
return { status, byInstance, state };
|
|
67
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ankka-console",
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "The ankka console as a package: the control plane client, sign-in and sessions, and the pages as routes a React Router host mounts.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=24"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"sideEffects": [
|
|
14
|
+
"*.css"
|
|
15
|
+
],
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"ankka-source": "./src/index.ts",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./client": {
|
|
23
|
+
"ankka-source": "./src/client/index.ts",
|
|
24
|
+
"types": "./dist/client/index.d.ts",
|
|
25
|
+
"default": "./dist/client/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./server": {
|
|
28
|
+
"ankka-source": "./src/server/index.ts",
|
|
29
|
+
"types": "./dist/server/index.d.ts",
|
|
30
|
+
"default": "./dist/server/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./testing": {
|
|
33
|
+
"ankka-source": "./src/testing/index.ts",
|
|
34
|
+
"types": "./dist/testing/index.d.ts",
|
|
35
|
+
"default": "./dist/testing/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./styles.css": "./dist/styles.css"
|
|
38
|
+
},
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/thinkmorestupidless/ankka.git",
|
|
42
|
+
"directory": "console/package"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://docs.ankka.cloud/",
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "node scripts/build.ts",
|
|
47
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
48
|
+
"test": "node --conditions=ankka-source --test 'test/**/*.test.ts'"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"jose": "^6.2.12",
|
|
52
|
+
"openid-client": "^6.8.8",
|
|
53
|
+
"zod": "^4.6.5"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@react-router/dev": "^8.4.0",
|
|
57
|
+
"@react-router/node": "^8.4.0",
|
|
58
|
+
"react": "^19.2.7",
|
|
59
|
+
"react-dom": "^19.2.7",
|
|
60
|
+
"react-router": "^8.4.0"
|
|
61
|
+
},
|
|
62
|
+
"peerDependenciesMeta": {
|
|
63
|
+
"@react-router/dev": {
|
|
64
|
+
"optional": true
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@react-router/dev": "^8.4.0",
|
|
69
|
+
"@react-router/node": "^8.4.0",
|
|
70
|
+
"@types/node": "^26.6.3",
|
|
71
|
+
"@types/react": "^19.3.0",
|
|
72
|
+
"@types/react-dom": "^19.3.0",
|
|
73
|
+
"react": "^19.3.0",
|
|
74
|
+
"react-dom": "^19.3.0",
|
|
75
|
+
"react-router": "^8.4.0",
|
|
76
|
+
"typescript": "^7.0.2",
|
|
77
|
+
"vite": "^8.3.1"
|
|
78
|
+
}
|
|
79
|
+
}
|