@orion-studios/payload-studio 0.6.0-beta.9 → 0.7.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 (66) hide show
  1. package/README.md +6 -1
  2. package/bin/init.js +329 -0
  3. package/dist/admin/client.js +2106 -585
  4. package/dist/admin/client.mjs +2161 -653
  5. package/dist/admin/index.d.mts +2 -2
  6. package/dist/admin/index.d.ts +2 -2
  7. package/dist/admin/index.js +190 -36
  8. package/dist/admin/index.mjs +2 -2
  9. package/dist/admin-app/client.js +14 -5
  10. package/dist/admin-app/client.mjs +1 -1
  11. package/dist/admin-app/index.d.mts +2 -2
  12. package/dist/admin-app/index.d.ts +2 -2
  13. package/dist/admin-app/styles.css +361 -41
  14. package/dist/admin.css +98 -2
  15. package/dist/blocks/index.mjs +1 -2
  16. package/dist/builder-v2/client.d.mts +18 -0
  17. package/dist/builder-v2/client.d.ts +18 -0
  18. package/dist/builder-v2/client.js +4287 -0
  19. package/dist/builder-v2/client.mjs +4162 -0
  20. package/dist/builder-v2/index.d.mts +249 -0
  21. package/dist/builder-v2/index.d.ts +249 -0
  22. package/dist/builder-v2/index.js +836 -0
  23. package/dist/builder-v2/index.mjs +786 -0
  24. package/dist/builder-v2/styles.css +2705 -0
  25. package/dist/{chunk-PF3EBZXF.mjs → chunk-7ZMXZRBP.mjs} +39 -3
  26. package/dist/{chunk-XKUTZ7IU.mjs → chunk-DTHBPJXU.mjs} +246 -25
  27. package/dist/{chunk-JQAHXYAM.mjs → chunk-KMYMSR7W.mjs} +163 -3
  28. package/dist/{chunk-WLOPFFN2.mjs → chunk-MMJNHBOF.mjs} +193 -39
  29. package/dist/{chunk-KPIX7OSV.mjs → chunk-NF37A575.mjs} +14 -5
  30. package/dist/{chunk-OTHERBGX.mjs → chunk-OF6BATTO.mjs} +57 -112
  31. package/dist/chunk-VA545CHJ.mjs +202 -0
  32. package/dist/forms/index.d.mts +25 -0
  33. package/dist/forms/index.d.ts +25 -0
  34. package/dist/forms/index.js +237 -0
  35. package/dist/forms/index.mjs +25 -0
  36. package/dist/forms/server.d.mts +35 -0
  37. package/dist/forms/server.d.ts +35 -0
  38. package/dist/forms/server.js +442 -0
  39. package/dist/forms/server.mjs +228 -0
  40. package/dist/{index-Crx_MtPw.d.ts → index-0xXWuOuz.d.ts} +38 -6
  41. package/dist/{index-Cv-6qnrw.d.mts → index-BU82akSL.d.mts} +38 -6
  42. package/dist/{index-Bm2SaC3r.d.mts → index-BbTcimgH.d.mts} +4 -2
  43. package/dist/{index-D8BNfUJb.d.mts → index-Cen-9wcc.d.mts} +17 -5
  44. package/dist/{index-52HdVLQq.d.ts → index-DAdN56fM.d.ts} +1 -1
  45. package/dist/{index-CkT_eyhK.d.ts → index-DV-nW43e.d.ts} +4 -2
  46. package/dist/{index-DEQC3Dwj.d.mts → index-G_uTNffQ.d.mts} +1 -1
  47. package/dist/{index-DD_E2UfJ.d.ts → index-gxcMPpm-.d.ts} +17 -5
  48. package/dist/index.d.mts +5 -5
  49. package/dist/index.d.ts +5 -5
  50. package/dist/index.js +522 -171
  51. package/dist/index.mjs +10 -11
  52. package/dist/nextjs/index.d.mts +1 -1
  53. package/dist/nextjs/index.d.ts +1 -1
  54. package/dist/nextjs/index.js +95 -114
  55. package/dist/nextjs/index.mjs +2 -2
  56. package/dist/{sitePreviewTypes-BkHCWxNW.d.mts → sitePreviewTypes-BrJwGzJj.d.mts} +1 -1
  57. package/dist/{sitePreviewTypes-BkHCWxNW.d.ts → sitePreviewTypes-BrJwGzJj.d.ts} +1 -1
  58. package/dist/studio-pages/builder.css +66 -5
  59. package/dist/studio-pages/client.js +618 -73
  60. package/dist/studio-pages/client.mjs +641 -96
  61. package/dist/studio-pages/index.d.mts +1 -1
  62. package/dist/studio-pages/index.d.ts +1 -1
  63. package/dist/studio-pages/index.js +1893 -24
  64. package/dist/studio-pages/index.mjs +11 -3
  65. package/package.json +38 -3
  66. package/dist/chunk-OQSEJXC4.mjs +0 -166
