gutterpress 0.11.23-alpha.4 → 0.11.23-alpha.6

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 (52) hide show
  1. package/README.md +1 -1
  2. package/dist/api/index.d.ts +5 -3
  3. package/dist/api/index.js +17 -7
  4. package/dist/{build-c48eer6f.js → build-py643c5a.js} +8 -8
  5. package/dist/{cli-93mkaw6v.js → cli-09jj8w5g.js} +63 -31
  6. package/dist/{cli-a35w7wzg.js → cli-31anr0r9.js} +107 -56
  7. package/dist/{cli-y6d1arem.js → cli-55br530w.js} +4 -4
  8. package/dist/{cli-54xt7pjg.js → cli-58fsk6d7.js} +2 -2
  9. package/dist/{cli-d9mm3vvh.js → cli-bnf7eb38.js} +1 -1
  10. package/dist/{cli-gnpea9dx.js → cli-qzkq9em8.js} +1 -1
  11. package/dist/{cli-pspjxnc8.js → cli-tf9tw6at.js} +1 -1
  12. package/dist/{cli-rqh295j9.js → cli-x777v272.js} +3 -3
  13. package/dist/cli.js +12 -12
  14. package/dist/{doctor-ptb346k8.js → doctor-tyrzqphh.js} +3 -3
  15. package/dist/{engine-4rzdx6af.js → engine-4rabsgwq.js} +1 -1
  16. package/dist/{engine-6txhxmmv.js → engine-wm4fggac.js} +2 -2
  17. package/dist/{ext-gy8szg3x.js → ext-70kt3eft.js} +8 -8
  18. package/dist/{extension-restore-m8tj43e7.js → extension-restore-fjfn1hrk.js} +4 -4
  19. package/dist/{extension-restore-dymzcasz.js → extension-restore-whag4sm0.js} +2 -2
  20. package/dist/{index-8ywkd2sv.js → index-1zqkfzcd.js} +3 -3
  21. package/dist/{index-5kh4c78h.js → index-2vxzxyyj.js} +2 -2
  22. package/dist/{index-kaks3mm2.js → index-cmakyf43.js} +3 -3
  23. package/dist/{index-h6yk5tjx.js → index-cw03e9p4.js} +107 -56
  24. package/dist/{index-ea94zbq4.js → index-ejbfetdn.js} +327 -86
  25. package/dist/{index-yc3xj266.js → index-wm4x7xbf.js} +1 -1
  26. package/dist/index.js +18 -8
  27. package/dist/lib/publish/connect.d.ts +8 -1
  28. package/dist/lib/publish/manifest-publish.d.ts +26 -2
  29. package/dist/lib/publish/selections.d.ts +12 -1
  30. package/dist/lib/publish/types.d.ts +15 -5
  31. package/dist/lib/remote-auth/repair.d.ts +2 -2
  32. package/dist/lib/remote-auth/revisions.d.ts +60 -0
  33. package/dist/lib/remote-auth/scorched-earth.d.ts +2 -2
  34. package/dist/lib/remote-auth/sync-messages.d.ts +28 -27
  35. package/dist/lib/remote-auth/sync-types.d.ts +3 -0
  36. package/dist/lib/remote-auth/sync.d.ts +7 -8
  37. package/dist/lib/remote-auth/transport.d.ts +8 -1
  38. package/dist/lib/source-provider.d.ts +80 -35
  39. package/dist/{manifest.schema-w86c1xw1.json → manifest.schema-93sd7zje.json} +13 -6
  40. package/dist/{new-t2t28ccb.js → new-b27kyr02.js} +11 -11
  41. package/dist/{plugins-fec8t2bh.js → plugins-racab3cj.js} +1 -1
  42. package/dist/{plugins-sqa4msdk.js → plugins-vpx7c53c.js} +3 -3
  43. package/dist/{preflight-srq8fktp.js → preflight-akdqz9v8.js} +8 -8
  44. package/dist/{preview-zsp9hstd.js → preview-bck9f88w.js} +8 -8
  45. package/dist/{preview-interface-nnmrxyqm.js → preview-interface-0xdh0r5b.js} +3 -66
  46. package/dist/{publish-hhy31gr9.js → publish-keyp8rh4.js} +8 -8
  47. package/dist/render.js +2 -2
  48. package/dist/schema/manifest.types.d.ts +18 -3
  49. package/dist/{source-provider-knmcam50.js → source-provider-n7vehh6t.js} +15 -3
  50. package/dist/{source-provider-98k5deda.js → source-provider-tgzet3j5.js} +15 -3
  51. package/dist/{validate-r9jdz85h.js → validate-z28cvr5x.js} +8 -8
  52. package/package.json +1 -1
