@rigkit/runtime-client 0.2.6 → 0.2.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.
- package/package.json +1 -1
- package/src/api.ts +49 -0
- package/src/client.ts +23 -0
- package/src/index.ts +8 -0
- package/src/manager.ts +57 -13
- package/src/schemas.ts +2 -0
- package/src/version.ts +1 -1
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -18,6 +18,7 @@ export const RuntimeControlHealthEffectSchema = Schema.Struct({
|
|
|
18
18
|
projectDir: Schema.String,
|
|
19
19
|
configPath: Schema.String,
|
|
20
20
|
statePath: OptionalString,
|
|
21
|
+
globalFragmentRoot: OptionalString,
|
|
21
22
|
engineVersion: Schema.String,
|
|
22
23
|
runtimeVersion: Schema.String,
|
|
23
24
|
expiresAt: Schema.String,
|
|
@@ -99,6 +100,41 @@ export const RuntimeControlSnapshotsResponseEffectSchema = Schema.Struct({
|
|
|
99
100
|
snapshots: Schema.Array(Schema.Unknown),
|
|
100
101
|
}).annotations({ identifier: "SnapshotsResponse" });
|
|
101
102
|
|
|
103
|
+
export const RuntimeControlCacheEntryEffectSchema = Schema.Struct({
|
|
104
|
+
scope: Schema.Literal("local", "global"),
|
|
105
|
+
workflow: Schema.String,
|
|
106
|
+
nodePath: Schema.String,
|
|
107
|
+
nodeName: Schema.String,
|
|
108
|
+
nodeKind: Schema.String,
|
|
109
|
+
runId: Schema.String,
|
|
110
|
+
invalidated: Schema.Boolean,
|
|
111
|
+
createdAt: Schema.String,
|
|
112
|
+
fragmentHash: Schema.optional(Schema.String),
|
|
113
|
+
}).annotations({ identifier: "CacheEntry" });
|
|
114
|
+
|
|
115
|
+
export const RuntimeControlCacheResponseEffectSchema = Schema.Struct({
|
|
116
|
+
entries: Schema.Array(RuntimeControlCacheEntryEffectSchema),
|
|
117
|
+
}).annotations({ identifier: "CacheResponse" });
|
|
118
|
+
|
|
119
|
+
export const RuntimeControlCacheClearRequestEffectSchema = Schema.Struct({
|
|
120
|
+
scope: Schema.optional(Schema.Literal("local", "global", "all")),
|
|
121
|
+
}).annotations({ identifier: "CacheClearRequest" });
|
|
122
|
+
|
|
123
|
+
export const RuntimeControlCacheClearResponseEffectSchema = Schema.Struct({
|
|
124
|
+
ok: Schema.Boolean,
|
|
125
|
+
deleted: Schema.Number,
|
|
126
|
+
}).annotations({ identifier: "CacheClearResponse" });
|
|
127
|
+
|
|
128
|
+
export const RuntimeControlCacheInvalidateRequestEffectSchema = Schema.Struct({
|
|
129
|
+
workflow: Schema.optional(Schema.String),
|
|
130
|
+
nodePaths: Schema.optional(Schema.Array(Schema.String)),
|
|
131
|
+
}).annotations({ identifier: "CacheInvalidateRequest" });
|
|
132
|
+
|
|
133
|
+
export const RuntimeControlCacheInvalidateResponseEffectSchema = Schema.Struct({
|
|
134
|
+
ok: Schema.Boolean,
|
|
135
|
+
invalidated: Schema.Number,
|
|
136
|
+
}).annotations({ identifier: "CacheInvalidateResponse" });
|
|
137
|
+
|
|
102
138
|
export const RuntimeControlRunEffectSchema = Schema.Struct({
|
|
103
139
|
runId: Schema.String,
|
|
104
140
|
operation: Schema.String,
|
|
@@ -157,6 +193,12 @@ export type RuntimeControlWorkflowsResponse = Schema.Schema.Type<typeof RuntimeC
|
|
|
157
193
|
export type RuntimeControlWorkspace = Schema.Schema.Type<typeof RuntimeControlWorkspaceEffectSchema>;
|
|
158
194
|
export type RuntimeControlWorkspacesResponse = Schema.Schema.Type<typeof RuntimeControlWorkspacesResponseEffectSchema>;
|
|
159
195
|
export type RuntimeControlSnapshotsResponse = Schema.Schema.Type<typeof RuntimeControlSnapshotsResponseEffectSchema>;
|
|
196
|
+
export type RuntimeControlCacheEntry = Schema.Schema.Type<typeof RuntimeControlCacheEntryEffectSchema>;
|
|
197
|
+
export type RuntimeControlCacheResponse = Schema.Schema.Type<typeof RuntimeControlCacheResponseEffectSchema>;
|
|
198
|
+
export type RuntimeControlCacheClearRequest = Schema.Schema.Type<typeof RuntimeControlCacheClearRequestEffectSchema>;
|
|
199
|
+
export type RuntimeControlCacheClearResponse = Schema.Schema.Type<typeof RuntimeControlCacheClearResponseEffectSchema>;
|
|
200
|
+
export type RuntimeControlCacheInvalidateRequest = Schema.Schema.Type<typeof RuntimeControlCacheInvalidateRequestEffectSchema>;
|
|
201
|
+
export type RuntimeControlCacheInvalidateResponse = Schema.Schema.Type<typeof RuntimeControlCacheInvalidateResponseEffectSchema>;
|
|
160
202
|
export type RuntimeControlRunOperationRequest = Schema.Schema.Type<typeof RuntimeControlRunOperationRequestEffectSchema>;
|
|
161
203
|
export type RuntimeControlRun = Schema.Schema.Type<typeof RuntimeControlRunEffectSchema>;
|
|
162
204
|
export type RuntimeControlRunsResponse = Schema.Schema.Type<typeof RuntimeControlRunsResponseEffectSchema>;
|
|
@@ -180,6 +222,13 @@ export const runtimeControlApi = HttpApi.make("rigkit-runtime")
|
|
|
180
222
|
.add(HttpApiEndpoint.get("workflows", "/workflows").addSuccess(RuntimeControlWorkflowsResponseEffectSchema))
|
|
181
223
|
.add(HttpApiEndpoint.get("workspaces", "/workspaces").addSuccess(RuntimeControlWorkspacesResponseEffectSchema))
|
|
182
224
|
.add(HttpApiEndpoint.get("snapshots", "/snapshots").addSuccess(RuntimeControlSnapshotsResponseEffectSchema))
|
|
225
|
+
.add(HttpApiEndpoint.get("cache", "/cache").addSuccess(RuntimeControlCacheResponseEffectSchema))
|
|
226
|
+
.add(HttpApiEndpoint.post("clearCache", "/cache/clear")
|
|
227
|
+
.setPayload(RuntimeControlCacheClearRequestEffectSchema)
|
|
228
|
+
.addSuccess(RuntimeControlCacheClearResponseEffectSchema))
|
|
229
|
+
.add(HttpApiEndpoint.post("invalidateCache", "/cache/invalidate")
|
|
230
|
+
.setPayload(RuntimeControlCacheInvalidateRequestEffectSchema)
|
|
231
|
+
.addSuccess(RuntimeControlCacheInvalidateResponseEffectSchema))
|
|
183
232
|
.add(HttpApiEndpoint.get("runs", "/runs").addSuccess(RuntimeControlRunsResponseEffectSchema))
|
|
184
233
|
.add(HttpApiEndpoint.post("startRun", "/runs")
|
|
185
234
|
.setPayload(RuntimeControlRunOperationRequestEffectSchema)
|
package/src/client.ts
CHANGED
|
@@ -22,6 +22,11 @@ import {
|
|
|
22
22
|
runtimeControlApi,
|
|
23
23
|
type RuntimeControlHealth,
|
|
24
24
|
type RuntimeControlHostResponse,
|
|
25
|
+
type RuntimeControlCacheClearRequest,
|
|
26
|
+
type RuntimeControlCacheClearResponse,
|
|
27
|
+
type RuntimeControlCacheInvalidateRequest,
|
|
28
|
+
type RuntimeControlCacheInvalidateResponse,
|
|
29
|
+
type RuntimeControlCacheResponse,
|
|
25
30
|
type RuntimeControlMetadata,
|
|
26
31
|
type RuntimeControlOkResponse,
|
|
27
32
|
type RuntimeControlOperationsManifest,
|
|
@@ -49,6 +54,9 @@ export type RuntimeHttpClient = {
|
|
|
49
54
|
workflows(): Promise<RuntimeControlWorkflowsResponse>;
|
|
50
55
|
workspaces(): Promise<RuntimeControlWorkspacesResponse>;
|
|
51
56
|
snapshots(): Promise<RuntimeControlSnapshotsResponse>;
|
|
57
|
+
cache(): Promise<RuntimeControlCacheResponse>;
|
|
58
|
+
clearCache(body: RuntimeControlCacheClearRequest): Promise<RuntimeControlCacheClearResponse>;
|
|
59
|
+
invalidateCache(body: RuntimeControlCacheInvalidateRequest): Promise<RuntimeControlCacheInvalidateResponse>;
|
|
52
60
|
runs(): Promise<RuntimeControlRunsResponse>;
|
|
53
61
|
startRun(body: RuntimeControlRunOperationRequest): Promise<RuntimeControlRunStarted>;
|
|
54
62
|
run(runId: string): Promise<RuntimeControlRun>;
|
|
@@ -125,6 +133,21 @@ function makeRuntimeHttpClient(options: RuntimeHttpClientOptions): RuntimeHttpCl
|
|
|
125
133
|
method: "GET",
|
|
126
134
|
path: "/snapshots",
|
|
127
135
|
}),
|
|
136
|
+
cache: () =>
|
|
137
|
+
runRuntimeHttpRequest(withRuntimeControlClient(options, (client) => client.cache({ withResponse: true })), {
|
|
138
|
+
method: "GET",
|
|
139
|
+
path: "/cache",
|
|
140
|
+
}),
|
|
141
|
+
clearCache: (body) =>
|
|
142
|
+
runRuntimeHttpRequest(
|
|
143
|
+
withRuntimeControlClient(options, (client) => client.clearCache({ payload: body, withResponse: true })),
|
|
144
|
+
{ method: "POST", path: "/cache/clear" },
|
|
145
|
+
),
|
|
146
|
+
invalidateCache: (body) =>
|
|
147
|
+
runRuntimeHttpRequest(
|
|
148
|
+
withRuntimeControlClient(options, (client) => client.invalidateCache({ payload: body, withResponse: true })),
|
|
149
|
+
{ method: "POST", path: "/cache/invalidate" },
|
|
150
|
+
),
|
|
128
151
|
runs: () =>
|
|
129
152
|
runRuntimeHttpRequest(withRuntimeControlClient(options, (client) => client.runs({ withResponse: true })), {
|
|
130
153
|
method: "GET",
|
package/src/index.ts
CHANGED
|
@@ -31,6 +31,10 @@ export {
|
|
|
31
31
|
RuntimeControlOperationCliEffectSchema,
|
|
32
32
|
RuntimeControlOperationEffectSchema,
|
|
33
33
|
RuntimeControlOperationsManifestEffectSchema,
|
|
34
|
+
RuntimeControlCacheEntryEffectSchema,
|
|
35
|
+
RuntimeControlCacheResponseEffectSchema,
|
|
36
|
+
RuntimeControlCacheClearRequestEffectSchema,
|
|
37
|
+
RuntimeControlCacheClearResponseEffectSchema,
|
|
34
38
|
RuntimeControlProjectInfoEffectSchema,
|
|
35
39
|
RuntimeControlRunEffectSchema,
|
|
36
40
|
RuntimeControlRunOperationRequestEffectSchema,
|
|
@@ -49,6 +53,10 @@ export {
|
|
|
49
53
|
type RuntimeControlOperation,
|
|
50
54
|
type RuntimeControlOperationCli,
|
|
51
55
|
type RuntimeControlOperationsManifest,
|
|
56
|
+
type RuntimeControlCacheEntry,
|
|
57
|
+
type RuntimeControlCacheResponse,
|
|
58
|
+
type RuntimeControlCacheClearRequest,
|
|
59
|
+
type RuntimeControlCacheClearResponse,
|
|
52
60
|
type RuntimeControlProjectInfo,
|
|
53
61
|
type RuntimeControlRun,
|
|
54
62
|
type RuntimeControlRunOperationRequest,
|
package/src/manager.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { spawn, type ChildProcessByStdio } from "node:child_process";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
@@ -34,6 +34,7 @@ export type RuntimeProjectOptions = {
|
|
|
34
34
|
projectDir: string;
|
|
35
35
|
configPath: string;
|
|
36
36
|
statePath?: string;
|
|
37
|
+
globalFragmentRoot?: string;
|
|
37
38
|
source?: unknown;
|
|
38
39
|
};
|
|
39
40
|
|
|
@@ -67,6 +68,9 @@ export type RuntimePaths = {
|
|
|
67
68
|
handlePath: string;
|
|
68
69
|
tokenPath: string;
|
|
69
70
|
lockPath: string;
|
|
71
|
+
// Where the daemon's stderr is captured. The CLI tails this on run failure
|
|
72
|
+
// so users see real stack traces instead of "Internal server error".
|
|
73
|
+
runtimeLogPath: string;
|
|
70
74
|
};
|
|
71
75
|
|
|
72
76
|
const DEFAULT_IDLE_MS = 30 * 60 * 1000;
|
|
@@ -87,6 +91,9 @@ async function getOrStartRuntimeUnsafe(options: GetOrStartRuntimeOptions): Promi
|
|
|
87
91
|
const projectDir = resolve(options.projectDir);
|
|
88
92
|
const configPath = resolve(options.configPath);
|
|
89
93
|
const statePath = options.statePath ? resolve(options.statePath) : undefined;
|
|
94
|
+
const globalFragmentRoot = options.globalFragmentRoot
|
|
95
|
+
? resolve(options.globalFragmentRoot)
|
|
96
|
+
: join(options.rigkitHome ?? defaultRigkitHome(), "fragments");
|
|
90
97
|
const projectId = projectIdFor({
|
|
91
98
|
projectDir,
|
|
92
99
|
configPath,
|
|
@@ -97,6 +104,7 @@ async function getOrStartRuntimeUnsafe(options: GetOrStartRuntimeOptions): Promi
|
|
|
97
104
|
projectDir,
|
|
98
105
|
configPath,
|
|
99
106
|
statePath,
|
|
107
|
+
...(options.globalFragmentRoot ? { globalFragmentRoot } : {}),
|
|
100
108
|
source: options.source,
|
|
101
109
|
});
|
|
102
110
|
const paths = runtimePaths(projectId, options.rigkitHome);
|
|
@@ -112,6 +120,7 @@ async function getOrStartRuntimeUnsafe(options: GetOrStartRuntimeOptions): Promi
|
|
|
112
120
|
projectDir,
|
|
113
121
|
configPath,
|
|
114
122
|
statePath,
|
|
123
|
+
globalFragmentRoot,
|
|
115
124
|
projectId,
|
|
116
125
|
runtimeFingerprint,
|
|
117
126
|
paths,
|
|
@@ -145,6 +154,7 @@ export function runtimeFingerprintFor(options: RuntimeProjectOptions): string {
|
|
|
145
154
|
const projectDir = resolve(options.projectDir);
|
|
146
155
|
const configPath = resolve(options.configPath);
|
|
147
156
|
const statePath = options.statePath ? resolve(options.statePath) : null;
|
|
157
|
+
const globalFragmentRoot = options.globalFragmentRoot ? resolve(options.globalFragmentRoot) : null;
|
|
148
158
|
const hash = createHash("sha256");
|
|
149
159
|
|
|
150
160
|
hash.update("project\0");
|
|
@@ -153,6 +163,8 @@ export function runtimeFingerprintFor(options: RuntimeProjectOptions): string {
|
|
|
153
163
|
hash.update(configPath);
|
|
154
164
|
hash.update("\0state\0");
|
|
155
165
|
hash.update(statePath ?? "");
|
|
166
|
+
hash.update("\0global-fragment-root\0");
|
|
167
|
+
hash.update(globalFragmentRoot ?? "");
|
|
156
168
|
hash.update("\0source\0");
|
|
157
169
|
hash.update(JSON.stringify(options.source ?? null));
|
|
158
170
|
|
|
@@ -172,6 +184,7 @@ export function runtimePaths(projectId: string, rigkitHome = defaultRigkitHome()
|
|
|
172
184
|
handlePath: join(root, `${projectId}.json`),
|
|
173
185
|
tokenPath: join(root, `${projectId}.token`),
|
|
174
186
|
lockPath: join(root, `${projectId}.lock`),
|
|
187
|
+
runtimeLogPath: join(root, `${projectId}.log`),
|
|
175
188
|
};
|
|
176
189
|
}
|
|
177
190
|
|
|
@@ -248,13 +261,22 @@ async function startRuntime(input: GetOrStartRuntimeOptions & {
|
|
|
248
261
|
String(input.idleMs ?? DEFAULT_IDLE_MS),
|
|
249
262
|
];
|
|
250
263
|
if (input.statePath) args.push("--state", input.statePath);
|
|
264
|
+
if (input.globalFragmentRoot) args.push("--global-fragment-root", input.globalFragmentRoot);
|
|
251
265
|
if (input.source !== undefined) args.push("--source-json", JSON.stringify(input.source));
|
|
252
266
|
|
|
267
|
+
mkdirSync(input.paths.root, { recursive: true });
|
|
268
|
+
const stderrFd = openSync(input.paths.runtimeLogPath, "a");
|
|
253
269
|
const proc = spawn(runtimeBin, args, {
|
|
254
270
|
detached: true,
|
|
255
|
-
stdio: ["ignore", "pipe",
|
|
271
|
+
stdio: ["ignore", "pipe", stderrFd],
|
|
256
272
|
env: process.env,
|
|
257
|
-
})
|
|
273
|
+
}) as ChildProcessByStdio<null, Readable, null>;
|
|
274
|
+
// The child inherits the fd; the parent can release its own handle.
|
|
275
|
+
try {
|
|
276
|
+
closeSync(stderrFd);
|
|
277
|
+
} catch {
|
|
278
|
+
// best-effort
|
|
279
|
+
}
|
|
258
280
|
|
|
259
281
|
const line = await readReadyLine(proc, input.paths, input.projectDir);
|
|
260
282
|
let ready: ReturnType<typeof RuntimeReadySchema.parse>;
|
|
@@ -535,16 +557,38 @@ function updateProjectSurfaceFingerprint(hash: ReturnType<typeof createHash>, pr
|
|
|
535
557
|
}
|
|
536
558
|
|
|
537
559
|
function updateRigkitPackageFingerprint(hash: ReturnType<typeof createHash>, scopeDir: string): void {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
560
|
+
// Walk every @rigkit scope reachable from the project's node_modules. We
|
|
561
|
+
// recurse into each package's own `node_modules/@rigkit` so that nested
|
|
562
|
+
// installs (e.g. @rigkit/engine living under @rigkit/sdk/node_modules) are
|
|
563
|
+
// hashed too. Without this, edits to a transitive @rigkit package wouldn't
|
|
564
|
+
// shift the runtime fingerprint and the daemon wouldn't auto-restart.
|
|
565
|
+
const visited = new Set<string>();
|
|
566
|
+
const stack: string[] = [scopeDir];
|
|
567
|
+
|
|
568
|
+
while (stack.length > 0) {
|
|
569
|
+
const dir = stack.pop()!;
|
|
570
|
+
if (!existsSync(dir)) continue;
|
|
571
|
+
let canonical: string;
|
|
572
|
+
try {
|
|
573
|
+
canonical = realpathSync(dir);
|
|
574
|
+
} catch {
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
if (visited.has(canonical)) continue;
|
|
578
|
+
visited.add(canonical);
|
|
579
|
+
|
|
580
|
+
const packageDirs = readdirSync(dir, { withFileTypes: true })
|
|
581
|
+
.filter((entry) => entry.isDirectory() || entry.isSymbolicLink())
|
|
582
|
+
.map((entry) => join(dir, entry.name))
|
|
583
|
+
.sort();
|
|
584
|
+
|
|
585
|
+
for (const packageDir of packageDirs) {
|
|
586
|
+
updateFileFingerprint(hash, "rigkit-package", join(packageDir, "package.json"));
|
|
587
|
+
for (const file of collectFiles(join(packageDir, "src"))) {
|
|
588
|
+
updateFileFingerprint(hash, "rigkit-source", file);
|
|
589
|
+
}
|
|
590
|
+
// Recurse into this package's own @rigkit scope, if it has nested deps.
|
|
591
|
+
stack.push(join(packageDir, "node_modules", "@rigkit"));
|
|
548
592
|
}
|
|
549
593
|
}
|
|
550
594
|
}
|
package/src/schemas.ts
CHANGED
|
@@ -42,6 +42,7 @@ export const RuntimeHandleEffectSchema = Schema.Struct({
|
|
|
42
42
|
projectDir: Schema.String,
|
|
43
43
|
configPath: Schema.String,
|
|
44
44
|
statePath: Schema.optional(Schema.String),
|
|
45
|
+
globalFragmentRoot: Schema.optional(Schema.String),
|
|
45
46
|
pid: Schema.Int,
|
|
46
47
|
url: Schema.String,
|
|
47
48
|
tokenPath: Schema.String,
|
|
@@ -64,6 +65,7 @@ export const RuntimeHealthEffectSchema = Schema.Struct({
|
|
|
64
65
|
projectDir: Schema.optional(Schema.String),
|
|
65
66
|
configPath: Schema.optional(Schema.String),
|
|
66
67
|
statePath: Schema.optional(Schema.String),
|
|
68
|
+
globalFragmentRoot: Schema.optional(Schema.String),
|
|
67
69
|
engineVersion: Schema.optional(Schema.String),
|
|
68
70
|
runtimeVersion: Schema.optional(Schema.String),
|
|
69
71
|
expiresAt: Schema.optional(Schema.String),
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const RIGKIT_RUNTIME_CLIENT_VERSION = "0.2.
|
|
1
|
+
export const RIGKIT_RUNTIME_CLIENT_VERSION = "0.2.8";
|