package/README.md CHANGED
@@ -22,8 +22,10 @@ Prefer explicit subpath imports.
22
22
  import { configureAdmin, type StudioSection } from '@orion-studios/payload-studio/admin'
23
23
  import { createPayloadClient, createPageQueries, createSiteQueries } from '@orion-studios/payload-studio/nextjs'
24
24
  import { defaultPageLayoutBlocks } from '@orion-studios/payload-studio/blocks'
25
- import { pageStudioModuleManifest } from '@orion-studios/payload-studio/studio-pages'
25
+ import { createStudioPagesCollection, pageStudioModuleManifest } from '@orion-studios/payload-studio/studio-pages'
26
26
  import { withImageUploadOptimization } from '@orion-studios/payload-studio/studio'
27
+ import { validateEmail, formatPhoneUS } from '@orion-studios/payload-studio/forms'
28
+ import { createFormSubmissionHandler } from '@orion-studios/payload-studio/forms/server'
27
29
  ```
28
30
 
29
31
  The root `@orion-studios/payload-studio` namespace export remains available for backward compatibility, but new integrations should treat subpath imports as the public contract.
@@ -32,6 +34,7 @@ The root `@orion-studios/payload-studio` namespace export remains available for
32
34
 
33
35
  ```bash
34
36
  npm install @orion-studios/payload-studio
37
+ npx payload-studio-init # scaffolds app scripts, lib wrappers, and the form submission route
35
38
  ```
36
39
 
37
40
  ```ts
