canopycms 0.12.0 → 0.12.1

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 (154) hide show
  1. package/CHANGELOG.md +164 -48
  2. package/dist/api/admin.d.ts +4 -4
  3. package/dist/api/branch-review.js +45 -13
  4. package/dist/api/branch-status.d.ts +12 -0
  5. package/dist/api/branch-status.js +13 -0
  6. package/dist/api/branch-update-from-base.d.ts +23 -0
  7. package/dist/api/branch-update-from-base.js +176 -0
  8. package/dist/api/branch.d.ts +5 -0
  9. package/dist/api/branch.js +1 -0
  10. package/dist/api/client.d.ts +14 -1
  11. package/dist/api/client.js +22 -0
  12. package/dist/api/comments.d.ts +2 -2
  13. package/dist/api/content.d.ts +38 -1
  14. package/dist/api/content.js +41 -5
  15. package/dist/api/merge-conflicts.d.ts +226 -0
  16. package/dist/api/merge-conflicts.js +674 -0
  17. package/dist/api/routes.js +2 -0
  18. package/dist/api/types.d.ts +7 -3
  19. package/dist/base-update.d.ts +26 -0
  20. package/dist/base-update.js +31 -0
  21. package/dist/branch-metadata-file.d.ts +51 -0
  22. package/dist/branch-metadata-file.js +11 -0
  23. package/dist/branch-schema-cache.d.ts +12 -0
  24. package/dist/branch-schema-cache.js +27 -2
  25. package/dist/cli/backfill-item-keys.d.ts +77 -0
  26. package/dist/cli/backfill-item-keys.js +320 -0
  27. package/dist/cli/cli.d.ts +1 -1
  28. package/dist/cli/cli.js +9658 -1499
  29. package/dist/cli/generate-ai-content.js +354 -244
  30. package/dist/cli/init.js +6 -0
  31. package/dist/cli/site-config.d.ts +14 -2
  32. package/dist/cli/site-config.js +20 -4
  33. package/dist/comment-store.d.ts +8 -0
  34. package/dist/comment-store.js +28 -0
  35. package/dist/content-index-generation.d.ts +1 -4
  36. package/dist/content-index-generation.js +1 -4
  37. package/dist/content-store.d.ts +39 -3
  38. package/dist/content-store.js +48 -15
  39. package/dist/editor/BranchManager.d.ts +4 -1
  40. package/dist/editor/BranchManager.js +9 -5
  41. package/dist/editor/Editor.js +429 -52
  42. package/dist/editor/EntryNavigator.d.ts +10 -2
  43. package/dist/editor/EntryNavigator.js +12 -4
  44. package/dist/editor/FormRenderer.d.ts +8 -2
  45. package/dist/editor/FormRenderer.js +5 -6
  46. package/dist/editor/base-update-wait.d.ts +74 -0
  47. package/dist/editor/base-update-wait.js +91 -0
  48. package/dist/editor/branch-status.js +1 -1
  49. package/dist/editor/components/BaseUpdateNotice.d.ts +12 -0
  50. package/dist/editor/components/BaseUpdateNotice.js +24 -0
  51. package/dist/editor/components/BranchPill.d.ts +4 -1
  52. package/dist/editor/components/BranchPill.js +5 -2
  53. package/dist/editor/components/ConflictsGroup.d.ts +100 -0
  54. package/dist/editor/components/ConflictsGroup.js +364 -0
  55. package/dist/editor/components/EditorHeader.d.ts +16 -1
  56. package/dist/editor/components/EditorHeader.js +92 -30
  57. package/dist/editor/components/EntryChangesDrawer.d.ts +16 -2
  58. package/dist/editor/components/EntryChangesDrawer.js +33 -167
  59. package/dist/editor/components/EntryHeader.d.ts +3 -1
  60. package/dist/editor/components/EntryHeader.js +2 -2
  61. package/dist/editor/components/GetLatestChangesButton.d.ts +15 -0
  62. package/dist/editor/components/GetLatestChangesButton.js +29 -0
  63. package/dist/editor/components/ReleaseHoldButton.d.ts +20 -0
  64. package/dist/editor/components/ReleaseHoldButton.js +36 -0
  65. package/dist/editor/components/RetryToastMessage.js +1 -1
  66. package/dist/editor/components/change-parts.d.ts +51 -0
  67. package/dist/editor/components/change-parts.js +171 -0
  68. package/dist/editor/conflict-cards.d.ts +90 -0
  69. package/dist/editor/conflict-cards.js +279 -0
  70. package/dist/editor/conflict-choices.d.ts +60 -0
  71. package/dist/editor/conflict-choices.js +108 -0
  72. package/dist/editor/conflict-notice.d.ts +25 -0
  73. package/dist/editor/conflict-notice.js +39 -0
  74. package/dist/editor/copy.d.ts +12 -0
  75. package/dist/editor/copy.js +12 -0
  76. package/dist/editor/entry-diff.d.ts +2 -1
  77. package/dist/editor/entry-diff.js +5 -21
  78. package/dist/editor/hooks/useBaseUpdate.d.ts +36 -0
  79. package/dist/editor/hooks/useBaseUpdate.js +269 -0
  80. package/dist/editor/hooks/useBranchManager.d.ts +6 -1
  81. package/dist/editor/hooks/useBranchManager.js +28 -7
  82. package/dist/editor/hooks/useBranchesData.js +3 -0
  83. package/dist/editor/hooks/useConflictChoices.d.ts +24 -0
  84. package/dist/editor/hooks/useConflictChoices.js +75 -0
  85. package/dist/editor/hooks/useConflictsData.d.ts +26 -0
  86. package/dist/editor/hooks/useConflictsData.js +89 -0
  87. package/dist/editor/hooks/useDraftManager.d.ts +5 -0
  88. package/dist/editor/hooks/useDraftManager.js +24 -8
  89. package/dist/editor/hooks/useEntryManager.d.ts +9 -0
  90. package/dist/editor/hooks/useEntryManager.js +5 -0
  91. package/dist/editor/release-hold.d.ts +12 -0
  92. package/dist/editor/release-hold.js +39 -0
  93. package/dist/editor/server-clock.d.ts +4 -0
  94. package/dist/editor/server-clock.js +15 -0
  95. package/dist/editor/undo-change.d.ts +7 -0
  96. package/dist/editor/undo-change.js +19 -4
  97. package/dist/git-manager.d.ts +5 -0
  98. package/dist/git-manager.js +30 -0
  99. package/dist/item-keys.d.ts +13 -0
  100. package/dist/item-keys.js +36 -14
  101. package/dist/merge/conflict-path.d.ts +40 -0
  102. package/dist/merge/conflict-path.js +128 -0
  103. package/dist/merge/diff3.d.ts +27 -0
  104. package/dist/merge/diff3.js +113 -0
  105. package/dist/merge/entry-merge.d.ts +94 -0
  106. package/dist/merge/entry-merge.js +875 -0
  107. package/dist/merge/list-alignment.d.ts +52 -0
  108. package/dist/merge/list-alignment.js +441 -0
  109. package/dist/merge/text-merge.d.ts +29 -0
  110. package/dist/merge/text-merge.js +59 -0
  111. package/dist/merge/value-equality.d.ts +18 -0
  112. package/dist/merge/value-equality.js +50 -0
  113. package/dist/merge-conflicts.d.ts +232 -0
  114. package/dist/merge-conflicts.js +451 -0
  115. package/dist/operating-mode/client-safe-strategy.d.ts +2 -0
  116. package/dist/operating-mode/client-safe-strategy.js +6 -0
  117. package/dist/operating-mode/types.d.ts +5 -0
  118. package/dist/services.d.ts +16 -1
  119. package/dist/services.js +82 -22
  120. package/dist/task-queue/cms-task-queue.d.ts +3 -1
  121. package/dist/types.d.ts +28 -2
  122. package/dist/utils/content-serialize.d.ts +18 -1
  123. package/dist/utils/content-serialize.js +12 -0
  124. package/dist/utils/content-write-lock.d.ts +3 -3
  125. package/dist/utils/content-write-lock.js +3 -3
  126. package/dist/utils/markdown-body-splice.d.ts +1 -1
  127. package/dist/utils/markdown-body-splice.js +1 -19
  128. package/dist/utils/markdown-parse.d.ts +9 -0
  129. package/dist/utils/markdown-parse.js +27 -0
  130. package/dist/version.d.ts +1 -1
  131. package/dist/version.js +1 -1
  132. package/dist/worker/branch-merge.d.ts +53 -37
  133. package/dist/worker/branch-merge.js +139 -54
  134. package/dist/worker/cms-worker.d.ts +16 -3
  135. package/dist/worker/cms-worker.js +59 -12
  136. package/dist/worker/field-merge.d.ts +65 -0
  137. package/dist/worker/field-merge.js +636 -0
  138. package/dist/worker/git-sync.d.ts +1 -1
  139. package/dist/worker/git-sync.js +7 -6
  140. package/dist/worker/github-commits.d.ts +42 -10
  141. package/dist/worker/github-commits.js +287 -47
  142. package/dist/worker/github-gateway-http.js +17 -9
  143. package/dist/worker/github-gateway-wire.d.ts +21 -12
  144. package/dist/worker/github-gateway-wire.js +5 -1
  145. package/dist/worker/github-gateway.d.ts +10 -1
  146. package/dist/worker/github-gateway.js +18 -6
  147. package/dist/worker/github-transfer.d.ts +5 -3
  148. package/dist/worker/github-transfer.js +8 -5
  149. package/dist/worker/rebase.d.ts +5 -4
  150. package/dist/worker/rebase.js +293 -156
  151. package/dist/worker/task-runner.d.ts +1 -1
  152. package/dist/worker/task-runner.js +14 -2
  153. package/dist/worker/worker-context.d.ts +18 -2
  154. package/package.json +1 -1
