@phtngyn/cms 0.2.0-beta.4 → 0.2.0-beta.6

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 (116) hide show
  1. package/README.md +31 -13
  2. package/package.json +7 -7
  3. package/src/ApplicationTypes.d.ts +3 -3
  4. package/src/Authoring.d.ts +11 -3
  5. package/src/{Configuration-BU-UyGoH.js → Configuration-JQ1qyaU0.js} +347 -189
  6. package/src/Configuration-JQ1qyaU0.js.map +1 -0
  7. package/src/Configuration.d.ts +1 -1
  8. package/src/Content.d.ts +7 -6
  9. package/src/Content.js +106 -47
  10. package/src/Content.js.map +1 -1
  11. package/src/ContentTransfer-BxwswWn3.js +86 -0
  12. package/src/ContentTransfer-BxwswWn3.js.map +1 -0
  13. package/src/{ContentTransfer-CRQet3QJ.d.ts → ContentTransfer-Z9FHyLez.d.ts} +33 -9
  14. package/src/{DocumentEngine-ClhFXW9M.js → DocumentEngine-j6Vi7nQo.js} +279 -178
  15. package/src/DocumentEngine-j6Vi7nQo.js.map +1 -0
  16. package/src/DocumentModel.d.ts +9 -2
  17. package/src/DocumentModel.js +17 -4
  18. package/src/DocumentModel.js.map +1 -1
  19. package/src/{Forms-DoB56hfe.js → Forms-CX-hwmJF.js} +18 -11
  20. package/src/Forms-CX-hwmJF.js.map +1 -0
  21. package/src/{Forms-BbkE7QfC.js → Forms-CfNPTiCr.js} +2 -2
  22. package/src/{Forms-BbkE7QfC.js.map → Forms-CfNPTiCr.js.map} +1 -1
  23. package/src/Media-j1bTritO.js +112 -0
  24. package/src/Media-j1bTritO.js.map +1 -0
  25. package/src/Module.js +0 -4
  26. package/src/Module.js.map +1 -1
  27. package/src/References-CCPDAPve.js +45 -0
  28. package/src/References-CCPDAPve.js.map +1 -0
  29. package/src/{S3MediaObjects-CR3p1WTg.js → S3MediaObjects-BRuPQbxl.js} +454 -516
  30. package/src/S3MediaObjects-BRuPQbxl.js.map +1 -0
  31. package/src/cli/content.js +6 -5
  32. package/src/cli/content.js.map +1 -1
  33. package/src/cli.js +16 -3
  34. package/src/cli.js.map +1 -1
  35. package/src/{connection-D5S9Iph-.js → connection-BP80q4d-.js} +2 -2
  36. package/src/{connection-D5S9Iph-.js.map → connection-BP80q4d-.js.map} +1 -1
  37. package/src/{dev-lifecycle-D3f9-upa.js → dev-lifecycle-CExksm2R.js} +27 -7
  38. package/src/dev-lifecycle-CExksm2R.js.map +1 -0
  39. package/src/{installation-fZtNxtoW.js → installation-BoG8E3nJ.js} +7982 -7155
  40. package/src/installation-BoG8E3nJ.js.map +1 -0
  41. package/src/internal/authoring-catalog.js +2 -2
  42. package/src/internal/authoring-compiler.js +35 -9
  43. package/src/internal/authoring-compiler.js.map +1 -1
  44. package/src/internal/authoring-metadata.js +14 -5
  45. package/src/internal/authoring-metadata.js.map +1 -1
  46. package/src/internal/configuration.js +27 -3
  47. package/src/internal/configuration.js.map +1 -1
  48. package/src/internal/dev-lifecycle.js +2 -2
  49. package/src/internal/document-model.js +134 -43
  50. package/src/internal/document-model.js.map +1 -1
  51. package/src/internal/field-metadata.js +2 -1
  52. package/src/internal/field-metadata.js.map +1 -1
  53. package/src/internal/form-capabilities.js +1 -1
  54. package/src/{location-CPX7oj0o.js → location-CMNGO3lU.js} +2 -2
  55. package/src/{location-CPX7oj0o.js.map → location-CMNGO3lU.js.map} +1 -1
  56. package/src/{metadata-BEZPWh-3.js → metadata-UzZmjwxM.js} +2 -2
  57. package/src/{metadata-BEZPWh-3.js.map → metadata-UzZmjwxM.js.map} +1 -1
  58. package/src/{models-C9kF9JlQ.js → models-5j67LMqW.js} +4 -4
  59. package/src/{models-C9kF9JlQ.js.map → models-5j67LMqW.js.map} +1 -1
  60. package/src/{models-ChRxBChy.js → models-VmGmG19-.js} +42 -130
  61. package/src/models-VmGmG19-.js.map +1 -0
  62. package/src/runtime/delivery/DocumentRenderer.js +5 -1
  63. package/src/runtime/delivery/DocumentRenderer.js.map +1 -1
  64. package/src/runtime/delivery/context.js +1 -1
  65. package/src/runtime/delivery/plugin.js +2 -2
  66. package/src/runtime/delivery/preview.d.ts +1 -1
  67. package/src/runtime/delivery/types.d.ts +1 -1
  68. package/src/runtime/delivery/useCmsDocumentSeo.d.ts +1 -1
  69. package/src/runtime/forms/document.js +2 -2
  70. package/src/runtime/forms/useCmsForm.js +2 -2
  71. package/src/runtime/installation.js +1 -1
  72. package/src/runtime/plugin.js +1 -1
  73. package/src/runtime/preview/CmsStudioPreviewMarker.js +18 -4
  74. package/src/runtime/preview/CmsStudioPreviewMarker.js.map +1 -1
  75. package/src/runtime/preview/connection.js +1 -1
  76. package/src/runtime/preview/controller.js +65 -74
  77. package/src/runtime/preview/controller.js.map +1 -1
  78. package/src/runtime/preview/overlay.js +85 -28
  79. package/src/runtime/preview/overlay.js.map +1 -1
  80. package/src/runtime/preview/plugin.client.js +4 -4
  81. package/src/runtime/preview/preview.css +50 -36
  82. package/src/runtime/preview/protocol.d.ts +11 -5
  83. package/src/runtime/preview/protocol.js +17 -5
  84. package/src/runtime/preview/protocol.js.map +1 -1
  85. package/src/runtime/preview/regions.js +142 -0
  86. package/src/runtime/preview/regions.js.map +1 -0
  87. package/src/runtime/preview/store.js +1 -1
  88. package/src/runtime/sitemap.js +9 -10
  89. package/src/runtime/sitemap.js.map +1 -1
  90. package/src/{scalars-B2lgGUnj.js → scalars-CVZqT3L0.js} +2 -6
  91. package/src/scalars-CVZqT3L0.js.map +1 -0
  92. package/src/{store-CCsjHaZm.js → store-PKKB8xa2.js} +49 -66
  93. package/src/store-PKKB8xa2.js.map +1 -0
  94. package/src/{types-DutFRtaG.d.ts → types-DZ0IV-Ow.d.ts} +14 -3
  95. package/studio/CreateDocumentDialog-DqvusuGU.js +335 -0
  96. package/studio/{documentPlanning-CDb31mnl.js → SelectMenu-BgikeouH.js} +16292 -12303
  97. package/studio/{editor-Bzlh3zXt.js → editor-P2rB7Csp.js} +11228 -11927
  98. package/studio/host.css +1 -1
  99. package/studio/host.js +28987 -34295
  100. package/studio/rolldown-runtime-Dy4uBu1J.js +11 -0
  101. package/src/Configuration-BU-UyGoH.js.map +0 -1
  102. package/src/ContentTransfer-BhF9G56s.js +0 -57
  103. package/src/ContentTransfer-BhF9G56s.js.map +0 -1
  104. package/src/DocumentEngine-ClhFXW9M.js.map +0 -1
  105. package/src/Forms-DoB56hfe.js.map +0 -1
  106. package/src/S3MediaObjects-CR3p1WTg.js.map +0 -1
  107. package/src/dev-lifecycle-D3f9-upa.js.map +0 -1
  108. package/src/installation-fZtNxtoW.js.map +0 -1
  109. package/src/models-ChRxBChy.js.map +0 -1
  110. package/src/runtime/preview/targets.js +0 -101
  111. package/src/runtime/preview/targets.js.map +0 -1
  112. package/src/scalars-B2lgGUnj.js.map +0 -1
  113. package/src/store-CCsjHaZm.js.map +0 -1
  114. package/studio/CreateDocumentDialog-DJ8c0WZb.js +0 -256
  115. package/studio/dom-to-image-more.min-D6jGGdrW.js +0 -877
  116. package/studio/rolldown-runtime-B0aSnxlc.js +0 -20
