@woodsportal/hubspot-kit 1.0.36 → 1.0.37

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.
package/CHANGELOG.md CHANGED
@@ -19,6 +19,11 @@
19
19
  - **CSS entries** — shared `tailwind.css.config.css`; documented never-merge rules on `main.dev.css` / `main.prod.css`
20
20
  - **`wp doctor`** — CSS pipeline checks (prefix, `.temp` @source, `skipRuntimeCss`, `module.css` dw utilities, CDN `require_css` warning)
21
21
 
22
+ ## 1.0.37 — 2026-06-08
23
+
24
+ ### Dev server
25
+ - **Consumer dep resolution** — replace `createRequire` / `require.resolve` with a filesystem `package.json` exports resolver for Vite, React plugins, and JSX runtime aliases; fixes `getStatus` crash on Node 24+ when starting `yarn local`
26
+
22
27
  ## 1.0.36 — 2026-06-08
23
28
 
24
29
  ### Dev server
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@woodsportal/hubspot-kit",
3
- "version": "1.0.36",
3
+ "version": "1.0.37",
4
4
  "description": "WoodsCLI — HubSpot CMS dev kit by WoodsPortal. wp CLI, Vite presets, module-config overlay, and theme/module build pipelines.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -51,7 +51,7 @@
51
51
  "build": "tsup",
52
52
  "dev": "tsup --watch",
53
53
  "typecheck": "tsc --noEmit",
54
- "test": "node --import tsx --test 'src/lib/**/*.test.ts' 'src/schema/**/*.test.ts' 'src/vite/**/*.test.ts' 'scripts/portal-build-id.test.mjs' 'scripts/vite/ensure-dev-kit-shims.test.mjs' 'scripts/vite/consumer-react-aliases.test.mjs' && vitest run src/dev-module-config/__tests__/normalize-repeater-items.test.ts src/dev-module-config/__tests__/module-config-transform.test.ts src/dev-module-config/__tests__/flatten-visible-fields.test.ts",
54
+ "test": "node --import tsx --test 'src/lib/**/*.test.ts' 'src/schema/**/*.test.ts' 'src/vite/**/*.test.ts' 'scripts/portal-build-id.test.mjs' 'scripts/resolve-consumer-dep.test.mjs' 'scripts/vite/ensure-dev-kit-shims.test.mjs' 'scripts/vite/consumer-react-aliases.test.mjs' && vitest run src/dev-module-config/__tests__/normalize-repeater-items.test.ts src/dev-module-config/__tests__/module-config-transform.test.ts src/dev-module-config/__tests__/flatten-visible-fields.test.ts",
55
55
  "test:examples": "node examples/smoke/run-matrix.mjs --tier static",
56
56
  "lint": "eslint src",
57
57
  "verify": "npm run typecheck && npm run test && npm run test:examples && npm run build",
@@ -1,25 +1,90 @@
1
1
  /**
2
2
  * Resolve and import packages from the consumer project (woodscli.json root).
3
- * Kit scripts live under @woodsportal/hubspot-kit; Vite/React plugins are consumer deps.
3
+ * Pure filesystem resolution avoids createRequire (Node 24+ getStatus) and
4
+ * import.meta.resolve from kit context (wrong node_modules).
4
5
  */
5
- import { createRequire } from 'node:module'
6
- import { resolve } from 'node:path'
6
+ import { existsSync, readFileSync } from 'node:fs'
7
+ import { resolve, sep } from 'node:path'
7
8
  import { pathToFileURL } from 'node:url'
9
+
8
10
  import { findProjectRoot } from './project-root.mjs'
9
11
 
