@byline/cli 0.1.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 (251) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +23 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +72 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/doctor.d.ts +2 -0
  8. package/dist/commands/doctor.d.ts.map +1 -0
  9. package/dist/commands/doctor.js +36 -0
  10. package/dist/commands/doctor.js.map +1 -0
  11. package/dist/commands/init.d.ts +16 -0
  12. package/dist/commands/init.d.ts.map +1 -0
  13. package/dist/commands/init.js +76 -0
  14. package/dist/commands/init.js.map +1 -0
  15. package/dist/context.d.ts +38 -0
  16. package/dist/context.d.ts.map +1 -0
  17. package/dist/context.js +37 -0
  18. package/dist/context.js.map +1 -0
  19. package/dist/index.d.ts +5 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +4 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/lib/pg-url.d.ts +11 -0
  24. package/dist/lib/pg-url.d.ts.map +1 -0
  25. package/dist/lib/pg-url.js +22 -0
  26. package/dist/lib/pg-url.js.map +1 -0
  27. package/dist/manifest/deps.d.ts +29 -0
  28. package/dist/manifest/deps.d.ts.map +1 -0
  29. package/dist/manifest/deps.js +97 -0
  30. package/dist/manifest/deps.js.map +1 -0
  31. package/dist/manifest/env.d.ts +18 -0
  32. package/dist/manifest/env.d.ts.map +1 -0
  33. package/dist/manifest/env.js +38 -0
  34. package/dist/manifest/env.js.map +1 -0
  35. package/dist/phases/db-init.d.ts +3 -0
  36. package/dist/phases/db-init.d.ts.map +1 -0
  37. package/dist/phases/db-init.js +163 -0
  38. package/dist/phases/db-init.js.map +1 -0
  39. package/dist/phases/db.d.ts +11 -0
  40. package/dist/phases/db.d.ts.map +1 -0
  41. package/dist/phases/db.js +93 -0
  42. package/dist/phases/db.js.map +1 -0
  43. package/dist/phases/deps.d.ts +3 -0
  44. package/dist/phases/deps.d.ts.map +1 -0
  45. package/dist/phases/deps.js +115 -0
  46. package/dist/phases/deps.js.map +1 -0
  47. package/dist/phases/env.d.ts +3 -0
  48. package/dist/phases/env.d.ts.map +1 -0
  49. package/dist/phases/env.js +172 -0
  50. package/dist/phases/env.js.map +1 -0
  51. package/dist/phases/host.d.ts +3 -0
  52. package/dist/phases/host.d.ts.map +1 -0
  53. package/dist/phases/host.js +99 -0
  54. package/dist/phases/host.js.map +1 -0
  55. package/dist/phases/index.d.ts +7 -0
  56. package/dist/phases/index.d.ts.map +1 -0
  57. package/dist/phases/index.js +40 -0
  58. package/dist/phases/index.js.map +1 -0
  59. package/dist/phases/preflight.d.ts +4 -0
  60. package/dist/phases/preflight.d.ts.map +1 -0
  61. package/dist/phases/preflight.js +81 -0
  62. package/dist/phases/preflight.js.map +1 -0
  63. package/dist/phases/routes.d.ts +3 -0
  64. package/dist/phases/routes.d.ts.map +1 -0
  65. package/dist/phases/routes.js +145 -0
  66. package/dist/phases/routes.js.map +1 -0
  67. package/dist/phases/scaffold.d.ts +3 -0
  68. package/dist/phases/scaffold.d.ts.map +1 -0
  69. package/dist/phases/scaffold.js +113 -0
  70. package/dist/phases/scaffold.js.map +1 -0
  71. package/dist/phases/stub.d.ts +3 -0
  72. package/dist/phases/stub.d.ts.map +1 -0
  73. package/dist/phases/stub.js +25 -0
  74. package/dist/phases/stub.js.map +1 -0
  75. package/dist/phases/ui.d.ts +3 -0
  76. package/dist/phases/ui.d.ts.map +1 -0
  77. package/dist/phases/ui.js +93 -0
  78. package/dist/phases/ui.js.map +1 -0
  79. package/dist/phases/wire/index.d.ts +3 -0
  80. package/dist/phases/wire/index.d.ts.map +1 -0
  81. package/dist/phases/wire/index.js +67 -0
  82. package/dist/phases/wire/index.js.map +1 -0
  83. package/dist/phases/wire/root-tsx.d.ts +3 -0
  84. package/dist/phases/wire/root-tsx.d.ts.map +1 -0
  85. package/dist/phases/wire/root-tsx.js +57 -0
  86. package/dist/phases/wire/root-tsx.js.map +1 -0
  87. package/dist/phases/wire/server-ts.d.ts +3 -0
  88. package/dist/phases/wire/server-ts.d.ts.map +1 -0
  89. package/dist/phases/wire/server-ts.js +54 -0
  90. package/dist/phases/wire/server-ts.js.map +1 -0
  91. package/dist/phases/wire/shared.d.ts +34 -0
  92. package/dist/phases/wire/shared.d.ts.map +1 -0
  93. package/dist/phases/wire/shared.js +2 -0
  94. package/dist/phases/wire/shared.js.map +1 -0
  95. package/dist/phases/wire/start-ts.d.ts +3 -0
  96. package/dist/phases/wire/start-ts.d.ts.map +1 -0
  97. package/dist/phases/wire/start-ts.js +149 -0
  98. package/dist/phases/wire/start-ts.js.map +1 -0
  99. package/dist/phases/wire/tsconfig.d.ts +3 -0
  100. package/dist/phases/wire/tsconfig.d.ts.map +1 -0
  101. package/dist/phases/wire/tsconfig.js +105 -0
  102. package/dist/phases/wire/tsconfig.js.map +1 -0
  103. package/dist/phases/wire/vite-config.d.ts +3 -0
  104. package/dist/phases/wire/vite-config.d.ts.map +1 -0
  105. package/dist/phases/wire/vite-config.js +46 -0
  106. package/dist/phases/wire/vite-config.js.map +1 -0
  107. package/dist/prompts.d.ts +34 -0
  108. package/dist/prompts.d.ts.map +1 -0
  109. package/dist/prompts.js +49 -0
  110. package/dist/prompts.js.map +1 -0
  111. package/dist/runner.d.ts +5 -0
  112. package/dist/runner.d.ts.map +1 -0
  113. package/dist/runner.js +91 -0
  114. package/dist/runner.js.map +1 -0
  115. package/dist/state.d.ts +18 -0
  116. package/dist/state.d.ts.map +1 -0
  117. package/dist/state.js +68 -0
  118. package/dist/state.js.map +1 -0
  119. package/dist/templates/byline/admin.config.ts +41 -0
  120. package/dist/templates/byline/i18n.ts +47 -0
  121. package/dist/templates/byline/routes.ts +28 -0
  122. package/dist/templates/byline/seed.ts +19 -0
  123. package/dist/templates/byline/seeds/admin.ts +62 -0
  124. package/dist/templates/byline/server.config.ts +92 -0
  125. package/dist/templates/byline-examples/admin.config.ts +74 -0
  126. package/dist/templates/byline-examples/blocks/photo-block.ts +59 -0
  127. package/dist/templates/byline-examples/blocks/richtext-block.ts +35 -0
  128. package/dist/templates/byline-examples/collections/doc-example-flat-locale-all.ts +373 -0
  129. package/dist/templates/byline-examples/collections/doc-example-flat-locale-en.ts +283 -0
  130. package/dist/templates/byline-examples/collections/doc-example-tree-locale-all.ts +278 -0
  131. package/dist/templates/byline-examples/collections/doc-example-tree-locale-en.ts +205 -0
  132. package/dist/templates/byline-examples/collections/docs/admin.tsx +204 -0
  133. package/dist/templates/byline-examples/collections/docs/components/.gitkeep +0 -0
  134. package/dist/templates/byline-examples/collections/docs/components/feature-formatter.tsx +10 -0
  135. package/dist/templates/byline-examples/collections/docs/hooks/.gitkeep +0 -0
  136. package/dist/templates/byline-examples/collections/docs/index.ts +10 -0
  137. package/dist/templates/byline-examples/collections/docs/schema.ts +209 -0
  138. package/dist/templates/byline-examples/collections/docs-categories/admin.tsx +78 -0
  139. package/dist/templates/byline-examples/collections/docs-categories/components/.gitkeep +0 -0
  140. package/dist/templates/byline-examples/collections/docs-categories/hooks/.gitkeep +0 -0
  141. package/dist/templates/byline-examples/collections/docs-categories/index.ts +10 -0
  142. package/dist/templates/byline-examples/collections/docs-categories/schema.ts +33 -0
  143. package/dist/templates/byline-examples/collections/media/admin.tsx +188 -0
  144. package/dist/templates/byline-examples/collections/media/components/media-list-view.tsx +330 -0
  145. package/dist/templates/byline-examples/collections/media/components/media-thumbnail.tsx +63 -0
  146. package/dist/templates/byline-examples/collections/media/hooks/.gitkeep +0 -0
  147. package/dist/templates/byline-examples/collections/media/index.ts +10 -0
  148. package/dist/templates/byline-examples/collections/media/schema.ts +157 -0
  149. package/dist/templates/byline-examples/collections/news/admin.tsx +192 -0
  150. package/dist/templates/byline-examples/collections/news/components/.gitkeep +0 -0
  151. package/dist/templates/byline-examples/collections/news/hooks/.gitkeep +0 -0
  152. package/dist/templates/byline-examples/collections/news/index.ts +10 -0
  153. package/dist/templates/byline-examples/collections/news/schema.ts +91 -0
  154. package/dist/templates/byline-examples/collections/news-categories/admin.tsx +78 -0
  155. package/dist/templates/byline-examples/collections/news-categories/components/.gitkeep +0 -0
  156. package/dist/templates/byline-examples/collections/news-categories/hooks/.gitkeep +0 -0
  157. package/dist/templates/byline-examples/collections/news-categories/index.ts +10 -0
  158. package/dist/templates/byline-examples/collections/news-categories/schema.ts +33 -0
  159. package/dist/templates/byline-examples/collections/pages/admin.tsx +183 -0
  160. package/dist/templates/byline-examples/collections/pages/components/.gitkeep +0 -0
  161. package/dist/templates/byline-examples/collections/pages/hooks/.gitkeep +0 -0
  162. package/dist/templates/byline-examples/collections/pages/index.ts +10 -0
  163. package/dist/templates/byline-examples/collections/pages/schema.ts +96 -0
  164. package/dist/templates/byline-examples/components/length-indicator.tsx +138 -0
  165. package/dist/templates/byline-examples/components/pill.tsx +38 -0
  166. package/dist/templates/byline-examples/components/summary-length.tsx +39 -0
  167. package/dist/templates/byline-examples/fields/available-languages-field.ts +90 -0
  168. package/dist/templates/byline-examples/fields/lexical-richtext-compact.ts +88 -0
  169. package/dist/templates/byline-examples/i18n.ts +47 -0
  170. package/dist/templates/byline-examples/routes.ts +28 -0
  171. package/dist/templates/byline-examples/scripts/regenerate-media.ts +275 -0
  172. package/dist/templates/byline-examples/seed.ts +25 -0
  173. package/dist/templates/byline-examples/seeds/admin.ts +62 -0
  174. package/dist/templates/byline-examples/seeds/doc-categories.ts +71 -0
  175. package/dist/templates/byline-examples/seeds/docs.ts +293 -0
  176. package/dist/templates/byline-examples/seeds/news-categories.ts +71 -0
  177. package/dist/templates/byline-examples/server.config.ts +179 -0
  178. package/dist/templates/host/vite.config.ts +41 -0
  179. package/dist/templates/migrations/0000_condemned_kronos.sql +324 -0
  180. package/dist/templates/migrations/0001_sudden_phantom_reporter.sql +1 -0
  181. package/dist/templates/migrations/meta/0000_snapshot.json +2793 -0
  182. package/dist/templates/migrations/meta/0001_snapshot.json +2799 -0
  183. package/dist/templates/migrations/meta/_journal.json +20 -0
  184. package/dist/templates/routes/(byline)/admin/account/index.tsx +11 -0
  185. package/dist/templates/routes/(byline)/admin/collections/$collection/$id/api.tsx +16 -0
  186. package/dist/templates/routes/(byline)/admin/collections/$collection/$id/history.tsx +19 -0
  187. package/dist/templates/routes/(byline)/admin/collections/$collection/$id/index.tsx +16 -0
  188. package/dist/templates/routes/(byline)/admin/collections/$collection/create.tsx +11 -0
  189. package/dist/templates/routes/(byline)/admin/collections/$collection/index.tsx +11 -0
  190. package/dist/templates/routes/(byline)/admin/index.tsx +11 -0
  191. package/dist/templates/routes/(byline)/admin/permissions/index.tsx +11 -0
  192. package/dist/templates/routes/(byline)/admin/roles/$id/index.tsx +11 -0
  193. package/dist/templates/routes/(byline)/admin/roles/index.tsx +11 -0
  194. package/dist/templates/routes/(byline)/admin/route.tsx +11 -0
  195. package/dist/templates/routes/(byline)/admin/users/$id/index.tsx +11 -0
  196. package/dist/templates/routes/(byline)/admin/users/index.tsx +11 -0
  197. package/dist/templates/routes/(byline)/sign-in.tsx +11 -0
  198. package/dist/templates/ui-byline/blocks/photo-block/index.tsx +80 -0
  199. package/dist/templates/ui-byline/blocks/richtext-block/index.tsx +46 -0
  200. package/dist/templates/ui-byline/components/admonition/index.tsx +40 -0
  201. package/dist/templates/ui-byline/components/code/code-serializer.tsx +20 -0
  202. package/dist/templates/ui-byline/components/code/code.tsx +50 -0
  203. package/dist/templates/ui-byline/components/code/index.module.scss +137 -0
  204. package/dist/templates/ui-byline/components/code/index.ts +2 -0
  205. package/dist/templates/ui-byline/components/code/types.ts +5 -0
  206. package/dist/templates/ui-byline/components/code/utils.ts +20 -0
  207. package/dist/templates/ui-byline/components/heading-anchor/heading-anchor.tsx +69 -0
  208. package/dist/templates/ui-byline/components/heading-anchor/index.ts +1 -0
  209. package/dist/templates/ui-byline/components/heading-anchor/utils.ts +15 -0
  210. package/dist/templates/ui-byline/components/inline-image/index.tsx +109 -0
  211. package/dist/templates/ui-byline/components/layout/index.tsx +63 -0
  212. package/dist/templates/ui-byline/components/link/lang-link.tsx +70 -0
  213. package/dist/templates/ui-byline/components/link/link-field.tsx +298 -0
  214. package/dist/templates/ui-byline/components/link/link-lexical.tsx +191 -0
  215. package/dist/templates/ui-byline/components/list/index.ts +2 -0
  216. package/dist/templates/ui-byline/components/list/list-item.tsx +32 -0
  217. package/dist/templates/ui-byline/components/list/list.tsx +17 -0
  218. package/dist/templates/ui-byline/components/responsive-image/index.tsx +205 -0
  219. package/dist/templates/ui-byline/components/richtext-lexical/index.tsx +31 -0
  220. package/dist/templates/ui-byline/components/richtext-lexical/serialize/index.tsx +249 -0
  221. package/dist/templates/ui-byline/components/richtext-lexical/serialize/richtext-node-formats.ts +66 -0
  222. package/dist/templates/ui-byline/components/richtext-lexical/serialize/types.ts +48 -0
  223. package/dist/templates/ui-byline/components/richtext-lexical/serialize/utils.ts +15 -0
  224. package/dist/templates/ui-byline/components/table-cell/index.tsx +36 -0
  225. package/dist/templates/ui-byline/components/vimeo/index.tsx +21 -0
  226. package/dist/templates/ui-byline/components/youtube/index.tsx +22 -0
  227. package/dist/templates/ui-byline/render-blocks.tsx +71 -0
  228. package/dist/templates/ui-byline/types/i18n.ts +14 -0
  229. package/dist/templates/ui-byline/utils/image-sources.ts +102 -0
  230. package/dist/templates/ui-byline/utils/to-kebab-case.ts +5 -0
  231. package/dist/types.d.ts +54 -0
  232. package/dist/types.d.ts.map +1 -0
  233. package/dist/types.js +2 -0
  234. package/dist/types.js.map +1 -0
  235. package/dist/ui/diff.d.ts +4 -0
  236. package/dist/ui/diff.d.ts.map +1 -0
  237. package/dist/ui/diff.js +23 -0
  238. package/dist/ui/diff.js.map +1 -0
  239. package/dist/ui/grid.d.ts +7 -0
  240. package/dist/ui/grid.d.ts.map +1 -0
  241. package/dist/ui/grid.js +24 -0
  242. package/dist/ui/grid.js.map +1 -0
  243. package/dist/ui/logger.d.ts +14 -0
  244. package/dist/ui/logger.d.ts.map +1 -0
  245. package/dist/ui/logger.js +30 -0
  246. package/dist/ui/logger.js.map +1 -0
  247. package/dist/ui/snippet.d.ts +2 -0
  248. package/dist/ui/snippet.d.ts.map +1 -0
  249. package/dist/ui/snippet.js +7 -0
  250. package/dist/ui/snippet.js.map +1 -0
  251. package/package.json +69 -0
