@ricsam/r5d-worker 0.0.161 → 0.0.163
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/dist/cjs/package.json +1 -1
- package/dist/mjs/internal-r5dctl.cjs +1 -1
- package/dist/mjs/main.mjs +2 -2
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/personal/client.mjs +2 -2
- package/dist/mjs/personal/publication-refusal.mjs +47 -0
- package/dist/mjs/personal/runtime.mjs +47 -46
- package/dist/mjs/runtime/workspace/authority.mjs +521 -76
- package/dist/mjs/runtime/workspace/files.mjs +44 -7
- package/dist/mjs/runtime/workspace/outer.mjs +286 -0
- package/dist/mjs/runtime/workspace/storage-wire.mjs +5 -2
- package/dist/types/personal/publication-refusal.d.ts +35 -0
- package/dist/types/personal/runtime.d.ts +3 -2
- package/dist/types/runtime/workspace/authority.d.ts +86 -4
- package/dist/types/runtime/workspace/contracts.d.ts +26 -0
- package/dist/types/runtime/workspace/files.d.ts +30 -1
- package/dist/types/runtime/workspace/outer.d.ts +105 -0
- package/dist/types/runtime/workspace/storage-wire.d.ts +2 -1
- package/package.json +2 -2
package/dist/cjs/package.json
CHANGED
|
@@ -20605,7 +20605,7 @@ function resolveEntrypointPath(entrypoint) {
|
|
|
20605
20605
|
}
|
|
20606
20606
|
}
|
|
20607
20607
|
function getR5dctlVersion() {
|
|
20608
|
-
if (true) return "0.0.
|
|
20608
|
+
if (true) return "0.0.163";
|
|
20609
20609
|
const entrypoint = process.argv[1] ? resolveEntrypointPath(process.argv[1]) : null;
|
|
20610
20610
|
let current = entrypoint ? import_node_path2.default.dirname(entrypoint) : process.cwd();
|
|
20611
20611
|
for (let index = 0; index < 12; index += 1) {
|
package/dist/mjs/main.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { startManagerRpc } from "./runtime/releases/rpc-main.mjs";
|
|
|
7
7
|
import { ManagerRpcConfig } from "./runtime/releases/rpc-protocol.mjs";
|
|
8
8
|
const args = process.argv.slice(2);
|
|
9
9
|
if (args.includes("--version")) {
|
|
10
|
-
console.log(`r5d-worker ${true ? "0.0.
|
|
10
|
+
console.log(`r5d-worker ${true ? "0.0.163" : "development"}`);
|
|
11
11
|
} else if (!args.length || args.includes("--help")) {
|
|
12
12
|
console.log(
|
|
13
13
|
"Usage: r5d-worker start --label <label> [--root <dir>] [--base-url <url>] [--token <worker-token>]\n r5d-worker executor /absolute/private/config.json\n r5d-worker manager /absolute/private/config.json\n\nRun independently supervised durable runtime services. Provision configuration with r5dinfra."
|
|
@@ -15,7 +15,7 @@ if (args.includes("--version")) {
|
|
|
15
15
|
} else if (args[0] === "start") {
|
|
16
16
|
const runtime = await startPersonalWorker(
|
|
17
17
|
parsePersonalWorkerOptions(args.slice(1)),
|
|
18
|
-
true ? "0.0.
|
|
18
|
+
true ? "0.0.163" : "development"
|
|
19
19
|
);
|
|
20
20
|
console.log(`Worker connected: ${runtime.resourceId}`);
|
|
21
21
|
let closing = false;
|
package/dist/mjs/package.json
CHANGED
|
@@ -103,7 +103,7 @@ async function startPersonalWorker(options, version) {
|
|
|
103
103
|
platform: process.platform,
|
|
104
104
|
arch: process.arch,
|
|
105
105
|
hostname: os.hostname(),
|
|
106
|
-
capabilities: { updateClis: true, durableWorkspace: true }
|
|
106
|
+
capabilities: { updateClis: true, durableWorkspace: true, outerWorkspace: true }
|
|
107
107
|
});
|
|
108
108
|
const grant = PersonalWorkerGrant.parse(
|
|
109
109
|
await request("/api/personal/resources/register", { kind: "worker", ...identity, label: options.label, metadata: metadata() })
|
|
@@ -116,7 +116,7 @@ async function startPersonalWorker(options, version) {
|
|
|
116
116
|
try {
|
|
117
117
|
const response = await request(`${endpoint}/storage`, {
|
|
118
118
|
instanceId: identity.instanceId,
|
|
119
|
-
request: { sessionId, envelope: { protocol: 1, installationId: grant.installationId, request: storageRequest } }
|
|
119
|
+
request: { ...sessionId === null ? { scope: "account" } : { sessionId }, envelope: { protocol: 1, installationId: grant.installationId, request: storageRequest } }
|
|
120
120
|
});
|
|
121
121
|
if (!response || !("result" in response)) throw new Error("Invalid scoped storage response");
|
|
122
122
|
return response.result;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const CONFLICT_PUBLICATION_CODES = /* @__PURE__ */ new Set([
|
|
2
|
+
"conflict",
|
|
3
|
+
"sync_conflict",
|
|
4
|
+
"workbench_conflict",
|
|
5
|
+
"workbench_operation_in_progress"
|
|
6
|
+
]);
|
|
7
|
+
const TRANSIENT_PUBLICATION_CODES = /* @__PURE__ */ new Set([
|
|
8
|
+
"not_initialized",
|
|
9
|
+
"apply_refused",
|
|
10
|
+
"mirror_advanced",
|
|
11
|
+
"authority_closed",
|
|
12
|
+
"busy"
|
|
13
|
+
]);
|
|
14
|
+
const BLOCKED_PUBLICATION_CODES = /* @__PURE__ */ new Set([
|
|
15
|
+
"secret_or_runtime_path",
|
|
16
|
+
"secret_content",
|
|
17
|
+
"unsafe_file",
|
|
18
|
+
"unsafe_git",
|
|
19
|
+
"unsafe_path",
|
|
20
|
+
"unsafe_tree",
|
|
21
|
+
"too_large"
|
|
22
|
+
]);
|
|
23
|
+
const PUBLICATION_OBSERVATION_THRESHOLDS = /* @__PURE__ */ new Map([["unsafe_file", 2]]);
|
|
24
|
+
const OPERATION_IN_PROGRESS_CODE = "workbench_operation_in_progress";
|
|
25
|
+
const ABANDONED_OPERATION_OBSERVATIONS = 2;
|
|
26
|
+
const STUCK_OPERATION_OBSERVATIONS = 30;
|
|
27
|
+
function publicationRefusalOutcome(code) {
|
|
28
|
+
if (CONFLICT_PUBLICATION_CODES.has(code)) return "conflict_blocked";
|
|
29
|
+
if (BLOCKED_PUBLICATION_CODES.has(code)) return "large_diff_blocked";
|
|
30
|
+
return "failed";
|
|
31
|
+
}
|
|
32
|
+
function publicationRefusalElects(code, observations, context = {}) {
|
|
33
|
+
if (code === OPERATION_IN_PROGRESS_CODE)
|
|
34
|
+
return context.workbenchHasLiveRun ? observations >= STUCK_OPERATION_OBSERVATIONS : observations >= ABANDONED_OPERATION_OBSERVATIONS;
|
|
35
|
+
return observations >= (PUBLICATION_OBSERVATION_THRESHOLDS.get(code) ?? 1);
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
ABANDONED_OPERATION_OBSERVATIONS,
|
|
39
|
+
BLOCKED_PUBLICATION_CODES,
|
|
40
|
+
CONFLICT_PUBLICATION_CODES,
|
|
41
|
+
OPERATION_IN_PROGRESS_CODE,
|
|
42
|
+
PUBLICATION_OBSERVATION_THRESHOLDS,
|
|
43
|
+
STUCK_OPERATION_OBSERVATIONS,
|
|
44
|
+
TRANSIENT_PUBLICATION_CODES,
|
|
45
|
+
publicationRefusalElects,
|
|
46
|
+
publicationRefusalOutcome
|
|
47
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { publicationRefusalElects, publicationRefusalOutcome, TRANSIENT_PUBLICATION_CODES } from "./publication-refusal.mjs";
|
|
2
3
|
import { PersonalTcpManager } from "./tcp.mjs";
|
|
3
4
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
4
5
|
import { promises as fs } from "node:fs";
|
|
@@ -11,6 +12,7 @@ import { EXECUTOR_CAPABILITY, ExecutorCredential } from "../runtime/protocol.mjs
|
|
|
11
12
|
import { privateDirectory, readPrivateJson } from "../runtime/storage.mjs";
|
|
12
13
|
import { WorkspaceAuthority } from "../runtime/workspace/authority.mjs";
|
|
13
14
|
import { ApprovedWorkbench, WorkspaceError } from "../runtime/workspace/contracts.mjs";
|
|
15
|
+
import { OuterSnapshotRefusal } from "../runtime/workspace/outer.mjs";
|
|
14
16
|
import { WorkspaceStorageClient } from "../runtime/workspace/storage-client.mjs";
|
|
15
17
|
import { BranchName, GitOid, StorageId } from "../runtime/workspace/storage-wire.mjs";
|
|
16
18
|
const PersonalWorkerGrant = z.object({
|
|
@@ -203,7 +205,11 @@ exec ${quote(executable)} ${quote(cli)} "$@"
|
|
|
203
205
|
config: { installationId: grant.installationId, root: authorityRoot, workspaceRoot, dynamicWorkbenches: true, workbenches: [] },
|
|
204
206
|
executor: async () => ({ client, workerFence: current.workerFence }),
|
|
205
207
|
resolveWorkbench: async (identity) => identity.userId === grant.userId ? manifests.get(routes.get(identity.sessionId) ?? "") ?? null : null,
|
|
206
|
-
storage: async (identity) => new WorkspaceStorageClient(grant.installationId, options.storage(identity.sessionId), async () => current.workerFence)
|
|
208
|
+
storage: async (identity) => new WorkspaceStorageClient(grant.installationId, options.storage(identity.sessionId), async () => current.workerFence),
|
|
209
|
+
accountStorage: async (userId) => {
|
|
210
|
+
if (userId !== grant.userId) throw new Error("Wrong personal worker principal");
|
|
211
|
+
return new WorkspaceStorageClient(grant.installationId, options.storage(null), async () => current.workerFence);
|
|
212
|
+
}
|
|
207
213
|
});
|
|
208
214
|
async function approve(input) {
|
|
209
215
|
const cwd = input.rootProfile === "account" ? workspaceRoot : input.namespace && input.projectName ? path.join(workspaceRoot, "projects", input.namespace, input.projectName, ...input.branch.split("/")) : path.join(workspaceRoot, "workbenches", input.id);
|
|
@@ -253,62 +259,46 @@ exec ${quote(executable)} ${quote(cli)} "$@"
|
|
|
253
259
|
}
|
|
254
260
|
}
|
|
255
261
|
}
|
|
256
|
-
const blockedPublicationCodes = /* @__PURE__ */ new Set([
|
|
257
|
-
"secret_or_runtime_path",
|
|
258
|
-
"secret_content",
|
|
259
|
-
"unsafe_file",
|
|
260
|
-
"unsafe_git",
|
|
261
|
-
"unsafe_path",
|
|
262
|
-
"unsafe_tree",
|
|
263
|
-
"too_large"
|
|
264
|
-
]);
|
|
265
|
-
const conflictPublicationCodes = /* @__PURE__ */ new Set(["conflict", "workbench_conflict"]);
|
|
266
262
|
const failedPublicationAttempts = /* @__PURE__ */ new Map();
|
|
267
263
|
let publication = null, closing = false;
|
|
268
264
|
const synchronize = () => {
|
|
269
265
|
if (publication) return publication;
|
|
270
266
|
const next = (async () => {
|
|
271
267
|
const results = [];
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
} else {
|
|
297
|
-
attempt.observations++;
|
|
298
|
-
}
|
|
299
|
-
if (code === "unsafe_file" && attempt.observations < 2) continue;
|
|
268
|
+
try {
|
|
269
|
+
const outer = await authority.synchronizeOuter(grant.userId);
|
|
270
|
+
failedPublicationAttempts.delete("workspace");
|
|
271
|
+
results.push({ workbenchId: "workspace", ...outer });
|
|
272
|
+
} catch (error) {
|
|
273
|
+
const code = error instanceof WorkspaceError ? error.code : "publication_failed";
|
|
274
|
+
results.push({ workbenchId: "workspace", error: code });
|
|
275
|
+
if (!TRANSIENT_PUBLICATION_CODES.has(code) && options.publicationReport) {
|
|
276
|
+
let startingHead = null;
|
|
277
|
+
try {
|
|
278
|
+
startingHead = (await authority.outerStatus(grant.userId)).publishedHead;
|
|
279
|
+
} catch {
|
|
280
|
+
}
|
|
281
|
+
const outcome = publicationRefusalOutcome(code);
|
|
282
|
+
const paths = error instanceof OuterSnapshotRefusal ? error.paths : [];
|
|
283
|
+
const fingerprint = canonicalJson({ code, startingHead, outcome, paths });
|
|
284
|
+
let attempt = failedPublicationAttempts.get("workspace");
|
|
285
|
+
if (!attempt || attempt.fingerprint !== fingerprint) {
|
|
286
|
+
attempt = { fingerprint, attemptId: randomUUID(), observations: 1 };
|
|
287
|
+
failedPublicationAttempts.set("workspace", attempt);
|
|
288
|
+
} else {
|
|
289
|
+
attempt.observations++;
|
|
290
|
+
}
|
|
291
|
+
if (publicationRefusalElects(code, attempt.observations)) {
|
|
300
292
|
try {
|
|
301
293
|
await options.publicationReport(WorkspacePublicationReport.parse({
|
|
302
294
|
protocol: 1,
|
|
303
295
|
attemptId: attempt.attemptId,
|
|
304
|
-
|
|
305
|
-
workbenchId,
|
|
306
|
-
repositoryId: manifest.repositoryId,
|
|
307
|
-
branch: manifest.branch,
|
|
296
|
+
scope: "workspace",
|
|
308
297
|
outcome,
|
|
309
298
|
startingHead,
|
|
310
299
|
diffSizeBytes: outcome === "large_diff_blocked" && code === "too_large" ? 5 * 1024 * 1024 + 1 : 0,
|
|
311
|
-
error: code
|
|
300
|
+
error: code,
|
|
301
|
+
...paths.length ? { paths } : {}
|
|
312
302
|
}));
|
|
313
303
|
} catch (reportError) {
|
|
314
304
|
process.stderr.write(`[r5d-worker] publication report deferred: ${reportError instanceof WorkspaceError ? reportError.code : "publication_report_failed"}
|
|
@@ -317,13 +307,24 @@ exec ${quote(executable)} ${quote(cli)} "$@"
|
|
|
317
307
|
}
|
|
318
308
|
}
|
|
319
309
|
}
|
|
310
|
+
for (const [workbenchId, sessionId] of publicationSessions) {
|
|
311
|
+
if (closing) break;
|
|
312
|
+
const manifest = manifests.get(workbenchId);
|
|
313
|
+
if (!manifest || manifest.rootProfile !== "project") continue;
|
|
314
|
+
try {
|
|
315
|
+
results.push({ workbenchId, ...await authority.mirror({ userId: grant.userId, sessionId }) });
|
|
316
|
+
} catch (error) {
|
|
317
|
+
results.push({ workbenchId, error: error instanceof WorkspaceError ? error.code : "mirror_failed" });
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
320
|
return results;
|
|
321
321
|
})();
|
|
322
322
|
publication = next;
|
|
323
323
|
void next.then(
|
|
324
324
|
(results) => {
|
|
325
|
-
|
|
326
|
-
|
|
325
|
+
const deferred = results.filter((result) => result.error && !TRANSIENT_PUBLICATION_CODES.has(result.error));
|
|
326
|
+
if (deferred.length)
|
|
327
|
+
process.stderr.write(`[r5d-worker] periodic workspace publication deferred: ${deferred.map((result) => `${result.workbenchId}:${result.error}`).join(", ")}
|
|
327
328
|
`);
|
|
328
329
|
if (publication === next) publication = null;
|
|
329
330
|
},
|