@@ -19,7 +19,7 @@ import {
19
19
  stringValueAt,
20
20
  toFolioPage,
21
21
  wantsRecto
22
- } from "./index-5kh4c78h.js";
22
+ } from "./index-2vxzxyyj.js";
23
23
  import {
24
24
  launchChromium
25
25
  } from "./index-bt0qws5c.js";
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ import {
32
32
  connectGoogleDrive,
33
33
  connectPublishProvider,
34
34
  defaultConfigDir,
35
+ deleteRevision,
35
36
  deleteSnippet,
36
37
  describeVersions,
37
38
  diagnoseProjectRemote,
@@ -79,6 +80,7 @@ import {
79
80
  readPageSetup,
80
81
  readPublishSettings,
81
82
  refreshRemoteCopies,
83
+ renameRevision,
82
84
  repairOnlineBackup,
83
85
  reportMissingTools,
84
86
  requireGoogleClientCredentials,
@@ -100,6 +102,7 @@ import {
100
102
  runPublish,
101
103
  sanitizeCloneFolderName,
102
104
  saveProjectAsTemplate,
105
+ savePublishSettings,
103
106
  saveSnippet,
104
107
  scaffoldExtension,
105
108
  scaffoldProject,
@@ -116,7 +119,7 @@ import {
116
119
  substituteVariables,
117
120
  syncProject,
118
121
  testRemoteAccess
119
- } from "./index-ea94zbq4.js";
122
+ } from "./index-ejbfetdn.js";
120
123
  import {
121
124
  DEFAULT_NPM_REGISTRY,
122
125
  MANIFEST_FILENAMES,
@@ -146,7 +149,7 @@ import {
146
149
  setExtensionEnabled,
147
150
  updateExtensions,
148
151
  validateProjectExtensions
149
- } from "./index-kaks3mm2.js";
152
+ } from "./index-cmakyf43.js";
150
153
  import {
151
154
  BUNDLED_EXTENSIONS,
152
155
  EXTENSION_MANIFEST_FILENAME,
@@ -162,12 +165,12 @@ import {
162
165
  pathEscapesFolder,
163
166
  readExtensionMeta,
164
167
  resolveExtension
165
- } from "./index-8ywkd2sv.js";
168
+ } from "./index-1zqkfzcd.js";
166
169
  import"./index-ht1bcqdd.js";
167
170
  import {
168
171
  BUILD_DIAGNOSTIC_CODES
169
- } from "./index-yc3xj266.js";
170
- import"./index-5kh4c78h.js";
172
+ } from "./index-wm4x7xbf.js";
173
+ import"./index-2vxzxyyj.js";
171
174
  import {
172
175
  BuildError
173
176
  } from "./index-46ycxe6r.js";
@@ -183,14 +186,16 @@ import {
183
186
  RESTORE_BACKUP_MESSAGE,
184
187
  SWITCH_BRANCH_SNAPSHOT_MESSAGE,
185
188
  countUnversionedChanges,
189
+ createRevision,
186
190
  isNoChangesError,
187
- listLocalBranches,
191
+ listRevisions,
188
192
  providerFor,
189
193
  resolveLogger,
190
194
  restoreVersionWithBackup,
195
+ revisionNameFrom,
191
196
  switchBranch,
192
197
  whenGitIdle
193
- } from "./index-h6yk5tjx.js";
198
+ } from "./index-cw03e9p4.js";
194
199
  import {
195
200
  EXTENSIONS_DIR
196
201
  } from "./index-5x42amh8.js";
