gutterpress 0.11.21 → 0.11.22-alpha.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 (51) hide show
  1. package/README.md +11 -0
  2. package/dist/api/index.d.ts +5 -1
  3. package/dist/api/index.js +67 -46
  4. package/dist/{build-0neyk5h6.js → build-se85j9ec.js} +16 -10
  5. package/dist/cli-5553w972.js +75 -0
  6. package/dist/{cli-b57adna7.js → cli-8hccw62p.js} +9 -201
  7. package/dist/cli-9vy4b6ec.js +2089 -0
  8. package/dist/{cli-sqkccnm7.js → cli-d8xjns66.js} +1 -102
  9. package/dist/{cli-j0drzb6f.js → cli-fbwqv7p4.js} +720 -5428
  10. package/dist/cli-gc9av5hs.js +103 -0
  11. package/dist/cli-gmm3bdeq.js +196 -0
  12. package/dist/cli-h3phdstf.js +200 -0
  13. package/dist/{index-qf7y4d85.js → cli-habkc5ng.js} +12 -258
  14. package/dist/cli-pfrg1r9x.js +3073 -0
  15. package/dist/{cli-j79451n6.js → cli-yejbb9f8.js} +5 -76
  16. package/dist/cli.js +15 -13
  17. package/dist/{doctor-fptq8tvn.js → doctor-bv2t82zd.js} +7 -4
  18. package/dist/{engine-x07q927h.js → engine-h4ehmrvf.js} +4 -3
  19. package/dist/{engine-0b8bt05n.js → engine-qwkyhrej.js} +3 -2
  20. package/dist/{ext-gp624t5c.js → ext-a8ndp142.js} +21 -14
  21. package/dist/extension-restore-926mv2qk.js +16 -0
  22. package/dist/extension-restore-q1f7njec.js +20 -0
  23. package/dist/index-38e18a7j.js +3244 -0
  24. package/dist/{index-mr72vt8n.js → index-5h9a38jn.js} +1 -213
  25. package/dist/{cli-5qr3z0qa.js → index-93pqkvty.js} +63 -207
  26. package/dist/index-dhknsvfz.js +213 -0
  27. package/dist/index-dm7hx46j.js +2208 -0
  28. package/dist/{index-t7r8g75c.js → index-gmfh6n05.js} +4 -2
  29. package/dist/index-r7jcsk6h.js +200 -0
  30. package/dist/{index-mr7zs8mv.js → index-tkjvs1gf.js} +4774 -9354
  31. package/dist/index.js +70 -49
  32. package/dist/lib/extension-manifest.d.ts +22 -1
  33. package/dist/lib/markdown/plugins.d.ts +20 -0
  34. package/dist/lib/markdown/two-versions.d.ts +32 -0
  35. package/dist/lib/publish/plugin-provider.d.ts +16 -0
  36. package/dist/lib/publish/run-publish.d.ts +13 -5
  37. package/dist/lib/publish/types.d.ts +34 -2
  38. package/dist/lib/text-diff.d.ts +43 -0
  39. package/dist/lib/two-versions-markers.d.ts +26 -0
  40. package/dist/lib/version-changes.d.ts +87 -0
  41. package/dist/{new-dre6aw05.js → new-nadp2hvb.js} +23 -16
  42. package/dist/plugins-gy4q9vaa.js +26 -0
  43. package/dist/plugins-yeh4shd7.js +24 -0
  44. package/dist/{preflight-1k1zkg1p.js → preflight-c6q25xqa.js} +18 -11
  45. package/dist/{preview-dtrksvxf.js → preview-y8chv4cb.js} +19 -13
  46. package/dist/{publish-g1ytnrmr.js → publish-3qwvxsxa.js} +40 -23
  47. package/dist/render.js +120 -0
  48. package/dist/{source-provider-pzmz0br9.js → source-provider-2r74a7wp.js} +2 -1
  49. package/dist/{source-provider-qbthnmqw.js → source-provider-qbfknhyy.js} +2 -1
  50. package/dist/{validate-yrrq8639.js → validate-w108kk87.js} +16 -10
  51. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,58 +4,42 @@ import {
4
4
  AUTO_SYNC_MAX_MINUTES,
5
5
  AUTO_SYNC_MIN_MINUTES,
6
6
  AUTO_SYNC_PUSH_INTERVAL_MINUTES,
7
- BUILT_IN_STYLE_SET_IDS,
8
7
  BUILT_IN_TEMPLATE_IDS,
9
- BUNDLED_EXTENSIONS,
10
- DEFAULT_NPM_REGISTRY,
11
- EXTENSIONS_DIR,
12
8
  EXTENSION_KINDS,
13
- EXTENSION_MANIFEST_FILENAME,
14
9
  FileTokenStore,
15
10
  GDRIVE_HOST,
16
11
  GITHUB_HOST,
17
12
  GOOGLE_NOT_CONFIGURED_MESSAGE,
18
13
  GitHubAuthProvider,
19
14
  GoogleAuthProvider,
20
- MANIFEST_FILENAMES,
21
15
  MAX_SEARCH_BYTES,
22
- PRESETS,
23
- PRESET_IDS,
24
16
  PublishSelectionsStore,
25
- RECOMMENDED_EXTENSIONS,
26
17
  REPAIR_SNAPSHOT_MESSAGE,
27
18
  RESERVED_PREFIX,
28
19
  SEARCH_KEYWORDS,
29
20
  SNIPPETS_DIR,
30
21
  SYNC_SNAPSHOT_MESSAGE,
31
- TARGETS,
32
- TARGET_IDS,
33
- addBuiltInStyleSet,
34
- addExtension,
22
+ VERSION_CHANGES_SHOWN,
35
23
  adoptFolder,
36
- assertExtensionContained,
37
24
  autoSnapshotDelayMs,
38
25
  autoSyncDelayMs,
39
26
  checkCss,
40
- checkExtensionUpdates,
41
27
  checkRemoteUpdates,
42
28
  checkToolAvailability,
43
29
  cloneRepository,
30
+ compareVersionFile,
44
31
  connectGenericHost,
45
32
  connectGoogleDrive,
46
33
  connectPublishProvider,
47
34
  defaultConfigDir,
48
35
  deleteSnippet,
49
- describeExtension,
36
+ describeVersions,
50
37
  diagnoseProjectRemote,
51
38
  disconnectPublishCredential,
52
- ensureProjectGitignore,
53
39
  escapeYamlScalar,
54
40
  executeAndReport,
55
41
  executeValidation,
56
- extensionCarries,
57
- extensionEntry,
58
- extensionStyleList,
42
+ exportVersionTree,
59
43
  extractUrlCredential,
60
44
  extractVariables,
61
45
  forgeKindForHost,
@@ -63,18 +47,15 @@ import {
63
47
  getCheckById,
64
48
  getChecks,
65
49
  getSystemDiagnostics,
66
- hasProjectManifest,
67
50
  importExtensionFromFile,
68
51
  importExtensionFromUrl,
69
52
  importTemplateFromFolder,
70
53
  inspectImage,
71
- isBundledExtension,
72
54
  isGitInternalPath,
73
- isPathSpecifier,
74
55
  isSshRemoteUrl,
75
56
  isValidRepositoryName,
76
57
  knownForgeTokenUrl,
77
- listBuiltInStyleSets,
58
+ listBookPublishProviders,
78
59
  listBuiltInTemplates,
79
60
  listCustomTemplates,
80
61
  listGitHubBranches,
@@ -82,49 +63,34 @@ import {
82
63
  listLocationVariants,
83
64
  listMarkerComponents,
84
65
  listMergedSnippets,
85
- listNpmVersions,
86
- listProjectExtensions,
66
+ listOnlineVersions,
87
67
  listProjectStyles,
88
68
  listPublishAccounts,
89
69
  listPublishProviders,
90
70
  listRepoBooks,
91
71
  listSnippets,
92
- loadManifest,
93
- loadManifestWithPath,
94
- log,
95
- npmRegistryUrl,
96
72
  openPath,
97
- parseExtensionSpecifier,
98
73
  parseRemoteOrigin,
99
- pathEscapesFolder,
100
74
  pkceChallengeFromVerifier,
101
75
  publishConnectionStatus,
102
76
  publishCredentialKey,
103
77
  publishProviderFor,
104
- publishTargetFor,
105
- readExtensionCss,
106
- readExtensionMeta,
107
78
  readManifestFields,
108
79
  readPageSetup,
109
80
  readPublishSettings,
110
81
  refreshRemoteCopies,
111
- removeExtension,
112
- reorderExtensions,
113
82
  repairOnlineBackup,
114
83
  reportMissingTools,
115
84
  requireGoogleClientCredentials,
116
85
  resolveActiveStyles,
117
86
  resolveCheckSelectors,
118
- resolveConfig,
119
- resolveExtension,
120
87
  resolveExtensionPrefix,
121
88
  resolveGitHubClientId,
122
89
  resolveGoogleClientId,
123
90
  resolveGoogleClientSecret,
124
91
  resolvePublishFormat,
92
+ resolvePublishProvider,
125
93
  resolvePublishRequest,
126
- restoreFailureMessage,
127
- restorePinnedExtensions,
128
94
  revokeGoogleCredential,
129
95
  ruleRemoteUrls,
130
96
  ruleRiskyProps,
@@ -132,7 +98,6 @@ import {
132
98
  runBuild,
133
99
  runChecks,
134
100
  runPublish,
135
- sameExtension,
136
101
  sanitizeCloneFolderName,
137
102
  saveProjectAsTemplate,
138
103
  saveSnippet,
@@ -141,7 +106,6 @@ import {
141
106
  scorchedEarth,
142
107
  searchNpmExtensions,
143
108
  setActiveStyles,
144
- setExtensionEnabled,
145
109
  setManifestFields,
146
110
  setPageSetup,
147
111
  setPublishProviderConfig,
@@ -151,17 +115,65 @@ import {
151
115
  startPreviewServer,
152
116
  substituteVariables,
153
117
  syncProject,
154
- testRemoteAccess,
118
+ testRemoteAccess
119
+ } from "./index-tkjvs1gf.js";
120
+ import {
121
+ BUILT_IN_STYLE_SET_IDS,
122
+ BUNDLED_EXTENSIONS,
123
+ DEFAULT_NPM_REGISTRY,
124
+ EXTENSIONS_DIR,
125
+ MANIFEST_FILENAMES,
126
+ PRESETS,
127
+ PRESET_IDS,
128
+ RECOMMENDED_EXTENSIONS,
129
+ TARGETS,
130
+ TARGET_IDS,
131
+ addBuiltInStyleSet,
132
+ addExtension,
133
+ checkExtensionUpdates,
134
+ describeExtension,
135
+ ensureProjectGitignore,
136
+ hasProjectManifest,
137
+ isBundledExtension,
138
+ isPathSpecifier,
139
+ listBuiltInStyleSets,
140
+ listNpmVersions,
141
+ listProjectExtensions,
142
+ loadManifest,
143
+ loadManifestWithPath,
144
+ npmRegistryUrl,
145
+ parseExtensionSpecifier,
146
+ publishTargetFor,
147
+ readExtensionCss,
148
+ removeExtension,
149
+ reorderExtensions,
150
+ resolveConfig,
151
+ restoreFailureMessage,
152
+ restorePinnedExtensions,
153
+ sameExtension,
154
+ setExtensionEnabled,
155
155
  updateExtensions,
156
156
  validateProjectExtensions
157
- } from "./index-mr7zs8mv.js";
157
+ } from "./index-dm7hx46j.js";
158
+ import {
159
+ EXTENSION_MANIFEST_FILENAME,
160
+ assertExtensionContained,
161
+ extensionCarries,
162
+ extensionEntry,
163
+ extensionStyleList,
164
+ log,
165
+ pathEscapesFolder,
166
+ readExtensionMeta,
167
+ resolveExtension
168
+ } from "./index-38e18a7j.js";
158
169
  import"./index-ht1bcqdd.js";
159
170
  import {
160
171
  BUILD_DIAGNOSTIC_CODES
161
- } from "./index-t7r8g75c.js";
172
+ } from "./index-gmfh6n05.js";
173
+ import"./index-5h9a38jn.js";
162
174
  import {
163
175
  BuildError
164
- } from "./index-mr72vt8n.js";
176
+ } from "./index-dhknsvfz.js";
165
177
  import"./index-sth219v1.js";
166
178
  import {
167
179
  DEFAULT_PRINT_OPTS,
@@ -171,7 +183,6 @@ import {
171
183
  import {
172
184
  AUTO_SNAPSHOT_MESSAGE,
173
185
  HISTORY_PAGE_LIMIT,
174
- PLUGINS_DIR,
175
186
  RESTORE_BACKUP_MESSAGE,
176
187
  SWITCH_BRANCH_SNAPSHOT_MESSAGE,
177
188
  countUnversionedChanges,
@@ -182,7 +193,10 @@ import {
182
193
  restoreVersionWithBackup,
183
194
  switchBranch,
184
195
  whenGitIdle
185
- } from "./index-qf7y4d85.js";
196
+ } from "./index-93pqkvty.js";
197
+ import {
198
+ PLUGINS_DIR
199
+ } from "./index-r7jcsk6h.js";
186
200
  import {
187
201
  capabilitiesFor,
188
202
  detectProjectSource,
@@ -227,6 +241,7 @@ export {
227
241
  restorePinnedExtensions,
228
242
  restoreFailureMessage,
229
243
  resolvePublishRequest,
244
+ resolvePublishProvider,
230
245
  resolvePublishFormat,
231
246
  resolveLogger,
232
247
  resolveGoogleClientSecret,
@@ -271,6 +286,7 @@ export {
271
286
  listPublishAccounts,
272
287
  listProjectStyles,
273
288
  listProjectExtensions,
289
+ listOnlineVersions,
274
290
  listNpmVersions,
275
291
  listMergedSnippets,
276
292
  listMarkerComponents,
@@ -281,6 +297,7 @@ export {
281
297
  listCustomTemplates,
282
298
  listBuiltInTemplates,
283
299
  listBuiltInStyleSets,
300
+ listBookPublishProviders,
284
301
  knownForgeTokenUrl,
285
302
  isValidRepositoryName,
286
303
  isSshRemoteUrl,
@@ -304,6 +321,7 @@ export {
304
321
  extensionStyleList,
305
322
  extensionEntry,
306
323
  extensionCarries,
324
+ exportVersionTree,
307
325
  executeValidation,
308
326
  executeAndReport,
309
327
  escapeYamlScalar,
@@ -311,6 +329,7 @@ export {
311
329
  disconnectPublishCredential,
312
330
  diagnoseProjectRemote,
313
331
  detectProjectSource,
332
+ describeVersions,
314
333
  describeExtension,
315
334
  deleteSnippet,
316
335
  defaultConfigDir,
@@ -318,6 +337,7 @@ export {
318
337
  connectPublishProvider,
319
338
  connectGoogleDrive,
320
339
  connectGenericHost,
340
+ compareVersionFile,
321
341
  cloneRepository,
322
342
  checkToolAvailability,
323
343
  checkRemoteUpdates,
@@ -331,6 +351,7 @@ export {
331
351
  adoptFolder,
332
352
  addExtension,
333
353
  addBuiltInStyleSet,
354
+ VERSION_CHANGES_SHOWN,
334
355
  TARGET_IDS,
335
356
  TARGETS,
336
357
  SYNC_SNAPSHOT_MESSAGE,
@@ -70,6 +70,15 @@ export interface ExtensionMetadata {
70
70
  * does the merge.
71
71
  */
72
72
  snippets?: string;
73
+ /**
74
+ * `gutterpress.publish: true` — EXPERIMENTAL (#381): the package is a
75
+ * publishing plugin. Its entry (npm `main`/`exports`, or a folder's `main`)
76
+ * exports a named `publish` function and contributes NO markdown-it plugin,
77
+ * so the markdown loader skips it without importing it. A boolean, not a
78
+ * path: it lets core recognise a publisher from package.json alone, without
79
+ * executing its code. Anything other than literal `true` reads as absent.
80
+ */
81
+ publish?: boolean;
73
82
  /**
74
83
  * npm `engines.gutterpress` — the Gutterpress versions the extension works
75
84
  * with, as a semver range (e.g. `">=0.11.20-alpha.3"`). Checked when the
@@ -98,7 +107,8 @@ export declare function extensionStyleList(meta: ExtensionMetadata): string[];
98
107
  * The markdown-it entry of a FOLDER extension: an explicit
99
108
  * `gutterpress.markdown` when the package's `main` is not the plugin,
100
109
  * otherwise npm's own `main`. `undefined` for a folder that carries no
101
- * markdown behaviour at all (a look).
110
+ * markdown behaviour at all (a look, or a publishing plugin — whose `main` is
111
+ * its publish module, not a markdown-it plugin).
102
112
  */
103
113
  export declare function extensionEntry(meta: ExtensionMetadata): string | undefined;
104
114
  /** What an extension declares, by field — the desktop's one-list filter. */
@@ -107,8 +117,19 @@ export interface ExtensionCarries {
107
117
  styles: boolean;
108
118
  snippets: boolean;
109
119
  components: boolean;
120
+ /** A publishing plugin (experimental, #381). */
121
+ publish: boolean;
110
122
  }
111
123
  export declare function extensionCarries(meta: ExtensionMetadata): ExtensionCarries;
124
+ /**
125
+ * A publishing plugin (experimental, #381) is a publisher and nothing else:
126
+ * its entry is never imported while a book renders, so a markdown entry,
127
+ * styles, components or snippets it also declared would either load (a
128
+ * folder) or be dropped without a word (a vendored copy). One rule, checked
129
+ * here, keeps both load paths and the publish path agreeing. Not a listing
130
+ * guard — `readExtensionMeta` stays tolerant.
131
+ */
132
+ export declare function assertPublishOnly(meta: ExtensionMetadata, ref: string): void;
112
133
  /**
113
134
  * True when a declared relative path escapes its own folder (absolute, or a
114
135
  * `..` segment) — the traversal shape every containment check in this
@@ -1,4 +1,5 @@
1
1
  import type { ResolvedExtensionConfig } from "../../schema/manifest.types";
2
+ import type { PublishPluginFunction } from "../publish/types";
2
3
  import type { LoadedPlugin } from "./renderer";
3
4
  export type { GutterpressComponent, GutterpressComponentBlock, GutterpressComponentProblem, GutterpressMarkerDeclaration, GutterpressMarkerLabel, GutterpressMarkerTable, GutterpressPlugin, GutterpressPluginMetadata, GutterpressPluginExport, LoadedPlugin, } from "./renderer";
4
5
  export { applyPlugins, collectPluginCss, collectPluginStylePaths, collectPluginStyleGroups } from "./renderer";
@@ -7,6 +8,25 @@ import { type PluginStyleGroup } from "./renderer";
7
8
  /** Test-only: reset the path-plugin cache between test cases. */
8
9
  export declare function __resetPathPluginCacheForTests(): void;
9
10
  export declare function loadPlugin(config: ResolvedExtensionConfig, baseDir: string): Promise<LoadedPlugin>;
11
+ /** Where a publishing plugin's package sits, as discovery found it. */
12
+ export interface PublishPluginLocation {
13
+ /** The package folder: a `path:` folder, or the vendored copy's package dir. */
14
+ dir: string;
15
+ /** The vendored install root of an npm entry; `null` for a folder. */
16
+ installRoot: string | null;
17
+ /** The manifest spelling, for messages. */
18
+ ref: string;
19
+ }
20
+ /**
21
+ * EXPERIMENTAL (#381): import a publishing plugin's entry and return its
22
+ * named `publish` export. Only the publish path calls this — never a build or
23
+ * preview (see the skip in {@link loadPlugin}). The package is the one
24
+ * discovery located, so there is no second lookup and no fall-through to a
25
+ * same-named package elsewhere: a vendored copy loads through
26
+ * {@link importVendoredEntry}, a folder's `main` through the mtime cache, so
27
+ * the long-lived desktop host sees edits.
28
+ */
29
+ export declare function loadPublishFunction({ dir, installRoot, ref }: PublishPluginLocation): Promise<PublishPluginFunction>;
10
30
  /**
11
31
  * Load all plugins from the resolved configuration.
12
32
  *
@@ -0,0 +1,32 @@
1
+ /**
2
+ * `two_versions` — renders a passage the converge merge left with TWO
3
+ * versions as two labelled boxes instead of broken markdown.
4
+ *
5
+ * After a sync that found a passage edited both here and online, the file
6
+ * holds both versions inside the marker family `two-versions-markers.ts`
7
+ * spells out. Those lines are valid markdown — `=======` is a setext
8
+ * underline, `>>>>>>>` seven nested blockquotes — so until this rule the
9
+ * preview showed the author's paragraph as a chapter-sized heading, listed
10
+ * `<<<<<<< your version` in the outline, and gave no way to read either
11
+ * version as it would print. The `source.sync.merge-markers` check still
12
+ * reports every block as an error, so a build never ships one; this rule
13
+ * only decides what the LIVE PREVIEW shows while the author chooses.
14
+ *
15
+ * The output is plain HTML + CSS: a `div.gp-two-versions` holding two
16
+ * `div.gp-version`s (`-yours`, `-online`), each labelled through
17
+ * `data-label` and each parsed as ordinary block markdown, so a heading or
18
+ * a list inside a version renders as one. No viewer or print code reads
19
+ * these classes; `TWO_VERSIONS_CSS` is the whole styling. Matching is as
20
+ * exact as the check's: the three fixed lines, at the start of a line, in
21
+ * order; anything else (a bare `=======`, a half-deleted family) is left
22
+ * to markdown as before.
23
+ */
24
+ import type MarkdownIt from "markdown-it";
25
+ /** The styling for the block above — injected by assemble.ts with MARKER_CSS. */
26
+ export declare const TWO_VERSIONS_CSS = "\n.gp-two-versions {\n margin: 1em 0;\n border: 2px dashed #b7791f;\n border-radius: 6px;\n break-inside: avoid;\n}\n.gp-two-versions > .gp-version {\n padding: 0.5em 0.9em;\n}\n.gp-two-versions > .gp-version + .gp-version {\n border-top: 2px dashed #b7791f;\n}\n.gp-two-versions > .gp-version > .gp-version-text {\n margin: 0;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font-size: 0.85em;\n}\n.gp-two-versions > .gp-version::before {\n content: attr(data-label);\n display: block;\n margin-bottom: 0.35em;\n font-family: system-ui, sans-serif;\n font-size: 0.7em;\n font-weight: 700;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: #b7791f;\n}\n";
27
+ /**
28
+ * markdown-it plugin. Before `html_block` so the `<` opener is ours first;
29
+ * listed as a paragraph terminator so a block that starts right under a
30
+ * line of prose (as the merge writes it) still opens.
31
+ */
32
+ export default function gpTwoVersions(md: MarkdownIt): void;
@@ -0,0 +1,16 @@
1
+ import type { PublishProvider, PublishProviderInfo } from "./types.ts";
2
+ /** The book whose `extensions:` are searched — the pair runPublish takes. */
3
+ export interface PublishBook {
4
+ projectDir: string;
5
+ manifestPath?: string;
6
+ }
7
+ /** Built-in providers, then the book's enabled publishing plugins. Reads
8
+ * package.json only; a book whose manifest can't be read lists the built-ins. */
9
+ export declare function listBookPublishProviders(book: PublishBook): Promise<PublishProviderInfo[]>;
10
+ /**
11
+ * The provider for `id`: a built-in (exactly as `publishProviderFor`), else
12
+ * one of the book's publishing plugins. An npm entry of that name is restored
13
+ * first, so a fresh clone can publish. Throws on an unknown id, naming every
14
+ * destination the book has.
15
+ */
16
+ export declare function resolvePublishProvider(id: string, book: PublishBook): Promise<PublishProvider>;
@@ -1,4 +1,4 @@
1
- import type { PreflightIssue, PublishArtifactFormat, PublishDeps, PublishOutcome, PublishProviderInfo, PublishRequest } from "./types.ts";
1
+ import type { PreflightIssue, PublishArtifactFormat, PublishDeps, PublishOutcome, PublishProvider, PublishProviderInfo, PublishRequest } from "./types.ts";
2
2
  export interface RunPublishOptions {
3
3
  projectDir: string;
4
4
  providerId: string;
@@ -10,6 +10,12 @@ export interface RunPublishOptions {
10
10
  artifactPath?: string;
11
11
  /** Stop after preflight — report issues without contacting the platform. */
12
12
  dryRun?: boolean;
13
+ /**
14
+ * The provider, when the caller has already resolved it (the CLI does, to
15
+ * map a failed restore to its own exit code): no second lookup or restore.
16
+ * Default: {@link resolvePublishProvider}(`providerId`).
17
+ */
18
+ provider?: PublishProvider;
13
19
  }
14
20
  export interface RunPublishResult {
15
21
  ok: boolean;
@@ -33,11 +39,13 @@ export interface RunPublishResult {
33
39
  * with a preflight error over one bad manifest field.
34
40
  */
35
41
  export declare function resolvePublishFormat(info: PublishProviderInfo, providerConfig: Record<string, unknown>): PublishArtifactFormat;
42
+ type RequestOptions = Pick<RunPublishOptions, "projectDir" | "providerId" | "manifestPath" | "artifactPath">;
36
43
  /**
37
- * Resolve the {@link PublishRequest} for a provider from the project's
38
- * manifest — shared by `runPublish` and by hosts that call individual
39
- * provider methods (authenticate, listProducts) outside a full publish.
44
+ * Resolve the {@link PublishRequest} for a BUILT-IN provider from the
45
+ * project's manifest — for hosts that call individual provider methods
46
+ * (authenticate, listProducts, destinations) outside a full publish.
40
47
  */
41
- export declare function resolvePublishRequest(options: Pick<RunPublishOptions, "projectDir" | "providerId" | "manifestPath" | "artifactPath">, deps: PublishDeps): Promise<PublishRequest>;
48
+ export declare function resolvePublishRequest(options: RequestOptions, deps: PublishDeps): Promise<PublishRequest>;
42
49
  /** Preflight → authenticate → upload, with structured results throughout. */
43
50
  export declare function runPublish(options: RunPublishOptions, deps: PublishDeps): Promise<RunPublishResult>;
51
+ export {};
@@ -39,13 +39,17 @@ export type PublishProviderId = "local" | "itch" | "drivethrurpg" | "kdp" | "azu
39
39
  * - "api" — real programmatic upload (itch.io, Azure SWA, Shopify)
40
40
  * - "guided" — no upload API exists; we validate + stage a package and open
41
41
  * the platform's upload page with a checklist (DTRPG, KDP)
42
+ * - "plugin" — a publishing plugin (experimental, #381): the book's own
43
+ * extension runs the upload and handles its own sign-in
42
44
  */
43
- export type PublishProviderKind = "api" | "guided";
45
+ export type PublishProviderKind = "api" | "guided" | "plugin";
44
46
  /** Which build output the provider consumes. */
45
47
  export type PublishArtifactFormat = "pdf" | "html";
46
48
  /** Static, UI-facing description of a provider. */
47
49
  export interface PublishProviderInfo {
48
- id: PublishProviderId;
50
+ /** A built-in {@link PublishProviderId}, or a publishing plugin's package
51
+ * name (experimental, #381). */
52
+ id: string;
49
53
  /** Human name ("itch.io"). */
50
54
  label: string;
51
55
  kind: PublishProviderKind;
@@ -106,7 +110,35 @@ export interface PublishProviderInfo {
106
110
  label: string;
107
111
  canCreate: boolean;
108
112
  };
113
+ /** A badge, not a kind: the provider may change or go away. Set on every
114
+ * publishing plugin today (#381). */
115
+ experimental?: true;
116
+ }
117
+ export interface PublishPluginContext {
118
+ project: {
119
+ dir: string;
120
+ title: string;
121
+ authors: string[];
122
+ };
123
+ /** The one build output validated for this run: a PDF file, or the
124
+ * website export directory. */
125
+ 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`. */
128
+ settings: Record<string, unknown>;
129
+ /** Progress line sink. Use this, never `console.log`: stdout carries
130
+ * `--json` output. */
131
+ log: (message: string) => void;
132
+ }
133
+ export interface PublishPluginResult {
134
+ /** Where the published work lives — kept only when it is an http(s) URL. */
135
+ url?: string;
136
+ /** One-line summary shown to the author. */
137
+ detail?: string;
109
138
  }
139
+ /** `outputDir` is the folder holding `context.artifact.path`: the website
140
+ * export directory for html, the PDF's folder for pdf. */
141
+ export type PublishPluginFunction = (outputDir: string, context: PublishPluginContext) => Promise<PublishPluginResult | void>;
110
142
  /** The project being published (resolved from the manifest by the orchestrator). */
111
143
  export interface PublishProject {
112
144
  projectDir: string;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * text-diff.ts — a small two-way sequence diff for the Versions view.
3
+ *
4
+ * Two readers: the what-changed hint on a version card ("3 paragraphs
5
+ * changed") and the side-by-side file compare (lines aligned, changed ones
6
+ * marked). Myers' O(ND) algorithm over any array, with a budget: when two
7
+ * texts have almost nothing in common the edit script is as long as both
8
+ * texts and the trace would grow with its square, so past the budget the
9
+ * result is "everything after the common ends changed" — honest for the
10
+ * hint, readable in the compare view, and bounded in memory. Pure, no I/O.
11
+ */
12
+ export type DiffOp<T> = {
13
+ kind: "equal";
14
+ a: T;
15
+ b: T;
16
+ } | {
17
+ kind: "delete";
18
+ a: T;
19
+ } | {
20
+ kind: "insert";
21
+ b: T;
22
+ };
23
+ export declare function diffSequences<T>(a: readonly T[], b: readonly T[]): DiffOp<T>[];
24
+ /**
25
+ * How many items changed, counting an edited item once: each run of
26
+ * deletes and inserts counts as the larger of the two, so a reworded
27
+ * paragraph is "1 paragraph changed", not a removal plus an addition.
28
+ */
29
+ export declare function countChanged<T>(ops: readonly DiffOp<T>[]): number;
30
+ /** One row of the side-by-side compare: a line on each side, or a gap. */
31
+ export interface CompareRow {
32
+ then: string | null;
33
+ now: string | null;
34
+ changed: boolean;
35
+ }
36
+ /**
37
+ * Lay a line diff out as two aligned columns: equal lines share a row;
38
+ * within a changed run the removed and added lines pair up in order and
39
+ * the longer side's extra lines face a gap.
40
+ */
41
+ export declare function alignRows(ops: readonly DiffOp<string>[]): CompareRow[];
42
+ /** Split into lines for diffing; a CR before the break is not content. */
43
+ export declare function textLines(text: string): string[];
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The exact lines a converge merge writes around a passage edited both here
3
+ * and online (`remote-auth/converge-merge.ts`):
4
+ *
5
+ * <<<<<<< your version
6
+ * …the passage as edited on this computer…
7
+ * =======
8
+ * …the passage as edited online…
9
+ * >>>>>>> online version
10
+ *
11
+ * Three consumers read them back and must agree byte for byte: the merge
12
+ * that writes them, the `source.sync.merge-markers` check that reports them,
13
+ * and the markdown rule that renders them as two labelled versions instead
14
+ * of a setext heading (`markdown/two-versions.ts`). This file imports
15
+ * nothing, so the node-free `/render` graph can depend on it too.
16
+ *
17
+ * (The desktop's editor panel keeps its own copy of the two sentinels — the
18
+ * renderer may not value-import the lib — pinned to the merge's real output
19
+ * by `packages/desktop/tests/editor/two-versions.test.ts`.)
20
+ */
21
+ /** Marker labels — author language, never git jargon. */
22
+ export declare const YOUR_VERSION_LABEL = "your version";
23
+ export declare const ONLINE_VERSION_LABEL = "online version";
24
+ export declare const TWO_VERSIONS_OPEN = "<<<<<<< your version";
25
+ export declare const TWO_VERSIONS_SEPARATOR = "=======";
26
+ export declare const TWO_VERSIONS_CLOSE = ">>>>>>> online version";
@@ -0,0 +1,87 @@
1
+ import { type SnapshotEntry } from "./source-provider.ts";
2
+ import { defaultGitHttp } from "./remote-auth/git-http.ts";
3
+ import type { HostCredential, TokenStore } from "./remote-auth/token-store.ts";
4
+ import { type CompareRow } from "./text-diff.ts";
5
+ export type { CompareRow };
6
+ export interface VersionFileChange {
7
+ /** Repo-relative path, forward slashes. */
8
+ path: string;
9
+ kind: "added" | "removed" | "changed";
10
+ /** Plain size hint: "3 paragraphs changed", "1 rule changed", "replaced", "added", "removed". */
11
+ hint: string;
12
+ /** Both sides are text, so the compare view can show them. */
13
+ text: boolean;
14
+ }
15
+ export interface VersionChanges {
16
+ files: VersionFileChange[];
17
+ /** Changed files beyond the ones listed (the list is capped). */
18
+ more: number;
19
+ }
20
+ /** A history entry with what it changed and where it is kept. */
21
+ export interface VersionEntry extends SnapshotEntry {
22
+ changes: VersionFileChange[];
23
+ moreChanges: number;
24
+ /** True = online too; false = on this computer only; null = no online copy to compare with. */
25
+ backedUp: boolean | null;
26
+ }
27
+ /** How many changed files a version card lists before "and N more". */
28
+ export declare const VERSION_CHANGES_SHOWN = 8;
29
+ /** The size hint for a text file that changed between two versions. */
30
+ export declare function changeHint(filepath: string, before: string, after: string): string;
31
+ /**
32
+ * The files `oid` changed against its first parent (every file, for a
33
+ * version with no parent), sorted by path and capped to
34
+ * {@link VERSION_CHANGES_SHOWN}.
35
+ */
36
+ export declare function listVersionChanges(dir: string, oid: string, options?: {
37
+ cache?: object;
38
+ }): Promise<VersionChanges>;
39
+ /**
40
+ * A history page with each version's changes and whether it is backed up.
41
+ * Versions come newest-first, and everything older than the first backed-up
42
+ * one is backed up too, so the ancestry walk runs only over the versions
43
+ * that are on this computer only.
44
+ */
45
+ export declare function describeVersions(projectDir: string, entries: SnapshotEntry[]): Promise<VersionEntry[]>;
46
+ /**
47
+ * The commits reachable from `fromOid` that `baseOid`'s history does not
48
+ * have, newest first, down to (not including) their merge base. None when
49
+ * the two share no history.
50
+ */
51
+ export declare function commitsAhead(dir: string, fromOid: string, baseOid: string, cache?: object, limit?: number): Promise<SnapshotEntry[]>;
52
+ /**
53
+ * What is online that this computer has not got: fetch the book's branch
54
+ * (remote-tracking ref only — no merge, no checkout, safe on a dirty tree)
55
+ * and describe the commits above the merge base. Quiet on every failure,
56
+ * reporting why, like `checkRemoteUpdates`.
57
+ */
58
+ export declare function listOnlineVersions(options: {
59
+ projectDir: string;
60
+ credential?: HostCredential;
61
+ tokenStore?: TokenStore;
62
+ httpClient?: typeof defaultGitHttp;
63
+ }): Promise<{
64
+ entries: VersionEntry[];
65
+ reason?: "no-remote" | "auth" | "offline";
66
+ }>;
67
+ /**
68
+ * One file at version `id` beside the same file as it is on disk now, as
69
+ * aligned rows for the compare view. `binary` when either side is not text.
70
+ * A side that does not exist (the file was added since, or removed) is an
71
+ * empty column.
72
+ */
73
+ export declare function compareVersionFile(projectDir: string, id: string, filepath: string): Promise<{
74
+ binary: true;
75
+ } | {
76
+ binary: false;
77
+ rows: CompareRow[];
78
+ }>;
79
+ /**
80
+ * Write every file of version `id` under `destDir` (the whole repository
81
+ * tree, so a book inside a larger repository still finds its shared
82
+ * stylesheets) and return the folder the preview should render — the
83
+ * book's own subfolder of it.
84
+ */
85
+ export declare function exportVersionTree(projectDir: string, id: string, destDir: string): Promise<{
86
+ inputDir: string;
87
+ }>;