@michaelthielemann/kestrel 4.1.0 → 4.1.2

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.
@@ -1,38 +1,44 @@
1
1
  /**
2
- * The consumer-facing authoring API, registered as Nuxt/Nitro auto-imports so a site built on Kestrel
3
- * can write `defineCollection({...})` without importing it. Every name here is also importable
4
- * explicitly from its package; the auto-import is a convenience, not the only path.
2
+ * Kestrel's authoring API, registered as Nuxt/Nitro auto-imports so a site built on Kestrel can write
3
+ * `defineCollection({...})` or `getCollection('pages')` without importing the same surface a 3.x site
4
+ * had when this code still lived in the layers' `server/utils`. The names are read off the packages'
5
+ * real exports at build time, so a new public function is auto-importable the moment it is exported;
6
+ * every name stays importable explicitly from its package as well.
5
7
  */
6
8
  export interface AutoImportEntry {
7
9
  name: string
8
10
  from: string
9
11
  }
10
12
 
11
- const CORE = '@michaelthielemann/kestrel-core'
12
- const FIELDS = '@michaelthielemann/kestrel-fields'
13
- const ACCESS = '@michaelthielemann/kestrel-access'
13
+ const PKG = '@michaelthielemann/kestrel-'
14
14
 
15
- const entries = (from: string, names: string[]): AutoImportEntry[] => names.map((name) => ({ name, from }))
15
+ /** Order matters: a name exported by several packages (re-exports) is registered from the first one. */
16
+ const SERVER_PACKAGES = ['core', 'fields', 'contracts', 'auth', 'access', 'media', 'collections', 'publishing', 'delivery-live', 'delivery-static']
17
+ const APP_PACKAGES = ['core/client', 'fields/client']
16
18
 
17
- /** Server-only (Nitro) authoring API: collections, pipelines, revisions, field populators, access. */
18
- export const serverAutoImports: AutoImportEntry[] = [
19
- ...entries(CORE, [
20
- 'defineCollection',
21
- 'buildCollection',
22
- 'definePipeline',
23
- 'registerPipeline',
24
- 'registerAfterStep',
25
- 'syncStep',
26
- 'asyncStep',
27
- 'eventsOf',
28
- 'getFieldPopulator',
29
- 'readRevisions',
30
- 'registerRevisionUpcast',
31
- 'useDb',
32
- ]),
33
- ...entries(FIELDS, ['defineFieldType', 'constrain', 'opt']),
34
- ...entries(ACCESS, ['registerAccessGrant']),
35
- ]
19
+ /** `kestrelDiscovery`: module manifests for the discovery module, never something a site calls.
20
+ * `renderRouteLive`: the public layer's own `server/utils` wrapper of the same name is the wired one, and
21
+ * Nitro's directory scan already auto-imports it — registering the package export too only draws a
22
+ * "duplicated imports" warning on every build. */
23
+ const EXCLUDED = new Set(['default', 'kestrelDiscovery', 'renderRouteLive'])
36
24
 
37
- /** App-side (Vue) authoring API: block definitions live next to their components. */
38
- export const appAutoImports: AutoImportEntry[] = entries(`${FIELDS}/client`, ['defineBlock'])
25
+ async function collect(packages: string[]): Promise<AutoImportEntry[]> {
26
+ const seen = new Set<string>()
27
+ const entries: AutoImportEntry[] = []
28
+ for (const pkg of packages) {
29
+ const from = PKG + pkg
30
+ const mod = (await import(from)) as Record<string, unknown>
31
+ for (const name of Object.keys(mod)) {
32
+ if (EXCLUDED.has(name) || seen.has(name)) continue
33
+ seen.add(name)
34
+ entries.push({ name, from })
35
+ }
36
+ }
37
+ return entries
38
+ }
39
+
40
+ /** Server-only (Nitro) authoring API: every runtime export of the server packages. */
41
+ export const serverAutoImports = (): Promise<AutoImportEntry[]> => collect(SERVER_PACKAGES)
42
+
43
+ /** App-side (Vue) authoring API: every runtime export of the client entry points. */
44
+ export const appAutoImports = (): Promise<AutoImportEntry[]> => collect(APP_PACKAGES)
@@ -13,18 +13,30 @@ import { appAutoImports, serverAutoImports } from './auto-imports'
13
13
  */
