@thallylabs/migrate 0.2.24 → 0.2.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -171,6 +171,54 @@ from Fern MDX pages (`../../components/...`, resolved against the Fern
171
171
  project root) are migrated the same way Mintlify and Docusaurus components
172
172
  are — see "Mintlify compatibility" below.
173
173
 
174
+ ## Mintlify `sourceRef` repositories
175
+
176
+ A Mintlify navigation node `{"sourceRef": "owner/repo"}` mounts the docs of another
177
+ repository. Mintlify does not document where that mount lives, so it cannot be
178
+ derived from `docs.json`; supply it with a repeatable flag:
179
+
180
+ ```bash
181
+ create-thally-docs migrate https://github.com/OpenRouterTeam/docs my-docs \
182
+ --source-ref OpenRouterTeam/typescript-sdk=client-sdks/typescript
183
+ ```
184
+
185
+ Without a mapping the node is skipped with a warning that names the flag.
186
+
187
+ - The repository must be on github.com. Its docs root is the directory holding a
188
+ Mintlify `docs.json` (`docs/` first, then the repository root); without one the
189
+ mapping is skipped with a warning.
190
+ - Every `.md`/`.mdx` file under that root is imported (orphans included) through the
191
+ same pipeline as the main site, under `<mount-path>/...`. Assets are copied under
192
+ `public/<mount-path>/...`. The node is replaced by the referenced `docs.json`
193
+ navigation with page paths prefixed by the mount path; tabs become groups, and the
194
+ parent group keeps its label and icon.
195
+ - Root-absolute links inside those pages (`/models/x`, `/images/x.png`) are prefixed
196
+ with the mount path (sub-site semantics: Mintlify's behavior here is not
197
+ documented, so this is an assumption). Relative links work as-is.
198
+ - Pages, navigation, assets and the referenced repository's custom components are
199
+ imported. Its components are bundled with the main site's under `src/mdx/migrated/`
200
+ and registered in `src/mdx/custom-components.tsx`; their content-hashed names cannot
201
+ clash with the main site's. Branding, colors, redirects, OpenAPI specs and
202
+ access-restricted pages of the referenced repository are ignored (one warning says
203
+ so). Access-restricted pages and the files only they use are withheld from the site
204
+ and are not saved anywhere (the main site saves its own under `migration-quarantine/`;
205
+ a referenced repository's are discarded), so recover them from that repository if
206
+ needed.
207
+ - Safety limits per referenced repository, fixed constants: 5,000 files and 50 MB under
208
+ the docs root. Over a limit the whole repository is refused, never imported
209
+ partially. Symlinks and dot-directories are removed before import, and a docs
210
+ directory that resolves outside the clone is refused. A repository GitHub reports as
211
+ larger than 200 MB is refused before cloning (if the GitHub API is unreachable the
212
+ clone proceeds and the limits above still apply), its submodules are not fetched,
213
+ and a `docs.json` over 1 MB is ignored. `repo` must match `owner/repo`; the mount
214
+ path must be a relative lowercase slug path (no `..`, no leading slash), must not
215
+ start with a name the site itself uses (`api`, `admin`, `_next`, `public`,
216
+ `llms.txt`, `sitemap.xml`, ...), must not collide with an existing page or directory
217
+ of the main site, and mappings must not overlap.
218
+ - A mapping that matches no `sourceRef` in the navigation is reported and imports
219
+ nothing. `migration-report.json` lists each imported repository with its page count
220
+ under `sourceRefs`.
221
+
174
222
  ## Mintlify compatibility
175
223
 
176
224
  Repository imports preserve named/default local JSX and TSX components and
@@ -214,8 +262,8 @@ same-length nested fence is widened so the inner fence no longer closes it, and
214
262
  a bare placeholder tag in prose (`<Feature> requires a plan`) that would stop
215
263
  the page compiling is escaped as text rather than losing the page.
216
264
  The Mintlify `search-bar-entry` click trigger is mapped to Thally's search
217
- shortcut. Markdown mixed inside interactive JSX, computed imports, and
218
- namespace imports are reported for manual review; unsupported source is
265
+ shortcut. Markdown mixed inside interactive JSX and computed imports are
266
+ reported for manual review; unsupported source is
219
267
  preserved, not replaced with empty stubs. An external package's JSX usage is
220
268
  dropped and replaced with a safe fallback (with a warning); if that package's
221
269
  binding is instead referenced outside JSX (an expression, a prop, or an
@@ -237,6 +285,30 @@ Next) and copied into any extracted client module. A source site's own
237
285
  passes a page-authored function into a client component needs the client
238
286
  wrapper described above; unsupported callback shapes retain their content
239
287
  with a warning. An unconfirmed target is warned for review.
288
+ Other relative imports of a copied file are handled the same way: a namespace
289
+ import (`import * as X from './comp.jsx'`) and a dynamic `import('./comp.jsx')`
290
+ point at the copied module, and a relative side-effect import
291
+ (`import './styles.css'`) is removed with a warning, like one from an npm
292
+ package. A page is excluded only when the relative target is not copied (for
293
+ example a Next.js `./metadata` module, or an `export ... from` re-export), with
294
+ a single warning naming it. An MDX expression that names an identifier the page
295
+ never defines (`{missing}`) is removed with a warning, since it would throw at
296
+ render; define the name or escape the braces as `\{ \}` to keep the text.
297
+ A value import from a local snippet (`import { FEE, fee } from
298
+ '/snippets/c.mdx'`) is inlined when each name is a static value (string,
299
+ number, boolean, `null`, or an object/array of those) or a self-contained
300
+ function. Inlined functions may only use pure built-ins (`Math`, `JSON`,
301
+ `String`, `Number`, `Boolean`, `Array`, `Date`, `Intl`, `parseInt`,
302
+ `parseFloat`, `isNaN`, `isFinite`, `encodeURIComponent` and
303
+ `decodeURIComponent`) and may not reach
304
+ `Function`, constructors, `globalThis`, `fetch` or other globals; anything else
305
+ is not inlined. A name the snippet does not export, or one that cannot be
306
+ inlined, is bound to `undefined` (as Mintlify does for a missing export) with a
307
+ warning, while the other names of the same import are still inlined. A snippet
308
+ import that resolves outside the repository through a symlink is refused, and a
309
+ snippet whose frontmatter cannot be read is not inlined (left as a comment with
310
+ a warning). Mintlify `sourceRef` navigation nodes have no Thally equivalent and
311
+ are reported rather than migrated.
240
312
  File paths cannot escape the repository checkout; symlinks and oversized
241
313
  graphs are rejected. This is compatibility analysis, **not a code sandbox**:
242
314
  imported JavaScript executes when the developer builds or runs the resulting
@@ -260,30 +332,43 @@ generic unknown-component fallback.
260
332
 
261
333
  ### Access-restricted pages
262
334
 
263
- A gated Mintlify page must never migrate as public. A page is withheld when its
264
- frontmatter sets a non-empty `groups` (list or string) or `public: false`
265
- (also `"false"`, `no`, `off`, `0`; empty `groups` restricts nothing), or when it sits
266
- under a navigation group or tab that sets `groups` (a list of strings) or
267
- `public: false`. `public: true` alone is not gating. Withheld pages are not
268
- written to `src/content` and are removed from navigation (emptied groups and
269
- tabs included), whether or not navigation lists them. The original file is
270
- written unchanged to `migration-quarantine/<original path>` at the project
271
- root, which no runtime content reader, search index, or `llms` output walks;
272
- `create-thally-docs` also adds it to the project's `.gitignore` (appended once,
273
- existing entries kept) so it is never committed or pushed. A public page that
274
- imports a withheld page as a component does not inline it (a `gated-page`
275
- warning names the importer). Invalid frontmatter fails the run rather than
276
- importing the page. Each page gets a
277
- `gated-page` warning, plus a summary; `create-thally-docs` prints these last
278
- under an "ACCESS-RESTRICTED CONTENT" heading and the report records them and a
279
- `quarantined` count. Links from other pages to a withheld page are left as
280
- authored and will fail `thally check`; images and other assets used only by
281
- gated pages are still copied to `public/`. Mintlify's site-wide authentication mode lives in its
282
- dashboard and cannot be read from a repository, so when any page sets
335
+ Restricted Mintlify pages migrate as real pages with normalized access
336
+ frontmatter that the Thally runtime enforces (see `/guides/authenticated-docs`):
337
+
338
+ - Frontmatter `groups` becomes a list of trimmed group names (`groups: admin`
339
+ and `groups: "a, b"` become lists); `public` becomes a boolean (`"false"`,
340
+ `no`, `off`, `0` are `false`; `true`/`"true"` is `true`). Empty `groups`
341
+ restricts nothing.
342
+ - Rules on navigation containers (a group, tab, version, dropdown, anchor,
343
+ language, or `menu` item) are pushed down into the frontmatter of every page
344
+ below them, because the runtime reads access only from pages: container
345
+ `groups` (a list of strings) and `public: false` restrict, and Mintlify's
346
+ group-level `public: true` opens pages that name no groups of their own.
347
+ Pages stay in navigation where they were.
348
+ - Rules combine to the strictest: nested and page group lists intersect,
349
+ `public: false` anywhere wins, and a page listed under both an open and a
350
+ restricted container gets the restricted rule.
351
+
352
+ A page whose rules cannot be carried over safely fails closed instead: a
353
+ malformed value (`public: maybe`, `groups: [1]`), group lists that share no
354
+ group, or frontmatter that declares `groups`/`public` but cannot be parsed or
355
+ read. Such a page is not written to `src/content`, is removed from navigation,
356
+ and its original is written unchanged to `migration-quarantine/<original path>`
357
+ at the project root, which no runtime reader walks; `create-thally-docs` adds
358
+ that folder to `.gitignore`. Each quarantined page gets a `gated-page` warning.
359
+
360
+ What a restricted page uses must not leak through surfaces that are not access
361
+ controlled: it is never inlined into another page (a `gated-page` warning names
362
+ the importer), images and other assets used only by restricted pages are not
363
+ copied to `public/` (they are saved under `migration-quarantine/assets/`), and
364
+ OpenAPI operations documented only on restricted pages are withheld from the
365
+ published spec. One `gated-page` summary counts the restricted pages and notes
366
+ that Thally hides them from everyone until reader authentication is configured
367
+ in `docs.json` `auth`; no `auth` block is generated, because Mintlify's
368
+ dashboard settings cannot be read from a repository. When any page sets
283
369
  `public: true` (which implies the source site required sign-in for everything
284
- else) one `gated-page` warning says Thally will publish every imported page.
285
- Restricted-container `groups` and `public: false` are honored fail-closed even
286
- though Mintlify documents only `"public": true` on a group.
370
+ else), one more `gated-page` warning says every unrestricted page will be
371
+ public until `auth` is configured.
287
372
 