package/README.md CHANGED
@@ -39,7 +39,6 @@ export default defineCmsConfig({
39
39
  label: 'Page',
40
40
  route: '/:path*',
41
41
  schema: pageSchema,
42
- source: '.',
43
42
  },
44
43
  },
45
44
  },
@@ -80,6 +79,8 @@ Use the supported lifecycle before starting Nuxt:
80
79
 
81
80
  ```sh
82
81
  cms dev doctor
82
+ cms configuration check
83
+ cms --json configuration check > configuration-report.json
83
84
  CMS_EMAIL=admin@example.test CMS_PASSWORD=admin@example.test cms dev bootstrap --content ./content --publish
84
85
  cms dev reset --database --media
85
86
  cms dev reset --database --media --yes --bootstrap --content ./content --publish
@@ -91,6 +92,10 @@ All lifecycle commands accept `--root <directory>`, `--env-file <path>`, `--verb
91
92
 
92
93
  `reset` is a dry run unless `--yes` is present. It refuses to run while the configured CMS is live and can remove only the configured PostgreSQL schema and S3 prefix. Choose `--database`, `--media`, or both.
93
94
 
95
+ `configuration check` is the read-only local and CI gate for authored configuration changes. It compares `cms.config.ts` plus discovered blocks and forms with the installation's accepted serializable catalog, validates every authored and published Document, and emits the same underlying report used during startup. Human output names each required remediation; `--json` emits the versioned report without presentation text. Compatible reports exit successfully. Reports with affected Documents exit unsuccessfully, so CI can use the command directly.
96
+
97
+ Runtime startup records the first valid catalog and later compatible candidates. It never rewrites Documents to make a candidate fit. Field renames or removals, route or locale changes, unavailable blocks, narrower block permissions, and narrower form capabilities must be resolved through a separate explicit content change before startup can adopt the candidate.
98
+
94
99
  ## Content CLI
