@woodsportal/hubspot-kit 1.0.4 → 1.0.26

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 (217) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +4 -2
  3. package/dist/{chunk-JDGIAYHX.js → chunk-GTTIJVAR.js} +43 -3
  4. package/dist/chunk-GTTIJVAR.js.map +1 -0
  5. package/dist/cli.js +1400 -338
  6. package/dist/cli.js.map +1 -1
  7. package/dist/exec-U2OJATR3.js +12 -0
  8. package/dist/index.d.ts +20 -0
  9. package/dist/index.js +8 -1
  10. package/dist/index.js.map +1 -1
  11. package/examples/greenfield/module-hybrid-cdn/README.md +40 -3
  12. package/examples/greenfield/module-hybrid-cdn/public/fields.json +44 -1
  13. package/examples/greenfield/module-hybrid-cdn/src/app.tsx +8 -0
  14. package/examples/greenfield/module-hybrid-cdn/src/assets/css/main.dev.css +6 -1
  15. package/examples/greenfield/module-hybrid-cdn/src/cdn/app-entry.ts +32 -0
  16. package/examples/greenfield/module-hybrid-cdn/src/cdn/vendor-entry.ts +28 -0
  17. package/examples/greenfield/module-hybrid-cdn/src/components/layout/section-card.tsx +20 -0
  18. package/examples/greenfield/module-hybrid-cdn/src/components/layout/starter-nav.tsx +28 -0
  19. package/examples/greenfield/module-hybrid-cdn/src/components/layout/starter-shell.tsx +18 -0
  20. package/examples/greenfield/module-hybrid-cdn/src/config/router.ts +4 -0
  21. package/examples/greenfield/module-hybrid-cdn/src/config/routes.ts +5 -0
  22. package/examples/greenfield/module-hybrid-cdn/src/defaultData.ts +2 -7
  23. package/examples/greenfield/module-hybrid-cdn/src/features/starter/components/starter-guide-page.tsx +93 -0
  24. package/examples/greenfield/module-hybrid-cdn/src/features/starter/components/starter-home-page.tsx +21 -0
  25. package/examples/greenfield/module-hybrid-cdn/src/features/starter/components/starter-home.tsx +52 -0
  26. package/examples/greenfield/module-hybrid-cdn/src/features/starter/components/starter-single-page.tsx +17 -0
  27. package/examples/greenfield/module-hybrid-cdn/src/features/starter/content/woodscli-guide-content.ts +86 -0
  28. package/examples/greenfield/module-hybrid-cdn/src/features/starter/hooks/use-starter-preview.ts +47 -0
  29. package/examples/greenfield/module-hybrid-cdn/src/features/starter/index.ts +6 -0
  30. package/examples/greenfield/module-hybrid-cdn/src/hubspot/bootstrap.ts +10 -0
  31. package/examples/greenfield/module-hybrid-cdn/src/hubspot/default-data.ts +7 -0
  32. package/examples/greenfield/module-hybrid-cdn/src/integrations/tanstack-router/router.tsx +25 -0
  33. package/examples/greenfield/module-hybrid-cdn/src/main.tsx +4 -3
  34. package/examples/greenfield/module-hybrid-cdn/src/portal/mount-dev-preview.tsx +8 -0
  35. package/examples/greenfield/module-hybrid-cdn/src/portal/mount-portal.tsx +12 -0
  36. package/examples/greenfield/module-hybrid-cdn/src/routeTree.gen.ts +77 -0
  37. package/examples/greenfield/module-hybrid-cdn/src/routes/__root.tsx +15 -0
  38. package/examples/greenfield/module-hybrid-cdn/src/routes/guide.tsx +7 -0
  39. package/examples/greenfield/module-hybrid-cdn/src/routes/index.tsx +7 -0
  40. package/examples/greenfield/module-hybrid-cdn/tsconfig.json +20 -0
  41. package/examples/greenfield/module-monolith/public/fields.json +44 -1
  42. package/examples/greenfield/module-monolith/src/app.tsx +8 -0
  43. package/examples/greenfield/module-monolith/src/assets/css/main.dev.css +8 -0
  44. package/examples/greenfield/module-monolith/src/components/layout/section-card.tsx +20 -0
  45. package/examples/greenfield/module-monolith/src/components/layout/starter-nav.tsx +28 -0
  46. package/examples/greenfield/module-monolith/src/components/layout/starter-shell.tsx +18 -0
  47. package/examples/greenfield/module-monolith/src/config/router.ts +4 -0
  48. package/examples/greenfield/module-monolith/src/config/routes.ts +5 -0
  49. package/examples/greenfield/module-monolith/src/defaultData.ts +2 -7
  50. package/examples/greenfield/module-monolith/src/features/starter/components/starter-guide-page.tsx +93 -0
  51. package/examples/greenfield/module-monolith/src/features/starter/components/starter-home-page.tsx +21 -0
  52. package/examples/greenfield/module-monolith/src/features/starter/components/starter-home.tsx +52 -0
  53. package/examples/greenfield/module-monolith/src/features/starter/components/starter-single-page.tsx +17 -0
  54. package/examples/greenfield/module-monolith/src/features/starter/content/woodscli-guide-content.ts +86 -0
  55. package/examples/greenfield/module-monolith/src/features/starter/hooks/use-starter-preview.ts +47 -0
  56. package/examples/greenfield/module-monolith/src/features/starter/index.ts +6 -0
  57. package/examples/greenfield/module-monolith/src/hubspot/default-data.ts +7 -0
  58. package/examples/greenfield/module-monolith/src/hubspot/types.ts +17 -0
  59. package/examples/greenfield/module-monolith/src/integrations/tanstack-router/router.tsx +25 -0
  60. package/examples/greenfield/module-monolith/src/main.tsx +5 -0
  61. package/examples/greenfield/module-monolith/src/portal/mount-dev-preview.tsx +8 -0
  62. package/examples/greenfield/module-monolith/src/portal/mount-portal.tsx +12 -0
  63. package/examples/greenfield/module-monolith/src/routeTree.gen.ts +77 -0
  64. package/examples/greenfield/module-monolith/src/routes/__root.tsx +15 -0
  65. package/examples/greenfield/module-monolith/src/routes/guide.tsx +7 -0
  66. package/examples/greenfield/module-monolith/src/routes/index.tsx +7 -0
  67. package/examples/greenfield/module-monolith/tsconfig.json +20 -0
  68. package/package.json +4 -1
  69. package/scripts/check-hubspot-bundle-size.mjs +5 -2
  70. package/scripts/ensure-wphs-workspace.mjs +2 -1
  71. package/scripts/hubspot-module-postbuild.mjs +1 -1
  72. package/scripts/read-woodsportal-config.mjs +4 -1
  73. package/scripts/run-hubspot-module-postbuild.mjs +9 -4
  74. package/scripts/vite/bootstrap-shim-resolver.js +47 -0
  75. package/scripts/vite/ensure-dev-kit-shims.js +7 -1
  76. package/scripts/vite/react-dev-plugin-options.js +2 -1
  77. package/scripts/watch-hubspot.mjs +107 -17
  78. package/scripts/wphs-paths.mjs +1 -0
  79. package/scripts/write-audit-artifacts.mjs +2 -1
  80. package/src/dev/bootstrap-greenfield.tsx +59 -0
  81. package/src/dev/bootstrap.tsx +46 -0
  82. package/src/dev-module-config/__tests__/fixtures/fields.json +3014 -0
  83. package/src/dev-module-config/__tests__/fixtures/golden-module.fixture.ts +102 -0
  84. package/src/dev-module-config/__tests__/module-config-storage.test.ts +40 -0
  85. package/src/dev-module-config/__tests__/module-config-transform.test.ts +55 -0
  86. package/src/dev-module-config/__tests__/normalize-repeater-items.test.ts +46 -0
  87. package/src/dev-module-config/dev-module-display-name.ts +5 -0
  88. package/src/dev-module-config/runtime/module-config-bridge.ts +27 -0
  89. package/src/dev-module-config/runtime/module-config-runtime.ts +185 -0
  90. package/src/dev-module-config/schema/build-default-item.ts +7 -0
  91. package/src/dev-module-config/schema/deep-merge.ts +27 -0
  92. package/src/dev-module-config/schema/extract-defaults.ts +62 -0
  93. package/src/dev-module-config/schema/normalize-choices.ts +18 -0
  94. package/src/dev-module-config/schema/normalize-repeater-items.ts +31 -0
  95. package/src/dev-module-config/schema/parse-fields-json.ts +2 -0
  96. package/src/dev-module-config/schema/types.ts +75 -0
  97. package/src/dev-module-config/schema/validate-module-config.ts +81 -0
  98. package/src/dev-module-config/schema/visibility.ts +130 -0
  99. package/src/dev-module-config/storage/config-json.ts +46 -0
  100. package/src/dev-module-config/storage/workspace-store.ts +139 -0
  101. package/src/dev-module-config/transform/build-hubspot-data.ts +409 -0
  102. package/src/dev-module-config/ui/FieldRenderer.tsx +353 -0
  103. package/src/dev-module-config/ui/ModuleConfigAnimatedPresence.tsx +72 -0
  104. package/src/dev-module-config/ui/ModuleConfigCollapsible.tsx +43 -0
  105. package/src/dev-module-config/ui/ModuleConfigDockSideIcon.tsx +27 -0
  106. package/src/dev-module-config/ui/ModuleConfigOverlay.tsx +134 -0
  107. package/src/dev-module-config/ui/ModuleConfigPersistenceStatus.tsx +89 -0
  108. package/src/dev-module-config/ui/ModuleConfigShell.tsx +355 -0
  109. package/src/dev-module-config/ui/ModuleConfigThemeToggle.tsx +32 -0
  110. package/src/dev-module-config/ui/ModuleConfigUiContext.tsx +65 -0
  111. package/src/dev-module-config/ui/editors/DeveloperOptionsEditor.tsx +61 -0
  112. package/src/dev-module-config/ui/editors/MenuOptionsEditor.tsx +103 -0
  113. package/src/dev-module-config/ui/hubspot/HsColorField.tsx +106 -0
  114. package/src/dev-module-config/ui/hubspot/HsColorPickerPopover.tsx +210 -0
  115. package/src/dev-module-config/ui/hubspot/HsFieldLabel.tsx +24 -0
  116. package/src/dev-module-config/ui/hubspot/HsFieldWidgets.tsx +248 -0
  117. package/src/dev-module-config/ui/hubspot/HsImageField.tsx +112 -0
  118. package/src/dev-module-config/ui/hubspot/HsOccurrenceGroupEditor.tsx +243 -0
  119. package/src/dev-module-config/ui/hubspot/HsRepeaterList.tsx +178 -0
  120. package/src/dev-module-config/ui/hubspot/HsSectionHeader.tsx +20 -0
  121. package/src/dev-module-config/ui/hubspot/HsToggle.tsx +39 -0
  122. package/src/dev-module-config/ui/hubspot/HsToggleRow.tsx +30 -0
  123. package/src/dev-module-config/ui/hubspot/hs-color-palette.ts +11 -0
  124. package/src/dev-module-config/ui/hubspot/module-config-typography.ts +26 -0
  125. package/src/dev-module-config/ui/module-config-motion.css +134 -0
  126. package/src/dev-module-config/ui/module-config-motion.ts +28 -0
  127. package/src/dev-module-config/ui/module-config-overlay-side.ts +29 -0
  128. package/src/dev-module-config/ui/module-config-surfaces.ts +27 -0
  129. package/src/dev-module-config/ui/module-config-theme.css +489 -0
  130. package/src/dev-module-config/ui/module-config-toolbar-theme.ts +35 -0
  131. package/src/dev-module-config/ui/navigation/ModuleConfigNavContext.tsx +194 -0
  132. package/src/dev-module-config/ui/use-dev-module-config-live-revision.ts +22 -0
  133. package/src/dev-module-config/ui/use-hubspot-live-exports.ts +27 -0
  134. package/src/dev-module-config/ui/use-module-config.ts +124 -0
  135. package/src/routing/build-api-routes.ts +37 -0
  136. package/src/routing/route-format.ts +19 -0
  137. package/templates/module-hybrid-cdn/README.md +53 -3
  138. package/templates/module-hybrid-cdn/index.html +12 -1
  139. package/templates/module-hybrid-cdn/package.json +6 -2
  140. package/templates/module-hybrid-cdn/public/fields.json +44 -1
  141. package/templates/module-hybrid-cdn/src/app.tsx +8 -0
  142. package/templates/module-hybrid-cdn/src/assets/css/main.dev.css +6 -1
  143. package/templates/module-hybrid-cdn/src/cdn/app-entry.ts +32 -0
  144. package/templates/module-hybrid-cdn/src/cdn/vendor-entry.ts +28 -0
  145. package/templates/module-hybrid-cdn/src/components/layout/section-card.tsx +20 -0
  146. package/templates/module-hybrid-cdn/src/components/layout/starter-nav.tsx +28 -0
  147. package/templates/module-hybrid-cdn/src/components/layout/starter-shell.tsx +18 -0
  148. package/templates/module-hybrid-cdn/src/config/router.ts +4 -0
  149. package/templates/module-hybrid-cdn/src/config/routes.ts +5 -0
  150. package/templates/module-hybrid-cdn/src/defaultData.ts +2 -7
  151. package/templates/module-hybrid-cdn/src/features/starter/components/starter-guide-page.tsx +93 -0
  152. package/templates/module-hybrid-cdn/src/features/starter/components/starter-home-page.tsx +21 -0
  153. package/templates/module-hybrid-cdn/src/features/starter/components/starter-home.tsx +52 -0
  154. package/templates/module-hybrid-cdn/src/features/starter/components/starter-single-page.tsx +17 -0
  155. package/templates/module-hybrid-cdn/src/features/starter/content/woodscli-guide-content.ts +86 -0
  156. package/templates/module-hybrid-cdn/src/features/starter/hooks/starter-preview-values.ts +42 -0
  157. package/templates/module-hybrid-cdn/src/features/starter/hooks/use-starter-preview.dev.ts +17 -0
  158. package/templates/module-hybrid-cdn/src/features/starter/hooks/use-starter-preview.ts +30 -0
  159. package/templates/module-hybrid-cdn/src/features/starter/index.ts +6 -0
  160. package/templates/module-hybrid-cdn/src/hubspot/bootstrap.ts +10 -0
  161. package/templates/module-hybrid-cdn/src/hubspot/default-data.ts +7 -0
  162. package/templates/module-hybrid-cdn/src/hubspot/module-entry.tsx +9 -0
  163. package/templates/module-hybrid-cdn/src/integrations/tanstack-router/router.tsx +25 -0
  164. package/templates/module-hybrid-cdn/src/main.tsx +4 -3
  165. package/templates/module-hybrid-cdn/src/portal/mount-dev-preview.tsx +8 -0
  166. package/templates/module-hybrid-cdn/src/portal/mount-portal.tsx +12 -0
  167. package/templates/module-hybrid-cdn/src/routeTree.gen.ts +77 -0
  168. package/templates/module-hybrid-cdn/src/routes/__root.tsx +15 -0
  169. package/templates/module-hybrid-cdn/src/routes/guide.tsx +7 -0
  170. package/templates/module-hybrid-cdn/src/routes/index.tsx +7 -0
  171. package/templates/module-hybrid-cdn/tsconfig.json +20 -0
  172. package/templates/module-hybrid-cdn/vite.config.monolith.mjs +8 -0
  173. package/templates/module-monolith/README.md +59 -0
  174. package/templates/module-monolith/index.html +12 -0
  175. package/templates/module-monolith/package.json +10 -3
  176. package/templates/module-monolith/public/fields.json +44 -1
  177. package/templates/module-monolith/public/module.html +1 -0
  178. package/templates/module-monolith/src/app.tsx +8 -0
  179. package/templates/module-monolith/src/assets/css/main.dev.css +6 -1
  180. package/templates/module-monolith/src/components/layout/section-card.tsx +20 -0
  181. package/templates/module-monolith/src/components/layout/starter-nav.tsx +28 -0
  182. package/templates/module-monolith/src/components/layout/starter-shell.tsx +18 -0
  183. package/templates/module-monolith/src/config/router.ts +4 -0
  184. package/templates/module-monolith/src/config/routes.ts +5 -0
  185. package/templates/module-monolith/src/defaultData.ts +2 -7
  186. package/templates/module-monolith/src/features/starter/components/starter-guide-page.tsx +93 -0
  187. package/templates/module-monolith/src/features/starter/components/starter-home-page.tsx +21 -0
  188. package/templates/module-monolith/src/features/starter/components/starter-home.tsx +52 -0
  189. package/templates/module-monolith/src/features/starter/components/starter-single-page.tsx +17 -0
  190. package/templates/module-monolith/src/features/starter/content/woodscli-guide-content.ts +86 -0
  191. package/templates/module-monolith/src/features/starter/hooks/starter-preview-values.ts +42 -0
  192. package/templates/module-monolith/src/features/starter/hooks/use-starter-preview.dev.ts +17 -0
  193. package/templates/module-monolith/src/features/starter/hooks/use-starter-preview.ts +30 -0
  194. package/templates/module-monolith/src/features/starter/index.ts +6 -0
  195. package/templates/module-monolith/src/hubspot/default-data.ts +7 -0
  196. package/templates/module-monolith/src/hubspot/module-entry.tsx +9 -0
  197. package/templates/module-monolith/src/integrations/tanstack-router/router.tsx +25 -0
  198. package/templates/module-monolith/src/main.tsx +4 -3
  199. package/templates/module-monolith/src/portal/mount-dev-preview.tsx +8 -0
  200. package/templates/module-monolith/src/portal/mount-portal.tsx +12 -0
  201. package/templates/module-monolith/src/routeTree.gen.ts +77 -0
  202. package/templates/module-monolith/src/routes/__root.tsx +15 -0
  203. package/templates/module-monolith/src/routes/guide.tsx +7 -0
  204. package/templates/module-monolith/src/routes/index.tsx +7 -0
  205. package/templates/module-monolith/tsconfig.json +20 -0
  206. package/templates/module-monolith/vite.config.monolith.mjs +8 -0
  207. package/templates/module-monolith/woodscli.json +1 -0
  208. package/templates/shared/.env.dev.example +5 -0
  209. package/templates/shared/.env.prod.example +5 -0
  210. package/templates/shared/.env.stg.example +3 -0
  211. package/templates/shared/portal.cdn.json.example +8 -0
  212. package/templates/theme-starter/package.json +5 -2
  213. package/vite/vite.config.dev.mjs +9 -1
  214. package/vite/vite.config.monolith.mjs +22 -17
  215. package/dist/chunk-JDGIAYHX.js.map +0 -1
  216. package/dist/exec-K5C6LZP4.js +0 -10
  217. /package/dist/{exec-K5C6LZP4.js.map → exec-U2OJATR3.js.map} +0 -0
