@rigkit/sdk 0.1.8

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.
@@ -0,0 +1,63 @@
1
+ import { RIGKIT_ENGINE_VERSION } from "@rigkit/engine";
2
+ import { RIGKIT_RUNTIME_VERSION } from "./version.ts";
3
+ import { createRuntimeControlApiHandler } from "./api-handlers.ts";
4
+ import {
5
+ RUNTIME_API_VERSION,
6
+ RUNTIME_PROTOCOL_HASH,
7
+ } from "./protocol.ts";
8
+ import { type RunStore } from "./runs.ts";
9
+ import type { RuntimeContext } from "./types.ts";
10
+
11
+ export type { RuntimeAppState } from "./control.ts";
12
+
13
+ export type RuntimeApp = {
14
+ fetch(request: Request): Promise<Response>;
15
+ request(path: string, init?: RequestInit): Promise<Response>;
16
+ };
17
+
18
+ export function createRuntimeApp(context: RuntimeContext, store: RunStore): RuntimeApp {
19
+ const controlApi = createRuntimeControlApiHandler(context, store);
20
+
21
+ return {
22
+ async fetch(request) {
23
+ return controlApi.handler(request);
24
+ },
25
+
26
+ async request(path, init) {
27
+ const url = path.startsWith("http://") || path.startsWith("https://")
28
+ ? path
29
+ : `http://runtime.local${path.startsWith("/") ? path : `/${path}`}`;
30
+ return await this.fetch(new Request(url, init)) ?? runtimeJsonError(500, "Request did not produce a response");
31
+ },
32
+ };
33
+ }
34
+
35
+ export function sessionRunIdFor(pathname: string): string | undefined {
36
+ const match = /^\/runs\/([^/]+)\/session$/.exec(pathname);
37
+ return match?.[1] ? decodeURIComponent(match[1]) : undefined;
38
+ }
39
+
40
+ export function runtimeJsonError(status: number, message: string): Response {
41
+ return withRuntimeHeaders(Response.json({ error: { message } }, { status }));
42
+ }
43
+
44
+ export function withRuntimeHeaders(response: Response): Response {
45
+ const headers = new Headers(response.headers);
46
+ for (const [key, value] of Object.entries(runtimeHeaders())) {
47
+ headers.set(key, value);
48
+ }
49
+ return new Response(response.body, {
50
+ status: response.status,
51
+ statusText: response.statusText,
52
+ headers,
53
+ });
54
+ }
55
+
56
+ export function runtimeHeaders() {
57
+ return {
58
+ "x-rigkit-api-version": String(RUNTIME_API_VERSION),
59
+ "x-rigkit-protocol-hash": RUNTIME_PROTOCOL_HASH,
60
+ "x-rigkit-engine-version": RIGKIT_ENGINE_VERSION,
61
+ "x-rigkit-runtime-version": RIGKIT_RUNTIME_VERSION,
62
+ };
63
+ }
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env bun
2
+ import { resolve } from "node:path";
3
+ import { serveRuntime } from "./server.ts";
4
+
5
+ type ServeArgs = {
6
+ projectId?: string;
7
+ projectDir?: string;
8
+ configPath?: string;
9
+ statePath?: string;
10
+ sourceJson?: string;
11
+ handlePath?: string;
12
+ tokenPath?: string;
13
+ host?: string;
14
+ port?: number;
15
+ idleMs?: number;
16
+ };
17
+
18
+ const [command, ...args] = process.argv.slice(2);
19
+
20
+ if (command !== "serve") {
21
+ console.error(`Usage: rigkit-runtime serve --project-id <id> --project-dir <dir> --config <file> --handle <file> --token <file>`);
22
+ process.exit(1);
23
+ }
24
+
25
+ const options = parseServeArgs(args);
26
+ const missing = [
27
+ ["--project-id", options.projectId],
28
+ ["--project-dir", options.projectDir],
29
+ ["--config", options.configPath],
30
+ ["--handle", options.handlePath],
31
+ ["--token", options.tokenPath],
32
+ ].filter(([, value]) => !value);
33
+ if (missing.length > 0) {
34
+ console.error(`Missing required runtime args: ${missing.map(([name]) => name).join(", ")}`);
35
+ process.exit(1);
36
+ }
37
+
38
+ const runtime = await serveRuntime({
39
+ projectId: options.projectId!,
40
+ projectDir: resolve(options.projectDir!),
41
+ configPath: resolve(options.configPath!),
42
+ statePath: options.statePath ? resolve(options.statePath) : undefined,
43
+ source: options.sourceJson ? JSON.parse(options.sourceJson) : undefined,
44
+ handlePath: resolve(options.handlePath!),
45
+ tokenPath: resolve(options.tokenPath!),
46
+ host: options.host,
47
+ port: options.port,
48
+ idleMs: options.idleMs,
49
+ });
50
+
51
+ console.log(JSON.stringify({
52
+ type: "ready",
53
+ url: runtime.url,
54
+ token: runtime.token,
55
+ }));
56
+
57
+ for (const signal of ["SIGINT", "SIGTERM"] as const) {
58
+ process.on(signal, () => {
59
+ runtime.stop();
60
+ process.exit(0);
61
+ });
62
+ }
63
+
64
+ await new Promise(() => {});
65
+
66
+ function parseServeArgs(args: string[]): ServeArgs {
67
+ const parsed: ServeArgs = {};
68
+ for (let index = 0; index < args.length; index += 1) {
69
+ const arg = args[index]!;
70
+ const next = args[index + 1];
71
+ const readValue = () => {
72
+ if (!next) throw new Error(`${arg} requires a value`);
73
+ index += 1;
74
+ return next;
75
+ };
76
+
77
+ switch (arg) {
78
+ case "--project-id":
79
+ parsed.projectId = readValue();
80
+ break;
81
+ case "--project-dir":
82
+ case "--project":
83
+ parsed.projectDir = readValue();
84
+ break;
85
+ case "--config":
86
+ parsed.configPath = readValue();
87
+ break;
88
+ case "--state":
89
+ case "--state-path":
90
+ parsed.statePath = readValue();
91
+ break;
92
+ case "--source-json":
93
+ parsed.sourceJson = readValue();
94
+ break;
95
+ case "--handle":
96
+ parsed.handlePath = readValue();
97
+ break;
98
+ case "--token":
99
+ parsed.tokenPath = readValue();
100
+ break;
101
+ case "--host":
102
+ parsed.host = readValue();
103
+ break;
104
+ case "--port":
105
+ parsed.port = Number(readValue());
106
+ break;
107
+ case "--idle-ms":
108
+ parsed.idleMs = Number(readValue());
109
+ break;
110
+ default:
111
+ throw new Error(`Unknown runtime arg ${arg}`);
112
+ }
113
+ }
114
+ return parsed;
115
+ }
@@ -0,0 +1,163 @@
1
+ import { RIGKIT_ENGINE_VERSION, type WorkspaceRecord } from "@rigkit/engine";
2
+ import { RIGKIT_RUNTIME_VERSION } from "./version.ts";
3
+ import { RuntimeHostRequestError } from "./errors.ts";
4
+ import { loadEngine, operationManifestFor, runOperation } from "./operations.ts";
5
+ import {
6
+ RUNTIME_API_VERSION,
7
+ RUNTIME_PROTOCOL_HASH,
8
+ RuntimeProtocolSchemaError,
9
+ type HostResponse,
10
+ type RunOperationRequest,
11
+ type RuntimeOperation,
12
+ } from "./protocol.ts";
13
+ import {
14
+ createRun,
15
+ summarizeRun,
16
+ sseResponse,
17
+ type RunStore,
18
+ } from "./runs.ts";
19
+ import type { RuntimeContext } from "./types.ts";
20
+
21
+ export type RuntimeAppState = {
22
+ readonly context: RuntimeContext;
23
+ readonly store: RunStore;
24
+ };
25
+
26
+ export class RuntimeControlHttpError extends Error {
27
+ constructor(readonly status: number, message: string) {
28
+ super(message);
29
+ this.name = "RuntimeControlHttpError";
30
+ }
31
+ }
32
+
33
+ export function runtimeHealth(context: RuntimeContext) {
34
+ return {
35
+ ok: true,
36
+ projectId: context.projectId,
37
+ projectDir: context.projectDir,
38
+ configPath: context.configPath,
39
+ statePath: context.statePath,
40
+ engineVersion: RIGKIT_ENGINE_VERSION,
41
+ runtimeVersion: RIGKIT_RUNTIME_VERSION,
42
+ expiresAt: context.getExpiresAt(),
43
+ };
44
+ }
45
+
46
+ export function runtimeMetadata() {
47
+ return {
48
+ apiVersion: RUNTIME_API_VERSION,
49
+ engineVersion: RIGKIT_ENGINE_VERSION,
50
+ runtimeVersion: RIGKIT_RUNTIME_VERSION,
51
+ protocolHash: RUNTIME_PROTOCOL_HASH,
52
+ };
53
+ }
54
+
55
+ export async function runtimeProject(context: RuntimeContext) {
56
+ const engine = await loadEngine(context);
57
+ return engine.getProjectInfo();
58
+ }
59
+
60
+ export async function runtimeOperations(context: RuntimeContext) {
61
+ const engine = await loadEngine(context);
62
+ return operationManifestFor(engine);
63
+ }
64
+
65
+ export async function runtimeWorkflows(context: RuntimeContext) {
66
+ const engine = await loadEngine(context);
67
+ return { workflows: engine.listWorkflowSummaries() };
68
+ }
69
+
70
+ export async function runtimeWorkspaces(context: RuntimeContext) {
71
+ const engine = await loadEngine(context);
72
+ return { workspaces: engine.listWorkspaces().map(runtimeWorkspace) };
73
+ }
74
+
75
+ export async function runtimeSnapshots(context: RuntimeContext) {
76
+ const engine = await loadEngine(context);
77
+ return { snapshots: engine.listSnapshots() };
78
+ }
79
+
80
+ export function runtimeRuns(store: RunStore) {
81
+ return {
82
+ runs: [...store.runs.values()].map((run) => summarizeRun(run)),
83
+ };
84
+ }
85
+
86
+ export async function startRuntimeRun(state: RuntimeAppState, body: RunOperationRequest) {
87
+ const engine = await loadEngine(state.context);
88
+ const manifest = operationManifestFor(engine);
89
+ const operation = findRuntimeOperation(manifest.operations, body.operation);
90
+ if (!operation) throw new RuntimeControlHttpError(400, `Unknown operation ${body.operation}`);
91
+
92
+ const run = createRun(operation.id, body.input ?? {}, operation);
93
+ state.store.runs.set(run.id, run);
94
+ runOperation(run, state.store, state.context);
95
+
96
+ return {
97
+ runId: run.id,
98
+ operation: run.operation,
99
+ status: run.status,
100
+ eventsUrl: `/runs/${run.id}/events`,
101
+ sessionUrl: `/runs/${run.id}/session`,
102
+ };
103
+ }
104
+
105
+ export function runtimeRun(store: RunStore, runId: string) {
106
+ const run = store.runs.get(runId);
107
+ if (!run) throw new RuntimeControlHttpError(404, `Unknown run ${runId}`);
108
+ return summarizeRun(run);
109
+ }
110
+
111
+ export function runtimeRunEvents(store: RunStore, runId: string): Response {
112
+ const run = store.runs.get(runId);
113
+ if (!run) throw new RuntimeControlHttpError(404, `Unknown run ${runId}`);
114
+ return sseResponse(run);
115
+ }
116
+
117
+ export function submitHostResponse(state: RuntimeAppState, requestId: string, body: HostResponse) {
118
+ const pending = state.store.hostResponses.get(requestId);
119
+ if (!pending) throw new RuntimeControlHttpError(404, `Unknown host request ${requestId}`);
120
+
121
+ state.store.hostResponses.delete(requestId);
122
+ clearPendingHostRequest(state.store, requestId);
123
+ if ("error" in body) {
124
+ pending.reject(new RuntimeHostRequestError({
125
+ requestId,
126
+ hostCode: body.error.code,
127
+ message: body.error.message ?? "Host request failed",
128
+ }));
129
+ } else {
130
+ pending.resolve(body.result ?? null);
131
+ }
132
+ return { ok: true };
133
+ }
134
+
135
+ export function shutdownRuntime(context: RuntimeContext) {
136
+ setTimeout(() => context.stop(), 0);
137
+ return { ok: true };
138
+ }
139
+
140
+ export function runtimeControlErrorStatus(error: unknown): number {
141
+ if (error instanceof RuntimeControlHttpError) return error.status;
142
+ if (error instanceof RuntimeProtocolSchemaError) return 400;
143
+ return 500;
144
+ }
145
+
146
+ function findRuntimeOperation(operations: RuntimeOperation[], requestedOperation: string): RuntimeOperation | undefined {
147
+ return operations.find((operation) =>
148
+ operation.id === requestedOperation || operation.aliases?.includes(requestedOperation)
149
+ );
150
+ }
151
+
152
+ function runtimeWorkspace(workspace: WorkspaceRecord): WorkspaceRecord & { data: WorkspaceRecord["metadata"] } {
153
+ return {
154
+ ...workspace,
155
+ data: workspace.metadata,
156
+ };
157
+ }
158
+
159
+ export function clearPendingHostRequest(store: RunStore, requestId: string): void {
160
+ for (const run of store.runs.values()) {
161
+ run.pendingHostRequestIds.delete(requestId);
162
+ }
163
+ }
@@ -0,0 +1,108 @@
1
+ import {
2
+ EngineOperationNotFoundError,
3
+ EngineOperationValidationError,
4
+ } from "@rigkit/engine";
5
+
6
+ export type RuntimeFailureCode =
7
+ | "ENGINE_FAILED"
8
+ | "HOST_REQUEST_FAILED"
9
+ | "OPERATION_NOT_FOUND"
10
+ | "OPERATION_VALIDATION_FAILED"
11
+ | "RUN_CANCELLED";
12
+
13
+ export class RuntimeOperationValidationError extends Error {
14
+ readonly code = "OPERATION_VALIDATION_FAILED" as const;
15
+ readonly operation: string;
16
+
17
+ constructor(input: { operation: string; cause: unknown }) {
18
+ super(`Invalid input for operation ${input.operation}: ${String(input.cause)}`, { cause: input.cause });
19
+ this.name = "RuntimeOperationValidationError";
20
+ this.operation = input.operation;
21
+ }
22
+ }
23
+
24
+ export class RuntimeOperationNotFoundError extends Error {
25
+ readonly code = "OPERATION_NOT_FOUND" as const;
26
+ readonly operation: string;
27
+
28
+ constructor(operation: string) {
29
+ super(`Unknown operation ${operation}`);
30
+ this.name = "RuntimeOperationNotFoundError";
31
+ this.operation = operation;
32
+ }
33
+ }
34
+
35
+ export class RuntimeHostRequestError extends Error {
36
+ readonly code = "HOST_REQUEST_FAILED" as const;
37
+ readonly requestId?: string;
38
+ readonly method?: string;
39
+ readonly hostCode?: string;
40
+
41
+ constructor(input: {
42
+ message?: string;
43
+ requestId?: string;
44
+ method?: string;
45
+ hostCode?: string;
46
+ cause?: unknown;
47
+ }) {
48
+ super(input.message ?? "Host request failed", { cause: input.cause });
49
+ this.name = "RuntimeHostRequestError";
50
+ this.requestId = input.requestId;
51
+ this.method = input.method;
52
+ this.hostCode = input.hostCode;
53
+ }
54
+ }
55
+
56
+ export class RuntimeEngineError extends Error {
57
+ readonly code = "ENGINE_FAILED" as const;
58
+
59
+ constructor(input: { message?: string; cause: unknown }) {
60
+ super(input.message ?? errorMessage(input.cause), { cause: input.cause });
61
+ this.name = "RuntimeEngineError";
62
+ }
63
+ }
64
+
65
+ export class RuntimeRunCancelledError extends Error {
66
+ readonly code = "RUN_CANCELLED" as const;
67
+
68
+ constructor() {
69
+ super("Run cancelled by host");
70
+ this.name = "RuntimeRunCancelledError";
71
+ }
72
+ }
73
+
74
+ export type RuntimeRunError =
75
+ | RuntimeEngineError
76
+ | RuntimeHostRequestError
77
+ | RuntimeOperationNotFoundError
78
+ | RuntimeOperationValidationError
79
+ | RuntimeRunCancelledError;
80
+
81
+ export function isRuntimeRunError(error: unknown): error is RuntimeRunError {
82
+ return error instanceof RuntimeEngineError
83
+ || error instanceof RuntimeHostRequestError
84
+ || error instanceof RuntimeOperationNotFoundError
85
+ || error instanceof RuntimeOperationValidationError
86
+ || error instanceof RuntimeRunCancelledError;
87
+ }
88
+
89
+ export function normalizeRuntimeRunError(error: unknown): RuntimeRunError {
90
+ if (isRuntimeRunError(error)) return error;
91
+ if (error instanceof EngineOperationNotFoundError) return new RuntimeOperationNotFoundError(error.operation);
92
+ if (error instanceof EngineOperationValidationError) {
93
+ return new RuntimeOperationValidationError({ operation: error.operation, cause: error });
94
+ }
95
+ return new RuntimeEngineError({ cause: error });
96
+ }
97
+
98
+ export function runtimeFailureBody(error: unknown): { code: RuntimeFailureCode; message: string } {
99
+ const normalized = normalizeRuntimeRunError(error);
100
+ return {
101
+ code: normalized.code,
102
+ message: normalized.message,
103
+ };
104
+ }
105
+
106
+ function errorMessage(error: unknown): string {
107
+ return error instanceof Error ? error.message : String(error);
108
+ }
@@ -0,0 +1,81 @@
1
+ export {
2
+ RuntimeEngineError,
3
+ RuntimeHostRequestError,
4
+ RuntimeOperationNotFoundError,
5
+ RuntimeOperationValidationError,
6
+ RuntimeRunCancelledError,
7
+ isRuntimeRunError,
8
+ normalizeRuntimeRunError,
9
+ runtimeFailureBody,
10
+ type RuntimeFailureCode,
11
+ type RuntimeRunError,
12
+ } from "./errors.ts";
13
+ export {
14
+ RuntimeServerError,
15
+ serveRuntime,
16
+ serveRuntimeEffect,
17
+ type ServeRuntimeOptions,
18
+ type RuntimeServer,
19
+ } from "./server.ts";
20
+ export { RIGKIT_RUNTIME_VERSION } from "./version.ts";
21
+ export {
22
+ RuntimeApiState,
23
+ createRuntimeControlApiHandler,
24
+ runtimeApiStateLayer,
25
+ runtimeControlApiErrorMiddlewareLayer,
26
+ runtimeControlApiHandlersLayer,
27
+ } from "./api-handlers.ts";
28
+ export {
29
+ RuntimeControlHttpError,
30
+ runtimeControlErrorStatus,
31
+ } from "./control.ts";
32
+ export {
33
+ createRuntimeStateService,
34
+ type RuntimeStateService,
35
+ type RuntimeStateServiceOptions,
36
+ } from "./state.ts";
37
+ export {
38
+ HostCapabilityRequirementEffectSchema,
39
+ HostMethodRequirementEffectSchema,
40
+ OkResponseEffectSchema,
41
+ OperationsManifestEffectSchema,
42
+ ProjectInfoEffectSchema,
43
+ RunStartedEffectSchema,
44
+ RuntimeHealthEffectSchema,
45
+ RuntimeMetadataEffectSchema,
46
+ RuntimeOperationCliEffectSchema,
47
+ RuntimeOperationEffectSchema,
48
+ RuntimeRunEffectSchema,
49
+ RunsResponseEffectSchema,
50
+ SnapshotsResponseEffectSchema,
51
+ WorkflowSummaryEffectSchema,
52
+ WorkflowsResponseEffectSchema,
53
+ WorkspaceEffectSchema,
54
+ WorkspacesResponseEffectSchema,
55
+ runtimeControlApi,
56
+ runtimeControlOpenApiDocument,
57
+ } from "./api.ts";
58
+ export { createRuntimeApp, type RuntimeAppState } from "./app.ts";
59
+ export type { HostCapabilitySessionResult } from "./runs.ts";
60
+ export {
61
+ DEFAULT_IDLE_MS,
62
+ HostCommandRequestEffectSchema,
63
+ HostCommandRequestSchema,
64
+ HostCommandResultEffectSchema,
65
+ HostCommandResultSchema,
66
+ HostResponseEffectSchema,
67
+ HostResponseSchema,
68
+ RUNTIME_API_VERSION,
69
+ RUNTIME_PROTOCOL_HASH,
70
+ RunOperationRequestEffectSchema,
71
+ RunOperationRequestSchema,
72
+ RuntimeProtocolSchemaError,
73
+ type RuntimeOperationsManifest,
74
+ type HostCommandRequest,
75
+ type HostCommandResult,
76
+ type HostResponse,
77
+ type HostCapabilityRequestEvent,
78
+ type HostRequestEvent,
79
+ type RuntimeEvent,
80
+ type RuntimeOperation,
81
+ } from "./protocol.ts";
@@ -0,0 +1,5 @@
1
+ import { runtimeControlOpenApiDocument } from "./api.ts";
2
+
3
+ export function openApiDocument(): Record<string, unknown> {
4
+ return runtimeControlOpenApiDocument() as unknown as Record<string, unknown>;
5
+ }