@phtngyn/cms 0.1.0-beta.0 → 0.1.0-beta.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 (123) hide show
  1. package/README.md +72 -1
  2. package/package.json +5 -5
  3. package/src/Authoring.d.ts +13 -1
  4. package/src/{AuthoringSchema-BQ5kbhVB.js → Configuration-DyKo0sLS.js} +595 -367
  5. package/src/Configuration-DyKo0sLS.js.map +1 -0
  6. package/src/{DocumentEngine-Da0kWotL.js → DocumentEngine-DYObwMDY.js} +44 -66
  7. package/src/DocumentEngine-DYObwMDY.js.map +1 -0
  8. package/src/DocumentModel.d.ts +4 -0
  9. package/src/DocumentModel.js.map +1 -1
  10. package/src/{HttpPaths-86qLGB90.js → HttpPaths-BbS21Jy8.js} +4 -2
  11. package/src/{HttpPaths-86qLGB90.js.map → HttpPaths-BbS21Jy8.js.map} +1 -1
  12. package/src/Module.js +27 -76
  13. package/src/Module.js.map +1 -1
  14. package/src/{StudioHttp-BTLLooh0.js → StudioHttp-jR2-bc01.js} +44 -242
  15. package/src/StudioHttp-jR2-bc01.js.map +1 -0
  16. package/src/{connection-ZGtL54qY.js → connection-CBTY-TzB.js} +3 -3
  17. package/src/{connection-ZGtL54qY.js.map → connection-CBTY-TzB.js.map} +1 -1
  18. package/src/{installation-BNKaVjni.js → installation-DeuBiFRE.js} +488 -236
  19. package/src/installation-DeuBiFRE.js.map +1 -0
  20. package/src/internal/authoring-catalog.js +147 -0
  21. package/src/internal/authoring-catalog.js.map +1 -0
  22. package/src/internal/authoring-compiler.js +2 -1
  23. package/src/internal/authoring-compiler.js.map +1 -1
  24. package/src/internal/authoring-metadata.js +67 -48
  25. package/src/internal/authoring-metadata.js.map +1 -1
  26. package/src/internal/configuration.js +5 -6
  27. package/src/internal/configuration.js.map +1 -1
  28. package/src/internal/document-model.js +3 -2
  29. package/src/internal/document-model.js.map +1 -1
  30. package/src/internal/studio-app.js +66 -0
  31. package/src/internal/studio-app.js.map +1 -0
  32. package/src/location-DtYv2aes.js +36 -0
  33. package/src/location-DtYv2aes.js.map +1 -0
  34. package/src/{metadata-Czvi3E4K.js → metadata-DE1Mc2td.js} +2 -2
  35. package/src/{metadata-Czvi3E4K.js.map → metadata-DE1Mc2td.js.map} +1 -1
  36. package/src/{models-Citx8jBi.js → models-BkMgeaOL.js} +252 -3
  37. package/src/models-BkMgeaOL.js.map +1 -0
  38. package/src/{models-DS5ClMsH.js → models-C3witQBK.js} +8 -31
  39. package/src/models-C3witQBK.js.map +1 -0
  40. package/src/runtime/blocks.js +17 -0
  41. package/src/runtime/blocks.js.map +1 -0
  42. package/src/runtime/collaboration.js +9 -4
  43. package/src/runtime/collaboration.js.map +1 -1
  44. package/src/runtime/delivery/DocumentRenderer.js +6 -3
  45. package/src/runtime/delivery/DocumentRenderer.js.map +1 -1
  46. package/src/runtime/delivery/blocks.js +6 -0
  47. package/src/runtime/delivery/blocks.js.map +1 -0
  48. package/src/runtime/delivery/context.js +12 -0
  49. package/src/runtime/delivery/context.js.map +1 -0
  50. package/src/runtime/delivery/document-page.js +5 -3
  51. package/src/runtime/delivery/document-page.js.map +1 -1
  52. package/src/runtime/delivery/document.js +18 -2
  53. package/src/runtime/delivery/document.js.map +1 -1
  54. package/src/runtime/delivery/error.js +11 -0
  55. package/src/runtime/delivery/error.js.map +1 -0
  56. package/src/runtime/delivery/plugin.js +21 -0
  57. package/src/runtime/delivery/plugin.js.map +1 -0
  58. package/src/runtime/delivery/useDocument.js +6 -3
  59. package/src/runtime/delivery/useDocument.js.map +1 -1
  60. package/src/runtime/delivery/useDocumentQuery.js +6 -3
  61. package/src/runtime/delivery/useDocumentQuery.js.map +1 -1
  62. package/src/runtime/installation.js +1 -1
  63. package/src/runtime/plugin.js +3 -3
  64. package/src/runtime/plugin.js.map +1 -1
  65. package/src/runtime/preview/connection.js +1 -1
  66. package/src/runtime/preview/controller.js +29 -10
  67. package/src/runtime/preview/controller.js.map +1 -1
  68. package/src/runtime/preview/overlay.js +65 -0
  69. package/src/runtime/preview/overlay.js.map +1 -0
  70. package/src/runtime/preview/plugin.client.js +21 -34
  71. package/src/runtime/preview/plugin.client.js.map +1 -1
  72. package/src/runtime/preview/preview.css +72 -4
  73. package/src/runtime/preview/store.js +1 -1
  74. package/src/runtime/studio-app.js +5 -1
  75. package/src/runtime/studio-app.js.map +1 -1
  76. package/src/runtime/studio-entry.js +36 -0
  77. package/src/runtime/studio-entry.js.map +1 -0
  78. package/src/runtime/studio-navigation.js +11 -0
  79. package/src/runtime/studio-navigation.js.map +1 -0
  80. package/src/{store-Nl4uxEXx.js → store-CfFFx9Ua.js} +3 -3
  81. package/src/{store-Nl4uxEXx.js.map → store-CfFFx9Ua.js.map} +1 -1
  82. package/studio/CreateDocumentDialog--L9lTfx6.js +256 -0
  83. package/studio/collaboration-DUuu678R.js +4565 -0
  84. package/studio/documentPlanning-BXX04Woe.js +28989 -0
  85. package/studio/dom-to-image-more.min-D6jGGdrW.js +877 -0
  86. package/studio/editor-PexnXkJY.js +30817 -0
  87. package/studio/host.css +3 -0
  88. package/studio/host.js +44179 -0
  89. package/studio/rolldown-runtime-B0aSnxlc.js +20 -0
  90. package/dist/studio/assets/ActivityEntryRow-D--fRvWI.js +0 -1
  91. package/dist/studio/assets/ActivityView-D-XBBUHb.js +0 -1
  92. package/dist/studio/assets/CreateDocumentDialog-CH8UH1QM.js +0 -1
  93. package/dist/studio/assets/DocumentsView-CxRpmAxt.js +0 -34
  94. package/dist/studio/assets/DropdownMenu-BSb1l7fr.js +0 -1
  95. package/dist/studio/assets/Input-DVao38h7.js +0 -3
  96. package/dist/studio/assets/MediaView-BHrPIjxB.js +0 -1
  97. package/dist/studio/assets/Modal-VNrXGa5C.js +0 -1
  98. package/dist/studio/assets/OverviewView-DfP6-mLZ.js +0 -1
  99. package/dist/studio/assets/Select-BJZIs9sY.js +0 -1
  100. package/dist/studio/assets/SettingsView-CerHe-ua.js +0 -1
  101. package/dist/studio/assets/Skeleton-CWJNi3nS.js +0 -1
  102. package/dist/studio/assets/StudioPageHeader-DP9HDAF2.js +0 -1
  103. package/dist/studio/assets/UsersView-cP3REkH2.js +0 -1
  104. package/dist/studio/assets/collaboration-BLnCzfvV.js +0 -4
  105. package/dist/studio/assets/context-dY4fNbn3.js +0 -1
  106. package/dist/studio/assets/editor-CE07wW83.js +0 -137
  107. package/dist/studio/assets/gateway-BAyQgCse.js +0 -10
  108. package/dist/studio/assets/index-CjoaPLhZ.js +0 -28
  109. package/dist/studio/assets/index-s2rPqCmP.css +0 -2
  110. package/dist/studio/assets/render-BkxbK2St.js +0 -83
  111. package/dist/studio/assets/rolldown-runtime-DK3Fl9T5.js +0 -1
  112. package/dist/studio/assets/useMediaLibrary-D7qR7aBf.js +0 -1
  113. package/dist/studio/index.html +0 -76
  114. package/src/AuthoringSchema-BQ5kbhVB.js.map +0 -1
  115. package/src/Configuration-BGYFD2N1.js +0 -150
  116. package/src/Configuration-BGYFD2N1.js.map +0 -1
  117. package/src/DocumentEngine-Da0kWotL.js.map +0 -1
  118. package/src/StudioHttp-BTLLooh0.js.map +0 -1
  119. package/src/installation-BNKaVjni.js.map +0 -1
  120. package/src/internal/component-metadata.js +0 -37
  121. package/src/internal/component-metadata.js.map +0 -1
  122. package/src/models-Citx8jBi.js.map +0 -1
  123. package/src/models-DS5ClMsH.js.map +0 -1
