@better-t-stack/template-generator 3.36.5 → 3.38.0

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 +1 @@
1
- {"version":3,"file":"template-reader.d.mts","names":["isBinaryPath","filePath","default"],"sources":["../../../../node_modules/.bun/is-binary-path@3.0.0/node_modules/is-binary-path/index.d.ts","../../src/core/template-reader.ts"],"x_google_ignoreList":[0],"mappings":";;;;;;AAcqD;;;;ACJrD;;;;AAAgC;iBDIRA,YAAAA,CAAaC,QAAgB;;;iBCJrC,gBAAA,CAAA;AAAA,iBAcA,sBAAA,CAAA;AAAA,iBAcM,aAAA,CAAc,MAAA,YAAkB,OAAO,CAAC,GAAA;AAAA,iBA2B9C,YAAA,CAAa,YAAoB;AAAA,iBAO3B,aAAA,CAAc,MAAA,YAAkB,OAAO"}
1
+ {"version":3,"file":"template-reader.d.mts","names":[],"sources":["../../../../node_modules/.bun/is-binary-path@3.0.0/node_modules/is-binary-path/index.d.ts","../../src/core/template-reader.ts"],"x_google_ignoreList":[0],"mappings":";;;;;;;;;;;;;;;iBAcwB,aAAa;;;iBCJrB;iBAcA;iBAcM,cAAc,kBAAkB,QAAQ;iBA2B9C,aAAa;iBAOP,cAAc,kBAAkB"}
@@ -1,3 +1,3 @@
1
- import { a as loadTemplates, i as loadTemplate, n as getTemplatesRoot, r as listTemplates, t as getBinaryTemplatesRoot } from "../template-reader-DVuwwW6S.mjs";
2
- import { t as isBinaryPath } from "../is-binary-path-maAgJE_Q.mjs";
1
+ import { a as loadTemplates, i as loadTemplate, n as getTemplatesRoot, r as listTemplates, t as getBinaryTemplatesRoot } from "../template-reader-Apnxs6ej.mjs";
2
+ import { t as isBinaryPath } from "../is-binary-path-C-QlvTjz.mjs";
3
3
  export { getTemplatesRoot as TEMPLATES_ROOT, getTemplatesRoot, getBinaryTemplatesRoot, isBinaryPath, listTemplates, loadTemplate, loadTemplates };
@@ -1,9 +1,7 @@
1
- import { a as VirtualFileTree } from "./types-CzW_c7t0.mjs";
2
- import * as _$better_result0 from "better-result";
1
+ import { a as VirtualFileTree } from "./types-u2lb8od9.mjs";
3
2
  import { Result } from "better-result";
4
-
5
3
  //#region src/fs-writer.d.ts
