@forgecart/cli 2.202610122318.0 → 2.202610130038.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/sync/sync-image-update.d.ts +35 -0
- package/dist/src/sync/sync-image-update.js +78 -0
- package/dist/src/sync/sync-image-update.js.map +1 -0
- package/dist/src/sync/workspace-sync.client.d.ts +11 -1
- package/dist/src/sync/workspace-sync.client.js +27 -4
- package/dist/src/sync/workspace-sync.client.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AdminApiRefusal } from '../admin-api/admin-api-refusal.error.js';
|
|
2
|
+
/**
|
|
3
|
+
* The admin API's typed answer while the workspace's pod moves onto the
|
|
4
|
+
* current image (#2371): the pod ran a build older than the deployed one, the
|
|
5
|
+
* shop recycled it, and the workspace re-provisions.
|
|
6
|
+
*/
|
|
7
|
+
export declare const IMAGE_UPDATING_CODE = "WORKSPACE_IMAGE_UPDATING";
|
|
8
|
+
/**
|
|
9
|
+
* One exchange's wait through a workspace update (#2371). Every time the admin
|
|
10
|
+
* API answers {@link IMAGE_UPDATING_CODE}, the exchange waits the
|
|
11
|
+
* `retryAfterSeconds` the answer names and asks again — by itself, for as long
|
|
12
|
+
* as the answer is the update and no longer: the workspace's states bound the
|
|
13
|
+
* wait, never a sleep budget, and `--timeout` bounds each exchange alone. The
|
|
14
|
+
* merchant is told once that the workspace is updating to the current version;
|
|
15
|
+
* the run's interrupt ends the wait.
|
|
16
|
+
*/
|
|
17
|
+
export declare class SyncImageUpdateWait {
|
|
18
|
+
private readonly field;
|
|
19
|
+
private readonly interrupt;
|
|
20
|
+
private announced;
|
|
21
|
+
/**
|
|
22
|
+
* @param field the operation the exchange asks — named when the wait is interrupted.
|
|
23
|
+
* @param interrupt ends the wait when the run is interrupted.
|
|
24
|
+
*/
|
|
25
|
+
constructor(field: string, interrupt: AbortSignal);
|
|
26
|
+
/** Whether `error` is the admin API's answer that the workspace is updating. */
|
|
27
|
+
static isUpdating(error: unknown): error is AdminApiRefusal;
|
|
28
|
+
/** Wait out one update answer: tell the merchant once, then pause the seconds it names. */
|
|
29
|
+
through(answer: AdminApiRefusal): Promise<void>;
|
|
30
|
+
/** The wait the answer names: a positive whole number of seconds, else the default. */
|
|
31
|
+
private retryAfterSeconds;
|
|
32
|
+
private announce;
|
|
33
|
+
/** Pause `ms`: true once it elapsed, false when the run is interrupted. */
|
|
34
|
+
private pause;
|
|
35
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { AdminApiRefusal } from '../admin-api/admin-api-refusal.error.js';
|
|
2
|
+
import { print } from '../output.js';
|
|
3
|
+
/**
|
|
4
|
+
* The admin API's typed answer while the workspace's pod moves onto the
|
|
5
|
+
* current image (#2371): the pod ran a build older than the deployed one, the
|
|
6
|
+
* shop recycled it, and the workspace re-provisions.
|
|
7
|
+
*/
|
|
8
|
+
export const IMAGE_UPDATING_CODE = 'WORKSPACE_IMAGE_UPDATING';
|
|
9
|
+
/** The seconds between two asks when an answer names none it can be read by. */
|
|
10
|
+
const DEFAULT_RETRY_AFTER_SECONDS = 5;
|
|
11
|
+
/** Milliseconds in a second — the answer names its wait in seconds. */
|
|
12
|
+
const MS_PER_SECOND = 1000;
|
|
13
|
+
/**
|
|
14
|
+
* One exchange's wait through a workspace update (#2371). Every time the admin
|
|
15
|
+
* API answers {@link IMAGE_UPDATING_CODE}, the exchange waits the
|
|
16
|
+
* `retryAfterSeconds` the answer names and asks again — by itself, for as long
|
|
17
|
+
* as the answer is the update and no longer: the workspace's states bound the
|
|
18
|
+
* wait, never a sleep budget, and `--timeout` bounds each exchange alone. The
|
|
19
|
+
* merchant is told once that the workspace is updating to the current version;
|
|
20
|
+
* the run's interrupt ends the wait.
|
|
21
|
+
*/
|
|
22
|
+
export class SyncImageUpdateWait {
|
|
23
|
+
field;
|
|
24
|
+
interrupt;
|
|
25
|
+
announced = false;
|
|
26
|
+
/**
|
|
27
|
+
* @param field the operation the exchange asks — named when the wait is interrupted.
|
|
28
|
+
* @param interrupt ends the wait when the run is interrupted.
|
|
29
|
+
*/
|
|
30
|
+
constructor(field, interrupt) {
|
|
31
|
+
this.field = field;
|
|
32
|
+
this.interrupt = interrupt;
|
|
33
|
+
}
|
|
34
|
+
/** Whether `error` is the admin API's answer that the workspace is updating. */
|
|
35
|
+
static isUpdating(error) {
|
|
36
|
+
return error instanceof AdminApiRefusal && error.code === IMAGE_UPDATING_CODE;
|
|
37
|
+
}
|
|
38
|
+
/** Wait out one update answer: tell the merchant once, then pause the seconds it names. */
|
|
39
|
+
async through(answer) {
|
|
40
|
+
const seconds = this.retryAfterSeconds(answer.variables);
|
|
41
|
+
this.announce(answer.variables, seconds);
|
|
42
|
+
if (await this.pause(seconds * MS_PER_SECOND))
|
|
43
|
+
return;
|
|
44
|
+
throw new Error(`Interrupted while the workspace updated to the current version, before the admin API answered ${this.field}.`);
|
|
45
|
+
}
|
|
46
|
+
/** The wait the answer names: a positive whole number of seconds, else the default. */
|
|
47
|
+
retryAfterSeconds(variables) {
|
|
48
|
+
const named = Number(variables.retryAfterSeconds);
|
|
49
|
+
if (!Number.isSafeInteger(named) || named <= 0)
|
|
50
|
+
return DEFAULT_RETRY_AFTER_SECONDS;
|
|
51
|
+
return named;
|
|
52
|
+
}
|
|
53
|
+
announce(variables, seconds) {
|
|
54
|
+
if (this.announced)
|
|
55
|
+
return;
|
|
56
|
+
this.announced = true;
|
|
57
|
+
const target = variables.currentImage ? ` (${variables.currentImage})` : '';
|
|
58
|
+
print(` update the workspace is updating to the current version${target}: sync asks again every ${String(seconds)} s until it answers`);
|
|
59
|
+
}
|
|
60
|
+
/** Pause `ms`: true once it elapsed, false when the run is interrupted. */
|
|
61
|
+
pause(ms) {
|
|
62
|
+
const interrupt = this.interrupt;
|
|
63
|
+
if (interrupt.aborted)
|
|
64
|
+
return Promise.resolve(false);
|
|
65
|
+
return new Promise((resolve) => {
|
|
66
|
+
const timer = setTimeout(() => {
|
|
67
|
+
interrupt.removeEventListener('abort', onInterrupt);
|
|
68
|
+
resolve(true);
|
|
69
|
+
}, ms);
|
|
70
|
+
function onInterrupt() {
|
|
71
|
+
clearTimeout(timer);
|
|
72
|
+
resolve(false);
|
|
73
|
+
}
|
|
74
|
+
interrupt.addEventListener('abort', onInterrupt, { once: true });
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=sync-image-update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-image-update.js","sourceRoot":"","sources":["../../../src/sync/sync-image-update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC1E,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAErC;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;AAE9D,gFAAgF;AAChF,MAAM,2BAA2B,GAAG,CAAC,CAAC;AAEtC,uEAAuE;AACvE,MAAM,aAAa,GAAG,IAAI,CAAC;AAE3B;;;;;;;;GAQG;AACH,MAAM,OAAO,mBAAmB;IAQX;IACA;IARX,SAAS,GAAG,KAAK,CAAC;IAE1B;;;OAGG;IACH,YACmB,KAAa,EACb,SAAsB;QADtB,UAAK,GAAL,KAAK,CAAQ;QACb,cAAS,GAAT,SAAS,CAAa;IACtC,CAAC;IAEJ,gFAAgF;IAChF,MAAM,CAAC,UAAU,CAAC,KAAc;QAC9B,OAAO,KAAK,YAAY,eAAe,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,CAAC;IAChF,CAAC;IAED,2FAA2F;IAC3F,KAAK,CAAC,OAAO,CAAC,MAAuB;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACzD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACzC,IAAI,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,aAAa,CAAC;YAAE,OAAO;QACtD,MAAM,IAAI,KAAK,CACb,iGAAiG,IAAI,CAAC,KAAK,GAAG,CAC/G,CAAC;IACJ,CAAC;IAED,uFAAuF;IAC/E,iBAAiB,CAAC,SAA2C;QACnE,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;YAAE,OAAO,2BAA2B,CAAC;QACnF,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,QAAQ,CAAC,SAA2C,EAAE,OAAe;QAC3E,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,MAAM,MAAM,GAAG,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5E,KAAK,CACH,gEAAgE,MAAM,2BAA2B,MAAM,CAAC,OAAO,CAAC,qBAAqB,CACtI,CAAC;IACJ,CAAC;IAED,2EAA2E;IACnE,KAAK,CAAC,EAAU;QACtB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QACjC,IAAI,SAAS,CAAC,OAAO;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACrD,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;YACtC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,SAAS,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;gBACpD,OAAO,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC,EAAE,EAAE,CAAC,CAAC;YACP,SAAS,WAAW;gBAClB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;YACD,SAAS,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -4,7 +4,9 @@ import type { SyncPulledBundle, SyncPushResult, SyncServingState } from './type/
|
|
|
4
4
|
* The admin API's three workspace-sync operations (#2781) — the surface
|
|
5
5
|
* `forgecart sync` reaches the shop through, over the {@link AdminApiClient}:
|
|
6
6
|
* every exchange is bounded by `--timeout` and ends when the run is
|
|
7
|
-
* interrupted, and answers are read field by field.
|
|
7
|
+
* interrupted, and answers are read field by field. A workspace updating to
|
|
8
|
+
* the current version (#2371) is no refusal: every operation waits it out and
|
|
9
|
+
* asks again ({@link SyncImageUpdateWait}).
|
|
8
10
|
*/
|
|
9
11
|
export declare class WorkspaceSyncClient {
|
|
10
12
|
private readonly api;
|
|
@@ -37,6 +39,14 @@ export declare class WorkspaceSyncClient {
|
|
|
37
39
|
* header; the boundary is the form's own.
|
|
38
40
|
*/
|
|
39
41
|
private uploadRequest;
|
|
42
|
+
/**
|
|
43
|
+
* POST one operation over the admin API and answer its root field, asking
|
|
44
|
+
* again for as long as the admin API answers that the workspace is updating
|
|
45
|
+
* to the current version — each ask its own exchange under `--timeout`.
|
|
46
|
+
*/
|
|
47
|
+
private exchange;
|
|
48
|
+
/** One exchange, then — for an update answer — the wait it names and the next ask. */
|
|
49
|
+
private exchangeThroughUpdate;
|
|
40
50
|
/** A pulled bundle's bytes against what it declares: its length, then its sha256. */
|
|
41
51
|
private assertDeclared;
|
|
42
52
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
+
import { SyncImageUpdateWait } from './sync-image-update.js';
|
|
2
3
|
/** The SDK's `WorkspaceSyncRetrieve` operation, verbatim. */
|
|
3
4
|
const STATE_DOCUMENT = `query WorkspaceSyncRetrieve {
|
|
4
5
|
workspaceSyncState {
|
|
@@ -37,7 +38,9 @@ const BUNDLE_FILE_NAME = 'serving.bundle';
|
|
|
37
38
|
* The admin API's three workspace-sync operations (#2781) — the surface
|
|
38
39
|
* `forgecart sync` reaches the shop through, over the {@link AdminApiClient}:
|
|
39
40
|
* every exchange is bounded by `--timeout` and ends when the run is
|
|
40
|
-
* interrupted, and answers are read field by field.
|
|
41
|
+
* interrupted, and answers are read field by field. A workspace updating to
|
|
42
|
+
* the current version (#2371) is no refusal: every operation waits it out and
|
|
43
|
+
* asks again ({@link SyncImageUpdateWait}).
|
|
41
44
|
*/
|
|
42
45
|
export class WorkspaceSyncClient {
|
|
43
46
|
api;
|
|
@@ -52,7 +55,7 @@ export class WorkspaceSyncClient {
|
|
|
52
55
|
}
|
|
53
56
|
/** The board's serving commit, read from the pod. */
|
|
54
57
|
async state() {
|
|
55
|
-
const result = await this.
|
|
58
|
+
const result = await this.exchange(this.api.jsonRequest(STATE_DOCUMENT, {}), 'workspaceSyncState');
|
|
56
59
|
return { servingSha: result.readString('servingSha') };
|
|
57
60
|
}
|
|
58
61
|
/**
|
|
@@ -61,7 +64,7 @@ export class WorkspaceSyncClient {
|
|
|
61
64
|
* reads it: a short or mismatched bundle is an error, and nothing is written.
|
|
62
65
|
*/
|
|
63
66
|
async bundle(sinceSha) {
|
|
64
|
-
const result = await this.
|
|
67
|
+
const result = await this.exchange(this.api.jsonRequest(BUNDLE_DOCUMENT, { input: { sinceSha } }), 'workspaceSyncBundle');
|
|
65
68
|
const bytes = Buffer.from(result.readString('data'), 'base64');
|
|
66
69
|
this.assertDeclared(bytes, result.readCount('byteLength'), result.readString('sha256'));
|
|
67
70
|
return {
|
|
@@ -76,7 +79,7 @@ export class WorkspaceSyncClient {
|
|
|
76
79
|
* without a bundle carries the lines alone.
|
|
77
80
|
*/
|
|
78
81
|
async push(bundle, envLines) {
|
|
79
|
-
const result = await this.
|
|
82
|
+
const result = await this.exchange(this.pushRequest(bundle, envLines), 'pushWorkspaceSync');
|
|
80
83
|
return {
|
|
81
84
|
accepted: result.readBoolean('accepted'),
|
|
82
85
|
servingSha: result.readNullableString('servingSha'),
|
|
@@ -114,6 +117,26 @@ export class WorkspaceSyncClient {
|
|
|
114
117
|
headers: { ...this.api.authHeaders(), 'apollo-require-preflight': 'true' },
|
|
115
118
|
};
|
|
116
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* POST one operation over the admin API and answer its root field, asking
|
|
122
|
+
* again for as long as the admin API answers that the workspace is updating
|
|
123
|
+
* to the current version — each ask its own exchange under `--timeout`.
|
|
124
|
+
*/
|
|
125
|
+
async exchange(request, field) {
|
|
126
|
+
return this.exchangeThroughUpdate(request, field, new SyncImageUpdateWait(field, this.interrupt));
|
|
127
|
+
}
|
|
128
|
+
/** One exchange, then — for an update answer — the wait it names and the next ask. */
|
|
129
|
+
async exchangeThroughUpdate(request, field, update) {
|
|
130
|
+
try {
|
|
131
|
+
return await this.api.exchange(request, field, this.interrupt);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
if (!SyncImageUpdateWait.isUpdating(error))
|
|
135
|
+
throw error;
|
|
136
|
+
await update.through(error);
|
|
137
|
+
}
|
|
138
|
+
return this.exchangeThroughUpdate(request, field, update);
|
|
139
|
+
}
|
|
117
140
|
/** A pulled bundle's bytes against what it declares: its length, then its sha256. */
|
|
118
141
|
assertDeclared(bytes, byteLength, sha256) {
|
|
119
142
|
if (bytes.length !== byteLength) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-sync.client.js","sourceRoot":"","sources":["../../../src/sync/workspace-sync.client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"workspace-sync.client.js","sourceRoot":"","sources":["../../../src/sync/workspace-sync.client.ts"],"names":[],"mappings":"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"}
|