95
100
 
96
101
  The installed package provides a `cms` command for importing a plain Markdown folder, exporting Studio-authored Markdown, and moving content between running CMS installations. Create the first administrator in Studio, then sign in to the CLI with that administrator's email and password. The CLI prompts for the site URL, administrator email, and password when they are missing. For noninteractive use, set `CMS_URL`, `CMS_EMAIL`, and `CMS_PASSWORD`; `--url` and `--email` can replace the first two variables. Use HTTPS outside localhost.
@@ -104,11 +109,11 @@ CMS_URL=https://target.example.com CMS_EMAIL=admin@example.com cms content plan
104
109
  CMS_URL=https://target.example.com CMS_EMAIL=admin@example.com cms content apply ./seed --publish
105
110
  ```
106
111
 
107
- Export writes each authored source at its CMS path and a `.cms-content.json` index with content hashes and the exact-revision publication state. Commit both to Git to review changes. Export refuses to replace locally edited Markdown or index entries. It does not delete files that disappeared from the CMS; remove stale files and index entries yourself after review. `diff` compares local Markdown and publication state with the current target and reports target-only documents. `plan` validates the whole incoming set and lists creates, updates, publications, and conflicts without writing. `apply` plans again, then commits the batch atomically against the generation it just inspected. Run `plan` and `diff` before applying, especially when targeting another environment.
112
+ Export chooses deterministic filesystem paths and writes a version 2 `.cms-content.json` index containing each document's stable identity, revisioned placement, revision ID, publication state, and content hash. Filesystem paths are only an import/export concern; moving a document in Studio does not rename anything in core document state. Commit the Markdown and index together to review changes. Export preserves indexed paths when possible, refuses to replace locally edited Markdown or index entries, and does not delete files that disappeared from the CMS. Remove stale files and index entries yourself after review. `diff` compares local Markdown, placement, and publication state with the current target and reports target-only documents. `plan` validates the whole incoming set and lists creates, updates, publications, unpublications, and conflicts without writing. `apply` plans again, then commits the batch atomically against the generation it just inspected. Run `plan` and `diff` before applying, especially when targeting another environment.
108
113
 
109
114
  The export index and every indexed Markdown path must stay inside the selected content directory without symlinked path components. Import and export reject symlinks at those boundaries.
110
115
 
111
- For a folder without `.cms-content.json`, the CLI reads nested `.md` and `.mdc` files and uses folder-relative document paths. These sources are eligible for publication with `--publish`. Imports create drafts by default. Existing content with different Markdown is a conflict until you pass `--overwrite` to `plan` and `apply`. For an exported folder, `--publish` publishes only index entries marked `published: true`; without it, they remain drafts on the target. A newly imported draft does not unpublish an older target revision. The CLI does not delete target documents or move a target-only document. A concurrent change after planning causes `apply` to fail; review and retry.
116
+ For a folder without `.cms-content.json`, the CLI reads nested `.md` and `.mdc` files and infers an initial collection, locale, parent, and slug from folders. A collection or locale directory is optional when configuration makes it unambiguous; `index.md` represents the home document or the entry represented by its containing folder. This inference happens only on the first unindexed import. These sources are eligible for publication with `--publish`. Imports create drafts by default. Existing content with different Markdown is a conflict until you pass `--overwrite` to `plan` and `apply`. For an exported folder, `--publish` synchronizes the indexed publication state: entries marked `published: true` are published and entries marked `published: false` are unpublished. Without it, imported changes remain drafts and existing target publication stays unchanged. The CLI does not delete target documents or move a target-only document. A concurrent change after planning causes `apply` to fail; review and retry.
112
117
 
113
118
  The command tree is intentionally shared: future CMS operations can be added beside `content` without separate executables.
114
119
 
@@ -134,7 +139,7 @@ const document = await client.readDocument('8c62d2a7-b839-450a-bc08-5eccb420dc60
134
139
  await client.export({ directory: './content' })
135
140
  ```
