@forgecart/cli 2.202610130131.0 → 2.202610130431.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 (67) hide show
  1. package/dist/src/admin-api/admin-api-refusal.error.d.ts +2 -2
  2. package/dist/src/admin-api/admin-api-refusal.error.js +2 -2
  3. package/dist/src/admin-api/admin-api.client.d.ts +8 -4
  4. package/dist/src/admin-api/admin-api.client.js +11 -9
  5. package/dist/src/admin-api/admin-api.client.js.map +1 -1
  6. package/dist/src/admin-api/admin-api.result.d.ts +7 -0
  7. package/dist/src/admin-api/admin-api.result.js +31 -2
  8. package/dist/src/admin-api/admin-api.result.js.map +1 -1
  9. package/dist/src/authorization/cli-authorization-flow.d.ts +21 -14
  10. package/dist/src/authorization/cli-authorization-flow.js +40 -31
  11. package/dist/src/authorization/cli-authorization-flow.js.map +1 -1
  12. package/dist/src/authorization/cli-credential-check.d.ts +6 -13
  13. package/dist/src/authorization/cli-credential-check.js +6 -23
  14. package/dist/src/authorization/cli-credential-check.js.map +1 -1
  15. package/dist/src/authorization/cli-credential-step.d.ts +74 -0
  16. package/dist/src/authorization/cli-credential-step.js +154 -0
  17. package/dist/src/authorization/cli-credential-step.js.map +1 -0
  18. package/dist/src/authorization/cli-unauthorized-refusal.d.ts +18 -8
  19. package/dist/src/authorization/cli-unauthorized-refusal.js +26 -11
  20. package/dist/src/authorization/cli-unauthorized-refusal.js.map +1 -1
  21. package/dist/src/authorization/type/cli-authorization.types.d.ts +36 -4
  22. package/dist/src/authorization/type/cli-authorization.types.js +16 -3
  23. package/dist/src/authorization/type/cli-authorization.types.js.map +1 -1
  24. package/dist/src/commands/init.d.ts +0 -10
  25. package/dist/src/commands/init.js +17 -42
  26. package/dist/src/commands/init.js.map +1 -1
  27. package/dist/src/commands/sync.js +2 -2
  28. package/dist/src/commands/sync.js.map +1 -1
  29. package/dist/src/deploy/deploy.runner.d.ts +15 -8
  30. package/dist/src/deploy/deploy.runner.js +19 -10
  31. package/dist/src/deploy/deploy.runner.js.map +1 -1
  32. package/dist/src/sync/sync-bundle-push.d.ts +34 -0
  33. package/dist/src/sync/sync-bundle-push.js +97 -0
  34. package/dist/src/sync/sync-bundle-push.js.map +1 -0
  35. package/dist/src/sync/sync-dotenv.file.d.ts +30 -22
  36. package/dist/src/sync/sync-dotenv.file.js +49 -54
  37. package/dist/src/sync/sync-dotenv.file.js.map +1 -1
  38. package/dist/src/sync/sync-env-channel.d.ts +47 -0
  39. package/dist/src/sync/sync-env-channel.js +106 -0
  40. package/dist/src/sync/sync-env-channel.js.map +1 -0
  41. package/dist/src/sync/sync-env.runner.d.ts +26 -10
  42. package/dist/src/sync/sync-env.runner.js +73 -40
  43. package/dist/src/sync/sync-env.runner.js.map +1 -1
  44. package/dist/src/sync/sync-record.file.d.ts +18 -10
  45. package/dist/src/sync/sync-record.file.js +30 -10
  46. package/dist/src/sync/sync-record.file.js.map +1 -1
  47. package/dist/src/sync/sync-repository.d.ts +7 -2
  48. package/dist/src/sync/sync-repository.js +26 -5
  49. package/dist/src/sync/sync-repository.js.map +1 -1
  50. package/dist/src/sync/sync-round.d.ts +28 -15
  51. package/dist/src/sync/sync-round.js +78 -39
  52. package/dist/src/sync/sync-round.js.map +1 -1
  53. package/dist/src/sync/sync-watch.d.ts +2 -1
  54. package/dist/src/sync/sync-watch.js +2 -1
  55. package/dist/src/sync/sync-watch.js.map +1 -1
  56. package/dist/src/sync/sync.runner.d.ts +16 -8
  57. package/dist/src/sync/sync.runner.js +30 -26
  58. package/dist/src/sync/sync.runner.js.map +1 -1
  59. package/dist/src/sync/type/sync.types.d.ts +78 -16
  60. package/dist/src/sync/type/sync.types.js.map +1 -1
  61. package/dist/src/sync/workspace-sync.client.d.ts +43 -16
  62. package/dist/src/sync/workspace-sync.client.js +125 -31
  63. package/dist/src/sync/workspace-sync.client.js.map +1 -1
  64. package/dist/src/util/dotenv.util.d.ts +19 -5
  65. package/dist/src/util/dotenv.util.js +42 -5
  66. package/dist/src/util/dotenv.util.js.map +1 -1
  67. package/package.json +1 -1
@@ -1,11 +1,11 @@
1
- import { createHash } from 'node:crypto';
2
1
  import { mkdir, stat } from 'node:fs/promises';
3
2
  import { resolve } from 'node:path';
4
3
  import { AdminApiClient } from '../admin-api/admin-api.client.js';
5
- import { CliCredentialCheck } from '../authorization/cli-credential-check.js';
4
+ import { CliCredentialStep } from '../authorization/cli-credential-step.js';
6
5
  import { QuestionPromptAdapter } from '../question/question-prompt.adapter.js';