6
- declare const FileWriteError_base: _$better_result0.TaggedErrorClass<"FileWriteError", {
4
+ declare const FileWriteError_base: import("better-result").TaggedErrorClass<"FileWriteError", {
7
5
  message: string;
8
6
  path?: string;
9
7
  cause?: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"fs-writer.d.mts","names":[],"sources":["../src/fs-writer.ts"],"mappings":";;;;;cAM2F,mBAAA;;;;;;;;cAO9E,cAAA,SAAuB,mBAIhC;;;;AAJJ;iBAUsB,SAAA,CACpB,IAAA,EAAM,eAAA,EACN,OAAA,WACC,OAAA,CAAQ,MAAA,OAAa,cAAA;;;AATpB;AAMJ;iBAiDsB,aAAA,CACpB,IAAA,EAAM,eAAA,EACN,OAAA,UACA,MAAA,GAAS,QAAA,uBACR,OAAA,CAAQ,MAAA,WAAiB,cAAA"}
1
+ {"version":3,"file":"fs-writer.d.mts","names":[],"sources":["../src/fs-writer.ts"],"mappings":";;;;EAeW;EACF;EACC;;;;;cAHG,uBAAuB;;;;;iBAUd,UACpB,MAAM,iBACN,kBACC,QAAQ,aAAa;;;;;iBAgDF,cACpB,MAAM,iBACN,iBACA,SAAS,+BACR,QAAQ,iBAAiB"}
@@ -1,6 +1,7 @@
1
- import { t as getBinaryTemplatesRoot } from "./template-reader-DVuwwW6S.mjs";
1
+ import { t as getBinaryTemplatesRoot } from "./template-reader-Apnxs6ej.mjs";
2
2
  import { Result, TaggedError } from "better-result";
3
3
  import { dirname, join } from "pathe";
4
+ import path from "node:path";
4
5
  import * as fs from "node:fs/promises";
5
6
  //#region src/fs-writer.ts
6
7
  const BINARY_FILE_MARKER = "[Binary file]";
@@ -31,10 +32,12 @@ async function writeNodeInternal(node, baseDir, relativePath) {
31
32
  const nodePath = relativePath ? join(relativePath, node.name) : node.name;
32
33
  if (node.type === "file") {
33
34
  const fileNode = node;
35
+ await assertSafeWritePath(baseDir, fullPath);
34
36
  await fs.mkdir(dirname(fullPath), { recursive: true });
35
37
  if (fileNode.content === BINARY_FILE_MARKER && fileNode.sourcePath) await copyBinaryFile(fileNode.sourcePath, fullPath);
36
38
  else if (fileNode.content !== BINARY_FILE_MARKER) await fs.writeFile(fullPath, fileNode.content, "utf-8");
37
39
  } else {
40
+ await assertSafeWritePath(baseDir, fullPath);
38
41
  await fs.mkdir(fullPath, { recursive: true });
39
42
  for (const child of node.children) await writeNodeInternal(child, baseDir, nodePath);
40
43
  }
@@ -64,6 +67,7 @@ async function writeSelectedNodeInternal(node, baseDir, relativePath, filter, wr
64
67
  if (node.type === "file") {
65
68
  if (filter(nodePath)) {
66
69
  const fileNode = node;
70
+ await assertSafeWritePath(baseDir, join(baseDir, nodePath));
67
71
  await fs.mkdir(dirname(join(baseDir, nodePath)), { recursive: true });
68
72
  if (fileNode.content === BINARY_FILE_MARKER && fileNode.sourcePath) await copyBinaryFile(fileNode.sourcePath, join(baseDir, nodePath));
69
73
  else if (fileNode.content !== BINARY_FILE_MARKER) await fs.writeFile(join(baseDir, nodePath), fileNode.content, "utf-8");
@@ -75,6 +79,31 @@ async function copyBinaryFile(templatePath, destPath) {
75
79
  const sourcePath = join(getBinaryTemplatesRoot(), templatePath);
76
80
  await fs.copyFile(sourcePath, destPath);
77
81
  }
82
+ async function assertSafeWritePath(baseDir, destinationPath) {
83
+ const resolvedBase = path.resolve(baseDir);
84
+ const resolvedDestination = path.resolve(destinationPath);
85
+ const relativeDestination = path.relative(resolvedBase, resolvedDestination);
86
+ if (relativeDestination === ".." || relativeDestination.startsWith(`..${path.sep}`) || path.isAbsolute(relativeDestination)) throw new FileWriteError({
87
+ message: `Refusing to write outside project directory: ${resolvedDestination}`,
88
+ path: resolvedDestination
89
+ });
90
+ let currentPath = resolvedBase;
91
+ const pathSegments = relativeDestination.split(path.sep).filter(Boolean);
92
+ for (const segment of ["", ...pathSegments]) {
93
+ if (segment) currentPath = path.join(currentPath, segment);
94
+ let stats;
95
+ try {
96
+ stats = await fs.lstat(currentPath);
97
+ } catch (error) {
98
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") return;
99
+ throw error;
100
+ }
101
+ if (stats.isSymbolicLink()) throw new FileWriteError({
102
+ message: `Refusing to write through symbolic link: ${currentPath}`,
103
+ path: currentPath
104
+ });
105
+ }
106
+ }
78
107
  //#endregion
79
108
  export { FileWriteError, writeSelected, writeTree };
80
109
 
@@ -1 +1 @@
1
- {"version":3,"file":"fs-writer.mjs","names":[],"sources":["../src/fs-writer.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\n\nimport { Result, TaggedError } from \"better-result\";\nimport { join, dirname } from \"pathe\";\n\nimport { getBinaryTemplatesRoot } from \"./core/template-reader\";\nimport type { VirtualFileTree, VirtualNode, VirtualFile, VirtualDirectory } from \"./types\";\n\nconst BINARY_FILE_MARKER = \"[Binary file]\";\n\n/**\n * Error class for filesystem write failures\n */\nexport class FileWriteError extends TaggedError(\"FileWriteError\")<{\n message: string;\n path?: string;\n cause?: unknown;\n}>() {}\n\n/**\n * Writes a virtual file tree to the filesystem.\n * Returns a Result type for type-safe error handling.\n */\nexport async function writeTree(\n tree: VirtualFileTree,\n destDir: string,\n): Promise<Result<void, FileWriteError>> {\n return Result.tryPromise({\n try: async () => {\n for (const child of tree.root.children) {\n await writeNodeInternal(child, destDir, \"\");\n }\n },\n catch: (e) => {\n if (FileWriteError.is(e)) return e;\n return new FileWriteError({\n message: e instanceof Error ? e.message : String(e),\n cause: e,\n });\n },\n });\n}\n\nasync function writeNodeInternal(\n node: VirtualNode,\n baseDir: string,\n relativePath: string,\n): Promise<void> {\n const fullPath = join(baseDir, relativePath, node.name);\n const nodePath = relativePath ? join(relativePath, node.name) : node.name;\n\n if (node.type === \"file\") {\n const fileNode = node as VirtualFile;\n await fs.mkdir(dirname(fullPath), { recursive: true });\n\n if (fileNode.content === BINARY_FILE_MARKER && fileNode.sourcePath) {\n await copyBinaryFile(fileNode.sourcePath, fullPath);\n } else if (fileNode.content !== BINARY_FILE_MARKER) {\n await fs.writeFile(fullPath, fileNode.content, \"utf-8\");\n }\n } else {\n await fs.mkdir(fullPath, { recursive: true });\n for (const child of (node as VirtualDirectory).children) {\n await writeNodeInternal(child, baseDir, nodePath);\n }\n }\n}\n\n/**\n * Writes selected files from a virtual file tree to the filesystem.\n * Returns a Result with the list of written file paths.\n */\nexport async function writeSelected(\n tree: VirtualFileTree,\n destDir: string,\n filter: (filePath: string) => boolean,\n): Promise<Result<string[], FileWriteError>> {\n return Result.tryPromise({\n try: async () => {\n const writtenFiles: string[] = [];\n await writeSelectedNodeInternal(tree.root, destDir, \"\", filter, writtenFiles);\n return writtenFiles;\n },\n catch: (e) => {\n if (FileWriteError.is(e)) return e;\n return new FileWriteError({\n message: e instanceof Error ? e.message : String(e),\n cause: e,\n });\n },\n });\n}\n\nasync function writeSelectedNodeInternal(\n node: VirtualNode,\n baseDir: string,\n relativePath: string,\n filter: (filePath: string) => boolean,\n writtenFiles: string[],\n): Promise<void> {\n const nodePath = relativePath ? `${relativePath}/${node.name}` : node.name;\n\n if (node.type === \"file\") {\n if (filter(nodePath)) {\n const fileNode = node as VirtualFile;\n await fs.mkdir(dirname(join(baseDir, nodePath)), { recursive: true });\n\n if (fileNode.content === BINARY_FILE_MARKER && fileNode.sourcePath) {\n await copyBinaryFile(fileNode.sourcePath, join(baseDir, nodePath));\n } else if (fileNode.content !== BINARY_FILE_MARKER) {\n await fs.writeFile(join(baseDir, nodePath), fileNode.content, \"utf-8\");\n }\n writtenFiles.push(nodePath);\n }\n } else {\n for (const child of (node as VirtualDirectory).children) {\n await writeSelectedNodeInternal(child, baseDir, nodePath, filter, writtenFiles);\n }\n }\n}\n\nasync function copyBinaryFile(templatePath: string, destPath: string): Promise<void> {\n const templatesRoot = getBinaryTemplatesRoot();\n const sourcePath = join(templatesRoot, templatePath);\n // Let errors propagate - they'll be caught by the Result wrapper\n await fs.copyFile(sourcePath, destPath);\n}\n"],"mappings":";;;;;AAQA,MAAM,qBAAqB;;;;AAK3B,IAAa,iBAAb,cAAoC,YAAY,gBAAgB,EAI7D,EAAE,CAAC;;;;;AAMN,eAAsB,UACpB,MACA,SACuC;CACvC,OAAO,OAAO,WAAW;EACvB,KAAK,YAAY;GACf,KAAK,MAAM,SAAS,KAAK,KAAK,UAC5B,MAAM,kBAAkB,OAAO,SAAS,EAAE;EAE9C;EACA,QAAQ,MAAM;GACZ,IAAI,eAAe,GAAG,CAAC,GAAG,OAAO;GACjC,OAAO,IAAI,eAAe;IACxB,SAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;IAClD,OAAO;GACT,CAAC;EACH;CACF,CAAC;AACH;AAEA,eAAe,kBACb,MACA,SACA,cACe;CACf,MAAM,WAAW,KAAK,SAAS,cAAc,KAAK,IAAI;CACtD,MAAM,WAAW,eAAe,KAAK,cAAc,KAAK,IAAI,IAAI,KAAK;CAErE,IAAI,KAAK,SAAS,QAAQ;EACxB,MAAM,WAAW;EACjB,MAAM,GAAG,MAAM,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;EAErD,IAAI,SAAS,YAAY,sBAAsB,SAAS,YACtD,MAAM,eAAe,SAAS,YAAY,QAAQ;OAC7C,IAAI,SAAS,YAAY,oBAC9B,MAAM,GAAG,UAAU,UAAU,SAAS,SAAS,OAAO;CAE1D,OAAO;EACL,MAAM,GAAG,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;EAC5C,KAAK,MAAM,SAAU,KAA0B,UAC7C,MAAM,kBAAkB,OAAO,SAAS,QAAQ;CAEpD;AACF;;;;;AAMA,eAAsB,cACpB,MACA,SACA,QAC2C;CAC3C,OAAO,OAAO,WAAW;EACvB,KAAK,YAAY;GACf,MAAM,eAAyB,CAAC;GAChC,MAAM,0BAA0B,KAAK,MAAM,SAAS,IAAI,QAAQ,YAAY;GAC5E,OAAO;EACT;EACA,QAAQ,MAAM;GACZ,IAAI,eAAe,GAAG,CAAC,GAAG,OAAO;GACjC,OAAO,IAAI,eAAe;IACxB,SAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;IAClD,OAAO;GACT,CAAC;EACH;CACF,CAAC;AACH;AAEA,eAAe,0BACb,MACA,SACA,cACA,QACA,cACe;CACf,MAAM,WAAW,eAAe,GAAG,aAAa,GAAG,KAAK,SAAS,KAAK;CAEtE,IAAI,KAAK,SAAS;MACZ,OAAO,QAAQ,GAAG;GACpB,MAAM,WAAW;GACjB,MAAM,GAAG,MAAM,QAAQ,KAAK,SAAS,QAAQ,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;GAEpE,IAAI,SAAS,YAAY,sBAAsB,SAAS,YACtD,MAAM,eAAe,SAAS,YAAY,KAAK,SAAS,QAAQ,CAAC;QAC5D,IAAI,SAAS,YAAY,oBAC9B,MAAM,GAAG,UAAU,KAAK,SAAS,QAAQ,GAAG,SAAS,SAAS,OAAO;GAEvE,aAAa,KAAK,QAAQ;EAC5B;QAEA,KAAK,MAAM,SAAU,KAA0B,UAC7C,MAAM,0BAA0B,OAAO,SAAS,UAAU,QAAQ,YAAY;AAGpF;AAEA,eAAe,eAAe,cAAsB,UAAiC;CAEnF,MAAM,aAAa,KADG,uBACc,GAAG,YAAY;CAEnD,MAAM,GAAG,SAAS,YAAY,QAAQ;AACxC"}
1
+ {"version":3,"file":"fs-writer.mjs","names":[],"sources":["../src/fs-writer.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport { Result, TaggedError } from \"better-result\";\nimport { join, dirname } from \"pathe\";\n\nimport { getBinaryTemplatesRoot } from \"./core/template-reader\";\nimport type { VirtualFileTree, VirtualNode, VirtualFile, VirtualDirectory } from \"./types\";\n\nconst BINARY_FILE_MARKER = \"[Binary file]\";\n\n/**\n * Error class for filesystem write failures\n */\nexport class FileWriteError extends TaggedError(\"FileWriteError\")<{\n message: string;\n path?: string;\n cause?: unknown;\n}>() {}\n\n/**\n * Writes a virtual file tree to the filesystem.\n * Returns a Result type for type-safe error handling.\n */\nexport async function writeTree(\n tree: VirtualFileTree,\n destDir: string,\n): Promise<Result<void, FileWriteError>> {\n return Result.tryPromise({\n try: async () => {\n for (const child of tree.root.children) {\n await writeNodeInternal(child, destDir, \"\");\n }\n },\n catch: (e) => {\n if (FileWriteError.is(e)) return e;\n return new FileWriteError({\n message: e instanceof Error ? e.message : String(e),\n cause: e,\n });\n },\n });\n}\n\nasync function writeNodeInternal(\n node: VirtualNode,\n baseDir: string,\n relativePath: string,\n): Promise<void> {\n const fullPath = join(baseDir, relativePath, node.name);\n const nodePath = relativePath ? join(relativePath, node.name) : node.name;\n\n if (node.type === \"file\") {\n const fileNode = node as VirtualFile;\n await assertSafeWritePath(baseDir, fullPath);\n await fs.mkdir(dirname(fullPath), { recursive: true });\n\n if (fileNode.content === BINARY_FILE_MARKER && fileNode.sourcePath) {\n await copyBinaryFile(fileNode.sourcePath, fullPath);\n } else if (fileNode.content !== BINARY_FILE_MARKER) {\n await fs.writeFile(fullPath, fileNode.content, \"utf-8\");\n }\n } else {\n await assertSafeWritePath(baseDir, fullPath);\n await fs.mkdir(fullPath, { recursive: true });\n for (const child of (node as VirtualDirectory).children) {\n await writeNodeInternal(child, baseDir, nodePath);\n }\n }\n}\n\n/**\n * Writes selected files from a virtual file tree to the filesystem.\n * Returns a Result with the list of written file paths.\n */\nexport async function writeSelected(\n tree: VirtualFileTree,\n destDir: string,\n filter: (filePath: string) => boolean,\n): Promise<Result<string[], FileWriteError>> {\n return Result.tryPromise({\n try: async () => {\n const writtenFiles: string[] = [];\n await writeSelectedNodeInternal(tree.root, destDir, \"\", filter, writtenFiles);\n return writtenFiles;\n },\n catch: (e) => {\n if (FileWriteError.is(e)) return e;\n return new FileWriteError({\n message: e instanceof Error ? e.message : String(e),\n cause: e,\n });\n },\n });\n}\n\nasync function writeSelectedNodeInternal(\n node: VirtualNode,\n baseDir: string,\n relativePath: string,\n filter: (filePath: string) => boolean,\n writtenFiles: string[],\n): Promise<void> {\n const nodePath = relativePath ? `${relativePath}/${node.name}` : node.name;\n\n if (node.type === \"file\") {\n if (filter(nodePath)) {\n const fileNode = node as VirtualFile;\n await assertSafeWritePath(baseDir, join(baseDir, nodePath));\n await fs.mkdir(dirname(join(baseDir, nodePath)), { recursive: true });\n\n if (fileNode.content === BINARY_FILE_MARKER && fileNode.sourcePath) {\n await copyBinaryFile(fileNode.sourcePath, join(baseDir, nodePath));\n } else if (fileNode.content !== BINARY_FILE_MARKER) {\n await fs.writeFile(join(baseDir, nodePath), fileNode.content, \"utf-8\");\n }\n writtenFiles.push(nodePath);\n }\n } else {\n for (const child of (node as VirtualDirectory).children) {\n await writeSelectedNodeInternal(child, baseDir, nodePath, filter, writtenFiles);\n }\n }\n}\n\nasync function copyBinaryFile(templatePath: string, destPath: string): Promise<void> {\n const templatesRoot = getBinaryTemplatesRoot();\n const sourcePath = join(templatesRoot, templatePath);\n // Let errors propagate - they'll be caught by the Result wrapper\n await fs.copyFile(sourcePath, destPath);\n}\n\nasync function assertSafeWritePath(baseDir: string, destinationPath: string): Promise<void> {\n const resolvedBase = path.resolve(baseDir);\n const resolvedDestination = path.resolve(destinationPath);\n const relativeDestination = path.relative(resolvedBase, resolvedDestination);\n\n if (\n relativeDestination === \"..\" ||\n relativeDestination.startsWith(`..${path.sep}`) ||\n path.isAbsolute(relativeDestination)\n ) {\n throw new FileWriteError({\n message: `Refusing to write outside project directory: ${resolvedDestination}`,\n path: resolvedDestination,\n });\n }\n\n let currentPath = resolvedBase;\n const pathSegments = relativeDestination.split(path.sep).filter(Boolean);\n for (const segment of [\"\", ...pathSegments]) {\n if (segment) currentPath = path.join(currentPath, segment);\n\n let stats;\n try {\n stats = await fs.lstat(currentPath);\n } catch (error) {\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"ENOENT\"\n ) {\n return;\n }\n throw error;\n }\n\n if (stats.isSymbolicLink()) {\n throw new FileWriteError({\n message: `Refusing to write through symbolic link: ${currentPath}`,\n path: currentPath,\n });\n }\n }\n}\n"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -1,9 +1,7 @@
1
- import { a as VirtualFileTree, i as VirtualFile, n as GeneratorOptions, o as VirtualNode, r as VirtualDirectory, t as GeneratorError } from "./types-CzW_c7t0.mjs";
1
+ import { a as VirtualFileTree, i as VirtualFile, n as GeneratorOptions, o as VirtualNode, r as VirtualDirectory, t as GeneratorError } from "./types-u2lb8od9.mjs";
2
2
  import { Result } from "better-result";
3
- import * as _$memfs from "memfs";
4
3
  import Handlebars from "handlebars";
5
4
  import { ProjectConfig } from "@better-t-stack/types";
6
-
7
5
  //#region src/core/virtual-fs.d.ts
8
6
  declare class VirtualFileSystem {
9
7
  private _fs;
@@ -26,8 +24,8 @@ declare class VirtualFileSystem {
26
24
  getDirectoryCount(): number;
27
25
  toTree(rootName?: string): VirtualDirectory;
28
26
  clear(): void;
29
- getVolume(): _$memfs.Volume;
30
- getFs(): _$memfs.IFs;
27
+ getVolume(): import("memfs").Volume;
28
+ getFs(): import("memfs").IFs;
31
29
  private walkDir;
32
30
  private buildTree;
33
31
  private sortChildren;
@@ -96,17 +94,17 @@ declare const TEMPLATE_COUNT = 506;
96
94
  //#endregion
97
95
  //#region src/utils/add-deps.d.ts
98
96
  declare const dependencyVersionMap: {
99
- readonly typescript: "^6";
100
- readonly "better-auth": "1.6.23";
101
- readonly "@better-auth/expo": "1.6.23";
102
- readonly "@clerk/backend": "^3.10.0";
103
- readonly "@clerk/express": "^2.1.35";
104
- readonly "@clerk/fastify": "^3.1.45";
105
- readonly "@clerk/nextjs": "^7.5.12";
106
- readonly "@clerk/react": "^6.11.3";
107
- readonly "@clerk/react-router": "^3.5.4";
108
- readonly "@clerk/tanstack-react-start": "^1.4.12";
109
- readonly "@clerk/expo": "^3.6.5";
97
+ readonly typescript: "^6.0.3";
98
+ readonly "better-auth": "1.6.25";
99
+ readonly "@better-auth/expo": "1.6.25";
100
+ readonly "@clerk/backend": "^3.13.2";
101
+ readonly "@clerk/express": "^2.1.47";
102
+ readonly "@clerk/fastify": "^3.1.57";
103
+ readonly "@clerk/nextjs": "^7.6.2";
104
+ readonly "@clerk/react": "^6.12.8";
105
+ readonly "@clerk/react-router": "^3.6.1";
106
+ readonly "@clerk/tanstack-react-start": "^1.4.24";
107
+ readonly "@clerk/expo": "^4.1.0";
110
108
  readonly "drizzle-orm": "^0.45.2";
111
109
  readonly "drizzle-kit": "^0.31.10";
112
110
  readonly "@planetscale/database": "^1.20.1";
@@ -116,68 +114,68 @@ declare const dependencyVersionMap: {
116
114
  readonly pg: "^8.22.0";
117
115
  readonly "@types/pg": "^8.20.0";
118
116
  readonly "@types/ws": "^8.18.1";
119
- readonly ws: "^8.21.0";
120
- readonly mysql2: "^3.22.5";
121
- readonly "@prisma/client": "^7.8.0";
122
- readonly prisma: "^7.8.0";
123
- readonly "@prisma/adapter-d1": "^7.8.0";
124
- readonly "@prisma/adapter-neon": "^7.8.0";
125
- readonly "@prisma/adapter-mariadb": "^7.8.0";
126
- readonly "@prisma/adapter-libsql": "^7.8.0";
127
- readonly "@prisma/adapter-better-sqlite3": "^7.8.0";
128
- readonly "@prisma/adapter-pg": "^7.8.0";
129
- readonly "@prisma/adapter-planetscale": "^7.8.0";
130
- readonly mongoose: "^9.7.3";
131
- readonly mongodb: "^7.4.0";
117
+ readonly ws: "^8.21.1";
118
+ readonly mysql2: "^3.23.2";
119
+ readonly "@prisma/client": "^7.9.1";
120
+ readonly prisma: "^7.9.1";
121
+ readonly "@prisma/adapter-d1": "^7.9.1";
122
+ readonly "@prisma/adapter-neon": "^7.9.1";
123
+ readonly "@prisma/adapter-mariadb": "^7.9.1";
124
+ readonly "@prisma/adapter-libsql": "^7.9.1";
125
+ readonly "@prisma/adapter-better-sqlite3": "^7.9.1";
126
+ readonly "@prisma/adapter-pg": "^7.9.1";
127
+ readonly "@prisma/adapter-planetscale": "^7.9.1";
128
+ readonly mongoose: "^9.8.1";
129
+ readonly mongodb: "^7.5.0";
132
130
  readonly "vite-plugin-pwa": "^1.3.0";
133
131
  readonly "@vite-pwa/assets-generator": "^1.0.2";
134
132
  readonly "@tauri-apps/cli": "^2.11.4";
135
- readonly "@biomejs/biome": "^2.5.2";
136
- readonly oxlint: "^1.72.0";
137
- readonly oxfmt: "^0.57.0";
133
+ readonly "@biomejs/biome": "^2.5.6";
134
+ readonly oxlint: "^1.76.0";
135
+ readonly oxfmt: "^0.61.0";
138
136
  readonly husky: "^9.1.7";
139
- readonly lefthook: "^2.1.9";
140
- readonly "lint-staged": "^17.0.7";
141
- readonly tsx: "^4.22.5";
142
- readonly "@types/node": "^22.13.14";
137
+ readonly lefthook: "^2.1.10";
138
+ readonly "lint-staged": "^17.2.0";
139
+ readonly tsx: "^4.23.1";
140
+ readonly "@types/node": "^22.20.1";
143
141
  readonly "@types/bun": "^1.3.14";
144
142
  readonly "@elysiajs/node": "^1.4.5";
145
143
  readonly "@elysiajs/cors": "^1.4.2";
146
144
  readonly "@elysiajs/trpc": "^1.1.0";
147
145
  readonly elysia: "^1.4.29";
148
- readonly "@sinclair/typebox": "^0.34.49";
149
- readonly "@hono/node-server": "^2.0.8";
146
+ readonly "@sinclair/typebox": "^0.34.52";
147
+ readonly "@hono/node-server": "^2.0.12";
150
148
  readonly "@hono/trpc-server": "^0.4.2";
151
- readonly hono: "^4.12.27";
149
+ readonly hono: "^4.12.32";
152
150
  readonly cors: "^2.8.6";
153
151
  readonly express: "^5.2.1";
154
152
  readonly "@types/express": "^5.0.6";
155
153
  readonly "@types/cors": "^2.8.19";
156
- readonly fastify: "^5.9.0";
157
- readonly "@fastify/cors": "^11.2.0";
158
- readonly turbo: "^2.10.2";
159
- readonly nx: "^23.0.1";
160
- readonly "vite-plus": "0.2.2";
161
- readonly rolldown: "1.1.4";
162
- readonly ai: "^7.0.13";
163
- readonly "@ai-sdk/google": "^4.0.7";
164
- readonly "@ai-sdk/vue": "^4.0.13";
165
- readonly "@ai-sdk/svelte": "^5.0.13";
166
- readonly "@ai-sdk/react": "^4.0.14";
167
- readonly "@ai-sdk/devtools": "^1.0.1";
154
+ readonly fastify: "^5.10.0";
155
+ readonly "@fastify/cors": "^11.3.0";
156
+ readonly turbo: "^2.10.7";
157
+ readonly nx: "^23.1.0";
158
+ readonly "vite-plus": "0.2.6";
159
+ readonly rolldown: "1.2.0";
160
+ readonly ai: "^7.0.41";
161
+ readonly "@ai-sdk/google": "^4.0.27";
162
+ readonly "@ai-sdk/vue": "^4.0.41";
163
+ readonly "@ai-sdk/svelte": "^5.0.41";
164
+ readonly "@ai-sdk/react": "^4.0.44";
165
+ readonly "@ai-sdk/devtools": "^1.0.8";
168
166
  readonly streamdown: "^2.5.0";
169
- readonly shiki: "^4.3.0";
170
- readonly "@orpc/server": "^1.14.6";
171
- readonly "@orpc/client": "^1.14.6";
172
- readonly "@orpc/openapi": "^1.14.6";
173
- readonly "@orpc/zod": "^1.14.6";
174
- readonly "@orpc/tanstack-query": "^1.14.6";
167
+ readonly shiki: "^4.3.1";
168
+ readonly "@orpc/server": "^1.14.12";
169
+ readonly "@orpc/client": "^1.14.12";
170
+ readonly "@orpc/openapi": "^1.14.12";
171
+ readonly "@orpc/zod": "^1.14.12";
172
+ readonly "@orpc/tanstack-query": "^1.14.12";
175
173
  readonly "@trpc/tanstack-react-query": "^11.18.0";
176
174
  readonly "@trpc/server": "^11.18.0";
177
175
  readonly "@trpc/client": "^11.18.0";
178
- readonly next: "^16.2.0";
176
+ readonly next: "^16.2.12";
179
177
  readonly nitro: "^3.0.260610-beta";
180
- readonly convex: "^1.42.1";
178
+ readonly convex: "^1.42.3";
181
179
  readonly "@convex-dev/react-query": "^0.1.0";
182
180
  readonly "@convex-dev/agent": "^0.6.4";
183
181
  readonly "@convex-dev/polar": "^0.9.2";
@@ -185,44 +183,44 @@ declare const dependencyVersionMap: {
185
183
  readonly "convex-nuxt": "0.1.5";
186
184
  readonly "convex-vue": "^0.1.5";
187
185
  readonly "@convex-dev/better-auth": "^0.12.5";
188
- readonly "@tanstack/svelte-query": "^6.1.36";
189
- readonly "@tanstack/svelte-query-devtools": "^6.1.36";
190
- readonly "@tanstack/vue-query-devtools": "^6.1.36";
191
- readonly "@tanstack/vue-query": "^5.101.2";
192
- readonly "@tanstack/react-query-devtools": "^5.101.2";
193
- readonly "@tanstack/react-query": "^5.101.2";
194
- readonly "@tanstack/react-form": "^1.33.0";
186
+ readonly "@tanstack/svelte-query": "^6.1.38";
187
+ readonly "@tanstack/svelte-query-devtools": "^6.1.38";
188
+ readonly "@tanstack/vue-query-devtools": "^6.1.38";
189
+ readonly "@tanstack/vue-query": "^5.101.4";
190
+ readonly "@tanstack/react-query-devtools": "^5.101.4";
191
+ readonly "@tanstack/react-query": "^5.101.4";
192
+ readonly "@tanstack/react-form": "^1.33.2";
195
193
  readonly "@tanstack/react-router-ssr-query": "^1.167.1";
196
- readonly "@tanstack/solid-form": "^1.33.0";
197
- readonly "@tanstack/svelte-form": "^1.33.0";
198
- readonly "@tanstack/solid-query": "^5.101.2";
199
- readonly "@tanstack/solid-query-devtools": "^5.101.2";
194
+ readonly "@tanstack/solid-form": "^1.33.2";
195
+ readonly "@tanstack/svelte-form": "^1.33.2";
196
+ readonly "@tanstack/solid-query": "^5.101.4";
197
+ readonly "@tanstack/solid-query-devtools": "^5.101.4";
200
198
  readonly "@tanstack/solid-router-devtools": "^1.167.0";
201
- readonly wrangler: "^4.107.0";
202
- readonly "@cloudflare/vite-plugin": "1.43.0";
203
- readonly "@opennextjs/cloudflare": "^1.20.1";
199
+ readonly wrangler: "^4.115.0";
200
+ readonly "@cloudflare/vite-plugin": "1.48.0";
201
+ readonly "@opennextjs/cloudflare": "^1.20.2";
204
202
  readonly "nitro-cloudflare-dev": "^0.2.2";
205
203
  readonly "@sveltejs/adapter-cloudflare": "^7.2.9";
206
204
  readonly "@sveltejs/adapter-node": "^5.5.7";
207
205
  readonly "@sveltejs/adapter-vercel": "^6.3.4";
208
- readonly "@cloudflare/workers-types": "^4.20260702.1";
209
- readonly "@astrojs/cloudflare": "^14.1.0";
210
- readonly "@astrojs/node": "^11.0.1";
211
- readonly "@astrojs/vercel": "^11.0.1";
206
+ readonly "@cloudflare/workers-types": "^5.20260728.1";
207
+ readonly "@astrojs/cloudflare": "^14.1.6";
208
+ readonly "@astrojs/node": "^11.0.3";
209
+ readonly "@astrojs/vercel": "^11.0.4";
212
210
  readonly alchemy: "^0.93.12";
213
- readonly vercel: "^54.18.6";
211
+ readonly vercel: "^58.1.0";
214
212
  readonly dotenv: "^17.4.2";
215
- readonly tsdown: "^0.22.3";
213
+ readonly tsdown: "^0.22.14";
216
214
  readonly zod: "^4.4.3";
217
215
  readonly "@t3-oss/env-core": "^0.13.11";
218
216
  readonly "@t3-oss/env-nextjs": "^0.13.11";
219
217
  readonly "@t3-oss/env-nuxt": "^0.13.11";
220
218
  readonly "@polar-sh/better-auth": "^1.8.4";
221
219
  readonly "@polar-sh/checkout": "^0.4.0";
222
- readonly "@polar-sh/sdk": "^0.47.1";
223
- readonly "@stripe/react-stripe-js": "^5.6.1";
224
- readonly "@stripe/stripe-js": "^8.11.0";
225
- readonly evlog: "^2.22.0";
220
+ readonly "@polar-sh/sdk": "^0.49.0";
221
+ readonly "@stripe/react-stripe-js": "^6.8.0";
222
+ readonly "@stripe/stripe-js": "^9.12.1";
223
+ readonly evlog: "^2.22.4";
226
224
  };
227
225
  type AvailableDependencies = keyof typeof dependencyVersionMap;
228
226
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/core/virtual-fs.ts","../src/core/template-processor.ts","../src/template-handlers/utils.ts","../src/template-handlers/addons.ts","../src/generator.ts","../src/processors/addons-deps.ts","../src/processors/nx-generator.ts","../src/processors/turbo-generator.ts","../src/processors/vite-plus-generator.ts","../src/post-process/package-configs.ts","../src/post-process/vercel-config.ts","../src/bts-config.ts","../src/templates.generated.ts","../src/utils/add-deps.ts","../src/utils/reproducible-command.ts"],"mappings":";;;;;;;cAOa,iBAAA;EAAA,QACH,GAAA;EAAA,QACA,IAAA;EAAA,QACA,cAAA;;EAQR,SAAA,CAAU,QAAA,UAAkB,OAAA,UAAiB,UAAA;EAY7C,QAAA,CAAS,QAAA;EAQT,MAAA,CAAO,IAAA;EASP,UAAA,CAAW,QAAA;EAQX,eAAA,CAAgB,OAAA;EAQhB,KAAA,CAAM,OAAA;EAIN,UAAA,CAAW,QAAA;EASX,OAAA,CAAQ,OAAA;EAQR,QAAA,aAAA,CAAsB,QAAA,WAAmB,CAAA;EAUzC,SAAA,CAAU,QAAA,UAAkB,IAAA,WAAe,MAAA;EAI3C,WAAA,CAAA;EAMA,iBAAA,CAAA;EAMA,YAAA,CAAA;EAIA,iBAAA,CAAA;EAIA,MAAA,CAAO,QAAA,YAAuB,gBAAA;EAO9B,KAAA,CAAA;EAOA,SAAA,CAAA,GAd8C,OAAA,CAcrC,MAAA;EAGT,KAAA,CAAA,GAHS,OAAA,CAGJ,GAAA;EAAA,QAIG,OAAA;EAAA,QAeA,SAAA;EAAA,QAiCA,YAAA;EAAA,QAWA,aAAA;AAAA;;;iBC5JM,qBAAA,CAAsB,OAAA,UAAiB,OAAA,EAAS,aAAa;AAAA,iBAI7D,YAAA,CAAa,QAAgB;AAAA,iBAI7B,iBAAA,CAAkB,QAAgB;AAAA,iBAYlC,kBAAA,CACd,QAAA,UACA,OAAA,UACA,OAAA,EAAS,aAAa;;;KC5DZ,YAAA,GAAe,GAAG;;;iBCAR,qBAAA,CACpB,GAAA,EAAK,iBAAA,EACL,SAAA,EAAW,YAAA,EACX,MAAA,EAAQ,aAAA,GACP,OAAA;;;;;AHFH;;;;;;;;;;;iBI0CsB,QAAA,CACpB,OAAA,EAAS,gBAAA,GACR,OAAA,CAAQ,MAAA,CAAO,eAAA,EAAiB,cAAA;;;iBCrCnB,iBAAA,CAAkB,GAAA,EAAK,iBAAA,EAAmB,MAAA,EAAQ,aAAa;;;iBCS/D,eAAA,CAAgB,GAAA,EAAK,iBAAA,EAAmB,MAAA,EAAQ,aAAa;;;iBCC7D,kBAAA,CAAmB,GAAA,EAAK,iBAAA,EAAmB,MAAA,EAAQ,aAAa;;;iBCXhE,qBAAA,CAAsB,GAAA,EAAK,iBAAA,EAAmB,MAAA,EAAQ,aAAa;;;;ARNnF;;iBS8BgB,qBAAA,CAAsB,GAAA,EAAK,iBAAA,EAAmB,MAAA,EAAQ,aAAa;;;iBCQnE,mBAAA,CAAoB,GAAA,EAAK,iBAAA,EAAmB,MAAA,EAAQ,aAAa;;;;;;;iBCnCjE,mBAAA,CACd,GAAA,EAAK,iBAAA,EACL,aAAA,EAAe,aAAa,EAC5B,OAAA,UACA,mBAAA;;;cCXW,kBAAA,EAAoB,GAAG;AAAA,cA6slCvB,cAAA;;;cCnslCA,oBAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsKD,qBAAA,gBAAqC,oBAAoB;;;iBCxJrD,2BAAA,CAA4B,MAAqB,EAAb,aAAa"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/core/virtual-fs.ts","../src/core/template-processor.ts","../src/template-handlers/utils.ts","../src/template-handlers/addons.ts","../src/generator.ts","../src/processors/addons-deps.ts","../src/processors/nx-generator.ts","../src/processors/turbo-generator.ts","../src/processors/vite-plus-generator.ts","../src/post-process/package-configs.ts","../src/post-process/vercel-config.ts","../src/bts-config.ts","../src/templates.generated.ts","../src/utils/add-deps.ts","../src/utils/reproducible-command.ts"],"mappings":";;;;;cAOa;UACH;UACA;UACA;;EAQR,UAAU,kBAAkB,iBAAiB;EAY7C,SAAS;EAQT,OAAO;EASP,WAAW;EAQX,gBAAgB;EAQhB,MAAM;EAIN,WAAW;EASX,QAAQ;EAQR,SAAS,aAAa,mBAAmB;EAUzC,UAAU,kBAAkB,eAAe;EAI3C;EAMA;EAMA;EAIA;EAIA,OAAO,oBAAuB;EAO9B;EAOA,6BAAS;EAGT,yBAAK;UAIG;UAeA;UAiCA;UAWA;;;;iBC5JM,sBAAsB,iBAAiB,SAAS;iBAIhD,aAAa;iBAIb,kBAAkB;iBAYlB,mBACd,kBACA,iBACA,SAAS;;;KC5DC,eAAe;;;iBCAL,sBACpB,KAAK,mBACL,WAAW,cACX,QAAQ,gBACP;;;;;;;;;;;;;;;;iBCwCmB,SACpB,SAAS,mBACR,QAAQ,OAAO,iBAAiB;;;iBCrCnB,kBAAkB,KAAK,mBAAmB,QAAQ;;;iBCSlD,gBAAgB,KAAK,mBAAmB,QAAQ;;;iBCChD,mBAAmB,KAAK,mBAAmB,QAAQ;;;iBCXnD,sBAAsB,KAAK,mBAAmB,QAAQ;;;;;;iBCwBtD,sBAAsB,KAAK,mBAAmB,QAAQ;;;iBCQtD,oBAAoB,KAAK,mBAAmB,QAAQ;;;;;;;iBCnCpD,oBACd,KAAK,mBACL,eAAe,eACf,iBACA;;;cCXW,oBAAoB;cAitlCpB;;;cCvslCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsKD,qCAAqC;;;iBCxJjC,4BAA4B,QAAQ"}