136
141
 
137
- Plans expose creates, updates, publications, conflicts, issues, unchanged entries, and target-only sources. They are bound to their client, source, options, and generation; `apply(plan)` never replans. `readDocument(id)` returns the authored Markdown and exact publication state. `CmsContentError.code` provides stable authentication, not-found, conflict, validation, generation, filesystem, response, and network failure categories.
142
+ Plans expose creates, updates, publications, unpublications, conflicts, issues, unchanged entries, and target-only sources. They are bound to their client, source, options, and generation; `apply(plan)` never replans. `readDocument(id)` returns the authored Markdown and exact publication state. `CmsContentError.code` provides stable authentication, not-found, conflict, validation, generation, filesystem, response, and network failure categories.
138
143
 
139
144
  ## Search and sharing
140
145
 
@@ -205,24 +210,35 @@ const pageSchema = {
205
210
  }
206
211
  ```
207
212
 
208
- Supply actual draft 2020-12 schemas from the chosen library, using its input and output conversion modes respectively. Studio reads the input structure; the validator remains responsible for execution. A missing input converter produces a configuration error naming Standard JSON Schema V1. Foreign schemas use JSON Schema `title`, `description`, `default`, and `x-cms-input` for presentation.
213
+ Supply actual draft 2020-12 schemas from the chosen library, using its input and output conversion modes respectively. Studio reads the input structure; the validator remains responsible for execution. A missing input converter produces a configuration error naming Standard JSON Schema V1. Foreign schemas use JSON Schema `title`, `description`, `default`, `x-cms-input`, and `x-cms-options` for presentation.
209
214
 
210
215
  Effect schemas are also accepted directly. The CMS derives Studio inputs from their encoded structure and runs the original decoder, preserving defaults, transformations, and asynchronous validation. Decoders must not require external Effect services, and their output must be a JSON-compatible object.
211
216
 
212
217
  ```ts
213
218
  import { Schema } from 'effect'
214
- import { CalendarDate, field } from '@phtngyn/cms/DocumentModel'
219
+ import { CalendarDate, field, managedMediaReference } from '@phtngyn/cms/DocumentModel'
215
220
 
216
221
  const pageSchema = Schema.Struct({
217
222
  description: field(Schema.String, { default: '', input: 'textarea' }),
218
223
  publishedAt: Schema.optionalKey(field(CalendarDate, { label: 'Published on' })),
224
+ contributors: field(
225
+ Schema.Array(
226
+ Schema.Struct({
227
+ id: Schema.String,
228
+ name: Schema.NonEmptyString,
229
+ role: field(Schema.String, { default: 'Contributor' }),
230
+ }),
231
+ ),
232
+ { default: [], label: 'Contributors' },
233
+ ),
234
+ socialImage: Schema.optionalKey(managedMediaReference),
219
235
  title: Schema.NonEmptyString,
220
236
  })
