@byline/cli 2.7.0 → 3.0.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 (21) hide show
  1. package/dist/templates/byline-examples/collections/docs/admin.tsx +1 -1
  2. package/dist/templates/byline-examples/collections/docs/schema.ts +1 -2
  3. package/dist/templates/byline-examples/collections/news/admin.tsx +1 -1
  4. package/dist/templates/byline-examples/collections/news/schema.ts +1 -2
  5. package/dist/templates/byline-examples/collections/pages/admin.tsx +1 -1
  6. package/dist/templates/byline-examples/collections/pages/schema.ts +1 -2
  7. package/dist/templates/byline-examples/scripts/backfill-version-locales.ts +46 -0
  8. package/dist/templates/byline-examples/scripts/import-docs.ts +107 -23
  9. package/dist/templates/byline-examples/scripts/lib/mdast-to-lexical.test.node.ts +262 -0
  10. package/dist/templates/byline-examples/scripts/lib/mdast-to-lexical.ts +8 -3
  11. package/dist/templates/byline-examples/scripts/lib/rewrite-doc-links.ts +141 -0
  12. package/dist/templates/byline-examples/scripts/lib/strip-leading-h1.test.node.ts +66 -0
  13. package/dist/templates/byline-examples/scripts/re-anchor.ts +102 -0
  14. package/dist/templates/byline-examples/scripts/regenerate-media.ts +1 -1
  15. package/dist/templates/migrations/{0000_black_sabra.sql → 0000_yielding_northstar.sql} +22 -2
  16. package/dist/templates/migrations/meta/0000_snapshot.json +164 -3
  17. package/dist/templates/migrations/meta/_journal.json +2 -2
  18. package/dist/templates/routes/_byline/route.lazy.tsx +16 -6
  19. package/dist/templates/routes/_byline/route.tsx +34 -9
  20. package/package.json +1 -1
  21. package/dist/templates/byline-examples/fields/available-languages-field.ts +0 -99
@@ -9,9 +9,19 @@
9
9
  /**
10
10
  * Lazy companion to `_byline/route.tsx`. TanStack Router loads this on
11
11
  * demand when a `_byline/*` URL matches, so the Byline UI providers,
12
- * stylesheets, and the admin config side-effect import (which
13
- * transitively pulls in the Lexical editor module graph) only run when
14
- * an admin route is actually visited — public routes stay clean.
12
+ * stylesheets, and the admin config side-effect import (which transitively
13
+ * pulls in the Lexical editor module graph) only run when an admin route is
14
+ * actually visited — public routes stay clean.
15
+ *
16
+ * The `byline/admin.config` import below registers the client config in the
17
+ * *client component graph* — it runs whenever this lazy module loads (component
18
+ * render / initial hydration), where the sibling `route.tsx` `beforeLoad` does
19
+ * NOT help: on initial hydration TanStack Start reuses the dehydrated SSR result
20
+ * and does not re-run `beforeLoad`, yet the admin layout component still calls
21
+ * `getClientConfig()` at render. The two registration points are complementary —
22
+ * `beforeLoad` (a dynamic import) covers the *loader* phase before any
23
+ * `_byline/*` child loader; this import covers component render / hydration.
24
+ * Both call `defineClientConfig` idempotently.
15
25
  *
16
26
  * If you also want to use the Byline UI components on your public site,
17
27
  * import the same stylesheets from your front-end's pathless layout
@@ -26,9 +36,9 @@ import { ToastProvider, ToastViewport } from '@byline/ui/react'
26
36
  import '@byline/ui/reset.css'
27
37
  import '@byline/ui/styles.css'
28
38
 
29
- // Initialize Byline admin config sits in the lazy companion so the
30
- // Lexical editor module graph only loads when a _byline/* URL matches.
31
- // See byline/admin.config.ts for the comment on why this is side-effecty.
39
+ // Register the Byline client config (component-render / hydration entry point
40
+ // see the file header). The sibling `route.tsx` `beforeLoad` covers the loader
41
+ // phase. Lexical's module graph only loads when a `_byline/*` URL matches.
32
42
  import '../../../byline/admin.config'
33
43
 
34
44
  export const Route = createLazyFileRoute('/_byline')({
@@ -12,17 +12,42 @@
12
12
  * to URL paths — `/_byline/admin/...` resolves to `/admin/...` and
13
13
  * `/_byline/sign-in` resolves to `/sign-in`.
14
14
  *
15
- * This file is intentionally bare. The router needs the route definition
16
- * at startup to build the tree for URL matching, so anything declared
17
- * here ends up in the eager module graph (and Vite will modulepreload
18
- * its dependencies on every page).
15
+ * This file is intentionally light. The router needs the route definition
16
+ * at startup to build the tree for URL matching, so anything *statically*
17
+ * imported here ends up in the eager module graph (and Vite will
18
+ * modulepreload its dependencies on every page).
19
19
  *
20
- * The component, providers, Byline UI stylesheets, and the admin config
21
- * side-effect import live in the sibling `route.lazy.tsx` — TanStack
22
- * Router loads that file on demand when a `_byline/*` URL matches, so
23
- * the editor + admin shell deps stay out of public-route bundles.
20
+ * The component, providers, and Byline UI stylesheets live in the sibling
21
+ * `route.lazy.tsx` — TanStack Router loads that file on demand when a
22
+ * `_byline/*` URL matches, so the editor + admin shell deps stay out of
23
+ * public-route bundles.
24
+ *
25
+ * Registering the Byline client config has two complementary entry points
26
+ * (both call `defineClientConfig` idempotently):
27
+ * - the `beforeLoad` below — covers the *loader* phase, resolving before any
28
+ * `_byline/*` child loader reads the config (e.g. the admin dashboard
29
+ * loader's `getClientConfig()`);
30
+ * - the side-effect import in `route.lazy.tsx` — covers component render /
31
+ * initial hydration, where `beforeLoad` is not re-run.
32
+ * Both use `byline/admin.config` (a dynamic import here), so its module graph
33
+ * (incl. the Lexical editor) stays code-split out of the eager/public bundle.
24
34
  */
