@byline/cli 3.20.4 → 4.0.0
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 +42 -2
- package/dist/cli.js +5 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +1 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +10 -14
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/setup-checks.d.ts +9 -0
- package/dist/commands/setup-checks.d.ts.map +1 -1
- package/dist/commands/setup-checks.js +43 -18
- package/dist/commands/setup-checks.js.map +1 -1
- package/dist/commands/setup.js +1 -1
- package/dist/commands/setup.js.map +1 -1
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +6 -0
- package/dist/context.js.map +1 -1
- package/dist/lib/dependency-version.d.ts +12 -0
- package/dist/lib/dependency-version.d.ts.map +1 -0
- package/dist/lib/dependency-version.js +101 -0
- package/dist/lib/dependency-version.js.map +1 -0
- package/dist/lib/planned-writes.d.ts +8 -0
- package/dist/lib/planned-writes.d.ts.map +1 -0
- package/dist/lib/planned-writes.js +177 -0
- package/dist/lib/planned-writes.js.map +1 -0
- package/dist/lib/planned-writes.test.d.ts +2 -0
- package/dist/lib/planned-writes.test.d.ts.map +1 -0
- package/dist/lib/planned-writes.test.js +113 -0
- package/dist/lib/planned-writes.test.js.map +1 -0
- package/dist/lib/release-policy.d.ts +12 -0
- package/dist/lib/release-policy.d.ts.map +1 -0
- package/dist/lib/release-policy.js +20 -0
- package/dist/lib/release-policy.js.map +1 -0
- package/dist/lib/release-policy.test.d.ts +2 -0
- package/dist/lib/release-policy.test.d.ts.map +1 -0
- package/dist/lib/release-policy.test.js +36 -0
- package/dist/lib/release-policy.test.js.map +1 -0
- package/dist/lib/route-config.d.ts +40 -0
- package/dist/lib/route-config.d.ts.map +1 -0
- package/dist/lib/route-config.js +322 -0
- package/dist/lib/route-config.js.map +1 -0
- package/dist/lib/static-config.d.ts +20 -0
- package/dist/lib/static-config.d.ts.map +1 -0
- package/dist/lib/static-config.js +444 -0
- package/dist/lib/static-config.js.map +1 -0
- package/dist/lib/static-config.test.d.ts +2 -0
- package/dist/lib/static-config.test.d.ts.map +1 -0
- package/dist/lib/static-config.test.js +105 -0
- package/dist/lib/static-config.test.js.map +1 -0
- package/dist/lib/template-hook-boundary.test.node.d.ts +2 -0
- package/dist/lib/template-hook-boundary.test.node.d.ts.map +1 -0
- package/dist/lib/template-hook-boundary.test.node.js +30 -0
- package/dist/lib/template-hook-boundary.test.node.js.map +1 -0
- package/dist/lib/template-path.d.ts +5 -0
- package/dist/lib/template-path.d.ts.map +1 -0
- package/dist/lib/template-path.js +9 -0
- package/dist/lib/template-path.js.map +1 -0
- package/dist/lib/workspace-root.d.ts +28 -0
- package/dist/lib/workspace-root.d.ts.map +1 -0
- package/dist/lib/workspace-root.js +205 -0
- package/dist/lib/workspace-root.js.map +1 -0
- package/dist/manifest/deps.d.ts +1 -1
- package/dist/manifest/deps.d.ts.map +1 -1
- package/dist/manifest/deps.js +18 -8
- package/dist/manifest/deps.js.map +1 -1
- package/dist/phases/deps.d.ts +14 -1
- package/dist/phases/deps.d.ts.map +1 -1
- package/dist/phases/deps.js +312 -137
- package/dist/phases/deps.js.map +1 -1
- package/dist/phases/deps.test.d.ts +2 -0
- package/dist/phases/deps.test.d.ts.map +1 -0
- package/dist/phases/deps.test.js +343 -0
- package/dist/phases/deps.test.js.map +1 -0
- package/dist/phases/preflight.d.ts.map +1 -1
- package/dist/phases/preflight.js +59 -11
- package/dist/phases/preflight.js.map +1 -1
- package/dist/phases/prompts.d.ts +2 -0
- package/dist/phases/prompts.d.ts.map +1 -1
- package/dist/phases/prompts.js +51 -2
- package/dist/phases/prompts.js.map +1 -1
- package/dist/phases/routes-ui.test.d.ts +2 -0
- package/dist/phases/routes-ui.test.d.ts.map +1 -0
- package/dist/phases/routes-ui.test.js +766 -0
- package/dist/phases/routes-ui.test.js.map +1 -0
- package/dist/phases/routes.d.ts +4 -1
- package/dist/phases/routes.d.ts.map +1 -1
- package/dist/phases/routes.js +610 -122
- package/dist/phases/routes.js.map +1 -1
- package/dist/phases/scaffold-smoke.test.d.ts +2 -0
- package/dist/phases/scaffold-smoke.test.d.ts.map +1 -0
- package/dist/phases/scaffold-smoke.test.js +168 -0
- package/dist/phases/scaffold-smoke.test.js.map +1 -0
- package/dist/phases/scaffold.d.ts +4 -1
- package/dist/phases/scaffold.d.ts.map +1 -1
- package/dist/phases/scaffold.js +275 -72
- package/dist/phases/scaffold.js.map +1 -1
- package/dist/phases/scaffold.test.d.ts +2 -0
- package/dist/phases/scaffold.test.d.ts.map +1 -0
- package/dist/phases/scaffold.test.js +178 -0
- package/dist/phases/scaffold.test.js.map +1 -0
- package/dist/phases/ui.d.ts +4 -1
- package/dist/phases/ui.d.ts.map +1 -1
- package/dist/phases/ui.js +51 -59
- package/dist/phases/ui.js.map +1 -1
- package/dist/phases/wire/index.d.ts.map +1 -1
- package/dist/phases/wire/index.js +10 -6
- package/dist/phases/wire/index.js.map +1 -1
- package/dist/phases/wire/shared.d.ts +4 -1
- package/dist/phases/wire/shared.d.ts.map +1 -1
- package/dist/phases/wire/vite-config.d.ts.map +1 -1
- package/dist/phases/wire/vite-config.js +69 -20
- package/dist/phases/wire/vite-config.js.map +1 -1
- package/dist/phases/wire/vite-config.test.d.ts +2 -0
- package/dist/phases/wire/vite-config.test.d.ts.map +1 -0
- package/dist/phases/wire/vite-config.test.js +97 -0
- package/dist/phases/wire/vite-config.test.js.map +1 -0
- package/dist/prompts.d.ts +1 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +7 -2
- package/dist/prompts.js.map +1 -1
- package/dist/runner.js +1 -1
- package/dist/runner.js.map +1 -1
- package/dist/templates/byline/admin.config.ts +8 -7
- package/dist/templates/byline/clients.server.ts +77 -0
- package/dist/templates/byline/collection-types.contract.ts +67 -0
- package/dist/templates/byline/collections/index.ts +17 -0
- package/dist/templates/byline/collections/server-hooks.ts +7 -0
- package/dist/templates/byline/generated/collection-types.ts +11 -0
- package/dist/templates/byline/i18n.ts +3 -3
- package/dist/templates/byline/locales.ts +9 -9
- package/dist/templates/byline/public.ts +12 -0
- package/dist/templates/byline/routes.ts +7 -6
- package/dist/templates/byline/scripts/generate-types.ts +81 -0
- package/dist/templates/byline/server.config.ts +5 -5
- package/dist/templates/byline-examples/admin.config.ts +18 -21
- package/dist/templates/byline-examples/blocks/photo-block.ts +3 -2
- package/dist/templates/byline-examples/clients.server.ts +77 -0
- package/dist/templates/byline-examples/collection-types.contract.ts +67 -0
- package/dist/templates/byline-examples/collections/docs/hooks.ts +30 -20
- package/dist/templates/byline-examples/collections/docs/schema.ts +18 -18
- package/dist/templates/byline-examples/collections/index.ts +22 -0
- package/dist/templates/byline-examples/collections/media/components/media-list-view.tsx +11 -6
- package/dist/templates/byline-examples/collections/media/schema.ts +16 -0
- package/dist/templates/byline-examples/collections/news/schema.ts +17 -3
- package/dist/templates/byline-examples/collections/news-categories/schema.ts +13 -0
- package/dist/templates/byline-examples/collections/pages/schema.ts +13 -0
- package/dist/templates/byline-examples/collections/server-hooks.ts +8 -0
- package/dist/templates/byline-examples/fields/ai-text.ts +1 -1
- package/dist/templates/byline-examples/fields/ai-textarea.ts +1 -1
- package/dist/templates/byline-examples/fields/lexical-richtext-ai.tsx +3 -3
- package/dist/templates/byline-examples/generated/collection-types.ts +139 -0
- package/dist/templates/byline-examples/i18n.ts +3 -3
- package/dist/templates/byline-examples/locales.ts +9 -9
- package/dist/templates/byline-examples/public.ts +12 -0
- package/dist/templates/byline-examples/routes.ts +7 -6
- package/dist/templates/byline-examples/scripts/backfill-version-locales.ts +1 -1
- package/dist/templates/byline-examples/scripts/generate-types.ts +81 -0
- package/dist/templates/byline-examples/scripts/import-docs.ts +11 -12
- package/dist/templates/byline-examples/scripts/lib/mdast-to-lexical.test.node.ts +93 -233
- package/dist/templates/byline-examples/scripts/lib/mdast-to-lexical.ts +2 -2
- package/dist/templates/byline-examples/scripts/lib/strip-leading-h1.test.node.ts +0 -4
- package/dist/templates/byline-examples/scripts/re-anchor.ts +3 -3
- package/dist/templates/byline-examples/scripts/regenerate-media.ts +6 -5
- package/dist/templates/byline-examples/server.config.ts +6 -15
- package/dist/templates/host/vite.config.ts +2 -0
- package/dist/templates/routes/_byline/admin/collections/$collection/$id/api.tsx +1 -6
- package/dist/templates/routes/_byline/admin/collections/$collection/$id/history.tsx +1 -7
- package/dist/templates/routes/_byline/admin/collections/$collection/$id/index.tsx +1 -6
- package/dist/templates/routes/_byline/route.lazy.tsx +1 -2
- package/dist/templates/routes/_byline/route.tsx +1 -1
- package/dist/templates/ui-byline/blocks/photo-block/index.tsx +18 -23
- package/dist/templates/ui-byline/blocks/richtext-block/index.tsx +1 -1
- package/dist/templates/ui-byline/components/admonition/index.tsx +11 -8
- package/dist/templates/ui-byline/components/code/code.tsx +6 -4
- package/dist/templates/ui-byline/components/link/lang-link.tsx +4 -8
- package/dist/templates/ui-byline/components/link/link-field.tsx +3 -2
- package/dist/templates/ui-byline/components/link/link-lexical.tsx +9 -8
- package/dist/templates/ui-byline/render-blocks.tsx +38 -38
- package/dist/templates/ui-byline/types/content.ts +25 -0
- package/dist/templates/ui-byline/types/i18n.ts +4 -8
- package/dist/test-helpers.d.ts +5 -0
- package/dist/test-helpers.d.ts.map +1 -0
- package/dist/test-helpers.js +52 -0
- package/dist/test-helpers.js.map +1 -0
- package/dist/types.d.ts +21 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/ui-template-contract.test.d.ts +2 -0
- package/dist/ui-template-contract.test.d.ts.map +1 -0
- package/dist/ui-template-contract.test.js +130 -0
- package/dist/ui-template-contract.test.js.map +1 -0
- package/dist/workspace-root.test.d.ts +2 -0
- package/dist/workspace-root.test.d.ts.map +1 -0
- package/dist/workspace-root.test.js +307 -0
- package/dist/workspace-root.test.js.map +1 -0
- package/package.json +9 -1
|
@@ -8,20 +8,21 @@
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Registers Byline's client-side config (collection admin UI configs,
|
|
11
|
-
* field editors, i18n, routes) in the current module graph.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* field editors, i18n, routes) in the current module graph. The `_byline`
|
|
12
|
+
* route registers it from two complementary points: a dynamic import in
|
|
13
|
+
* `route.tsx` covers child loaders, while the side-effect import in
|
|
14
|
+
* `route.lazy.tsx` covers component render and initial hydration. Keeping
|
|
15
|
+
* both imports behind `_byline/*` keeps the admin graph off public routes.
|
|
15
16
|
*
|
|
16
17
|
* This is the minimal scaffold: no example collections registered. Add
|
|
17
|
-
*
|
|
18
|
-
* arrays as you create them.
|
|
18
|
+
* schemas to `collections/index.ts` and presentation configs to `admin`.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import type { ClientConfig } from '@byline/core'
|
|
22
22
|
import { defineClientConfig } from '@byline/core'
|
|
23
23
|
import { RichTextField as LexicalRichTextField } from '@byline/richtext-lexical'
|
|
24
24
|
|
|
25
|
+
import { collections } from './collections/index.js'
|
|
25
26
|
import { i18n } from './i18n.js'
|
|
26
27
|
import { DEFAULT_SERVER_URL, routes } from './routes.js'
|
|
27
28
|
|
|
@@ -31,7 +32,7 @@ export const config: ClientConfig = {
|
|
|
31
32
|
serverURL,
|
|
32
33
|
i18n,
|
|
33
34
|
routes,
|
|
34
|
-
collections
|
|
35
|
+
collections,
|
|
35
36
|
admin: [],
|
|
36
37
|
fields: {
|
|
37
38
|
richText: { editor: LexicalRichTextField },
|
|
@@ -0,0 +1,77 @@
|
|
|
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
|
+
* Typed, server-only access to this application's Byline clients.
|
|
11
|
+
*
|
|
12
|
+
* ```text
|
|
13
|
+
* generated/collection-types.ts
|
|
14
|
+
* `CollectionFieldsByPath`
|
|
15
|
+
* |
|
|
16
|
+
* v
|
|
17
|
+
* collections/index.ts --------------------.
|
|
18
|
+
* `BylineCollections` |
|
|
19
|
+
* v
|
|
20
|
+
* @byline/host-tanstack-start ------> clients.server.ts
|
|
21
|
+
* runtime client getters |
|
|
22
|
+
* v
|
|
23
|
+
* typed `get*BylineClient()` getters
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Why this boundary exists:
|
|
27
|
+
*
|
|
28
|
+
* The TanStack host owns the runtime admin, public, system, and viewer client
|
|
29
|
+
* singletons. It intentionally knows nothing about an application's collection
|
|
30
|
+
* schemas, so its getters cannot provide application-specific collection paths
|
|
31
|
+
* and field shapes. The generated `CollectionFieldsByPath` registry is exported
|
|
32
|
+
* as `BylineCollections` by `collections/index.ts`; this module joins the host
|
|
33
|
+
* getters and app registry once instead of repeating a type assertion at every
|
|
34
|
+
* server call site.
|
|
35
|
+
*
|
|
36
|
+
* Typical server usage:
|
|
37
|
+
*
|
|
38
|
+
* ```ts
|
|
39
|
+
* const publicClient = getPublicBylineClient() // anonymous published reads
|
|
40
|
+
* const viewerClient = getViewerBylineClient() // public or admin-preview reads
|
|
41
|
+
* const adminClient = getAdminBylineClient() // current admin request authority
|
|
42
|
+
* const systemClient = getSystemBylineClient() // trusted hooks and maintenance
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* Calls to `client.collection('<collection-path>')` are therefore checked
|
|
46
|
+
* against this application's generated registry and return that collection's
|
|
47
|
+
* canonical generated field shape. `collection-types.contract.ts` separately
|
|
48
|
+
* proves that those generated shapes match the runtime schemas exactly.
|
|
49
|
+
*
|
|
50
|
+
* The `.server.ts` suffix is intentional. Import these getters only from server
|
|
51
|
+
* routes, loaders, actions, scripts, or lifecycle-hook modules; browser code
|
|
52
|
+
* must not cross this boundary.
|
|
53
|
+
*
|
|
54
|
+
* This module does not create client singletons, generate collection types, or
|
|
55
|
+
* configure the host. It only applies the app-specific client type and
|
|
56
|
+
* re-exports the host-owned getters (plus the viewer preview-state helper).
|
|
57
|
+
*/
|
|
58
|
+
import type { BylineClient } from '@byline/client'
|
|
59
|
+
import {
|
|
60
|
+
getAdminBylineClient as getHostAdminBylineClient,
|
|
61
|
+
getSystemBylineClient as getHostSystemBylineClient,
|
|
62
|
+
} from '@byline/host-tanstack-start/integrations/byline-client'
|
|
63
|
+
import { getPublicBylineClient as getHostPublicBylineClient } from '@byline/host-tanstack-start/integrations/byline-public-client'
|
|
64
|
+
import {
|
|
65
|
+
getViewerBylineClient as getHostViewerBylineClient,
|
|
66
|
+
isPreviewActive,
|
|
67
|
+
} from '@byline/host-tanstack-start/integrations/byline-viewer-client'
|
|
68
|
+
|
|
69
|
+
import type { BylineCollections } from './collections/index.js'
|
|
70
|
+
|
|
71
|
+
type AppBylineClient = BylineClient<BylineCollections>
|
|
72
|
+
|
|
73
|
+
export const getAdminBylineClient = getHostAdminBylineClient as () => AppBylineClient
|
|
74
|
+
export const getPublicBylineClient = getHostPublicBylineClient as () => AppBylineClient
|
|
75
|
+
export const getSystemBylineClient = getHostSystemBylineClient as () => AppBylineClient
|
|
76
|
+
export const getViewerBylineClient = getHostViewerBylineClient as () => AppBylineClient
|
|
77
|
+
export { isPreviewActive }
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile-time contract between this application's collection schemas and its
|
|
3
|
+
* generated collection-type projection.
|
|
4
|
+
*
|
|
5
|
+
* ```text
|
|
6
|
+
* collections/index.ts generated/collection-types.ts
|
|
7
|
+
* `typeof collections` `CollectionFields*ByPath`
|
|
8
|
+
* | |
|
|
9
|
+
* v v
|
|
10
|
+
* inferred registry ----------- Exact -------- generated registry
|
|
11
|
+
* |
|
|
12
|
+
* v
|
|
13
|
+
* TypeScript error on drift
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* The generated file is deliberately a standalone projection for typed clients
|
|
17
|
+
* and frontend code; it does not import the runtime schemas. This module joins
|
|
18
|
+
* those two app-owned sources at compile time and requires their collection
|
|
19
|
+
* keys, ordinary field shapes, and all-locale field shapes to match exactly.
|
|
20
|
+
*
|
|
21
|
+
* This file has no runtime behavior. Keep it application-owned: `@byline/core`
|
|
22
|
+
* provides the inference and code-generation machinery, but only this
|
|
23
|
+
* application knows its concrete collection tuple and generated output.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import type { CollectionFieldData, CollectionFieldDataAllLocales } from '@byline/core'
|
|
27
|
+
|
|
28
|
+
import type { collections } from './collections/index.js'
|
|
29
|
+
import type {
|
|
30
|
+
CollectionFieldsAllLocalesByPath,
|
|
31
|
+
CollectionFieldsByPath,
|
|
32
|
+
} from './generated/collection-types.js'
|
|
33
|
+
|
|
34
|
+
type InferredFieldsByPath = {
|
|
35
|
+
[Definition in (typeof collections)[number] as Definition['path']]: CollectionFieldData<Definition>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type InferredFieldsAllLocalesByPath = {
|
|
39
|
+
[Definition in (typeof collections)[number] as Definition['path']]: CollectionFieldDataAllLocales<Definition>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type IsAny<Value> = 0 extends 1 & Value ? true : false
|
|
43
|
+
type Exact<Left, Right> = IsAny<Left> extends true
|
|
44
|
+
? IsAny<Right>
|
|
45
|
+
: IsAny<Right> extends true
|
|
46
|
+
? false
|
|
47
|
+
: (<Value>() => Value extends Left ? 1 : 2) extends <Value>() =>
|
|
48
|
+
Value extends Right ? 1 : 2
|
|
49
|
+
? (<Value>() => Value extends Right ? 1 : 2) extends <Value>() =>
|
|
50
|
+
Value extends Left ? 1 : 2
|
|
51
|
+
? true
|
|
52
|
+
: false
|
|
53
|
+
: false
|
|
54
|
+
type Assert<Value extends true> = Value
|
|
55
|
+
|
|
56
|
+
type GeneratedKeysMatchRuntimeRegistry = Assert<
|
|
57
|
+
Exact<keyof CollectionFieldsByPath, keyof InferredFieldsByPath>
|
|
58
|
+
>
|
|
59
|
+
type GeneratedFieldsMatchRuntimeRegistry = Assert<
|
|
60
|
+
Exact<CollectionFieldsByPath, InferredFieldsByPath>
|
|
61
|
+
>
|
|
62
|
+
type GeneratedAllLocalesKeysMatchRuntimeRegistry = Assert<
|
|
63
|
+
Exact<keyof CollectionFieldsAllLocalesByPath, keyof InferredFieldsAllLocalesByPath>
|
|
64
|
+
>
|
|
65
|
+
type GeneratedAllLocalesFieldsMatchRuntimeRegistry = Assert<
|
|
66
|
+
Exact<CollectionFieldsAllLocalesByPath, InferredFieldsAllLocalesByPath>
|
|
67
|
+
>
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
import type { InferCollectionRegistry } from '@byline/core'
|
|
10
|
+
|
|
11
|
+
import type { CollectionFieldsByPath } from '../generated/collection-types.js'
|
|
12
|
+
|
|
13
|
+
/** Add schema-only collection imports here; keep admin presentation separate. */
|
|
14
|
+
export const collections = [] as const
|
|
15
|
+
|
|
16
|
+
export type InferredBylineCollections = InferCollectionRegistry<typeof collections>
|
|
17
|
+
export type BylineCollections = CollectionFieldsByPath
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Generated by @byline/core/codegen
|
|
2
|
+
// Format version: 1
|
|
3
|
+
// Hash: 4ef42b796dc35fceb394f97eaef885c5795c52031ba91f9ca6ca7e0fd2f20608
|
|
4
|
+
|
|
5
|
+
export type CollectionFieldsByPath = {
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type CollectionFieldsAllLocalesByPath = {
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type CollectionPath = keyof CollectionFieldsByPath
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* translation bundle.
|
|
13
13
|
*
|
|
14
14
|
* The locale arrays themselves live in `./locales.ts`, a dependency-free leaf
|
|
15
|
-
* module
|
|
16
|
-
* translation graph this file depends on. Re-exported here for
|
|
17
|
-
* with existing `~/i18n` importers.
|
|
15
|
+
* module exposed to public frontend code by `./public.ts`, without pulling in
|
|
16
|
+
* the admin translation graph this file depends on. Re-exported here for
|
|
17
|
+
* back-compat with existing `~/i18n` importers.
|
|
18
18
|
*
|
|
19
19
|
* `interface` locales govern the CMS admin UI language.
|
|
20
20
|
* `content` locales govern the languages a document can be published in.
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
* registry). `byline/i18n.ts` consumes these to assemble the
|
|
13
13
|
* `defineServerConfig` / `defineClientConfig` payload.
|
|
14
14
|
*
|
|
15
|
-
* Kept separate from `byline/i18n.ts` so
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* (`@byline/i18n/admin`) that `i18n.ts` depends on.
|
|
19
|
-
* would; importing this won't — which keeps the lazy
|
|
20
|
-
* (`src/routes/_byline/route.lazy.tsx`) intact.
|
|
15
|
+
* Kept separate from `byline/i18n.ts` so `byline/public.ts` can expose the
|
|
16
|
+
* locale arrays to a public frontend (or a collection schema file loaded
|
|
17
|
+
* outside Vite — e.g. when running seeds via tsx) without dragging in the
|
|
18
|
+
* admin translation graph (`@byline/i18n/admin`) that `i18n.ts` depends on.
|
|
19
|
+
* Importing `byline/i18n.ts` would; importing this won't — which keeps the lazy
|
|
20
|
+
* admin/public bundle split (`src/routes/_byline/route.lazy.tsx`) intact.
|
|
21
21
|
*
|
|
22
22
|
* `interface` locales govern the CMS admin UI language; `content` locales
|
|
23
23
|
* govern the languages a document can be published in.
|
|
@@ -33,10 +33,10 @@ export interface LocaleDefinition {
|
|
|
33
33
|
// (or a third-party plugin merged in via `mergeTranslations(...)`).
|
|
34
34
|
// `adminTranslations({ locales })` in `byline/i18n.ts` throws at boot if a
|
|
35
35
|
// requested code is not bundled — `@byline/i18n/admin` ships English and French.
|
|
36
|
-
export const interfaceLocales
|
|
36
|
+
export const interfaceLocales = [
|
|
37
37
|
{ code: 'en', label: 'English' },
|
|
38
38
|
{ code: 'fr', label: 'Français' },
|
|
39
|
-
]
|
|
39
|
+
] as const satisfies readonly LocaleDefinition[]
|
|
40
40
|
|
|
41
41
|
/** Locales a document can be published in. */
|
|
42
42
|
export const contentLocales = [
|
|
@@ -44,4 +44,4 @@ export const contentLocales = [
|
|
|
44
44
|
{ code: 'fr', label: 'Français' },
|
|
45
45
|
{ code: 'es', label: 'Español' },
|
|
46
46
|
{ code: 'de', label: 'Deutsch' },
|
|
47
|
-
] as const
|
|
47
|
+
] as const satisfies readonly LocaleDefinition[]
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
/** Client-safe public configuration. Keep this barrel free of admin and server imports. */
|
|
10
|
+
export { contentLocales, interfaceLocales } from './locales.js'
|
|
11
|
+
export { routes } from './routes.js'
|
|
12
|
+
export type { LocaleDefinition } from './locales.js'
|
|
@@ -7,17 +7,18 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* URL
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Client-safe URL paths for admin, sign-in, and the future public API.
|
|
11
|
+
* Resolve once at this client-safe configuration boundary so consumers only
|
|
12
|
+
* read canonical paths.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import
|
|
15
|
+
import { resolveRoutes } from '@byline/core'
|
|
16
16
|
|
|
17
|
-
export const routes
|
|
17
|
+
export const routes = resolveRoutes({
|
|
18
18
|
admin: '/admin',
|
|
19
19
|
api: '/api',
|
|
20
|
-
|
|
20
|
+
signIn: '/sign-in',
|
|
21
|
+
})
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Fallback used by both server and admin entry points when no
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto'
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import { dirname, resolve } from 'node:path'
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
5
|
+
|
|
6
|
+
import { emitCollectionTypes } from '@byline/core/codegen'
|
|
7
|
+
|
|
8
|
+
import { collections } from '../collections/index.js'
|
|
9
|
+
|
|
10
|
+
const defaultOutputPath = fileURLToPath(
|
|
11
|
+
new URL('../generated/collection-types.ts', import.meta.url)
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
export type GenerationStatus = 'current' | 'unchanged' | 'written'
|
|
15
|
+
|
|
16
|
+
export function writeCollectionTypes(
|
|
17
|
+
outputPath: string,
|
|
18
|
+
source: string,
|
|
19
|
+
check: boolean
|
|
20
|
+
): GenerationStatus {
|
|
21
|
+
const existing = existsSync(outputPath) ? readFileSync(outputPath, 'utf8') : undefined
|
|
22
|
+
|
|
23
|
+
if (check) {
|
|
24
|
+
if (existing === undefined) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`generated collection types are missing: ${outputPath}. Run pnpm byline:generate`
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
if (existing !== source) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`generated collection types are stale: ${outputPath}. Run pnpm byline:generate`
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
return 'current'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (existing === source) return 'unchanged'
|
|
38
|
+
|
|
39
|
+
mkdirSync(dirname(outputPath), { recursive: true })
|
|
40
|
+
const temporaryPath = `${outputPath}.${process.pid}.${randomUUID()}.tmp`
|
|
41
|
+
try {
|
|
42
|
+
writeFileSync(temporaryPath, source, 'utf8')
|
|
43
|
+
renameSync(temporaryPath, outputPath)
|
|
44
|
+
} finally {
|
|
45
|
+
rmSync(temporaryPath, { force: true })
|
|
46
|
+
}
|
|
47
|
+
return 'written'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function parseArgs(args: readonly string[]): { check: boolean } {
|
|
51
|
+
const unknown = args.filter((arg) => arg !== '--check')
|
|
52
|
+
if (unknown.length > 0) throw new Error(`unknown argument: ${unknown.join(', ')}`)
|
|
53
|
+
if (args.filter((arg) => arg === '--check').length > 1) {
|
|
54
|
+
throw new Error('duplicate argument: --check')
|
|
55
|
+
}
|
|
56
|
+
return { check: args.includes('--check') }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function generateCollectionTypes(
|
|
60
|
+
outputPath = defaultOutputPath,
|
|
61
|
+
check = false
|
|
62
|
+
): { hash: string; status: GenerationStatus } {
|
|
63
|
+
const { source, hash } = emitCollectionTypes(collections)
|
|
64
|
+
return { hash, status: writeCollectionTypes(outputPath, source, check) }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function main(): void {
|
|
68
|
+
const { check } = parseArgs(process.argv.slice(2))
|
|
69
|
+
const { hash, status } = generateCollectionTypes(defaultOutputPath, check)
|
|
70
|
+
console.log(`collection types: ${collections.length} collections ${hash.slice(0, 12)} ${status}`)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const entryPath = process.argv[1]
|
|
74
|
+
if (entryPath !== undefined && pathToFileURL(resolve(entryPath)).href === import.meta.url) {
|
|
75
|
+
try {
|
|
76
|
+
main()
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error(`collection type generation failed: ${(error as Error).message}`)
|
|
79
|
+
process.exitCode = 1
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
* read it back with `getBylineCore<AdminStore>()`.
|
|
15
15
|
*
|
|
16
16
|
* This is the minimal scaffold: no example collections registered. Add
|
|
17
|
-
* collection schemas to the
|
|
18
|
-
* `byline/collections/<name>/schema.ts`.
|
|
17
|
+
* collection schemas to the shared tuple in `byline/collections/index.ts`.
|
|
19
18
|
*/
|
|
20
19
|
|
|
21
20
|
import { type AdminStore, registerAdminAbilities } from '@byline/admin'
|
|
@@ -23,7 +22,6 @@ import { JwtSessionProvider } from '@byline/admin/auth'
|
|
|
23
22
|
import { type BylineCore, initBylineCore } from '@byline/core'
|
|
24
23
|
import { pgAdapter } from '@byline/db-postgres'
|
|
25
24
|
import { createAdminStore } from '@byline/db-postgres/admin'
|
|
26
|
-
import { getAdminBylineClient } from '@byline/host-tanstack-start/integrations/byline-client'
|
|
27
25
|
import {
|
|
28
26
|
lexicalEditorEmbedServer,
|
|
29
27
|
lexicalEditorPopulateServer,
|
|
@@ -31,13 +29,14 @@ import {
|
|
|
31
29
|
} from '@byline/richtext-lexical/server'
|
|
32
30
|
import { localStorageProvider } from '@byline/storage-local'
|
|
33
31
|
|
|
32
|
+
import { getAdminBylineClient } from './clients.server.js'
|
|
33
|
+
import { collections } from './collections/index.js'
|
|
34
|
+
import { serverHooks } from './collections/server-hooks.js'
|
|
34
35
|
import { i18n } from './i18n.js'
|
|
35
36
|
import { DEFAULT_SERVER_URL, routes } from './routes.js'
|
|
36
37
|
|
|
37
38
|
const serverURL = process.env.VITE_SERVER_URL || DEFAULT_SERVER_URL
|
|
38
39
|
|
|
39
|
-
const collections: Parameters<typeof pgAdapter>[0]['collections'] = []
|
|
40
|
-
|
|
41
40
|
// HMR-safe singleton. Vite's program reload re-evaluates this module
|
|
42
41
|
// without disposing the previous module's resources — every reload
|
|
43
42
|
// would otherwise allocate a fresh pg `Pool` (max: 20) inside
|
|
@@ -93,6 +92,7 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
|
|
|
93
92
|
i18n,
|
|
94
93
|
routes,
|
|
95
94
|
collections,
|
|
95
|
+
hooks: serverHooks,
|
|
96
96
|
db,
|
|
97
97
|
adminStore,
|
|
98
98
|
// Local filesystem — suitable for development and self-hosted
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Registers Byline's client-side config (collection admin UI configs,
|
|
11
|
-
* field editors, i18n, routes) in the current module graph.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* field editors, i18n, routes) in the current module graph. The `_byline`
|
|
12
|
+
* route registers it from two complementary points: a dynamic import in
|
|
13
|
+
* `route.tsx` covers child loaders, while the side-effect import in
|
|
14
|
+
* `route.lazy.tsx` covers component render and initial hydration. Keeping
|
|
15
|
+
* both imports behind `_byline/*` keeps the admin graph off public routes.
|
|
15
16
|
*
|
|
16
|
-
* In TanStack Start
|
|
17
|
-
*
|
|
17
|
+
* In TanStack Start the server entry (`src/server.ts`) and the SSR rendering
|
|
18
|
+
* context run in separate Vite environments, so
|
|
18
19
|
* importing this file from `src/server.ts` would NOT propagate the
|
|
19
20
|
* registration into the SSR render module graph.
|
|
20
21
|
*/
|
|
@@ -28,11 +29,12 @@ import { RichTextField as LexicalRichTextField } from '@byline/richtext-lexical'
|
|
|
28
29
|
// commented `richText` block below for the exact shape.
|
|
29
30
|
// import { lexicalEditor } from '@byline/richtext-lexical'
|
|
30
31
|
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
32
|
+
import { DocsAdmin } from './collections/docs/admin.js'
|
|
33
|
+
import { collections } from './collections/index.js'
|
|
34
|
+
import { MediaAdmin } from './collections/media/admin.js'
|
|
35
|
+
import { NewsAdmin } from './collections/news/admin.js'
|
|
36
|
+
import { NewsCategoriesAdmin } from './collections/news-categories/admin.js'
|
|
37
|
+
import { PagesAdmin } from './collections/pages/admin.js'
|
|
36
38
|
import { i18n } from './i18n.js'
|
|
37
39
|
import { DEFAULT_SERVER_URL, routes } from './routes.js'
|
|
38
40
|
|
|
@@ -42,7 +44,7 @@ export const config: ClientConfig = {
|
|
|
42
44
|
serverURL,
|
|
43
45
|
i18n,
|
|
44
46
|
routes,
|
|
45
|
-
collections
|
|
47
|
+
collections,
|
|
46
48
|
admin: [DocsAdmin, NewsAdmin, PagesAdmin, MediaAdmin, NewsCategoriesAdmin],
|
|
47
49
|
fields: {
|
|
48
50
|
// Default registration — every `type: 'richText'` field gets the full
|
|
@@ -58,19 +60,14 @@ export const config: ClientConfig = {
|
|
|
58
60
|
// mutations are local to this call. Per-field `editorConfig`
|
|
59
61
|
// continues to take precedence over whatever is baked in here.
|
|
60
62
|
//
|
|
61
|
-
// import {
|
|
62
|
-
// lexicalEditor,
|
|
63
|
-
// AdmonitionExtension,
|
|
64
|
-
// CodeHighlightExtension,
|
|
65
|
-
// TableExtension,
|
|
66
|
-
// } from '@byline/richtext-lexical'
|
|
63
|
+
// import { builtInExtensions, lexicalEditor } from '@byline/richtext-lexical/config'
|
|
67
64
|
//
|
|
68
65
|
// richText: {
|
|
69
66
|
// editor: lexicalEditor((c) => {
|
|
70
67
|
// c.extensions
|
|
71
|
-
// .remove(
|
|
72
|
-
// .remove(
|
|
73
|
-
// .remove(
|
|
68
|
+
// .remove(builtInExtensions.Table)
|
|
69
|
+
// .remove(builtInExtensions.CodeHighlight)
|
|
70
|
+
// .remove(builtInExtensions.Admonition)
|
|
74
71
|
// c.settings.placeholderText = 'Start writing...'
|
|
75
72
|
// return c
|
|
76
73
|
// }),
|
|
@@ -53,7 +53,8 @@ export type PhotoBlockFields = BlockFieldData<typeof PhotoBlock>
|
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Full block instance shape (`_id`, `_type` + fields) as it appears
|
|
56
|
-
* inside a document tree.
|
|
57
|
-
*
|
|
56
|
+
* inside a document tree. This alias is useful for schema-local helpers;
|
|
57
|
+
* app-facing renderers should import `PhotoBlockData` from
|
|
58
|
+
* `byline/generated/collection-types.ts` and overlay populated relations.
|
|
58
59
|
*/
|
|
59
60
|
export type PhotoBlockData = BlockData<typeof PhotoBlock>
|
|
@@ -0,0 +1,77 @@
|
|
|
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
|
+
* Typed, server-only access to this application's Byline clients.
|
|
11
|
+
*
|
|
12
|
+
* ```text
|
|
13
|
+
* generated/collection-types.ts
|
|
14
|
+
* `CollectionFieldsByPath`
|
|
15
|
+
* |
|
|
16
|
+
* v
|
|
17
|
+
* collections/index.ts --------------------.
|
|
18
|
+
* `BylineCollections` |
|
|
19
|
+
* v
|
|
20
|
+
* @byline/host-tanstack-start ------> clients.server.ts
|
|
21
|
+
* runtime client getters |
|
|
22
|
+
* v
|
|
23
|
+
* typed `get*BylineClient()` getters
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Why this boundary exists:
|
|
27
|
+
*
|
|
28
|
+
* The TanStack host owns the runtime admin, public, system, and viewer client
|
|
29
|
+
* singletons. It intentionally knows nothing about an application's collection
|
|
30
|
+
* schemas, so its getters cannot provide application-specific collection paths
|
|
31
|
+
* and field shapes. The generated `CollectionFieldsByPath` registry is exported
|
|
32
|
+
* as `BylineCollections` by `collections/index.ts`; this module joins the host
|
|
33
|
+
* getters and app registry once instead of repeating a type assertion at every
|
|
34
|
+
* server call site.
|
|
35
|
+
*
|
|
36
|
+
* Typical server usage:
|
|
37
|
+
*
|
|
38
|
+
* ```ts
|
|
39
|
+
* const publicClient = getPublicBylineClient() // anonymous published reads
|
|
40
|
+
* const viewerClient = getViewerBylineClient() // public or admin-preview reads
|
|
41
|
+
* const adminClient = getAdminBylineClient() // current admin request authority
|
|
42
|
+
* const systemClient = getSystemBylineClient() // trusted hooks and maintenance
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* Calls such as `systemClient.collection('docs')` are therefore checked against
|
|
46
|
+
* this application's generated registry and return the canonical generated
|
|
47
|
+
* field shape for `docs`. `collection-types.contract.ts` separately proves that
|
|
48
|
+
* those generated shapes still match the runtime collection schemas exactly.
|
|
49
|
+
*
|
|
50
|
+
* The `.server.ts` suffix is intentional. Import these getters only from server
|
|
51
|
+
* routes, loaders, actions, scripts, or lifecycle-hook modules; browser code
|
|
52
|
+
* must not cross this boundary.
|
|
53
|
+
*
|
|
54
|
+
* This module does not create client singletons, generate collection types, or
|
|
55
|
+
* configure the host. It only applies the app-specific client type and
|
|
56
|
+
* re-exports the host-owned getters (plus the viewer preview-state helper).
|
|
57
|
+
*/
|
|
58
|
+
import type { BylineClient } from '@byline/client'
|
|
59
|
+
import {
|
|
60
|
+
getAdminBylineClient as getHostAdminBylineClient,
|
|
61
|
+
getSystemBylineClient as getHostSystemBylineClient,
|
|
62
|
+
} from '@byline/host-tanstack-start/integrations/byline-client'
|
|
63
|
+
import { getPublicBylineClient as getHostPublicBylineClient } from '@byline/host-tanstack-start/integrations/byline-public-client'
|
|
64
|
+
import {
|
|
65
|
+
getViewerBylineClient as getHostViewerBylineClient,
|
|
66
|
+
isPreviewActive,
|
|
67
|
+
} from '@byline/host-tanstack-start/integrations/byline-viewer-client'
|
|
68
|
+
|
|
69
|
+
import type { BylineCollections } from './collections/index.js'
|
|
70
|
+
|
|
71
|
+
type AppBylineClient = BylineClient<BylineCollections>
|
|
72
|
+
|
|
73
|
+
export const getAdminBylineClient = getHostAdminBylineClient as () => AppBylineClient
|
|
74
|
+
export const getPublicBylineClient = getHostPublicBylineClient as () => AppBylineClient
|
|
75
|
+
export const getSystemBylineClient = getHostSystemBylineClient as () => AppBylineClient
|
|
76
|
+
export const getViewerBylineClient = getHostViewerBylineClient as () => AppBylineClient
|
|
77
|
+
export { isPreviewActive }
|