@indigoai-us/hq-cloud 6.15.2 → 6.15.3
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/bin/sync-mutation.d.ts +1 -3
- package/dist/bin/sync-mutation.d.ts.map +1 -1
- package/dist/bin/sync-mutation.js +5 -5
- package/dist/bin/sync-mutation.js.map +1 -1
- package/dist/bin/sync-mutation.test.js +36 -137
- package/dist/bin/sync-mutation.test.js.map +1 -1
- package/dist/cli/sync.d.ts +7 -6
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +21 -37
- package/dist/cli/sync.js.map +1 -1
- package/dist/cli/sync.test.js +27 -47
- package/dist/cli/sync.test.js.map +1 -1
- package/dist/sync/base-version-resolver.d.ts +11 -0
- package/dist/sync/base-version-resolver.d.ts.map +1 -0
- package/dist/sync/base-version-resolver.js +48 -0
- package/dist/sync/base-version-resolver.js.map +1 -0
- package/dist/sync/base-version-resolver.test.d.ts +2 -0
- package/dist/sync/base-version-resolver.test.d.ts.map +1 -0
- package/dist/sync/base-version-resolver.test.js +24 -0
- package/dist/sync/base-version-resolver.test.js.map +1 -0
- package/dist/sync/lease-client.d.ts +17 -0
- package/dist/sync/lease-client.d.ts.map +1 -1
- package/dist/sync/lease-client.js +46 -1
- package/dist/sync/lease-client.js.map +1 -1
- package/dist/sync/mutation-client.d.ts +2 -0
- package/dist/sync/mutation-client.d.ts.map +1 -1
- package/dist/sync/mutation-client.js +2 -0
- package/dist/sync/mutation-client.js.map +1 -1
- package/dist/sync/mutation-session.d.ts +49 -0
- package/dist/sync/mutation-session.d.ts.map +1 -0
- package/dist/sync/mutation-session.js +282 -0
- package/dist/sync/mutation-session.js.map +1 -0
- package/dist/sync/mutation-session.test.d.ts +2 -0
- package/dist/sync/mutation-session.test.d.ts.map +1 -0
- package/dist/sync/mutation-session.test.js +190 -0
- package/dist/sync/mutation-session.test.js.map +1 -0
- package/dist/sync/uploader-finalization.d.ts +20 -0
- package/dist/sync/uploader-finalization.d.ts.map +1 -1
- package/dist/sync/uploader-finalization.js +48 -0
- package/dist/sync/uploader-finalization.js.map +1 -1
- package/dist/sync/uploader-finalization.test.js +15 -0
- package/dist/sync/uploader-finalization.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -7,9 +7,7 @@ export interface SyncMutationCliDeps {
|
|
|
7
7
|
stdin?: AsyncIterable<unknown>;
|
|
8
8
|
stdout?: TextWriter;
|
|
9
9
|
stderr?: TextWriter;
|
|
10
|
-
createClient?: (
|
|
11
|
-
/** Test-only override; production uses the private OS temp spool directory. */
|
|
12
|
-
spoolDirectory?: string;
|
|
10
|
+
createClient?: () => SyncMutationStdinClient;
|
|
13
11
|
}
|
|
14
12
|
/** Run the one-request V2 sidecar protocol without calling process.exit. */
|
|
15
13
|
export declare function runSyncMutationCli(argv: readonly string[], deps?: SyncMutationCliDeps): Promise<number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-mutation.d.ts","sourceRoot":"","sources":["../../src/bin/sync-mutation.ts"],"names":[],"mappings":";AAYA,OAAO,
|
|
1
|
+
{"version":3,"file":"sync-mutation.d.ts","sourceRoot":"","sources":["../../src/bin/sync-mutation.ts"],"names":[],"mappings":";AAYA,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,gBAAgB,CAAC;AAOxB,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,uBAAuB,CAAC;CAC9C;AAUD,4EAA4E;AAC5E,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,IAAI,GAAE,mBAAwB,GAC7B,OAAO,CAAC,MAAM,CAAC,CAuBjB"}
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import * as fs from "node:fs";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
|
-
import {
|
|
13
|
-
|
|
12
|
+
import { isSyncMutationStdinCommand, runSyncMutationStdinJson, } from "../cli/sync.js";
|
|
13
|
+
import { LocalEnrolledMutationSession, SyncMutationNotEnrolledError, SYNC_MUTATION_NOT_ENROLLED_EXIT, } from "../sync/mutation-session.js";
|
|
14
14
|
async function readStdin(stdin) {
|
|
15
15
|
const chunks = [];
|
|
16
16
|
for await (const chunk of stdin) {
|
|
@@ -23,20 +23,20 @@ export async function runSyncMutationCli(argv, deps = {}) {
|
|
|
23
23
|
const stdin = deps.stdin ?? process.stdin;
|
|
24
24
|
const stdout = deps.stdout ?? process.stdout;
|
|
25
25
|
const stderr = deps.stderr ?? process.stderr;
|
|
26
|
-
const createClient = deps.createClient ?? ((
|
|
26
|
+
const createClient = deps.createClient ?? (() => new LocalEnrolledMutationSession());
|
|
27
27
|
if (!isSyncMutationStdinCommand(argv)) {
|
|
28
28
|
stderr.write("usage: hq-cloud sync mutation --stdin-json\n");
|
|
29
29
|
return 2;
|
|
30
30
|
}
|
|
31
31
|
try {
|
|
32
|
-
const output = await runSyncMutationStdinJson(await readStdin(stdin), createClient(
|
|
32
|
+
const output = await runSyncMutationStdinJson(await readStdin(stdin), createClient());
|
|
33
33
|
stdout.write(output);
|
|
34
34
|
return 0;
|
|
35
35
|
}
|
|
36
36
|
catch (error) {
|
|
37
37
|
const message = error instanceof Error ? error.message : String(error);
|
|
38
38
|
stderr.write("hq-cloud sync mutation: " + message + "\n");
|
|
39
|
-
return 1;
|
|
39
|
+
return error instanceof SyncMutationNotEnrolledError ? SYNC_MUTATION_NOT_ENROLLED_EXIT : 1;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
const isDirectInvocation = (() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-mutation.js","sourceRoot":"","sources":["../../src/bin/sync-mutation.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"sync-mutation.js","sourceRoot":"","sources":["../../src/bin/sync-mutation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,165 +1,64 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import * as fs from "node:fs";
|
|
3
|
-
import * as os from "node:os";
|
|
4
|
-
import * as path from "node:path";
|
|
5
1
|
import { Readable } from "node:stream";
|
|
6
2
|
import { describe, expect, it, vi } from "vitest";
|
|
7
3
|
import { runSyncMutationCli } from "./sync-mutation.js";
|
|
8
|
-
import {
|
|
9
|
-
import { MutationClient } from "../sync/mutation-client.js";
|
|
4
|
+
import { SyncMutationNotEnrolledError, SYNC_MUTATION_NOT_ENROLLED_EXIT, } from "../sync/mutation-session.js";
|
|
10
5
|
function writer() {
|
|
11
6
|
let output = "";
|
|
12
|
-
return {
|
|
13
|
-
write(chunk) {
|
|
14
|
-
output += chunk;
|
|
15
|
-
},
|
|
16
|
-
text: () => output,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
function response(status, body) {
|
|
20
|
-
return {
|
|
21
|
-
ok: status >= 200 && status < 300,
|
|
22
|
-
status,
|
|
23
|
-
headers: { get: () => null },
|
|
24
|
-
body: null,
|
|
25
|
-
text: async () => JSON.stringify(body),
|
|
26
|
-
};
|
|
7
|
+
return { write(chunk) { output += chunk; }, text: () => output };
|
|
27
8
|
}
|
|
9
|
+
const committed = {
|
|
10
|
+
requestDigest: "digest_1",
|
|
11
|
+
status: { status: "committed", attemptId: "attempt_1", versionId: "version_1", deltaId: "delta_1" },
|
|
12
|
+
};
|
|
28
13
|
describe("hq-cloud sync mutation --stdin-json", () => {
|
|
29
|
-
it("
|
|
14
|
+
it("passes the complete upsert envelope as one local change", async () => {
|
|
30
15
|
const stdout = writer();
|
|
31
16
|
const stderr = writer();
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
17
|
+
const submit = vi.fn().mockResolvedValue(committed);
|
|
18
|
+
const request = JSON.stringify({ canonicalPath: "notes/a.md", op: "upsert", contentBase64: Buffer.from("hello").toString("base64") });
|
|
19
|
+
const code = await runSyncMutationCli(["sync", "mutation", "--stdin-json"], {
|
|
20
|
+
stdin: Readable.from([request.slice(0, 9), request.slice(9)]), stdout, stderr,
|
|
21
|
+
createClient: () => ({ submit }),
|
|
37
22
|
});
|
|
23
|
+
expect(code).toBe(0);
|
|
24
|
+
expect(stderr.text()).toBe("");
|
|
25
|
+
expect(submit).toHaveBeenCalledWith({ canonicalPath: "notes/a.md", op: "upsert", bytes: Uint8Array.from(Buffer.from("hello")) });
|
|
26
|
+
expect(JSON.parse(stdout.text())).toMatchObject({ contractVersion: 2, action: "submit", requestDigest: "digest_1" });
|
|
27
|
+
});
|
|
28
|
+
it("passes deletes without bytes", async () => {
|
|
29
|
+
const stdout = writer();
|
|
30
|
+
const stderr = writer();
|
|
31
|
+
const submit = vi.fn().mockResolvedValue({ ...committed, requestDigest: "digest_delete" });
|
|
38
32
|
const code = await runSyncMutationCli(["sync", "mutation", "--stdin-json"], {
|
|
39
|
-
stdin: Readable.from([JSON.stringify({
|
|
40
|
-
|
|
41
|
-
action: "recover",
|
|
42
|
-
authorization: { bearer: "token", deviceId: "device_a", capabilityVector: {}, lease: {} },
|
|
43
|
-
attemptId: "attempt_1",
|
|
44
|
-
})]),
|
|
45
|
-
stdout,
|
|
46
|
-
stderr,
|
|
47
|
-
createClient: () => ({ submit: vi.fn(), recover }),
|
|
33
|
+
stdin: Readable.from([JSON.stringify({ canonicalPath: "notes/a.md", op: "delete" })]), stdout, stderr,
|
|
34
|
+
createClient: () => ({ submit }),
|
|
48
35
|
});
|
|
49
36
|
expect(code).toBe(0);
|
|
50
|
-
expect(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
},
|
|
37
|
+
expect(submit).toHaveBeenCalledWith({ canonicalPath: "notes/a.md", op: "delete" });
|
|
38
|
+
});
|
|
39
|
+
it("uses the documented closed exit when local enrollment or the rollout flag is unavailable", async () => {
|
|
40
|
+
const stdout = writer();
|
|
41
|
+
const stderr = writer();
|
|
42
|
+
const submit = vi.fn().mockRejectedValue(new SyncMutationNotEnrolledError());
|
|
43
|
+
const code = await runSyncMutationCli(["sync", "mutation", "--stdin-json"], {
|
|
44
|
+
stdin: Readable.from([JSON.stringify({ canonicalPath: "notes/a.md", op: "delete" })]), stdout, stderr,
|
|
45
|
+
createClient: () => ({ submit }),
|
|
59
46
|
});
|
|
60
|
-
expect(
|
|
61
|
-
expect(
|
|
47
|
+
expect(code).toBe(SYNC_MUTATION_NOT_ENROLLED_EXIT);
|
|
48
|
+
expect(stdout.text()).toBe("");
|
|
49
|
+
expect(stderr.text()).toContain("not enrolled for realtime V2 mutations");
|
|
62
50
|
});
|
|
63
51
|
it("rejects an invalid command without consuming stdin", async () => {
|
|
64
52
|
const stdout = writer();
|
|
65
53
|
const stderr = writer();
|
|
66
54
|
const createClient = vi.fn();
|
|
67
55
|
const code = await runSyncMutationCli(["sync", "mutation"], {
|
|
68
|
-
stdin: Readable.from(["must not be read"]),
|
|
69
|
-
stdout,
|
|
70
|
-
stderr,
|
|
71
|
-
createClient,
|
|
56
|
+
stdin: Readable.from(["must not be read"]), stdout, stderr, createClient,
|
|
72
57
|
});
|
|
73
58
|
expect(code).toBe(2);
|
|
74
59
|
expect(stdout.text()).toBe("");
|
|
75
60
|
expect(stderr.text()).toBe("usage: hq-cloud sync mutation --stdin-json\n");
|
|
76
61
|
expect(createClient).not.toHaveBeenCalled();
|
|
77
62
|
});
|
|
78
|
-
it("fails malformed contentBase64 cleanly before submitting", async () => {
|
|
79
|
-
const stdout = writer();
|
|
80
|
-
const stderr = writer();
|
|
81
|
-
const submit = vi.fn();
|
|
82
|
-
const code = await runSyncMutationCli(["sync", "mutation", "--stdin-json"], {
|
|
83
|
-
stdin: Readable.from([JSON.stringify({
|
|
84
|
-
contractVersion: 2,
|
|
85
|
-
action: "submit",
|
|
86
|
-
input: { authorization: {}, request: { operation: "upsert" } },
|
|
87
|
-
contentBase64: "not base64!",
|
|
88
|
-
})]),
|
|
89
|
-
stdout,
|
|
90
|
-
stderr,
|
|
91
|
-
createClient: () => ({ submit, recover: vi.fn() }),
|
|
92
|
-
});
|
|
93
|
-
expect(code).toBe(1);
|
|
94
|
-
expect(stdout.text()).toBe("");
|
|
95
|
-
expect(stderr.text()).toBe("hq-cloud sync mutation: sync mutation: contentBase64 must be valid base64\n");
|
|
96
|
-
expect(submit).not.toHaveBeenCalled();
|
|
97
|
-
});
|
|
98
|
-
it("consumes the complete stdin envelope and spools a multipart upsert after prepare", async () => {
|
|
99
|
-
const bytes = Buffer.alloc(MAX_SMALL_CANDIDATE_BYTES + 1, 0xab);
|
|
100
|
-
const attemptId = `attempt_large_${process.pid}_${Date.now()}`;
|
|
101
|
-
const spoolDirectory = fs.mkdtempSync(path.join(os.tmpdir(), "hq-cloud-sync-cli-"));
|
|
102
|
-
const fetchImpl = vi.fn()
|
|
103
|
-
.mockResolvedValueOnce(response(201, { status: "prepared", attemptId }))
|
|
104
|
-
.mockResolvedValueOnce(response(202, { status: "committed", attemptId, versionId: "version_large", deltaId: "delta_large" }));
|
|
105
|
-
let spoolPath;
|
|
106
|
-
const client = new MutationClient({
|
|
107
|
-
apiUrl: "https://api.example.test",
|
|
108
|
-
fetchImpl,
|
|
109
|
-
now: () => Date.parse("2026-08-14T00:00:00.000Z"),
|
|
110
|
-
candidateUploader: { uploadSmall: vi.fn() },
|
|
111
|
-
multipartUploader: {
|
|
112
|
-
upload: async ({ spool }) => {
|
|
113
|
-
spoolPath = spool.filePath;
|
|
114
|
-
expect(spool.size).toBe(bytes.byteLength);
|
|
115
|
-
expect(createHash("sha256").update(spool.readPart(1)).digest("hex")).toBe(createHash("sha256").update(bytes.subarray(0, 8 * 1024 * 1024)).digest("hex"));
|
|
116
|
-
return { status: "candidate-ready", attemptId, candidateVersionId: "candidate_large" };
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
const request = JSON.stringify({
|
|
121
|
-
contractVersion: 2,
|
|
122
|
-
action: "submit",
|
|
123
|
-
input: {
|
|
124
|
-
authorization: {
|
|
125
|
-
bearer: "token",
|
|
126
|
-
deviceId: "device_a",
|
|
127
|
-
capabilityVector: { hqCloud: "6.15.2", hqDesktop: "1.0.0", protocol: 2, journal: 3, durableApply: 2 },
|
|
128
|
-
lease: { lease: "lease_1", issuedAt: "2026-08-14T00:00:00.000Z", expiresAt: "2026-08-14T00:01:00.000Z", authorizationEpoch: "epoch_1" },
|
|
129
|
-
},
|
|
130
|
-
request: {
|
|
131
|
-
contractVersion: 2,
|
|
132
|
-
deviceId: "device_a",
|
|
133
|
-
clientMutationId: "mutation_large",
|
|
134
|
-
canonicalPath: "notes/large.bin",
|
|
135
|
-
operation: "upsert",
|
|
136
|
-
baseVersionId: null,
|
|
137
|
-
generation: 1,
|
|
138
|
-
membershipRevision: "member_1",
|
|
139
|
-
scopeRevision: "scope_1",
|
|
140
|
-
source: { kind: "regular", mode: 0o600, sha256: `sha256:${createHash("sha256").update(bytes).digest("hex")}`, size: bytes.byteLength },
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
contentBase64: bytes.toString("base64"),
|
|
144
|
-
});
|
|
145
|
-
try {
|
|
146
|
-
const stdout = writer();
|
|
147
|
-
const stderr = writer();
|
|
148
|
-
const code = await runSyncMutationCli(["sync", "mutation", "--stdin-json"], {
|
|
149
|
-
stdin: Readable.from([request.slice(0, 17), request.slice(17, -29), request.slice(-29)]),
|
|
150
|
-
stdout,
|
|
151
|
-
stderr,
|
|
152
|
-
createClient: () => client,
|
|
153
|
-
spoolDirectory,
|
|
154
|
-
});
|
|
155
|
-
expect(code, stderr.text()).toBe(0);
|
|
156
|
-
expect(JSON.parse(stdout.text())).toMatchObject({ action: "submit", status: { status: "committed", attemptId, versionId: "version_large" } });
|
|
157
|
-
expect(spoolPath).toBeDefined();
|
|
158
|
-
expect(fs.existsSync(spoolPath)).toBe(false);
|
|
159
|
-
}
|
|
160
|
-
finally {
|
|
161
|
-
fs.rmSync(spoolDirectory, { recursive: true, force: true });
|
|
162
|
-
}
|
|
163
|
-
}, 120_000);
|
|
164
63
|
});
|
|
165
64
|
//# sourceMappingURL=sync-mutation.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-mutation.test.js","sourceRoot":"","sources":["../../src/bin/sync-mutation.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"sync-mutation.test.js","sourceRoot":"","sources":["../../src/bin/sync-mutation.test.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/sync.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { type SyncMode } from "../vault-client.js";
|
|
|
9
9
|
import { type TelemetryClaims } from "../telemetry-events.js";
|
|
10
10
|
import { type ScopePrefixInput } from "../prefix-coalesce.js";
|
|
11
11
|
import type { ConflictStrategy, ConflictResolution } from "./conflict.js";
|
|
12
|
-
import { MutationClient, type MutationStatus
|
|
12
|
+
import { MutationClient, type MutationStatus } from "../sync/mutation-client.js";
|
|
13
13
|
import { DurableApplyEngine, type DurableApplyContent } from "../sync/durable-apply.js";
|
|
14
14
|
import type { DeltaPage, DeltaRecord } from "../sync/delta-client.js";
|
|
15
15
|
/** The desktop sidecar invokes exactly `hq-cloud sync mutation --stdin-json`. */
|
|
@@ -23,20 +23,21 @@ export declare const SYNC_MUTATION_CONTENT_BASE64_FIELD = "contentBase64";
|
|
|
23
23
|
/** Reject aliases/extra flags: the packaged sidecar contract is byte-for-byte stable. */
|
|
24
24
|
export declare function isSyncMutationStdinCommand(argv: readonly string[]): boolean;
|
|
25
25
|
export interface SyncMutationStdinClient {
|
|
26
|
-
submit(input:
|
|
26
|
+
submit(input: {
|
|
27
|
+
canonicalPath: string;
|
|
28
|
+
op: "upsert" | "delete";
|
|
29
|
+
bytes?: Uint8Array;
|
|
30
|
+
}): Promise<{
|
|
27
31
|
requestDigest: string;
|
|
28
32
|
status: MutationStatus;
|
|
29
33
|
}>;
|
|
30
|
-
recover(authorization: SubmitMutationInput["authorization"], attemptId: string): Promise<MutationStatus>;
|
|
31
34
|
}
|
|
32
35
|
/**
|
|
33
36
|
* Decode the one-request/one-result sidecar boundary. The process launcher
|
|
34
37
|
* owns stdin/stdout; this pure adapter makes its exact JSON contract testable.
|
|
35
38
|
* It intentionally has no V1 or S3-coordinate alternative.
|
|
36
39
|
*/
|
|
37
|
-
export declare function runSyncMutationStdinJson(stdinJson: string, client: SyncMutationStdinClient
|
|
38
|
-
spoolDirectory?: string;
|
|
39
|
-
}): Promise<string>;
|
|
40
|
+
export declare function runSyncMutationStdinJson(stdinJson: string, client: SyncMutationStdinClient): Promise<string>;
|
|
40
41
|
/** Compile-time anchor proving the CLI surface calls the concrete V2 client. */
|
|
41
42
|
export declare function createSyncMutationClient(options: ConstructorParameters<typeof MutationClient>[0]): MutationClient;
|
|
42
43
|
/**
|
package/dist/cli/sync.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/cli/sync.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/cli/sync.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAEV,kBAAkB,EAEnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAA+B,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEhF,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,wBAAwB,CAAC;AAkDhC,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAU/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAc1E,OAAO,EACL,cAAc,EACd,KAAK,cAAc,EACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,kBAAkB,EAClB,KAAK,mBAAmB,EACzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtE,iFAAiF;AACjF,eAAO,MAAM,2BAA2B,+CAAgD,CAAC;AAEzF;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,kBAAkB,CAAC;AAElE,yFAAyF;AACzF,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAI3E;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,KAAK,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,QAAQ,GAAG,QAAQ,CAAC;QAAC,KAAK,CAAC,EAAE,UAAU,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,cAAc,CAAA;KAAE,CAAC,CAAC;CACnJ;AA+CD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,qBAAqB,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,cAAc,CAEjH;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,kBAAkB,EAC1B,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,aAAa,GAAG,eAAe,GAAG,QAAQ,CAAC,EACjE,YAAY,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,mBAAmB,CAAC,GACjE,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,iBAAiB,GACzB;IACE,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAC1B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,GACD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAChD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,UAAU,EAAE,kBAAkB,CAAC;CAChC,GACD;IACE;;;;;;;;;;;;;;;;OAgBG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CACvE,GACD;IACE;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,IAAI,EAAE,2BAA2B,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EACF,YAAY,GACZ,gBAAgB,GAChB,gBAAgB,GAChB,iBAAiB,GACjB,uBAAuB,GACvB,gBAAgB,GAChB,mBAAmB,CAAC;CACzB,GACD;IACE;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,IAAI,EAAE,+BAA+B,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,GACD;IACE;;;;;;;;;;;;;;;OAeG;IACH,IAAI,EAAE,8BAA8B,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B,GACD;IACE;;;;;;;;;;;;;;;;OAgBG;IACH,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,GACD;IACE;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,IAAI,EAAE,2BAA2B,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,QAAQ,CAAC;CACpB,GACD;IACE;;;;;;;;;OASG;IACH,IAAI,EAAE,iBAAiB,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,GACD;IACE;;;;;;;;;;;OAWG;IACH,IAAI,EAAE,6BAA6B,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IACE;;;;;;;;;;;;OAYG;IACH,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,GACD;IACE;;;;;;;;;;;;;;;OAeG;IACH,IAAI,EAAE,yBAAyB,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE;;;;;;;;;;;;;;OAcG;IACH,IAAI,EAAE,wBAAwB,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;CACtB,GACD;IACE;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,kBAAkB,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAEN,MAAM,WAAW,WAAW;IAC1B,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,2BAA2B;IAC3B,WAAW,EAAE,kBAAkB,CAAC;IAChC,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC7C;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC/B;;;;;;;;;;;;;;;OAeG;IACH,eAAe,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACrC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;;;;;;;;;;;OAiBG;IACH,iBAAiB,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC;IAC7C;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACzC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB;;;;OAIG;IACH,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,4CAA4C;IAC5C,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;;;OAOG;IACH,qBAAqB,EAAE,MAAM,CAAC;IAC9B;;;;;;;;;OASG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AA4DD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAM5C;AAiBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,kBAAkB,EAC/B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,EACrE,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,GACvC,OAAO,CAAC,IAAI,CAAC,CA6Ef;AAoCD;;GAEG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAOpE;AAw7CD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE,OAAsC,GAC5C,OAAO,CAoBT"}
|
package/dist/cli/sync.js
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* Never auto-overwrites local changes — prompts on conflict.
|
|
6
6
|
*/
|
|
7
7
|
import * as fs from "fs";
|
|
8
|
-
import { tmpdir } from "node:os";
|
|
9
8
|
import * as path from "path";
|
|
10
9
|
import { VaultAuthError, VaultClient } from "../vault-client.js";
|
|
11
10
|
import { readlinkOrNull } from "../lib/readlink-safe.js";
|
|
@@ -39,14 +38,10 @@ export const SYNC_MUTATION_STDIN_COMMAND = ["sync", "mutation", "--stdin-json"];
|
|
|
39
38
|
* field; it is decoded locally and never included in the prepare request.
|
|
40
39
|
*/
|
|
41
40
|
export const SYNC_MUTATION_CONTENT_BASE64_FIELD = "contentBase64";
|
|
42
|
-
const SYNC_MUTATION_SPOOL_DIRECTORY = path.join(tmpdir(), "hq-cloud", "sync-mutation-spools");
|
|
43
41
|
/** Reject aliases/extra flags: the packaged sidecar contract is byte-for-byte stable. */
|
|
44
42
|
export function isSyncMutationStdinCommand(argv) {
|
|
45
43
|
return argv.length === SYNC_MUTATION_STDIN_COMMAND.length && argv.every((value, index) => value === SYNC_MUTATION_STDIN_COMMAND[index]);
|
|
46
44
|
}
|
|
47
|
-
function isRecord(value) {
|
|
48
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
49
|
-
}
|
|
50
45
|
/** Decode canonical RFC 4648 base64 without Buffer's permissive truncation. */
|
|
51
46
|
function decodeMutationContentBase64(value) {
|
|
52
47
|
if (typeof value !== "string" || value.length % 4 !== 0) {
|
|
@@ -65,23 +60,27 @@ function decodeMutationContentBase64(value) {
|
|
|
65
60
|
// request JSON. MutationClient treats this as the immutable source snapshot.
|
|
66
61
|
return Uint8Array.from(decoded);
|
|
67
62
|
}
|
|
68
|
-
function submitInputFromStdinRequest(request
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
const mutationRequest = input.request;
|
|
75
|
-
if (isRecord(mutationRequest) && mutationRequest.operation === "delete") {
|
|
76
|
-
throw new Error(`sync mutation: delete must not include ${SYNC_MUTATION_CONTENT_BASE64_FIELD}`);
|
|
63
|
+
function submitInputFromStdinRequest(request) {
|
|
64
|
+
if (Object.keys(request).some((key) => key !== "canonicalPath" && key !== "op" && key !== SYNC_MUTATION_CONTENT_BASE64_FIELD)) {
|
|
65
|
+
throw new Error("sync mutation: stdin has unknown fields");
|
|
66
|
+
}
|
|
67
|
+
if (typeof request.canonicalPath !== "string" || request.canonicalPath.length === 0) {
|
|
68
|
+
throw new Error("sync mutation: canonicalPath is required");
|
|
77
69
|
}
|
|
70
|
+
if (request.op !== "upsert" && request.op !== "delete") {
|
|
71
|
+
throw new Error("sync mutation: op must be upsert or delete");
|
|
72
|
+
}
|
|
73
|
+
if (request.op === "delete") {
|
|
74
|
+
if (SYNC_MUTATION_CONTENT_BASE64_FIELD in request)
|
|
75
|
+
throw new Error(`sync mutation: delete must not include ${SYNC_MUTATION_CONTENT_BASE64_FIELD}`);
|
|
76
|
+
return { canonicalPath: request.canonicalPath, op: "delete" };
|
|
77
|
+
}
|
|
78
|
+
if (!(SYNC_MUTATION_CONTENT_BASE64_FIELD in request))
|
|
79
|
+
throw new Error("sync mutation: upsert requires contentBase64");
|
|
78
80
|
return {
|
|
79
|
-
|
|
81
|
+
canonicalPath: request.canonicalPath,
|
|
82
|
+
op: "upsert",
|
|
80
83
|
bytes: decodeMutationContentBase64(request[SYNC_MUTATION_CONTENT_BASE64_FIELD]),
|
|
81
|
-
// This is process-owned state, deliberately not a JSON input field. For
|
|
82
|
-
// multipart upserts MutationClient creates the attempt-ID-named durable
|
|
83
|
-
// spool only after prepare returns that ID.
|
|
84
|
-
spoolDirectory,
|
|
85
84
|
};
|
|
86
85
|
}
|
|
87
86
|
/**
|
|
@@ -89,7 +88,7 @@ function submitInputFromStdinRequest(request, spoolDirectory) {
|
|
|
89
88
|
* owns stdin/stdout; this pure adapter makes its exact JSON contract testable.
|
|
90
89
|
* It intentionally has no V1 or S3-coordinate alternative.
|
|
91
90
|
*/
|
|
92
|
-
export async function runSyncMutationStdinJson(stdinJson, client
|
|
91
|
+
export async function runSyncMutationStdinJson(stdinJson, client) {
|
|
93
92
|
let value;
|
|
94
93
|
try {
|
|
95
94
|
value = JSON.parse(stdinJson);
|
|
@@ -100,23 +99,8 @@ export async function runSyncMutationStdinJson(stdinJson, client, options = {})
|
|
|
100
99
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
101
100
|
throw new Error("sync mutation: stdin must be an object");
|
|
102
101
|
const request = value;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (request.action === "submit") {
|
|
106
|
-
if (Object.keys(request).some((key) => key !== "contractVersion" && key !== "action" && key !== "input" && key !== SYNC_MUTATION_CONTENT_BASE64_FIELD))
|
|
107
|
-
throw new Error("sync mutation: stdin submit has unknown fields");
|
|
108
|
-
const result = await client.submit(submitInputFromStdinRequest(request, options.spoolDirectory ?? SYNC_MUTATION_SPOOL_DIRECTORY));
|
|
109
|
-
return `${JSON.stringify({ contractVersion: 2, action: "submit", requestDigest: result.requestDigest, status: result.status })}\n`;
|
|
110
|
-
}
|
|
111
|
-
if (request.action === "recover") {
|
|
112
|
-
if (Object.keys(request).some((key) => key !== "contractVersion" && key !== "action" && key !== "authorization" && key !== "attemptId"))
|
|
113
|
-
throw new Error("sync mutation: stdin recover has unknown fields");
|
|
114
|
-
if (typeof request.attemptId !== "string")
|
|
115
|
-
throw new Error("sync mutation: recover attemptId is required");
|
|
116
|
-
const status = await client.recover(request.authorization, request.attemptId);
|
|
117
|
-
return `${JSON.stringify({ contractVersion: 2, action: "recover", status })}\n`;
|
|
118
|
-
}
|
|
119
|
-
throw new Error("sync mutation: stdin action must be submit or recover");
|
|
102
|
+
const result = await client.submit(submitInputFromStdinRequest(request));
|
|
103
|
+
return `${JSON.stringify({ contractVersion: 2, action: "submit", requestDigest: result.requestDigest, status: result.status })}\n`;
|
|
120
104
|
}
|
|
121
105
|
/** Compile-time anchor proving the CLI surface calls the concrete V2 client. */
|
|
122
106
|
export function createSyncMutationClient(options) {
|