@thallylabs/migrate 0.2.25 → 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
@@ -332,30 +332,43 @@ generic unknown-component fallback.
332
332
 
333
333
  ### Access-restricted pages
334
334
 
335
- A gated Mintlify page must never migrate as public. A page is withheld when its
336
- frontmatter sets a non-empty `groups` (list or string) or `public: false`
337
- (also `"false"`, `no`, `off`, `0`; empty `groups` restricts nothing), or when it sits
338
- under a navigation group or tab that sets `groups` (a list of strings) or
339
- `public: false`. `public: true` alone is not gating. Withheld pages are not
340
- written to `src/content` and are removed from navigation (emptied groups and
341
- tabs included), whether or not navigation lists them. The original file is
342
- written unchanged to `migration-quarantine/<original path>` at the project
343
- root, which no runtime content reader, search index, or `llms` output walks;
344
- `create-thally-docs` also adds it to the project's `.gitignore` (appended once,
345
- existing entries kept) so it is never committed or pushed. A public page that
346
- imports a withheld page as a component does not inline it (a `gated-page`
347
- warning names the importer). Invalid frontmatter fails the run rather than
348
- importing the page. Each page gets a
349
- `gated-page` warning, plus a summary; `create-thally-docs` prints these last
350
- under an "ACCESS-RESTRICTED CONTENT" heading and the report records them and a
351
- `quarantined` count. Links from other pages to a withheld page are left as
352
- authored and will fail `thally check`; images and other assets used only by
353
- gated pages are still copied to `public/`. Mintlify's site-wide authentication mode lives in its
354
- 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
355
369
  `public: true` (which implies the source site required sign-in for everything
356
- else) one `gated-page` warning says Thally will publish every imported page.
357
- Restricted-container `groups` and `public: false` are honored fail-closed even
358
- 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.
359
372
 
360
373
  ### Site-wide scripts, styles, fonts, and settings
361
374
 
package/dist/index.d.ts CHANGED
@@ -230,6 +230,13 @@ interface MigrationPage {
230
230
  mode?: 'default' | 'wide' | 'custom' | 'center' | 'home';
231
231
  hidden?: boolean;
232
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;
233
240
  /** Social/SEO overrides from `og:*` and `twitter:*` frontmatter, keyed by the migrated frontmatter field. */
234
241
  meta?: Partial<Record<'ogTitle' | 'ogDescription' | 'ogImage' | 'twitterTitle' | 'twitterDescription' | 'twitterImage', string>>;
235
242
  /** OpenAPI operation key rendered by Thally instead of ordinary MDX. */
@@ -254,7 +261,7 @@ interface MigrationAsset {
254
261
  }
255
262
  interface MigrationWarning {
256
263
  code: 'collision' | 'invalid-page' | 'missing-page' | 'unsupported-config' | 'limit-reached' | 'fetch-failed' | 'skipped-file'
257
- /** 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. */
258
265
  | 'gated-page';
259
266
  message: string;
260
267
  source?: string;
@@ -281,7 +288,11 @@ interface MigrationBundle {
281
288
  remoteApiSpecs?: Array<RemoteApiSpec>;
282
289
  /** Customer-owned component source and registry; paths are repository-relative. */
283
290
  componentFiles?: Array<RenderedMigrationFile>;
284
- /** 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
+ */
285
296
  quarantinedFiles?: Array<RenderedMigrationFile>;
286
297
  /** Access-restricted pages the file limit dropped: neither published nor saved in quarantinedFiles. */
287
298
  droppedGatedPages?: number;
@@ -448,6 +459,30 @@ declare function detectRepositoryDocsDir(repositoryDir: string): string;
448
459
  /** Import an already-available repository directory into a canonical bundle. */
449
460
  declare function migrateRepository(options: RepositoryMigrationOptions): MigrationBundle;
450
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
+
451
486
  /**
452
487
  * Navigation projection for imported sites. Mintlify's schema is intentionally
453
488
  * more expressive than Thally's tab/group model, so complex containers are
@@ -459,16 +494,24 @@ interface MintlifyPageReference {
459
494
  navigationId: string;
460
495
  locale?: string;
461
496
  }
462
- /** A page listed under an access-restricted navigation container. */
463
- 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 {
464
503
  ref: string;
465
- reason: string;
504
+ access: NavigationAccess;
466
505
  }
467
506
  interface MintlifyNavigationResult {
468
507
  docsConfig: MigrationDocsConfig;
469
508
  pageReferences: Array<MintlifyPageReference>;
470
- /** Pages under a restricted container; withheld from `docsConfig` and `pageReferences`. */
471
- 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>;
472
515
  /** `sourceRef` mounts under a restricted container; never resolved, so nothing of theirs is imported. */
473
516
  gatedSourceRefs: Array<string>;
474
517
  warnings: Array<MigrationWarning>;