221
237
  ```
222
238
 
223
- Use `Schema.optionalKey` for optional fields and `Schema.Finite` for numeric fields. A `field` default supplies Studio's initial value and applies only when the containing key is absent; invalid explicit values still fail. `CalendarDate` validates calendar dates stored as `YYYY-MM-DD` strings. Advanced Effect schemas, transformations, and defaults remain supported directly. `effect` is an intentional runtime dependency and is installed explicitly because authored schemas expose its public types.
239
+ Use `Schema.optionalKey` for optional fields, `Schema.NullOr` for explicit nulls, and `Schema.Finite` for numeric fields. A `field` default supplies Studio's initial value and applies only when the containing key is absent; invalid explicit values still fail. `field` can also give enum values distinct human labels through `options`. `CalendarDate` validates calendar dates stored as `YYYY-MM-DD` strings. Advanced Effect schemas, transformations, and defaults remain supported directly. `effect` is an intentional runtime dependency and is installed explicitly because authored schemas expose its public types.
224
240
 
225
- Studio supports strings, calendar dates, finite numbers, booleans, string arrays, choices, and nested objects. Non-recursive local references are resolved. Ambiguous unions, structural intersections, recursive schemas, and unsupported field shapes fail configuration rather than producing incomplete forms.
241
+ Studio supports strings, calendar dates, finite numbers, booleans, string arrays, choices, nested objects, repeatable objects, document references, and managed-media references. Repeatable object schemas must contain a required string `id`; Studio owns that identity and provides add, duplicate, remove, and reorder operations. `documentReference` and `managedMediaReference` store identity-backed source strings and project them to current routes or URLs for preview and delivery. Non-recursive local references are resolved. Ambiguous unions, structural intersections, recursive schemas, and unsupported field shapes fail configuration rather than producing incomplete forms.
226
242
 
227
243
  ## Start editing
228
244
 
@@ -245,7 +261,7 @@ Draft delivery requires the current Studio session and document access permissio
245
261
  - Import `defineCmsBlock` from `@phtngyn/cms/Authoring` to declare editable props and slots in your Nuxt Vue components.
246
262
  - Import Markdown folders with `cms content plan` and `cms content apply` after creating the first administrator.
247
263
 
248
- Nuxt generates `#cms/types` whenever configuration, collection schemas, or authored blocks change. It includes collection, form, block, locale, message-key, and interpolation-parameter types. Collection schema outputs flow through `useDocument<'pages'>()` and `useDocumentQuery()`, including typed filter and sort paths. Registered form names and configured capabilities narrow `CmsFormDefinition<'contact-form'>`.
264
+ Nuxt generates `#cms/types` whenever configuration, collection schemas, or authored blocks change. It includes collection, form, block, locale, message-key, and interpolation-parameter types. Collection schema outputs, including repeatable objects and references, flow through `useDocument<'pages'>()` and `useDocumentQuery()`. Filtering and sorting remain limited to typed scalar paths and scalar lists; repeatable-object predicates are intentionally excluded. Registered form names and configured capabilities narrow `CmsFormDefinition<'contact-form'>`.
249
265
 