@@ -0,0 +1,293 @@
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 { getCollectionDefinition, getDefaultStatus, getServerConfig, slugify } from '@byline/core'
10
+
11
+ // Complex test document with many fields and arrays. The system `path`
12
+ // is supplied separately to `createDocumentVersion` as a top-level
13
+ // argument — it is no longer a user-defined field.
14
+ const sampleDocument = {
15
+ title: {
16
+ en: 'My First Document',
17
+ es: 'Mi Primer Documento',
18
+ },
19
+ summary: {
20
+ en: 'This is a sample document for testing purposes.',
21
+ es: 'Este es un documento de muestra para fines de prueba.',
22
+ },
23
+ // category: {
24
+ // targetCollectionId: "cat-123",
25
+ // targetDocumentId: "electronics-audio"
26
+ // },
27
+ featured: false,
28
+ publishedOn: new Date('2024-01-15T10:00:00'),
29
+ content: [
30
+ {
31
+ _type: 'richTextBlock',
32
+ richText: {
33
+ en: {
34
+ root: {
35
+ children: [
36
+ {
37
+ children: [
38
+ {
39
+ detail: 0,
40
+ format: 0,
41
+ mode: 'normal',
42
+ style: '',
43
+ text: 'Some richtext here...',
44
+ type: 'text',
45
+ version: 1,
46
+ },
47
+ ],
48
+ direction: 'ltr',
49
+ format: '',
50
+ indent: 0,
51
+ type: 'paragraph',
52
+ version: 1,
53
+ textFormat: 0,
54
+ textStyle: '',
55
+ },
56
+ ],
57
+ direction: 'ltr',
58
+ format: '',
59
+ indent: 0,
60
+ type: 'root',
61
+ version: 1,
62
+ },
63
+ },
64
+ es: {
65
+ root: {
66
+ children: [
67
+ {
68
+ children: [
69
+ {
70
+ detail: 0,
71
+ format: 0,
72
+ mode: 'normal',
73
+ style: '',
74
+ text: 'Aquí hay un campo de texto enriquecido...',
75
+ type: 'text',
76
+ version: 1,
77
+ },
78
+ ],
79
+ direction: 'ltr',
80
+ format: '',
81
+ indent: 0,
82
+ type: 'paragraph',
83
+ version: 1,
84
+ textFormat: 0,
85
+ textStyle: '',
86
+ },
87
+ ],
88
+ direction: 'ltr',
89
+ format: '',
90
+ indent: 0,
91
+ type: 'root',
92
+ version: 1,
93
+ },
94
+ },
95
+ },
96
+ constrainedWidth: true,
97
+ },
98
+ {
99
+ _type: 'photoBlock',
100
+ display: 'wide',
101
+ alt: 'Some alt text here',
102
+ caption: {
103
+ en: {
104
+ root: {
105
+ children: [
106
+ {
107
+ children: [
108
+ {
109
+ detail: 0,
110
+ format: 0,
111
+ mode: 'normal',
112
+ style: '',
113
+ text: 'Here is a richtext field Here is a richtext field Here is a richtext field Here is a rich text field.',
114
+ type: 'text',
115
+ version: 1,
116
+ },
117
+ ],
118
+ direction: 'ltr',
119
+ format: '',
120
+ indent: 0,
121
+ type: 'paragraph',
122
+ version: 1,
123
+ textFormat: 0,
124
+ textStyle: '',
125
+ },
126
+ ],
127
+ direction: 'ltr',
128
+ format: '',
129
+ indent: 0,
130
+ type: 'root',
131
+ version: 1,
132
+ },
133
+ },
134
+ es: {
135
+ root: {
136
+ children: [
137
+ {
138
+ children: [
139
+ {
140
+ detail: 0,
141
+ format: 0,
142
+ mode: 'normal',
143
+ style: '',
144
+ text: 'Aquí hay un campo de texto enriquecido. Aquí hay un campo de texto enriquecido. Aquí hay un campo de texto enriquecido. Aquí hay un campo de texto enriquecido.',
145
+ type: 'text',
146
+ version: 1,
147
+ },
148
+ ],
149
+ direction: 'ltr',
150
+ format: '',
151
+ indent: 0,
152
+ type: 'paragraph',
153
+ version: 1,
154
+ textFormat: 0,
155
+ textStyle: '',
156
+ },
157
+ ],
158
+ direction: 'ltr',
159
+ format: '',
160
+ indent: 0,
161
+ type: 'root',
162
+ version: 1,
163
+ },
164
+ },
165
+ },
166
+ },
167
+ ],
168
+ reviews: [
169
+ {
170
+ reviewItem: {
171
+ rating: 5,
172
+ comment: {
173
+ root: {
174
+ children: [
175
+ {
176
+ children: [
177
+ {
178
+ detail: 0,
179
+ format: 0,
180
+ mode: 'normal',
181
+ style: '',
182
+ text: 'Some review text here...',
183
+ type: 'text',
184
+ version: 1,
185
+ },
186
+ ],
187
+ direction: 'ltr',
188
+ format: '',
189
+ indent: 0,
190
+ type: 'paragraph',
191
+ version: 1,
192
+ textFormat: 0,
193
+ textStyle: '',
194
+ },
195
+ ],
196
+ direction: 'ltr',
197
+ format: '',
198
+ indent: 0,
199
+ type: 'root',
200
+ version: 1,
201
+ },
202
+ },
203
+ },
204
+ },
205
+ {
206
+ reviewItem: {
207
+ rating: 3,
208
+ comment: {
209
+ root: {
210
+ children: [
211
+ {
212
+ children: [
213
+ {
214
+ detail: 0,
215
+ format: 0,
216
+ mode: 'normal',
217
+ style: '',
218
+ text: 'Some review text here...',
219
+ type: 'text',
220
+ version: 1,
221
+ },
222
+ ],
223
+ direction: 'ltr',
224
+ format: '',
225
+ indent: 0,
226
+ type: 'paragraph',
227
+ version: 1,
228
+ textFormat: 0,
229
+ textStyle: '',
230
+ },
231
+ ],
232
+ direction: 'ltr',
233
+ format: '',
234
+ indent: 0,
235
+ type: 'root',
236
+ version: 1,
237
+ },
238
+ },
239
+ },
240
+ },
241
+ ],
242
+ links: [{ link: 'https://example.com' }, { link: 'https://another-example.com' }],
243
+ }
244
+
245
+ export async function seedDocs(count = 1000) {
246
+ const db = getServerConfig().db
247
+
248
+ const collectionDefinition = getCollectionDefinition('docs')
249
+
250
+ if (!collectionDefinition) {
251
+ console.error('Collection definition not found for "docs"')
252
+ return
253
+ }
254
+
255
+ // `initBylineCore` already registered the collection row via
256
+ // `ensureCollections()` when byline/server.config was imported, so we
257
+ // look the row up rather than re-inserting (which would violate the
258
+ // unique-path constraint).
259
+ const existing = await db.queries.collections.getCollectionByPath('docs')
260
+ if (!existing) {
261
+ throw new Error(
262
+ "seedDocuments: expected the 'docs' collection to be registered by initBylineCore()"
263
+ )
264
+ }
265
+
266
+ const bulkDocsCollection = {
267
+ id: existing.id as string,
268
+ name: existing.path as string,
269
+ version: (existing.version as number | undefined) ?? 1,
270
+ }
271
+
272
+ console.log(`Seeding into Docs collection (${bulkDocsCollection.name})`)
273
+
274
+ for (let i = 0; i < count; i++) {
275
+ const docData = structuredClone(sampleDocument)
276
+ docData.title.en = `A bulk created document. ${i + 1}` // Ensure unique names
277
+ const seedPath = slugify(docData.title.en, {
278
+ locale: 'en',
279
+ collectionPath: 'docs',
280
+ })
281
+ await db.commands.documents.createDocumentVersion({
282
+ collectionId: bulkDocsCollection.id,
283
+ collectionVersion: bulkDocsCollection.version,
284
+ collectionConfig: collectionDefinition,
285
+ action: 'create',
286
+ documentData: docData,
287
+ path: seedPath,
288
+ status: getDefaultStatus(collectionDefinition),
289
+ })
290
+ }
291
+
292
+ console.log(` - seeded ${count} docs`)
293
+ }
@@ -0,0 +1,71 @@
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 { getCollectionDefinition, getDefaultStatus, getServerConfig, slugify } from '@byline/core'
10
+
11
+ const categories = [
12
+ {
13
+ name: { en: 'Local' },
14
+ description: { en: 'Hyper-local news.' },
15
+ },
16
+ {
17
+ name: { en: 'Regional' },
18
+ description: { en: 'News and updates from the surrounding region.' },
19
+ },
20
+ {
21
+ name: { en: 'World' },
22
+ description: { en: 'International news and updates.' },
23
+ },
24
+ ]
25
+
26
+ export async function seedNewsCategories() {
27
+ const db = getServerConfig().db
28
+
29
+ const collectionDefinition = getCollectionDefinition('news-categories')
30
+
31
+ if (!collectionDefinition) {
32
+ console.error('Collection definition not found for "news-categories"')
33
+ return
34
+ }
35
+
36
+ // `initBylineCore` already registered the collection row via
37
+ // `ensureCollections()` when byline/server.config was imported, so we
38
+ // look the row up rather than re-inserting (which would violate the
39
+ // unique-path constraint).
40
+ const existing = await db.queries.collections.getCollectionByPath('news-categories')
41
+ if (!existing) {
42
+ throw new Error(
43
+ "seedNewsCategories: expected the 'news-categories' collection to be registered by initBylineCore()"
44
+ )
45
+ }
46
+
47
+ const categoriesCollection = {
48
+ id: existing.id as string,
49
+ name: existing.path as string,
50
+ version: (existing.version as number | undefined) ?? 1,
51
+ }
52
+
53
+ console.log(`Seeding into News Categories collection (${categoriesCollection.name})`)
54
+
55
+ for (const category of categories) {
56
+ const seedPath = slugify(category.name.en, {
57
+ locale: 'en',
58
+ collectionPath: 'news-categories',
59
+ })
60
+ await db.commands.documents.createDocumentVersion({
61
+ collectionId: categoriesCollection.id,
62
+ collectionVersion: categoriesCollection.version,
63
+ collectionConfig: collectionDefinition,
64
+ action: 'create',
65
+ documentData: category,
66
+ path: seedPath,
67
+ status: getDefaultStatus(collectionDefinition),
68
+ })
69
+ console.log(` - seeded category: ${category.name.en} (${seedPath})`)
70
+ }
71
+ }
@@ -0,0 +1,179 @@
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-side Byline bootstrap. Imported as a side-effect from
11
+ * `src/server.ts` (and from any seed / migration script that needs the
12
+ * configured runtime). Resolves the composed `BylineCore` and registers
13
+ * it on the process global via `initBylineCore()` — server-side callers
14
+ * read it back with `getBylineCore<AdminStore>()`.
15
+ */
16
+
17
+ import { type AdminStore, registerAdminAbilities } from '@byline/admin'
18
+ import { JwtSessionProvider } from '@byline/admin/auth'
19
+ import { type BylineCore, initBylineCore } from '@byline/core'
20
+ import { pgAdapter } from '@byline/db-postgres'
21
+ import { createAdminStore } from '@byline/db-postgres/admin'
22
+ import { getAdminBylineClient } from '@byline/host-tanstack-start/integrations/byline-client'
23
+ import { lexicalEditorServer } from '@byline/richtext-lexical/server'
24
+ import { localStorageProvider } from '@byline/storage-local'
25
+
26
+ // Import collection definitions directly from schema files — NOT the full
27
+ // admin config or index barrels. The admin config / index files pull in
28
+ // admin UI configs (React components, CSS modules) that are not loadable
29
+ // outside Vite (e.g. when running seeds via tsx).
30
+ import { Docs } from './collections/docs/schema.js'
31
+ import { DocsCategories } from './collections/docs-categories/schema.js'
32
+ import { Media } from './collections/media/schema.js'
33
+ import { News } from './collections/news/schema.js'
34
+ import { NewsCategories } from './collections/news-categories/schema.js'
35
+ import { Pages } from './collections/pages/schema.js'
36
+ import { i18n } from './i18n.js'
37
+ import { DEFAULT_SERVER_URL, routes } from './routes.js'
38
+
39
+ const serverURL = process.env.VITE_SERVER_URL || DEFAULT_SERVER_URL
40
+
41
+ const collections = [Docs, News, Pages, Media, DocsCategories, NewsCategories]
42
+
43
+ // HMR-safe singleton. Vite's program reload re-evaluates this module
44
+ // without disposing the previous module's resources — every reload
45
+ // would otherwise allocate a fresh pg `Pool` (max: 20) inside
46
+ // `pgAdapter`, the previous pool would orphan but stay alive, and
47
+ // after a handful of HMR cycles Postgres' `max_connections` is
48
+ // exhausted and every query fails with `53300 sorry, too many clients
49
+ // already`. Stashing the resolving `Promise` (so concurrent reloads
50
+ // converge on one build) lets module reloads reuse the same pool.
51
+ // Production has no HMR so this guard is a no-op there.
52
+ declare global {
53
+ // biome-ignore lint: globalThis augmentation requires `var` rather than `let`
54
+ var __bylineCoreSingleton__: Promise<BylineCore<AdminStore>> | undefined
55
+ }
56
+
57
+ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
58
+ // Construct the db adapter up-front so we can thread its drizzle handle
59
+ // into the session provider without a second connection pool. The admin
60
+ // store bundles the four admin repositories (users / roles / permissions
61
+ // / refresh tokens) that `JwtSessionProvider`, the admin-user server
62
+ // fns, and the super-admin seed all consume. Built once here and
63
+ // surfaced on `bylineCore.adminStore` so downstream callers talk to
64
+ // `AdminStore` — the interface — rather than casting the adapter.
65
+ //
66
+ // Future approaches, if/when the wiring grows:
67
+ //
68
+ // Option B — Adapter-owned admin store. Have `pgAdapter()` return
69
+ // `{ ..., adminStore }` directly so the integration point doesn't
70
+ // need the separate `createAdminStore(db.drizzle)` call or the
71
+ // `@byline/db-postgres/admin` import. Widens the adapter contract
72
+ // slightly but removes one more concrete-adapter mention from this
73
+ // file.
74
+ //
75
+ // Option C — Full DI via `@byline/core`'s `Registry`. Register
76
+ // `adminStore` as a typed factory keyed off `db`; adapters
77
+ // contribute the factory, `initBylineCore()` composes it. Most
78
+ // flexible (lazy construction, test wiring, multi-store setups) but
79
+ // heavier until we have a second adapter or a second DI consumer
80
+ // to justify the ceremony.
81
+ const db = pgAdapter({
82
+ connectionString: process.env.DB_CONNECTION_STRING || '',
83
+ collections,
84
+ })
85
+
86
+ const adminStore = createAdminStore(db.drizzle)
87
+
88
+ // Built-in JWT session provider. Signing secret comes from the
89
+ // environment — see `.env.example`. Phase 5 uses HS256 with Byline's
90
+ // default TTLs (15-minute access, 30-day refresh). Alternative providers
91
+ // (Lucia, better-auth, WorkOS, Clerk, institutional SSO) can be dropped
92
+ // in here by implementing the `SessionProvider` interface from
93
+ // `@byline/auth`.
94
+ const signingSecret = process.env.BYLINE_JWT_SECRET
95
+ if (!signingSecret || signingSecret.length < 32) {
96
+ throw new Error(
97
+ 'BYLINE_JWT_SECRET must be set and carry at least 32 bytes of entropy. ' +
98
+ 'Generate one with `openssl rand -base64 48` and add it to your .env.'
99
+ )
100
+ }
101
+
102
+ const sessionProvider = new JwtSessionProvider({
103
+ store: adminStore,
104
+ signingSecret,
105
+ })
106
+
107
+ const core = await initBylineCore<AdminStore>({
108
+ serverURL,
109
+ i18n,
110
+ routes,
111
+ collections,
112
+ db,
113
+ adminStore,
114
+ // Site-wide default storage provider — used by any upload collection
115
+ // that does not specify its own `upload.storage` override.
116
+ //
117
+ // To route a specific collection to a different backend, set `storage`
118
+ // inside that collection's `upload` config block instead of (or in
119
+ // addition to) this site-wide default.
120
+ //
121
+ // Local filesystem is suitable for development and self-hosted
122
+ // deployments. Swap for '@byline/storage-s3' (s3StorageProvider) for
123
+ // cloud/production. The `uploadDir` is served as a static path at
124
+ // `baseUrl` by your web server.
125
+ storage: localStorageProvider({
126
+ uploadDir: './public/uploads',
127
+ baseUrl: '/uploads',
128
+ }),
129
+ sessionProvider,
130
+ fields: {
131
+ // Server-side richtext adapter — refreshes embedded relation
132
+ // envelopes (link `{ title, path }`, inline-image `{ title, altText,
133
+ // image, sizes }`) on every read, gated per-field by
134
+ // `populateRelationsOnRead`. See docs/RICHTEXT.md for the full design.
135
+ //
136
+ // `getClient` returns a `BylineClient` — the SDK over the storage
137
+ // primitives that the populate visitors use to batch-fetch target
138
+ // documents (e.g. `client.collection('media').find({ where: { id:
139
+ // { $in: [...] } } })`). The client carries the DB adapter, the
140
+ // collection registry, the request-context resolver, and every
141
+ // read-pipeline phase (`beforeRead` → populate → `afterRead`), so
142
+ // populate's nested reads run under the *same* authenticated actor
143
+ // and the *same* `ReadContext` as the request that triggered them.
144
+ // That's what makes A→B→A cycle protection and visited-set dedup
145
+ // work across relation populate, richtext populate, and any user-
146
+ // land `afterRead` hooks.
147
+ //
148
+ // We pass `getAdminBylineClient` (not the public client) because
149
+ // admin server fns are the only call sites that read documents in
150
+ // the admin webapp today — the populate phase inherits whichever
151
+ // actor the request resolved. A future public-facing host would
152
+ // register its own client whose `requestContext` factory resolves
153
+ // an end-user actor instead. See `@byline/host-tanstack-start/
154
+ // integrations/byline-client.ts` for how the admin client is built.
155
+ //
156
+ // Why a getter, not a value: `getAdminBylineClient()` reads the
157
+ // server config singleton, which is only populated *after*
158
+ // `initBylineCore()` returns. Passing a factory defers resolution
159
+ // to populate-call time so registration order here doesn't matter.
160
+ richText: { populate: lexicalEditorServer({ getClient: getAdminBylineClient }) },
161
+ },
162
+ })
163
+
164
+ // Register admin-subsystem abilities (admin.users.*, admin.roles.*) on
165
+ // the shared registry. Collection abilities are auto-registered by
166
+ // `initBylineCore()`; admin abilities are opt-in here so `@byline/core`
167
+ // does not depend on `@byline/admin`.
168
+ registerAdminAbilities(core.abilities)
169
+
170
+ return core
171
+ }
172
+
173
+ // Cache the *Promise*, not the resolved value, so concurrent module
174
+ // loads during a reload race converge on a single build rather than
175
+ // each starting their own. The top-level `await` surfaces init errors
176
+ // at module load time; downstream callers retrieve the resolved core
177
+ // via `getBylineCore<AdminStore>()` from `@byline/core`.
178
+ globalThis.__bylineCoreSingleton__ ??= buildBylineCore()
179
+ await globalThis.__bylineCoreSingleton__
@@ -0,0 +1,41 @@
1
+ import { tanstackStart } from '@tanstack/react-start/plugin/vite'
2
+
3
+ import tailwindcss from '@tailwindcss/vite'
4
+ import react from '@vitejs/plugin-react'
5
+ import { defineConfig } from 'vite'
6
+
7
+ export default defineConfig({
8
+ server: {
9
+ port: 5173,
10
+ },
11
+ resolve: {
12
+ tsconfigPaths: true,
13
+ },
14
+ ssr: {
15
+ noExternal: ['@byline/ui'],
16
+ // Packages that load platform-specific native `.node` binaries at
17
+ // runtime via dynamic require(). Rollup cannot bundle these, so we
18
+ // keep them external and let Node.js resolve them from node_modules
19
+ // at runtime.
20
+ // - sharp + @byline/storage-local — image processing
21
+ // - @byline/db-postgres — adapter depends on pg native bindings
22
+ external: ['sharp', '@byline/storage-local', '@byline/admin', '@byline/db-postgres'],
23
+ },
24
+ // The same packages need to be kept out of Vite's client-side dep
25
+ // pre-bundling step. TanStack Start strips server-only imports from
26
+ // server-fn modules during its own compile pass, but Vite's
27
+ // `optimizeDeps` runs BEFORE that and tries to pre-bundle anything
28
+ // a client-reachable file imports — including transitive imports
29
+ // reached via `@byline/admin/admin-*` subpath barrels. Excluding the
30
+ // package roots here keeps Vite from touching them on the client side.
31
+ optimizeDeps: {
32
+ exclude: ['sharp', '@byline/storage-local', '@byline/admin', '@byline/db-postgres'],
33
+ },
34
+ plugins: [
35
+ tanstackStart(),
36
+ // NOTE: react() must come AFTER tanstackStart()
37
+ react(),
38
+ tailwindcss(),
39
+ ],
40
+ clearScreen: false,
41
+ })