25
35
 
26
36
  import { createFileRoute } from '@tanstack/react-router'
27
37
 
28
- export const Route = createFileRoute('/_byline')({})
38
+ export const Route = createFileRoute('/_byline')({
39
+ beforeLoad: async () => {
40
+ // Register the Byline client config (`defineClientConfig` runs as a
41
+ // side-effect of importing `byline/admin.config`) before any `_byline/*`
42
+ // child loader reads it. A parent route's `beforeLoad` resolves before its
43
+ // children's loaders, closing the dev race where a loader outran the lazy
44
+ // component module's side-effect import (on the client there is no
45
+ // server-config fallback, so `getClientConfig()` threw "Byline has not been
46
+ // configured yet"). The dynamic import keeps `admin.config` out of the
47
+ // eager/public bundle and evaluates once (cached). NOTE: `beforeLoad` is
48
+ // not re-run on initial client hydration (the SSR result is dehydrated), so
49
+ // the `route.lazy.tsx` side-effect import registers the config for the
50
+ // hydrated component render.
51
+ await import('../../../byline/admin.config')
52
+ },
53
+ })
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@byline/cli",
3
3
  "private": false,
4
4
  "license": "MPL-2.0",
5
- "version": "2.7.0",
5
+ "version": "3.0.1",
6
6
  "engines": {
7
7
  "node": ">=20.9.0"
8
8
  },
@@ -1,99 +0,0 @@
1
- /**
2
- * This Source Code is subject to the terms of the Mozilla Public
3
- * License, v. 2.0. If a copy of the MPL was not distributed with this
4
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
- *
6
- * Copyright (c) Infonomic Company Limited
7
- */
8
-
9
- /**
10
- * **Schema-side helper.** Returns a `GroupField` schema that emits one
11
- * `checkbox` field per configured content locale. Drop the result into
12
- * a collection's `fields` array in `<collection>/schema.ts`. Pure data;
13
- * the only imports are `@byline/core` types and the i18n locale list.
14
- *
15
- * See `docs/FIELDS.md` for the schema-vs-admin model.
16
- */
17
-
18
- import type { GroupField } from '@byline/core'
19
-
20
- import { contentLocales, type LocaleDefinition } from '../i18n.js'
21
-
22
- type Options = Partial<Omit<GroupField, 'type' | 'fields'>> & {
23
- locales?: readonly LocaleDefinition[]
24
- }
25
-
26
- type LocaleFields<T extends readonly LocaleDefinition[]> = {
27
- [K in keyof T]: {
28
- name: T[K]['code']
29
- label: T[K]['label']
30
- type: 'checkbox'
31
- optional: true
32
- }
33
- }
34
-
35
- type WithOverride<O, K extends string, V, D> = O extends { [P in K]: V } ? O[K] : D
36
-
37
- type AvailableLanguagesField<Opts extends Options> = Omit<GroupField, 'name' | 'fields'> & {
38
- name: WithOverride<Opts, 'name', string, 'availableLanguages'>
39
- fields: LocaleFields<
40
- WithOverride<Opts, 'locales', readonly LocaleDefinition[], typeof contentLocales>
41
- >
42
- }
43
-
44
- const builtInValidate = (value: Record<string, boolean> | undefined): string | undefined => {
45
- const hasSelection =
46
- value != null &&
47
- typeof value === 'object' &&
48
- !Array.isArray(value) &&
49
- Object.values(value).some(Boolean)
50
- if (!hasSelection) {
51
- return 'At least one language must be selected'
52
- }
53
- return undefined
54
- }
55
-
56
- /**
57
- * Returns a `GroupField` that renders one checkbox per locale entry.
58
- * Validation requires at least one language to be selected; if the caller
59
- * supplies its own `validate`, the built-in rule runs first and the caller's
60
- * validator only runs when the built-in passes.
61
- *
62
- * @description This field is intended for use in a document's "Edit" view
63
- * to allow editors to specify which languages a document is available in.
64
- * It is orthogonal to the defined workflow system and is here as a 'signal'
65
- * to frontend websites / consumers - allowing them to implement their own
66
- * logic around content availability per language.
67
- *
68
- * @param options - Optional overrides. Accepts any `GroupField` property
69
- * except `type` and `fields` (which are computed), plus a `locales` array
70
- * that drives the generated checkbox set.
71
- */
72
- export function availableLanguagesField<const Opts extends Options>(
73
- options: Opts = {} as Opts
74
- ): AvailableLanguagesField<Opts> {
75
- const { name, label, helpText, locales, validate: userValidate, ...rest } = options
76
-
77
- const validate = userValidate
78
- ? (value: any, data: Record<string, any>) => {
79
- const builtInError = builtInValidate(value)
80
- if (builtInError) return builtInError
81
- return userValidate(value, data)
82
- }
83
- : builtInValidate
84
-
85
- return {
86
- ...rest,
87
- name: (name ?? 'availableLanguages') as any,
88
- label: label ?? 'Published Languages',
89
- helpText: helpText ?? 'Select the languages this document is available in.',
90
- type: 'group',
91
- fields: (locales ?? contentLocales).map(({ code, label }) => ({
92
- name: code,
93
- label,
94
- type: 'checkbox' as const,
95
- optional: true,
96
- })) as any,
97
- validate,
98
- }
99
- }