14
14
  export default defineNuxtModule<KestrelConfig>({
15
15
  meta: { name: 'kestrel', configKey: 'kestrel' },
16
- setup(options, nuxt) {
16
+ async setup(options, nuxt) {
17
17
  const c = resolveKestrel(options, process.env, nuxt.options.rootDir)
18
18
 
19
19
  // Registered through hooks rather than `addImports`/`addServerImports`, which need an active Kit
20
20
  // instance (`useNuxt()`) that plain `setup()` callers (tests) do not provide.
21
+ const [app, server] = await Promise.all([appAutoImports(), serverAutoImports()])
22
+ // The packages' own compiled output must not be rewritten by the auto-import transform: it would
23
+ // inject an import for a symbol a dist file declares itself. Under `node_modules` the default exclusion
24
+ // covers that; in a workspace checkout the packages resolve to `packages/*/dist`, which it does not.
25
+ // Nitro REPLACES its `node_modules` default with any non-empty `exclude`, so that one is restated.
26
+ const ownDist = /[\\/](node_modules|packages)[\\/](@michaelthielemann[\\/])?kestrel-[^\\/]+[\\/]/
27
+ const imports = (nuxt.options.imports ||= {} as typeof nuxt.options.imports)
28
+ imports.transform ||= {}
29
+ imports.transform.exclude = [...(imports.transform.exclude ?? []), ownDist]
21
30
  nuxt.hook('imports:extend', (imports) => {
22
- imports.push(...appAutoImports)
31
+ imports.push(...app)
23
32
  })
24
33
  nuxt.hook('nitro:config', (config) => {
25
34
  config.imports ||= {}
26
35
  config.imports.imports ||= []
27
- config.imports.imports.push(...serverAutoImports)
36
+ config.imports.imports.push(...server)
37
+ const prior = config.imports.exclude
38
+ const excluded = Array.isArray(prior) ? [...prior] : prior ? [prior] : []
39
+ config.imports.exclude = [...excluded, /node_modules/, ownDist]
28
40
  })
29
41
 
30
42
  // `app:resolve` is the first hook where `mainComponent` is settled across all layers. In dev it fires
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@michaelthielemann/kestrel",
3
- "version": "4.1.0",
3
+ "version": "4.1.2",
4
4
  "description": "A slim, collection-driven Nuxt 4 CMS meta-layer with a runtime schema engine. Add `extends: ['@michaelthielemann/kestrel']`, define collections, and the database migrates itself.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Michael Thielemann <283621694+MichaelThielemann@users.noreply.github.com>",
@@ -76,16 +76,16 @@
76
76
  "thumbhash": "^0.1.1",
77
77
  "typescript": "^6.0.3",
78
78
  "zod": "^4.4.3",
79
+ "@michaelthielemann/kestrel-access": "0.1.0",
79
80
  "@michaelthielemann/kestrel-auth": "0.1.0",
81
+ "@michaelthielemann/kestrel-core": "0.1.0",
80
82
  "@michaelthielemann/kestrel-contracts": "0.1.0",
81
83
  "@michaelthielemann/kestrel-collections": "0.1.0",
82
- "@michaelthielemann/kestrel-core": "0.1.0",
83
- "@michaelthielemann/kestrel-access": "0.1.0",
84
- "@michaelthielemann/kestrel-delivery-live": "0.1.0",
85
- "@michaelthielemann/kestrel-fields": "0.1.0",
86
- "@michaelthielemann/kestrel-publishing": "0.1.0",
87
84
  "@michaelthielemann/kestrel-delivery-static": "0.1.0",
88
- "@michaelthielemann/kestrel-media": "0.1.0"
85
+ "@michaelthielemann/kestrel-fields": "0.1.0",
86
+ "@michaelthielemann/kestrel-delivery-live": "0.1.0",
87
+ "@michaelthielemann/kestrel-media": "0.1.0",
88
+ "@michaelthielemann/kestrel-publishing": "0.1.0"
89
89
  },
90
90
  "//peers": "Framework singletons the layer sources import by bare specifier. Peers, not dependencies: a second copy breaks identity (two Vue instances; an h3 v1 `createError` handed to an h3 v2 error handler, which surfaces our 400/404/409 as bare 500s). All optional, because kestrel's own `nuxt` dependency already supplies them transitively — the entry pins identity where a copy exists rather than demanding one, and a required peer would ERESOLVE-fail npm installs on any Nuxt whose bundled range we did not anticipate. Each is also a devDependency so this repo resolves it without auto-install-peers writing a phantom root dependency into the lockfile.",
91
91
  "peerDependencies": {