@@ -70,6 +73,8 @@ const adminConfig = configureAdmin({
70
73
  - `@orion-studios/payload-studio/admin-app/client`
71
74
  - `@orion-studios/payload-studio/admin-app/styles.css`
72
75
  - `@orion-studios/payload-studio/blocks`
76
+ - `@orion-studios/payload-studio/forms`
77
+ - `@orion-studios/payload-studio/forms/server`
73
78
  - `@orion-studios/payload-studio/nextjs`
74
79
  - `@orion-studios/payload-studio/studio`
75
80
  - `@orion-studios/payload-studio/studio-pages`
package/bin/init.js ADDED
@@ -0,0 +1,329 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Scaffolds the app-side files required by the Studio Website Setup Guide.
5
+ *
6
+ * Usage (from the consuming app root):
7
+ * npx payload-studio-init
8
+ *
9
+ * Existing files are never overwritten — safe to re-run after upgrades.
10
+ */
11
+
12
+ const fs = require('fs')
13
+ const path = require('path')
14
+
15
+ const cwd = process.cwd()
16
+
17
+ const hasSrcDir = fs.existsSync(path.join(cwd, 'src'))
18
+ const srcRoot = hasSrcDir ? 'src' : '.'
19
+
20
+ const FILES = [
21
+ {
22
+ file: 'scripts/clean-next-cache.cjs',
23
+ contents: `#!/usr/bin/env node
24
+
25
+ // Clears stale Next.js build caches before dev/build runs.
26
+ // Pass --all to remove the entire .next directory instead of just the cache.
27
+
28
+ const fs = require('fs')
29
+ const path = require('path')
30
+
31
+ const all = process.argv.includes('--all')
32
+ const target = path.join(process.cwd(), '.next', all ? '' : 'cache')
33
+
34
+ try {
35
+ fs.rmSync(target, { recursive: true, force: true })
36
+ console.log('[clean-next-cache] removed ' + path.relative(process.cwd(), target || '.next'))
37
+ } catch (error) {
38
+ console.warn('[clean-next-cache] skipped: ' + error.message)
39
+ }
40
+ `,
41
+ },
42
+ {
43
+ file: 'scripts/schema-sync.ts',
44
+ contents: `/**
45
+ * Pushes the current Payload schema to the database.
46
+ *
47
+ * Run via: npm run schema:sync
48
+ * The PAYLOAD_SCHEMA_PUSH=true env flag is set by the npm script — schema push
49
+ * stays opt-in only, per the Studio contract.
50
+ */
51
+
52
+ import config from '../${srcRoot}/payload.config'
53
+ import { getPayload } from 'payload'
54
+
55
+ async function run() {
56
+ if (process.env.PAYLOAD_SCHEMA_PUSH !== 'true') {
57
+ console.error('Refusing to run: set PAYLOAD_SCHEMA_PUSH=true (use \`npm run schema:sync\`).')
58
+ process.exit(1)
59
+ }
60
+
61
+ const payload = await getPayload({ config })
62
+ console.log('[schema-sync] schema synchronized')
63
+ if (typeof payload.db?.destroy === 'function') {
64
+ await payload.db.destroy()
65
+ }
66
+ process.exit(0)
67
+ }
68
+
69
+ run().catch((error) => {
70
+ console.error('[schema-sync] failed:', error)
71
+ process.exit(1)
72
+ })
73
+ `,
74
+ },
75
+ {
76
+ file: 'scripts/seed.ts',
77
+ contents: `/**
78
+ * Seeds the CMS with the canonical default pages from src/lib/site-page-layouts.
79
+ * Existing pages are left untouched — safe to re-run.
80
+ *
81
+ * Run via: npm run seed
82
+ */
83
+
84
+ import config from '../${srcRoot}/payload.config'
85
+ import { getPayload } from 'payload'
86
+ import { sitePageLayouts } from '../${srcRoot}/lib/site-page-layouts'
87
+
88
+ async function run() {
89
+ const payload = await getPayload({ config })
90
+
91
+ for (const page of sitePageLayouts) {
92
+ const existing = await payload.find({
93
+ collection: 'pages',
94
+ limit: 1,
95
+ where: { slug: { equals: page.slug } },
96
+ })
97
+
98
+ if (existing.docs.length > 0) {
99
+ console.log('[seed] skip existing page: ' + page.slug)
100
+ continue
101
+ }
102
+
103
+ await payload.create({
104
+ collection: 'pages',
105
+ data: {
106
+ _status: 'published',
107
+ layout: page.layout,
108
+ slug: page.slug,
109
+ title: page.title,
110
+ },
111
+ })
112
+ console.log('[seed] created page: ' + page.slug)
113
+ }
114
+
115
+ if (typeof payload.db?.destroy === 'function') {
116
+ await payload.db.destroy()
117
+ }
118
+ process.exit(0)
119
+ }
120
+
121
+ run().catch((error) => {
122
+ console.error('[seed] failed:', error)
123
+ process.exit(1)
124
+ })
125
+ `,
126
+ },
127
+ {
128
+ file: 'scripts/sync-page-layouts.ts',
129
+ contents: `/**
130
+ * Syncs the canonical default layouts from src/lib/site-page-layouts into the
131
+ * CMS for pages that have NOT been edited in the Studio builder yet
132
+ * (no studioDocument). Builder-authored pages are never overwritten.
133
+ *
134
+ * Run via: npm run pages:sync-layouts
135
+ */
136
+
137
+ import config from '../${srcRoot}/payload.config'
138
+ import { getPayload } from 'payload'
139
+ import { sitePageLayouts } from '../${srcRoot}/lib/site-page-layouts'
140
+
141
+ async function run() {
142
+ const payload = await getPayload({ config })
143
+
144
+ for (const page of sitePageLayouts) {
145
+ const existing = await payload.find({
146
+ collection: 'pages',
147
+ draft: true,
148
+ limit: 1,
149
+ where: { slug: { equals: page.slug } },
150
+ })
151
+
152
+ const doc = existing.docs[0] as { id: number | string; studioDocument?: unknown } | undefined
153
+
154
+ if (!doc) {
155
+ await payload.create({
156
+ collection: 'pages',
157
+ data: {
158
+ _status: 'published',
159
+ layout: page.layout,
160
+ slug: page.slug,
161
+ title: page.title,
162
+ },
163
+ })
164
+ console.log('[sync-layouts] created page: ' + page.slug)
165
+ continue
166
+ }
167
+
168
+ if (doc.studioDocument) {
169
+ console.log('[sync-layouts] skip builder-owned page: ' + page.slug)
170
+ continue
171
+ }
172
+
173
+ await payload.update({
174
+ collection: 'pages',
175
+ id: doc.id,
176
+ data: { layout: page.layout },
177
+ })
178
+ console.log('[sync-layouts] updated layout for page: ' + page.slug)
179
+ }
180
+
181
+ if (typeof payload.db?.destroy === 'function') {
182
+ await payload.db.destroy()
183
+ }
184
+ process.exit(0)
185
+ }
186
+
187
+ run().catch((error) => {
188
+ console.error('[sync-layouts] failed:', error)
189
+ process.exit(1)
190
+ })
191
+ `,
192
+ },
193
+ {
194
+ file: `${srcRoot}/lib/payload.ts`,
195
+ contents: `import config from '@/payload.config'
196
+ import { createPayloadClient, WEBSITE_CONTENT_TAG } from '@orion-studios/payload-studio/nextjs'
197
+
198
+ export const getPayloadClient = createPayloadClient(config)
199
+ export { WEBSITE_CONTENT_TAG }
200
+ `,
201
+ },
202
+ {
203
+ file: `${srcRoot}/lib/pages.ts`,
204
+ contents: `import { createPageQueries } from '@orion-studios/payload-studio/nextjs'
205
+ import { getPayloadClient, WEBSITE_CONTENT_TAG } from '@/lib/payload'
206
+
207
+ export const { getPageBySegments, listPublishedPagePaths, pathToSegments } = createPageQueries(
208
+ getPayloadClient,
209
+ { contentTag: WEBSITE_CONTENT_TAG },
210
+ )
211
+ `,
212
+ },
213
+ {
214
+ file: `${srcRoot}/lib/site.ts`,
215
+ contents: `import { createSiteQueries } from '@orion-studios/payload-studio/nextjs'
216
+ import { getPayloadClient, WEBSITE_CONTENT_TAG } from '@/lib/payload'
217
+
218
+ export const { getSiteSettings, getHeader, getFooter, getSocialMedia } = createSiteQueries(
219
+ getPayloadClient,
220
+ { contentTag: WEBSITE_CONTENT_TAG },
221
+ )
222
+ `,
223
+ },
224
+ {
225
+ file: `${srcRoot}/lib/site-page-layouts.ts`,
226
+ contents: `/**
227
+ * Canonical default page layouts.
228
+ *
229
+ * This module is the single layout source used by runtime fallback, the seed
230
+ * script, and the sync script, per the Studio Website Setup Guide.
231
+ */
232
+
233
+ export type SitePageLayout = {
234
+ slug: string
235
+ title: string
236
+ layout: Array<Record<string, unknown>>
237
+ }
238
+
239
+ export const sitePageLayouts: SitePageLayout[] = [
240
+ {
241
+ slug: 'home',
242
+ title: 'Home',
243
+ layout: [],
244
+ },
245
+ ]
246
+ `,
247
+ },
248
+ {
249
+ file: `${srcRoot}/app/api/form-submissions/[slug]/route.ts`,
250
+ contents: `import { createFormSubmissionHandler } from '@orion-studios/payload-studio/forms/server'
251
+ import { getPayloadClient } from '@/lib/payload'
252
+
253
+ /**
254
+ * Public form submission boundary. Anonymous users must never write directly
255
+ * to the submissions collection — this route is the only entry point.
256
+ * Origin check, honeypot, minimum fill time, rate limiting, and server-side
257
+ * re-validation are handled by the shared package handler.
258
+ */
259
+ export const POST = createFormSubmissionHandler({
260
+ getPayloadClient,
261
+ })
262
+ `,
263
+ },
264
+ ]
265
+
266
+ const REQUIRED_SCRIPTS = {
267
+ dev: 'node scripts/clean-next-cache.cjs && npm run generate:importmap && next dev --webpack',
268
+ build:
269
+ 'node scripts/clean-next-cache.cjs --all && npm run generate:importmap && next build --webpack',
270
+ lint: 'eslint .',
271
+ typecheck: 'tsc --noEmit',
272
+ verify: 'npm run payload:types && npm run lint && npm run typecheck',
273
+ payload: "NODE_OPTIONS='--import tsx' payload",
274
+ 'payload:types': "NODE_OPTIONS='--import tsx' payload generate:types",
275
+ 'generate:importmap': "NODE_OPTIONS='--import tsx' payload generate:importmap",
276
+ 'schema:sync': 'PAYLOAD_SCHEMA_PUSH=true tsx scripts/schema-sync.ts',
277
+ seed: 'tsx scripts/seed.ts',
278
+ 'pages:sync-layouts': 'tsx scripts/sync-page-layouts.ts',
279
+ }
280
+
281
+ try {
282
+ console.log('Payload Studio app scaffolding\n')
283
+
284
+ let created = 0
285
+ let skipped = 0
286
+
287
+ for (const entry of FILES) {
288
+ const target = path.join(cwd, entry.file)
289
+
290
+ if (fs.existsSync(target)) {
291
+ console.log(' skip (exists) ' + entry.file)
292
+ skipped += 1
293
+ continue
294
+ }
295
+
296
+ fs.mkdirSync(path.dirname(target), { recursive: true })
297
+ fs.writeFileSync(target, entry.contents)
298
+ console.log(' created ' + entry.file)
299
+ created += 1
300
+ }
301
+
302
+ console.log('\n' + created + ' file(s) created, ' + skipped + ' skipped (already present).')
303
+
304
+ // Report which required package.json scripts are missing, without mutating.
305
+ const pkgPath = path.join(cwd, 'package.json')
306
+ if (fs.existsSync(pkgPath)) {
307
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
308
+ const scripts = pkg.scripts || {}
309
+ const missing = Object.entries(REQUIRED_SCRIPTS).filter(([name]) => !scripts[name])
310
+
311
+ if (missing.length > 0) {
312
+ console.log('\nAdd the following to package.json "scripts":\n')
313
+ for (const [name, command] of missing) {
314
+ console.log(' "' + name + '": "' + command.replace(/"/g, '\\"') + '",')
315
+ }
316
+ } else {
317
+ console.log('\nAll required package.json scripts are present.')
318
+ }
319
+ }
320
+
321
+ console.log('\nNext steps:')
322
+ console.log(' 1. Wire payload.config.ts with configureAdmin(...) and createStudioPagesCollection(...)')
323
+ console.log(' 2. npm run payload:types')
324
+ console.log(' 3. npm run generate:importmap')
325
+ console.log(' 4. See docs/studio-website-setup-guide.md for the full contract.')
326
+ } catch (error) {
327
+ console.error('Scaffolding failed:', error)
328
+ process.exit(1)
329
+ }