@byline/cli 3.21.0 → 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.
Files changed (179) hide show
  1. package/README.md +29 -3
  2. package/dist/cli.js +5 -2
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/doctor.d.ts.map +1 -1
  5. package/dist/commands/doctor.js +1 -0
  6. package/dist/commands/doctor.js.map +1 -1
  7. package/dist/commands/init.d.ts +3 -0
  8. package/dist/commands/init.d.ts.map +1 -1
  9. package/dist/commands/init.js +10 -14
  10. package/dist/commands/init.js.map +1 -1
  11. package/dist/commands/setup-checks.d.ts +9 -0
  12. package/dist/commands/setup-checks.d.ts.map +1 -1
  13. package/dist/commands/setup-checks.js +43 -18
  14. package/dist/commands/setup-checks.js.map +1 -1
  15. package/dist/commands/setup.js +1 -1
  16. package/dist/commands/setup.js.map +1 -1
  17. package/dist/context.d.ts +2 -0
  18. package/dist/context.d.ts.map +1 -1
  19. package/dist/context.js +6 -0
  20. package/dist/context.js.map +1 -1
  21. package/dist/lib/dependency-version.d.ts +12 -0
  22. package/dist/lib/dependency-version.d.ts.map +1 -0
  23. package/dist/lib/dependency-version.js +101 -0
  24. package/dist/lib/dependency-version.js.map +1 -0
  25. package/dist/lib/planned-writes.d.ts +8 -0
  26. package/dist/lib/planned-writes.d.ts.map +1 -0
  27. package/dist/lib/planned-writes.js +177 -0
  28. package/dist/lib/planned-writes.js.map +1 -0
  29. package/dist/lib/planned-writes.test.d.ts +2 -0
  30. package/dist/lib/planned-writes.test.d.ts.map +1 -0
  31. package/dist/lib/planned-writes.test.js +113 -0
  32. package/dist/lib/planned-writes.test.js.map +1 -0
  33. package/dist/lib/release-policy.d.ts +12 -0
  34. package/dist/lib/release-policy.d.ts.map +1 -0
  35. package/dist/lib/release-policy.js +20 -0
  36. package/dist/lib/release-policy.js.map +1 -0
  37. package/dist/lib/release-policy.test.d.ts +2 -0
  38. package/dist/lib/release-policy.test.d.ts.map +1 -0
  39. package/dist/lib/release-policy.test.js +36 -0
  40. package/dist/lib/release-policy.test.js.map +1 -0
  41. package/dist/lib/route-config.d.ts +40 -0
  42. package/dist/lib/route-config.d.ts.map +1 -0
  43. package/dist/lib/route-config.js +322 -0
  44. package/dist/lib/route-config.js.map +1 -0
  45. package/dist/lib/static-config.d.ts +20 -0
  46. package/dist/lib/static-config.d.ts.map +1 -0
  47. package/dist/lib/static-config.js +444 -0
  48. package/dist/lib/static-config.js.map +1 -0
  49. package/dist/lib/static-config.test.d.ts +2 -0
  50. package/dist/lib/static-config.test.d.ts.map +1 -0
  51. package/dist/lib/static-config.test.js +105 -0
  52. package/dist/lib/static-config.test.js.map +1 -0
  53. package/dist/lib/template-hook-boundary.test.node.d.ts +2 -0
  54. package/dist/lib/template-hook-boundary.test.node.d.ts.map +1 -0
  55. package/dist/lib/template-hook-boundary.test.node.js +30 -0
  56. package/dist/lib/template-hook-boundary.test.node.js.map +1 -0
  57. package/dist/lib/template-path.d.ts +5 -0
  58. package/dist/lib/template-path.d.ts.map +1 -0
  59. package/dist/lib/template-path.js +9 -0
  60. package/dist/lib/template-path.js.map +1 -0
  61. package/dist/lib/workspace-root.d.ts +28 -0
  62. package/dist/lib/workspace-root.d.ts.map +1 -0
  63. package/dist/lib/workspace-root.js +205 -0
  64. package/dist/lib/workspace-root.js.map +1 -0
  65. package/dist/manifest/deps.d.ts +1 -1
  66. package/dist/manifest/deps.d.ts.map +1 -1
  67. package/dist/manifest/deps.js +18 -8
  68. package/dist/manifest/deps.js.map +1 -1
  69. package/dist/phases/deps.d.ts +14 -1
  70. package/dist/phases/deps.d.ts.map +1 -1
  71. package/dist/phases/deps.js +312 -137
  72. package/dist/phases/deps.js.map +1 -1
  73. package/dist/phases/deps.test.d.ts +2 -0
  74. package/dist/phases/deps.test.d.ts.map +1 -0
  75. package/dist/phases/deps.test.js +343 -0
  76. package/dist/phases/deps.test.js.map +1 -0
  77. package/dist/phases/preflight.d.ts.map +1 -1
  78. package/dist/phases/preflight.js +59 -11
  79. package/dist/phases/preflight.js.map +1 -1
  80. package/dist/phases/prompts.d.ts +2 -0
  81. package/dist/phases/prompts.d.ts.map +1 -1
  82. package/dist/phases/prompts.js +51 -2
  83. package/dist/phases/prompts.js.map +1 -1
  84. package/dist/phases/routes-ui.test.d.ts +2 -0
  85. package/dist/phases/routes-ui.test.d.ts.map +1 -0
  86. package/dist/phases/routes-ui.test.js +766 -0
  87. package/dist/phases/routes-ui.test.js.map +1 -0
  88. package/dist/phases/routes.d.ts +4 -1
  89. package/dist/phases/routes.d.ts.map +1 -1
  90. package/dist/phases/routes.js +610 -122
  91. package/dist/phases/routes.js.map +1 -1
  92. package/dist/phases/scaffold-smoke.test.d.ts +2 -0
  93. package/dist/phases/scaffold-smoke.test.d.ts.map +1 -0
  94. package/dist/phases/scaffold-smoke.test.js +168 -0
  95. package/dist/phases/scaffold-smoke.test.js.map +1 -0
  96. package/dist/phases/scaffold.d.ts +3 -2
  97. package/dist/phases/scaffold.d.ts.map +1 -1
  98. package/dist/phases/scaffold.js +268 -91
  99. package/dist/phases/scaffold.js.map +1 -1
  100. package/dist/phases/scaffold.test.js +171 -22
  101. package/dist/phases/scaffold.test.js.map +1 -1
  102. package/dist/phases/ui.d.ts +4 -1
  103. package/dist/phases/ui.d.ts.map +1 -1
  104. package/dist/phases/ui.js +51 -59
  105. package/dist/phases/ui.js.map +1 -1
  106. package/dist/phases/wire/index.d.ts.map +1 -1
  107. package/dist/phases/wire/index.js +10 -6
  108. package/dist/phases/wire/index.js.map +1 -1
  109. package/dist/phases/wire/shared.d.ts +4 -1
  110. package/dist/phases/wire/shared.d.ts.map +1 -1
  111. package/dist/phases/wire/vite-config.d.ts.map +1 -1
  112. package/dist/phases/wire/vite-config.js +69 -20
  113. package/dist/phases/wire/vite-config.js.map +1 -1
  114. package/dist/phases/wire/vite-config.test.d.ts +2 -0
  115. package/dist/phases/wire/vite-config.test.d.ts.map +1 -0
  116. package/dist/phases/wire/vite-config.test.js +97 -0
  117. package/dist/phases/wire/vite-config.test.js.map +1 -0
  118. package/dist/prompts.d.ts +1 -0
  119. package/dist/prompts.d.ts.map +1 -1
  120. package/dist/prompts.js +7 -2
  121. package/dist/prompts.js.map +1 -1
  122. package/dist/runner.js +1 -1
  123. package/dist/runner.js.map +1 -1
  124. package/dist/templates/byline/clients.server.ts +77 -0
  125. package/dist/templates/byline/collection-types.contract.ts +25 -0
  126. package/dist/templates/byline/collections/server-hooks.ts +7 -0
  127. package/dist/templates/byline/routes.ts +7 -6
  128. package/dist/templates/byline/server.config.ts +3 -1
  129. package/dist/templates/byline-examples/admin.config.ts +7 -12
  130. package/dist/templates/byline-examples/blocks/photo-block.ts +3 -2
  131. package/dist/templates/byline-examples/clients.server.ts +77 -0
  132. package/dist/templates/byline-examples/collection-types.contract.ts +25 -0
  133. package/dist/templates/byline-examples/collections/docs/hooks.ts +23 -13
  134. package/dist/templates/byline-examples/collections/docs/schema.ts +2 -11
  135. package/dist/templates/byline-examples/collections/media/components/media-list-view.tsx +11 -6
  136. package/dist/templates/byline-examples/collections/media/schema.ts +3 -0
  137. package/dist/templates/byline-examples/collections/news/schema.ts +4 -3
  138. package/dist/templates/byline-examples/collections/server-hooks.ts +8 -0
  139. package/dist/templates/byline-examples/fields/ai-text.ts +1 -1
  140. package/dist/templates/byline-examples/fields/ai-textarea.ts +1 -1
  141. package/dist/templates/byline-examples/fields/lexical-richtext-ai.tsx +3 -3
  142. package/dist/templates/byline-examples/routes.ts +7 -6
  143. package/dist/templates/byline-examples/scripts/backfill-version-locales.ts +1 -1
  144. package/dist/templates/byline-examples/scripts/import-docs.ts +11 -12
  145. package/dist/templates/byline-examples/scripts/lib/mdast-to-lexical.test.node.ts +93 -233
  146. package/dist/templates/byline-examples/scripts/lib/mdast-to-lexical.ts +2 -2
  147. package/dist/templates/byline-examples/scripts/lib/strip-leading-h1.test.node.ts +0 -4
  148. package/dist/templates/byline-examples/scripts/re-anchor.ts +3 -3
  149. package/dist/templates/byline-examples/scripts/regenerate-media.ts +6 -5
  150. package/dist/templates/byline-examples/server.config.ts +5 -4
  151. package/dist/templates/host/vite.config.ts +2 -0
  152. package/dist/templates/routes/_byline/route.lazy.tsx +1 -2
  153. package/dist/templates/routes/_byline/route.tsx +1 -1
  154. package/dist/templates/ui-byline/blocks/photo-block/index.tsx +18 -22
  155. package/dist/templates/ui-byline/components/admonition/index.tsx +11 -8
  156. package/dist/templates/ui-byline/components/code/code.tsx +6 -4
  157. package/dist/templates/ui-byline/components/link/lang-link.tsx +4 -8
  158. package/dist/templates/ui-byline/components/link/link-field.tsx +3 -2
  159. package/dist/templates/ui-byline/components/link/link-lexical.tsx +9 -8
  160. package/dist/templates/ui-byline/render-blocks.tsx +38 -34
  161. package/dist/templates/ui-byline/types/content.ts +25 -0
  162. package/dist/templates/ui-byline/types/i18n.ts +4 -8
  163. package/dist/test-helpers.d.ts +5 -0
  164. package/dist/test-helpers.d.ts.map +1 -0
  165. package/dist/test-helpers.js +52 -0
  166. package/dist/test-helpers.js.map +1 -0
  167. package/dist/types.d.ts +21 -1
  168. package/dist/types.d.ts.map +1 -1
  169. package/dist/ui-template-contract.test.d.ts +2 -0
  170. package/dist/ui-template-contract.test.d.ts.map +1 -0
  171. package/dist/ui-template-contract.test.js +130 -0
  172. package/dist/ui-template-contract.test.js.map +1 -0
  173. package/dist/workspace-root.test.d.ts +2 -0
  174. package/dist/workspace-root.test.d.ts.map +1 -0
  175. package/dist/workspace-root.test.js +307 -0
  176. package/dist/workspace-root.test.js.map +1 -0
  177. package/package.json +9 -1
  178. package/dist/templates/byline/client.server.ts +0 -32
  179. package/dist/templates/byline-examples/client.server.ts +0 -32