250
266
  ```ts
251
267
  import type { CmsCollection, CmsFormDefinition, CmsLocale } from '#cms/types'
@@ -269,7 +285,9 @@ An open editor reads the new catalog without reseeding content or replacing its
269
285
 
270
286
  ## Component authoring and collection permissions
271
287
 
272
- Keep the Vue props, slots, defaults, and `defineCmsBlock` declaration together in the component's `<script setup lang="ts">`. Only declared fields and regions appear in Studio. Text regions accept plain text; rich-text regions offer only their declared `features`. Optional slots can be removed and added again. Initial content seeds new blocks; it never overwrites existing content when a declaration changes. Render optional slot wrappers conditionally to avoid empty layout space.
288
+ Keep the Vue props, slots, defaults, and `defineCmsBlock` declaration together in the component's `<script setup lang="ts">`. Only declared fields and regions appear in Studio. Text regions accept one plain paragraph. Inline-text regions keep that single-paragraph shape while offering their declared inline formatting `features`. Rich-text regions accept multiple paragraphs and offer only their declared inline and list `features`. Optional slots can be removed and added again. Initial content seeds new blocks; it never overwrites existing content when a declaration changes. Render optional slot wrappers conditionally to avoid empty layout space.
289
+
290
+ Render declared fields through ordinary Vue slot outlets. Studio follows each slot's rendered content through application components automatically: clicking a card title selects its title content, clicking its description selects the description, and clicking the remaining card surface selects the card block. Nuxt rejects an authored block when a declared slot has no matching outlet, so rendered fields cannot silently disappear from preview selection.
273
291
 
274
292
  A collection can restrict available component blocks:
275
293
 
@@ -291,7 +309,7 @@ Clearing an optional property removes its stored override, so a Vue default can
291
309
 
292
310
  ### Images, links, and composition
293
311
 
294
- String props can declare `input: 'image'` or `input: 'link'`. Studio uses the existing media library for image selection/upload and the document catalog for page links. Values remain ordinary URL strings: internal links store the selected document's public path. Image descriptions belong to a separate Vue prop; Studio does not invent an alt-text field or change your component's rendering. URL syntax and allowed schemes are checked before publication, and semantic props participate in the existing document/media reference index, including inside objects and lists. Changing a target's public path requires updating its links; references do not silently retarget by title.
312
+ String props can declare `input: 'image'` or `input: 'link'`. Studio uses the existing media library for image selection/upload and the document catalog for internal links. Internal selections are stored as `cms-document:<uuid>?route=<last-known-route>`: identity remains authoritative while the readable route provides a fallback when the target is unavailable. Studio resolves these references against authored documents and website delivery resolves them against published documents, so moving a target changes rendered links without rewriting Markdown. External links remain ordinary URLs. Image descriptions belong to a separate Vue prop; Studio does not invent an alt-text field or change your component's rendering. URL syntax and allowed schemes are checked before publication, and semantic props participate in the existing document/media reference index, including inside objects and lists.
295
313
 
296
314
  Slots with `input: 'blocks'` accept nested components. Optional `blocks` and `groups` selectors restrict direct children; omitting both permits all collection-allowed blocks. Collection permissions apply at every depth. Studio offers insertion, selection, deletion and sibling reordering inside each region. Existing content is retained when a schema change makes it invalid.
297
315
 
@@ -414,7 +432,7 @@ i18n: {
414
432
  },
415
433
  ```
416
434
 
417
- Locale codes also define the first directory of document source paths: `en/index.md` serves `/`, and `de/index.md` serves `/de`. Collection source matching starts after that directory. Markdown contains the editor-authored language already; it needs no translation key. Markdown and source paths remain stored in document revisions, with collaborative working edits checkpointed into Markdown. Import a Markdown folder with the admin CLI; subsequent changes require another plan and apply, with `--overwrite` for different Markdown.
435
+ Locale is part of stable document identity and route derivation. For an unindexed import, locale codes may be inferred from the first directory (`en/index.md`, `de/index.md`); the generated export index preserves the identity afterward. Markdown contains the editor-authored language already and needs no translation key. Revisions store identity, placement, and Markdown, while collaborative working edits checkpoint into Markdown. Import a Markdown folder with the admin CLI; subsequent changes require another plan and apply, with `--overwrite` for different Markdown.
418
436
 
419
437
  Use the auto-imported composable in website components:
420
438
 
@@ -429,7 +447,7 @@ t('footer.copyright', { year: 2026 })
429
447
 
430
448
  Message keys receive generated TypeScript completion. Dictionaries contain nested plain strings; dots are reserved for key paths. Named `{parameters}` accept strings and numbers; missing parameters remain visible. Messages fall back from the URL locale to `fallbackLocale`, then to the key. Omit `fallbackLocale` (or set it to `null`) to disable fallback. The same explicit fallback policy applies to document lookup. Development warns about missing requested-locale messages. Render messages as text, and use native `Intl` for date and number formatting.
431
449
 
432
- Only validated public i18n data enters the website bundle. Installation credentials and handlers stay server-side. Small dictionaries can stay inline; larger ones can be imported into the same config. Configuration changes restart Nuxt. Omitting `i18n` preserves unlocalized source paths; the composable returns an empty locale and untranslated keys.
450
+ Only validated public i18n data enters the website bundle. Installation credentials and handlers stay server-side. Small dictionaries can stay inline; larger ones can be imported into the same config. Configuration changes restart Nuxt. Omitting `i18n` creates unlocalized document identities; the composable returns an empty locale and untranslated keys.
433
451
 
