@kosmojs/dev 0.0.20 → 0.0.22

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 (192) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +11 -10
  3. package/pkg/{src/ast.d.ts → ast.d.ts} +11 -16
  4. package/pkg/{src/base-plugin → base-plugin}/api-handler.d.ts +1 -1
  5. package/pkg/{src/base-plugin → base-plugin}/worker.d.ts +1 -2
  6. package/pkg/base-plugin/worker.js +489 -221
  7. package/pkg/base-plugin/worker.js.map +4 -4
  8. package/pkg/{src/cache.d.ts → cache.d.ts} +1 -1
  9. package/pkg/index.js +640 -296
  10. package/pkg/index.js.map +4 -4
  11. package/pkg/{src/paths.d.ts → paths.d.ts} +2 -2
  12. package/pkg/{src/render.d.ts → render.d.ts} +4 -4
  13. package/pkg/routes-factory/base.d.ts +47 -0
  14. package/pkg/{src/routes-factory → routes-factory}/index.d.ts +1 -0
  15. package/pkg/stub-generator/index.js +1 -12
  16. package/pkg/stub-generator/index.js.map +2 -2
  17. package/pkg/{src/types.d.ts → types.d.ts} +55 -38
  18. package/pkg/src/routes-factory/base.d.ts +0 -17
  19. package/pkg/test/@fixtures/app/lib/@src/{api}/articles/[...path]/index.ts/types.d.ts +0 -3
  20. package/pkg/test/@fixtures/app/lib/@src/{api}/articles/[...path]/types.d.ts +0 -3
  21. package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/[[author]]/index.ts/types.d.ts +0 -4
  22. package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/[[author]]/types.d.ts +0 -4
  23. package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/index.ts/types.d.ts +0 -3
  24. package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/types.d.ts +0 -3
  25. package/pkg/test/@fixtures/app/lib/@src/{api}/books/index.ts/types.d.ts +0 -1
  26. package/pkg/test/@fixtures/app/lib/@src/{api}/books/types.d.ts +0 -1
  27. package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/[[id]].json/index.ts/types.d.ts +0 -4
  28. package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/[[id]].json/types.d.ts +0 -4
  29. package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/index.ts/types.d.ts +0 -3
  30. package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/types.d.ts +0 -3
  31. package/pkg/test/@fixtures/app/lib/@src/{api}/index/index.ts/types.d.ts +0 -1
  32. package/pkg/test/@fixtures/app/lib/@src/{api}/index/types.d.ts +0 -1
  33. package/pkg/test/@fixtures/app/lib/@src/{api}/pages/[...path].html/index.ts/types.d.ts +0 -3
  34. package/pkg/test/@fixtures/app/lib/@src/{api}/pages/[...path].html/types.d.ts +0 -3
  35. package/pkg/test/@fixtures/app/lib/@src/{api}/users/[id].json/index.ts/types.d.ts +0 -3
  36. package/pkg/test/@fixtures/app/lib/@src/{api}/users/[id].json/types.d.ts +0 -3
  37. package/pkg/test/@fixtures/app/src/test/api/articles/[...path]/index.d.ts +0 -0
  38. package/pkg/test/@fixtures/app/src/test/api/books/[category]/[[author]]/index.d.ts +0 -0
  39. package/pkg/test/@fixtures/app/src/test/api/books/[category]/index.d.ts +0 -0
  40. package/pkg/test/@fixtures/app/src/test/api/books/index.d.ts +0 -0
  41. package/pkg/test/@fixtures/app/src/test/api/files/[[folder]]/[[id]].json/index.d.ts +0 -0
  42. package/pkg/test/@fixtures/app/src/test/api/files/[[folder]]/index.d.ts +0 -0
  43. package/pkg/test/@fixtures/app/src/test/api/index/index.d.ts +0 -0
  44. package/pkg/test/@fixtures/app/src/test/api/pages/[...path].html/index.d.ts +0 -0
  45. package/pkg/test/@fixtures/app/src/test/api/users/[id].json/index.d.ts +0 -0
  46. package/pkg/test/@fixtures/app/src/test/pages/about/careers/[jobId]/index.d.ts +0 -0
  47. package/pkg/test/@fixtures/app/src/test/pages/about/careers/layout.d.ts +0 -0
  48. package/pkg/test/@fixtures/app/src/test/pages/about/index.d.ts +0 -0
  49. package/pkg/test/@fixtures/app/src/test/pages/about/layout.d.ts +0 -0
  50. package/pkg/test/@fixtures/app/src/test/pages/about/team/index.d.ts +0 -0
  51. package/pkg/test/@fixtures/app/src/test/pages/account/layout.d.ts +0 -0
  52. package/pkg/test/@fixtures/app/src/test/pages/account/profile/index.d.ts +0 -0
  53. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/index.d.ts +0 -0
  54. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/resources/[[type]]/[...path]/index.d.ts +0 -0
  55. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/resources/[[type]]/index.d.ts +0 -0
  56. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/resources/[[type]]/layout.d.ts +0 -0
  57. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/resources/index.d.ts +0 -0
  58. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/resources/layout.d.ts +0 -0
  59. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/settings/general/index.d.ts +0 -0
  60. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/settings/index.d.ts +0 -0
  61. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/settings/layout.d.ts +0 -0
  62. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/settings/permissions/index.d.ts +0 -0
  63. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/users/[userId]/index.d.ts +0 -0
  64. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/users/index.d.ts +0 -0
  65. package/pkg/test/@fixtures/app/src/test/pages/admin/[tenant]/users/layout.d.ts +0 -0
  66. package/pkg/test/@fixtures/app/src/test/pages/admin/index.d.ts +0 -0
  67. package/pkg/test/@fixtures/app/src/test/pages/admin/layout.d.ts +0 -0
  68. package/pkg/test/@fixtures/app/src/test/pages/blog/[[category]]/[[tag]]/index.d.ts +0 -0
  69. package/pkg/test/@fixtures/app/src/test/pages/blog/[[category]]/index.d.ts +0 -0
  70. package/pkg/test/@fixtures/app/src/test/pages/blog/index.d.ts +0 -0
  71. package/pkg/test/@fixtures/app/src/test/pages/blog/layout.d.ts +0 -0
  72. package/pkg/test/@fixtures/app/src/test/pages/blog/post/[slug]/index.d.ts +0 -0
  73. package/pkg/test/@fixtures/app/src/test/pages/blog/post/[slug]/layout.d.ts +0 -0
  74. package/pkg/test/@fixtures/app/src/test/pages/contact/index.d.ts +0 -0
  75. package/pkg/test/@fixtures/app/src/test/pages/contact/layout.d.ts +0 -0
  76. package/pkg/test/@fixtures/app/src/test/pages/courses/[courseId]/layout.d.ts +0 -0
  77. package/pkg/test/@fixtures/app/src/test/pages/courses/[courseId]/lessons/[[lessonId]]/assignments/[...assignmentPath]/index.d.ts +0 -0
  78. package/pkg/test/@fixtures/app/src/test/pages/dashboard/[view]/index.d.ts +0 -0
  79. package/pkg/test/@fixtures/app/src/test/pages/dashboard/analytics/index.d.ts +0 -0
  80. package/pkg/test/@fixtures/app/src/test/pages/dashboard/index.d.ts +0 -0
  81. package/pkg/test/@fixtures/app/src/test/pages/dashboard/layout.d.ts +0 -0
  82. package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/billing/index.d.ts +0 -0
  83. package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/index.d.ts +0 -0
  84. package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/layout.d.ts +0 -0
  85. package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/notifications/index.d.ts +0 -0
  86. package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/profile/index.d.ts +0 -0
  87. package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/security/index.d.ts +0 -0
  88. package/pkg/test/@fixtures/app/src/test/pages/dashboard/settings/security/layout.d.ts +0 -0
  89. package/pkg/test/@fixtures/app/src/test/pages/docs/[...path]/index.d.ts +0 -0
  90. package/pkg/test/@fixtures/app/src/test/pages/docs/index.d.ts +0 -0
  91. package/pkg/test/@fixtures/app/src/test/pages/docs/layout.d.ts +0 -0
  92. package/pkg/test/@fixtures/app/src/test/pages/files/[...filePath]/index.d.ts +0 -0
  93. package/pkg/test/@fixtures/app/src/test/pages/files/[...filePath]/layout.d.ts +0 -0
  94. package/pkg/test/@fixtures/app/src/test/pages/legal/layout.d.ts +0 -0
  95. package/pkg/test/@fixtures/app/src/test/pages/legal/privacy/index.d.ts +0 -0
  96. package/pkg/test/@fixtures/app/src/test/pages/legal/terms/index.d.ts +0 -0
  97. package/pkg/test/@fixtures/app/src/test/pages/news/[category]/articles/[...articlePath]/index.d.ts +0 -0
  98. package/pkg/test/@fixtures/app/src/test/pages/news/[category]/layout.d.ts +0 -0
  99. package/pkg/test/@fixtures/app/src/test/pages/portal/[clientId]/layout.d.ts +0 -0
  100. package/pkg/test/@fixtures/app/src/test/pages/portal/[clientId]/reports/[reportType]/data/[dataView]/index.d.ts +0 -0
  101. package/pkg/test/@fixtures/app/src/test/pages/portal/[clientId]/reports/[reportType]/data/[dataView]/layout.d.ts +0 -0
  102. package/pkg/test/@fixtures/app/src/test/pages/portal/[clientId]/reports/[reportType]/layout.d.ts +0 -0
  103. package/pkg/test/@fixtures/app/src/test/pages/portal/[clientId]/reports/layout.d.ts +0 -0
  104. package/pkg/test/@fixtures/app/src/test/pages/portal/layout.d.ts +0 -0
  105. package/pkg/test/@fixtures/app/src/test/pages/products/[id]/index.d.ts +0 -0
  106. package/pkg/test/@fixtures/app/src/test/pages/products/index.d.ts +0 -0
  107. package/pkg/test/@fixtures/app/src/test/pages/profile/[username]/layout.d.ts +0 -0
  108. package/pkg/test/@fixtures/app/src/test/pages/profile/[username]/posts/[postId]/comments/[...thread]/index.d.ts +0 -0
  109. package/pkg/test/@fixtures/app/src/test/pages/profile/[username]/posts/[postId]/layout.d.ts +0 -0
  110. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/files/[...path]/index.d.ts +0 -0
  111. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/files/index.d.ts +0 -0
  112. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/files/layout.d.ts +0 -0
  113. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/index.d.ts +0 -0
  114. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/layout.d.ts +0 -0
  115. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/[taskId]/comments/[commentId]/index.d.ts +0 -0
  116. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/[taskId]/comments/index.d.ts +0 -0
  117. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/[taskId]/comments/layout.d.ts +0 -0
  118. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/[taskId]/index.d.ts +0 -0
  119. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/[taskId]/layout.d.ts +0 -0
  120. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/index.d.ts +0 -0
  121. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/tasks/layout.d.ts +0 -0
  122. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/team/[userId]/index.d.ts +0 -0
  123. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/team/index.d.ts +0 -0
  124. package/pkg/test/@fixtures/app/src/test/pages/projects/[projectId]/team/layout.d.ts +0 -0
  125. package/pkg/test/@fixtures/app/src/test/pages/projects/index.d.ts +0 -0
  126. package/pkg/test/@fixtures/app/src/test/pages/projects/layout.d.ts +0 -0
  127. package/pkg/test/@fixtures/app/src/test/pages/properties/[[city]]/filters/[...filters]/index.d.ts +0 -0
  128. package/pkg/test/@fixtures/app/src/test/pages/properties/filters/index.d.ts +0 -0
  129. package/pkg/test/@fixtures/app/src/test/pages/properties/layout.d.ts +0 -0
  130. package/pkg/test/@fixtures/app/src/test/pages/search/[[query]]/[[page]]/index.d.ts +0 -0
  131. package/pkg/test/@fixtures/app/src/test/pages/search/[[query]]/layout.d.ts +0 -0
  132. package/pkg/test/@fixtures/app/src/test/pages/search/index.d.ts +0 -0
  133. package/pkg/test/@fixtures/app/src/test/pages/shop/[category]/[productId]/index.d.ts +0 -0
  134. package/pkg/test/@fixtures/app/src/test/pages/shop/[category]/[productId]/layout.d.ts +0 -0
  135. package/pkg/test/@fixtures/app/src/test/pages/shop/cart/index.d.ts +0 -0
  136. package/pkg/test/@fixtures/app/src/test/pages/shop/checkout/confirm/index.d.ts +0 -0
  137. package/pkg/test/@fixtures/app/src/test/pages/shop/checkout/layout.d.ts +0 -0
  138. package/pkg/test/@fixtures/app/src/test/pages/shop/checkout/payment/index.d.ts +0 -0
  139. package/pkg/test/@fixtures/app/src/test/pages/shop/checkout/shipping/index.d.ts +0 -0
  140. package/pkg/test/@fixtures/app/src/test/pages/shop/checkout/shipping/layout.d.ts +0 -0
  141. package/pkg/test/@fixtures/app/src/test/pages/shop/index.d.ts +0 -0
  142. package/pkg/test/@fixtures/app/src/test/pages/shop/layout.d.ts +0 -0
  143. package/pkg/test/@fixtures/app/src/test/pages/shop/orders/[orderId]/index.d.ts +0 -0
  144. package/pkg/test/@fixtures/app/src/test/pages/shop/orders/index.d.ts +0 -0
  145. package/pkg/test/@fixtures/app/src/test/pages/shop/orders/layout.d.ts +0 -0
  146. package/pkg/test/@fixtures/app/src/test/pages/shop/product/[id]/index.d.ts +0 -0
  147. package/pkg/test/@fixtures/app/src/test/pages/shop/product/[id]/layout.d.ts +0 -0
  148. package/pkg/test/@fixtures/app/src/test/pages/shop/product/[id]/reviews/index.d.ts +0 -0
  149. package/pkg/test/@fixtures/app/src/test/pages/shop/products/[[category]]/index.d.ts +0 -0
  150. package/pkg/test/@fixtures/app/src/test/pages/shop/products/index.d.ts +0 -0
  151. package/pkg/test/@fixtures/app/src/test/pages/shop/products/layout.d.ts +0 -0
  152. package/pkg/test/@fixtures/app/src/test/pages/signup/index.d.ts +0 -0
  153. package/pkg/test/@fixtures/app/src/test/pages/store/[category]/filters/[...filters]/index.d.ts +0 -0
  154. package/pkg/test/@fixtures/app/src/test/pages/store/[category]/sort/[sortBy]/index.d.ts +0 -0
  155. package/pkg/test/@fixtures/app/src/test/pages/store/[category]/sort/layout.d.ts +0 -0
  156. package/pkg/test/@fixtures/app/src/test/pages/store/layout.d.ts +0 -0
  157. package/pkg/test/@fixtures/app/src/test/pages/users/[username]/followers/index.d.ts +0 -0
  158. package/pkg/test/@fixtures/app/src/test/pages/users/[username]/following/index.d.ts +0 -0
  159. package/pkg/test/@fixtures/app/src/test/pages/users/[username]/index.d.ts +0 -0
  160. package/pkg/test/@fixtures/app/src/test/pages/users/[username]/layout.d.ts +0 -0
  161. package/pkg/test/@fixtures/app/src/test/pages/users/[username]/posts/[postId]/index.d.ts +0 -0
  162. package/pkg/test/@fixtures/app/src/test/pages/users/[username]/posts/[postId]/layout.d.ts +0 -0
  163. package/pkg/test/@fixtures/app/src/test/pages/users/[username]/posts/index.d.ts +0 -0
  164. package/pkg/test/@fixtures/app/src/test/pages/users/[username]/posts/layout.d.ts +0 -0
  165. package/pkg/test/@fixtures/app/src/test/pages/users/index.d.ts +0 -0
  166. package/pkg/test/@fixtures/app/src/test/pages/users/layout.d.ts +0 -0
  167. package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/analytics/[range]/index.d.ts +0 -0
  168. package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/analytics/[range]/layout.d.ts +0 -0
  169. package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/analytics/index.d.ts +0 -0
  170. package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/analytics/layout.d.ts +0 -0
  171. package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/team/[memberId]/permissions/[...permissionPath]/index.d.ts +0 -0
  172. package/pkg/test/@fixtures/app/src/test/pages/workspace/[workspaceId]/team/layout.d.ts +0 -0
  173. package/pkg/test/@fixtures/ast/extractTypeDeclarations/exports/with-referenced-files.d.ts +0 -1
  174. package/pkg/test/@fixtures/ast/extractTypeDeclarations/imports/with-referenced-files.d.ts +0 -1
  175. package/pkg/test/ast/extractParamsRefinements.test.d.ts +0 -1
  176. package/pkg/test/ast/extractRouteMethods.test.d.ts +0 -1
  177. package/pkg/test/ast/extractTypeDeclarations.test.d.ts +0 -1
  178. package/pkg/test/routes/index.d.ts +0 -4
  179. package/pkg/test/routes/nesting.test.d.ts +0 -1
  180. package/pkg/test/routes/resolver.test.d.ts +0 -1
  181. package/pkg/test/routes/routes.test.d.ts +0 -1
  182. /package/pkg/{src/alias-plugin → alias-plugin}/index.d.ts +0 -0
  183. /package/pkg/{src/base-plugin → base-plugin}/index.d.ts +0 -0
  184. /package/pkg/{src/base-plugin → base-plugin}/spinner.d.ts +0 -0
  185. /package/pkg/{src/defaults.d.ts → defaults.d.ts} +0 -0
  186. /package/pkg/{src/define-plugin → define-plugin}/index.d.ts +0 -0
  187. /package/pkg/{src/fs.d.ts → fs.d.ts} +0 -0
  188. /package/pkg/{src/index.d.ts → index.d.ts} +0 -0
  189. /package/pkg/{src/routes-factory → routes-factory}/nesting.d.ts +0 -0
  190. /package/pkg/{src/routes-factory → routes-factory}/resolve.d.ts +0 -0
  191. /package/pkg/{src/stub-generator → stub-generator}/index.d.ts +0 -0
  192. /package/pkg/{src/typebox.d.ts → typebox.d.ts} +0 -0
