@forgecart/cli 2.202610102045.0 → 2.202610110825.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.
Files changed (50) hide show
  1. package/dist/src/authorization/cli-unauthorized-refusal.d.ts +10 -4
  2. package/dist/src/authorization/cli-unauthorized-refusal.js +11 -3
  3. package/dist/src/authorization/cli-unauthorized-refusal.js.map +1 -1
  4. package/dist/src/cli.js +4 -0
  5. package/dist/src/cli.js.map +1 -1
  6. package/dist/src/commands/init.js +5 -47
  7. package/dist/src/commands/init.js.map +1 -1
  8. package/dist/src/commands/sync.d.ts +14 -0
  9. package/dist/src/commands/sync.js +49 -0
  10. package/dist/src/commands/sync.js.map +1 -0
  11. package/dist/src/exit-ladder.d.ts +8 -1
  12. package/dist/src/exit-ladder.js +7 -0
  13. package/dist/src/exit-ladder.js.map +1 -1
  14. package/dist/src/sync/sync-api.error.d.ts +15 -0
  15. package/dist/src/sync/sync-api.error.js +26 -0
  16. package/dist/src/sync/sync-api.error.js.map +1 -0
  17. package/dist/src/sync/sync-divergence.d.ts +43 -0
  18. package/dist/src/sync/sync-divergence.js +104 -0
  19. package/dist/src/sync/sync-divergence.js.map +1 -0
  20. package/dist/src/sync/sync-dotenv.file.d.ts +36 -0
  21. package/dist/src/sync/sync-dotenv.file.js +95 -0
  22. package/dist/src/sync/sync-dotenv.file.js.map +1 -0
  23. package/dist/src/sync/sync-env.runner.d.ts +29 -0
  24. package/dist/src/sync/sync-env.runner.js +95 -0
  25. package/dist/src/sync/sync-env.runner.js.map +1 -0
  26. package/dist/src/sync/sync-record.file.d.ts +28 -0
  27. package/dist/src/sync/sync-record.file.js +86 -0
  28. package/dist/src/sync/sync-record.file.js.map +1 -0
  29. package/dist/src/sync/sync-repository.d.ts +110 -0
  30. package/dist/src/sync/sync-repository.js +396 -0
  31. package/dist/src/sync/sync-repository.js.map +1 -0
  32. package/dist/src/sync/sync-round.d.ts +95 -0
  33. package/dist/src/sync/sync-round.js +355 -0
  34. package/dist/src/sync/sync-round.js.map +1 -0
  35. package/dist/src/sync/sync-watch.d.ts +48 -0
  36. package/dist/src/sync/sync-watch.js +144 -0
  37. package/dist/src/sync/sync-watch.js.map +1 -0
  38. package/dist/src/sync/sync.runner.d.ts +37 -0
  39. package/dist/src/sync/sync.runner.js +121 -0
  40. package/dist/src/sync/sync.runner.js.map +1 -0
  41. package/dist/src/sync/type/sync.types.d.ts +159 -0
  42. package/dist/src/sync/type/sync.types.js +30 -0
  43. package/dist/src/sync/type/sync.types.js.map +1 -0
  44. package/dist/src/sync/workspace-sync.client.d.ts +85 -0
  45. package/dist/src/sync/workspace-sync.client.js +317 -0
  46. package/dist/src/sync/workspace-sync.client.js.map +1 -0
  47. package/dist/src/util/dotenv.util.d.ts +28 -0
  48. package/dist/src/util/dotenv.util.js +81 -0
  49. package/dist/src/util/dotenv.util.js.map +1 -0
  50. package/package.json +1 -1