434
452
  ## License
435
453
 
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "directory": "packages/nuxt"
18
18
  },
19
19
  "name": "@phtngyn/cms",
20
- "version": "0.2.0-beta.4",
20
+ "version": "0.2.0-beta.6",
21
21
  "type": "module",
22
22
  "files": [
23
23
  "bin",
@@ -62,11 +62,11 @@
62
62
  }
63
63
  },
64
64
  "dependencies": {
65
- "@aws-sdk/client-s3": "^3.1131.0",
65
+ "@aws-sdk/client-s3": "^3.1136.0",
66
66
  "@comark/nuxt": "^0.7.0",
67
67
  "@comark/vue": "^0.7.0",
68
- "@effect/platform-node-shared": "^4.0.0-rc.115",
69
- "@effect/sql-pg": "^4.0.0-rc.115",
68
+ "@effect/platform-node-shared": "^4.0.0-rc.116",
69
+ "@effect/sql-pg": "^4.0.0-rc.116",
70
70
  "@hocuspocus/server": "^4.7.0",
71
71
  "@nuxt/kit": "^4.5.2",
72
72
  "@nuxt/schema": "^4.5.2",
@@ -76,13 +76,13 @@
76
76
  "@tiptap/core": "^3.31.3",
77
77
  "@tiptap/starter-kit": "^3.31.3",
78
78
  "@tiptap/y-tiptap": "^3.0.9",
79
- "@vue/compiler-sfc": "^3.6.0-rc.8",
80
- "better-auth": "^1.7.4",
79
+ "@vue/compiler-sfc": "^3.6.0-rc.9",
80
+ "better-auth": "^1.7.5",
81
81
  "c12": "^4.0.0-rc.1",
82
82
  "comark": "^0.7.0",
83
83
  "diff": "^9.0.0",
84
84
  "drizzle-orm": "^1.0.0-rc.5-169397b",
85
- "effect": "^4.0.0-rc.115",
85
+ "effect": "^4.0.0-rc.116",
86
86
  "h3": "^1.15.11",
87
87
  "jiti": "^2.7.0",
88
88
  "nitropack": "^2.13.4",
@@ -1,6 +1,6 @@
1
1
  import { a as FormStep, n as FormDefinition, r as FormField } from "./Forms-R0HoTR-o.js";
2
2
  import { a as CmsMessageParameters, i as CmsMessageKey, r as CmsLocale } from "./I18n-zbqpWxki.js";
3
- import { n as DeliveryDocumentPage, t as DeliveryDocument } from "./types-DutFRtaG.js";
3
+ import { n as DeliveryDocumentPage, t as DeliveryDocument } from "./types-DZ0IV-Ow.js";
4
4
  import { Schema } from "effect";
5
5
  import { StandardSchemaV1 } from "@standard-schema/spec";
6
6
  //#region src/ApplicationTypes.d.ts
@@ -60,8 +60,8 @@ type Scalar = boolean | number | string | null;
60
60
  type FieldPaths<Value> = Value extends ReadonlyArray<unknown> ? never : Value extends object ? { [Key in Extract<keyof Value, string>]: NonNullable<Value[Key]> extends Scalar | ReadonlyArray<Scalar> ? Key : `${Key}.${FieldPaths<NonNullable<Value[Key]>>}`; }[Extract<keyof Value, string>] : never;
61
61
  type CollectionDataField<Name extends CmsCollectionName> = Extract<FieldPaths<CmsCollection<Name>['data']>, string>;
62
62
  type FieldValue<Value, Path extends string> = Path extends `${infer Head}.${infer Tail}` ? Head extends keyof Value ? FieldValue<NonNullable<Value[Head]>, Tail> : never : Path extends keyof Value ? Value[Path] : never;
63
- type DocumentField<Name extends CmsCollectionName> = 'collection' | 'description' | 'id' | 'key' | 'locale' | 'path' | 'source.path' | 'title' | CollectionDataField<Name> | `data.${CollectionDataField<Name>}`;
64
- type DocumentFieldValue<Name extends CmsCollectionName, Field extends DocumentField<Name>> = Field extends `data.${infer Path}` ? FieldValue<CmsCollection<Name>['data'], Path> : Field extends CollectionDataField<Name> ? FieldValue<CmsCollection<Name>['data'], Field> : Field extends 'collection' ? Name : Field extends 'locale' ? CmsLocale : Field extends 'source.path' ? CmsCollection<Name>['source']['path'] : Field extends keyof CmsCollection<Name> ? CmsCollection<Name>[Field] : never;
63
+ type DocumentField<Name extends CmsCollectionName> = 'collection' | 'description' | 'id' | 'key' | 'locale' | 'path' | 'title' | CollectionDataField<Name> | `data.${CollectionDataField<Name>}`;
64
+ type DocumentFieldValue<Name extends CmsCollectionName, Field extends DocumentField<Name>> = Field extends `data.${infer Path}` ? FieldValue<CmsCollection<Name>['data'], Path> : Field extends CollectionDataField<Name> ? FieldValue<CmsCollection<Name>['data'], Field> : Field extends 'collection' ? Name : Field extends 'locale' ? CmsLocale : Field extends keyof CmsCollection<Name> ? CmsCollection<Name>[Field] : never;
65
65
  type FilterValue<Value> = NonNullable<Value> extends ReadonlyArray<infer Item> ? Extract<NonNullable<Item>, Scalar> | ReadonlyArray<Extract<NonNullable<Item>, Scalar>> : Extract<NonNullable<Value>, Scalar> | ReadonlyArray<Extract<NonNullable<Value>, Scalar>>;
66
66
  type CmsDocumentQueryWhere<Name extends CmsCollectionName> = { readonly [Field in DocumentField<Name>]?: FilterValue<DocumentFieldValue<Name, Field>>; };
67
67
  export interface CmsDocumentQuerySort<Name extends CmsCollectionName> {
@@ -4,13 +4,16 @@ export type CmsBlockProp<Value> = {
4
4
  readonly label: string;
5
5
  readonly help?: string;
6
6
  } & ([NonNullable<Value>] extends [never] ? never : [NonNullable<Value>] extends [string] ? {
7
- readonly input: 'text' | 'textarea' | 'select' | 'image' | 'link';
7
+ readonly input: 'text' | 'textarea' | 'select' | 'image' | 'link' | 'document' | 'media';
8
8
  readonly optionLabels?: Partial<Record<Extract<Value, string>, string>>;
9
9
  } : [NonNullable<Value>] extends [number] ? {
10
10
  readonly input: 'number';
11
11
  } : [NonNullable<Value>] extends [boolean] ? {
12
12
  readonly input: 'toggle';
13
- } : [NonNullable<Value>] extends [ReadonlyArray<infer Item>] ? Item extends {
13
+ } : [NonNullable<Value>] extends [ReadonlyArray<infer Item>] ? [Item] extends [string] ? {
14
+ readonly input: 'multiselect';
15
+ readonly optionLabels?: Partial<Record<Extract<Item, string>, string>>;
16
+ } : Item extends {
14
17
  readonly id: string;
15
18
  } ? {
16
19
  readonly input: 'list';
@@ -19,18 +22,23 @@ export type CmsBlockProp<Value> = {
19
22
  readonly input: 'object';
20
23
  readonly fields: { readonly [Key in keyof NonNullable<Value>]?: CmsBlockProp<NonNullable<Value>[Key]>; };
21
24
  } : never);
25
+ export type CmsInlineTextFeature = 'bold' | 'italic' | 'link' | 'code';
26
+ export type CmsRichTextFeature = CmsInlineTextFeature | 'bullet-list';
22
27
  export type CmsBlockSlot = {
23
28
  readonly label: string;
24
29
  readonly help?: string;
25
30
  } & ({
26
31
  readonly input: 'text';
32
+ } | {
33
+ readonly input: 'inline-text';
34
+ readonly features: ReadonlyArray<CmsInlineTextFeature>;
27
35
  } | {
28
36
  readonly input: 'blocks';
29
37
  readonly blocks?: ReadonlyArray<string>;
30
38
  readonly groups?: ReadonlyArray<string>;
31
39
  } | {
32
40
  readonly input: 'rich-text';
33
- readonly features: ReadonlyArray<'bold' | 'italic' | 'link' | 'bullet-list' | 'code'>;
41
+ readonly features: ReadonlyArray<CmsRichTextFeature>;
34
42
  });
35
43
  export interface CmsBlockDeclaration<Props, Slots> {
36
44
  readonly label: string;