package/README.md CHANGED
@@ -76,7 +76,13 @@ For storage using the AWS credential chain, omit `credentials`. To create a miss
76
76
  2. Enter your initialization token and create the first administrator. Initialization then closes.
77
77
  3. Create a page in Studio, edit it, and publish it. The module provides page routing and rendering; your app must render `<NuxtPage />` in `app/app.vue` if it has a custom app shell. Existing app routes can provide custom page layouts.
78
78
 
79
- Studio is bundled with the module; no separate Studio deployment or auth setup is required. Readiness is available at `/_cms/health/ready`. Restart Nuxt after changing CMS configuration or component schemas.
79
+ Studio is bundled with the module; no separate Studio deployment or auth setup is required. Readiness is available at `/_cms/health/ready`. Component schemas update through HMR during development. CMS configuration changes use Nuxt’s restart lifecycle.
80
+
81
+ ## Preview drafts
82
+
83
+ Studio previews render authored documents through the same Nuxt routes, layouts, components, `useDocument`, and `useDocumentQuery` used by the website. A page can be previewed before its first publication. Preview mode follows internal navigation and survives iframe reloads; ordinary website requests continue to read published content.
84
+
85
+ Draft delivery requires the current Studio session and document access permission. Preview URLs contain only iframe coordination information, never an access token. Preview HTML and draft API responses are private and uncached. Once the page renders, the editor bridge overlays current collaborative edits without waiting for publication or replacing Nuxt HMR.
80
86
 