@@ -3,15 +3,21 @@
3
3
  * HubSpot CMS watch — uses woodscli.json upload paths.
4
4
  */
5
5
  import { spawn, spawnSync } from 'node:child_process'
6
- import { watch } from 'node:fs'
7
- import { resolve } from 'node:path'
6
+ import { existsSync, watch } from 'node:fs'
7
+ import { dirname, resolve } from 'node:path'
8
+ import { fileURLToPath } from 'node:url'
8
9
 
9
10
  import { moduleOutDir, moduleUploadPath, readWoodsportalConfig, themeUploadPath } from './read-woodsportal-config.mjs'
10
11
 
12
+ const kitScriptsDir = dirname(fileURLToPath(import.meta.url))
13
+ const kitRoot = resolve(kitScriptsDir, '..')
14
+ const kitCli = resolve(kitRoot, 'dist/cli.js')
15
+
16
+ const argv = process.argv.slice(2)
17
+ const rebuild = argv.includes('--rebuild')
18
+ const tier = parseTier(argv)
19
+
11
20
  const { root, config } = readWoodsportalConfig()
12
- const rebuild = process.argv.includes('--rebuild')
13
- const isProd = process.argv.includes('--prod')
14
- const buildScript = isProd ? 'build:prod' : 'build:dev'
15
21
 