@@ -9,10 +9,13 @@ export declare const MAX_JSON_REQUEST_BYTES: number;
9
9
  export declare const MAX_JSON_ANSWER_BYTES: number;
10
10
  export declare const fetchRequest: z.ZodObject<{
11
11
  have: z.ZodArray<z.ZodString, "many">;
12
+ fresh: z.ZodOptional<z.ZodBoolean>;
12
13
  }, "strict", z.ZodTypeAny, {
13
14
  have: string[];
15
+ fresh?: boolean | undefined;
14
16
  }, {
15
17
  have: string[];
18
+ fresh?: boolean | undefined;
16
19
  }>;
17
20
  export declare const pushRequest: z.ZodObject<{
18
21
  branch: z.ZodString;
@@ -56,13 +59,13 @@ export declare const requests: {
56
59
  }, "strict", z.ZodTypeAny, {
57
60
  title: string;
58
61
  base: string;
59
- head: string;
60
62
  body: string;
63
+ head: string;
61
64
  }, {
62
65
  title: string;
63
66
  base: string;
64
- head: string;
65
67
  body: string;
68
+ head: string;
66
69
  }>;
67
70
  readonly updatePullRequest: z.ZodObject<{
68
71
  number: z.ZodNumber;
@@ -97,15 +100,15 @@ export declare const requests: {
97
100
  }, "strict", z.ZodTypeAny, {
98
101
  title: string;
99
102
  base: string;
100
- head: string;
101
103
  body: string;
104
+ head: string;
102
105
  markReadyIfDraft?: boolean | undefined;
103
106
  mergeSectionIntoBody?: boolean | undefined;
104
107
  }, {
105
108
  title: string;
106
109
  base: string;
107
- head: string;
108
110
  body: string;
111
+ head: string;
109
112
  markReadyIfDraft?: boolean | undefined;
110
113
  mergeSectionIntoBody?: boolean | undefined;
111
114
  }>;
@@ -211,12 +214,14 @@ export declare const answers: {
211
214
  body: z.ZodNullable<z.ZodString>;
212
215
  mergeable_state: z.ZodOptional<z.ZodString>;
213
216
  baseRef: z.ZodOptional<z.ZodString>;
217
+ headSha: z.ZodOptional<z.ZodString>;
214
218
  }, "strict", z.ZodTypeAny, {
215
219
  merged: boolean;
216
220
  state: "open" | "closed";
217
221
  body: string | null;
218
222
  merged_at: string | null;
219
223
  node_id: string;
224
+ headSha?: string | undefined;
220
225
  mergeable_state?: string | undefined;
221
226
  baseRef?: string | undefined;
222
227
  }, {
@@ -225,6 +230,7 @@ export declare const answers: {
225
230
  body: string | null;
226
231
  merged_at: string | null;
227
232
  node_id: string;
233
+ headSha?: string | undefined;
228
234
  mergeable_state?: string | undefined;
229
235
  baseRef?: string | undefined;
230
236
  }>;
@@ -312,21 +318,21 @@ export declare const answers: {
312
318
  kind: z.ZodEnum<["auto-scaling", "spot"]>;
313
319
  reason: z.ZodString;
314
320
  }, "strict", z.ZodTypeAny, {
315
- kind: "auto-scaling" | "spot";
316
321
  reason: string;
317
- }, {
318
322
  kind: "auto-scaling" | "spot";
323
+ }, {
319
324
  reason: string;
325
+ kind: "auto-scaling" | "spot";
320
326
  }>>;
321
327
  }, "strict", z.ZodTypeAny, {
322
328
  notice: {
323
- kind: "auto-scaling" | "spot";
324
329
  reason: string;
330
+ kind: "auto-scaling" | "spot";
325
331
  } | null;
326
332
  }, {
327
333
  notice: {
328
- kind: "auto-scaling" | "spot";
329
334
  reason: string;
335
+ kind: "auto-scaling" | "spot";
330
336
  } | null;
331
337
  }>;
332
338
  readonly completeLifecycle: z.ZodObject<{}, "strict", z.ZodTypeAny, {}, {}>;
@@ -360,15 +366,18 @@ export declare const fetchPoll: z.ZodDiscriminatedUnion<"state", [z.ZodObject<{
360
366
  /** Every GitHub branch and its tip, as pairs: a `Map` has no JSON form of its own. */
361
367
  refs: z.ZodArray<z.ZodTuple<[z.ZodString, z.ZodString], null>, "many">;
362
368
  bundleId: z.ZodNullable<z.ZodString>;
369
+ startedAt: z.ZodNumber;
363
370
  }, "strict", z.ZodTypeAny, {
364
371
  state: "done";
365
372
  refs: [string, string][];
366
373
  progress: number;
374
+ startedAt: number;
367
375
  bundleId: string | null;
368
376
  }, {
369
377
  state: "done";
370
378
  refs: [string, string][];
371
379
  progress: number;
380
+ startedAt: number;
372
381
  bundleId: string | null;
373
382
  }>]>;
374
383
  export declare const pushAnswer: z.ZodUnion<[z.ZodObject<{
@@ -391,15 +400,15 @@ export declare const pushAnswer: z.ZodUnion<[z.ZodObject<{
391
400
  pastStaleLease: z.ZodBoolean;
392
401
  }, "strict", z.ZodTypeAny, {
393
402
  kind: "pushed";
403
+ moved: true;
394
404
  from: string | null;
395
405
  to: string;
396
- moved: true;
397
406
  pastStaleLease: boolean;
398
407
  }, {
399
408
  kind: "pushed";
409
+ moved: true;
400
410
  from: string | null;
401
411
  to: string;
402
- moved: true;
403
412
  pastStaleLease: boolean;
404
413
  }>, z.ZodObject<{
405
414
  kind: z.ZodLiteral<"need-objects">;
@@ -431,15 +440,15 @@ declare const errorEnvelope: z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
431
440
  branch: string;
432
441
  push: boolean;
433
442
  message: string;
434
- kind: "refusal";
435
443
  reason: "settings" | "protected" | "invalid" | "other-settings" | "outside-namespace" | "not-a-commit" | "too-long";
444
+ kind: "refusal";
436
445
  operation: "push" | "delete" | "pull-request";
437
446
  }, {
438
447
  branch: string;
439
448
  push: boolean;
440
449
  message: string;
441
- kind: "refusal";
442
450
  reason: "settings" | "protected" | "invalid" | "other-settings" | "outside-namespace" | "not-a-commit" | "too-long";
451
+ kind: "refusal";
443
452
  operation: "push" | "delete" | "pull-request";
444
453
  }>, z.ZodObject<{
445
454
  kind: z.ZodLiteral<"push">;
@@ -37,7 +37,9 @@ const objectId = z.string().regex(/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/, 'not a full
37
37
  const name = z.string().max(4096);
38
38
  const prNumber = z.number().int().safe();
39
39
  const message = z.string().max(MAX_MESSAGE_LENGTH);
40
- export const fetchRequest = z.object({ have: z.array(objectId).max(MAX_FETCH_HAVE) }).strict();
40
+ export const fetchRequest = z
41
+ .object({ have: z.array(objectId).max(MAX_FETCH_HAVE), fresh: z.boolean().optional() })
42
+ .strict();
41
43
  export const pushRequest = z
42
44
  .object({
43
45
  branch: name,
@@ -114,6 +116,7 @@ export const answers = {
114
116
  body: pullRequestText.body.nullable(),
115
117
  mergeable_state: z.string().max(64).optional(),
116
118
  baseRef: z.string().max(256).optional(),
119
+ headSha: objectId.optional(),
117
120
  })
118
121
  .strict(),
119
122
  createOrUpdatePullRequest: pullRequestRef.extend({ created: z.boolean() }).strict(),
@@ -187,6 +190,7 @@ export const fetchPoll = z.discriminatedUnion('state', [
187
190
  /** Every GitHub branch and its tip, as pairs: a `Map` has no JSON form of its own. */
188
191
  refs: z.array(z.tuple([name, objectId])).max(1_000_000),
189
192
  bundleId: jobId.nullable(),
193
+ startedAt: z.number().int().nonnegative(),
190
194
  })
191
195
  .strict(),
192
196
  ]);
@@ -15,6 +15,11 @@ export interface GitHubFetchResult {
15
15
  * request's `have` and their history; null when that leaves nothing to send.
16
16
  */
17
17
  bundleId: string | null;
18
+ /**
19
+ * When the GitHub fetch `refs` come from began, by the gateway's clock, which is the worker's:
20
+ * they share the instance. A fetch can be joined or reused, so this can predate the request.
21
+ */
22
+ startedAt: number;
18
23
  }
19
24
  /** The most `have` IDs one fetch takes. */
20
25
  export declare const MAX_FETCH_HAVE = 10000;
@@ -81,6 +86,8 @@ export type GitHubPullRequest = Pick<RestEndpointMethodTypes['pulls']['get']['re
81
86
  mergeable_state?: string;
82
87
  /** The branch the pull request merges into on GitHub, which a person can change. */
83
88
  baseRef?: string;
89
+ /** The pull request's head commit, read with `mergeable_state`. */
90
+ headSha?: string;
84
91
  };
85
92
  export type GitHubCreateOrUpdatePullRequest = Omit<CreateOrUpdatePullRequestParams, 'octokit' | 'owner' | 'repo' | 'signal'>;
86
93
  /**
@@ -114,10 +121,12 @@ export interface GitHubGateway {
114
121
  * Fetch every GitHub branch, and answer with all of them and a bundle of the commits `have`
115
122
  * lacks. `have` is the caller's own tips, at most {@link MAX_FETCH_HAVE} object IDs; any the
116
123
  * gateway does not hold as a commit is ignored. A new fetch replaces a bundle not yet opened.
117
- * `onProgress` is told of each sign of life from the gateway's git while the caller waits.
124
+ * `fresh` takes no GitHub fetch begun before the request arrived. `onProgress` is told of each
125
+ * sign of life from the gateway's git while the caller waits.
118
126
  */
119
127
  fetch(request: {
120
128
  have: readonly string[];
129
+ fresh?: boolean;
121
130
  }, signal?: AbortSignal, onProgress?: () => void): Promise<GitHubFetchResult>;
122
131
  /**
123
132
  * The bundle a fetch answered with, readable once. Throws {@link GitHubTransientError}
@@ -197,11 +197,14 @@ class LocalGitHubGateway {
197
197
  * own, which repairs a corrupt mirror first ({@link GitHubMirror.heal}), and its failure re-reads
198
198
  * the credential when it reached GitHub, whoever started it.
199
199
  */
200
- async joinGitHubFetch(resolve, signal) {
200
+ async joinGitHubFetch(resolve, signal,
201
+ /** Join or reuse only a fetch that began at or after this time. */
202
+ notBefore) {
201
203
  const current = this.githubFetch;
202
204
  const window = this.options.fetchCoalesceMs ?? FETCH_COALESCE_MS;
203
205
  const reusable = current !== null &&
204
206
  !current.failed &&
207
+ (notBefore === undefined || current.startedAt >= notBefore) &&
205
208
  (current.completedAt === null ||
206
209
  (Date.now() - current.completedAt < window && this.isCurrent(current.snapshot)));
207
210
  const job = reusable ? current : this.startGitHubFetch(resolve);
@@ -223,7 +226,7 @@ class LocalGitHubGateway {
223
226
  async afterGitHubFetch(join, fn) {
224
227
  for (let attempt = 1;; attempt++) {
225
228
  const snapshot = await join();
226
- const result = await this.mirror.exclusive(async (session) => this.isCurrent(snapshot) ? { value: await fn(session) } : null);
229
+ const result = await this.mirror.exclusive(async (session) => this.isCurrent(snapshot) ? { value: await fn(session, snapshot) } : null);
227
230
  if (result !== null)
228
231
  return result.value;
229
232
  if (attempt === 2) {
@@ -234,6 +237,7 @@ class LocalGitHubGateway {
234
237
  /** Start a GitHub fetch, taking its place at once, before the credential resolves. */
235
238
  startGitHubFetch(resolve) {
236
239
  let reachedGitHub = false;
240
+ const startedAt = Date.now();
237
241
  const run = async () => {
238
242
  const credential = await resolve();
239
243
  const own = {
@@ -248,12 +252,18 @@ class LocalGitHubGateway {
248
252
  const pushes = this.pushes;
249
253
  await this.mirror.heal(mirror, own);
250
254
  await this.mirror.fetchFromGitHub(mirror, own);
251
- return { generation: this.mirror.generation, pushes };
255
+ return { generation: this.mirror.generation, pushes, startedAt };
252
256
  });
253
257
  await this.mirror.afterFetch();
254
258
  return snapshot;
255
259
  };
256
- const job = { failed: false, completedAt: null, snapshot: null, done: run() };
260
+ const job = {
261
+ failed: false,
262
+ completedAt: null,
263
+ snapshot: null,
264
+ startedAt,
265
+ done: run(),
266
+ };
257
267
  job.done.then((snapshot) => {
258
268
  job.completedAt = Date.now();
259
269
  job.snapshot = snapshot;
@@ -472,19 +482,20 @@ class LocalGitHubGateway {
472
482
  }
473
483
  }
474
484
  fetchOnce(request, signal) {
485
+ const notBefore = request.fresh ? Date.now() : undefined;
475
486
  const have = [...new Set(request.have)];
476
487
  if (have.length > MAX_FETCH_HAVE) {
477
488
  throw new Error(`A fetch takes at most ${MAX_FETCH_HAVE} have IDs, not ${have.length}`);
478
489
  }
479
490
  for (const id of have)
480
491
  assertObjectId(id);
481
- return this.credentialed(signal, (reach) => this.afterGitHubFetch(() => this.joinGitHubFetch(() => this.credential(reach), signal), async (mirror) => {
492
+ return this.credentialed(signal, (reach) => this.afterGitHubFetch(() => this.joinGitHubFetch(() => this.credential(reach), signal, notBefore), async (mirror, snapshot) => {
482
493
  this.mirror.assertUsable();
483
494
  const refs = await mirror.heads();
484
495
  const file = await this.mirror.outgoingBundlePath();
485
496
  const created = await mirror.createBundle(have, file, signal);
486
497
  const bundleId = await this.mirror.setPendingBundle(created ? file : null);
487
- return { refs, bundleId };
498
+ return { refs, bundleId, startedAt: snapshot.startedAt };
488
499
  }));
489
500
  }
490
501
  openBundle(bundleId) {
@@ -688,6 +699,7 @@ class LocalGitHubGateway {
688
699
  body: ours ? (data.body ?? '') : null,
689
700
  mergeable_state: data.mergeable_state,
690
701
  baseRef: data.base.ref,
702
+ headSha: data.head.sha,
691
703
  };
692
704
  });
693
705
  }
@@ -12,11 +12,13 @@ export interface TransferContext {
12
12
  /**
13
13
  * Fetch every GitHub branch into `remote.git`'s tracking namespace (`GITHUB_TRACKING_REF_PREFIX`),
14
14
  * which then holds exactly GitHub's branches. `have` is every tip `remote.git` holds, so the
15
- * bundle carries only what it lacks. Returns GitHub's branches, and what an operator must fix in
16
- * remote.git for the namespace to keep up, if anything (see {@link moveTrackingRefs}).
15
+ * bundle carries only what it lacks. `fresh` takes no GitHub fetch the gateway began before this
16
+ * call. Returns GitHub's branches, when the GitHub fetch they come from began, and what an operator
17
+ * must fix in remote.git for the namespace to keep up, if anything (see {@link moveTrackingRefs}).
17
18
  */
18
- export declare function fetchGitHubIntoRemoteGit(ctx: TransferContext, signal?: AbortSignal): Promise<{
19
+ export declare function fetchGitHubIntoRemoteGit(ctx: TransferContext, signal?: AbortSignal, fresh?: boolean): Promise<{
19
20
  refs: ReadonlyMap<string, string>;
21
+ fetchedAt: number;
20
22
  needsOperator: string | null;
21
23
  }>;
22
24
  /**
@@ -28,16 +28,19 @@ const MAX_PUSH_RESTARTS = 3;
28
28
  /**
29
29
  * Fetch every GitHub branch into `remote.git`'s tracking namespace (`GITHUB_TRACKING_REF_PREFIX`),
30
30
  * which then holds exactly GitHub's branches. `have` is every tip `remote.git` holds, so the
31
- * bundle carries only what it lacks. Returns GitHub's branches, and what an operator must fix in
32
- * remote.git for the namespace to keep up, if anything (see {@link moveTrackingRefs}).
31
+ * bundle carries only what it lacks. `fresh` takes no GitHub fetch the gateway began before this
32
+ * call. Returns GitHub's branches, when the GitHub fetch they come from began, and what an operator
33
+ * must fix in remote.git for the namespace to keep up, if anything (see {@link moveTrackingRefs}).
33
34
  */
34
- export async function fetchGitHubIntoRemoteGit(ctx, signal) {
35
+ export async function fetchGitHubIntoRemoteGit(ctx, signal, fresh = false) {
35
36
  const gitDir = ctx.remoteGitPath;
36
- const { refs, bundleId } = await ctx.github().fetch({ have: await haveOf(gitDir) }, signal);
37
+ const { refs, bundleId, startedAt } = await ctx
38
+ .github()
39
+ .fetch({ have: await haveOf(gitDir), fresh }, signal);
37
40
  if (bundleId !== null)
38
41
  await unbundle(ctx, gitDir, bundleId, signal);
39
42
  const needsOperator = await moveTrackingRefs(ctx, gitDir, refs, signal);
40
- return { refs, needsOperator };
43
+ return { refs, fetchedAt: startedAt, needsOperator };
41
44
  }
42
45
  /**
43
46
  * Seed the new bare repository at `gitDir`, which must not exist yet, with every GitHub branch as
@@ -7,8 +7,9 @@ import type { WorkerContext } from './worker-context.js';
7
7
  * The rebase loop: the deepest leaf of the git-sync cluster, and the most
8
8
  * safety-critical part of the worker. `syncGit` (git-sync.ts) calls
9
9
  * `runRebaseCycle` once per cycle; every branch workspace behind the base
10
- * branch is rebased onto it, keeping the BRANCH's version of any conflicting
11
- * file. Three things make it the part most likely to misbehave under real EFS
10
+ * branch takes it in: by a rebase where git and the field merge agree there is
11
+ * nothing to decide, and by a merge (github-commits.ts' `mergeIntoBranch`)
12
+ * wherever there is. Three things make it the part most likely to misbehave under real EFS
12
13
  * and spot conditions, all documented at the point they happen:
13
14
  *
14
15
  * - it holds the [SYNC-C1] cross-host content-write lock for the whole rebase,
@@ -27,7 +28,7 @@ import type { WorkerContext } from './worker-context.js';
27
28
  * but still need their PR's resolution polled, and this loop is the only thing
28
29
  * that walks every branch workspace.
29
30
  */
30
- export type RebaseContext = Pick<WorkerContext, 'baseBranch' | 'sanitizedBaseBranch' | 'contentBranchesPath' | 'contentRoot' | 'remoteGitPath' | 'taskDir' | 'taskTimeoutMs' | 'github' | 'ensureStatusReport' | 'afterConflictDetectedForTesting' | 'afterRebaseCompletedForTesting' | 'ensureSettingsBranch' | 'isDraining'>;
31
+ export type RebaseContext = Pick<WorkerContext, 'baseBranch' | 'sanitizedBaseBranch' | 'contentBranchesPath' | 'contentRoot' | 'remoteGitPath' | 'taskDir' | 'taskTimeoutMs' | 'github' | 'ensureStatusReport' | 'afterConflictDetectedForTesting' | 'afterRebaseCompletedForTesting' | 'ensureSettingsBranch' | 'isDraining' | 'requestBranchSync'>;
31
32
  /**
32
33
  * Per-cycle outcome of `rebaseActiveBranches()`, folded by `syncGit()` into the
33
34
  * worker's self-reported status (`WorkerStatusReport.lastGitSync`, see
@@ -85,4 +86,4 @@ export declare function pollMergeState(ctx: RebaseContext, branchDir: string, br
85
86
  * that branch's cross-host content-write lock and runs a series of git
86
87
  * subprocesses against a shared filesystem.
87
88
  */
88
- export declare function runRebaseCycle(ctx: RebaseContext, gatewayPolicy?: BranchPolicyDescription, gitHub?: GitHubSnapshot): Promise<RebaseSummary>;
89
+ export declare function runRebaseCycle(ctx: RebaseContext, gatewayPolicy?: BranchPolicyDescription, gitHub?: GitHubSnapshot, requested?: ReadonlySet<string>): Promise<RebaseSummary>;