81
87
  ## Customize
82
88
 
@@ -88,3 +94,68 @@ Studio is bundled with the module; no separate Studio deployment or auth setup i
88
94
  ## License
89
95
 
90
96
  Proprietary. Copyright (c) 2026 Phat (phtngyn). All rights reserved. Use, copying, modification, and redistribution require prior written permission. Third-party components retain their own licenses.
97
+
98
+ ## Studio and authoring during development
99
+
100
+ Studio at `/_cms/app` is a separate HTML document, Vue application, and Tailwind build. It owns its Nuxt UI settings, styles, and overlays independently of the website. Your app root and layouts apply only to the website. Both applications use the same Nuxt server; no separate Studio server or port is required.
101
+
102
+ Only components that declare `defineCmsBlock` appear in the authoring catalog. Nuxt compiles their Vue props, slots, imported types, and presentation into one generated `#cms/authoring` module. Studio’s entry imports this module through Nuxt’s Vite graph, so isolation does not require a custom HMR transport. A separate Vue component map supplies Comark’s renderer, so adding or removing a block does not reinitialize Studio. Valid semantic changes update Studio and rebuild the Nitro worker automatically, keeping the development listener running. Invalid changes show a Vite error and retain the last valid catalog.
103
+
104
+ An open editor reads the new catalog without reseeding content or replacing its collaborative document. Publishing waits until the collaboration server and editor use the same catalog revision. Installation configuration changes still use Nuxt’s configuration restart lifecycle.
105
+
106
+ ## Component authoring and collection permissions
107
+
108
+ 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.
109
+
110
+ A collection can restrict available component blocks:
111
+
112
+ ```ts
113
+ pages: {
114
+ label: 'Page',
115
+ route: '/:path*',
116
+ schema: z.object({ title: z.string() }),
117
+ body: {
118
+ blocks: ['content-hero'],
119
+ groups: ['Editorial'],
120
+ },
121
+ },
122
+ ```
123
+
124
+ Block names and groups form a union. Omitting `body` permits all declared blocks; `body: {}` permits none. Ordinary text remains available. Unknown selectors fail configuration validation. Studio insertion and server publication use the same document-owned rules, including blocks inside other content. A restriction change preserves existing content and reports what must be corrected before publication.
125
+
126
+ Clearing an optional property removes its stored override, so a Vue default can apply. Reset writes the current declared default. Nullable fields also offer an explicit no-value choice; empty strings, zero, and false remain actual values.
127
+
128
+ ### Images, links, and composition
129
+
130
+ 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.
131
+
132
+ 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.
133
+
134
+ Use object props for structured data and slots for composed content:
135
+
136
+ ```ts
137
+ interface Props {
138
+ settings?: { compact: boolean }
139
+ features?: Array<{ id: string; title: string; link?: string }>
140
+ }
141
+ // Inside the component's defineCmsBlock declaration:
142
+ props: {
143
+ settings: {
144
+ label: 'Settings', input: 'object',
145
+ fields: { compact: { label: 'Compact spacing', input: 'toggle' } },
146
+ },
147
+ features: {
148
+ label: 'Features', input: 'list',
149
+ fields: {
150
+ title: { label: 'Title', input: 'text' },
151
+ link: { label: 'Link', input: 'link' },
152
+ },
153
+ },
154
+ },
155
+ ```
156
+
157
+ Every list item needs a required `id: string` in its Vue type. Studio generates and preserves this value; use it as the item's Vue `:key`. Do not declare an editable control for `id`. Object/list shapes, requiredness and string choices come from Vue, including nested fields. Literal factory defaults such as `() => []` and `() => ({ compact: false })` are supported. Computed defaults and recursive types are not editable contracts.
158
+
159
+ Collaboration merges object fields and list-item fields independently. List ordering is separate from item values; simultaneous insertions at the same position retain both items in deterministic identity order. Removing an item takes precedence over concurrent edits to it. Competing edits to the same field use Yjs conflict resolution. Authoring schemas and controls update through the existing HMR path without reseeding content.
160
+
161
+ See the example's `ContentSection.vue` for a complete component-local declaration with images, links, layout settings, repeatable features and nested blocks.
package/package.json CHANGED
@@ -14,10 +14,10 @@
14
14
  "directory": "packages/nuxt"