package/dist/runner.js CHANGED
@@ -57,7 +57,7 @@ function previewPlan(phase, plan, ctx) {
57
57
  ctx.logger.raw(` • ${note}`);
58
58
  for (const w of plan.writes) {
59
59
  const before = w.before ?? readIfExists(w.path);
60
- const label = before ? 'modify' : 'create';
60
+ const label = w.mode === 'delete' ? 'delete' : before ? 'modify' : 'create';
61
61
  ctx.logger.raw(` ${label} ${w.path}`);
62
62
  if (before !== w.contents) {
63
63
  ctx.logger.raw(renderDiff(w.path, before, w.contents));
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAIzC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,KAAY,EAAE,GAAY;IACvD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACxC,IAAI,QAAQ,KAAK,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAC/C,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,EAAE,qBAAqB,CAAC,CAAA;QACpD,OAAO,MAAM,CAAA;IACf,CAAC;IACD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,EAAE,4BAA4B,CAAC,CAAA;QACzD,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,EAAE,aAAa,CAAC,CAAA;IACzC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAElC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtF,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,EAAE,kBAAkB,CAAC,CAAA;QAC9C,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACrC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;QACjB,OAAO,MAAM,CAAA;IACf,CAAC;IAED,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAAA;IAE7B,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,EAAE,4BAA4B,CAAC,CAAA;QACxD,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACjD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,EAAE,oBAAoB,CAAC,CAAA;QAChD,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAC3C,IAAI,MAAM,CAAC,KAAK;QAAE,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK;YAAE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAElE,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;QAC5B,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACrC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,EAAE,SAAS,CAAC,CAAA;IAC1C,CAAC;SAAM,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACtC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,EAAE,8BAA8B,CAAC,CAAA;IAC5D,CAAC;SAAM,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACtC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,EAAE,YAAY,CAAC,CAAA;IAC3C,CAAC;IACD,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;IACjB,OAAO,MAAM,CAAC,KAAK,CAAA;AACrB,CAAC;AAED,SAAS,WAAW,CAAC,KAAY,EAAE,IAAU,EAAE,GAAY;IACzD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;IAClC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK;QAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAA;IAC9D,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAA;QAC1C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QACzC,IAAI,MAAM,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC1B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;QACxD,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAChE,CAAC;IACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACpB,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,KAAY,EAAE,GAAY;IACnD,sEAAsE;IACtE,kEAAkE;IAClE,oEAAoE;IACpE,sEAAsE;IACtE,qEAAqE;IACrE,IAAI,KAAK,CAAC,WAAW,KAAK,MAAM;QAAE,OAAO,IAAI,CAAA;IAC7C,IAAI,GAAG,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IAC1B,IAAI,GAAG,CAAC,GAAG;QAAE,OAAO,IAAI,CAAA;IACxB,OAAO,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC1B,OAAO,EAAE,SAAS,KAAK,CAAC,EAAE,WAAW;QACrC,YAAY,EAAE,IAAI;KACnB,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AAC3D,CAAC"}
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
@@ -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 }
@@ -1,3 +1,28 @@
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
+
1
26
  import type { CollectionFieldData, CollectionFieldDataAllLocales } from '@byline/core'
2
27
 
3
28
  import type { collections } from './collections/index.js'
@@ -0,0 +1,7 @@
1
+ /** Server-only lifecycle hook registry. Imported only by server.config.ts. */
2
+ import type { ServerHooksConfig } from '@byline/core'
3
+
4
+ export const serverHooks = {
5
+ collections: {},
6
+ uploads: {},
7
+ } satisfies ServerHooksConfig
@@ -7,17 +7,18 @@
7
7
  */
8
8
 
9
9
  /**
10
- * URL segments for admin and (future) public API routes. Defaults of
11
- * `/admin` and `/api` are applied automatically by `resolveRoutes()` —
12
- * keys only need to be set here when overriding either default.
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 type { RoutesConfig } from '@byline/core'
15
+ import { resolveRoutes } from '@byline/core'
16
16
 
17
- export const routes: Partial<RoutesConfig> = {
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
@@ -29,8 +29,9 @@ import {
29
29
  } from '@byline/richtext-lexical/server'
30
30
  import { localStorageProvider } from '@byline/storage-local'
31
31
 
32
- import { getAdminBylineClient } from './client.server.js'
32
+ import { getAdminBylineClient } from './clients.server.js'
33
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
 
@@ -91,6 +92,7 @@ async function buildBylineCore(): Promise<BylineCore<AdminStore>> {
91
92
  i18n,
92
93
  routes,
93
94
  collections,
95
+ hooks: serverHooks,
94
96
  db,
95
97
  adminStore,
96
98
  // Local filesystem — suitable for development and self-hosted
@@ -14,8 +14,8 @@
14
14
  * `route.lazy.tsx` covers component render and initial hydration. Keeping
15
15
  * both imports behind `_byline/*` keeps the admin graph off public routes.
16
16
  *
17
- * In TanStack Start with Vite 6 the server entry (`src/server.ts`) and
18
- * the SSR rendering context run in separate Vite environments, so
17
+ * In TanStack Start the server entry (`src/server.ts`) and the SSR rendering
18
+ * context run in separate Vite environments, so
19
19
  * importing this file from `src/server.ts` would NOT propagate the
20
20
  * registration into the SSR render module graph.
21
21
  */
@@ -29,8 +29,8 @@ import { RichTextField as LexicalRichTextField } from '@byline/richtext-lexical'
29
29
  // commented `richText` block below for the exact shape.
30
30
  // import { lexicalEditor } from '@byline/richtext-lexical'
31
31
 
32
- import { collections } from './collections/index.js'
33
32
  import { DocsAdmin } from './collections/docs/admin.js'
33
+ import { collections } from './collections/index.js'
34
34
  import { MediaAdmin } from './collections/media/admin.js'
35
35
  import { NewsAdmin } from './collections/news/admin.js'
36
36
  import { NewsCategoriesAdmin } from './collections/news-categories/admin.js'
@@ -60,19 +60,14 @@ export const config: ClientConfig = {
60
60
  // mutations are local to this call. Per-field `editorConfig`
61
61
  // continues to take precedence over whatever is baked in here.
62
62
  //
63
- // import {
64
- // lexicalEditor,
65
- // AdmonitionExtension,
66
- // CodeHighlightExtension,
67
- // TableExtension,
68
- // } from '@byline/richtext-lexical'
63
+ // import { builtInExtensions, lexicalEditor } from '@byline/richtext-lexical/config'
69
64
  //
70
65
  // richText: {
71
66
  // editor: lexicalEditor((c) => {
72
67
  // c.extensions
73
- // .remove(TableExtension)
74
- // .remove(CodeHighlightExtension)
75
- // .remove(AdmonitionExtension)
68
+ // .remove(builtInExtensions.Table)
69
+ // .remove(builtInExtensions.CodeHighlight)
70
+ // .remove(builtInExtensions.Admonition)
76
71
  // c.settings.placeholderText = 'Start writing...'
77
72
  // return c
78
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. Use this as the prop type for the photo
57
- * block renderer.
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 }
@@ -1,3 +1,28 @@
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
+
1
26
  import type { CollectionFieldData, CollectionFieldDataAllLocales } from '@byline/core'
2
27
 
3
28
  import type { collections } from './collections/index.js'
@@ -18,21 +18,19 @@
18
18
  * the client. Hook *bodies*, however, only ever run server-side.
19
19
  *
20
20
  * Search indexing is the canonical reason this matters: it imports the
21
- * server-only app client boundary from `byline/client.server.ts`. Importing
21
+ * server-only app client boundary from `byline/clients.server.ts`. Importing
22
22
  * that from the schema would drag server code into the browser bundle (fatal
23
- * in dev). The schema avoids it by referencing these hooks through a
24
- * **dynamic import** instead of an inline object:
23
+ * in dev). The server bootstrap avoids it by registering these hooks from a
24
+ * server-only module:
25
25
  *
26
- * // schema.ts
27
- * hooks: () => import('./hooks.js')
26
+ * // collections/server-hooks.ts
27
+ * collections: { docs: () => import('./docs/hooks.js') }
28
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".
29
+ * No client entry reaches that registry, so this file and its transitive graph
30
+ * are structurally absent from the client bundle without a host-framework
31
+ * transform. `@byline/core` attaches and resolves the loader on the server.
32
+ * The upshot: **inside this file we may statically import server-only modules
33
+ * directly.** See docs/04-collections → "Server-only hook registry".
36
34
  *
37
35
  * ──────────────────────────────────────────────────────────────────────────
38
36
  * Search indexing
@@ -52,7 +50,7 @@
52
50
  */
53
51
 
54
52
  import { defineHooks } from '@byline/core'
55
- import { getSystemBylineClient } from '../../client.server.js'
53
+ import { getSystemBylineClient } from '../../clients.server.js'
56
54
 
57
55
  export default defineHooks({
58
56
  beforeCreate: async ({ data, collectionPath }) => {
@@ -73,6 +71,18 @@ export default defineHooks({
73
71
  )
74
72
  await getSystemBylineClient().collection('docs').indexDocument(documentId)
75
73
  },
74
+ // Path and advertised-locale edits are immediate document-grain writes, not
75
+ // content updates. Re-index their published view through this dedicated event.
76
+ afterSystemFieldsChange: async ({ documentId, collectionPath, requested, changed }) => {
77
+ console.log(
78
+ `afterSystemFieldsChange: ${documentId} in '${collectionPath}' changed`,
79
+ changed
80
+ )
81
+ // Advertised locales affect alternates/sitemaps, not indexed content.
82
+ if (requested.path) {
83
+ await getSystemBylineClient().collection('docs').indexDocument(documentId)
84
+ }
85
+ },
76
86
  beforeStatusChange: async ({ documentId, collectionPath, previousStatus, nextStatus }) => {
77
87
  console.log(
78
88
  `beforeStatusChange: ${documentId} in '${collectionPath}' ${previousStatus} → ${nextStatus}`
@@ -65,17 +65,8 @@ export const Docs = defineCollection({
65
65
  useAsPath: 'title',
66
66
  advertiseLocales: true, // Renders the available-locales sidebar widget.
67
67
  linksInEditor: true, // See type definition for details.
68
- // Collection lifecycle hooks. Hook *bodies* only ever run server-side, but
69
- // a collection *schema* is isomorphic — Byline bundles it into the browser
70
- // admin too (the admin reads field config from it), so anything the schema
71
- // *statically imports* ships to the client. Search indexing needs a
72
- // server-only import from the app's `client.server.ts` boundary, which would
73
- // crash the browser bundle if imported here. The **loader form** — a thunk
74
- // that dynamically imports a sibling module — keeps `./hooks.ts` and its
75
- // entire import graph out of the client bundle while running exactly like
76
- // inline hooks on the server.
77
- // See ./hooks.ts for the worked example and the full explanation.
78
- hooks: () => import('./hooks.js'),
68
+ // Server-only lifecycle hooks are registered in ../server-hooks.ts so this
69
+ // schema remains portable across host frameworks and safe in client graphs.
79
70
  fields: [
80
71
  {
81
72
  name: 'title',
@@ -19,11 +19,16 @@
19
19
  * - Top + bottom pagination (RouterPager)
20
20
  */
21
21
 
22
- import { Link, useNavigate, useRouterState } from '@tanstack/react-router'
22
+ import { useRouterState } from '@tanstack/react-router'
23
23
 
24
24
  import type { ListViewComponentProps, StoredFileValue, WorkflowStatus } from '@byline/core'
25
25
  import type { AnyCollectionSchemaTypes } from '@byline/core/zod-schemas'
26
26
  import { RouterPager } from '@byline/host-tanstack-start/admin-shell/chrome/router-pager'
27
+ import {
28
+ Link,
29
+ useNavigate,
30
+ } from '@byline/host-tanstack-start/admin-shell/chrome/loose-router'
31
+ import { getAdminRoutePath } from '@byline/host-tanstack-start/routes/admin-path'
27
32
  import { Container, IconButton, LoaderRing, PlusIcon, Search, Section, Select } from '@byline/ui/react'
28
33
  import { LocalDateTime } from '@byline/admin/react'
29
34
 
@@ -128,7 +133,7 @@ export function MediaListView({
128
133
  delete params.page
129
134
  params.query = query
130
135
  navigate({
131
- to: '/admin/collections/$collection',
136
+ to: getAdminRoutePath('collections', '$collection'),
132
137
  params: { collection: collectionPath },
133
138
  search: params,
134
139
  })
@@ -140,7 +145,7 @@ export function MediaListView({
140
145
  delete params.page
141
146
  delete params.query
142
147
  navigate({
143
- to: '/admin/collections/$collection',
148
+ to: getAdminRoutePath('collections', '$collection'),
144
149
  params: { collection: collectionPath },
145
150
  search: params,
146
151
  })
@@ -158,7 +163,7 @@ export function MediaListView({
158
163
  params.order = order
159
164
  params.desc = desc
160
165
  navigate({
161
- to: '/admin/collections/$collection',
166
+ to: getAdminRoutePath('collections', '$collection'),
162
167
  params: { collection: collectionPath },
163
168
  search: params,
164
169
  })
@@ -178,7 +183,7 @@ export function MediaListView({
178
183
  render={
179
184
  <Link
180
185
  className={styles['create-link']}
181
- to="/admin/collections/$collection/create"
186
+ to={getAdminRoutePath('collections', '$collection', 'create')}
182
187
  params={{ collection: collectionPath }}
183
188
  />
184
189
  }
@@ -239,7 +244,7 @@ export function MediaListView({
239
244
  return (
240
245
  <Link
241
246
  key={doc.id}
242
- to="/admin/collections/$collection/$id"
247
+ to={getAdminRoutePath('collections', '$collection', '$id')}
243
248
  params={{ collection: collectionPath, id: doc.id }}
244
249
  className={styles.card}
245
250
  >
@@ -128,6 +128,9 @@ export const Media = defineCollection({
128
128
  quality: 55,
129
129
  },
130
130
  ],
131
+ // Worked example: definition-attached inline hooks are appropriate
132
+ // when their entire implementation is isomorphic-safe. Hooks that
133
+ // import server-only code belong in collections/server-hooks.ts.
131
134
  hooks: {
132
135
  beforeStore: (ctx: BeforeStoreContext) => {
133
136
  console.log('beforeStore hook called', ctx)
@@ -99,8 +99,9 @@ export const News = defineCollection({
99
99
  })
100
100
 
101
101
  /**
102
- * Field data shape inferred directly from the schema. Use this as the
103
- * generic to typed read calls — `client.collection('news').find<NewsFields>()`
104
- * — so dot-notation on `doc.fields` is fully checked.
102
+ * Schema-local field shape for hooks and other collection implementation details.
103
+ * Frontend/client code should import `NewsFields` from
104
+ * `byline/generated/collection-types.ts`; ordinary reads infer it from the
105
+ * client registry, while populate/select projections may supply an overlay.
105
106
  */
106
107
  export type NewsFields = CollectionFieldData<typeof News>
@@ -0,0 +1,8 @@
1
+ /** Server-only lifecycle hook registry. Imported only by server.config.ts. */
2
+ import type { ServerHooksConfig } from '@byline/core'
3
+
4
+ export const serverHooks = {
5
+ collections: {
6
+ docs: () => import('./docs/hooks.js'),
7
+ },
8
+ } satisfies ServerHooksConfig
@@ -27,7 +27,7 @@ import { AiFieldPanel } from './ai-widgets/ai-field-panel.js'
27
27
  *
28
28
  * @example
29
29
  * ```ts
30
- * // apps/webapp/byline/collections/news/admin.tsx
30
+ * // byline/collections/news/admin.tsx
31
31
  * fields: {
32
32
  * title: aiTextFieldAdmin(),
33
33
  * }
@@ -28,7 +28,7 @@ import { AiFieldPanel } from './ai-widgets/ai-field-panel.js'
28
28
  *
29
29
  * @example
30
30
  * ```ts
31
- * // apps/webapp/byline/collections/news/admin.tsx
31
+ * // byline/collections/news/admin.tsx
32
32
  * fields: {
33
33
  * summary: aiTextAreaFieldAdmin({
34
34
  * components: { HelpText: SummaryLength },
@@ -13,7 +13,7 @@
13
13
  * - `LexicalRichTextAi` — a `RichTextEditorComponent` that registers
14
14
  * the AI assistant by adding `AiLexicalExtension` to the editor's
15
15
  * extension graph. Register globally in
16
- * `apps/webapp/byline/admin.config.ts` under
16
+ * `byline/admin.config.ts` under
17
17
  * `fields.richText.editor` to AI-enable every richtext field.
18
18
  * - `aiRichTextAdmin()` — a `FieldAdminConfig` factory. Drop into a
19
19
  * collection's `fields` map in `<collection>/admin.tsx` to opt one
@@ -38,7 +38,7 @@ import { builtInExtensions, lexicalEditor } from '@byline/richtext-lexical/confi
38
38
  * drawer via `ReactExtension.decorators` — no `featureAfterEditor`, no
39
39
  * React-context registry hop.
40
40
  *
41
- * **Global** opt-in — register in `apps/webapp/byline/admin.config.ts`:
41
+ * **Global** opt-in — register in `byline/admin.config.ts`:
42
42
  *
43
43
  * ```ts
44
44
  * fields: {
@@ -77,7 +77,7 @@ export const LexicalRichTextAi = lexicalEditor((c) => {
77
77
  *
78
78
  * @example
79
79
  * ```ts
80
- * // apps/webapp/byline/collections/news/admin.tsx
80
+ * // byline/collections/news/admin.tsx
81
81
  * import { aiRichTextAdmin } from '../../fields/lexical-richtext-ai.js'
82
82
  *
83
83
  * fields: {
@@ -7,17 +7,18 @@
7
7
  */
8
8
 
9
9
  /**
10
- * URL segments for admin and (future) public API routes. Defaults of
11
- * `/admin` and `/api` are applied automatically by `resolveRoutes()` —
12
- * keys only need to be set here when overriding either default.
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 type { RoutesConfig } from '@byline/core'
15
+ import { resolveRoutes } from '@byline/core'
16
16
 
17
- export const routes: Partial<RoutesConfig> = {
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
@@ -16,7 +16,7 @@
16
16
  * Idempotent — safe to re-run. Uses the installation's configured default
17
17
  * content locale (resolved from byline/i18n.ts via the server config).
18
18
  *
19
- * cd apps/webapp && pnpm tsx byline/scripts/backfill-version-locales.ts
19
+ * pnpm tsx byline/scripts/backfill-version-locales.ts
20
20
  *
21
21
  * See docs/07-internationalization/index.md.
22
22
  */