@@ -0,0 +1,317 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { CliUnauthorizedReason, CliUnauthorizedRefusal, } from '../authorization/cli-unauthorized-refusal.js';
3
+ import { isJsonObject } from '../json.js';
4
+ import { SyncApiError } from './sync-api.error.js';
5
+ /** The SDK's `WorkspaceSyncRetrieve` operation, verbatim. */
6
+ const STATE_DOCUMENT = `query WorkspaceSyncRetrieve {
7
+ workspaceSyncState {
8
+ id
9
+ servingSha
10
+ }
11
+ }`;
12
+ /** The SDK's `WorkspaceSyncPull` operation, verbatim. */
13
+ const BUNDLE_DOCUMENT = `query WorkspaceSyncPull($input: WorkspaceSyncBundleInput!) {
14
+ workspaceSyncBundle(input: $input) {
15
+ id
16
+ sinceSha
17
+ byteLength
18
+ sha256
19
+ data
20
+ envLines
21
+ }
22
+ }`;
23
+ /** The SDK's `WorkspaceSyncPush` operation, verbatim. */
24
+ const PUSH_DOCUMENT = `mutation WorkspaceSyncPush($input: PushWorkspaceSyncInput!) {
25
+ pushWorkspaceSync(input: $input) {
26
+ id
27
+ accepted
28
+ servingSha
29
+ gateMessages
30
+ runtimeError
31
+ seoFindings
32
+ envKeys
33
+ }
34
+ }`;
35
+ /** The codes the admin API refuses an admin operation's credentials with. */
36
+ const CREDENTIAL_REFUSALS = new Set(['UNAUTHORIZED', 'FORBIDDEN']);
37
+ /** The multipart part a push's bundle travels in, and the variable it answers (GraphQL multipart request spec). */
38
+ const BUNDLE_PART = '0';
39
+ const BUNDLE_VARIABLE = 'variables.input.bundle';
40
+ const BUNDLE_FILE_NAME = 'serving.bundle';
41
+ /** Milliseconds in a second — `--timeout` is given in seconds. */
42
+ const MS_PER_SECOND = 1000;
43
+ /**
44
+ * The admin API's three workspace-sync operations (#2781), over GraphQL on
45
+ * HTTP with the channel token and the admin secret as the `forgecart-token` and
46
+ * `forgecart-secret` headers — the one surface `forgecart sync` reaches the
47
+ * shop through. Every request goes to FORGECART_ADMIN_API_URL as given, and
48
+ * every exchange is bounded by `--timeout` and ends when the run is
49
+ * interrupted. Answers are read field by field: one the CLI cannot read is an
50
+ * error naming the endpoint, never a guess. Credentials the API refuses end the
51
+ * run on exit 3; any other refusal is a {@link SyncApiError} carrying its code.
52
+ */
53
+ export class WorkspaceSyncClient {
54
+ credentials;
55
+ timeoutSeconds;
56
+ interrupt;
57
+ /**
58
+ * @param credentials the four credentials the run settled.
59
+ * @param timeoutSeconds the bound on one exchange — `--timeout`.
60
+ * @param interrupt ends every exchange in flight when the run is interrupted.
61
+ */
62
+ constructor(credentials, timeoutSeconds, interrupt) {
63
+ this.credentials = credentials;
64
+ this.timeoutSeconds = timeoutSeconds;
65
+ this.interrupt = interrupt;
66
+ }
67
+ /** The board's serving commit, read from the pod. */
68
+ async state() {
69
+ const field = 'workspaceSyncState';
70
+ const result = await this.exchange(this.jsonRequest(STATE_DOCUMENT, {}), field);
71
+ return { servingSha: this.readString(result, 'servingSha', field) };
72
+ }
73
+ /**
74
+ * The serving branch since `sinceSha` — all of it for `''` — as ONE git
75
+ * bundle, checked against its declared byte length and sha256 before anything
76
+ * reads it: a short or mismatched bundle is an error, and nothing is written.
77
+ */
78
+ async bundle(sinceSha) {
79
+ const field = 'workspaceSyncBundle';
80
+ const result = await this.exchange(this.jsonRequest(BUNDLE_DOCUMENT, { input: { sinceSha } }), field);
81
+ const bytes = Buffer.from(this.readString(result, 'data', field), 'base64');
82
+ this.assertDeclared(bytes, this.readCount(result, 'byteLength', field), this.readString(result, 'sha256', field));
83
+ return {
84
+ sinceSha: this.readText(result, 'sinceSha', field),
85
+ bytes,
86
+ envLines: this.readStringList(result, 'envLines', field),
87
+ };
88
+ }
89
+ /**
90
+ * Push `bundle` — the laptop's tree as one commit cut on the serving tip — as
91
+ * an authenticated upload, with the merchant `.env` lines `envLines`; a push
92
+ * without a bundle carries the lines alone.
93
+ */
94
+ async push(bundle, envLines) {
95
+ const field = 'pushWorkspaceSync';
96
+ const result = await this.exchange(this.pushRequest(bundle, envLines), field);
97
+ return {
98
+ accepted: this.readBoolean(result, 'accepted', field),
99
+ servingSha: this.readNullableString(result, 'servingSha', field),
100
+ gateMessages: this.readStringList(result, 'gateMessages', field),
101
+ runtimeError: this.readNullableString(result, 'runtimeError', field),
102
+ seoFindings: this.readStringList(result, 'seoFindings', field),
103
+ envKeys: this.readCount(result, 'envKeys', field),
104
+ };
105
+ }
106
+ /** A push with a bundle is an upload; one with `.env` lines alone is plain JSON. */
107
+ pushRequest(bundle, envLines) {
108
+ if (bundle === null)
109
+ return this.jsonRequest(PUSH_DOCUMENT, { input: { envLines } });
110
+ return this.uploadRequest(bundle, envLines);
111
+ }
112
+ /** A GraphQL request as JSON. */
113
+ jsonRequest(document, variables) {
114
+ return {
115
+ body: JSON.stringify({ query: document, variables }),
116
+ headers: { ...this.authHeaders(), 'content-type': 'application/json' },
117
+ };
118
+ }
119
+ /**
120
+ * The push as a GraphQL multipart request: the operation, the map naming the
121
+ * bundle's variable, and the bundle itself, declared by its byte length and
122
+ * sha256. The admin API reads a multipart request only with the preflight
123
+ * header; the boundary is the form's own.
124
+ */
125
+ uploadRequest(bundle, envLines) {
126
+ const input = {
127
+ bundle: null,
128
+ byteLength: bundle.length,
129
+ sha256: createHash('sha256').update(bundle).digest('hex'),
130
+ envLines,
131
+ };
132
+ const form = new FormData();
133
+ form.append('operations', JSON.stringify({ query: PUSH_DOCUMENT, variables: { input } }));
134
+ form.append('map', JSON.stringify({ [BUNDLE_PART]: [BUNDLE_VARIABLE] }));
135
+ form.append(BUNDLE_PART, new Blob([new Uint8Array(bundle)]), BUNDLE_FILE_NAME);
136
+ return { body: form, headers: { ...this.authHeaders(), 'apollo-require-preflight': 'true' } };
137
+ }
138
+ authHeaders() {
139
+ return {
140
+ accept: 'application/json',
141
+ 'forgecart-token': this.credentials.channelToken,
142
+ 'forgecart-secret': this.credentials.adminSecret,
143
+ };
144
+ }
145
+ /**
146
+ * POST one operation and answer its root field's object. The exchange — the
147
+ * response and its whole body — is bounded by `--timeout` and ends with the
148
+ * run's interrupt.
149
+ */
150
+ async exchange(request, field) {
151
+ const bound = new AbortController();
152
+ const timer = setTimeout(() => {
153
+ bound.abort();
154
+ }, this.timeoutSeconds * MS_PER_SECOND);
155
+ const relay = () => {
156
+ bound.abort();
157
+ };
158
+ this.interrupt.addEventListener('abort', relay, { once: true });
159
+ try {
160
+ const { status, text } = await this.post(request, bound.signal, field);
161
+ return this.rootField(this.parseBody(text, status), field);
162
+ }
163
+ finally {
164
+ clearTimeout(timer);
165
+ this.interrupt.removeEventListener('abort', relay);
166
+ }
167
+ }
168
+ async post(request, signal, field) {
169
+ try {
170
+ const response = await fetch(this.credentials.adminApiUrl, {
171
+ method: 'POST',
172
+ headers: request.headers,
173
+ body: request.body,
174
+ signal,
175
+ });
176
+ return { status: response.status, text: await response.text() };
177
+ }
178
+ catch (error) {
179
+ throw this.exchangeFailure(error, signal, field);
180
+ }
181
+ }
182
+ /** Why an exchange ended without an answer: the run's interrupt, `--timeout`, or the network. */
183
+ exchangeFailure(error, signal, field) {
184
+ const endpoint = this.credentials.adminApiUrl;
185
+ if (this.interrupt.aborted) {
186
+ return new Error(`Interrupted while the admin API at ${endpoint} answered ${field}.`, {
187
+ cause: error,
188
+ });
189
+ }
190
+ if (signal.aborted) {
191
+ return new Error(`The admin API at ${endpoint} did not answer ${field} within --timeout ${String(this.timeoutSeconds)} s.`, { cause: error });
192
+ }
193
+ return new Error(`Could not reach the admin API at ${endpoint}: ${this.failureDetail(error)}.`, {
194
+ cause: error,
195
+ });
196
+ }
197
+ /** The response's GraphQL body — an answer that is not one names its HTTP status. */
198
+ parseBody(text, status) {
199
+ let parsed;
200
+ try {
201
+ parsed = JSON.parse(text);
202
+ }
203
+ catch (error) {
204
+ throw new Error(this.notGraphQlMessage(status), { cause: error });
205
+ }
206
+ if (!isJsonObject(parsed))
207
+ throw new Error(this.notGraphQlMessage(status));
208
+ return parsed;
209
+ }
210
+ /** The root field's object, once the body carries no error. */
211
+ rootField(body, field) {
212
+ this.assertNoErrors(body.errors, field);
213
+ const data = body.data;
214
+ const result = isJsonObject(data) ? data[field] : undefined;
215
+ if (!isJsonObject(result))
216
+ throw this.unreadable(field);
217
+ return result;
218
+ }
219
+ /**
220
+ * A GraphQL error ends the call: credentials refused as UNAUTHORIZED or
221
+ * FORBIDDEN on exit 3, any other code as the typed {@link SyncApiError}.
222
+ */
223
+ assertNoErrors(errors, field) {
224
+ if (!Array.isArray(errors) || errors.length === 0)
225
+ return;
226
+ const first = errors[0];
227
+ const extensions = this.extensionsOf(first);
228
+ const code = typeof extensions.code === 'string' ? extensions.code : undefined;
229
+ if (code !== undefined && CREDENTIAL_REFUSALS.has(code)) {
230
+ throw new CliUnauthorizedRefusal(CliUnauthorizedReason.REFUSED);
231
+ }
232
+ throw new SyncApiError(this.credentials.adminApiUrl, field, code ?? this.messageOf(first), this.errorVariables(extensions.variables));
233
+ }
234
+ extensionsOf(error) {
235
+ return isJsonObject(error) && isJsonObject(error.extensions) ? error.extensions : {};
236
+ }
237
+ messageOf(error) {
238
+ return isJsonObject(error) && typeof error.message === 'string' ? error.message : '';
239
+ }
240
+ /** The variables a typed error carries, as text — none when it carries none. */
241
+ errorVariables(variables) {
242
+ if (!isJsonObject(variables))
243
+ return {};
244
+ return Object.fromEntries(Object.entries(variables).map(([key, value]) => [
245
+ key,
246
+ typeof value === 'string' ? value : JSON.stringify(value),
247
+ ]));
248
+ }
249
+ /** A pulled bundle's bytes against what it declares: its length, then its sha256. */
250
+ assertDeclared(bytes, byteLength, sha256) {
251
+ if (bytes.length !== byteLength) {
252
+ throw new Error(`The pulled bundle is ${String(bytes.length)} bytes, not the ${String(byteLength)} it declares; nothing was written.`);
253
+ }
254
+ if (createHash('sha256').update(bytes).digest('hex') !== sha256) {
255
+ throw new Error('The pulled bundle does not hash to the sha256 it declares; nothing was written.');
256
+ }
257
+ }
258
+ /** A string field that must carry text. */
259
+ readString(record, key, field) {
260
+ const value = record[key];
261
+ if (typeof value !== 'string' || value === '')
262
+ throw this.unreadable(field);
263
+ return value;
264
+ }
265
+ /** A string field that may be empty. */
266
+ readText(record, key, field) {
267
+ const value = record[key];
268
+ if (typeof value !== 'string')
269
+ throw this.unreadable(field);
270
+ return value;
271
+ }
272
+ readNullableString(record, key, field) {
273
+ const value = record[key];
274
+ if (value === null)
275
+ return null;
276
+ if (typeof value !== 'string')
277
+ throw this.unreadable(field);
278
+ return value;
279
+ }
280
+ readStringList(record, key, field) {
281
+ const value = record[key];
282
+ if (!Array.isArray(value))
283
+ throw this.unreadable(field);
284
+ const items = value;
285
+ if (!items.every((item) => typeof item === 'string')) {
286
+ throw this.unreadable(field);
287
+ }
288
+ return items;
289
+ }
290
+ readCount(record, key, field) {
291
+ const value = record[key];
292
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
293
+ throw this.unreadable(field);
294
+ }
295
+ return value;
296
+ }
297
+ readBoolean(record, key, field) {
298
+ const value = record[key];
299
+ if (typeof value !== 'boolean')
300
+ throw this.unreadable(field);
301
+ return value;
302
+ }
303
+ unreadable(field) {
304
+ return new Error(`The admin API at ${this.credentials.adminApiUrl} answered a ${field} result the CLI cannot read.`);
305
+ }
306
+ notGraphQlMessage(status) {
307
+ return `The admin API at ${this.credentials.adminApiUrl} answered HTTP ${String(status)} without a GraphQL response.`;
308
+ }
309
+ /** What failed to connect: fetch's own message names nothing, its cause names the socket error. */
310
+ failureDetail(error) {
311
+ const cause = error instanceof Error ? error.cause : undefined;
312
+ if (cause instanceof Error)
313
+ return cause.message;
314
+ return error instanceof Error ? error.message : String(error);
315
+ }
316
+ }
317
+ //# sourceMappingURL=workspace-sync.client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-sync.client.js","sourceRoot":"","sources":["../../../src/sync/workspace-sync.client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The `.env` rules a storefront's `.env` is written and read by (#1123, #2781):
3
+ * init's merge — the keys a run manages refreshed in place, every other line
4
+ * verbatim — and the split `forgecart sync` carries `.env` by: the platform's
5
+ * own `FORGECART_*` keys, which init writes and which never cross between a
6
+ * laptop and its workspace, against the merchant's keys, which do.
7
+ */
8
+ /** The key `line` assigns — undefined for a comment, a blank or any other line. */
9
+ export declare function dotenvKey(line: string): string | undefined;
10
+ /** Whether `key` is the platform's — init's to write, never a merchant's to carry. */
11
+ export declare function isPlatformKey(key: string): boolean;
12
+ /** The value an assignment line assigns `key`: everything after its `=`, verbatim. */
13
+ export declare function dotenvValue(line: string, key: string): string;
14
+ /**
15
+ * The merchant's assignments among `lines`: the FIRST line of every key that is
16
+ * no platform key — the line init's merge refreshes — keyed by it, in order.
17
+ */
18
+ export declare function merchantAssignments(lines: readonly string[]): Map<string, string>;
19
+ /**
20
+ * Merge the `managed` keys into an `existing` `.env`, preserving every other
21
+ * line — merchant keys, comments, ordering — verbatim (#1123: a wholesale
22
+ * rewrite wiped the demo store's DEMO_* config on three provisioning drives).
23
+ * A managed key is refreshed in place at its existing position; its duplicates
24
+ * collapse onto the first occurrence; a managed key with no existing line is
25
+ * appended in the map's order. Trailing blank lines normalize to the single
26
+ * final newline. An empty `existing` renders the managed keys alone.
27
+ */
28
+ export declare function mergeDotenv(existing: string, managed: ReadonlyMap<string, string>): string;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * The `.env` rules a storefront's `.env` is written and read by (#1123, #2781):
3
+ * init's merge — the keys a run manages refreshed in place, every other line
4
+ * verbatim — and the split `forgecart sync` carries `.env` by: the platform's
5
+ * own `FORGECART_*` keys, which init writes and which never cross between a
6
+ * laptop and its workspace, against the merchant's keys, which do.
7
+ */
8
+ /** An assignment line: its key, then `=`. A line of any other shape is carried verbatim and never travels. */
9
+ const ASSIGNMENT = /^([A-Za-z_]\w*)=/;
10
+ /** The prefix every platform-owned key carries. */
11
+ const PLATFORM_KEY_PREFIX = 'FORGECART_';
12
+ /** The key `line` assigns — undefined for a comment, a blank or any other line. */
13
+ export function dotenvKey(line) {
14
+ return ASSIGNMENT.exec(line)?.[1];
15
+ }
16
+ /** Whether `key` is the platform's — init's to write, never a merchant's to carry. */
17
+ export function isPlatformKey(key) {
18
+ return key.startsWith(PLATFORM_KEY_PREFIX);
19
+ }
20
+ /** The value an assignment line assigns `key`: everything after its `=`, verbatim. */
21
+ export function dotenvValue(line, key) {
22
+ return line.slice(key.length + 1);
23
+ }
24
+ /**
25
+ * The merchant's assignments among `lines`: the FIRST line of every key that is
26
+ * no platform key — the line init's merge refreshes — keyed by it, in order.
27
+ */
28
+ export function merchantAssignments(lines) {
29
+ const assignments = new Map();
30
+ for (const line of lines) {
31
+ const key = dotenvKey(line);
32
+ if (key === undefined || isPlatformKey(key) || assignments.has(key))
33
+ continue;
34
+ assignments.set(key, line);
35
+ }
36
+ return assignments;
37
+ }
38
+ /**
39
+ * Merge the `managed` keys into an `existing` `.env`, preserving every other
40
+ * line — merchant keys, comments, ordering — verbatim (#1123: a wholesale
41
+ * rewrite wiped the demo store's DEMO_* config on three provisioning drives).
42
+ * A managed key is refreshed in place at its existing position; its duplicates
43
+ * collapse onto the first occurrence; a managed key with no existing line is
44
+ * appended in the map's order. Trailing blank lines normalize to the single
45
+ * final newline. An empty `existing` renders the managed keys alone.
46
+ */
47
+ export function mergeDotenv(existing, managed) {
48
+ const refreshed = new Set();
49
+ const merged = existing.split('\n').flatMap((line) => refreshLine(line, managed, refreshed));
50
+ trimTrailingBlanks(merged);
51
+ for (const [key, value] of managed) {
52
+ if (!refreshed.has(key))
53
+ merged.push(`${key}=${value}`);
54
+ }
55
+ merged.push('');
56
+ return merged.join('\n');
57
+ }
58
+ /**
59
+ * One existing line through the merge: a line no managed key assigns passes
60
+ * through verbatim, a managed key refreshes in place on first sight, and its
61
+ * later duplicates drop.
62
+ */
63
+ function refreshLine(line, managed, refreshed) {
64
+ const key = dotenvKey(line);
65
+ if (key === undefined)
66
+ return [line];
67
+ const value = managed.get(key);
68
+ if (value === undefined)
69
+ return [line];
70
+ if (refreshed.has(key))
71
+ return [];
72
+ refreshed.add(key);
73
+ return [`${key}=${value}`];
74
+ }
75
+ /** Drop the blank lines a file ends on: the merge writes exactly one final newline. */
76
+ function trimTrailingBlanks(lines) {
77
+ while (lines.length > 0 && lines[lines.length - 1] === '') {
78
+ lines.pop();
79
+ }
80
+ }
81
+ //# sourceMappingURL=dotenv.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dotenv.util.js","sourceRoot":"","sources":["../../../src/util/dotenv.util.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgecart/cli",
3
- "version": "2.202610102045.0",
3
+ "version": "2.202610110825.0",
4
4
  "type": "module",
5
5
  "description": "CLI for scaffolding and operating ForgeCart channel storefronts",
6
6
  "bin": {