@@ -224,6 +229,7 @@ export {
224
229
  scaffoldProject,
225
230
  scaffoldExtension,
226
231
  saveSnippet,
232
+ savePublishSettings,
227
233
  saveProjectAsTemplate,
228
234
  sanitizeCloneFolderName,
229
235
  sameExtension,
@@ -234,6 +240,7 @@ export {
234
240
  ruleRiskyProps,
235
241
  ruleRemoteUrls,
236
242
  revokeGoogleCredential,
243
+ revisionNameFrom,
237
244
  restoreVersionWithBackup,
238
245
  restorePinnedExtensions,
239
246
  restoreFailureMessage,
@@ -255,6 +262,7 @@ export {
255
262
  repoRootForSource,
256
263
  repairOnlineBackup,
257
264
  reorderExtensions,
265
+ renameRevision,
258
266
  removeExtension,
259
267
  refreshRemoteCopies,
260
268
  readyProbeExpr,
@@ -278,6 +286,7 @@ export {
278
286
  loadManifestWithPath,
279
287
  loadManifest,
280
288
  listSnippets,
289
+ listRevisions,
281
290
  listRepoBooks,
282
291
  listPublishProviders,
283
292
  listPublishAccounts,
@@ -288,7 +297,6 @@ export {
288
297
  listMergedSnippets,
289
298
  listMarkerComponents,
290
299
  listLocationVariants,
291
- listLocalBranches,
292
300
  listGitHubRepositories,
293
301
  listGitHubBranches,
294
302
  listCustomTemplates,
@@ -329,7 +337,9 @@ export {
329
337
  describeVersions,
330
338
  describeExtension,
331
339
  deleteSnippet,
340
+ deleteRevision,
332
341
  defaultConfigDir,
342
+ createRevision,
333
343
  countUnversionedChanges,
334
344
  connectPublishProvider,
335
345
  connectGoogleDrive,
@@ -1,6 +1,7 @@
1
1
  import { type PublishDeps } from "./types.ts";
2
2
  export interface ConnectPublishProviderOptions {
3
- projectDir: string;
3
+ /** The book whose manifest settings the check reads; omit to connect with no book open. */
4
+ projectDir?: string;
4
5
  providerId: string;
5
6
  /** The pasted API key. NEVER log this. */
6
7
  token: string;
@@ -11,6 +12,12 @@ export interface ConnectPublishProviderOptions {
11
12
  */
12
13
  account?: string;
13
14
  manifestPath?: string;
15
+ /**
16
+ * With no `projectDir` only: Shopify's store address (`publish.shopify.shop`
17
+ * in a book's manifest), which its key check needs. Used for the check and
18
+ * never stored; ignored when a book supplies its own settings.
19
+ */
20
+ shop?: string;
14
21
  }
15
22
  /**
16
23
  * Verify `token` with the platform, then store it. Throws a friendly,
@@ -1,5 +1,10 @@
1
- /** All `publish.*` sections, as plain JSON keyed by provider id (absent → {}). */
2
- export declare function readPublishSettings(projectDir: string): Promise<Record<string, Record<string, unknown>>>;
1
+ import type { PublishSelectionsStore } from "./selections.ts";
2
+ /**
3
+ * All `publish.*` sections, as plain JSON keyed by provider id (absent → {}).
4
+ * With the person's private store, what they see: their own values for the
5
+ * book laid over the manifest's.
6
+ */
7
+ export declare function readPublishSettings(projectDir: string, selections?: Pick<PublishSelectionsStore, "settings">): Promise<Record<string, Record<string, unknown>>>;
3
8
  /**
4
9
  * Merge `values` into `publish.<providerId>`. A value of `undefined`, `null`
5
10
  * or `""` deletes that key; emptied sections (and an emptied `publish:` map)
@@ -7,3 +12,22 @@ export declare function readPublishSettings(projectDir: string): Promise<Record<
7
12
  * from the in-memory document — no re-read.
8
13
  */
9
14
  export declare function setPublishProviderConfig(projectDir: string, providerId: string, values: Record<string, unknown>): Promise<Record<string, Record<string, unknown>>>;
15
+ /**
16
+ * Save a provider's settings where each belongs. The team decides where the
17
+ * book is published, so that is shared and goes in the manifest
18
+ * ({@link setPublishProviderConfig}): which destinations, each one's target,
19
+ * store, folder, environment and format. Only what is one person's own goes in
20
+ * their private store, keyed to this book, and is removed from the manifest if
21
+ * an older book kept it there:
22
+ *
23
+ * - `credential`: which of their saved accounts the book publishes with.
24
+ * - the local output folder `dir`, when it lies outside the book (a personal
25
+ * override). A folder inside the book is shared, and is written relative to
26
+ * it (an absolute in-book path is rewritten) so it means the same thing on
27
+ * every computer. An absolute path is never written to the manifest.
28
+ *
29
+ * Only the values passed are classified; the manifest is not rewritten unless
30
+ * one of them changes it. Empty values clear. Returns the settings as the
31
+ * person now sees them ({@link readPublishSettings}).
32
+ */
33
+ export declare function savePublishSettings(projectDir: string, providerId: string, values: Record<string, unknown>, selections: Pick<PublishSelectionsStore, "settings" | "setSettings">): Promise<Record<string, Record<string, unknown>>>;
@@ -1,3 +1,5 @@
1
+ /** One provider's private values for a book (strings only, as the manifest's are). */
2
+ type BookSettings = Record<string, string>;
1
3
  /** Both levels' explicit selections for a provider (for the UI). */
2
4
  export interface PublishAccountSelection {
3
5
  project?: string;
@@ -20,6 +22,15 @@ export declare class PublishSelectionsStore {
20
22
  levels(providerId: string, projectDir?: string): Promise<PublishAccountSelection>;
21
23
  /** Set (or clear, with an empty account) the global default for a provider. */
22
24
  setGlobal(providerId: string, account: string | null): Promise<void>;
23
- /** Set (or clear) the default for one provider within one project. */
25
+ /** Set (or clear) the saved account one provider uses within one project. */
24
26
  setProject(projectDir: string, providerId: string, account: string | null): Promise<void>;
27
+ /** Every private value for one book, by provider id (empty when none). */
28
+ settings(projectDir: string): Promise<Record<string, BookSettings>>;
29
+ /**
30
+ * Merge `values` into one provider's private values for one book. A value of
31
+ * `null` or `""` clears that key; an emptied provider (and book) entry is
32
+ * removed rather than left dangling. Nothing is written when nothing changes.
33
+ */
34
+ setSettings(projectDir: string, providerId: string, values: Record<string, string | null>): Promise<void>;
25
35
  }
36
+ export {};
@@ -19,6 +19,7 @@
19
19
  * host responses.
20
20
  */
21
21
  import type { HostCredential, TokenStore } from "../remote-auth/token-store.ts";
22
+ import type { PublishSelectionsStore } from "./selections.ts";
22
23
  /**
23
24
  * One author-editable, NON-SECRET settings field (stored in the manifest's
24
25
  * `publish.<id>` section). Declared by each provider so settings UIs are
@@ -123,8 +124,9 @@ export interface PublishPluginContext {
123
124
  /** The one build output validated for this run: a PDF file, or the
124
125
  * website export directory. */
125
126
  artifact: PublishArtifact;
126
- /** The manifest's `publish.<package-name>` section, minus the two keys core
127
- * reads from it: `format` (which build to publish) and `credential`. */
127
+ /** The manifest's `publish.<package-name>` section, minus the keys core
128
+ * reads from it: `format` (which build to publish), `credential` and
129
+ * `enabled` (whether the desktop's Publish view ticks it). */
128
130
  settings: Record<string, unknown>;
129
131
  /** Progress line sink. Use this, never `console.log`: stdout carries
130
132
  * `--json` output. */
@@ -197,11 +199,19 @@ export interface PublishDeps {
197
199
  * keyed by a compound `<host>#<account>` for named accounts (see
198
200
  * {@link publishCredentialKey}); empty/undefined resolves the legacy
199
201
  * bare-host entry, so existing single-credential setups keep working. The
200
- * orchestrator sets this from the effective selection (book manifest →
201
- * project/global default); providers read it transparently via
202
- * {@link resolvePublishCredential}.
202
+ * orchestrator sets this from the effective selection (the person's private
203
+ * choice for the book → the book manifest → this front-end default);
204
+ * providers read it transparently via {@link resolvePublishCredential}.
203
205
  */
204
206
  credentialAccount?: string;
207
+ /**
208
+ * The person's PRIVATE publishing values for a book (see
209
+ * {@link PublishSelectionsStore}): which saved account to use and an output
210
+ * folder outside the book. When given, they win over the manifest's
211
+ * `publish.<id>` values in every request. Absent (the CLI today): the
212
+ * manifest alone.
213
+ */
214
+ selections?: Pick<PublishSelectionsStore, "settings">;
205
215
  }
206
216
  /**
207
217
  * The TokenStore key for a publishing provider credential. Named accounts use a
@@ -1,6 +1,6 @@
1
1
  import type { SyncOutcome, SyncProjectOptions } from "./sync-types.ts";
2
- /** Message recorded on the version a repair saves. */
3
- export declare const REPAIR_SNAPSHOT_MESSAGE = "Repaired online backup";
2
+ /** Message recorded on the version a repair saves (older history says "Repaired online backup"). */
3
+ export declare const REPAIR_SNAPSHOT_MESSAGE = "Repaired the online copy";
4
4
  export interface RepairOnlineBackupOptions extends Pick<SyncProjectOptions, "projectDir" | "credential" | "tokenStore" | "authorName" | "authorEmail" | "logFile" | "httpClient"> {
5
5
  /**
6
6
  * Where the old `.git` and the fresh download go — chosen by the host,
@@ -0,0 +1,60 @@
1
+ import { defaultGitHttp } from "./git-http.ts";
2
+ import type { HostCredential, TokenStore } from "./token-store.ts";
3
+ /** How the online copy is reached: the same options `refreshRemoteCopies` takes. */
4
+ interface OnlineOptions {
5
+ credential?: HostCredential;
6
+ tokenStore?: TokenStore;
7
+ httpClient?: typeof defaultGitHttp;
8
+ }
9
+ export interface RenameRevisionOptions extends OnlineOptions {
10
+ projectDir: string;
11
+ from: string;
12
+ /** The new name as typed; spaces become hyphens. */
13
+ to: string;
14
+ }
15
+ export interface DeleteRevisionOptions extends OnlineOptions {
16
+ projectDir: string;
17
+ name: string;
18
+ /** Also remove it from the online copy (when it is there); default: this computer only. */
19
+ everywhere?: boolean;
20
+ /** Delete even though the revision holds versions found nowhere else. */
21
+ discard?: boolean;
22
+ }
23
+ /**
24
+ * Rename a revision. The open revision may be renamed (the book stays open on it).
25
+ *
26
+ * One that is also in the online copy is renamed there too, in an order that
27
+ * never loses anything, so each failure leaves a known state:
28
+ * 1. send the new name online — a failure leaves everything as it was;
29
+ * 2. remove the old name online — a failure removes the new name again, so
30
+ * everything is as it was; only if that can't be done either (the network
31
+ * dropped between the two) does the online copy keep both names, which the
32
+ * error says;
33
+ * 3. rename on this computer — only a local failure is possible here, and it
34
+ * leaves the online copy renamed and this computer under the old name, still
35
+ * listed (the new name shows as online-only).
36
+ * Offline or a rejected sign-in: nothing is renamed, anywhere.
37
+ */
38
+ export declare function renameRevision(options: RenameRevisionOptions): Promise<{
39
+ current: string | null;
40
+ name: string;
41
+ }>;
42
+ /**
43
+ * Delete a revision. Never the open one. By default only on this computer
44
+ * (a copy in the online copy stays, and shows as online-only); `everywhere`
45
+ * removes it from the online copy first, then here — a failure online leaves
46
+ * everything as it was, a failure here leaves it removed online and still
47
+ * listed on this computer.
48
+ *
49
+ * Nothing found only in the revision is deleted without a second look: when it
50
+ * holds versions found in no other revision (and, unless deleted everywhere, not
51
+ * in the online copy), the first call returns how many and deletes nothing; the
52
+ * caller asks and calls again with `discard: true`.
53
+ */
54
+ export declare function deleteRevision(options: DeleteRevisionOptions): Promise<{
55
+ deleted: true;
56
+ } | {
57
+ deleted: false;
58
+ versionsOnlyHere: number;
59
+ }>;
60
+ export {};
@@ -1,12 +1,12 @@
1
1
  import type { SyncProjectOptions } from "./sync-types.ts";
2
2
  export interface ScorchedEarthOptions extends Pick<SyncProjectOptions, "projectDir" | "credential" | "tokenStore" | "logFile" | "httpClient"> {
3
- /** Where the full copy of the folder goes — OUTSIDE the folder. Kept indefinitely. */
3
+ /** Where the safety folder goes — OUTSIDE the book's folder. Kept indefinitely. */
4
4
  backupDir: string;
5
5
  }
6
6
  export interface ScorchedEarthResult {
7
7
  /** The folder that was reset (the repo root of `projectDir`). */
8
8
  dir: string;
9
- /** Where the full copy of the folder (old `.git` included) was kept. */
9
+ /** Where the safety folder (the old folder, `.git` included) was kept. */
10
10
  backupDir: string;
11
11
  /** The branch the fresh copy has checked out. */
12
12
  branch?: string;
@@ -1,39 +1,40 @@
1
1
  /**
2
- * Author-language copy for sync (never raw git words). Extracted from sync.ts
3
- * so the transport and orchestrator modules share ONE source of these
4
- * strings — their exact wording is part of the observable contract (the host
5
- * renders them verbatim).
2
+ * Author-language copy for backing up and getting the latest — never sync,
3
+ * push, pull, repository, branch or snapshot. Extracted from sync.ts so the
4
+ * transport and orchestrator modules share ONE source of these strings — their
5
+ * exact wording is part of the observable contract (the host renders them
6
+ * verbatim).
6
7
  */
7
- export declare const MSG_UP_TO_DATE = "Everything is in sync.";
8
- export declare const MSG_UP_TO_DATE_PULLED = "Everything is in sync. The latest online changes were downloaded to this computer.";
8
+ export declare const MSG_UP_TO_DATE = "You're up to date with the online copy.";
9
+ export declare const MSG_UP_TO_DATE_PULLED = "You're up to date. The latest changes from the online copy were downloaded to this computer.";
9
10
  export declare const MSG_SYNCED = "Your changes are online.";
10
11
  export declare const MSG_SYNCED_MERGED = "Your changes are online, combined with changes from the online copy.";
11
- export declare const MSG_OFFLINE = "Your changes are saved on this computer. Gutterpress couldn't reach the online repository \u2014 try syncing again when you're back online.";
12
- export declare const MSG_AUTH = "The online repository didn't accept the saved connection. Reconnect and try again.";
13
- export declare const MSG_INSECURE_TRANSPORT = "This book's online address isn't secure, so the saved connection wasn't sent \u2014 connections are never sent over an insecure address. Switch the address to a secure one (starting with https), or to a local loopback address for a server on this computer, to sync.";
14
- export declare const MSG_BUSY = "The online copy is changing very quickly right now. Your work is saved on this computer \u2014 try Sync again in a moment.";
12
+ export declare const MSG_OFFLINE = "Your changes are saved on this computer. Gutterpress couldn't reach the online copy \u2014 try again when you're back online.";
13
+ export declare const MSG_AUTH = "The online copy didn't accept the saved sign-in. Sign in again and try again.";
14
+ export declare const MSG_INSECURE_TRANSPORT = "This book's online copy is at an address that isn't secure, so the saved sign-in wasn't sent \u2014 sign-ins are never sent over an insecure address. Switch the address to a secure one (starting with https), or to a local loopback address for a server on this computer, to back up.";
15
+ export declare const MSG_BUSY = "The online copy is changing very quickly right now. Your work is saved on this computer \u2014 try again in a moment.";
15
16
  /**
16
- * The book's own version history is unreadable — a damaged or missing
17
- * `.git`. Says the three things that are actually true and useful: the writing
18
- * is safe, the HISTORY is what broke, and (sync always has a remote, so this
19
- * always applies here) Repair online backup is the way back.
17
+ * The book's own versions are unreadable — a damaged or missing `.git`. Says
18
+ * the three things that are actually true and useful: the writing is safe, the
19
+ * VERSIONS are what broke, and (backing up always has an online copy, so this
20
+ * always applies here) "Repair the online copy" is the way back.
20
21
  */
21
- export declare const MSG_HISTORY_UNREADABLE = "This book's version history can't be read, so syncing can't continue. Your writing is safe \u2014 every file is still here on this computer. Use Repair online backup (in Where your work is kept) to get history and syncing working again.";
22
- export declare const MSG_UNRELATED = "This book and the online copy have no history in common, so they can't be combined. Either the online address points at a different book, or this book's own history was lost and started over. Your writing is safe \u2014 every file is still here on this computer. Check the online address; if it is correct, use Repair online backup (in Where your work is kept).";
23
- export declare const MSG_NO_REMOTE = "This book isn't connected to an online repository yet.";
24
- export declare const MSG_SSH_REMOTE = "This book's online address uses SSH (git@\u2026), which Gutterpress can't sync to. Switch it to the web (HTTPS) address to sync from here.";
25
- export declare const MSG_NO_BRANCH = "This book's version history isn't on a named branch, so it can't be synced right now.";
26
- /** Message recorded on the automatic pre-sync snapshot (D5 invariant).
27
- * Pre-0.10.1 history carries the old spelling "Snapshot before syncing". */
28
- export declare const SYNC_SNAPSHOT_MESSAGE = "Automatic backup of your work";
22
+ export declare const MSG_HISTORY_UNREADABLE = "This book's versions can't be read, so backing up can't continue. Your writing is safe \u2014 every file is still here on this computer. Use \"Repair the online copy\" (in Book setup \u2192 Online copy) to get versions and backing up working again.";
23
+ export declare const MSG_UNRELATED = "This book and the online copy have no versions in common, so they can't be combined. Either the online copy's address points at a different book, or this book's own versions were lost and started over. Your writing is safe \u2014 every file is still here on this computer. Check the online copy's address; if it is correct, use \"Repair the online copy\" (in Book setup \u2192 Online copy).";
24
+ export declare const MSG_NO_REMOTE = "This book doesn't have an online copy yet.";
25
+ export declare const MSG_SSH_REMOTE = "This book's online copy uses an SSH address (git@\u2026), which Gutterpress can't back up to. Switch it to the web (HTTPS) address to back up from here.";
26
+ export declare const MSG_NO_BRANCH = "This book isn't on a named revision, so it can't be backed up right now.";
27
+ /** Message recorded on the automatic version saved before backing up (D5 invariant).
28
+ * Older history carries the spellings "Automatic backup of your work" and,
29
+ * before 0.10.1, "Snapshot before syncing". */
30
+ export declare const SYNC_SNAPSHOT_MESSAGE = "Automatic version before backing up";
29
31
  /**
30
32
  * Message recorded when an edit reached disk while the fetch was in flight —
31
- * after the pre-sync snapshot, before the merge (see the re-snapshot in
32
- * `syncProject`). Distinct wording so the race is legible in history; the
33
- * copy is already writer-voiced, so it deliberately stays unchanged (every
34
- * rename permanently grows the timeline's superseded-spelling list).
33
+ * after the pre-backup version, before the merge (see the re-snapshot in
34
+ * `syncProject`). Distinct wording so the race is legible in history. Older
35
+ * history carries the spelling "Saved the edit you made while syncing".
35
36
  */
36
- export declare const SYNC_LATE_EDIT_MESSAGE = "Saved the edit you made while syncing";
37
+ export declare const SYNC_LATE_EDIT_MESSAGE = "Saved the edit you made while backing up";
37
38
  /**
38
39
  * The keep-both sibling contract, kept HERE rather than in converge-merge.ts
39
40
  * because every consumer needs it and converge-merge pulls in isomorphic-git:
@@ -54,6 +54,9 @@ export type SyncOutcome = {
54
54
  * and then hold the push — the converge report still surfaces here. */
55
55
  combinedFiles?: string[];
56
56
  keptBothFiles?: KeptBothFile[];
57
+ /** A pull-merge-only pass that held the push: this computer has versions
58
+ * the online copy lacks. Never set when the tips already matched. */
59
+ pushDeferred?: true;
57
60
  } | {
58
61
  status: "auth";
59
62
  message: string;
@@ -29,26 +29,25 @@ export declare function isUnrelatedHistories(e: unknown): boolean;
29
29
  */
30
30
  export declare function syncProject(options: SyncProjectOptions): Promise<SyncOutcome>;
31
31
  /**
32
- * Fetch every branch the remote has, so the project's copy list reflects what
32
+ * Fetch every branch the remote has, so the book's revision list reflects what
33
33
  * exists online rather than only what this clone happened to fetch before.
34
34
  *
35
- * The copy picker reads refs off disk (`listLocalBranches`). That makes a
36
- * branch pushed from anywhere else — another machine, the web UI, an agent
37
- * opening a PR — invisible here until someone runs `git fetch` in a terminal,
38
- * which is precisely the thing this app exists to avoid. So the picker calls
39
- * this first.
35
+ * `listRevisions` reads refs off disk. That makes a branch pushed from anywhere
36
+ * else — another machine, the web UI, an agent opening a PR — invisible here
37
+ * until someone runs `git fetch` in a terminal, which is precisely the thing
38
+ * this app exists to avoid. So the revision list calls this first.
40
39
  *
41
40
  * Unlike `fetchRemoteTip` this deliberately does NOT use `singleBranch`: the
42
41
  * whole point is the branches we do not have yet. It only ever writes
43
42
  * remote-tracking refs (`refs/remotes/<remote>/*`) — no local branch, no
44
43
  * working-tree change, no merge — so it is safe to call on a dirty tree.
45
44
  * `prune` drops tracking refs for branches deleted online, so the list cannot
46
- * offer a copy that is gone.
45
+ * offer a revision that is gone.
47
46
  *
48
47
  * Best-effort by contract: offline, unauthenticated, or no remote at all
49
48
  * resolves to `{ refreshed: false, reason }` rather than throwing. A stale
50
49
  * list beats an error dialog over a control the author did not explicitly ask
51
- * to sync — but it reports WHY, because a picker that silently omits copies
50
+ * to sync — but it reports WHY, because a list that silently omits revisions
52
51
  * is indistinguishable from a broken one, which is the bug this whole
53
52
  * function exists to fix.
54
53
  */
@@ -107,8 +107,15 @@ export declare function currentBranchOrThrow(dir: string): Promise<string>;
107
107
  export declare function guardTrackingRef<T>(dir: string, ref: string, cache: GitCache, fn: () => Promise<T>): Promise<T>;
108
108
  /**
109
109
  * Fetch the tracked branch's online tip. Returns `null` when the online
110
- * repository has no such branch yet (a freshly created empty repo).
110
+ * copy has no such revision yet (a freshly created empty repo, or a revision
111
+ * started on this computer).
111
112
  */
112
113
  export declare function fetchRemoteTip(dir: string, branch: string, transport: RemoteTransport, http: typeof httpNode, cache: GitCache): Promise<string | null>;
114
+ /**
115
+ * The online copy's tip for `branch` as the server advertises it right now.
116
+ * Reads refs only (`listServerRefs`: no objects downloaded, no history walked,
117
+ * nothing written); `undefined` when the online copy has no such revision.
118
+ */
119
+ export declare function serverTip(transport: RemoteTransport, branch: string, http: typeof httpNode): Promise<string | undefined>;
113
120
  /** First 8 chars of an oid for diagnostic log lines (null-safe). */
114
121
  export declare function short(oid: string | null | undefined): string;