@nextsparkjs/core 0.1.0-beta.173 → 0.1.0-beta.174

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,5 +1,5 @@
1
1
  {
2
- "generated": "2026-06-23T13:21:29.773Z",
2
+ "generated": "2026-06-25T14:35:28.210Z",
3
3
  "totalClasses": 1081,
4
4
  "classes": [
5
5
  "!text-2xl",
@@ -24,8 +24,10 @@ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
24
24
  const VALID_PATH_PATTERNS = [
25
25
  // Entity folders
26
26
  /^(contents\/)?themes\/[\w-]+\/entities\/[\w-]+\/api\/docs\.md$/,
27
- // Theme routes
27
+ // Theme routes (legacy: docs mirrored under app/api)
28
28
  /^(contents\/)?themes\/[\w-]+\/app\/api\/.*\/docs\.md$/,
29
+ // Theme routes (colocated next to the handler under api/)
30
+ /^(contents\/)?themes\/[\w-]+\/api\/.*\/docs\.md$/,
29
31
  // Core routes (monorepo mode)
30
32
  /^packages\/core\/templates\/app\/api\/.*\/docs\.md$/,
31
33
  // Core routes (NPM mode)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextsparkjs/core",
3
- "version": "0.1.0-beta.173",
3
+ "version": "0.1.0-beta.174",
4
4
  "description": "NextSpark - The complete SaaS framework for Next.js",
5
5
  "license": "MIT",
6
6
  "author": "NextSpark <hello@nextspark.dev>",
@@ -469,7 +469,7 @@
469
469
  "tailwind-merge": "^3.3.1",
470
470
  "uuid": "^13.0.0",
471
471
  "zod": "^4.1.5",
472
- "@nextsparkjs/testing": "0.1.0-beta.173"
472
+ "@nextsparkjs/testing": "0.1.0-beta.174"
473
473
  },
474
474
  "scripts": {
475
475
  "postinstall": "node scripts/postinstall.mjs || true",
@@ -439,75 +439,84 @@ async function discoverEntityFolders(config, results, processedEndpoints) {
439
439
  */
440
440
  async function discoverThemeRoutes(config, results, processedEndpoints) {
441
441
  const themeName = config.activeTheme
442
- const themeApiDir = join(config.themesDir, themeName, 'app', 'api')
443
442
 
444
- if (!existsSync(themeApiDir)) {
445
- verbose(`No theme API routes found for "${themeName}"`)
446
- return
447
- }
443
+ // Process every docs.md / presets.ts under `baseDir`, mapping each route
444
+ // directory to an endpoint via `endpointForDir(routeDir)`.
445
+ const processTree = async (baseDir, endpointForDir) => {
446
+ if (!existsSync(baseDir)) return
447
+
448
+ const docFiles = await findFilesRecursive(baseDir, 'docs.md')
449
+ const presetFiles = await findFilesRecursive(baseDir, 'presets.ts')
450
+
451
+ for (const docsPath of docFiles) {
452
+ try {
453
+ const routeDir = dirname(docsPath)
454
+ const endpoint = endpointForDir(routeDir)
455
+ if (processedEndpoints.has(endpoint)) continue
456
+
457
+ const content = await readFile(docsPath, 'utf-8')
458
+ const title = extractMarkdownTitle(content)
459
+ const slug = basename(routeDir)
460
+
461
+ results.docs.push({
462
+ slug,
463
+ title,
464
+ endpoint,
465
+ filePath: getStoragePath(docsPath, config),
466
+ source: 'route',
467
+ themeName
468
+ })
469
+ verbose(` Theme route doc discovered: ${endpoint}`)
448
470
 
449
- // Find all docs.md files in theme routes
450
- const docFiles = await findFilesRecursive(themeApiDir, 'docs.md')
451
- const presetFiles = await findFilesRecursive(themeApiDir, 'presets.ts')
452
-
453
- // Process docs
454
- for (const docsPath of docFiles) {
455
- try {
456
- const routeDir = dirname(docsPath)
457
- const relativeDir = relative(join(config.themesDir, themeName, 'app'), routeDir)
458
- const endpoint = '/' + normalizePath(relativeDir)
459
-
460
- const content = await readFile(docsPath, 'utf-8')
461
- const title = extractMarkdownTitle(content)
462
-
463
- // Extract slug from endpoint
464
- const slug = basename(routeDir)
465
-
466
- results.docs.push({
467
- slug,
468
- title,
469
- endpoint,
470
- filePath: getStoragePath(docsPath, config),
471
- source: 'route',
472
- themeName
473
- })
474
- verbose(` Theme route doc discovered: ${endpoint}`)
475
-
476
- processedEndpoints.add(endpoint)
477
- } catch (error) {
478
- log(` ERROR: Failed to read theme route doc: ${error.message}`, 'error')
471
+ processedEndpoints.add(endpoint)
472
+ } catch (error) {
473
+ log(` ERROR: Failed to read theme route doc: ${error.message}`, 'error')
474
+ }
479
475
  }
480
- }
481
476
 
482
- // Process presets
483
- for (const presetsPath of presetFiles) {
484
- try {
485
- const routeDir = dirname(presetsPath)
486
- const relativeDir = relative(join(config.themesDir, themeName, 'app'), routeDir)
487
- const endpoint = '/' + normalizePath(relativeDir)
488
-
489
- const content = await readFile(presetsPath, 'utf-8')
490
- const presetConfig = parsePresetFile(content)
491
-
492
- const slug = basename(routeDir)
493
- const finalEndpoint = presetConfig?.endpoint || endpoint
494
-
495
- results.presets.push({
496
- slug,
497
- endpoint: finalEndpoint,
498
- summary: presetConfig?.summary || '',
499
- presets: presetConfig?.presets || [],
500
- sourcePath: getStoragePath(presetsPath, config),
501
- source: 'route',
502
- themeName
503
- })
504
- verbose(` Theme route presets discovered: ${finalEndpoint} (${presetConfig?.presets?.length || 0} presets)`)
505
-
506
- processedEndpoints.add(finalEndpoint)
507
- } catch (error) {
508
- log(` ERROR: Failed to parse theme route presets: ${error.message}`, 'error')
477
+ for (const presetsPath of presetFiles) {
478
+ try {
479
+ const routeDir = dirname(presetsPath)
480
+ const endpoint = endpointForDir(routeDir)
481
+
482
+ const content = await readFile(presetsPath, 'utf-8')
483
+ const presetConfig = parsePresetFile(content)
484
+
485
+ const slug = basename(routeDir)
486
+ const finalEndpoint = presetConfig?.endpoint || endpoint
487
+ if (processedEndpoints.has(finalEndpoint)) continue
488
+
489
+ results.presets.push({
490
+ slug,
491
+ endpoint: finalEndpoint,
492
+ summary: presetConfig?.summary || '',
493
+ presets: presetConfig?.presets || [],
494
+ sourcePath: getStoragePath(presetsPath, config),
495
+ source: 'route',
496
+ themeName
497
+ })
498
+ verbose(` Theme route presets discovered: ${finalEndpoint} (${presetConfig?.presets?.length || 0} presets)`)
499
+
500
+ processedEndpoints.add(finalEndpoint)
501
+ } catch (error) {
502
+ log(` ERROR: Failed to parse theme route presets: ${error.message}`, 'error')
503
+ }
509
504
  }
510
505
  }
506
+
507
+ // Legacy tree: {theme}/app/api/** — the docs path mirrors the full request URL
508
+ // under `app/` (e.g. app/api/v1/theme/{theme}/foo -> /api/v1/theme/{theme}/foo).
509
+ const appDir = join(config.themesDir, themeName, 'app')
510
+ await processTree(join(appDir, 'api'), (routeDir) =>
511
+ '/' + normalizePath(relative(appDir, routeDir))
512
+ )
513
+
514
+ // Colocated tree: {theme}/api/** — docs/presets live next to the route handler,
515
+ // mapped the same way the handlers are (api/foo -> /api/v1/theme/{theme}/foo).
516
+ const apiDir = join(config.themesDir, themeName, 'api')
517
+ await processTree(apiDir, (routeDir) =>
518
+ '/api/v1/theme/' + themeName + '/' + normalizePath(relative(apiDir, routeDir))
519
+ )
511
520
  }
512
521
 
513
522
  /**
@@ -24,8 +24,10 @@ import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
24
24
  const VALID_PATH_PATTERNS = [
25
25
  // Entity folders
26
26
  /^(contents\/)?themes\/[\w-]+\/entities\/[\w-]+\/api\/docs\.md$/,
27
- // Theme routes
27
+ // Theme routes (legacy: docs mirrored under app/api)
28
28
  /^(contents\/)?themes\/[\w-]+\/app\/api\/.*\/docs\.md$/,
29
+ // Theme routes (colocated next to the handler under api/)
30
+ /^(contents\/)?themes\/[\w-]+\/api\/.*\/docs\.md$/,
29
31
  // Core routes (monorepo mode)
30
32
  /^packages\/core\/templates\/app\/api\/.*\/docs\.md$/,
31
33
  // Core routes (NPM mode)