6
+ import { SyncBundlePush } from './sync-bundle-push.js';
7
7
  import { SyncDivergenceSelection } from './sync-divergence.js';
8
- import { SyncDotenvFile } from './sync-dotenv.file.js';
8
+ import { SyncEnvChannel } from './sync-env-channel.js';
9
9
  import { SyncRecordFile } from './sync-record.file.js';
10
10
  import { SyncRepository } from './sync-repository.js';
11
11
  import { SyncRound } from './sync-round.js';
@@ -13,11 +13,15 @@ import { SyncWatch } from './sync-watch.js';
13
13
  import { WorkspaceSyncClient } from './workspace-sync.client.js';
14
14
  /**
15
15
  * `forgecart sync [name]` (#2781): keep the storefront's tree and the board's
16
- * serving tree the same tree. Before anything leaves the machine the run
17
- * settles its four credentials — the environment, then the storefront's `.env`,
18
- * then its `.forgecart/config.json`, exactly as `init` reads them; a key in no
19
- * source exits 3 with nothing sent — and needs `git` on the PATH. Then it runs
20
- * ONE round, or, with `--watch`, a round whenever a side moves until Ctrl-C.
16
+ * serving tree the same tree. The run first checks what it needs locally:
17
+ * `git` on the PATH, and the storefront. It then reads its four credentials
18
+ * through the credential step (launch#62 N3), from the environment, then the
19
+ * storefront's `.env`, then its `.forgecart/config.json`. When a key is in no
20
+ * source, or the admin API refuses the credentials, the step authorizes this
21
+ * machine at `/authorize` and writes the four delivered keys into `.env`.
22
+ * Without a terminal the step prints the URL and the code, waits for the
23
+ * authorization's window, and exits 3. Then the run does ONE round, or, with
24
+ * `--watch`, a round whenever a side moves until Ctrl-C.
21
25
  */