288
373
  ### Site-wide scripts, styles, fonts, and settings
289
374
 
package/dist/index.d.ts CHANGED
@@ -81,6 +81,8 @@ interface MigrationDocsConfig {
81
81
  };
82
82
  /** Local site-authored CSS projected from a source docs site, served from public/. */
83
83
  stylesheets?: Array<string>;
84
+ /** `false` hides the breadcrumb trail; Mintlify pages show only a group eyebrow. */
85
+ breadcrumbs?: boolean;
84
86
  tabs: Array<MigrationNavigationTab>;
85
87
  navigation?: {
86
88
  /** How sibling documentation collections are presented to readers. */
@@ -173,6 +175,8 @@ interface MigrationDocsConfig {
173
175
  playground?: {
174
176
  display: 'interactive' | 'simple' | 'none';
175
177
  };
178
+ /** `false` hides the visible "OpenAPI specification" line; Mintlify does not show it. */
179
+ specLink?: boolean;
176
180
  };
177
181
  /** Third-party analytics in Mintlify's `integrations` shape; validated again by the renderer. */
178
182
  integrations?: {
@@ -226,6 +230,13 @@ interface MigrationPage {
226
230
  mode?: 'default' | 'wide' | 'custom' | 'center' | 'home';
227
231
  hidden?: boolean;
228
232
  noindex?: boolean;
233
+ /**
234
+ * Reader access groups (frontmatter `groups`): trimmed, non-empty names the
235
+ * runtime matches exactly. The page needs a signed-in reader in one of them.
236
+ */
237
+ groups?: Array<string>;
238
+ /** Frontmatter `public`: `true` opens the page to anyone, `false` needs any signed-in reader. */
239
+ public?: boolean;
229
240
  /** Social/SEO overrides from `og:*` and `twitter:*` frontmatter, keyed by the migrated frontmatter field. */
230
241
  meta?: Partial<Record<'ogTitle' | 'ogDescription' | 'ogImage' | 'twitterTitle' | 'twitterDescription' | 'twitterImage', string>>;
231
242
  /** OpenAPI operation key rendered by Thally instead of ordinary MDX. */
@@ -250,7 +261,7 @@ interface MigrationAsset {
250
261
  }
251
262
  interface MigrationWarning {
252
263
  code: 'collision' | 'invalid-page' | 'missing-page' | 'unsupported-config' | 'limit-reached' | 'fetch-failed' | 'skipped-file'
253
- /** Access-restricted source page withheld from the published site (or a site-wide auth risk). */
264
+ /** Access-restricted source content: migrated with access rules, withheld (quarantined), or a site-wide auth risk. */
254
265
  | 'gated-page';
255
266
  message: string;
256
267
  source?: string;
@@ -277,10 +288,20 @@ interface MigrationBundle {
277
288
  remoteApiSpecs?: Array<RemoteApiSpec>;
278
289
  /** Customer-owned component source and registry; paths are repository-relative. */
279
290
  componentFiles?: Array<RenderedMigrationFile>;
280
- /** Access-restricted source pages, written outside every published path. */
291
+ /**
292
+ * Restricted content that cannot be published safely (pages whose access
293
+ * rules are malformed or contradictory, and assets used only by restricted
294
+ * pages), written outside every published path.
295
+ */
281
296
  quarantinedFiles?: Array<RenderedMigrationFile>;
282
297
  /** Access-restricted pages the file limit dropped: neither published nor saved in quarantinedFiles. */
283
298
  droppedGatedPages?: number;
299
+ /** Mintlify `sourceRef` repositories imported under a mount path, with their page counts. */
300
+ sourceRefs?: Array<{
301
+ repo: string;
302
+ mountPath: string;
303
+ pages: number;
304
+ }>;
284
305
  docsConfig: MigrationDocsConfig;
285
306
  site?: {
286
307
  name?: string;
@@ -324,6 +345,51 @@ interface RenderedMigrationFile {
324
345
  content: string | Uint8Array;
325
346
  }
326
347
 
348
+ /**
349
+ * Mintlify `sourceRef` navigation nodes mount the docs of another repository
350
+ * (`{"sourceRef": "owner/repo"}`). The mount path is not derivable from any
351
+ * docs.json, so the caller supplies it with `--source-ref owner/repo=<path>`.
352
+ * The referenced repository is untrusted remote content: it is validated,
353
+ * size-capped, stripped of symlinks and dot-directories, then run through the
354
+ * same repository pipeline as the main site and prefixed with its mount path.
355
+ */
356
+
357
+ /** Per referenced repository: files and bytes under its docs root. Constants on purpose, not configurable. */
358
+ declare const SOURCE_REF_MAX_FILES = 5000;
359
+ declare const SOURCE_REF_MAX_BYTES = 50000000;
360
+ /** GitHub reports repository size in KB; a larger repository is refused before it is cloned. */
361
+ declare const SOURCE_REF_MAX_REPOSITORY_KB = 200000;
362
+ interface SourceRefMapping {
363
+ /** `owner/repo`, exactly as written in the source navigation. */
364
+ repo: string;
365
+ /** Relative slug path the referenced docs are mounted at, e.g. `client-sdks/typescript`. */
366
+ mountPath: string;
367
+ }
368
+ interface SourceRefImport extends SourceRefMapping {
369
+ pages: Array<MigrationPage>;
370
+ assets: Array<MigrationAsset>;
371
+ /** Navigation entries with every page id already prefixed by the mount path. */
372
+ navigation: Array<string | MigrationNavigationGroup>;
373
+ /** Custom component files (and registry) the mounted pages' `<MigratedXXXX/>` tags need; merged into the main bundle. */
374
+ componentFiles?: Array<RenderedMigrationFile>;
375
+ /** Why the import is empty (or partial), plus forwarded pipeline warnings. */
376
+ warnings: Array<MigrationWarning>;
377
+ }
378
+ /** Parse repeated `owner/repo=mount/path` values; throws on anything unsafe. */
379
+ declare function parseSourceRefFlags(values: ReadonlyArray<string>): Array<SourceRefMapping>;
380
+ /**
381
+ * Why a referenced repository is too large to clone, or null when it is small
382
+ * enough or its size is unknown (GitHub API unreachable, rate-limited or
383
+ * private): an unknown size proceeds, and the post-clone caps still apply.
384
+ */
385
+ declare function sourceRefOversizeReason(repo: string, fetcher?: MigrationFetcher): Promise<string | null>;
386
+ /**
387
+ * Import one cloned referenced repository as a sub-site under its mount path.
388
+ * `repositoryDir` is a disposable clone: symlinks and dot-directories under
389
+ * its docs root are deleted.
390
+ */
391
+ declare function importSourceRef(mapping: SourceRefMapping, repositoryDir: string): SourceRefImport;
392
+
327
393
  /**
328
394
  * Repository adapter for the shared migration engine. Traversal is bounded;
329
395
  * `scanFiles` follows a symbolic link only when its resolved real path stays
@@ -346,6 +412,8 @@ interface RepositoryMigrationOptions {
346
412
  sourceUrl: string;
347
413
  docsDir?: string;
348
414
  platform?: MigrationPlatform;
415
+ /** @internal Mount path of a sourceRef import; keeps its component files separate from any other copy of the same source. */
416
+ componentNamespace?: string;
349
417
  /** @internal Prefix used by additional Docusaurus docs-plugin instances. */
350
418
  docusaurusRoutePrefix?: string;
351
419
  /** @internal Prevent recursive discovery while importing one plugin root. */
@@ -360,6 +428,8 @@ interface RepositoryMigrationOptions {
360
428
  maxSourceFiles?: number;
361
429
  /** @internal Redirects are global config, read once, not per plugin instance. */
362
430
  docusaurusSkipRedirects?: boolean;
431
+ /** Mintlify `sourceRef` repositories already fetched and prepared by `importSourceRef`. */
432
+ sourceRefs?: ReadonlyArray<SourceRefImport>;
363
433
  }
364
434
  /** Parse and validate a public GitHub repository URL. */
365
435
  declare function parseGitHubRepositoryUrl(rawUrl: string): GitHubRepositorySource;
@@ -377,7 +447,11 @@ declare function gitmodulePaths(targetDir: string): Array<string>;
377
447
  * submodule-fetch-failure warning (this function otherwise returns exactly
378
448
  * as before, so existing callers are unaffected).
379
449
  */
380
- declare function cloneGitHubRepository(source: GitHubRepositorySource, targetDir: string, warnings?: Array<MigrationWarning>): Promise<void>;
450
+ declare function cloneGitHubRepository(source: GitHubRepositorySource, targetDir: string, warnings?: Array<MigrationWarning>,
451
+ /** Untrusted referenced repositories: never follow their `.gitmodules` to further remotes. */
452
+ options?: {
453
+ skipSubmodules?: boolean;
454
+ }): Promise<void>;
381
455
  /** Detect a supported repository docs platform from unambiguous config files. */
382
456
  declare function detectRepositoryPlatform(repositoryDir: string, docsDir?: string): MigrationPlatform;
383
457
  /** Pick the first conventional content root containing Markdown. */
@@ -385,6 +459,30 @@ declare function detectRepositoryDocsDir(repositoryDir: string): string;
385
459
  /** Import an already-available repository directory into a canonical bundle. */
386
460
  declare function migrateRepository(options: RepositoryMigrationOptions): MigrationBundle;
387
461
 
462
+ /**
463
+ * Mintlify-only helpers: page access rules, site-wide CSS/JS/font assets,
464
+ * and appearance settings. Kept apart from the generic repository walk so the
465
+ * rules that decide how restricted pages migrate (and what is quarantined)
466
+ * are auditable in one place.
467
+ *
468
+ * Access invariant: a restricted page migrates with normalized `groups` /
469
+ * `public` frontmatter that the Thally runtime enforces; anything ambiguous
470
+ * (malformed values, group lists that share no group) fails closed and the
471
+ * page is quarantined instead.
472
+ */
473
+
474
+ /** Access imposed by every navigation container above one appearance of a page. */
475
+ interface NavigationAccess {
476
+ /** Intersection of every container group list on the path. */
477
+ groups?: Array<string>;
478
+ /** Some container on the path sets `public: false`. */
479
+ hasPublicFalse: boolean;
480
+ /** Some container on the path sets `public: true` (Mintlify's documented group flag). */
481
+ hasPublicTrue: boolean;
482
+ /** Set when a container value is malformed or nested group lists share no group. */
483
+ problem?: string;
484
+ }
485
+
388
486
  /**
389
487
  * Navigation projection for imported sites. Mintlify's schema is intentionally
390
488
  * more expressive than Thally's tab/group model, so complex containers are
@@ -396,21 +494,37 @@ interface MintlifyPageReference {
396
494
  navigationId: string;
397
495
  locale?: string;
398
496
  }
399
- /** A page listed under an access-restricted navigation container. */
400
- interface MintlifyGatedReference {
497
+ /**
498
+ * One appearance of a page reference in navigation, with the access rules of
499
+ * every container above it. Thally reads access only from page frontmatter,
500
+ * so these are pushed down into the frontmatter of the pages they cover.
501
+ */
502
+ interface MintlifyReferenceAccess {
401
503
  ref: string;
402
- reason: string;
504
+ access: NavigationAccess;
403
505
  }
404
506
  interface MintlifyNavigationResult {
405
507
  docsConfig: MigrationDocsConfig;
406
508
  pageReferences: Array<MintlifyPageReference>;
407
- /** Pages under a restricted container; withheld from `docsConfig` and `pageReferences`. */
408
- gatedReferences: Array<MintlifyGatedReference>;
509
+ /**
510
+ * Access imposed by navigation containers, one entry per appearance of a
511
+ * page (open appearances included, so a page listed in several places can
512
+ * be given the strictest rule). Restricted pages stay in `docsConfig`.
513
+ */
514
+ referenceAccess: Array<MintlifyReferenceAccess>;
515
+ /** `sourceRef` mounts under a restricted container; never resolved, so nothing of theirs is imported. */
516
+ gatedSourceRefs: Array<string>;
409
517
  warnings: Array<MigrationWarning>;
410
518
  }
411
519
  interface MintlifyProjectionOptions {
412
520
  /** Public URL migrations may expose page hrefs including the docs mount path. */
413
521
  pathPrefix?: string;
522
+ /**
523
+ * Resolves a `sourceRef` repository (`owner/repo`) to the navigation entries
524
+ * of its imported docs, already prefixed with their mount path. Returns null
525
+ * when the repository was not mapped with `--source-ref`.
526
+ */
527
+ resolveSourceRef?: (repo: string) => Array<string | MigrationNavigationGroup> | null;
414
528
  }
415
529
  /** Preserve Mintlify's implicit `/section` route for section landing pages. */
416
530
  declare function addMintlifyDirectoryRedirects(config: MigrationDocsConfig, pages: Array<MigrationPage>): MigrationDocsConfig;
@@ -589,4 +703,4 @@ declare function migrateUrl(options: UrlMigrationOptions): Promise<MigrationBund
589
703
  */
590
704
  declare function hydrateRemoteApiSpecs(bundle: MigrationBundle, fetcher?: MigrationFetcher): Promise<MigrationBundle>;
591
705
 
592
- export { type GitHubRepositorySource, type MigrationAsset, type MigrationBundle, type MigrationDocsConfig, type MigrationFetchRequest, type MigrationFetchResponse, type MigrationFetcher, type MigrationNavigationGroup, type MigrationNavigationTab, type MigrationPage, type MigrationPlatform, type MigrationWarning, type RenderedMigrationFile, type RepositoryMigrationOptions, type UrlMigrationOptions, addMintlifyDirectoryRedirects, buildNavigationFromPages, cloneGitHubRepository, defaultMigrationFetcher, detectRepositoryDocsDir, detectRepositoryPlatform, gitmodulePaths, hydrateRemoteApiSpecs, mergeMigrationConfig, migrateRepository, migrateUrl, normalizeMdx, parseGitHubRepositoryUrl, parseMarkdownPage, projectFernNavigation, projectMintlifyIntegrations, projectMintlifyNavigation, pruneMissingNavigationPages, readFernConfig, readMintlifyConfig, renderMigrationFiles, validateIntegrations, validateMigrationUrl };
706
+ export { type GitHubRepositorySource, type MigrationAsset, type MigrationBundle, type MigrationDocsConfig, type MigrationFetchRequest, type MigrationFetchResponse, type MigrationFetcher, type MigrationNavigationGroup, type MigrationNavigationTab, type MigrationPage, type MigrationPlatform, type MigrationWarning, type RenderedMigrationFile, type RepositoryMigrationOptions, SOURCE_REF_MAX_BYTES, SOURCE_REF_MAX_FILES, SOURCE_REF_MAX_REPOSITORY_KB, type SourceRefImport, type SourceRefMapping, type UrlMigrationOptions, addMintlifyDirectoryRedirects, buildNavigationFromPages, cloneGitHubRepository, defaultMigrationFetcher, detectRepositoryDocsDir, detectRepositoryPlatform, gitmodulePaths, hydrateRemoteApiSpecs, importSourceRef, mergeMigrationConfig, migrateRepository, migrateUrl, normalizeMdx, parseGitHubRepositoryUrl, parseMarkdownPage, parseSourceRefFlags, projectFernNavigation, projectMintlifyIntegrations, projectMintlifyNavigation, pruneMissingNavigationPages, readFernConfig, readMintlifyConfig, renderMigrationFiles, sourceRefOversizeReason, validateIntegrations, validateMigrationUrl };