15
15
  },
16
16
  "name": "@phtngyn/cms",
17
- "version": "0.1.0-beta.0",
17
+ "version": "0.1.0-beta.1",
18
18
  "type": "module",
19
19
  "files": [
20
- "dist",
20
+ "studio",
21
21
  "src",
22
22
  "README.md",
23
23
  "LICENSE"
@@ -61,9 +61,9 @@
61
61
  "h3": "^1.15.11",
62
62
  "jiti": "^2.7.0",
63
63
  "nitropack": "^2.13.4",
64
- "nuxt-component-meta": "^0.18.0",
65
64
  "pg": "^8.23.0",
66
- "typescript": "npm:typescript-native-bridge@6.0.3-bridge.15.tsgo.7.0.2",
65
+ "typescript": "npm:typescript-native-bridge@6.0.3-bridge.16.tsgo.7.0.2",
66
+ "vite": "^8.2.2",
67
67
  "vue-component-meta": "^3.3.11",
68
68
  "yjs": "^13.6.32",
69
69
  "zod": "^4.5.4"
@@ -72,4 +72,4 @@
72
72
  "nuxt": ">=4.5.0 <5.0.0",
73
73
  "vue": ">=3.6.0-rc.6 <4.0.0"
74
74
  }
75
- }
75
+ }
@@ -4,18 +4,30 @@ 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';
7
+ readonly input: 'text' | 'textarea' | 'select' | 'image' | 'link';
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 {
14
+ readonly id: string;
15
+ } ? {
16
+ readonly input: 'list';
17
+ readonly fields: { readonly [Key in Exclude<keyof Item, 'id'>]?: CmsBlockProp<Item[Key]>; };
18
+ } : never : [NonNullable<Value>] extends [object] ? {
19
+ readonly input: 'object';
20
+ readonly fields: { readonly [Key in keyof NonNullable<Value>]?: CmsBlockProp<NonNullable<Value>[Key]>; };
13
21
  } : never);
14
22
  export type CmsBlockSlot = {
15
23
  readonly label: string;
16
24
  readonly help?: string;
17
25
  } & ({
18
26
  readonly input: 'text';
27
+ } | {
28
+ readonly input: 'blocks';
29
+ readonly blocks?: ReadonlyArray<string>;
30
+ readonly groups?: ReadonlyArray<string>;
19
31
  } | {
20
32
  readonly input: 'rich-text';
21
33
  readonly features: ReadonlyArray<'bold' | 'italic' | 'link' | 'bullet-list' | 'code'>;