@byline/cli 3.13.3 → 3.15.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/dist/manifest/deps.d.ts.map +1 -1
- package/dist/manifest/deps.js +6 -0
- package/dist/manifest/deps.js.map +1 -1
- package/dist/templates/byline-examples/collections/docs/admin.tsx +15 -4
- package/dist/templates/byline-examples/collections/docs/hooks.ts +112 -0
- package/dist/templates/byline-examples/collections/docs/schema.ts +19 -80
- package/dist/templates/byline-examples/collections/media/admin.tsx +2 -2
- package/dist/templates/byline-examples/collections/news/admin.tsx +3 -3
- package/dist/templates/byline-examples/collections/news-categories/admin.tsx +1 -1
- package/dist/templates/byline-examples/collections/pages/admin.tsx +3 -3
- package/dist/templates/byline-examples/server.config.ts +24 -0
- package/package.json +1 -1
- package/dist/templates/byline-examples/collections/docs/hooks/.gitkeep +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../src/manifest/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAA;AAEnD;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,YAAY,CAAA;AAE1C,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,QAAQ,CAAA;IACf,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAA;IACZ,qEAAqE;IACrE,QAAQ,CAAC,EAAE,eAAe,CAAA;CAC3B;AASD,eAAO,MAAM,cAAc,WAAW,CAAA;AAEtC,eAAO,MAAM,SAAS,EAAE,SAAS,OAAO,
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../src/manifest/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAA;AAEnD;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,YAAY,CAAA;AAE1C,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,QAAQ,CAAA;IACf,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAA;IACZ,qEAAqE;IACrE,QAAQ,CAAC,EAAE,eAAe,CAAA;CAC3B;AASD,eAAO,MAAM,cAAc,WAAW,CAAA;AAEtC,eAAO,MAAM,SAAS,EAAE,SAAS,OAAO,EAuK9B,CAAA"}
|
package/dist/manifest/deps.js
CHANGED
|
@@ -78,6 +78,12 @@ export const DEP_SPECS = [
|
|
|
78
78
|
group: 'byline',
|
|
79
79
|
note: 'Lexical-backed richtext field + server populate',
|
|
80
80
|
},
|
|
81
|
+
{
|
|
82
|
+
name: '@byline/search-postgres',
|
|
83
|
+
version: BYLINE_VERSION,
|
|
84
|
+
group: 'byline',
|
|
85
|
+
note: 'built-in Postgres full-text search provider; registered in byline/server.config.ts, drives collections/docs indexing hooks',
|
|
86
|
+
},
|
|
81
87
|
{
|
|
82
88
|
name: '@byline/storage-local',
|
|
83
89
|
version: BYLINE_VERSION,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../src/manifest/deps.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../src/manifest/deps.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* Copyright (c) Infonomic Company Limited
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { type CollectionAdminConfig, type ColumnDefinition, defineAdmin } from '@byline/core'
|
|
10
9
|
import { DateTimeFormatter } from '@byline/admin/react'
|
|
10
|
+
import { type CollectionAdminConfig, type ColumnDefinition, defineAdmin } from '@byline/core'
|
|
11
|
+
import { ReindexButton } from '@byline/host-tanstack-start/admin-shell/collections/reindex-button'
|
|
11
12
|
|
|
12
13
|
import { SummaryLength } from '~/components/summary-length.js'
|
|
13
14
|
|
|
@@ -70,12 +71,12 @@ export const DocsAdmin: CollectionAdminConfig = defineAdmin(Docs, {
|
|
|
70
71
|
* picker modal (opened from a `relation` field widget). Omit to fall back to a
|
|
71
72
|
* single-line render of `useAsTitle` + `path`.
|
|
72
73
|
*
|
|
73
|
-
* Shape matches `ColumnDefinition` so formatters can be reused across list and
|
|
74
|
+
* Shape matches `ColumnDefinition` so formatters can be reused across list and item view.
|
|
74
75
|
*
|
|
75
76
|
* @example
|
|
76
|
-
*
|
|
77
|
+
* itemView: [{ fieldName: 'title', label: 'Title' }] // or defined above as `pickerViewColumns`
|
|
77
78
|
*/
|
|
78
|
-
//
|
|
79
|
+
// itemView: [],
|
|
79
80
|
|
|
80
81
|
/**
|
|
81
82
|
* Custom list-view component that completely replaces the default table-based `ListView`
|
|
@@ -89,6 +90,16 @@ export const DocsAdmin: CollectionAdminConfig = defineAdmin(Docs, {
|
|
|
89
90
|
*/
|
|
90
91
|
// listView: undefined,
|
|
91
92
|
|
|
93
|
+
/**
|
|
94
|
+
* Header action components for the default list view — a reusable slot in
|
|
95
|
+
* the list header (the Payload `beforeList`/`afterList` analog). `ReindexButton`
|
|
96
|
+
* rebuilds this collection's search index; it self-gates on the
|
|
97
|
+
* `collections.docs.reindex` ability, so it only appears for actors who
|
|
98
|
+
* hold it. Drop this (and the `search` config in schema.ts) if you don't
|
|
99
|
+
* want search on this collection. See docs/05-reading-and-delivery/07-search.md.
|
|
100
|
+
*/
|
|
101
|
+
listActions: [ReindexButton],
|
|
102
|
+
|
|
92
103
|
/**
|
|
93
104
|
* Group name for organising this collection in the admin sidebar navigation.
|
|
94
105
|
*
|
|
@@ -0,0 +1,112 @@
|
|
|
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
|
+
* Server-only lifecycle hooks for the `docs` collection.
|
|
11
|
+
*
|
|
12
|
+
* ──────────────────────────────────────────────────────────────────────────
|
|
13
|
+
* Why this file exists (the affordance)
|
|
14
|
+
* ──────────────────────────────────────────────────────────────────────────
|
|
15
|
+
* A collection *schema* (`./schema.ts`) is **isomorphic** — Byline bundles it
|
|
16
|
+
* into the browser admin as well as the server, because the admin reads field
|
|
17
|
+
* config from it. Anything the schema *statically imports* therefore ships to
|
|
18
|
+
* the client. Hook *bodies*, however, only ever run server-side.
|
|
19
|
+
*
|
|
20
|
+
* Search indexing is the canonical reason this matters: it imports
|
|
21
|
+
* `getSystemBylineClient` from `@byline/host-tanstack-start`, a server-only
|
|
22
|
+
* module. Importing that from the schema would drag server code into the
|
|
23
|
+
* browser bundle (fatal in dev). The schema avoids it by referencing these
|
|
24
|
+
* hooks through a **dynamic import** instead of an inline object:
|
|
25
|
+
*
|
|
26
|
+
* // schema.ts
|
|
27
|
+
* hooks: () => import('./hooks.js')
|
|
28
|
+
*
|
|
29
|
+
* Because the schema reaches this module only through `import()`, this file —
|
|
30
|
+
* and its entire transitive import graph — is **structurally absent** from
|
|
31
|
+
* the client bundle. `@byline/core` resolves the loader once on the server
|
|
32
|
+
* (memoized) and calls these hooks exactly as it would inline ones. The
|
|
33
|
+
* upshot: **inside this file we may statically import server-only modules
|
|
34
|
+
* directly.** See docs/04-collections → "Hooks must not statically import
|
|
35
|
+
* server-only code".
|
|
36
|
+
*
|
|
37
|
+
* ──────────────────────────────────────────────────────────────────────────
|
|
38
|
+
* Search indexing
|
|
39
|
+
* ──────────────────────────────────────────────────────────────────────────
|
|
40
|
+
* Indexing rides the same lifecycle hooks. The orchestration lives in
|
|
41
|
+
* `@byline/client`: `indexDocument` re-reads the *published* view per locale
|
|
42
|
+
* and upserts / removes (so publish, unpublish, draft-over-published, and
|
|
43
|
+
* plain edits all converge on the same idempotent path); `removeFromIndex`
|
|
44
|
+
* drops every locale on delete.
|
|
45
|
+
*
|
|
46
|
+
* Resolve the client with `getSystemBylineClient()` (super-admin context, no
|
|
47
|
+
* session cookies) — NOT the request-scoped `getAdminBylineClient()`.
|
|
48
|
+
* Indexing is background maintenance that runs from out-of-band write paths
|
|
49
|
+
* too (the import-docs script, seeds, migrations), where there is no HTTP
|
|
50
|
+
* request to read a session cookie from. See
|
|
51
|
+
* docs/05-reading-and-delivery/07-search.md.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
import { defineHooks } from '@byline/core'
|
|
55
|
+
import { getSystemBylineClient } from '@byline/host-tanstack-start/integrations/byline-client'
|
|
56
|
+
|
|
57
|
+
export default defineHooks({
|
|
58
|
+
beforeCreate: async ({ data, collectionPath }) => {
|
|
59
|
+
console.log(`beforeCreate: creating a document in '${collectionPath}'`, data)
|
|
60
|
+
},
|
|
61
|
+
afterCreate: async ({ collectionPath, documentId, documentVersionId }) => {
|
|
62
|
+
console.log(
|
|
63
|
+
`afterCreate: document ${documentId} (version ${documentVersionId}) created in '${collectionPath}'`
|
|
64
|
+
)
|
|
65
|
+
await getSystemBylineClient().collection(collectionPath).indexDocument(documentId)
|
|
66
|
+
},
|
|
67
|
+
beforeUpdate: async ({ data, collectionPath }) => {
|
|
68
|
+
console.log(`beforeUpdate: updating a document in '${collectionPath}'`, data)
|
|
69
|
+
},
|
|
70
|
+
afterUpdate: async ({ collectionPath, documentId, documentVersionId }) => {
|
|
71
|
+
console.log(
|
|
72
|
+
`afterUpdate: document ${documentId} (version ${documentVersionId}) in '${collectionPath}' updated`
|
|
73
|
+
)
|
|
74
|
+
await getSystemBylineClient().collection(collectionPath).indexDocument(documentId)
|
|
75
|
+
},
|
|
76
|
+
beforeStatusChange: async ({ documentId, collectionPath, previousStatus, nextStatus }) => {
|
|
77
|
+
console.log(
|
|
78
|
+
`beforeStatusChange: ${documentId} in '${collectionPath}' ${previousStatus} → ${nextStatus}`
|
|
79
|
+
)
|
|
80
|
+
},
|
|
81
|
+
// Publish / unpublish flow through the status lifecycle (not afterUpdate),
|
|
82
|
+
// so re-index here too — this is when content becomes visible / invisible
|
|
83
|
+
// to anonymous traffic.
|
|
84
|
+
afterStatusChange: async ({ documentId, collectionPath, previousStatus, nextStatus }) => {
|
|
85
|
+
console.log(
|
|
86
|
+
`afterStatusChange: ${documentId} in '${collectionPath}' ${previousStatus} → ${nextStatus}`
|
|
87
|
+
)
|
|
88
|
+
await getSystemBylineClient().collection(collectionPath).indexDocument(documentId)
|
|
89
|
+
},
|
|
90
|
+
beforeUnpublish: async ({ documentId, collectionPath }) => {
|
|
91
|
+
console.log(`beforeUnpublish: unpublishing ${documentId} in '${collectionPath}'`)
|
|
92
|
+
},
|
|
93
|
+
afterUnpublish: async ({ documentId, collectionPath }) => {
|
|
94
|
+
console.log(`afterUnpublish: ${documentId} in '${collectionPath}' unpublished`)
|
|
95
|
+
await getSystemBylineClient().collection(collectionPath).indexDocument(documentId)
|
|
96
|
+
},
|
|
97
|
+
beforeDelete: async ({ documentId, collectionPath }) => {
|
|
98
|
+
console.log(`beforeDelete: deleting ${documentId} in '${collectionPath}'`)
|
|
99
|
+
},
|
|
100
|
+
afterDelete: async ({ documentId, collectionPath }) => {
|
|
101
|
+
console.log(`afterDelete: ${documentId} in '${collectionPath}' deleted`)
|
|
102
|
+
await getSystemBylineClient().collection(collectionPath).removeFromIndex(documentId)
|
|
103
|
+
},
|
|
104
|
+
// Fires on any structural tree change (place / reorder / re-parent /
|
|
105
|
+
// promote-on-delete) for a `tree: true` collection. The payload carries the
|
|
106
|
+
// affected set; a docs site typically invalidates its nav / breadcrumb /
|
|
107
|
+
// prev-next caches here. A tree move doesn't change a document's indexable
|
|
108
|
+
// text, so there's nothing to re-index.
|
|
109
|
+
afterTreeChange: async ({ collectionPath }) => {
|
|
110
|
+
console.log(`afterTreeChange: tree structure changed in '${collectionPath}'`)
|
|
111
|
+
},
|
|
112
|
+
})
|
|
@@ -41,90 +41,29 @@ export const Docs = defineCollection({
|
|
|
41
41
|
// placement from the source directory layout (see
|
|
42
42
|
// byline/scripts/import-docs.ts --tree).
|
|
43
43
|
tree: true,
|
|
44
|
-
|
|
44
|
+
// Collection search config (docs/05-reading-and-delivery/07-search.md).
|
|
45
|
+
// Each key names the part a field plays in the index: `body` fields feed
|
|
46
|
+
// the full-text search vector (`title` is display-only unless listed here,
|
|
47
|
+
// so we include it and boost it into the heaviest weight class); `facets`,
|
|
48
|
+
// `filters`, and `zones` round out the surface. Opting in here is what
|
|
49
|
+
// makes the lifecycle hooks in ./hooks.ts index this collection — and it
|
|
50
|
+
// requires a `search` provider registered in byline/server.config.ts.
|
|
51
|
+
search: { body: [{ field: 'title', boost: 2 }, 'summary'] },
|
|
45
52
|
useAsTitle: 'title',
|
|
46
53
|
useAsPath: 'title',
|
|
47
54
|
advertiseLocales: true, // Renders the available-locales sidebar widget.
|
|
48
55
|
linksInEditor: true, // See type definition for details.
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// Example: log the creation of a new document.
|
|
61
|
-
console.log(
|
|
62
|
-
`afterCreate: Document created with ID ${documentId} and version ID ${documentVersionId} in collection ${collectionPath}`
|
|
63
|
-
)
|
|
64
|
-
},
|
|
65
|
-
beforeUpdate: async ({ data, originalData, collectionPath }) => {
|
|
66
|
-
// Example: prevent a document from being published if it doesn't have a title.
|
|
67
|
-
console.log(
|
|
68
|
-
`beforeUpdate: Updating a document in collection ${collectionPath} with data:`,
|
|
69
|
-
data
|
|
70
|
-
)
|
|
71
|
-
},
|
|
72
|
-
afterUpdate: async ({ data, originalData, collectionPath, documentId, documentVersionId }) => {
|
|
73
|
-
// Example: log the update of a document.
|
|
74
|
-
console.log(
|
|
75
|
-
`afterUpdate: Document with ID ${documentId} and version ID ${documentVersionId} in collection ${collectionPath} was updated`
|
|
76
|
-
)
|
|
77
|
-
},
|
|
78
|
-
beforeStatusChange: async ({
|
|
79
|
-
documentId,
|
|
80
|
-
documentVersionId,
|
|
81
|
-
collectionPath,
|
|
82
|
-
previousStatus,
|
|
83
|
-
nextStatus,
|
|
84
|
-
}) => {
|
|
85
|
-
console.log(
|
|
86
|
-
`beforeStatusChange: Changing status of document in collection ${collectionPath} from ${previousStatus} to ${nextStatus} with document ID ${documentId} and version ID ${documentVersionId}`
|
|
87
|
-
)
|
|
88
|
-
},
|
|
89
|
-
afterStatusChange: async ({
|
|
90
|
-
documentId,
|
|
91
|
-
documentVersionId,
|
|
92
|
-
collectionPath,
|
|
93
|
-
previousStatus,
|
|
94
|
-
nextStatus,
|
|
95
|
-
}) => {
|
|
96
|
-
console.log(
|
|
97
|
-
`afterStatusChange: Status of document in collection ${collectionPath} changed from ${previousStatus} to ${nextStatus} with document ID ${documentId} and version ID ${documentVersionId}`
|
|
98
|
-
)
|
|
99
|
-
},
|
|
100
|
-
beforeUnpublish: async ({ documentId, collectionPath }) => {
|
|
101
|
-
console.log(
|
|
102
|
-
`beforeUnpublish: Unpublishing document in collection ${collectionPath} with document ID ${documentId}.`
|
|
103
|
-
)
|
|
104
|
-
},
|
|
105
|
-
afterUnpublish: async ({ documentId, collectionPath }) => {
|
|
106
|
-
console.log(
|
|
107
|
-
`afterUnpublish: Document in collection ${collectionPath} with document ID ${documentId} unpublished.`
|
|
108
|
-
)
|
|
109
|
-
},
|
|
110
|
-
beforeDelete: async ({ documentId, collectionPath }) => {
|
|
111
|
-
console.log(
|
|
112
|
-
`beforeDelete: Deleting document in collection ${collectionPath} with document ID ${documentId}.`
|
|
113
|
-
)
|
|
114
|
-
},
|
|
115
|
-
afterDelete: async ({ documentId, collectionPath }) => {
|
|
116
|
-
console.log(
|
|
117
|
-
`afterDelete: Document in collection ${collectionPath} with document ID ${documentId} deleted.`
|
|
118
|
-
)
|
|
119
|
-
},
|
|
120
|
-
// Fires on any structural tree change (place / reorder / re-parent /
|
|
121
|
-
// promote-on-delete) for a `tree: true` collection. The payload carries the
|
|
122
|
-
// affected set; a docs site typically invalidates its nav / breadcrumb /
|
|
123
|
-
// prev-next caches here.
|
|
124
|
-
afterTreeChange: async ({ collectionPath }) => {
|
|
125
|
-
console.log(`afterTreeChange: tree structure changed in collection ${collectionPath}.`)
|
|
126
|
-
},
|
|
127
|
-
},
|
|
56
|
+
// Collection lifecycle hooks. Hook *bodies* only ever run server-side, but
|
|
57
|
+
// a collection *schema* is isomorphic — Byline bundles it into the browser
|
|
58
|
+
// admin too (the admin reads field config from it), so anything the schema
|
|
59
|
+
// *statically imports* ships to the client. Search indexing needs a
|
|
60
|
+
// server-only import (`getSystemBylineClient` from
|
|
61
|
+
// `@byline/host-tanstack-start`), which would crash the browser bundle if
|
|
62
|
+
// imported here. The **loader form** — a thunk that dynamically imports a
|
|
63
|
+
// sibling module — keeps `./hooks.ts` and its entire import graph out of
|
|
64
|
+
// the client bundle while running exactly like inline hooks on the server.
|
|
65
|
+
// See ./hooks.ts for the worked example and the full explanation.
|
|
66
|
+
hooks: () => import('./hooks.js'),
|
|
128
67
|
fields: [
|
|
129
68
|
{
|
|
130
69
|
name: 'title',
|
|
@@ -97,9 +97,9 @@ export const MediaAdmin: CollectionAdminConfig = defineAdmin(Media, {
|
|
|
97
97
|
* picker modal (opened from a `relation` field widget). Omit to fall back to a
|
|
98
98
|
* single-line render of `useAsTitle` + `path`.
|
|
99
99
|
*
|
|
100
|
-
* Shape matches `ColumnDefinition` so formatters can be reused across list and
|
|
100
|
+
* Shape matches `ColumnDefinition` so formatters can be reused across list and item view.
|
|
101
101
|
*/
|
|
102
|
-
|
|
102
|
+
itemView: pickerViewColumns,
|
|
103
103
|
|
|
104
104
|
/**
|
|
105
105
|
* Custom list-view component that completely replaces the default table-based `ListView`
|
|
@@ -81,12 +81,12 @@ export const NewsAdmin: CollectionAdminConfig = defineAdmin(News, {
|
|
|
81
81
|
* picker modal (opened from a `relation` field widget). Omit to fall back to a
|
|
82
82
|
* single-line render of `useAsTitle` + `path`.
|
|
83
83
|
*
|
|
84
|
-
* Shape matches `ColumnDefinition` so formatters can be reused across list and
|
|
84
|
+
* Shape matches `ColumnDefinition` so formatters can be reused across list and item view.
|
|
85
85
|
*
|
|
86
86
|
* @example
|
|
87
|
-
*
|
|
87
|
+
* itemView: [{ fieldName: 'title', label: 'Title' }] // or defined above as `pickerViewColumns`
|
|
88
88
|
*/
|
|
89
|
-
//
|
|
89
|
+
// itemView: [],
|
|
90
90
|
|
|
91
91
|
/**
|
|
92
92
|
* Custom list-view component that completely replaces the default table-based `ListView`
|
|
@@ -78,12 +78,12 @@ export const PagesAdmin: CollectionAdminConfig = defineAdmin(Pages, {
|
|
|
78
78
|
* picker modal (opened from a `relation` field widget). Omit to fall back to a
|
|
79
79
|
* single-line render of `useAsTitle` + `path`.
|
|
80
80
|
*
|
|
81
|
-
* Shape matches `ColumnDefinition` so formatters can be reused across list and
|
|
81
|
+
* Shape matches `ColumnDefinition` so formatters can be reused across list and item view.
|
|
82
82
|
*
|
|
83
83
|
* @example
|
|
84
|
-
*
|
|
84
|
+
* itemView: [{ fieldName: 'title', label: 'Title' }] // or defined above as `pickerViewColumns`
|
|
85
85
|
*/
|
|
86
|
-
//
|
|
86
|
+
// itemView: [],
|
|
87
87
|
|
|
88
88
|
/**
|
|
89
89
|
* Custom list-view component that completely replaces the default table-based `ListView`
|
|
@@ -24,7 +24,9 @@ import {
|
|
|
24
24
|
lexicalEditorEmbedServer,
|
|
25
25
|
lexicalEditorPopulateServer,
|
|
26
26
|
lexicalEditorToMarkdownServer,
|
|
27
|
+
lexicalEditorToTextServer,
|
|
27
28
|
} from '@byline/richtext-lexical/server'
|
|
29
|
+
import { migrate, postgresSearch } from '@byline/search-postgres'
|
|
28
30
|
import { localStorageProvider } from '@byline/storage-local'
|
|
29
31
|
|
|
30
32
|
// Import collection definitions directly from schema files — NOT the full
|
|
@@ -103,6 +105,15 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
|
|
|
103
105
|
// : undefined,
|
|
104
106
|
})
|
|
105
107
|
|
|
108
|
+
// Ensure the search-index schema before the provider serves any traffic.
|
|
109
|
+
// `@byline/search-postgres` owns its schema (numbered SQL inside the
|
|
110
|
+
// package) and applies it via `migrate(pool)` — it is NOT part of the
|
|
111
|
+
// host's Drizzle migration stream. We run it deliberately here, rather
|
|
112
|
+
// than relying on the driver's `autoMigrate` option, so startup DDL is an
|
|
113
|
+
// explicit, awaited step. Reuses the adapter's pool — no second
|
|
114
|
+
// connection. See docs/05-reading-and-delivery/07-search.md.
|
|
115
|
+
await migrate(db.pool, { log: (m) => console.log(m) })
|
|
116
|
+
|
|
106
117
|
const adminStore = createAdminStore(db.drizzle)
|
|
107
118
|
|
|
108
119
|
// Built-in JWT session provider. Signing secret comes from the
|
|
@@ -211,8 +222,21 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
|
|
|
211
222
|
// surface (`.md` content routes, `llms.txt`). Pure JSON walk — no
|
|
212
223
|
// client needed. Remove if you don't expose the markdown surface.
|
|
213
224
|
toMarkdown: lexicalEditorToMarkdownServer(),
|
|
225
|
+
// Plain-text extractor for search indexing — flattens rich-text
|
|
226
|
+
// `body` fields to indexable text for `buildSearchDocument`. Pure
|
|
227
|
+
// JSON walk, no client. Required by any collection that lists a
|
|
228
|
+
// richText field in its `search.body`. See
|
|
229
|
+
// docs/05-reading-and-delivery/07-search.md.
|
|
230
|
+
toText: lexicalEditorToTextServer(),
|
|
214
231
|
},
|
|
215
232
|
},
|
|
233
|
+
// Built-in Postgres full-text search provider. Reuses the adapter's pool
|
|
234
|
+
// (no second connection); the search index lives in the same database.
|
|
235
|
+
// Collections opt in via their `search` config (see
|
|
236
|
+
// collections/docs/schema.ts) and keep the index live via lifecycle
|
|
237
|
+
// hooks (see collections/docs/hooks.ts). Remove this registration if no
|
|
238
|
+
// collection declares a `search` config.
|
|
239
|
+
search: postgresSearch({ pool: db.pool, defaultLocale: i18n.content.defaultLocale }),
|
|
216
240
|
})
|
|
217
241
|
|
|
218
242
|
// Register admin-subsystem abilities (admin.users.*, admin.roles.*) on
|
package/package.json
CHANGED
|
File without changes
|