16
22
  const isTheme = config?.projectType === 'theme-starter'
17
23
  const hubspotModulePath = moduleOutDir(root)
@@ -22,13 +28,85 @@ const watchRoots = isTheme
22
28
  ? [theme.srcDir]
23
29
  : ['src', 'public'].map((dir) => resolve(root, dir))
24
30
 
31
+ /** @type {import('node:child_process').ChildProcess | null} */
32
+ let cmsChild = null
33
+ /** @type {ReturnType<typeof setTimeout> | null} */
34
+ let debounceTimer = null
35
+ /** @type {import('node:fs').FSWatcher[]} */
36
+ const fsWatchers = []
37
+ let shuttingDown = false
38
+
39
+ function parseTier(args) {
40
+ const idx = args.indexOf('--tier')
41
+ if (idx >= 0 && args[idx + 1]) {
42
+ const value = args[idx + 1]
43
+ if (value === 'dev' || value === 'stg' || value === 'prod') return value
44
+ }
45
+ if (args.includes('--prod')) return 'prod'
46
+ if (args.includes('--stg')) return 'stg'
47
+ return 'dev'
48
+ }
49
+
25
50
  function log(msg) {
26
51
  console.log(`[watch] ${msg}`)
27
52
  }
28
53
 
29
- function runYarn(script) {
30
- const result = spawnSync('yarn', [script], { cwd: root, stdio: 'inherit' })
31
- if (result.status !== 0) process.exit(result.status ?? 1)
54
+ function shutdown(signal) {
55
+ if (shuttingDown) return
56
+ shuttingDown = true
57
+
58
+ if (debounceTimer) {
59
+ clearTimeout(debounceTimer)
60
+ debounceTimer = null
61
+ }
62
+
63
+ for (const watcher of fsWatchers) {
64
+ try {
65
+ watcher.close()
66
+ } catch {
67
+ // ignore
68
+ }
69
+ }
70
+
71
+ if (cmsChild && !cmsChild.killed) {
72
+ cmsChild.kill(signal)
73
+ return
74
+ }
75
+
76
+ process.exit(signal === 'SIGINT' ? 130 : 143)
77
+ }
78
+
79
+ process.on('SIGINT', () => shutdown('SIGINT'))
80
+ process.on('SIGTERM', () => shutdown('SIGTERM'))
81
+
82
+ /**
83
+ * Run wp build from the same @woodsportal/hubspot-kit package as this script.
84
+ * Avoids consumer node_modules/.bin/wp (often an older pin with wrong outDir).
85
+ */
86
+ function runWpBuild() {
87
+ const env = { ...process.env, WP_HS_PROJECT_ROOT: root }
88
+
89
+ let command = process.execPath
90
+ let args = []
91
+
92
+ if (existsSync(kitCli)) {
93
+ args = [kitCli, 'build', '--tier', tier, '--quiet']
94
+ } else {
95
+ const localWp = resolve(root, 'node_modules', '.bin', 'wp')
96
+ command = existsSync(localWp) ? localWp : 'wp'
97
+ args = ['build', '--tier', tier, '--quiet']
98
+ }
99
+
100
+ log(`Running wp build --tier ${tier} …`)
101
+ const result = spawnSync(command, args, {
102
+ cwd: root,
103
+ stdio: 'inherit',
104
+ env,
105
+ shell: command === 'wp',
106
+ })
107
+ if (result.status !== 0) {
108
+ process.exit(result.status ?? 1)
109
+ }
32
110
  }
33
111
 
34
112
  function runBuild() {
@@ -36,19 +114,22 @@ function runBuild() {
36
114
  log('Theme project — no module build step')
37
115
  return
38
116
  }
39
- log(`Running ${buildScript} …`)
40
- runYarn(buildScript)
117
+ runWpBuild()
41
118
  }
42
119
 
43
120
  function startCmsWatch() {
44
121
  const src = isTheme ? theme.srcDir : hubspotModulePath
45
122
  const target = isTheme ? theme.uploadPath : hubspotUploadTarget
46
123
  log(`Starting hs cms watch ${src} → ${target}`)
47
- return spawn('hs', ['cms', 'watch', src, target], { cwd: root, stdio: 'inherit' })
124
+ cmsChild = spawn('hs', ['cms', 'watch', src, target], { cwd: root, stdio: 'inherit' })
125
+ cmsChild.on('exit', (code) => {
126
+ if (shuttingDown) return
127
+ process.exit(code ?? 0)
128
+ })
129
+ return cmsChild
48
130
  }
49
131
 
50
132
  function startRebuildWatcher() {
51
- let debounceTimer = null
52
133
  let building = false
53
134
  let pending = false
54
135
 
@@ -75,12 +156,21 @@ function startRebuildWatcher() {
75
156
  }
76
157
 
77
158
  for (const watchRoot of watchRoots) {
78
- watch(watchRoot, { recursive: true }, () => scheduleBuild())
159
+ const watcher = watch(watchRoot, { recursive: true }, () => scheduleBuild())
160
+ fsWatchers.push(watcher)
161
+ log(`Watching ${watchRoot}`)
79
162
  }
80
163
  }
81
164
 
82
- if (!isTheme) runBuild()
83
- const cms = startCmsWatch()
84
- if (rebuild && !isTheme) startRebuildWatcher()
165
+ if (!isTheme) {
166
+ const moduleJs = resolve(hubspotModulePath, 'module.js')
167
+ if (!existsSync(moduleJs)) {
168
+ log('Module dist missing — building before watch')
169
+ runBuild()
170
+ } else if (rebuild) {
171
+ runBuild()
172
+ }
173
+ }
85
174
 
86
- cms.on('exit', (code) => process.exit(code ?? 0))
175
+ startCmsWatch()
176
+ if (rebuild && !isTheme) startRebuildWatcher()
@@ -68,6 +68,7 @@ export function wphsPaths(projectRoot) {
68
68
  stateDir: join(workspaceRoot, 'state'),
69
69
  kitModuleConfigLink: join(workspaceRoot, '.kit-module-config'),
70
70
  kitBootstrapLink: join(workspaceRoot, '.kit-bootstrap.tsx'),
71
+ kitBootstrapGreenfieldLink: join(workspaceRoot, '.kit-bootstrap-greenfield.tsx'),
71
72
  readmePath: join(workspaceRoot, 'README.md'),
72
73
  brandingAssetsUrlPrefix: `/${workspaceDir}/assets/branding/`,
73
74
  legacyBrandingAssetsUrlPrefixes: [
@@ -6,6 +6,7 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from
6
6
  import { resolve, dirname } from 'node:path'
7
7
  import { fileURLToPath } from 'node:url'
8
8
  import { findProjectRoot } from './project-root.mjs'
9
+ import { moduleOutDir } from './read-woodsportal-config.mjs'
9
10
  import { gzipSync } from 'node:zlib'
10
11
 
11
12
  const root = findProjectRoot()
@@ -33,7 +34,7 @@ const report = {
33
34
  cdn: {},
34
35
  }
35
36
 
36
- const moduleDir = resolve(root, 'dist/WoodsPortal.Module')
37
+ const moduleDir = moduleOutDir(root)
37
38
  for (const name of ['module.js', 'module.css', 'module.html', 'fields.json']) {
38
39
  const path = resolve(moduleDir, name)
39
40
  if (existsSync(path)) {
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Greenfield / wp init dev shell — module-config overlay only (no full portal app).
3
+ * Use after `wp init`; adopt `dev/bootstrap` when wiring a real WoodsPortal consumer app.
4
+ */
5
+ import { createRoot } from 'react-dom/client'
6
+ import type { ReactNode } from 'react'
7
+
8
+ import {
9
+ bindModuleConfigToHubSpotData,
10
+ setModuleConfigAdapter,
11
+ syncHubSpotDataFromModuleState,
12
+ } from '@/dev/module-config/runtime/module-config-bridge'
13
+ import { initModuleConfigRuntime } from '@/dev/module-config/runtime/module-config-runtime'
14
+ import {
15
+ ModuleConfigOverlay,
16
+ registerModuleConfigShortcutHint,
17
+ } from '@/dev/module-config/ui/ModuleConfigOverlay'
18
+ import wphsAdapter from '@wphs/adapter'
19
+
20
+ export type MountGreenfieldDevOptions = {
21
+ /** Scaffold-owned preview (e.g. templates/src/app/StarterPage.tsx). */
22
+ preview?: ReactNode
23
+ }
24
+
25
+ export async function mountGreenfieldDev(options: MountGreenfieldDevOptions = {}): Promise<void> {
26
+ const rootElement = document.getElementById('app')
27
+
28
+ try {
29
+ setModuleConfigAdapter(wphsAdapter)
30
+ bindModuleConfigToHubSpotData()
31
+ const moduleState = await initModuleConfigRuntime()
32
+ syncHubSpotDataFromModuleState(moduleState)
33
+ registerModuleConfigShortcutHint()
34
+
35
+ if (!rootElement) {
36
+ throw new Error('Missing #app element — add index.html with <div id="app">')
37
+ }
38
+
39
+ createRoot(rootElement).render(
40
+ <div>
41
+ <ModuleConfigOverlay />
42
+ {options.preview ?? (
43
+ <main style={{ padding: '1.5rem', fontFamily: 'system-ui, sans-serif' }}>
44
+ <h1>WoodsCLI dev</h1>
45
+ <p>
46
+ Edit HubSpot module fields with <kbd>Ctrl+Shift+Z</kbd> (Mac: <kbd>⌃⇧Z</kbd>).
47
+ </p>
48
+ </main>
49
+ )}
50
+ </div>
51
+ )
52
+ } catch (error) {
53
+ const message = error instanceof Error ? error.message : String(error)
54
+ if (rootElement) {
55
+ rootElement.innerHTML = `<pre style="padding:1rem;font-family:system-ui;color:#b91c1c;white-space:pre-wrap">WoodsCLI dev failed to start:\n${message}</pre>`
56
+ }
57
+ console.error('[woodscli] mountGreenfieldDev failed', error)
58
+ }
59
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Kit-owned local dev bootstrap — module-config overlay + live export provider.
3
+ * Never imported in production CDN/HubSpot builds.
4
+ */
5
+ import { createRoot } from 'react-dom/client'
6
+
7
+ import { mountPortal, router } from '@/portal/mount-portal'
8
+ import {
9
+ bindModuleConfigToHubSpotData,
10
+ setModuleConfigAdapter,
11
+ syncHubSpotDataFromModuleState,
12
+ } from '@/dev/module-config/runtime/module-config-bridge'
13
+ import { initModuleConfigRuntime } from '@/dev/module-config/runtime/module-config-runtime'
14
+ import {
15
+ ModuleConfigOverlay,
16
+ registerModuleConfigShortcutHint,
17
+ } from '@/dev/module-config/ui/ModuleConfigOverlay'
18
+ import { useDevModuleConfigLiveRevision } from '@/dev/module-config/ui/use-dev-module-config-live-revision'
19
+ import { DevHubSpotLiveProvider } from '@/integrations/dev-hubspot-live-provider'
20
+ import { App } from '@/app'
21
+ import wphsAdapter from '@wphs/adapter'
22
+
23
+ export async function mountDevPortal(): Promise<void> {
24
+ setModuleConfigAdapter(wphsAdapter)
25
+ bindModuleConfigToHubSpotData()
26
+ const moduleState = await initModuleConfigRuntime()
27
+ syncHubSpotDataFromModuleState(moduleState)
28
+ registerModuleConfigShortcutHint()
29
+
30
+ await mountPortal({ includeGlobalStyles: true, skipAppRender: true })
31
+
32
+ const rootElement = document.getElementById('app')
33
+ if (!rootElement) return
34
+
35
+ function DevRoot() {
36
+ const revision = useDevModuleConfigLiveRevision()
37
+ return (
38
+ <DevHubSpotLiveProvider revision={revision}>
39
+ <ModuleConfigOverlay />
40
+ <App router={router} />
41
+ </DevHubSpotLiveProvider>
42
+ )
43
+ }
44
+
45
+ createRoot(rootElement).render(<DevRoot />)
46
+ }