10
12
  /**
11
- * @param {string} specifier - package name or subpath export
13
+ * @param {string} specifier
14
+ * @param {string} projectRoot
15
+ */
16
+ function readPkgJson(projectRoot, pkgName) {
17
+ const pkgJsonPath = resolve(projectRoot, 'node_modules', ...pkgName.split('/'), 'package.json')
18
+ if (!existsSync(pkgJsonPath)) {
19
+ throw new Error(`Cannot find package '${pkgName}' under ${projectRoot}`)
20
+ }
21
+ return { pkgJsonPath, pkg: JSON.parse(readFileSync(pkgJsonPath, 'utf8')) }
22
+ }
23
+
24
+ /**
25
+ * @param {string} pkgRoot
26
+ * @param {string} target
27
+ */
28
+ function resolveTargetFile(pkgRoot, target) {
29
+ const rel = target.replace(/^\.\//, '')
30
+ const abs = resolve(pkgRoot, rel)
31
+ if (existsSync(abs)) return abs
32
+ if (existsSync(`${abs}.js`)) return `${abs}.js`
33
+ if (existsSync(`${abs}.mjs`)) return `${abs}.mjs`
34
+ if (existsSync(resolve(abs, 'index.js'))) return resolve(abs, 'index.js')
35
+ return abs
36
+ }
37
+
38
+ /**
39
+ * @param {unknown} exportEntry
40
+ * @returns {string | null}
12
41
  */
13
- export function resolveConsumerDep(specifier) {
14
- const root = findProjectRoot()
15
- const require = createRequire(resolve(root, 'package.json'))
16
- return require.resolve(specifier)
42
+ function pickExportTarget(exportEntry) {
43
+ if (typeof exportEntry === 'string') return exportEntry
44
+ if (!exportEntry || typeof exportEntry !== 'object') return null
45
+
46
+ const record = /** @type {Record<string, unknown>} */ (exportEntry)
47
+ for (const key of ['import', 'default', 'node', 'require', 'module-sync']) {
48
+ const val = record[key]
49
+ if (typeof val === 'string') return val
50
+ const nested = pickExportTarget(val)
51
+ if (nested) return nested
52
+ }
53
+ return null
54
+ }
55
+
56
+ /**
57
+ * @param {string} specifier e.g. vite, @vitejs/plugin-react, react/jsx-dev-runtime
58
+ * @param {string} projectRoot
59
+ */
60
+ export function resolveConsumerDep(specifier, projectRoot = findProjectRoot()) {
61
+ const segments = specifier.split('/')
62
+ const pkgName = segments[0].startsWith('@')
63
+ ? `${segments[0]}/${segments[1]}`
64
+ : segments[0]
65
+ const subpath = segments[0].startsWith('@') ? segments.slice(2).join('/') : segments.slice(1).join('/')
66
+ const pkgRoot = resolve(projectRoot, 'node_modules', ...pkgName.split('/'))
67
+ const { pkg } = readPkgJson(projectRoot, pkgName)
68
+
69
+ if (!subpath) {
70
+ const rootExport = pickExportTarget(pkg.exports?.['.']) ?? pkg.module ?? pkg.main ?? 'index.js'
71
+ return resolveTargetFile(pkgRoot, rootExport)
72
+ }
73
+
74
+ const exportKey = `./${subpath}`
75
+ const exportTarget = pickExportTarget(pkg.exports?.[exportKey])
76
+ if (exportTarget) {
77
+ return resolveTargetFile(pkgRoot, exportTarget)
78
+ }
79
+
80
+ return resolveTargetFile(pkgRoot, subpath)
17
81
  }
18
82
 
19
83
  /**
20
84
  * @param {string} specifier
85
+ * @param {string} [projectRoot]
21
86
  */
22
- export async function importConsumerDep(specifier) {
23
- const resolved = resolveConsumerDep(specifier)
24
- return import(pathToFileURL(resolved).href)
87
+ export async function importConsumerDep(specifier, projectRoot = findProjectRoot()) {
88
+ const abs = resolveConsumerDep(specifier, projectRoot)
89
+ return import(pathToFileURL(abs).href)
25
90
  }
@@ -0,0 +1,22 @@
1
+ import assert from 'node:assert/strict'
2
+ import { describe, it } from 'node:test'
3
+
4
+ import { importConsumerDep, resolveConsumerDep } from './resolve-consumer-dep.mjs'
5
+ import { consumerDepFixtureRoot } from './test-fixtures/consumer-dep-fixture-root.mjs'
6
+
7
+ describe('resolveConsumerDep', () => {
8
+ it('resolves vite from consumer node_modules via filesystem resolver', () => {
9
+ const vitePath = resolveConsumerDep('vite', consumerDepFixtureRoot)
10
+ assert.match(vitePath, /node_modules[/\\]vite[/\\]/)
11
+ })
12
+
13
+ it('imports vite without createRequire', async () => {
14
+ const vite = await importConsumerDep('vite', consumerDepFixtureRoot)
15
+ assert.equal(typeof vite.createServer, 'function')
16
+ })
17
+
18
+ it('resolves nested package exports (TanStack router vite subpath)', () => {
19
+ const path = resolveConsumerDep('@tanstack/router-plugin/vite', consumerDepFixtureRoot)
20
+ assert.match(path, /node_modules[/\\]@tanstack[/\\]router-plugin[/\\]/)
21
+ })
22
+ })
@@ -0,0 +1,3 @@
1
+ export function TanStackRouterVite() {
2
+ return { name: 'tanstack-router-vite-fixture' }
3
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@tanstack/router-plugin",
3
+ "type": "module",
4
+ "exports": {
5
+ "./vite": {
6
+ "import": {
7
+ "types": "./dist/esm/vite.d.ts",
8
+ "default": "./dist/esm/vite.js"
9
+ },
10
+ "require": {
11
+ "types": "./dist/cjs/vite.d.cts",
12
+ "default": "./dist/cjs/vite.cjs"
13
+ }
14
+ }
15
+ }
16
+ }
@@ -0,0 +1 @@
1
+ export function jsxDEV() {}
@@ -0,0 +1 @@
1
+ export function jsx() {}
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "react",
3
+ "type": "module",
4
+ "exports": {
5
+ "./jsx-dev-runtime": "./jsx-dev-runtime.js",
6
+ "./jsx-runtime": "./jsx-runtime.js"
7
+ }
8
+ }
@@ -0,0 +1 @@
1
+ export function createServer() {}
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "vite",
3
+ "type": "module",
4
+ "exports": {
5
+ ".": {
6
+ "import": "./dist/node/index.js",
7
+ "require": "./index.cjs"
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,8 @@
1
+ import { dirname, resolve } from 'node:path'
2
+ import { fileURLToPath } from 'node:url'
3
+
4
+ /** Portable fake consumer root — no sibling monorepo checkout required. */
5
+ export const consumerDepFixtureRoot = resolve(
6
+ dirname(fileURLToPath(import.meta.url)),
7
+ 'consumer-dep',
8
+ )
@@ -1,6 +1,4 @@
1
- import { createRequire } from 'node:module'
2
- import { resolve } from 'node:path'
3
- import { pathToFileURL } from 'node:url'
1
+ import { resolveConsumerDep } from '../resolve-consumer-dep.mjs'
4
2
 
5
3
  /** Subpath runtimes only — do not alias top-level `react` / `react-dom` (breaks `react/jsx-runtime`). */
6
4
  const REACT_RUNTIME_SPECS = [
@@ -15,13 +13,12 @@ const REACT_RUNTIME_SPECS = [
15
13
  * `node_modules/@woodsportal/hubspot-kit` never loads a mismatched CJS copy in the browser.
16
14
  */
17
15
  export function consumerReactAliases(projectRoot) {
18
- const require = createRequire(pathToFileURL(resolve(projectRoot, 'package.json')))
19
16
  /** @type {Record<string, string>} */
20
17
  const alias = {}
21
18
 
22
19
  for (const spec of REACT_RUNTIME_SPECS) {
23
20
  try {
24
- alias[spec] = require.resolve(spec)
21
+ alias[spec] = resolveConsumerDep(spec, projectRoot)
25
22
  } catch {
26
23
  // consumer may omit optional subpaths until install completes
27
24
  }
@@ -1,32 +1,12 @@
1
1
  import assert from 'node:assert/strict'
2
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
3
- import { tmpdir } from 'node:os'
4
- import { join, resolve } from 'node:path'
5
2
  import { describe, it } from 'node:test'
6
3
 
4
+ import { consumerDepFixtureRoot } from '../test-fixtures/consumer-dep-fixture-root.mjs'
7
5
  import { consumerReactAliases } from './consumer-react-aliases.js'
8
6
 
9
7
  describe('consumerReactAliases', () => {
10
8
  it('resolves react jsx runtimes from the consumer project root', () => {
11
- const root = mkdtempSync(join(tmpdir(), 'wp-react-alias-'))
12
- try {
13
- mkdirSync(join(root, 'node_modules', 'react'), { recursive: true })
14
- writeFileSync(
15
- join(root, 'node_modules', 'react', 'package.json'),
16
- JSON.stringify({
17
- name: 'react',
18
- exports: {
19
- './jsx-dev-runtime': './jsx-dev-runtime.js',
20
- },
21
- }),
22
- )
23
- writeFileSync(join(root, 'node_modules', 'react', 'jsx-dev-runtime.js'), 'export {}')
24
- writeFileSync(join(root, 'package.json'), JSON.stringify({ name: 'fixture', type: 'module' }))
25
-
26
- const alias = consumerReactAliases(root)
27
- assert.match(alias['react/jsx-dev-runtime'], /node_modules[/\\]react[/\\]jsx-dev-runtime\.js$/)
28
- } finally {
29
- rmSync(root, { recursive: true, force: true })
30
- }
9
+ const alias = consumerReactAliases(consumerDepFixtureRoot)
10
+ assert.match(alias['react/jsx-dev-runtime'], /node_modules[/\\]react[/\\]jsx-dev-runtime/)
31
11
  })
32
12
  })
@@ -1,15 +1,13 @@
1
- import { createRequire } from 'node:module'
2
1
  import { resolve, sep } from 'node:path'
3
- import { pathToFileURL } from 'node:url'
2
+
3
+ import { resolveConsumerDep } from '../resolve-consumer-dep.mjs'
4
4
 
5
5
  /**
6
6
  * When Vite transforms kit dev UI (`.wphs/`, package src, or dev-module-config),
7
7
  * bare imports must resolve from the consumer project's node_modules.
8
8
  */
9
9
  export default function resolveFromProjectRoot(projectRoot, kitRoot) {
10
- const require = createRequire(pathToFileURL(resolve(projectRoot, 'package.json')))
11
10
  const kitRootNorm = resolve(kitRoot)
12
- const wphsNorm = resolve(projectRoot, '.wphs')
13
11
 
14
12
  function isKitUiImporter(importer) {
15
13
  const norm = resolve(importer)
@@ -32,7 +30,7 @@ export default function resolveFromProjectRoot(projectRoot, kitRoot) {
32
30
  return null
33
31
  }
34
32
  try {
35
- return require.resolve(source)
33
+ return resolveConsumerDep(source, projectRoot)
36
34
  } catch {
37
35
  return null
38
36
  }