22
26
  export class SyncRunner {
23
27
  name;
@@ -33,15 +37,10 @@ export class SyncRunner {
33
37
  async run() {
34
38
  this.assertFlags();
35
39
  const storefront = this.name ? resolve(process.cwd(), this.name) : process.cwd();
36
- const credentials = await CliCredentialCheck.settle(storefront);
37
40
  await SyncRepository.assertGitOnPath();
38
41
  await this.assertStorefront(storefront);
39
- if (this.options.watch === true) {
40
- await this.watch(storefront, credentials);
41
- return;
42
- }
43
- const { round } = this.assemble(storefront, credentials, new AbortController().signal);
44
- await round.run();
42
+ const step = new CliCredentialStep({ targetDir: storefront });
43
+ await step.run(async (credentials) => this.sync(storefront, credentials));
45
44
  }
46
45
  /** `--dry-run` plans one round and moves nothing; it cannot watch. */
47
46
  assertFlags() {
@@ -49,15 +48,26 @@ export class SyncRunner {
49
48
  return;
50
49
  throw new Error('--dry-run plans one round and moves nothing, so it cannot --watch.');
51
50
  }
52
- /** The storefront must be a directory — `--pull` makes a new one to take the workspace's tree into. */
51
+ /**
52
+ * The storefront must be a directory. `--pull` may name a new one, which
53
+ * {@link sync} makes once the credentials are settled, so an authorization
54
+ * that ends unapproved leaves no directory behind.
55
+ */
53
56
  async assertStorefront(storefront) {
54
- if (await this.isDirectory(storefront))
57
+ if (this.options.pull === true || (await this.isDirectory(storefront)))
55
58
  return;
56
- if (this.options.pull === true) {
59
+ throw new Error(`No storefront at ${storefront}: name an existing directory, or pass --pull to take the workspace's tree into a new one.`);
60
+ }
61
+ /** ONE round — or, with `--watch`, rounds until Ctrl-C — on the settled credentials. */
62
+ async sync(storefront, credentials) {
63
+ if (this.options.pull === true)
57
64
  await mkdir(storefront, { recursive: true });
65
+ if (this.options.watch === true) {
66
+ await this.watch(storefront, credentials);
58
67
  return;
59
68
  }
60
- throw new Error(`No storefront at ${storefront}: name an existing directory, or pass --pull to take the workspace's tree into a new one.`);
69
+ const { round } = this.assemble(storefront, credentials, new AbortController().signal);
70
+ await round.run();
61
71
  }
62
72
  /** Watch until Ctrl-C, which ends the run in flight and prints where it stood. */
63
73
  async watch(storefront, credentials) {
@@ -79,15 +89,9 @@ export class SyncRunner {
79
89
  const pullOnly = this.options.pull === true;
80
90
  const client = new WorkspaceSyncClient(new AdminApiClient(credentials, this.options.timeout), interrupt);
81
91
  const repository = new SyncRepository(storefront);
82
- const round = new SyncRound({ storefront: this.displayName(), pullOnly, dryRun: this.options.dryRun === true }, credentials, client, repository, new SyncRecordFile(storefront, this.channelOf(credentials)), new SyncDotenvFile(storefront), new SyncDivergenceSelection(new QuestionPromptAdapter(this.options), pullOnly));
92
+ const round = new SyncRound({ storefront: this.displayName(), pullOnly, dryRun: this.options.dryRun === true }, credentials, client, new SyncBundlePush(client), repository, new SyncRecordFile(storefront, credentials.channelToken), new SyncEnvChannel(storefront), new SyncDivergenceSelection(new QuestionPromptAdapter(this.options), pullOnly));
83
93
  return { client, repository, round };
84
94
  }
85
- /** The channel a record belongs to: a digest of the admin API and the channel token — never the token. */
86
- channelOf(credentials) {
87
- return createHash('sha256')
88
- .update(`${credentials.adminApiUrl}\n${credentials.channelToken}`)
89
- .digest('hex');
90
- }
91
95
  /** The storefront as the merchant named it. */
92
96
  displayName() {
93
97
  return this.name ?? '.';
@@ -1 +1 @@
1
- {"version":3,"file":"sync.runner.js","sourceRoot":"","sources":["../../../src/sync/sync.runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync.runner.js","sourceRoot":"","sources":["../../../src/sync/sync.runner.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { QuestionPromptInput } from '../../question/type/question-prompt.input.js';
2
+ import type { StorefrontEnvFile } from '../../util/dotenv.util.js';
2
3
  /**
3
4
  * `forgecart sync`'s options as commander parses them (#2781), beside the three
4
5
  * flags every questioning command carries — they answer the divergence
@@ -19,13 +20,30 @@ export interface SyncOptions extends QuestionPromptInput {
19
20
  export interface SyncEnvOptions {
20
21
  merge?: boolean;
21
22
  }
22
- /** What `forgecart sync-env` answers — the report the admin API parses. */
23
- export interface SyncEnvReport {
24
- /** The merchant lines of the storefront's `.env` once the run is done. */
23
+ /** One env file's merchant lines, as the env channel carries them. */
24
+ export interface SyncEnvFileLines {
25
+ file: StorefrontEnvFile;
25
26
  lines: string[];
26
- /** How many merchant keys a merge carried in; 0 for a read. */
27
+ }
28
+ /** How many merchant keys a merge carried into one env file. */
29
+ export interface SyncEnvFileMerge {
30
+ file: StorefrontEnvFile;
31
+ merged: number;
32
+ }
33
+ /** One env file in `forgecart sync-env`'s report: its merchant lines once the run is done, and the keys a merge carried in. */
34
+ export interface SyncEnvReportFile extends SyncEnvFileLines {
35
+ /** How many merchant keys a merge carried into the file; 0 for a read. */
27
36
  merged: number;
28
37
  }
38
+ /** What `forgecart sync-env` answers — the report the admin API parses: one entry per env file the storefront holds. */
39
+ export interface SyncEnvReport {
40
+ files: SyncEnvReportFile[];
41
+ }
42
+ /**
43
+ * What travelled through the env channel, file by file: for each env file, a
44
+ * digest of every merchant line as it last travelled, keyed by its key.
45
+ */
46
+ export type SyncEnvDigests = Partial<Record<StorefrontEnvFile, Record<string, string>>>;
29
47
  /** The board's serving branch, as the admin API reads it from the pod. */
30
48
  export interface SyncServingState {
31
49
  servingSha: string;
@@ -35,8 +53,37 @@ export interface SyncPulledBundle {
35
53
  /** The commit it is cut from; empty for the whole board. */
36
54
  sinceSha: string;
37
55
  bytes: Buffer;
38
- /** The merchant lines of the workspace's `.env`. */
39
- envLines: string[];
56
+ /** The merchant lines of every env file the workspace holds, file by file. */
57
+ envFiles: SyncEnvFileLines[];
58
+ }
59
+ /**
60
+ * A bundle as a chunked push declares it (factory task 2375): its byte length
61
+ * and sha256, the length of every part but the last, and each part's sha256 in
62
+ * index order.
63
+ */
64
+ export interface SyncBundleDeclaration {
65
+ byteLength: number;
66
+ sha256: string;
67
+ partBytes: number;
68
+ partSha256s: string[];
69
+ }
70
+ /** One part of a bundle a chunked push sends: its index, its bytes and their sha256. */
71
+ export interface SyncBundlePart {
72
+ index: number;
73
+ bytes: Buffer;
74
+ sha256: string;
75
+ }
76
+ /**
77
+ * The upload the admin API answered a chunked push's begin or part with: its
78
+ * id, the bundle it declares, and the indexes of the parts it holds, ascending.
79
+ */
80
+ export interface SyncUpload {
81
+ id: string;
82
+ byteLength: number;
83
+ sha256: string;
84
+ partBytes: number;
85
+ partCount: number;
86
+ heldParts: number[];
40
87
  }
41
88
  /** What the admin API answered a push. */
42
89
  export interface SyncPushResult {
@@ -45,17 +92,18 @@ export interface SyncPushResult {
45
92
  gateMessages: string[];
46
93
  runtimeError: string | null;
47
94
  seoFindings: string[];
48
- envKeys: number;
95
+ /** How many merchant keys the push merged into each env file it carried. */
96
+ envFiles: SyncEnvFileMerge[];
49
97
  }
50
98
  /**
51
99
  * The last sync, recorded under `.forgecart/sync/`: the channel it was against,
52
100
  * the serving commit the laptop's tree last matched, and a digest of every
53
- * merchant `.env` line as it last travelled.
101
+ * merchant line of every env file as it last travelled, file by file.
54
102
  */
55
103
  export interface SyncRecord {
56
104
  channel: string;
57
105
  servingSha: string;
58
- env: Record<string, string>;
106
+ env: SyncEnvDigests;
59
107
  }
60
108
  /** How a path differs between two trees (`git diff-tree`'s status letters). */
61
109
  export declare enum SyncChangeKind {
@@ -76,13 +124,13 @@ export interface SyncMaterialized {
76
124
  }
77
125
  /**
78
126
  * The serving branch, held in the private repository: its commit, the tree of
79
- * it that travels, and the merchant `.env` lines its bundle carried — null when
127
+ * it that travels, and the workspace's env files its bundle carried — null when
80
128
  * the commit was already held and no bundle was read.
81
129
  */
82
130
  export interface SyncServing {
83
131
  sha: string;
84
132
  tree: string;
85
- envLines: string[] | null;
133
+ envFiles: SyncEnvFileLines[] | null;
86
134
  }
87
135
  /** A round's view: the record, and the three trees it compares. */
88
136
  export interface SyncView {
@@ -122,10 +170,10 @@ export type SyncAttempt = {
122
170
  kind: 'moved';
123
171
  point: SyncDivergencePoint;
124
172
  };
125
- /** The `.env` lines a round sent alone: how many keys the workspace merged, and the digests to record. */
173
+ /** The env lines a round sent alone: how many keys the workspace merged, and the digests to record. */
126
174
  export interface SyncSentEnv {
127
175
  merged: number;
128
- digests: Record<string, string>;
176
+ digests: SyncEnvDigests;
129
177
  }
130
178
  /** What one round needs to know of its run. */
131
179
  export interface SyncRoundOptions {
@@ -136,13 +184,27 @@ export interface SyncRoundOptions {
136
184
  /** `--dry-run`: the round plans and moves nothing. */
137
185
  dryRun: boolean;
138
186
  }
139
- /** The merchant `.env` lines a push carries, and the digests the record takes once they landed. */
187
+ /**
188
+ * The merchant lines a push carries — one entry per env file the laptop holds,
189
+ * its lines changed since they last travelled — and the digests the record
190
+ * takes once they landed.
191
+ */
140
192
  export interface SyncOutgoingEnv {
193
+ files: SyncEnvFileLines[];
194
+ digests: SyncEnvDigests;
195
+ }
196
+ /** What taking the workspace's env lines did: the keys taken across every file, and the digests the record takes. */
197
+ export interface SyncTakenEnv {
198
+ taken: number;
199
+ digests: SyncEnvDigests;
200
+ }
201
+ /** One env file's merchant lines a push carries, and the digests to record for it once they landed. */
202
+ export interface SyncDotenvOutgoing {
141
203
  lines: string[];
142
204
  digests: Record<string, string>;
143
205
  }
144
- /** What taking the workspace's `.env` lines did: the keys taken, and the digests the record takes. */
145
- export interface SyncTakenEnv {
206
+ /** What taking the workspace's lines into one env file did: the keys taken, and the file's digests to record. */
207
+ export interface SyncDotenvTaken {
146
208
  taken: number;
147
209
  digests: Record<string, string>;
148
210
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sync.types.js","sourceRoot":"","sources":["../../../../src/sync/type/sync.types.ts"],"names":[],"mappings":"AAmEA,+EAA+E;AAC/E,MAAM,CAAN,IAAY,cAKX;AALD,WAAY,cAAc;IACxB,6BAAW,CAAA;IACX,+BAAa,CAAA;IACb,gCAAc,CAAA;IACd,oCAAkB,CAAA;AACpB,CAAC,EALW,cAAc,KAAd,cAAc,QAKzB;AA4CD,0CAA0C;AAC1C,MAAM,CAAN,IAAY,WAWX;AAXD,WAAY,WAAW;IACrB,6CAA6C;IAC7C,kCAAmB,CAAA;IACnB,uEAAuE;IACvE,4BAAa,CAAA;IACb,kEAAkE;IAClE,4BAAa,CAAA;IACb,oEAAoE;IACpE,wCAAyB,CAAA;IACzB,2DAA2D;IAC3D,oCAAqB,CAAA;AACvB,CAAC,EAXW,WAAW,KAAX,WAAW,QAWtB;AAmCD,mFAAmF;AACnF,MAAM,CAAN,IAAY,oBAIX;AAJD,WAAY,oBAAoB;IAC9B,uCAAe,CAAA;IACf,+CAAuB,CAAA;IACvB,uCAAe,CAAA;AACjB,CAAC,EAJW,oBAAoB,KAApB,oBAAoB,QAI/B"}
1
+ {"version":3,"file":"sync.types.js","sourceRoot":"","sources":["../../../../src/sync/type/sync.types.ts"],"names":[],"mappings":"AA0HA,+EAA+E;AAC/E,MAAM,CAAN,IAAY,cAKX;AALD,WAAY,cAAc;IACxB,6BAAW,CAAA;IACX,+BAAa,CAAA;IACb,gCAAc,CAAA;IACd,oCAAkB,CAAA;AACpB,CAAC,EALW,cAAc,KAAd,cAAc,QAKzB;AA4CD,0CAA0C;AAC1C,MAAM,CAAN,IAAY,WAWX;AAXD,WAAY,WAAW;IACrB,6CAA6C;IAC7C,kCAAmB,CAAA;IACnB,uEAAuE;IACvE,4BAAa,CAAA;IACb,kEAAkE;IAClE,4BAAa,CAAA;IACb,oEAAoE;IACpE,wCAAyB,CAAA;IACzB,2DAA2D;IAC3D,oCAAqB,CAAA;AACvB,CAAC,EAXW,WAAW,KAAX,WAAW,QAWtB;AAmDD,mFAAmF;AACnF,MAAM,CAAN,IAAY,oBAIX;AAJD,WAAY,oBAAoB;IAC9B,uCAAe,CAAA;IACf,+CAAuB,CAAA;IACvB,uCAAe,CAAA;AACjB,CAAC,EAJW,oBAAoB,KAApB,oBAAoB,QAI/B"}
@@ -1,12 +1,15 @@
1
1
  import type { AdminApiClient } from '../admin-api/admin-api.client.js';
2
- import type { SyncPulledBundle, SyncPushResult, SyncServingState } from './type/sync.types.js';
2
+ import type { SyncBundleDeclaration, SyncBundlePart, SyncEnvFileLines, SyncPulledBundle, SyncPushResult, SyncServingState, SyncUpload } from './type/sync.types.js';
3
3
  /**
4
- * The admin API's three workspace-sync operations (#2781) — the surface
5
- * `forgecart sync` reaches the shop through, over the {@link AdminApiClient}:
6
- * every exchange is bounded by `--timeout` and ends when the run is
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}).
4
+ * The admin API's workspace-sync operations (#2781) — the reads of the serving
5
+ * branch, the push, and the begin and the parts of a chunked push (factory task
6
+ * 2375) — the surface `forgecart sync` reaches the shop through, over the
7
+ * {@link AdminApiClient}: every exchange is bounded by `--timeout` and ends
8
+ * when the run is interrupted, and answers are read field by field.
9
+ * Credentials the API refuses are a `CliCredentialsRefusal`, which the
10
+ * credential step answers by authorizing. A workspace updating to the current
11
+ * version (#2371) is no refusal: every operation waits it out and asks again
12
+ * ({@link SyncImageUpdateWait}).
10
13
  */
11
14
  export declare class WorkspaceSyncClient {
12
15
  private readonly api;
@@ -26,19 +29,37 @@ export declare class WorkspaceSyncClient {
26
29
  bundle(sinceSha: string): Promise<SyncPulledBundle>;
27
30
  /**
28
31
  * Push `bundle` — the laptop's tree as one commit cut on the serving tip — as
29
- * an authenticated upload, with the merchant `.env` lines `envLines`; a push
30
- * without a bundle carries the lines alone.
32
+ * an authenticated upload, with the merchant lines of the env files
33
+ * `envFiles`, file by file; a push without a bundle carries the lines alone.
31
34
  */
32
- push(bundle: Buffer | null, envLines: readonly string[]): Promise<SyncPushResult>;
33
- /** A push with a bundle is an upload; one with `.env` lines alone is plain JSON. */
34
- private pushRequest;
35
+ push(bundle: Buffer | null, envFiles: readonly SyncEnvFileLines[]): Promise<SyncPushResult>;
36
+ /**
37
+ * Begin the chunked push of the bundle `declaration` declares — or, for a
38
+ * bundle the workspace already holds parts of, answer that same upload
39
+ * again — and answer the upload with the parts it holds.
40
+ */
41
+ beginUpload(declaration: SyncBundleDeclaration): Promise<SyncUpload>;
42
+ /** Send ONE part of the upload `uploadId` as an authenticated upload carrying its sha256. */
43
+ pushPart(uploadId: string, part: SyncBundlePart): Promise<SyncUpload>;
35
44
  /**
36
- * The push as a GraphQL multipart request: the operation, the map naming the
37
- * bundle's variable, and the bundle itself, declared by its byte length and
38
- * sha256. The admin API reads a multipart request only with the preflight
39
- * header; the boundary is the form's own.
45
+ * Land the parts the upload `uploadId` holds as ONE bundle, with the
46
+ * merchant lines of the env files `envFiles`, file by file — a push naming
47
+ * its upload, carrying no bundle.
40
48
  */
49
+ land(uploadId: string, envFiles: readonly SyncEnvFileLines[]): Promise<SyncPushResult>;
50
+ /** Send a push and read what it did. */
51
+ private pushed;
52
+ /** A push with a bundle is an upload; one with env lines alone is plain JSON. */
53
+ private pushRequest;
54
+ /** The push carrying its bundle whole, declared by its byte length and sha256. */
41
55
  private uploadRequest;
56
+ /**
57
+ * An operation carrying a file, as a GraphQL multipart request: the
58
+ * operation with `input`, the map naming the file's `variable`, and the
59
+ * file's `bytes`. The admin API reads a multipart request only with the
60
+ * preflight header; the boundary is the form's own.
61
+ */
62
+ private fileRequest;
42
63
  /**
43
64
  * POST one operation over the admin API and answer its root field, asking
44
65
  * again for as long as the admin API answers that the workspace is updating
@@ -49,4 +70,10 @@ export declare class WorkspaceSyncClient {
49
70
  private exchangeThroughUpdate;
50
71
  /** A pulled bundle's bytes against what it declares: its length, then its sha256. */
51
72
  private assertDeclared;
73
+ /** A chunked push's upload, read field by field. */
74
+ private readUpload;
75
+ /** The workspace's env files: one entry each, naming an env file a storefront reads, with its lines. */
76
+ private readEnvFiles;
77
+ /** How many merchant keys a push merged into each env file it carried. */
78
+ private readEnvMerges;
52
79
  }
@@ -1,4 +1,5 @@
1
1
  import { createHash } from 'node:crypto';
2
+ import { isStorefrontEnvFile } from '../util/dotenv.util.js';
2
3
  import { SyncImageUpdateWait } from './sync-image-update.js';
3
4
  /** The SDK's `WorkspaceSyncRetrieve` operation, verbatim. */
4
5
  const STATE_DOCUMENT = `query WorkspaceSyncRetrieve {
@@ -15,7 +16,10 @@ const BUNDLE_DOCUMENT = `query WorkspaceSyncPull($input: WorkspaceSyncBundleInpu
15
16
  byteLength
16
17
  sha256
17
18
  data
18
- envLines
19
+ envFiles {
20
+ file
21
+ lines
22
+ }
19
23
  }
20
24
  }`;
21
25
  /** The SDK's `WorkspaceSyncPush` operation, verbatim. */
@@ -27,20 +31,54 @@ const PUSH_DOCUMENT = `mutation WorkspaceSyncPush($input: PushWorkspaceSyncInput
27
31
  gateMessages
28
32
  runtimeError
29
33
  seoFindings
30
- envKeys
34
+ envFiles {
35
+ file
36
+ merged
37
+ }
38
+ }
39
+ }`;
40
+ /** The SDK's `WorkspaceSyncBeginUpload` operation, verbatim. */
41
+ const BEGIN_DOCUMENT = `mutation WorkspaceSyncBeginUpload($input: BeginWorkspaceSyncUploadInput!) {
42
+ beginWorkspaceSyncUpload(input: $input) {
43
+ id
44
+ byteLength
45
+ sha256
46
+ partBytes
47
+ partCount
48
+ heldParts
49
+ }
50
+ }`;
51
+ /** The SDK's `WorkspaceSyncPushPart` operation, verbatim. */
52
+ const PART_DOCUMENT = `mutation WorkspaceSyncPushPart($input: PushWorkspaceSyncPartInput!) {
53
+ pushWorkspaceSyncPart(input: $input) {
54
+ id
55
+ byteLength
56
+ sha256
57
+ partBytes
58
+ partCount
59
+ heldParts
31
60
  }
32
61
  }`;
33
- /** The multipart part a push's bundle travels in, and the variable it answers (GraphQL multipart request spec). */
34
- const BUNDLE_PART = '0';
62
+ /**
63
+ * The multipart part a file travels in, and the variables a push's bundle and
64
+ * a part's bytes answer, each under its file name (GraphQL multipart request
65
+ * spec).
66
+ */
67
+ const FILE_PART = '0';
35
68
  const BUNDLE_VARIABLE = 'variables.input.bundle';
36
69
  const BUNDLE_FILE_NAME = 'serving.bundle';
70
+ const PART_VARIABLE = 'variables.input.part';
71
+ const PART_FILE_NAME = 'serving.bundle.part';
37
72
  /**
38
- * The admin API's three workspace-sync operations (#2781) — the surface
39
- * `forgecart sync` reaches the shop through, over the {@link AdminApiClient}:
40
- * every exchange is bounded by `--timeout` and ends when the run is
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}).
73
+ * The admin API's workspace-sync operations (#2781) — the reads of the serving
74
+ * branch, the push, and the begin and the parts of a chunked push (factory task
75
+ * 2375) — the surface `forgecart sync` reaches the shop through, over the
76
+ * {@link AdminApiClient}: every exchange is bounded by `--timeout` and ends
77
+ * when the run is interrupted, and answers are read field by field.
78
+ * Credentials the API refuses are a `CliCredentialsRefusal`, which the
79
+ * credential step answers by authorizing. A workspace updating to the current
80
+ * version (#2371) is no refusal: every operation waits it out and asks again
81
+ * ({@link SyncImageUpdateWait}).
44
82
  */
45
83
  export class WorkspaceSyncClient {
46
84
  api;
@@ -70,48 +108,79 @@ export class WorkspaceSyncClient {
70
108
  return {
71
109
  sinceSha: result.readText('sinceSha'),
72
110
  bytes,
73
- envLines: result.readStringList('envLines'),
111
+ envFiles: this.readEnvFiles(result),
74
112
  };
75
113
  }
76
114
  /**
77
115
  * Push `bundle` — the laptop's tree as one commit cut on the serving tip — as
78
- * an authenticated upload, with the merchant `.env` lines `envLines`; a push
79
- * without a bundle carries the lines alone.
116
+ * an authenticated upload, with the merchant lines of the env files
117
+ * `envFiles`, file by file; a push without a bundle carries the lines alone.
118
+ */
119
+ async push(bundle, envFiles) {
120
+ return this.pushed(this.pushRequest(bundle, envFiles));
121
+ }
122
+ /**
123
+ * Begin the chunked push of the bundle `declaration` declares — or, for a
124
+ * bundle the workspace already holds parts of, answer that same upload
125
+ * again — and answer the upload with the parts it holds.
126
+ */
127
+ async beginUpload(declaration) {
128
+ const result = await this.exchange(this.api.jsonRequest(BEGIN_DOCUMENT, { input: declaration }), 'beginWorkspaceSyncUpload');
129
+ return this.readUpload(result);
130
+ }
131
+ /** Send ONE part of the upload `uploadId` as an authenticated upload carrying its sha256. */
132
+ async pushPart(uploadId, part) {
133
+ const input = { uploadId, index: part.index, sha256: part.sha256, part: null };
134
+ const result = await this.exchange(this.fileRequest(PART_DOCUMENT, input, PART_VARIABLE, part.bytes, PART_FILE_NAME), 'pushWorkspaceSyncPart');
135
+ return this.readUpload(result);
136
+ }
137
+ /**
138
+ * Land the parts the upload `uploadId` holds as ONE bundle, with the
139
+ * merchant lines of the env files `envFiles`, file by file — a push naming
140
+ * its upload, carrying no bundle.
80
141
  */
81
- async push(bundle, envLines) {
82
- const result = await this.exchange(this.pushRequest(bundle, envLines), 'pushWorkspaceSync');
142
+ async land(uploadId, envFiles) {
143
+ return this.pushed(this.api.jsonRequest(PUSH_DOCUMENT, { input: { uploadId, envFiles } }));
144
+ }
145
+ /** Send a push and read what it did. */
146
+ async pushed(request) {
147
+ const result = await this.exchange(request, 'pushWorkspaceSync');
83
148
  return {
84
149
  accepted: result.readBoolean('accepted'),
85
150
  servingSha: result.readNullableString('servingSha'),
86
151
  gateMessages: result.readStringList('gateMessages'),
87
152
  runtimeError: result.readNullableString('runtimeError'),
88
153
  seoFindings: result.readStringList('seoFindings'),
89
- envKeys: result.readCount('envKeys'),
154
+ envFiles: this.readEnvMerges(result),
90
155
  };
91
156
  }
92
- /** A push with a bundle is an upload; one with `.env` lines alone is plain JSON. */
93
- pushRequest(bundle, envLines) {
157
+ /** A push with a bundle is an upload; one with env lines alone is plain JSON. */
158
+ pushRequest(bundle, envFiles) {
94
159
  if (bundle === null)
95
- return this.api.jsonRequest(PUSH_DOCUMENT, { input: { envLines } });
96
- return this.uploadRequest(bundle, envLines);
160
+ return this.api.jsonRequest(PUSH_DOCUMENT, { input: { envFiles } });
161
+ return this.uploadRequest(bundle, envFiles);
97
162
  }
98
- /**
99
- * The push as a GraphQL multipart request: the operation, the map naming the
100
- * bundle's variable, and the bundle itself, declared by its byte length and
101
- * sha256. The admin API reads a multipart request only with the preflight
102
- * header; the boundary is the form's own.
103
- */
104
- uploadRequest(bundle, envLines) {
163
+ /** The push carrying its bundle whole, declared by its byte length and sha256. */
164
+ uploadRequest(bundle, envFiles) {
105
165
  const input = {
106
166
  bundle: null,
107
167
  byteLength: bundle.length,
108
168
  sha256: createHash('sha256').update(bundle).digest('hex'),
109
- envLines,
169
+ envFiles,
110
170
  };
171
+ return this.fileRequest(PUSH_DOCUMENT, input, BUNDLE_VARIABLE, bundle, BUNDLE_FILE_NAME);
172
+ }
173
+ /**
174
+ * An operation carrying a file, as a GraphQL multipart request: the
175
+ * operation with `input`, the map naming the file's `variable`, and the
176
+ * file's `bytes`. The admin API reads a multipart request only with the
177
+ * preflight header; the boundary is the form's own.
178
+ */
179
+ fileRequest(document, input, variable, bytes, fileName) {
111
180
  const form = new FormData();
112
- form.append('operations', JSON.stringify({ query: PUSH_DOCUMENT, variables: { input } }));
113
- form.append('map', JSON.stringify({ [BUNDLE_PART]: [BUNDLE_VARIABLE] }));
114
- form.append(BUNDLE_PART, new Blob([new Uint8Array(bundle)]), BUNDLE_FILE_NAME);
181
+ form.append('operations', JSON.stringify({ query: document, variables: { input } }));
182
+ form.append('map', JSON.stringify({ [FILE_PART]: [variable] }));
183
+ form.append(FILE_PART, new Blob([new Uint8Array(bytes)]), fileName);
115
184
  return {
116
185
  body: form,
117
186
  headers: { ...this.api.authHeaders(), 'apollo-require-preflight': 'true' },
@@ -146,5 +215,30 @@ export class WorkspaceSyncClient {
146
215
  throw new Error('The pulled bundle does not hash to the sha256 it declares; nothing was written.');
147
216
  }
148
217
  }
218
+ /** A chunked push's upload, read field by field. */
219
+ readUpload(result) {
220
+ return {
221
+ id: result.readString('id'),
222
+ byteLength: result.readCount('byteLength'),
223
+ sha256: result.readString('sha256'),
224
+ partBytes: result.readCount('partBytes'),
225
+ partCount: result.readCount('partCount'),
226
+ heldParts: result.readCountList('heldParts'),
227
+ };
228
+ }
229
+ /** The workspace's env files: one entry each, naming an env file a storefront reads, with its lines. */
230
+ readEnvFiles(result) {
231
+ return result.readObjectList('envFiles').map((entry) => ({
232
+ file: entry.readMember('file', isStorefrontEnvFile),
233
+ lines: entry.readStringList('lines'),
234
+ }));
235
+ }
236
+ /** How many merchant keys a push merged into each env file it carried. */
237
+ readEnvMerges(result) {
238
+ return result.readObjectList('envFiles').map((entry) => ({
239
+ file: entry.readMember('file', isStorefrontEnvFile),
240
+ merged: entry.readCount('merged'),
241
+ }));
242
+ }
149
243
  }
150
244
  //# sourceMappingURL=workspace-sync.client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-sync.client.js","sourceRoot":"","sources":["../../../src/sync/workspace-sync.client.ts"],"names":[],"mappings":"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"}
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;AAKzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAY7D,6DAA6D;AAC7D,MAAM,cAAc,GAAG;;;;;EAKrB,CAAC;AAEH,yDAAyD;AACzD,MAAM,eAAe,GAAG;;;;;;;;;;;;EAYtB,CAAC;AAEH,yDAAyD;AACzD,MAAM,aAAa,GAAG;;;;;;;;;;;;;EAapB,CAAC;AAEH,gEAAgE;AAChE,MAAM,cAAc,GAAG;;;;;;;;;EASrB,CAAC;AAEH,6DAA6D;AAC7D,MAAM,aAAa,GAAG;;;;;;;;;EASpB,CAAC;AAEH;;;;GAIG;AACH,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,eAAe,GAAG,wBAAwB,CAAC;AACjD,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAC1C,MAAM,aAAa,GAAG,sBAAsB,CAAC;AAC7C,MAAM,cAAc,GAAG,qBAAqB,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,MAAM,OAAO,mBAAmB;IAMX;IACA;IANnB;;;OAGG;IACH,YACmB,GAAmB,EACnB,SAAsB;QADtB,QAAG,GAAH,GAAG,CAAgB;QACnB,cAAS,GAAT,SAAS,CAAa;IACtC,CAAC;IAEJ,qDAAqD;IACrD,KAAK,CAAC,KAAK;QACT,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAChC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,cAAc,EAAE,EAAE,CAAC,EACxC,oBAAoB,CACrB,CAAC;QACF,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;IACzD,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,QAAgB;QAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAChC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,EAC9D,qBAAqB,CACtB,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC/D,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxF,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;YACrC,KAAK;YACL,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;SACpC,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI,CACR,MAAqB,EACrB,QAAqC;QAErC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IACzD,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,WAAW,CAAC,WAAkC;QAClD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAChC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,EAC5D,0BAA0B,CAC3B,CAAC;QACF,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,6FAA6F;IAC7F,KAAK,CAAC,QAAQ,CAAC,QAAgB,EAAE,IAAoB;QACnD,MAAM,KAAK,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAC/E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAChC,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,CAAC,KAAK,EAAE,cAAc,CAAC,EACjF,uBAAuB,CACxB,CAAC;QACF,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI,CAAC,QAAgB,EAAE,QAAqC;QAChE,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;IAC7F,CAAC;IAED,wCAAwC;IAChC,KAAK,CAAC,MAAM,CAAC,OAAwB;QAC3C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;QACjE,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC;YACxC,UAAU,EAAE,MAAM,CAAC,kBAAkB,CAAC,YAAY,CAAC;YACnD,YAAY,EAAE,MAAM,CAAC,cAAc,CAAC,cAAc,CAAC;YACnD,YAAY,EAAE,MAAM,CAAC,kBAAkB,CAAC,cAAc,CAAC;YACvD,WAAW,EAAE,MAAM,CAAC,cAAc,CAAC,aAAa,CAAC;YACjD,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;SACrC,CAAC;IACJ,CAAC;IAED,iFAAiF;IACzE,WAAW,CACjB,MAAqB,EACrB,QAAqC;QAErC,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QACzF,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED,kFAAkF;IAC1E,aAAa,CAAC,MAAc,EAAE,QAAqC;QACzE,MAAM,KAAK,GAAG;YACZ,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,MAAM,CAAC,MAAM;YACzB,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YACzD,QAAQ;SACT,CAAC;QACF,OAAO,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC3F,CAAC;IAED;;;;;OAKG;IACK,WAAW,CACjB,QAAgB,EAChB,KAA8B,EAC9B,QAAgB,EAChB,KAAa,EACb,QAAgB;QAEhB,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;QACrF,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QACpE,OAAO;YACL,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,0BAA0B,EAAE,MAAM,EAAE;SAC3E,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,QAAQ,CAAC,OAAwB,EAAE,KAAa;QAC5D,OAAO,IAAI,CAAC,qBAAqB,CAC/B,OAAO,EACP,KAAK,EACL,IAAI,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAC/C,CAAC;IACJ,CAAC;IAED,sFAAsF;IAC9E,KAAK,CAAC,qBAAqB,CACjC,OAAwB,EACxB,KAAa,EACb,MAA2B;QAE3B,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,mBAAmB,CAAC,UAAU,CAAC,KAAK,CAAC;gBAAE,MAAM,KAAK,CAAC;YACxD,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5D,CAAC;IAED,qFAAqF;IAC7E,cAAc,CAAC,KAAa,EAAE,UAAkB,EAAE,MAAc;QACtE,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,wBAAwB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,mBAAmB,MAAM,CAAC,UAAU,CAAC,oCAAoC,CACtH,CAAC;QACJ,CAAC;QACD,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CACb,iFAAiF,CAClF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,oDAAoD;IAC5C,UAAU,CAAC,MAAsB;QACvC,OAAO;YACL,EAAE,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;YAC3B,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC;YAC1C,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;YACnC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC;YACxC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC;YACxC,SAAS,EAAE,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC;SAC7C,CAAC;IACJ,CAAC;IAED,wGAAwG;IAChG,YAAY,CAAC,MAAsB;QACzC,OAAO,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACvD,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,mBAAmB,CAAC;YACnD,KAAK,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC;SACrC,CAAC,CAAC,CAAC;IACN,CAAC;IAED,0EAA0E;IAClE,aAAa,CAAC,MAAsB;QAC1C,OAAO,MAAM,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACvD,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,mBAAmB,CAAC;YACnD,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC;SAClC,CAAC,CAAC,CAAC;IACN,CAAC;CACF"}