@batijs/cli 0.0.650 → 0.0.651

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 (93) hide show
  1. package/dist/boilerplates/@batijs/authjs/files/server/authjs-handler.ts +1 -1
  2. package/dist/boilerplates/@batijs/aws/files/cdk/bin/infrastructure.ts +1 -1
  3. package/dist/boilerplates/@batijs/better-auth/files/database/better-auth/migrate.ts +1 -3
  4. package/dist/boilerplates/@batijs/better-auth/files/database/drizzle/schema/auth.ts +5 -5
  5. package/dist/boilerplates/@batijs/better-auth/files/server/better-auth-handler.ts +2 -2
  6. package/dist/boilerplates/@batijs/better-auth/files/server/better-auth.ts +8 -8
  7. package/dist/boilerplates/@batijs/cloudflare/files/$vite.config.ts.js +9 -9
  8. package/dist/boilerplates/@batijs/compiled/files/$vite.config.ts.js +9 -9
  9. package/dist/boilerplates/@batijs/docker-compose/files/docker-compose.yml +6 -6
  10. package/dist/boilerplates/@batijs/drizzle/files/database/drizzle/db.ts +3 -3
  11. package/dist/boilerplates/@batijs/drizzle/files/database/drizzle/queries/todos.ts +10 -10
  12. package/dist/boilerplates/@batijs/drizzle/files/database/drizzle/schema/todos.ts +2 -2
  13. package/dist/boilerplates/@batijs/drizzle/files/drizzle.config.ts +3 -3
  14. package/dist/boilerplates/@batijs/drizzle/types/database/drizzle/queries/todos.d.mts +6 -6
  15. package/dist/boilerplates/@batijs/edgeone/files/$vite.config.ts.js +7 -7
  16. package/dist/boilerplates/@batijs/elysia/files/+server.ts +1 -1
  17. package/dist/boilerplates/@batijs/elysia/files/server/elysia.ts +9 -9
  18. package/dist/boilerplates/@batijs/eslint/files/eslint.config.ts +14 -14
  19. package/dist/boilerplates/@batijs/express/files/+server.ts +10 -10
  20. package/dist/boilerplates/@batijs/fastify/files/+server.ts +10 -10
  21. package/dist/boilerplates/@batijs/hono/files/+server.ts +2 -2
  22. package/dist/boilerplates/@batijs/hono/files/entry_aws_lambda.ts +1 -3
  23. package/dist/boilerplates/@batijs/hono/files/server/hono.ts +9 -9
  24. package/dist/boilerplates/@batijs/kysely/files/$vite.config.ts.js +9 -12
  25. package/dist/boilerplates/@batijs/kysely/files/database/kysely/db.ts +5 -5
  26. package/dist/boilerplates/@batijs/kysely/files/database/kysely/migrate.ts +2 -4
  27. package/dist/boilerplates/@batijs/kysely/files/database/kysely/migrations/001_create_todos_table.ts +2 -3
  28. package/dist/boilerplates/@batijs/kysely/files/database/kysely/queries/todos.ts +8 -8
  29. package/dist/boilerplates/@batijs/kysely/files/vite-plugin-input.ts +1 -2
  30. package/dist/boilerplates/@batijs/kysely/types/database/kysely/queries/todos.d.mts +8 -8
  31. package/dist/boilerplates/@batijs/netlify/files/$vite.config.ts.js +8 -8
  32. package/dist/boilerplates/@batijs/postgres/files/database/postgres/db.ts +1 -1
  33. package/dist/boilerplates/@batijs/postgres/files/database/postgres/schema/todos.ts +1 -1
  34. package/dist/boilerplates/@batijs/react/files/$vite.config.ts.js +7 -7
  35. package/dist/boilerplates/@batijs/react/files/pages/+Head.tsx +6 -6
  36. package/dist/boilerplates/@batijs/react/files/pages/+Layout.tsx +14 -14
  37. package/dist/boilerplates/@batijs/react/files/pages/+config.ts +3 -3
  38. package/dist/boilerplates/@batijs/react/files/pages/index/+Page.tsx +1 -1
  39. package/dist/boilerplates/@batijs/react/files/pages/index/Counter.tsx +3 -3
  40. package/dist/boilerplates/@batijs/react/files/pages/todo/TodoList.tsx +6 -6
  41. package/dist/boilerplates/@batijs/react-better-auth/files/pages/account/+Page.tsx +1 -1
  42. package/dist/boilerplates/@batijs/react-better-auth/files/pages/login/+Page.tsx +4 -4
  43. package/dist/boilerplates/@batijs/react-better-auth/files/pages/signup/+Page.tsx +4 -4
  44. package/dist/boilerplates/@batijs/sentry/files/$vite.config.ts.js +10 -10
  45. package/dist/boilerplates/@batijs/sentry/files/pages/$+client.ts.js +12 -18
  46. package/dist/boilerplates/@batijs/shadcn-ui/files/$vite.config.ts.js +5 -27
  47. package/dist/boilerplates/@batijs/shared/files/vite.config.ts +1 -1
  48. package/dist/boilerplates/@batijs/shared-db/files/server/db-middleware.ts +21 -21
  49. package/dist/boilerplates/@batijs/shared-db/types/server/db-middleware.d.mts +10 -10
  50. package/dist/boilerplates/@batijs/shared-env/files/server/env.ts +6 -4
  51. package/dist/boilerplates/@batijs/shared-env/files/server/load.ts +1 -1
  52. package/dist/boilerplates/@batijs/shared-env/types/server/env.d.mts +2 -2
  53. package/dist/boilerplates/@batijs/shared-server/files/server/create-todo-handler.ts +16 -16
  54. package/dist/boilerplates/@batijs/shared-server/types/server/create-todo-handler.d.mts +10 -10
  55. package/dist/boilerplates/@batijs/shared-todo/files/global.d.ts +11 -11
  56. package/dist/boilerplates/@batijs/shared-todo/files/pages/todo/+config.ts +1 -4
  57. package/dist/boilerplates/@batijs/shared-todo/files/pages/todo/+data.ts +5 -5
  58. package/dist/boilerplates/@batijs/solid/files/$vite.config.ts.js +7 -7
  59. package/dist/boilerplates/@batijs/solid/files/pages/+Head.tsx +3 -4
  60. package/dist/boilerplates/@batijs/solid/files/pages/+Layout.tsx +10 -10
  61. package/dist/boilerplates/@batijs/solid/files/pages/+config.ts +3 -3
  62. package/dist/boilerplates/@batijs/solid/files/pages/index/Counter.tsx +2 -2
  63. package/dist/boilerplates/@batijs/solid/files/pages/todo/TodoList.tsx +6 -6
  64. package/dist/boilerplates/@batijs/solid-better-auth/files/pages/account/+Page.tsx +1 -1
  65. package/dist/boilerplates/@batijs/solid-better-auth/files/pages/login/+Page.tsx +4 -4
  66. package/dist/boilerplates/@batijs/solid-better-auth/files/pages/signup/+Page.tsx +4 -4
  67. package/dist/boilerplates/@batijs/sqlite/files/database/sqlite/db.ts +1 -1
  68. package/dist/boilerplates/@batijs/sqlite/files/database/sqlite/schema/todos.ts +1 -1
  69. package/dist/boilerplates/@batijs/tailwindcss/files/$vite.config.ts.js +7 -7
  70. package/dist/boilerplates/@batijs/tailwindcss/files/pages/tailwind.css +2 -2
  71. package/dist/boilerplates/@batijs/telefunc/files/$vite.config.ts.js +8 -8
  72. package/dist/boilerplates/@batijs/telefunc/files/global.d.ts +12 -12
  73. package/dist/boilerplates/@batijs/telefunc/files/pages/todo/TodoList.telefunc.ts +5 -5
  74. package/dist/boilerplates/@batijs/telefunc/files/server/telefunc-handler.ts +12 -12
  75. package/dist/boilerplates/@batijs/trpc/files/server/trpc-handler.ts +4 -4
  76. package/dist/boilerplates/@batijs/trpc/files/trpc/server.ts +15 -15
  77. package/dist/boilerplates/@batijs/ts-rest/files/server/ts-rest-handler.ts +15 -15
  78. package/dist/boilerplates/@batijs/vercel/files/$vite.config.ts.js +8 -8
  79. package/dist/boilerplates/@batijs/vue/files/$vite.config.ts.js +7 -7
  80. package/dist/boilerplates/@batijs/vue/files/components/Content.vue +2 -2
  81. package/dist/boilerplates/@batijs/vue/files/components/Counter.vue +3 -3
  82. package/dist/boilerplates/@batijs/vue/files/components/Logo.vue +2 -2
  83. package/dist/boilerplates/@batijs/vue/files/components/Sidebar.vue +2 -2
  84. package/dist/boilerplates/@batijs/vue/files/pages/+Head.vue +2 -3
  85. package/dist/boilerplates/@batijs/vue/files/pages/+Layout.vue +3 -3
  86. package/dist/boilerplates/@batijs/vue/files/pages/+config.ts +3 -3
  87. package/dist/boilerplates/@batijs/vue/files/pages/+onCreateApp.ts +1 -1
  88. package/dist/boilerplates/@batijs/vue/files/pages/todo/TodoList.vue +8 -8
  89. package/dist/boilerplates/@batijs/vue-better-auth/files/pages/account/+Page.vue +1 -1
  90. package/dist/boilerplates/@batijs/vue-better-auth/files/pages/login/+Page.vue +3 -3
  91. package/dist/boilerplates/@batijs/vue-better-auth/files/pages/signup/+Page.vue +2 -2
  92. package/dist/index.js +40 -43
  93. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { access, constants, lstat, mkdir, opendir, readFile, readdir, rm, rmdir,
7
7
  import { tmpdir } from "node:os";
8
8
  import path, { dirname, extname, join, normalize, parse, relative } from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
- import { formatCode, getVersion, packageManager, parseModule, transformAndFormat, which, withIcon } from "@batijs/core";
10
+ import { formatCode, getVersion, markEmptyExport, mergeDts, packageManager, transformAndFormat, which, withIcon } from "@batijs/core";
11
11
  import { BatiSet, cliFlags, features } from "@batijs/features";
12
12
  import { RulesMessage, execRules } from "@batijs/features/rules";
13
13
  import { AsyncLocalStorage, AsyncResource } from "node:async_hooks";
@@ -49,39 +49,36 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
49
49
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
50
50
  //#endregion
51
51
  //#region ../build/dist/index.js
52
- async function mergeDts({ fileContent, previousContent, filepath, meta }) {
53
- const previousAst = parseModule(previousContent);
54
- const currentAst = parseModule(fileContent);
55
- for (const imp of previousAst.imports.$items) currentAst.imports[imp.local] = imp;
56
- const index = currentAst.$ast.body.findIndex((node) => node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration");
57
- for (const node of previousAst.$ast.body) {
58
- if (node.type === "ImportDeclaration" || node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration") continue;
59
- if (index === -1) currentAst.$ast.body.push(node);
60
- else currentAst.$ast.body.splice(index, 0, node);
61
- }
62
- return clearExports((await transformAndFormat(currentAst.generate().code, meta, { filepath })).code, meta);
63
- }
64
- function clearExports(code, meta) {
52
+ let merger;
53
+ let emptyExportMarker;
54
+ /**
55
+ * Merge two already-`$$`-transformed `.d.ts` files into one: concatenate them and run the `mergeDts`
56
+ * codemod, which hoists/dedupes imports and folds same-named `declare global` / `declare module` /
57
+ * `namespace` / `interface` declarations together. Then tidy whitespace and strip a now-empty
58
+ * `export {}`.
59
+ */
60
+ async function mergeDts$1({ fileContent, previousContent, filepath, meta }) {
61
+ merger ??= mergeDts.forTarget("tsx");
62
+ return clearExports(await formatCode((await merger).transform(`${previousContent}\n${fileContent}`, {}), { filepath }), meta);
63
+ }
64
+ async function clearExports(code, meta) {
65
65
  if (code.trim() === "export {};") return;
66
- if (meta.BATI.has("biome")) {
67
- const index = code.indexOf("\nexport {};");
68
- const foundImport = code.match(/^import .* from /gm);
69
- if (index !== -1 && foundImport) return code.slice(0, index) + "\n// biome-ignore lint/complexity/noUselessEmptyExport: ensure that the file is considered as a module" + code.slice(index);
70
- }
71
- return code;
66
+ if (!meta.BATI.has("biome")) return code;
67
+ emptyExportMarker ??= markEmptyExport.forTarget("tsx");
68
+ return (await emptyExportMarker).transform(code, {});
72
69
  }
73
70
  async function executeOperationFile(op, { meta, previousOperationSameDestination }) {
74
71
  const code = await readFile(op.sourceAbsolute, { encoding: "utf-8" });
75
72
  const filepath = relative(op.source, op.sourceAbsolute);
76
73
  const result = await transformAndFormat(code, meta, { filepath });
77
74
  let fileContent = result.code;
78
- if (op.sourceAbsolute.endsWith(".d.ts")) if (previousOperationSameDestination?.content) fileContent = await mergeDts({
75
+ if (op.sourceAbsolute.endsWith(".d.ts")) if (previousOperationSameDestination?.content) fileContent = await mergeDts$1({
79
76
  fileContent,
80
77
  previousContent: previousOperationSameDestination.content,
81
- meta,
82
- filepath
78
+ filepath,
79
+ meta
83
80
  });
84
- else fileContent = clearExports(fileContent, meta);
81
+ else fileContent = await clearExports(fileContent, meta);
85
82
  return {
86
83
  context: result.context,
87
84
  content: fileContent ? fileContent.trimStart() : void 0
@@ -188,14 +185,14 @@ async function executeOperationTransform(op, { meta, previousOperationSameDestin
188
185
  }
189
186
  var RelationFile = class RelationFile {
190
187
  pathAbsolute;
191
- includeIfImported;
188
+ keepFileIfImported;
192
189
  static allPathAbsolute = /* @__PURE__ */ new Map();
193
- static allIncludeIfImported = [];
194
- constructor(pathAbsolute, includeIfImported) {
190
+ static allKeepFileIfImported = [];
191
+ constructor(pathAbsolute, keepFileIfImported) {
195
192
  this.pathAbsolute = pathAbsolute;
196
- this.includeIfImported = includeIfImported;
193
+ this.keepFileIfImported = keepFileIfImported;
197
194
  RelationFile.allPathAbsolute.set(pathAbsolute, this);
198
- if (includeIfImported) RelationFile.allIncludeIfImported.push(this);
195
+ if (keepFileIfImported) RelationFile.allKeepFileIfImported.push(this);
199
196
  }
200
197
  };
201
198
  var RelationImport = class RelationImport {
@@ -214,10 +211,10 @@ var RelationImport = class RelationImport {
214
211
  static computeUnimportedFiles() {
215
212
  const unimportedFiles = [];
216
213
  const importedByVolatileFile = [];
217
- for (const file of RelationFile.allIncludeIfImported) {
214
+ for (const file of RelationFile.allKeepFileIfImported) {
218
215
  const importedFile = RelationImport.allImports.find((ai) => ai.importTargetRelationFile === file);
219
216
  if (!importedFile) unimportedFiles.push(file);
220
- else if (importedFile.source.includeIfImported) importedByVolatileFile.push(importedFile);
217
+ else if (importedFile.source.keepFileIfImported) importedByVolatileFile.push(importedFile);
221
218
  }
222
219
  return computeDeepUnimportedFiles(importedByVolatileFile, unimportedFiles);
223
220
  }
@@ -290,8 +287,8 @@ async function main(options, meta) {
290
287
  const sources = Array.isArray(options.source) ? options.source : [options.source];
291
288
  const env = options.env ?? [];
292
289
  const deploy = options.deploy ?? [];
293
- function updateAllImports(target, imports, includeIfImported) {
294
- const rf = new RelationFile(target, includeIfImported);
290
+ function updateAllImports(target, imports, keepFileIfImported) {
291
+ const rf = new RelationFile(target, keepFileIfImported);
295
292
  if (!imports) return;
296
293
  for (const imp of imports.values()) new RelationImport(rf, path.resolve(path.dirname(target), imp));
297
294
  }
@@ -336,7 +333,7 @@ Please report this issue to https://github.com/vikejs/bati`);
336
333
  meta,
337
334
  previousOperationSameDestination: previousOp
338
335
  });
339
- updateAllImports(op.destinationAbsolute, report.context?.imports, Boolean(report.context?.flags.has("include-if-imported")));
336
+ updateAllImports(op.destinationAbsolute, report.context?.imports, Boolean(report.context?.flags.has("keep-file-if-imported")));
340
337
  } else if (op.kind === "transform") report = await executeOperationTransform(op, {
341
338
  meta,
342
339
  previousOperationSameDestination: previousOp,
@@ -2521,7 +2518,7 @@ var colorette_exports = /* @__PURE__ */ __exportAll({
2521
2518
  underline: () => underline,
2522
2519
  white: () => white,
2523
2520
  whiteBright: () => whiteBright,
2524
- yellow: () => yellow$1,
2521
+ yellow: () => yellow,
2525
2522
  yellowBright: () => yellowBright
2526
2523
  });
2527
2524
  const { env = {}, argv = [], platform = "" } = typeof process === "undefined" ? {} : process;
@@ -2583,7 +2580,7 @@ const createColors = ({ useColor = isColorSupported } = {}) => useColor ? colors
2583
2580
  ...colors,
2584
2581
  [key]: String
2585
2582
  }), {});
2586
- const { reset, bold, dim, italic, underline, inverse, hidden, strikethrough, black, red, green, yellow: yellow$1, blue, magenta, cyan, white, gray, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, blackBright, redBright, greenBright, yellowBright, blueBright, magentaBright, cyanBright, whiteBright, bgBlackBright, bgRedBright, bgGreenBright, bgYellowBright, bgBlueBright, bgMagentaBright, bgCyanBright, bgWhiteBright } = createColors();
2583
+ const { reset, bold, dim, italic, underline, inverse, hidden, strikethrough, black, red, green, yellow, blue, magenta, cyan, white, gray, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, blackBright, redBright, greenBright, yellowBright, blueBright, magentaBright, cyanBright, whiteBright, bgBlackBright, bgRedBright, bgGreenBright, bgYellowBright, bgBlueBright, bgMagentaBright, bgCyanBright, bgWhiteBright } = createColors();
2587
2584
  //#endregion
2588
2585
  //#region ../../node_modules/.bun/scule@1.3.0/node_modules/scule/dist/index.mjs
2589
2586
  const NUMBER_CHAR_RE = /\d/;
@@ -2641,7 +2638,7 @@ function kebabCase(str, joiner) {
2641
2638
  //#endregion
2642
2639
  //#region package.json
2643
2640
  var name = "@batijs/cli";
2644
- var version = "0.0.650";
2641
+ var version = "0.0.651";
2645
2642
  var description = "Next-gen scaffolder. Get started with fully-functional apps, and choose any tool you want";
2646
2643
  //#endregion
2647
2644
  //#region rules.ts
@@ -2856,13 +2853,13 @@ async function checkArguments(args) {
2856
2853
  newArgs.project = `my-app-${generateRandomFilename(5)}`;
2857
2854
  return newArgs;
2858
2855
  } else if (!stat.isDirectory()) {
2859
- console.error(`${yellow$1("⚠")} Target ${cyan(newArgs.project)} already exists but is not a directory. ${yellow$1("Aborting")}.`);
2856
+ console.error(`${yellow("⚠")} Target ${cyan(newArgs.project)} already exists but is not a directory. ${yellow("Aborting")}.`);
2860
2857
  process.exit(2);
2861
2858
  }
2862
2859
  try {
2863
2860
  await access(newArgs.project, constants.W_OK);
2864
2861
  } catch {
2865
- console.error(`${yellow$1("⚠")} Target folder ${cyan(newArgs.project)} already exists but is not writable. ${yellow$1("Aborting")}.`);
2862
+ console.error(`${yellow("⚠")} Target folder ${cyan(newArgs.project)} already exists but is not writable. ${yellow("Aborting")}.`);
2866
2863
  process.exit(3);
2867
2864
  }
2868
2865
  if (!newArgs.force) {
@@ -2870,7 +2867,7 @@ async function checkArguments(args) {
2870
2867
  newArgs.project = `my-app-${generateRandomFilename(5)}`;
2871
2868
  return newArgs;
2872
2869
  } else {
2873
- console.error(`${yellow$1("⚠")} Target folder ${cyan(newArgs.project)} already exists and is not empty.\n Continuing might erase existing files. ${yellow$1("Aborting")}.`);
2870
+ console.error(`${yellow("⚠")} Target folder ${cyan(newArgs.project)} already exists and is not empty.\n Continuing might erase existing files. ${yellow("Aborting")}.`);
2874
2871
  process.exit(4);
2875
2872
  }
2876
2873
  }
@@ -2898,7 +2895,7 @@ async function checkFlagsIncludesUiFramework(flags) {
2898
2895
  const flagsUi = features.filter((fs) => fs.category === "UI Framework").map((fs) => fs.flag);
2899
2896
  const flagsHosting = features.filter((fs) => fs.category === "Hosting").map((fs) => fs.flag);
2900
2897
  const flagsUiFound = flags.some((f) => flagsUi.includes(f));
2901
- if (flags.filter((f) => !flagsUi.includes(f) && !flagsHosting.includes(f)).length === 0) console.warn(`${yellow$1("🛈 Scaffolding a bare-bones app")} ➡️ Go to ${underline("https://vike.dev/new")} to scaffold full-fledged apps with Tailwind, authentication, database, deployment, and more.\n`);
2898
+ if (flags.filter((f) => !flagsUi.includes(f) && !flagsHosting.includes(f)).length === 0) console.warn(`${yellow("🛈 Scaffolding a bare-bones app")} ➡️ Go to ${underline("https://vike.dev/new")} to scaffold full-fledged apps with Tailwind, authentication, database, deployment, and more.\n`);
2902
2899
  if (!flagsUiFound) {
2903
2900
  const ui = await dist_default({
2904
2901
  theme: { style: { highlight(t) {
@@ -2937,7 +2934,7 @@ function checkRules(flags) {
2937
2934
  }
2938
2935
  if (warnings.length > 0) {
2939
2936
  warnings.forEach((m) => {
2940
- console.warn(yellow$1(`⚠ ${m.value}.`));
2937
+ console.warn(yellow(`⚠ ${m.value}.`));
2941
2938
  });
2942
2939
  console.log("");
2943
2940
  }
@@ -3004,7 +3001,7 @@ function gitInit(cwd) {
3004
3001
  force: true
3005
3002
  });
3006
3003
  } catch {}
3007
- console.warn(`${yellow$1("⚠")} failed to initialize a git repository in destination folder. Skipping.`);
3004
+ console.warn(`${yellow("⚠")} failed to initialize a git repository in destination folder. Skipping.`);
3008
3005
  }
3009
3006
  }
3010
3007
  async function run() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@batijs/cli",
3
- "version": "0.0.650",
3
+ "version": "0.0.651",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "check-types": "tsc --noEmit",
@@ -13,8 +13,8 @@
13
13
  "repository": "https://github.com/vikejs/bati",
14
14
  "license": "MIT",
15
15
  "devDependencies": {
16
- "@batijs/build": "0.0.650",
17
- "@batijs/compile": "0.0.650",
16
+ "@batijs/build": "0.0.651",
17
+ "@batijs/compile": "0.0.651",
18
18
  "@inquirer/prompts": "^8.5.2",
19
19
  "@types/node": "^20.19.37",
20
20
  "@types/which": "^3.0.4",
@@ -30,8 +30,8 @@
30
30
  "vite": "^8.0.16"
31
31
  },
32
32
  "dependencies": {
33
- "@batijs/core": "0.0.650",
34
- "@batijs/features": "0.0.650"
33
+ "@batijs/core": "0.0.651",
34
+ "@batijs/features": "0.0.651"
35
35
  },
36
36
  "bin": "./cli.js",
37
37
  "exports": {