package/pkg/index.js CHANGED
@@ -60,9 +60,6 @@ var pathResolver = ({
60
60
  },
61
61
  libEntry(...a) {
62
62
  return this.lib(defaults.entryDir, ...a);
63
- },
64
- fetch(...a) {
65
- return this.lib(defaults.fetchDir, ...a);
66
63
  }
67
64
  };
68
65
  return {
@@ -96,9 +93,6 @@ var pathResolver = ({
96
93
  },
97
94
  libPages(...a) {
98
95
  return this.lib(defaults.pagesDir, ...a);
99
- },
100
- fetch(...a) {
101
- return this.lib(defaults.fetchDir, ...a);
102
96
  }
103
97
  },
104
98
  createImport,
@@ -175,98 +169,33 @@ var alias_plugin_default = (appRoot, opt) => {
175
169
  };
176
170
 
177
171
  // src/base-plugin/index.ts
172
+ import { writeFile as writeFile3 } from "node:fs/promises";
178
173
  import { basename as basename2, join as join5, resolve as resolve5 } from "node:path";
179
- import { styleText as styleText2 } from "node:util";
174
+ import { styleText as styleText4 } from "node:util";
180
175
  import { Worker } from "node:worker_threads";
181
176
  import stubGenerator from "@kosmojs/dev/stub-generator";
182
177
 
183
178
  // src/routes-factory/resolve.ts
184
179
  import { dirname as dirname3, join as join3, resolve as resolve3 } from "node:path";
180
+ import { styleText as styleText2 } from "node:util";
185
181
  import crc5 from "crc/crc32";
182
+ import mimeTypes from "mime-types";
186
183
  import picomatch from "picomatch";
187
184
  import { glob as glob2 } from "tinyglobby";
188
185
 
189
- // src/render.ts
190
- import { mkdir, readFile, writeFile } from "node:fs/promises";
191
- import { dirname, join as join2 } from "node:path";
192
- import crc from "crc/crc32";
193
- import handlebars from "handlebars";
194
-
195
- // src/fs.ts
196
- import { access, constants } from "node:fs/promises";
197
- var pathExists = async (path) => {
198
- try {
199
- await access(path, constants.F_OK);
200
- return true;
201
- } catch {
202
- return false;
203
- }
204
- };
205
-
206
- // src/render.ts
207
- var render = (template, context2, options) => {
208
- const { noEscape = true, renderer = handlebars } = { ...options };
209
- return renderer.compile(template, { noEscape })(context2);
210
- };
211
- var renderAsFile = (file, template, context2, options) => {
212
- const { formatters, ...renderOpts } = { ...options };
213
- const content = render(template, context2, renderOpts);
214
- return Array.isArray(formatters) ? formatters.reduce((c, f) => f(c, file), content) : content;
215
- };
216
- var renderToFile = async (file, template, context2, options) => {
217
- const content = renderAsFile(file, template, context2, options);
218
- if (await pathExists(file)) {
219
- const { overwrite = true } = { ...options };
220
- if (overwrite === false) {
221
- return;
222
- }
223
- const fileContent = await readFile(file, "utf8");
224
- if (typeof overwrite === "function" && !overwrite(fileContent)) {
225
- return;
226
- }
227
- if (crc(content) === crc(fileContent)) {
228
- return;
229
- }
230
- }
231
- await mkdir(dirname(file), { recursive: true });
232
- await writeFile(file, content, "utf8");
233
- };
234
- var renderFactory = (options) => {
235
- const renderer = handlebars.create();
236
- if (options?.partials) {
237
- renderer.registerPartial(options.partials);
238
- }
239
- if (options?.helpers) {
240
- renderer.registerHelper(options.helpers);
241
- }
242
- return {
243
- render(template, context2, selfOoptions) {
244
- return render(template, context2, {
245
- renderer,
246
- ...options,
247
- ...selfOoptions
248
- });
249
- },
250
- async renderToFile(file, template, context2, selfOoptions) {
251
- return renderToFile(
252
- options?.outdir ? join2(options.outdir, file) : file,
253
- template,
254
- context2,
255
- { renderer, ...options, ...selfOoptions }
256
- );
257
- }
258
- };
259
- };
260
-
261
186
  // src/ast.ts
262
187
  import { resolve } from "node:path";
263
- import crc2 from "crc/crc32";
188
+ import { styleText } from "node:util";
189
+ import crc from "crc/crc32";
264
190
  import { flattener } from "tfusion";
265
191
  import {
266
192
  Project,
267
193
  SyntaxKind
268
194
  } from "ts-morph";
269
- import { HTTPMethods } from "@kosmojs/api";
195
+ import {
196
+ HTTPMethods,
197
+ RequestValidationTargets
198
+ } from "@kosmojs/api";
270
199
  var createProject = (opts) => new Project(opts);
271
200
  var resolveRouteSignature = async (route, opts) => {
272
201
  const {
@@ -278,19 +207,12 @@ var resolveRouteSignature = async (route, opts) => {
278
207
  );
279
208
  const defaultExport = extractDefaultExport(sourceFile);
280
209
  const paramsRefinements = defaultExport ? extractParamsRefinements(defaultExport) : void 0;
281
- const methods = defaultExport ? extractRouteMethods(defaultExport, route) : [];
282
- const payloadTypes = methods.flatMap((e) => {
283
- return e.payloadType ? [e.payloadType] : [];
284
- });
285
- const responseTypes = methods.flatMap((e) => {
286
- return e.responseType ? [e.responseType] : [];
287
- });
210
+ const methods = defaultExport ? extractRouteMethods(route, defaultExport) : [];
288
211
  return {
289
212
  typeDeclarations,
290
213
  paramsRefinements,
291
214
  methods: methods.map((e) => e.method),
292
- payloadTypes,
293
- responseTypes,
215
+ validationDefinitions: methods.flatMap((e) => e.validationDefinitions),
294
216
  referencedFiles
295
217
  };
296
218
  };
@@ -305,22 +227,23 @@ var extractDefaultExport = (sourceFile) => {
305
227
  return defaultExport;
306
228
  };
307
229
  var extractParamsRefinements = (callExpression) => {
308
- const [firstGeneric] = extractGenerics(callExpression);
309
- if (!firstGeneric?.node.isKind(SyntaxKind.TupleType)) {
230
+ const [
231
+ _routeName,
232
+ // first generic - the route name
233
+ paramsGeneric
234
+ // second generic - params refinements
235
+ ] = extractGenerics(callExpression);
236
+ if (!paramsGeneric?.isKind(SyntaxKind.TupleType)) {
310
237
  return;
311
238
  }
312
- const tupleElements = firstGeneric.node.getElements();
313
- if (!tupleElements?.length) {
314
- return;
315
- }
316
- return tupleElements.map((node, index) => {
239
+ return paramsGeneric.getElements().map((node, index) => {
317
240
  return {
318
241
  index,
319
242
  text: node.getText()
320
243
  };
321
244
  });
322
245
  };
323
- var extractRouteMethods = (callExpression, route) => {
246
+ var extractRouteMethods = (route, callExpression) => {
324
247
  const funcDeclaration = callExpression.getFirstChildByKind(SyntaxKind.ArrowFunction) || callExpression.getFirstChildByKind(SyntaxKind.FunctionExpression);
325
248
  if (!funcDeclaration) {
326
249
  return [];
@@ -341,35 +264,173 @@ var extractRouteMethods = (callExpression, route) => {
341
264
  }
342
265
  }
343
266
  const methods = [];
344
- const skipValidationFilter = (e) => /@skip-validation/.test(e);
345
267
  for (const [callExpression2, method] of callExpressions) {
346
- const [payloadGeneric, responseGeneric] = extractGenerics(callExpression2);
347
- const payloadText = payloadGeneric?.node ? payloadGeneric.node.getChildren().length === 0 ? "{}" : payloadGeneric.node.getFullText() : void 0;
348
- const responseText = responseGeneric?.node.getText();
349
- const responseType = responseText ? {
350
- id: ["ResponseT", crc2(route.id + method)].join(""),
351
- method,
352
- skipValidation: responseGeneric?.comments ? responseGeneric.comments.some(skipValidationFilter) : false,
353
- text: ["never", "object"].includes(responseText) ? "{}" : responseText,
354
- resolvedType: void 0
355
- } : void 0;
356
- const payloadType = payloadText ? {
357
- id: ["PayloadT", crc2(route.id + method)].join(""),
358
- responseTypeId: responseType?.id,
359
- method,
360
- skipValidation: payloadGeneric?.comments ? payloadGeneric.comments.some(skipValidationFilter) : false,
361
- isOptional: payloadText ? payloadText === "{}" || route.optionalParams : true,
362
- text: payloadText,
363
- resolvedType: void 0
364
- } : void 0;
268
+ const [vDefs, vOpts] = extractGenerics(callExpression2);
365
269
  methods.push({
366
270
  method,
367
- payloadType,
368
- responseType
271
+ validationDefinitions: extractValidationDefinitions(
272
+ route,
273
+ method,
274
+ vDefs,
275
+ vOpts
276
+ )
369
277
  });
370
278
  }
371
279
  return methods;
372
280
  };
281
+ var parseRuntimeValidation = (typeNode) => {
282
+ if (typeNode.isKind(SyntaxKind.LiteralType)) {
283
+ const literal = typeNode.getFirstChild();
284
+ if (literal?.isKind(SyntaxKind.TrueKeyword)) {
285
+ return true;
286
+ } else if (literal?.isKind(SyntaxKind.FalseKeyword)) {
287
+ return false;
288
+ }
289
+ }
290
+ return void 0;
291
+ };
292
+ var extractResponseVariant = (typeNode) => {
293
+ if (!typeNode.isKind(SyntaxKind.TupleType)) {
294
+ return;
295
+ }
296
+ let status = 200;
297
+ let contentType;
298
+ let body;
299
+ const [statusNode, contentTypeNode, bodyNode] = typeNode.getElements();
300
+ if (statusNode?.isKind(SyntaxKind.LiteralType)) {
301
+ const literal = statusNode.getFirstChildByKind(SyntaxKind.NumericLiteral);
302
+ if (literal) {
303
+ status = Number(literal.getText());
304
+ }
305
+ }
306
+ if (contentTypeNode) {
307
+ contentType = extractStringLiteral(contentTypeNode);
308
+ }
309
+ if (bodyNode) {
310
+ body = bodyNode.getText();
311
+ if (["object"].includes(body)) {
312
+ body = "{}";
313
+ }
314
+ }
315
+ return { status, contentType, body };
316
+ };
317
+ var parseValidationOptions = (typeNode) => {
318
+ const opts = {};
319
+ if (!typeNode?.isKind(SyntaxKind.TypeLiteral)) {
320
+ return opts;
321
+ }
322
+ for (const prop of typeNode.getMembers()) {
323
+ if (!prop.isKind(SyntaxKind.PropertySignature)) {
324
+ continue;
325
+ }
326
+ const target = prop.getName();
327
+ const typeNode2 = prop.getTypeNodeOrThrow();
328
+ if (!typeNode2.isKind(SyntaxKind.TypeLiteral)) {
329
+ continue;
330
+ }
331
+ let contentType;
332
+ let runtimeValidation;
333
+ const customErrors = {};
334
+ for (const member of typeNode2.getMembers()) {
335
+ if (!member.isKind(SyntaxKind.PropertySignature)) {
336
+ continue;
337
+ }
338
+ const nameNode = member.getNameNode();
339
+ const valueNode = member.getTypeNodeOrThrow();
340
+ const name = nameNode.isKind(SyntaxKind.StringLiteral) ? nameNode.getLiteralText() : nameNode.getText();
341
+ if (name === "contentType") {
342
+ contentType = extractStringLiteral(valueNode);
343
+ } else if (name === "runtimeValidation") {
344
+ runtimeValidation = parseRuntimeValidation(valueNode);
345
+ } else if (name.startsWith("error")) {
346
+ const literal = extractStringLiteral(valueNode);
347
+ if (literal) {
348
+ customErrors[name] = literal;
349
+ }
350
+ }
351
+ }
352
+ opts[target] = {
353
+ contentType,
354
+ runtimeValidation,
355
+ customErrors
356
+ };
357
+ }
358
+ return opts;
359
+ };
360
+ var extractStringLiteral = (typeNode) => {
361
+ const literal = typeNode.isKind(SyntaxKind.LiteralType) ? typeNode.getFirstChildByKind(SyntaxKind.StringLiteral) : void 0;
362
+ return literal ? literal.getLiteralText() : void 0;
363
+ };
364
+ var extractValidationDefinitions = (route, method, defsNode, optsNode) => {
365
+ const definitions = [];
366
+ if (!defsNode?.isKind(SyntaxKind.TypeLiteral)) {
367
+ return definitions;
368
+ }
369
+ const optsMap = parseValidationOptions(optsNode);
370
+ const createId = (target, hash) => {
371
+ return [
372
+ target.replace(/^./, (c) => c.toUpperCase()),
373
+ "T",
374
+ method,
375
+ crc(route.id + hash)
376
+ ].join("");
377
+ };
378
+ for (const prop of defsNode.getMembers()) {
379
+ if (!prop.isKind(SyntaxKind.PropertySignature)) {
380
+ continue;
381
+ }
382
+ const target = prop.getName();
383
+ const typeNode = prop.getTypeNodeOrThrow();
384
+ if (target === "response") {
385
+ const variants = typeNode.isKind(SyntaxKind.UnionType) ? typeNode.getChildrenOfKind(SyntaxKind.TupleType) : [typeNode];
386
+ definitions.push({
387
+ ...optsMap[target],
388
+ method,
389
+ target,
390
+ variants: variants.flatMap((e, i) => {
391
+ const { status, contentType, body } = extractResponseVariant(e) || {};
392
+ if (!status) {
393
+ return [];
394
+ }
395
+ if (contentType && typeof contentType !== "string") {
396
+ console.warn(
397
+ styleText(
398
+ ["bold", "red"],
399
+ `\u2717 The second element of a response variant should specify the Response Content Type`
400
+ )
401
+ );
402
+ console.warn(
403
+ styleText(["blue"], ` Example: [200, "json", Schema]`)
404
+ );
405
+ console.warn(
406
+ ` Route: ${route.name}; Method: ${method}; Response Variant: #${i}`
407
+ );
408
+ console.warn();
409
+ }
410
+ return [
411
+ {
412
+ id: createId(target, JSON.stringify([status, contentType, body])),
413
+ status,
414
+ contentType,
415
+ body
416
+ }
417
+ ];
418
+ })
419
+ });
420
+ } else if (Object.keys(RequestValidationTargets).includes(target)) {
421
+ definitions.push({
422
+ ...optsMap[target],
423
+ method,
424
+ target,
425
+ schema: {
426
+ id: createId(target),
427
+ text: typeNode.getText()
428
+ }
429
+ });
430
+ }
431
+ }
432
+ return definitions;
433
+ };
373
434
  var extractTypeDeclarations = (sourceFile, opts) => {
374
435
  const declarations = [];
375
436
  const referencedFiles = opts?.withReferencedFiles ? [] : void 0;
@@ -474,12 +535,7 @@ var getReferencedFiles = (importIdentifier) => {
474
535
  });
475
536
  };
476
537
  var extractGenerics = (callExpression) => {
477
- return callExpression.getTypeArguments().map((node) => {
478
- return {
479
- node,
480
- comments: node.getLeadingCommentRanges().map((range) => range.getText().trim())
481
- };
482
- });
538
+ return callExpression.getTypeArguments();
483
539
  };
484
540
  var typeResolverFactory = ({ appRoot }) => {
485
541
  const project = createProject({
@@ -488,7 +544,7 @@ var typeResolverFactory = ({ appRoot }) => {
488
544
  });
489
545
  const literalTypesResolver = (literalTypes, options) => {
490
546
  const sourceFile = project.createSourceFile(
491
- `${crc2(literalTypes)}-${Date.now()}.ts`,
547
+ `${crc(literalTypes)}-${Date.now()}.ts`,
492
548
  literalTypes,
493
549
  { overwrite: true }
494
550
  );
@@ -514,10 +570,23 @@ var typeResolverFactory = ({ appRoot }) => {
514
570
  };
515
571
 
516
572
  // src/cache.ts
517
- import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
518
- import { dirname as dirname2, resolve as resolve2 } from "node:path";
519
- import crc3 from "crc/crc32";
573
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
574
+ import { dirname, resolve as resolve2 } from "node:path";
575
+ import crc2 from "crc/crc32";
520
576
  import self from "@kosmojs/dev/package.json" with { type: "json" };
577
+
578
+ // src/fs.ts
579
+ import { access, constants } from "node:fs/promises";
580
+ var pathExists = async (path) => {
581
+ try {
582
+ await access(path, constants.F_OK);
583
+ return true;
584
+ } catch {
585
+ return false;
586
+ }
587
+ };
588
+
589
+ // src/cache.ts
521
590
  var cacheFactory = (route, {
522
591
  appRoot,
523
592
  sourceFolder,
@@ -526,11 +595,11 @@ var cacheFactory = (route, {
526
595
  const cacheFile = pathResolver({
527
596
  appRoot,
528
597
  sourceFolder
529
- }).createPath.libApi(dirname2(route.file), "cache.json");
598
+ }).createPath.libApi(dirname(route.file), "cache.json");
530
599
  const getCache = async (opt) => {
531
600
  if (await pathExists(cacheFile)) {
532
601
  try {
533
- const cache = JSON.parse(await readFile2(cacheFile, "utf8"));
602
+ const cache = JSON.parse(await readFile(cacheFile, "utf8"));
534
603
  return opt?.validate ? validateCache(cache) : cache;
535
604
  } catch (_e) {
536
605
  }
@@ -553,8 +622,8 @@ var cacheFactory = (route, {
553
622
  ] = await generateFileHash(file);
554
623
  }
555
624
  const cache = { ...rest, hash, referencedFiles };
556
- await mkdir2(dirname2(cacheFile), { recursive: true });
557
- await writeFile2(cacheFile, JSON.stringify(cache, null, 2), "utf8");
625
+ await mkdir(dirname(cacheFile), { recursive: true });
626
+ await writeFile(cacheFile, JSON.stringify(cache, null, 2), "utf8");
558
627
  return cache;
559
628
  };
560
629
  const validateCache = async (cache) => {
@@ -586,11 +655,11 @@ var cacheFactory = (route, {
586
655
  var generateFileHash = async (file, extraContext) => {
587
656
  let fileContent;
588
657
  try {
589
- fileContent = await readFile2(file, "utf8");
658
+ fileContent = await readFile(file, "utf8");
590
659
  } catch (_e) {
591
660
  return 0;
592
661
  }
593
- return fileContent ? crc3(
662
+ return fileContent ? crc2(
594
663
  JSON.stringify({
595
664
  ...extraContext,
596
665
  [self.cacheVersion]: fileContent
@@ -601,75 +670,230 @@ var identicalHashSum = (a, b) => {
601
670
  return a === b;
602
671
  };
603
672
 
673
+ // src/render.ts
674
+ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
675
+ import { dirname as dirname2, join as join2 } from "node:path";
676
+ import crc3 from "crc/crc32";
677
+ import handlebars from "handlebars";
678
+ var render = (template, context2, options) => {
679
+ const { noEscape = true, renderer = handlebars } = { ...options };
680
+ return renderer.compile(template, { noEscape })(context2);
681
+ };
682
+ var renderToFile = async (file, template, context2, options) => {
683
+ const content = render(template, context2, options);
684
+ if (await pathExists(file)) {
685
+ const { overwrite = true } = { ...options };
686
+ if (overwrite === false) {
687
+ return;
688
+ }
689
+ const fileContent = await readFile2(file, "utf8");
690
+ if (typeof overwrite === "function" && !overwrite(fileContent)) {
691
+ return;
692
+ }
693
+ if (crc3(content) === crc3(fileContent)) {
694
+ return;
695
+ }
696
+ }
697
+ await mkdir2(dirname2(file), { recursive: true });
698
+ await writeFile2(file, content, "utf8");
699
+ };
700
+ var renderFactory = (options) => {
701
+ const renderer = handlebars.create();
702
+ renderer.registerPartial({ ...options?.partials });
703
+ renderer.registerHelper({ ...options?.helpers });
704
+ return {
705
+ render(template, context2, selfOoptions) {
706
+ return render(template, context2, {
707
+ renderer,
708
+ ...options,
709
+ ...selfOoptions
710
+ });
711
+ },
712
+ async renderToFile(file, template, context2, selfOoptions) {
713
+ return renderToFile(
714
+ options?.outdir ? join2(options.outdir, file) : file,
715
+ template,
716
+ context2,
717
+ { renderer, ...options, ...selfOoptions }
718
+ );
719
+ }
720
+ };
721
+ };
722
+ var renderHelpers = {
723
+ createParamsLiteral: (params) => {
724
+ return params.schema.map((p) => {
725
+ return p.kind === "splat" ? `${p.const}?: Array<string | number>` : p.kind === "optional" ? `${p.const}?: string | number` : `${p.const}: string | number`;
726
+ }).join(", ");
727
+ }
728
+ };
729
+
604
730
  // src/routes-factory/base.ts
605
731
  import crc4 from "crc/crc32";
606
- var pathTokensFactory = (path) => {
607
- const requiredParamRegex = /^\[([^\]]+)\]$/;
608
- const optionalParamRegex = /^\[\[([^\]]+)\]\]$/;
609
- const restParamRegex = /^\[\.\.\.([^\]]+)\]$/;
610
- return path.split("/").map((orig, i) => {
611
- const [base, ext = ""] = orig.split(/(\.([\w\d-]+)$)/);
612
- const paramBase = (regex) => {
613
- const name = base.replace(regex, "$1") || base;
614
- return {
615
- name,
616
- const: /\W/.test(name) ? [name.replace(/\W/g, "_"), crc4(orig)].join("_") : name
617
- };
618
- };
619
- let param;
620
- if (base.startsWith("[")) {
621
- if (restParamRegex.test(base)) {
622
- param = {
623
- ...paramBase(restParamRegex),
624
- isRequired: false,
625
- isOptional: false,
626
- isRest: true
627
- };
628
- } else if (optionalParamRegex.test(base)) {
629
- param = {
630
- ...paramBase(optionalParamRegex),
631
- isRequired: false,
632
- isOptional: true,
633
- isRest: false
634
- };
635
- } else if (requiredParamRegex.test(base)) {
636
- param = {
637
- ...paramBase(requiredParamRegex),
638
- isRequired: true,
639
- isOptional: false,
640
- isRest: false
641
- };
732
+ import { parse } from "path-to-regexp";
733
+ var pathTokensFactory = (path, {
734
+ transformStaticValue = normalizeStaticValue
735
+ } = {}) => {
736
+ const extractParts = (tokens2, createConst, insideGroup = false) => {
737
+ const parts = [];
738
+ for (const token of tokens2) {
739
+ switch (token.type) {
740
+ case "text":
741
+ if (token.value !== "/") {
742
+ parts.push({
743
+ type: "static",
744
+ value: transformStaticValue(token.value)
745
+ });
746
+ }
747
+ break;
748
+ case "param":
749
+ parts.push({
750
+ type: "param",
751
+ kind: insideGroup ? "optional" : "required",
752
+ name: token.name,
753
+ const: createConst(token.name)
754
+ });
755
+ break;
756
+ case "wildcard":
757
+ parts.push({
758
+ type: "param",
759
+ kind: "splat",
760
+ name: token.name,
761
+ const: createConst(token.name)
762
+ });
763
+ break;
764
+ case "group":
765
+ parts.push(...extractParts(token.tokens, createConst, true));
766
+ break;
642
767
  }
643
768
  }
644
- return {
645
- orig,
646
- base,
647
- path: i === 0 ? orig.replace(/^index$/, "/") : orig,
648
- ext,
649
- ...param ? { param } : {}
650
- };
769
+ return parts;
770
+ };
771
+ const patternTransforms = [
772
+ // Transform required params: [id] => :id
773
+ // Only pure \w param names,
774
+ // [some-id] used as is, not treated as param,
775
+ // use [some_id] instead.
776
+ (s) => s.replace(/\[(\w+)\]/g, ":$1"),
777
+ // Transform optional params: {id} => {:id}
778
+ // Only pure \w param names,
779
+ // anything else treated as a path-to-regexp pattern and used as is.
780
+ // {some-id} treated as an optional static segment.
781
+ // use {some_id} for simple param syntax
782
+ // or {:some-id} pattern where :some is the param name and -id is a static segment.
783
+ (s) => s.replace(/\{(\w+)\}/g, "{:$1}"),
784
+ // Transform splat params: {...param} => {*param}
785
+ (s) => s.replace(/\{\.\.\./g, "{*"),
786
+ // Insert leading slash inside optional/splat groups.
787
+ // {:name} => {/:name}
788
+ // {*name} => {/*name}
789
+ (s) => {
790
+ return s.startsWith("{") ? s.replace(/^\{/, "{/") : s;
791
+ }
792
+ ];
793
+ const detectBareParams = (s) => {
794
+ let depth = 0;
795
+ for (const [i, ch] of [...s].entries()) {
796
+ if (ch === "{") {
797
+ depth += 1;
798
+ } else if (ch === "}") {
799
+ depth -= 1;
800
+ } else if (ch === ":" && depth === 0) {
801
+ const match = s.slice(i + 1).match(/^\w+/);
802
+ return match?.[0] || ":";
803
+ }
804
+ }
805
+ return;
806
+ };
807
+ const tokens = path.replace(/^index\/?/, "").split("/").flatMap((orig) => {
808
+ if (!orig.length) {
809
+ return [];
810
+ }
811
+ const bareParam = detectBareParams(orig);
812
+ if (bareParam === ":") {
813
+ throw new Error(
814
+ `${path} contains colons outside braces, use : only within {}`
815
+ );
816
+ } else if (bareParam) {
817
+ throw new Error(
818
+ `${path} contains bare params, use [${bareParam}] instead of :${bareParam}`
819
+ );
820
+ }
821
+ const pattern = patternTransforms.reduce((src, fn) => fn(src), orig);
822
+ const { tokens: tokens2 } = parse(pattern);
823
+ const parts = extractParts(tokens2, (val) => {
824
+ return /\W/.test(val) || /^\d/.test(val) ? [val.replace(/^\d+|\W/g, "_"), crc4(orig)].join("_") : val;
825
+ });
826
+ const isStatic = parts.length === 1 ? parts[0].type === "static" : false;
827
+ const isParam = parts.length === 1 ? parts[0].type === "param" : false;
828
+ const kind = isStatic ? "static" : isParam ? "param" : "mixed";
829
+ return [
830
+ {
831
+ kind,
832
+ orig,
833
+ pattern,
834
+ parts
835
+ }
836
+ ];
651
837
  });
838
+ return [
839
+ tokens,
840
+ tokens.map(({ pattern }, i) => {
841
+ const next = tokens[i + 1];
842
+ if (!next || next.pattern.includes("/")) {
843
+ return pattern;
844
+ }
845
+ const slashRequired = tokens.slice(i + 1).some((e) => {
846
+ return e.parts.some((e2) => {
847
+ return e2.type === "static" || e2.kind === "required";
848
+ });
849
+ });
850
+ return slashRequired ? `${pattern}/` : pattern;
851
+ }).join("")
852
+ ];
853
+ };
854
+ var normalizeStaticValue = (value) => {
855
+ return value.replace(/\+/g, "\\\\+");
652
856
  };
653
857
  var sortRoutes = (a, b) => {
654
- const aStaticSegments = staticSegments(a.pathTokens);
655
- const bStaticSegments = staticSegments(b.pathTokens);
656
- if (aStaticSegments !== bStaticSegments) {
657
- return bStaticSegments - aStaticSegments;
858
+ const aSpecificity = routeSpecificity(a.pathTokens);
859
+ const bSpecificity = routeSpecificity(b.pathTokens);
860
+ if (aSpecificity !== bSpecificity) {
861
+ return bSpecificity - aSpecificity;
658
862
  }
659
863
  if (a.pathTokens.length !== b.pathTokens.length) {
660
864
  return a.pathTokens.length - b.pathTokens.length;
661
865
  }
662
866
  return a.name.localeCompare(b.name);
663
867
  };
664
- var staticSegments = (pathTokens) => {
665
- return pathTokens.reduce((a, e) => a + (e.param ? 0 : 1), 0);
868
+ var paramWeight = (part) => {
869
+ return {
870
+ required: 2,
871
+ optional: 1,
872
+ splat: 0
873
+ }[part.kind];
874
+ };
875
+ var mixedSegmentWeight = (parts) => {
876
+ const hasSplat = parts.some((p) => {
877
+ return p.type === "param" ? p.kind === "splat" : false;
878
+ });
879
+ return hasSplat ? 0.5 : 3;
880
+ };
881
+ var segmentWeight = (token) => {
882
+ return {
883
+ static: 4,
884
+ mixed: mixedSegmentWeight(token.parts),
885
+ param: paramWeight(token.parts[0])
886
+ }[token.kind];
887
+ };
888
+ var routeSpecificity = (pathTokens) => {
889
+ return pathTokens.reduce((sum, token) => sum + segmentWeight(token), 0);
666
890
  };
667
891
 
668
892
  // src/routes-factory/templates/resolved-types.hbs
669
893
  var resolved_types_default = "{{#each resolvedTypes}}\nexport type {{name}} = {{text}};\n{{/each}}\n";
670
894
 
671
895
  // src/routes-factory/templates/types.hbs
672
- var types_default = '{{#each typeDeclarations}}{{text}}\n{{/each}}\n\nexport type {{params.id}} = {\n {{#each paramsSchema}}\n "{{name}}"{{#unless isRequired}}?{{/unless}}:{{#if isRest}} Array<{{/if}}\n {{#if refinement}}{{refinement.text}}{{else}}string{{/if}}\n {{#if isRest}}>{{/if}}\n {{/each}}\n};\n\n{{#each payloadTypes}}\nexport type {{id}} = {{text}};\n{{/each}}\n\n{{#each responseTypes}}\nexport type {{id}} = {{text}};\n{{/each}}\n';
896
+ var types_default = '{{#each typeDeclarations}}{{text}}\n{{/each}}\n\nexport type {{params.id}} = {\n {{#each paramsSchema}}\n "{{name}}"{{#unless isRequired}}?{{/unless}}: {{#if refinement}}\n {{refinement.text}},\n {{else}}\n {{#if isSplat}}Array<string>{{else}}string{{/if}},\n {{/if}}\n {{/each}}\n};\n\n{{#each validationTypes}}export type {{id}} = {{text}};\n{{/each}}\n';
673
897
 
674
898
  // src/routes-factory/resolve.ts
675
899
  var API_INDEX_BASENAME = "index";
@@ -740,15 +964,18 @@ var createRouteEntry = (fileFullpath, {
740
964
  return;
741
965
  }
742
966
  const [folder, file] = resolvedPaths;
743
- const pathTokens = pathTokensFactory(dirname3(file));
744
- return {
745
- id: `${file.replace(/\W+/g, "_")}_${crc5(file)}`,
746
- name: pathTokens.map((e) => e.orig).join("/"),
747
- folder,
748
- file,
749
- fileFullpath,
750
- pathTokens
751
- };
967
+ const id = `${file.replace(/\W+/g, "_")}_${crc5(file)}`;
968
+ const name = dirname3(file);
969
+ try {
970
+ const [pathTokens, pathPattern] = pathTokensFactory(dirname3(file));
971
+ return { id, name, folder, file, fileFullpath, pathTokens, pathPattern };
972
+ } catch (error) {
973
+ console.error(
974
+ `\u2757${styleText2("red", "ERROR")}: Failed parsing path for "${styleText2("cyan", file)}"`
975
+ );
976
+ console.error(error);
977
+ return;
978
+ }
752
979
  };
753
980
  var pageLayoutResolverFactory = () => {
754
981
  return (entry) => {
@@ -764,14 +991,17 @@ var pageLayoutResolverFactory = () => {
764
991
  };
765
992
  var pageRouteResolverFactory = () => {
766
993
  return (entry) => {
767
- const { id, name, folder, file, fileFullpath, pathTokens } = entry;
994
+ const { id, name, folder, file, fileFullpath, pathTokens, pathPattern } = entry;
768
995
  const handler = async () => {
769
996
  const entry2 = {
770
997
  id,
771
998
  name,
772
999
  pathTokens,
1000
+ pathPattern,
773
1001
  params: {
774
- schema: pathTokens.flatMap((e) => e.param ? [e.param] : [])
1002
+ schema: pathTokens.flatMap((e) => {
1003
+ return e.parts.filter((p) => p.type === "param");
1004
+ })
775
1005
  },
776
1006
  folder,
777
1007
  file,
@@ -802,28 +1032,33 @@ var apiRouteResolverFactory = (pluginOptions) => {
802
1032
  appRoot,
803
1033
  sourceFolder,
804
1034
  generators = [],
805
- formatters = [],
806
1035
  refineTypeName
807
1036
  } = pluginOptions;
808
- let resolveTypes = false;
809
- for (const { options } of generators) {
810
- if (options?.resolveTypes) {
811
- resolveTypes = true;
812
- }
813
- }
1037
+ const resolveTypes = generators.some((e) => e.options?.resolveTypes);
814
1038
  const {
815
1039
  //
816
1040
  literalTypesResolver,
817
1041
  getSourceFile,
818
1042
  refreshSourceFile
819
1043
  } = typeResolverFactory(pluginOptions);
820
- return (entry) => {
821
- const { id, name, file, folder, fileFullpath, pathTokens } = entry;
1044
+ return ({
1045
+ id,
1046
+ name,
1047
+ file,
1048
+ folder,
1049
+ fileFullpath,
1050
+ pathTokens,
1051
+ pathPattern
1052
+ }) => {
822
1053
  const handler = async (updatedFile) => {
823
- const paramsSchema = pathTokens.flatMap((e) => {
824
- return e.param ? [e.param] : [];
825
- });
826
- const optionalParams = paramsSchema.length ? !paramsSchema.some((e) => e.isRequired) : true;
1054
+ const paramsSchema = pathTokens.flatMap(
1055
+ (e) => {
1056
+ return e.parts.flatMap((p) => {
1057
+ return p.type === "param" ? [p] : [];
1058
+ });
1059
+ }
1060
+ );
1061
+ const optionalParams = paramsSchema.length ? paramsSchema.filter((e) => e.kind === "required").length === 0 : true;
827
1062
  const { getCache, persistCache } = cacheFactory(
828
1063
  { id, file, fileFullpath },
829
1064
  {
@@ -841,11 +1076,10 @@ var apiRouteResolverFactory = (pluginOptions) => {
841
1076
  typeDeclarations,
842
1077
  paramsRefinements,
843
1078
  methods,
844
- payloadTypes,
845
- responseTypes,
1079
+ validationDefinitions: validationDefinitions2,
846
1080
  referencedFiles = []
847
1081
  } = await resolveRouteSignature(
848
- { id, fileFullpath, optionalParams },
1082
+ { id, name, fileFullpath, optionalParams },
849
1083
  {
850
1084
  withReferencedFiles: true,
851
1085
  sourceFile: getSourceFile(fileFullpath),
@@ -854,6 +1088,11 @@ var apiRouteResolverFactory = (pluginOptions) => {
854
1088
  }
855
1089
  }
856
1090
  );
1091
+ const validationTypes = validationDefinitions2.flatMap((def) => {
1092
+ return def.target === "response" ? def.variants.flatMap(({ id: id2, body }) => {
1093
+ return body ? [{ id: id2, text: body }] : [];
1094
+ }) : [def.schema];
1095
+ });
857
1096
  const numericParams = paramsRefinements ? paramsRefinements.flatMap(({ text, index }) => {
858
1097
  if (text === "number") {
859
1098
  const param = paramsSchema.at(index);
@@ -875,25 +1114,21 @@ var apiRouteResolverFactory = (pluginOptions) => {
875
1114
  paramsSchema: paramsSchema.map((param, index) => {
876
1115
  return {
877
1116
  ...param,
1117
+ isRequired: param.kind === "required",
1118
+ isSplat: param.kind === "splat",
878
1119
  refinement: paramsRefinements?.at(index)
879
1120
  };
880
1121
  }),
881
1122
  typeDeclarations,
882
- payloadTypes,
883
- responseTypes
1123
+ validationTypes
884
1124
  });
885
1125
  const resolvedTypes = resolveTypes ? literalTypesResolver(typesFileContent, {
886
- overrides: [...payloadTypes, ...responseTypes].reduce(
887
- (map, { id: id2, skipValidation }) => {
888
- if (skipValidation) {
889
- map[id2] = "never";
890
- }
891
- return map;
892
- },
893
- { [refineTypeName]: refineTypeName }
894
- ),
895
- withProperties: [params.id, ...payloadTypes.map((e) => e.id)],
896
- formatters
1126
+ stripComments: true,
1127
+ overrides: { [refineTypeName]: refineTypeName },
1128
+ withProperties: [
1129
+ params.id,
1130
+ ...validationTypes.flatMap(({ id: id2 }) => id2)
1131
+ ]
897
1132
  }) : void 0;
898
1133
  await renderToFile(
899
1134
  typesFile,
@@ -906,26 +1141,94 @@ var apiRouteResolverFactory = (pluginOptions) => {
906
1141
  methods,
907
1142
  typeDeclarations,
908
1143
  numericParams,
909
- // text was needed at writing types.ts file, dropping from cache
910
- payloadTypes: payloadTypes.map(({ text, ...rest }) => {
911
- return {
912
- ...rest,
913
- resolvedType: resolvedTypes?.find((e) => e.name === rest.id)
914
- };
915
- }),
916
- responseTypes: responseTypes.map(({ text, ...rest }) => {
1144
+ referencedFiles,
1145
+ validationDefinitions: validationDefinitions2.map((def) => {
917
1146
  return {
918
- ...rest,
919
- resolvedType: resolvedTypes?.find((e) => e.name === rest.id)
1147
+ ...def,
1148
+ ...def.target === "response" ? {
1149
+ variants: def.variants.map((variant) => {
1150
+ return {
1151
+ ...variant,
1152
+ resolvedType: resolvedTypes?.find(
1153
+ (e) => e.name === variant.id
1154
+ )
1155
+ };
1156
+ })
1157
+ } : {
1158
+ schema: {
1159
+ ...def.schema,
1160
+ resolvedType: resolvedTypes?.find(
1161
+ (e) => e.name === def.schema.id
1162
+ )
1163
+ }
1164
+ }
920
1165
  };
921
- }),
922
- referencedFiles
1166
+ })
923
1167
  });
924
1168
  }
925
- const entry2 = {
1169
+ const validationDefinitions = cache.validationDefinitions.flatMap(
1170
+ (def) => {
1171
+ let augmentedDef = def;
1172
+ if (def.target === "response") {
1173
+ augmentedDef = {
1174
+ ...def,
1175
+ variants: def.variants.flatMap((variant, i) => {
1176
+ if (typeof variant.contentType !== "string") {
1177
+ return [variant];
1178
+ }
1179
+ if (variant.contentType.includes("/")) {
1180
+ return [variant];
1181
+ }
1182
+ const contentType = mimeTypes.lookup(variant.contentType);
1183
+ if (contentType === false) {
1184
+ console.warn(
1185
+ styleText2(
1186
+ ["bold", "red"],
1187
+ "\u2717 Failed resolving Response Content Type"
1188
+ )
1189
+ );
1190
+ console.warn(
1191
+ ` Invalid value provided for mime-types lookup - ${variant.contentType}`
1192
+ );
1193
+ console.warn(
1194
+ styleText2(
1195
+ ["cyan"],
1196
+ ` Response variant #${i} excluded from route schemas`
1197
+ )
1198
+ );
1199
+ console.warn(` Route: ${name}; Method: ${def.method}`);
1200
+ console.warn();
1201
+ return [];
1202
+ }
1203
+ return [{ ...variant, contentType }];
1204
+ })
1205
+ };
1206
+ } else if (def.contentType && !def.contentType.includes("/")) {
1207
+ const contentType = mimeTypes.lookup(def.contentType);
1208
+ if (contentType === false) {
1209
+ console.warn(
1210
+ styleText2(
1211
+ ["bold", "red"],
1212
+ "\u2717 Failed resolving Response Content Type"
1213
+ )
1214
+ );
1215
+ console.warn(
1216
+ ` Invalid value provided for mime-types lookup - ${def.contentType}`
1217
+ );
1218
+ console.warn(` Route: ${name}; Method: ${def.method}`);
1219
+ console.warn();
1220
+ } else {
1221
+ augmentedDef = { ...def, contentType };
1222
+ }
1223
+ }
1224
+ return augmentedDef ? [augmentedDef] : [];
1225
+ }
1226
+ );
1227
+ const entry = {
926
1228
  id,
927
1229
  name,
928
1230
  pathTokens,
1231
+ pathPattern,
929
1232
  params: cache.params,
930
1233
  numericParams: cache.numericParams,
931
1234
  optionalParams,
@@ -934,8 +1237,7 @@ var apiRouteResolverFactory = (pluginOptions) => {
934
1237
  fileFullpath,
935
1238
  methods: cache.methods,
936
1239
  typeDeclarations: cache.typeDeclarations,
937
- payloadTypes: cache.payloadTypes,
938
- responseTypes: cache.responseTypes,
1240
+ validationDefinitions,
939
1241
  referencedFiles: Object.keys(cache.referencedFiles).map(
940
1242
  // expand referenced files path,
941
1243
  // they are stored as relative in cache
@@ -944,7 +1246,7 @@ var apiRouteResolverFactory = (pluginOptions) => {
944
1246
  };
945
1247
  return {
946
1248
  kind: "apiRoute",
947
- entry: entry2
1249
+ entry
948
1250
  };
949
1251
  };
950
1252
  return { name, handler };
@@ -1075,32 +1377,29 @@ var routesFactory = async (pluginOptions) => {
1075
1377
 
1076
1378
  // src/base-plugin/api-handler.ts
1077
1379
  import { join as join4, resolve as resolve4 } from "node:path";
1078
- import { styleText } from "node:util";
1380
+ import { styleText as styleText3 } from "node:util";
1079
1381
  import { context } from "esbuild";
1080
1382
  var api_handler_default = async (options) => {
1081
1383
  const { appRoot, sourceFolder, baseurl, apiurl } = options;
1082
1384
  const { createPath } = pathResolver({ appRoot, sourceFolder });
1083
1385
  const outDir = join4(options.outDir, defaults.apiDir);
1084
1386
  const esbuildOptions = await import(resolve4(appRoot, "esbuild.json"), { with: { type: "json" } }).then((e) => e.default);
1085
- let app;
1086
- let devMiddlewareFactory;
1087
- let teardownHandler;
1387
+ let devSetup;
1088
1388
  const watcher = async () => {
1089
1389
  const rebuildPlugin = {
1090
1390
  name: "rebuild",
1091
1391
  setup(build) {
1092
1392
  build.onEnd(async () => {
1093
- if (app) {
1094
- await teardownHandler?.(app);
1393
+ if (devSetup) {
1394
+ await devSetup.teardownHandler?.();
1095
1395
  }
1096
1396
  try {
1097
- const exports = await import(`${outDir}/app.js?${Date.now()}`);
1098
- devMiddlewareFactory = exports.devMiddlewareFactory;
1099
- teardownHandler = exports.teardownHandler;
1100
- app = await exports.default();
1101
- console.debug(`${styleText("green", "\u279C")} Api handler ready`);
1397
+ await import(`${outDir}/dev.js?${Date.now()}`).then((e) => {
1398
+ devSetup = e.default;
1399
+ });
1400
+ console.debug(`${styleText3("green", "\u279C")} Api handler ready`);
1102
1401
  } catch (error) {
1103
- console.error(`${styleText("red", "\u2717")} Api handler error`);
1402
+ console.error(`${styleText3("red", "\u2717")} Api handler error`);
1104
1403
  console.error(error);
1105
1404
  }
1106
1405
  });
@@ -1108,9 +1407,13 @@ var api_handler_default = async (options) => {
1108
1407
  };
1109
1408
  const ctx = await context({
1110
1409
  ...esbuildOptions,
1410
+ define: {
1411
+ ...esbuildOptions.define,
1412
+ PRODUCTION_BUILD: "false"
1413
+ },
1111
1414
  logLevel: "error",
1112
1415
  bundle: true,
1113
- entryPoints: [createPath.api("app.ts")],
1416
+ entryPoints: [createPath.api("dev.ts")],
1114
1417
  plugins: [rebuildPlugin],
1115
1418
  outdir: outDir
1116
1419
  });
@@ -1126,16 +1429,20 @@ var api_handler_default = async (options) => {
1126
1429
  }
1127
1430
  };
1128
1431
  };
1129
- const devMiddleware = async (req, res, viteHandler) => {
1130
- const next = () => {
1131
- return viteHandler();
1132
- };
1133
- if (devMiddlewareFactory) {
1134
- const handler = devMiddlewareFactory(app);
1135
- await handler(req, res, next);
1136
- } else {
1137
- !req?.url || !new RegExp(`^${join4(baseurl, apiurl)}($|/)`).test(req.url) ? next() : await app?.callback()(req, res);
1432
+ const devMiddleware = async (req, res, next) => {
1433
+ const {
1434
+ requestMatcher = () => {
1435
+ return new RegExp(`^${join4(baseurl, apiurl)}($|/)`).test(
1436
+ req.url
1437
+ );
1438
+ },
1439
+ requestHandler
1440
+ } = { ...devSetup };
1441
+ if (!requestMatcher(req)) {
1442
+ return next();
1138
1443
  }
1444
+ const handler = requestHandler?.();
1445
+ return handler ? handler(req, res) : next();
1139
1446
  };
1140
1447
  return {
1141
1448
  watcher,
@@ -1144,9 +1451,9 @@ var api_handler_default = async (options) => {
1144
1451
  };
1145
1452
 
1146
1453
  // src/base-plugin/spinner.ts
1147
- import ora from "ora";
1454
+ import { Spinner } from "@topcli/spinner";
1148
1455
  var spinnerFactory = (startText) => {
1149
- const spinner = ora().start(startText);
1456
+ const spinner = new Spinner().start(startText);
1150
1457
  let _text = startText;
1151
1458
  return {
1152
1459
  text(text) {
@@ -1168,7 +1475,7 @@ var spinnerFactory = (startText) => {
1168
1475
  if (text) {
1169
1476
  this.text([_text, text].join("\n"));
1170
1477
  }
1171
- spinner.fail();
1478
+ spinner.failed();
1172
1479
  }
1173
1480
  };
1174
1481
  };
@@ -1179,19 +1486,13 @@ var base_plugin_default = (apiurl, pluginOptions) => {
1179
1486
  const outDirSuffix = "client";
1180
1487
  const store = {};
1181
1488
  const createWorker = () => {
1182
- const {
1183
- generators = [],
1184
- formatters = [],
1185
- ...restOptions
1186
- } = store.resolvedOptions;
1489
+ const { generators = [], ...restOptions } = store.resolvedOptions;
1187
1490
  const generatorModules = generators.map(
1188
1491
  (e) => [e.moduleImport, e.moduleConfig]
1189
1492
  );
1190
- const formatterModules = pluginOptions?.formatters ? pluginOptions.formatters.map((e) => [e.moduleImport, e.moduleConfig]) : [];
1191
1493
  const workerData = {
1192
1494
  ...restOptions,
1193
- generatorModules,
1194
- formatterModules
1495
+ generatorModules
1195
1496
  };
1196
1497
  return new Worker(resolve5(import.meta.dirname, "base-plugin/worker.js"), {
1197
1498
  workerData,
@@ -1230,10 +1531,10 @@ var base_plugin_default = (apiurl, pluginOptions) => {
1230
1531
  const { error } = msg;
1231
1532
  if (error.stack) {
1232
1533
  const [message, ...stack] = error.stack.split("\n");
1233
- console.error(styleText2("red", message));
1534
+ console.error(styleText4("red", message));
1234
1535
  console.error(stack.join("\n"));
1235
1536
  } else if (error?.message) {
1236
- console.error(`${styleText2("red", error?.name)}: ${error.message}`);
1537
+ console.error(`${styleText4("red", error?.name)}: ${error.message}`);
1237
1538
  } else {
1238
1539
  console.error(error);
1239
1540
  }
@@ -1275,19 +1576,12 @@ var base_plugin_default = (apiurl, pluginOptions) => {
1275
1576
  ...store.config.server.watch ? { options: store.config.server.watch } : {}
1276
1577
  };
1277
1578
  {
1278
- const {
1279
- generators = [],
1280
- formatters = [],
1281
- refineTypeName = "TRefine"
1282
- } = { ...pluginOptions };
1283
- const apiGenerator = generators.find((e) => e.kind === "api");
1284
- const fetchGenerator = generators.find((e) => e.kind === "fetch");
1285
- const ssrGenerator = generators.find((e) => e.kind === "ssr");
1286
- if (!apiGenerator || !fetchGenerator) {
1287
- throw new Error(
1288
- "Some of required generators missing, make sure both `api` and `fetch` generators configured properly"
1289
- );
1290
- }
1579
+ const { generators = [], refineTypeName = "TRefine" } = {
1580
+ ...pluginOptions
1581
+ };
1582
+ const apiGenerator = generators.find((e) => e.slot === "api");
1583
+ const fetchGenerator = generators.find((e) => e.slot === "fetch");
1584
+ const ssrGenerator = generators.find((e) => e.slot === "ssr");
1291
1585
  store.resolvedOptions = {
1292
1586
  ...pluginOptions,
1293
1587
  command: store.config.command,
@@ -1296,17 +1590,16 @@ var base_plugin_default = (apiurl, pluginOptions) => {
1296
1590
  // 1. stub generator should run first
1297
1591
  stubGenerator(),
1298
1592
  // 2. then api generator
1299
- apiGenerator,
1300
- // 3. then fetch generator
1301
- fetchGenerator,
1593
+ ...apiGenerator ? [apiGenerator] : [],
1594
+ // 3. then fetch generator, only if api generator also enabled
1595
+ ...fetchGenerator && apiGenerator ? [fetchGenerator] : [],
1302
1596
  // 4. user generators in the order they were added
1303
1597
  ...generators.filter((e) => {
1304
- return e.kind ? !["api", "fetch", "ssr"].includes(e.kind) : true;
1598
+ return e.slot ? !["api", "fetch", "ssr"].includes(e.slot) : true;
1305
1599
  }),
1306
1600
  // 5. ssr generator should run last
1307
1601
  ...ssrGenerator ? [ssrGenerator] : []
1308
1602
  ],
1309
- formatters: formatters.map((e) => e.formatter),
1310
1603
  refineTypeName,
1311
1604
  baseurl: store.config.base,
1312
1605
  apiurl,
@@ -1315,6 +1608,52 @@ var base_plugin_default = (apiurl, pluginOptions) => {
1315
1608
  outDir
1316
1609
  };
1317
1610
  }
1611
+ const packageJsonFile = resolve5(appRoot, "package.json");
1612
+ const packageJson = await import(packageJsonFile, {
1613
+ with: { type: "json" }
1614
+ }).then((e) => e.default);
1615
+ const newDependencies = [];
1616
+ for (const generator of store.resolvedOptions.generators) {
1617
+ for (const key of ["dependencies", "devDependencies"]) {
1618
+ for (const [pkg, ver] of Object.entries(generator[key] || {})) {
1619
+ if (!packageJson[key]?.[pkg]) {
1620
+ newDependencies.push([key, pkg, ver]);
1621
+ }
1622
+ }
1623
+ }
1624
+ }
1625
+ if (newDependencies.length) {
1626
+ console.warn();
1627
+ console.warn(
1628
+ [
1629
+ "\u{1F4A1} ",
1630
+ styleText4(["bold", "italic", "red"], "New dependencies added: "),
1631
+ styleText4("dim", newDependencies.map(([, pkg]) => pkg).join(", "))
1632
+ ].join("")
1633
+ );
1634
+ console.warn(
1635
+ "\u{1F4E6}",
1636
+ [
1637
+ styleText4(
1638
+ ["bold", "blueBright"],
1639
+ store.config.command === "build" ? "Install them and run a new build: " : "Install them and restart dev server: "
1640
+ ),
1641
+ styleText4(
1642
+ "dim",
1643
+ ["npm", "pnpm", "yarn"].map((e) => `\`${e} install\``).join(" / ")
1644
+ )
1645
+ ].join("")
1646
+ );
1647
+ console.warn();
1648
+ for (const [key, pkg, ver] of newDependencies) {
1649
+ packageJson[key] = { ...packageJson[key], [pkg]: ver };
1650
+ }
1651
+ await writeFile3(
1652
+ packageJsonFile,
1653
+ JSON.stringify(packageJson, null, 2),
1654
+ "utf8"
1655
+ );
1656
+ }
1318
1657
  if (store.config.command === "build") {
1319
1658
  const { resolvers } = await routesFactory(store.resolvedOptions);
1320
1659
  const resolvedEntries = [];
@@ -1343,6 +1682,10 @@ var base_plugin_default = (apiurl, pluginOptions) => {
1343
1682
  if (store.config.command !== "serve") {
1344
1683
  return;
1345
1684
  }
1685
+ if (!store.resolvedOptions.generators.find((e) => e.slot === "api")) {
1686
+ const stopWorker2 = workerHandler(() => stopWorker2());
1687
+ return;
1688
+ }
1346
1689
  const apiHandler = await api_handler_default(store.resolvedOptions);
1347
1690
  const apiWatcher = await apiHandler.watcher();
1348
1691
  const stopWorker = workerHandler(
@@ -1421,13 +1764,14 @@ export {
1421
1764
  isPageRoute,
1422
1765
  isRouteFile,
1423
1766
  nestedRoutesFactory,
1767
+ normalizeStaticValue,
1424
1768
  pageLayoutResolverFactory,
1425
1769
  pageRouteResolverFactory,
1426
1770
  pathResolver,
1427
1771
  pathTokensFactory,
1428
1772
  render,
1429
- renderAsFile,
1430
1773
  renderFactory,
1774
+ renderHelpers,
1431
1775
  renderToFile,
1432
1776
  routesFactory,
1433
1777
  scanRoutes,