@forgecart/cli 2.202610101403.0 → 2.202610110611.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.
- package/dist/src/authorization/cli-unauthorized-refusal.d.ts +10 -4
- package/dist/src/authorization/cli-unauthorized-refusal.js +11 -3
- package/dist/src/authorization/cli-unauthorized-refusal.js.map +1 -1
- package/dist/src/cli.js +4 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/init.js +5 -47
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/sync.d.ts +14 -0
- package/dist/src/commands/sync.js +49 -0
- package/dist/src/commands/sync.js.map +1 -0
- package/dist/src/exit-ladder.d.ts +8 -1
- package/dist/src/exit-ladder.js +7 -0
- package/dist/src/exit-ladder.js.map +1 -1
- package/dist/src/sync/sync-api.error.d.ts +15 -0
- package/dist/src/sync/sync-api.error.js +26 -0
- package/dist/src/sync/sync-api.error.js.map +1 -0
- package/dist/src/sync/sync-divergence.d.ts +43 -0
- package/dist/src/sync/sync-divergence.js +104 -0
- package/dist/src/sync/sync-divergence.js.map +1 -0
- package/dist/src/sync/sync-dotenv.file.d.ts +36 -0
- package/dist/src/sync/sync-dotenv.file.js +95 -0
- package/dist/src/sync/sync-dotenv.file.js.map +1 -0
- package/dist/src/sync/sync-env.runner.d.ts +29 -0
- package/dist/src/sync/sync-env.runner.js +95 -0
- package/dist/src/sync/sync-env.runner.js.map +1 -0
- package/dist/src/sync/sync-record.file.d.ts +28 -0
- package/dist/src/sync/sync-record.file.js +86 -0
- package/dist/src/sync/sync-record.file.js.map +1 -0
- package/dist/src/sync/sync-repository.d.ts +110 -0
- package/dist/src/sync/sync-repository.js +396 -0
- package/dist/src/sync/sync-repository.js.map +1 -0
- package/dist/src/sync/sync-round.d.ts +95 -0
- package/dist/src/sync/sync-round.js +355 -0
- package/dist/src/sync/sync-round.js.map +1 -0
- package/dist/src/sync/sync-watch.d.ts +48 -0
- package/dist/src/sync/sync-watch.js +144 -0
- package/dist/src/sync/sync-watch.js.map +1 -0
- package/dist/src/sync/sync.runner.d.ts +37 -0
- package/dist/src/sync/sync.runner.js +121 -0
- package/dist/src/sync/sync.runner.js.map +1 -0
- package/dist/src/sync/type/sync.types.d.ts +159 -0
- package/dist/src/sync/type/sync.types.js +30 -0
- package/dist/src/sync/type/sync.types.js.map +1 -0
- package/dist/src/sync/workspace-sync.client.d.ts +85 -0
- package/dist/src/sync/workspace-sync.client.js +317 -0
- package/dist/src/sync/workspace-sync.client.js.map +1 -0
- package/dist/src/util/dotenv.util.d.ts +28 -0
- package/dist/src/util/dotenv.util.js +81 -0
- package/dist/src/util/dotenv.util.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { CliExitLadder, CliRefusal } from '../exit-ladder.js';
|
|
2
|
+
import { print } from '../output.js';
|
|
3
|
+
import { SyncApiError } from './sync-api.error.js';
|
|
4
|
+
import { SYNC_DIVERGED_CODE, SyncDivergedRefusal, } from './sync-divergence.js';
|
|
5
|
+
import { SyncDivergenceChoice, SyncVerdict, } from './type/sync.types.js';
|
|
6
|
+
/** How many times one round reads both sides when the board moves under its push, before it stops on the divergence. */
|
|
7
|
+
const ROUND_ATTEMPTS = 3;
|
|
8
|
+
/** The code the admin API answers a delta the pod cannot cut with: the whole board is pulled instead. */
|
|
9
|
+
const SYNC_FAILED_CODE = 'WORKSPACE_SYNC_FAILED';
|
|
10
|
+
/** A commit id in print: its first twelve digits. */
|
|
11
|
+
const SHORT_SHA_LENGTH = 12;
|
|
12
|
+
/** How many changed paths a divergence lists per side before it counts the rest. */
|
|
13
|
+
const LISTED_PATHS = 20;
|
|
14
|
+
/**
|
|
15
|
+
* One round of `forgecart sync` (#2781): read the board's serving commit,
|
|
16
|
+
* snapshot the laptop's tree, hold the serving tree locally, print the plan
|
|
17
|
+
* ONCE, and move what it says — the laptop's tree and the serving tree are the
|
|
18
|
+
* same tree when it ends, or nothing moved.
|
|
19
|
+
*
|
|
20
|
+
* Both sides are compared against the base — the serving commit the laptop
|
|
21
|
+
* last matched. Only the workspace changed: its tree is written onto the
|
|
22
|
+
* laptop. Only the laptop changed: its tree is committed on the serving tip and
|
|
23
|
+
* pushed as ONE git bundle, which the pod lands through its promote pipeline or
|
|
24
|
+
* rejects with the gates' diagnostics (exit 1). Both changed: ONE selection —
|
|
25
|
+
* local overrides workspace, workspace overrides local, or Abort — never a
|
|
26
|
+
* merge; an abort or an unanswered selection ends the run on exit 4. The
|
|
27
|
+
* merchant lines of `.env` travel with the tree; the platform's keys never do.
|
|
28
|
+
*/
|
|
29
|
+
export class SyncRound {
|
|
30
|
+
options;
|
|
31
|
+
credentials;
|
|
32
|
+
client;
|
|
33
|
+
repository;
|
|
34
|
+
records;
|
|
35
|
+
dotenv;
|
|
36
|
+
selection;
|
|
37
|
+
constructor(options, credentials, client, repository, records, dotenv, selection) {
|
|
38
|
+
this.options = options;
|
|
39
|
+
this.credentials = credentials;
|
|
40
|
+
this.client = client;
|
|
41
|
+
this.repository = repository;
|
|
42
|
+
this.records = records;
|
|
43
|
+
this.dotenv = dotenv;
|
|
44
|
+
this.selection = selection;
|
|
45
|
+
}
|
|
46
|
+
/** Run the round; a board that moves under its push is read again, a bounded number of times. */
|
|
47
|
+
async run() {
|
|
48
|
+
let attempt = await this.attempt();
|
|
49
|
+
for (let tries = 1; tries < ROUND_ATTEMPTS && attempt.kind === 'moved'; tries += 1) {
|
|
50
|
+
print(' the workspace moved while the push landed: reading both sides again');
|
|
51
|
+
attempt = await this.attempt();
|
|
52
|
+
}
|
|
53
|
+
if (attempt.kind === 'settled')
|
|
54
|
+
return attempt.end;
|
|
55
|
+
throw new SyncDivergedRefusal([
|
|
56
|
+
`${SYNC_DIVERGED_CODE} — the workspace kept moving while the push landed; nothing landed. Re-run to settle it.`,
|
|
57
|
+
], attempt.point);
|
|
58
|
+
}
|
|
59
|
+
async attempt() {
|
|
60
|
+
print(`forgecart sync ${this.options.storefront}`);
|
|
61
|
+
const state = await this.client.state();
|
|
62
|
+
await this.repository.prepare();
|
|
63
|
+
const record = await this.heldRecord();
|
|
64
|
+
const local = await this.repository.snapshot();
|
|
65
|
+
if (this.options.dryRun)
|
|
66
|
+
return this.settled(await this.dryRun(state, record, local));
|
|
67
|
+
const serving = await this.holdServing(state.servingSha, record);
|
|
68
|
+
return this.settle(await this.viewOf(record, local, serving));
|
|
69
|
+
}
|
|
70
|
+
/** Decide, print the plan once, and move what it says. */
|
|
71
|
+
async settle(view) {
|
|
72
|
+
const verdict = this.verdictOf(view);
|
|
73
|
+
await this.printPlan(view, verdict);
|
|
74
|
+
switch (verdict) {
|
|
75
|
+
case SyncVerdict.IN_SYNC:
|
|
76
|
+
return this.settled(await this.inSync(view));
|
|
77
|
+
case SyncVerdict.PULL:
|
|
78
|
+
return this.settled(await this.pull(view));
|
|
79
|
+
case SyncVerdict.KEEP_LOCAL:
|
|
80
|
+
return this.settled(this.keepLocal(view));
|
|
81
|
+
case SyncVerdict.PUSH:
|
|
82
|
+
return this.land(view);
|
|
83
|
+
case SyncVerdict.DIVERGED:
|
|
84
|
+
return this.diverged(view);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
verdictOf(view) {
|
|
88
|
+
if (view.local === view.serving.tree)
|
|
89
|
+
return SyncVerdict.IN_SYNC;
|
|
90
|
+
if (view.localChanges.length === 0)
|
|
91
|
+
return SyncVerdict.PULL;
|
|
92
|
+
if (view.workspaceChanges.length > 0)
|
|
93
|
+
return SyncVerdict.DIVERGED;
|
|
94
|
+
return this.options.pullOnly ? SyncVerdict.KEEP_LOCAL : SyncVerdict.PUSH;
|
|
95
|
+
}
|
|
96
|
+
/** The two trees agree: record where they stand, and send `.env` lines the laptop changed. */
|
|
97
|
+
async inSync(view) {
|
|
98
|
+
const env = await this.sendEnvAlone(view.record);
|
|
99
|
+
await this.record(view.serving.sha, env.digests);
|
|
100
|
+
const summary = `in sync at serving ${this.short(view.serving.sha)}; ${String(env.merged)} .env key(s) merged into the workspace`;
|
|
101
|
+
print(summary);
|
|
102
|
+
return { localTree: view.local, servingSha: view.serving.sha, summary };
|
|
103
|
+
}
|
|
104
|
+
/** Only the workspace changed — or it overrides the laptop: its tree and its `.env` lines land on the laptop. */
|
|
105
|
+
async pull(view) {
|
|
106
|
+
const materialized = await this.repository.materialize(view.local, view.serving.tree);
|
|
107
|
+
const env = await this.takeEnv(view);
|
|
108
|
+
await this.record(view.serving.sha, env.digests);
|
|
109
|
+
const summary = `pulled serving ${this.short(view.serving.sha)}: ${String(materialized.written)} file(s) written, ${String(materialized.removed)} removed, ${String(env.taken)} .env key(s) taken`;
|
|
110
|
+
print(summary);
|
|
111
|
+
return { localTree: view.serving.tree, servingSha: view.serving.sha, summary };
|
|
112
|
+
}
|
|
113
|
+
/** Only the laptop changed, and the run never pushes: nothing moves. */
|
|
114
|
+
keepLocal(view) {
|
|
115
|
+
const summary = `kept ${String(view.localChanges.length)} local change(s) unsent: --pull never pushes`;
|
|
116
|
+
print(summary);
|
|
117
|
+
return {
|
|
118
|
+
localTree: view.local,
|
|
119
|
+
servingSha: view.record?.servingSha ?? view.serving.sha,
|
|
120
|
+
summary,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Push the laptop's tree onto the serving tip — or over it, when local
|
|
125
|
+
* overrides workspace — as ONE commit in ONE bundle, with the changed `.env`
|
|
126
|
+
* lines. A tree the gates reject ends the run on exit 1 with their
|
|
127
|
+
* diagnostics; a board that moved before the push landed is read again.
|
|
128
|
+
*/
|
|
129
|
+
async land(view) {
|
|
130
|
+
const sent = await this.repository.changes(view.serving.tree, view.local);
|
|
131
|
+
const outgoing = await this.dotenv.outgoing(view.record?.env ?? null);
|
|
132
|
+
const commit = await this.repository.pushCommit(view.local, view.serving.sha);
|
|
133
|
+
const bundle = await this.repository.pushBundle(commit, view.serving.sha);
|
|
134
|
+
const result = await this.sendPush(bundle, outgoing.lines);
|
|
135
|
+
if (result === null) {
|
|
136
|
+
return { kind: 'moved', point: { localTree: view.local, servingSha: view.serving.sha } };
|
|
137
|
+
}
|
|
138
|
+
if (!result.accepted)
|
|
139
|
+
throw this.rejection(result);
|
|
140
|
+
const landed = await this.holdLanded(result.servingSha, view.serving.sha);
|
|
141
|
+
await this.record(landed, outgoing.digests);
|
|
142
|
+
const summary = `pushed ${String(sent.length)} path(s): serving is ${this.short(landed)}; ${String(result.envKeys)} .env key(s) merged into the workspace`;
|
|
143
|
+
print(summary);
|
|
144
|
+
return this.settled({ localTree: view.local, servingSha: landed, summary });
|
|
145
|
+
}
|
|
146
|
+
/** Both sides changed: the selection decides which tree wins, or the run stops with nothing moved. */
|
|
147
|
+
async diverged(view) {
|
|
148
|
+
const choice = await this.selection.settle(this.divergenceLines(view), {
|
|
149
|
+
localTree: view.local,
|
|
150
|
+
servingSha: view.serving.sha,
|
|
151
|
+
});
|
|
152
|
+
if (choice === SyncDivergenceChoice.LOCAL)
|
|
153
|
+
return this.land(view);
|
|
154
|
+
return this.settled(await this.pull(view));
|
|
155
|
+
}
|
|
156
|
+
/** The divergence in words, as its refusal prints it. */
|
|
157
|
+
divergenceLines(view) {
|
|
158
|
+
const local = String(view.localChanges.length);
|
|
159
|
+
const workspace = String(view.workspaceChanges.length);
|
|
160
|
+
return [
|
|
161
|
+
`${SYNC_DIVERGED_CODE} — the workspace moved to serving ${this.short(view.serving.sha)} since ${this.lastSync(view.record)}, and both sides changed: ${local} local and ${workspace} workspace path(s).`,
|
|
162
|
+
];
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* `--dry-run`: the plan, and every path a push would send — from the record
|
|
166
|
+
* and the serving commit alone, so the one read of the serving commit is all
|
|
167
|
+
* that leaves the machine. Nothing moves on either side.
|
|
168
|
+
*/
|
|
169
|
+
async dryRun(state, record, local) {
|
|
170
|
+
const changes = await this.repository.changes(await this.baseOf(record), local);
|
|
171
|
+
const moved = record?.servingSha !== state.servingSha;
|
|
172
|
+
const outgoing = await this.dotenv.outgoing(record?.env ?? null);
|
|
173
|
+
print(` serving ${this.short(state.servingSha)}, ${this.lastSync(record)}`);
|
|
174
|
+
print(` local ${String(changes.length)} path(s) changed since the last sync`);
|
|
175
|
+
print(` workspace ${moved ? 'moved' : 'unchanged'} since the last sync`);
|
|
176
|
+
print(` .env ${String(outgoing.lines.length)} merchant key(s) a push would send`);
|
|
177
|
+
print(` plan ${this.dryVerdict(changes.length > 0, moved, state.servingSha)}`);
|
|
178
|
+
print(' paths a push would send:');
|
|
179
|
+
for (const change of changes)
|
|
180
|
+
print(` ${change.kind} ${change.path}`);
|
|
181
|
+
const summary = 'dry run: nothing moved on either side';
|
|
182
|
+
print(summary);
|
|
183
|
+
return { localTree: local, servingSha: record?.servingSha ?? state.servingSha, summary };
|
|
184
|
+
}
|
|
185
|
+
dryVerdict(localChanged, moved, servingSha) {
|
|
186
|
+
if (localChanged && moved) {
|
|
187
|
+
return 'diverged unless both sides changed alike: a run asks which tree wins';
|
|
188
|
+
}
|
|
189
|
+
if (moved)
|
|
190
|
+
return `pull serving ${this.short(servingSha)}`;
|
|
191
|
+
if (!localChanged)
|
|
192
|
+
return 'in sync';
|
|
193
|
+
if (this.options.pullOnly)
|
|
194
|
+
return 'keep the local changes: --pull never pushes';
|
|
195
|
+
return `push onto serving ${this.short(servingSha)}`;
|
|
196
|
+
}
|
|
197
|
+
/** The plan, printed once per round before anything moves. */
|
|
198
|
+
async printPlan(view, verdict) {
|
|
199
|
+
print(` serving ${this.short(view.serving.sha)}, ${this.lastSync(view.record)}`);
|
|
200
|
+
print(` local ${String(view.localChanges.length)} path(s) changed since the last sync`);
|
|
201
|
+
print(` workspace ${String(view.workspaceChanges.length)} path(s) changed since the last sync`);
|
|
202
|
+
print(` .env ${await this.envPlan(view, verdict)}`);
|
|
203
|
+
print(` plan ${verdict}`);
|
|
204
|
+
if (verdict !== SyncVerdict.DIVERGED)
|
|
205
|
+
return;
|
|
206
|
+
this.printChanges('changed on this laptop', view.localChanges);
|
|
207
|
+
this.printChanges('changed on the workspace', view.workspaceChanges);
|
|
208
|
+
}
|
|
209
|
+
/** The `.env` keys the plan carries, as a count. */
|
|
210
|
+
async envPlan(view, verdict) {
|
|
211
|
+
const recorded = view.record?.env ?? null;
|
|
212
|
+
if (verdict === SyncVerdict.PULL) {
|
|
213
|
+
const taken = await this.dotenv.takeable(view.serving.envLines ?? [], recorded);
|
|
214
|
+
return `${String(taken)} merchant key(s) to take`;
|
|
215
|
+
}
|
|
216
|
+
if (this.options.pullOnly)
|
|
217
|
+
return 'nothing to send: --pull never pushes';
|
|
218
|
+
const outgoing = await this.dotenv.outgoing(recorded);
|
|
219
|
+
return `${String(outgoing.lines.length)} merchant key(s) to send`;
|
|
220
|
+
}
|
|
221
|
+
printChanges(heading, changes) {
|
|
222
|
+
print(` ${heading}:`);
|
|
223
|
+
for (const change of changes.slice(0, LISTED_PATHS))
|
|
224
|
+
print(` ${change.kind} ${change.path}`);
|
|
225
|
+
if (changes.length > LISTED_PATHS) {
|
|
226
|
+
print(` … and ${String(changes.length - LISTED_PATHS)} more`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/** The record — when the private repository still holds its base; else a first sync. */
|
|
230
|
+
async heldRecord() {
|
|
231
|
+
const record = await this.records.read();
|
|
232
|
+
if (record === null)
|
|
233
|
+
return null;
|
|
234
|
+
if (await this.repository.hasCommit(record.servingSha))
|
|
235
|
+
return record;
|
|
236
|
+
print(` record the last sync's base ${this.short(record.servingSha)} is gone from .forgecart/sync: syncing as a first sync`);
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
/** The serving commit, held in the private repository — fetched as a bundle unless it already is. */
|
|
240
|
+
async holdServing(servingSha, record) {
|
|
241
|
+
if (await this.repository.hasCommit(servingSha)) {
|
|
242
|
+
return {
|
|
243
|
+
sha: servingSha,
|
|
244
|
+
tree: await this.repository.travellingTree(servingSha),
|
|
245
|
+
envLines: null,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
const bundle = await this.pulledBundle(record);
|
|
249
|
+
const sha = await this.repository.fetchBundle(bundle.bytes);
|
|
250
|
+
return { sha, tree: await this.repository.travellingTree(sha), envLines: bundle.envLines };
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* The bundle a pull reads: the serving commits since the recorded base when
|
|
254
|
+
* there is one, the whole board otherwise — or when the workspace cannot cut
|
|
255
|
+
* that delta. Which one is printed.
|
|
256
|
+
*/
|
|
257
|
+
async pulledBundle(record) {
|
|
258
|
+
if (record === null) {
|
|
259
|
+
print(' fetch the whole board: no recorded base');
|
|
260
|
+
return this.client.bundle('');
|
|
261
|
+
}
|
|
262
|
+
print(` fetch the serving commits since ${this.short(record.servingSha)}`);
|
|
263
|
+
try {
|
|
264
|
+
return await this.client.bundle(record.servingSha);
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
if (!(error instanceof SyncApiError) || error.code !== SYNC_FAILED_CODE)
|
|
268
|
+
throw error;
|
|
269
|
+
print(` fetch the workspace cut no delta (${error.code}): the whole board instead`);
|
|
270
|
+
return this.client.bundle('');
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/** The commit a push landed, held locally so the next round compares against it. */
|
|
274
|
+
async holdLanded(landed, cutOn) {
|
|
275
|
+
if (landed === null)
|
|
276
|
+
return cutOn;
|
|
277
|
+
if (await this.repository.hasCommit(landed))
|
|
278
|
+
return landed;
|
|
279
|
+
const bundle = await this.client.bundle(cutOn);
|
|
280
|
+
await this.repository.fetchBundle(bundle.bytes);
|
|
281
|
+
return (await this.repository.hasCommit(landed)) ? landed : cutOn;
|
|
282
|
+
}
|
|
283
|
+
/** The push, or null when the board moved past the commit it was cut on before it landed. */
|
|
284
|
+
async sendPush(bundle, envLines) {
|
|
285
|
+
try {
|
|
286
|
+
return await this.client.push(bundle, envLines);
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
if (error instanceof SyncApiError && error.code === SYNC_DIVERGED_CODE)
|
|
290
|
+
return null;
|
|
291
|
+
throw error;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/** A push the workspace did not take: exit 1, with what refused it. */
|
|
295
|
+
rejection(result) {
|
|
296
|
+
const indented = (text) => text.split('\n').map((line) => ` ${line}`);
|
|
297
|
+
return new CliRefusal(CliExitLadder.error, [
|
|
298
|
+
`the workspace did not take the push; serving stays at ${this.short(result.servingSha ?? '')}, and this laptop's tree as it is:`,
|
|
299
|
+
...result.gateMessages.flatMap(indented),
|
|
300
|
+
...(result.runtimeError === null ? [] : indented(`runtime: ${result.runtimeError}`)),
|
|
301
|
+
...result.seoFindings.flatMap((finding) => indented(`seo: ${finding}`)),
|
|
302
|
+
]);
|
|
303
|
+
}
|
|
304
|
+
/** The `.env` lines a round in sync sends alone — none for a run that never pushes. */
|
|
305
|
+
async sendEnvAlone(record) {
|
|
306
|
+
if (this.options.pullOnly)
|
|
307
|
+
return { merged: 0, digests: record?.env ?? {} };
|
|
308
|
+
const outgoing = await this.dotenv.outgoing(record?.env ?? null);
|
|
309
|
+
if (outgoing.lines.length === 0)
|
|
310
|
+
return { merged: 0, digests: outgoing.digests };
|
|
311
|
+
const result = await this.client.push(null, outgoing.lines);
|
|
312
|
+
return { merged: result.envKeys, digests: outgoing.digests };
|
|
313
|
+
}
|
|
314
|
+
/** The workspace's `.env` lines, taken — none when no bundle was read this round. */
|
|
315
|
+
async takeEnv(view) {
|
|
316
|
+
const recorded = view.record?.env ?? null;
|
|
317
|
+
if (view.serving.envLines === null)
|
|
318
|
+
return { taken: 0, digests: recorded ?? {} };
|
|
319
|
+
return this.dotenv.take(view.serving.envLines, this.credentials, recorded);
|
|
320
|
+
}
|
|
321
|
+
async viewOf(record, local, serving) {
|
|
322
|
+
const base = await this.baseOf(record);
|
|
323
|
+
return {
|
|
324
|
+
record,
|
|
325
|
+
base,
|
|
326
|
+
local,
|
|
327
|
+
serving,
|
|
328
|
+
localChanges: await this.repository.changes(base, local),
|
|
329
|
+
workspaceChanges: await this.repository.changes(base, serving.tree),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/** The travelling tree of the recorded base — the empty tree before a first sync. */
|
|
333
|
+
async baseOf(record) {
|
|
334
|
+
if (record === null)
|
|
335
|
+
return this.repository.emptyTree();
|
|
336
|
+
return this.repository.travellingTree(record.servingSha);
|
|
337
|
+
}
|
|
338
|
+
/** Record that the laptop stands on `servingSha`, and keep that commit held. */
|
|
339
|
+
async record(servingSha, env) {
|
|
340
|
+
await this.records.write(servingSha, env);
|
|
341
|
+
await this.repository.keepBase(servingSha);
|
|
342
|
+
}
|
|
343
|
+
settled(end) {
|
|
344
|
+
return { kind: 'settled', end };
|
|
345
|
+
}
|
|
346
|
+
lastSync(record) {
|
|
347
|
+
if (record === null)
|
|
348
|
+
return 'never synced';
|
|
349
|
+
return `last synced at ${this.short(record.servingSha)}`;
|
|
350
|
+
}
|
|
351
|
+
short(sha) {
|
|
352
|
+
return sha.slice(0, SHORT_SHA_LENGTH);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
//# sourceMappingURL=sync-round.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-round.js","sourceRoot":"","sources":["../../../src/sync/sync-round.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { SyncRepository } from './sync-repository.js';
|
|
2
|
+
import type { SyncRound } from './sync-round.js';
|
|
3
|
+
import type { WorkspaceSyncClient } from './workspace-sync.client.js';
|
|
4
|
+
/**
|
|
5
|
+
* `forgecart sync --watch` (#2781): one round now, then one whenever a side
|
|
6
|
+
* moves — the laptop's tree changing and holding still for a look, or the
|
|
7
|
+
* serving commit moving — until Ctrl-C, which ends the watch printing where it
|
|
8
|
+
* last stood. A round the gates reject waits for the next edit; a divergence
|
|
9
|
+
* prints its selection's end and waits for either side to move; a round that
|
|
10
|
+
* failed for any other reason is retried. Only refused credentials end the
|
|
11
|
+
* watch (exit 3).
|
|
12
|
+
*/
|
|
13
|
+
export declare class SyncWatch {
|
|
14
|
+
private readonly storefront;
|
|
15
|
+
private readonly round;
|
|
16
|
+
private readonly repository;
|
|
17
|
+
private readonly client;
|
|
18
|
+
/** Where the last round left both sides — empty before the first. */
|
|
19
|
+
private settled;
|
|
20
|
+
/** A local tree seen once, waiting a look to hold still. */
|
|
21
|
+
private pendingTree;
|
|
22
|
+
/** The local tree the round in flight was run for. */
|
|
23
|
+
private attemptedTree;
|
|
24
|
+
private nextStateRead;
|
|
25
|
+
private retryAfter;
|
|
26
|
+
private lastState;
|
|
27
|
+
constructor(storefront: string, round: SyncRound, repository: SyncRepository, client: WorkspaceSyncClient);
|
|
28
|
+
/** Watch until `interrupt` fires, then print the last state. */
|
|
29
|
+
run(interrupt: AbortSignal): Promise<void>;
|
|
30
|
+
/** One look: a changed local tree, else — now and then — the serving commit. */
|
|
31
|
+
private tick;
|
|
32
|
+
/** A changed local tree runs a round once it held still for a look. */
|
|
33
|
+
private onLocalChange;
|
|
34
|
+
/** With the laptop still, a serving commit that moved runs a round. */
|
|
35
|
+
private onStillTree;
|
|
36
|
+
private roundOn;
|
|
37
|
+
private guarded;
|
|
38
|
+
/**
|
|
39
|
+
* A round that did not settle: refused credentials end the watch; a
|
|
40
|
+
* divergence waits for either side to move; a push the workspace did not take
|
|
41
|
+
* waits for the next edit; anything else is retried after a pause. An
|
|
42
|
+
* interrupted round is the watch ending.
|
|
43
|
+
*/
|
|
44
|
+
private absorb;
|
|
45
|
+
private report;
|
|
46
|
+
/** Wait one look's interval: true once it elapsed, false when the watch is interrupted. */
|
|
47
|
+
private pause;
|
|
48
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { CliUnauthorizedRefusal } from '../authorization/cli-unauthorized-refusal.js';
|
|
2
|
+
import { CliRefusal } from '../exit-ladder.js';
|
|
3
|
+
import { print, printError } from '../output.js';
|
|
4
|
+
import { SyncDivergedRefusal } from './sync-divergence.js';
|
|
5
|
+
/** How often the watch looks at the laptop's tree. A change runs a round once it held for one look — an editor's save settles. */
|
|
6
|
+
const TICK_MS = 1000;
|
|
7
|
+
/** How often the watch reads the serving commit while the laptop's tree holds still. */
|
|
8
|
+
const STATE_READ_INTERVAL_MS = 3000;
|
|
9
|
+
/** How long the watch waits after a round that failed before it runs another for the same change. */
|
|
10
|
+
const RETRY_INTERVAL_MS = 10_000;
|
|
11
|
+
/** A commit id in print: its first twelve digits. */
|
|
12
|
+
const SHORT_SHA_LENGTH = 12;
|
|
13
|
+
/**
|
|
14
|
+
* `forgecart sync --watch` (#2781): one round now, then one whenever a side
|
|
15
|
+
* moves — the laptop's tree changing and holding still for a look, or the
|
|
16
|
+
* serving commit moving — until Ctrl-C, which ends the watch printing where it
|
|
17
|
+
* last stood. A round the gates reject waits for the next edit; a divergence
|
|
18
|
+
* prints its selection's end and waits for either side to move; a round that
|
|
19
|
+
* failed for any other reason is retried. Only refused credentials end the
|
|
20
|
+
* watch (exit 3).
|
|
21
|
+
*/
|
|
22
|
+
export class SyncWatch {
|
|
23
|
+
storefront;
|
|
24
|
+
round;
|
|
25
|
+
repository;
|
|
26
|
+
client;
|
|
27
|
+
/** Where the last round left both sides — empty before the first. */
|
|
28
|
+
settled = { localTree: '', servingSha: '' };
|
|
29
|
+
/** A local tree seen once, waiting a look to hold still. */
|
|
30
|
+
pendingTree = null;
|
|
31
|
+
/** The local tree the round in flight was run for. */
|
|
32
|
+
attemptedTree = '';
|
|
33
|
+
nextStateRead = 0;
|
|
34
|
+
retryAfter = 0;
|
|
35
|
+
lastState = 'no round has settled yet';
|
|
36
|
+
constructor(storefront, round, repository, client) {
|
|
37
|
+
this.storefront = storefront;
|
|
38
|
+
this.round = round;
|
|
39
|
+
this.repository = repository;
|
|
40
|
+
this.client = client;
|
|
41
|
+
}
|
|
42
|
+
/** Watch until `interrupt` fires, then print the last state. */
|
|
43
|
+
async run(interrupt) {
|
|
44
|
+
print(`watching ${this.storefront}: local edits push and workspace landings pull — Ctrl-C to stop`);
|
|
45
|
+
await this.repository.prepare();
|
|
46
|
+
await this.guarded(async () => this.roundOn(await this.repository.snapshot()), interrupt);
|
|
47
|
+
while (await this.pause(interrupt)) {
|
|
48
|
+
await this.guarded(() => this.tick(), interrupt);
|
|
49
|
+
}
|
|
50
|
+
print(`stopped watching ${this.storefront}: ${this.lastState}`);
|
|
51
|
+
}
|
|
52
|
+
/** One look: a changed local tree, else — now and then — the serving commit. */
|
|
53
|
+
async tick() {
|
|
54
|
+
const tree = await this.repository.snapshot();
|
|
55
|
+
if (tree !== this.settled.localTree)
|
|
56
|
+
return this.onLocalChange(tree);
|
|
57
|
+
this.pendingTree = null;
|
|
58
|
+
return this.onStillTree(tree);
|
|
59
|
+
}
|
|
60
|
+
/** A changed local tree runs a round once it held still for a look. */
|
|
61
|
+
async onLocalChange(tree) {
|
|
62
|
+
if (tree !== this.pendingTree) {
|
|
63
|
+
this.pendingTree = tree;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (Date.now() < this.retryAfter)
|
|
67
|
+
return;
|
|
68
|
+
await this.roundOn(tree);
|
|
69
|
+
}
|
|
70
|
+
/** With the laptop still, a serving commit that moved runs a round. */
|
|
71
|
+
async onStillTree(tree) {
|
|
72
|
+
if (Date.now() < this.nextStateRead)
|
|
73
|
+
return;
|
|
74
|
+
this.nextStateRead = Date.now() + STATE_READ_INTERVAL_MS;
|
|
75
|
+
const { servingSha } = await this.client.state();
|
|
76
|
+
if (servingSha === this.settled.servingSha || Date.now() < this.retryAfter)
|
|
77
|
+
return;
|
|
78
|
+
await this.roundOn(tree);
|
|
79
|
+
}
|
|
80
|
+
async roundOn(tree) {
|
|
81
|
+
this.attemptedTree = tree;
|
|
82
|
+
const end = await this.round.run();
|
|
83
|
+
this.settled = { localTree: end.localTree, servingSha: end.servingSha };
|
|
84
|
+
this.pendingTree = null;
|
|
85
|
+
this.lastState = end.summary;
|
|
86
|
+
}
|
|
87
|
+
async guarded(work, interrupt) {
|
|
88
|
+
try {
|
|
89
|
+
await work();
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
this.absorb(error, interrupt);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A round that did not settle: refused credentials end the watch; a
|
|
97
|
+
* divergence waits for either side to move; a push the workspace did not take
|
|
98
|
+
* waits for the next edit; anything else is retried after a pause. An
|
|
99
|
+
* interrupted round is the watch ending.
|
|
100
|
+
*/
|
|
101
|
+
absorb(error, interrupt) {
|
|
102
|
+
if (interrupt.aborted)
|
|
103
|
+
return;
|
|
104
|
+
if (error instanceof CliUnauthorizedRefusal)
|
|
105
|
+
throw error;
|
|
106
|
+
this.retryAfter = Date.now() + RETRY_INTERVAL_MS;
|
|
107
|
+
if (error instanceof SyncDivergedRefusal) {
|
|
108
|
+
this.report(error.lines);
|
|
109
|
+
this.settled = error.point;
|
|
110
|
+
this.lastState = `diverged from serving ${error.point.servingSha.slice(0, SHORT_SHA_LENGTH)}: waiting for either side to move`;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (error instanceof CliRefusal) {
|
|
114
|
+
this.report(error.lines);
|
|
115
|
+
this.settled = { localTree: this.attemptedTree, servingSha: this.settled.servingSha };
|
|
116
|
+
this.lastState = 'the workspace did not take the last push: waiting for the next edit';
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
120
|
+
printError(`Error: ${message}`);
|
|
121
|
+
this.lastState = `the last round failed: ${message}`;
|
|
122
|
+
}
|
|
123
|
+
report(lines) {
|
|
124
|
+
for (const line of lines)
|
|
125
|
+
printError(`forgecart sync: ${line}`);
|
|
126
|
+
}
|
|
127
|
+
/** Wait one look's interval: true once it elapsed, false when the watch is interrupted. */
|
|
128
|
+
pause(interrupt) {
|
|
129
|
+
if (interrupt.aborted)
|
|
130
|
+
return Promise.resolve(false);
|
|
131
|
+
return new Promise((resolve) => {
|
|
132
|
+
const timer = setTimeout(() => {
|
|
133
|
+
interrupt.removeEventListener('abort', onInterrupt);
|
|
134
|
+
resolve(true);
|
|
135
|
+
}, TICK_MS);
|
|
136
|
+
function onInterrupt() {
|
|
137
|
+
clearTimeout(timer);
|
|
138
|
+
resolve(false);
|
|
139
|
+
}
|
|
140
|
+
interrupt.addEventListener('abort', onInterrupt, { once: true });
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=sync-watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-watch.js","sourceRoot":"","sources":["../../../src/sync/sync-watch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { SyncOptions } from './type/sync.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* `forgecart sync [name]` (#2781): keep the storefront's tree and the board's
|
|
4
|
+
* serving tree the same tree. Before anything leaves the machine the run
|
|
5
|
+
* settles its four credentials — the environment, then the storefront's `.env`,
|
|
6
|
+
* then its `.forgecart/config.json`, exactly as `init` reads them; a key in no
|
|
7
|
+
* source exits 3 with nothing sent — and needs `git` on the PATH. Then it runs
|
|
8
|
+
* ONE round, or, with `--watch`, a round whenever a side moves until Ctrl-C.
|
|
9
|
+
*/
|
|
10
|
+
export declare class SyncRunner {
|
|
11
|
+
private readonly name;
|
|
12
|
+
private readonly options;
|
|
13
|
+
/**
|
|
14
|
+
* @param name the storefront directory as given — the current directory when absent.
|
|
15
|
+
* @param options the run's flags.
|
|
16
|
+
*/
|
|
17
|
+
constructor(name: string | undefined, options: SyncOptions);
|
|
18
|
+
run(): Promise<void>;
|
|
19
|
+
/** `--dry-run` plans one round and moves nothing; it cannot watch. */
|
|
20
|
+
private assertFlags;
|
|
21
|
+
/**
|
|
22
|
+
* The four credentials, from the first source carrying each. With one in no
|
|
23
|
+
* source the run prints where it looked — key names, never values — and exits
|
|
24
|
+
* 3 before any request.
|
|
25
|
+
*/
|
|
26
|
+
private settleCredentials;
|
|
27
|
+
/** The storefront must be a directory — `--pull` makes a new one to take the workspace's tree into. */
|
|
28
|
+
private assertStorefront;
|
|
29
|
+
/** Watch until Ctrl-C, which ends the run in flight and prints where it stood. */
|
|
30
|
+
private watch;
|
|
31
|
+
private assemble;
|
|
32
|
+
/** The channel a record belongs to: a digest of the admin API and the channel token — never the token. */
|
|
33
|
+
private channelOf;
|
|
34
|
+
/** The storefront as the merchant named it. */
|
|
35
|
+
private displayName;
|
|
36
|
+
private isDirectory;
|
|
37
|
+
}
|