@stackframe/init-stack 2.7.17 → 2.7.19

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @stackframe/init-stack
2
2
 
3
+ ## 2.7.19
4
+
5
+ ### Patch Changes
6
+
7
+ - Various changes
8
+ - @stackframe/stack-shared@2.7.19
9
+
10
+ ## 2.7.18
11
+
12
+ ### Patch Changes
13
+
14
+ - Various changes
15
+ - Updated dependencies
16
+ - @stackframe/stack-shared@2.7.18
17
+
3
18
  ## 2.7.17
4
19
 
5
20
  ### Patch Changes
@@ -0,0 +1,3 @@
1
+ declare function templateIdentity(strings: TemplateStringsArray, ...values: any[]): string;
2
+
3
+ export { templateIdentity };
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/index.ts
3
4
  import * as child_process from "child_process";
4
5
  import * as fs from "fs";
5
6
  import inquirer from "inquirer";
6
7
  import open from "open";
7
8
  import * as path from "path";
8
-
9
- const jsLikeFileExtensions = [
9
+ var jsLikeFileExtensions = [
10
10
  "mtsx",
11
11
  "ctsx",
12
12
  "tsx",
@@ -18,98 +18,76 @@ const jsLikeFileExtensions = [
18
18
  "jsx",
19
19
  "mjs",
20
20
  "cjs",
21
- "js",
21
+ "js"
22
22
  ];
23
-
24
- class UserError extends Error {
23
+ var UserError = class extends Error {
25
24
  constructor(message) {
26
25
  super(message);
27
26
  this.name = "UserError";
28
27
  }
29
- }
30
-
31
- let savedProjectPath = process.argv[2] || undefined;
32
-
33
- const isDryRun = process.argv.includes("--dry-run");
34
- const isNeon = process.argv.includes("--neon");
35
- const typeFromArgs = ["js", "next"].find(s => process.argv.includes(`--${s}`));
36
- const packageManagerFromArgs = ["npm", "yarn", "pnpm", "bun"].find(s => process.argv.includes(`--${s}`));
37
- const isClient = process.argv.includes("--client");
38
- const isServer = process.argv.includes("--server");
39
-
40
- const ansis = {
41
- red: "\x1b[31m",
42
- blue: "\x1b[34m",
43
- green: "\x1b[32m",
44
- yellow: "\x1b[33m",
45
-
46
- clear: "\x1b[0m",
47
- bold: "\x1b[1m",
48
28
  };
49
-
50
- const colorize = {
29
+ var savedProjectPath = process.argv[2] || void 0;
30
+ var isDryRun = process.argv.includes("--dry-run");
31
+ var isNeon = process.argv.includes("--neon");
32
+ var typeFromArgs = ["js", "next"].find((s) => process.argv.includes(`--${s}`));
33
+ var packageManagerFromArgs = ["npm", "yarn", "pnpm", "bun"].find((s) => process.argv.includes(`--${s}`));
34
+ var isClient = process.argv.includes("--client");
35
+ var isServer = process.argv.includes("--server");
36
+ var ansis = {
37
+ red: "\x1B[31m",
38
+ blue: "\x1B[34m",
39
+ green: "\x1B[32m",
40
+ yellow: "\x1B[33m",
41
+ clear: "\x1B[0m",
42
+ bold: "\x1B[1m"
43
+ };
44
+ var colorize = {
51
45
  red: (strings, ...values) => ansis.red + templateIdentity(strings, ...values) + ansis.clear,
52
46
  blue: (strings, ...values) => ansis.blue + templateIdentity(strings, ...values) + ansis.clear,
53
47
  green: (strings, ...values) => ansis.green + templateIdentity(strings, ...values) + ansis.clear,
54
48
  yellow: (strings, ...values) => ansis.yellow + templateIdentity(strings, ...values) + ansis.clear,
55
- bold: (strings, ...values) => ansis.bold + templateIdentity(strings, ...values) + ansis.clear,
56
- }
57
-
58
- const filesCreated = [];
59
- const filesModified = [];
60
- const commandsExecuted = [];
61
-
62
- const packagesToInstall = [];
63
- const writeFileHandlers = [];
64
- const nextSteps = [
65
- `Create an account and Stack Auth API key for your project on https://app.stack-auth.com`,
49
+ bold: (strings, ...values) => ansis.bold + templateIdentity(strings, ...values) + ansis.clear
50
+ };
51
+ var filesCreated = [];
52
+ var filesModified = [];
53
+ var commandsExecuted = [];
54
+ var packagesToInstall = [];
55
+ var writeFileHandlers = [];
56
+ var nextSteps = [
57
+ `Create an account and Stack Auth API key for your project on https://app.stack-auth.com`
66
58
  ];
67
-
68
59
  async function main() {
69
- // Welcome message
70
60
  console.log();
71
61
  console.log(`
72
- ██████
73
- ██████████████
74
- ████████████████████
75
- ████████████████████ WELCOME TO
76
- █████████████████ ╔═╗╔╦╗╔═╗╔═╗╦╔═ ┌─┐┬ ┬┌┬┐┬
77
- █████████████ ╚═╗ ╠═╣║ ╠╩╗ ├─┤│ ├─┤
78
- █████████████ ████ ╚═╝ ╩╚═╝╩ ┴└─┘
79
- █████████████████
80
- ██████ ██
81
- ████ ████
82
- █████ █████
83
- ██████
62
+ \u2588\u2588\u2588\u2588\u2588\u2588
63
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
64
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
65
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 WELCOME TO
66
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2554\u2550\u2557\u2554\u2566\u2557\u2554\u2550\u2557\u2554\u2550\u2557\u2566\u2554\u2550 \u250C\u2500\u2510\u252C \u252C\u250C\u252C\u2510\u252C \u252C
67
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u255A\u2550\u2557 \u2551 \u2560\u2550\u2563\u2551 \u2560\u2569\u2557 \u251C\u2500\u2524\u2502 \u2502 \u2502 \u251C\u2500\u2524
68
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 \u255A\u2550\u255D \u2569 \u2569 \u2569\u255A\u2550\u255D\u2569 \u2569 \u2534 \u2534\u2514\u2500\u2518 \u2534 \u2534 \u2534
69
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588
70
+ \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588
71
+ \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588
72
+ \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588
73
+ \u2588\u2588\u2588\u2588\u2588\u2588
84
74
  `);
85
75
  console.log();
86
-
87
-
88
- // Wait just briefly so we can use `Steps` in here (it's defined only after the call to `main()`)
89
76
  await new Promise((resolve) => resolve());
90
-
91
-
92
- // Prepare some stuff
93
77
  await clearStdin();
94
78
  const projectPath = await getProjectPath();
95
-
96
-
97
- // Steps
98
79
  const { packageJson } = await Steps.getProject();
99
80
  const type = await Steps.getProjectType({ packageJson });
100
-
101
81
  await Steps.addStackPackage(type);
102
- if (isNeon) packagesToInstall.push('@neondatabase/serverless');
103
-
82
+ if (isNeon) packagesToInstall.push("@neondatabase/serverless");
104
83
  await Steps.writeEnvVars(type);
105
-
106
84
  if (type === "next") {
107
85
  const projectInfo = await Steps.getNextProjectInfo({ packageJson });
108
86
  await Steps.updateNextLayoutFile(projectInfo);
109
87
  await Steps.writeStackAppFile(projectInfo, "server");
110
88
  await Steps.writeNextHandlerFile(projectInfo);
111
89
  await Steps.writeNextLoadingFile(projectInfo);
112
- nextSteps.push(`Copy the environment variables from the new API key into your .env.local file`)
90
+ nextSteps.push(`Copy the environment variables from the new API key into your .env.local file`);
113
91
  } else if (type === "js") {
114
92
  const defaultExtension = await Steps.guessDefaultFileExtension();
115
93
  const where = await Steps.getServerOrClientOrBoth();
@@ -120,33 +98,26 @@ async function main() {
120
98
  type,
121
99
  defaultExtension,
122
100
  indentation: " ",
123
- srcPath,
101
+ srcPath
124
102
  }, w);
125
103
  appFiles.push(fileName);
126
104
  }
127
105
  nextSteps.push(
128
106
  `Copy the environment variables from the new API key into your own environment and reference them in ${appFiles.join(" and ")}`,
129
- `Follow the instructions on how to use Stack Auth's vanilla SDK at http://docs.stack-auth.com/others/js-client`,
107
+ `Follow the instructions on how to use Stack Auth's vanilla SDK at http://docs.stack-auth.com/others/js-client`
130
108
  );
131
109
  } else {
132
110
  throw new Error("Unknown type: " + type);
133
111
  }
134
-
135
112
  const { packageManager } = await Steps.getPackageManager();
136
113
  await Steps.ensureReady(type);
137
-
138
-
139
- // Install dependencies
140
114
  console.log();
141
115
  console.log(colorize.bold`Installing dependencies...`);
142
116
  const installCommand = packageManager === "yarn" ? "yarn add" : `${packageManager} install`;
143
- await shellNicelyFormatted(`${installCommand} ${packagesToInstall.join(' ')}`, {
117
+ await shellNicelyFormatted(`${installCommand} ${packagesToInstall.join(" ")}`, {
144
118
  shell: true,
145
- cwd: projectPath,
119
+ cwd: projectPath
146
120
  });
147
-
148
-
149
- // Write files
150
121
  console.log();
151
122
  console.log(colorize.bold`Writing files...`);
152
123
  console.log();
@@ -154,8 +125,7 @@ async function main() {
154
125
  await writeFileHandler();
155
126
  }
156
127
  console.log(`${colorize.green`√`} Done writing files`);
157
-
158
- console.log('\n\n\n');
128
+ console.log("\n\n\n");
159
129
  console.log(colorize.bold`${colorize.green`Installation succeeded!`}`);
160
130
  console.log();
161
131
  console.log("Commands executed:");
@@ -171,9 +141,6 @@ async function main() {
171
141
  console.log(` ${colorize.green`${file}`}`);
172
142
  }
173
143
  console.log();
174
-
175
-
176
- // Success!
177
144
  console.log(`
178
145
  ${colorize.green`===============================================`}
179
146
 
@@ -183,8 +150,7 @@ Next steps:
183
150
 
184
151
  ${[...nextSteps.entries()].map(([index, step]) => `${index + 1}. ${step}`).join("\n")}
185
152
 
186
- ${type === "next" ? `Then, you will be able to access your sign-in page on http://your-website.example.com/handler/sign-in. That's it!`
187
- : "That's it!"}
153
+ ${type === "next" ? `Then, you will be able to access your sign-in page on http://your-website.example.com/handler/sign-in. That's it!` : "That's it!"}
188
154
 
189
155
  ${colorize.green`===============================================`}
190
156
 
@@ -194,49 +160,43 @@ For more information, please visit https://docs.stack-auth.com/getting-started/s
194
160
  await open("https://app.stack-auth.com/wizard-congrats");
195
161
  }
196
162
  }
197
-
198
- main()
199
- .catch((err) => {
200
- if (!(err instanceof UserError)) {
201
- console.error(err);
202
- }
203
- console.error('\n\n\n\n');
204
- console.log(colorize.red`===============================================`);
205
- console.error();
206
- if (err instanceof UserError) {
207
- console.error(`${colorize.red`ERROR!`} ${err.message}`);
208
- } else {
209
- console.error("An error occurred during the initialization process.");
210
- }
211
- console.error();
212
- console.log(colorize.red`===============================================`);
213
- console.error();
214
- console.error(
215
- "If you need assistance, please try installing Stack manually as described in https://docs.stack-auth.com/getting-started/setup or join our Discord where we're happy to help: https://discord.stack-auth.com"
216
- );
217
- if (!(err instanceof UserError)) {
218
- console.error("");
219
- console.error(`Error message: ${err.message}`);
220
- }
221
- console.error();
222
- process.exit(1);
223
- });
224
-
225
-
226
- const Steps = {
163
+ main().catch((err) => {
164
+ if (!(err instanceof UserError)) {
165
+ console.error(err);
166
+ }
167
+ console.error("\n\n\n\n");
168
+ console.log(colorize.red`===============================================`);
169
+ console.error();
170
+ if (err instanceof UserError) {
171
+ console.error(`${colorize.red`ERROR!`} ${err.message}`);
172
+ } else {
173
+ console.error("An error occurred during the initialization process.");
174
+ }
175
+ console.error();
176
+ console.log(colorize.red`===============================================`);
177
+ console.error();
178
+ console.error(
179
+ "If you need assistance, please try installing Stack manually as described in https://docs.stack-auth.com/getting-started/setup or join our Discord where we're happy to help: https://discord.stack-auth.com"
180
+ );
181
+ if (!(err instanceof UserError)) {
182
+ console.error("");
183
+ console.error(`Error message: ${err.message}`);
184
+ }
185
+ console.error();
186
+ process.exit(1);
187
+ });
188
+ var Steps = {
227
189
  async getProject() {
228
190
  let projectPath = await getProjectPath();
229
191
  if (!fs.existsSync(projectPath)) {
230
192
  throw new UserError(`The project path ${projectPath} does not exist`);
231
193
  }
232
-
233
194
  const packageJsonPath = path.join(projectPath, "package.json");
234
195
  if (!fs.existsSync(packageJsonPath)) {
235
196
  throw new UserError(
236
197
  `The package.json file does not exist in the project path ${projectPath}. You must initialize a new project first before installing Stack.`
237
198
  );
238
199
  }
239
-
240
200
  const packageJsonText = fs.readFileSync(packageJsonPath, "utf-8");
241
201
  let packageJson;
242
202
  try {
@@ -244,106 +204,84 @@ const Steps = {
244
204
  } catch (e) {
245
205
  throw new UserError(`package.json file is not valid JSON: ${e}`);
246
206
  }
247
-
248
207
  return { packageJson };
249
208
  },
250
-
251
209
  async getProjectType({ packageJson }) {
252
210
  if (typeFromArgs) return typeFromArgs;
253
-
254
211
  const maybeNextProject = await Steps.maybeGetNextProjectInfo({ packageJson });
255
212
  if (!("error" in maybeNextProject)) return "next";
256
-
257
- const { type } = assertInteractive() && await inquirer.prompt([
213
+ const { type } = await inquirer.prompt([
258
214
  {
259
215
  type: "list",
260
216
  name: "type",
261
217
  message: "Which integration would you like to install?",
262
218
  choices: [
263
219
  { name: "None (vanilla JS, Node.js, etc)", value: "js" },
264
- { name: "Next.js", value: "next" },
220
+ { name: "Next.js", value: "next" }
265
221
  ]
266
222
  }
267
223
  ]);
268
-
269
224
  return type;
270
225
  },
271
-
272
226
  async getStackPackageName(type, install = false) {
273
227
  return {
274
- "js": (install && process.env.STACK_JS_INSTALL_PACKAGE_NAME_OVERRIDE) || "@stackframe/js",
275
- "next": (install && process.env.STACK_NEXT_INSTALL_PACKAGE_NAME_OVERRIDE) || "@stackframe/stack",
228
+ "js": install && process.env.STACK_JS_INSTALL_PACKAGE_NAME_OVERRIDE || "@stackframe/js",
229
+ "next": install && process.env.STACK_NEXT_INSTALL_PACKAGE_NAME_OVERRIDE || "@stackframe/stack"
276
230
  }[type] ?? throwErr("Unknown type in addStackPackage: " + type);
277
231
  },
278
-
279
232
  async addStackPackage(type) {
280
- packagesToInstall.push(await Steps.getStackPackageName(type, true));
233
+ packagesToInstall.push(await Steps.getStackPackageName(type, true));
281
234
  },
282
-
283
235
  async getNextProjectInfo({ packageJson }) {
284
236
  const maybe = await Steps.maybeGetNextProjectInfo({ packageJson });
285
237
  if ("error" in maybe) throw new UserError(maybe.error);
286
238
  return maybe;
287
239
  },
288
-
289
240
  async maybeGetNextProjectInfo({ packageJson }) {
290
241
  const projectPath = await getProjectPath();
291
-
292
- const nextVersionInPackageJson = packageJson?.dependencies?.["next"] ?? packageJson?.devDependencies?.["next"];
242
+ const nextVersionInPackageJson = packageJson.dependencies?.["next"] ?? packageJson.devDependencies?.["next"];
293
243
  if (!nextVersionInPackageJson) {
294
244
  return { error: `The project at ${projectPath} does not appear to be a Next.js project, or does not have 'next' installed as a dependency.` };
295
245
  }
296
- if (
297
- !nextVersionInPackageJson.includes("14") &&
298
- !nextVersionInPackageJson.includes("15") &&
299
- nextVersionInPackageJson !== "latest"
300
- ) {
301
- return { error: `The project at ${projectPath} is using an unsupported version of Next.js (found ${nextVersionInPackageJson}).\n\nOnly Next.js 14 & 15 projects are currently supported. See Next's upgrade guide: https://nextjs.org/docs/app/building-your-application/upgrading/version-14` };
246
+ if (!nextVersionInPackageJson.includes("14") && !nextVersionInPackageJson.includes("15") && nextVersionInPackageJson !== "latest") {
247
+ return { error: `The project at ${projectPath} is using an unsupported version of Next.js (found ${nextVersionInPackageJson}).
248
+
249
+ Only Next.js 14 & 15 projects are currently supported. See Next's upgrade guide: https://nextjs.org/docs/app/building-your-application/upgrading/version-14` };
302
250
  }
303
-
304
251
  const nextConfigPathWithoutExtension = path.join(projectPath, "next.config");
305
252
  const nextConfigFileExtension = await findJsExtension(
306
253
  nextConfigPathWithoutExtension
307
254
  );
308
- const nextConfigPath =
309
- nextConfigPathWithoutExtension + "." + (nextConfigFileExtension ?? "js");
255
+ const nextConfigPath = nextConfigPathWithoutExtension + "." + (nextConfigFileExtension ?? "js");
310
256
  if (!fs.existsSync(nextConfigPath)) {
311
257
  return { error: `Expected file at ${nextConfigPath}. Only Next.js projects are currently supported.` };
312
258
  }
313
-
314
259
  const hasSrcAppFolder = fs.existsSync(path.join(projectPath, "src/app"));
315
260
  const srcPath = path.join(projectPath, hasSrcAppFolder ? "src" : "");
316
261
  const appPath = path.join(srcPath, "app");
317
262
  if (!fs.existsSync(appPath)) {
318
263
  return { error: `The app path ${appPath} does not exist. Only the Next.js app router is supported.` };
319
264
  }
320
-
321
265
  const dryUpdateNextLayoutFileResult = await Steps.dryUpdateNextLayoutFile({ appPath, defaultExtension: "jsx" });
322
-
323
266
  return {
324
267
  type: "next",
325
268
  srcPath,
326
269
  appPath,
327
270
  defaultExtension: dryUpdateNextLayoutFileResult.fileExtension,
328
- indentation: dryUpdateNextLayoutFileResult.indentation,
271
+ indentation: dryUpdateNextLayoutFileResult.indentation
329
272
  };
330
273
  },
331
-
332
274
  async writeEnvVars(type) {
333
275
  const projectPath = await getProjectPath();
334
-
335
- // TODO: in non-Next environments, ask the user what method they prefer for envvars
336
276
  if (type !== "next") return false;
337
-
338
277
  const envLocalPath = path.join(projectPath, ".env.local");
339
-
340
278
  const potentialEnvLocations = [
341
279
  path.join(projectPath, ".env"),
342
280
  path.join(projectPath, ".env.development"),
343
281
  path.join(projectPath, ".env.default"),
344
282
  path.join(projectPath, ".env.defaults"),
345
283
  path.join(projectPath, ".env.example"),
346
- envLocalPath,
284
+ envLocalPath
347
285
  ];
348
286
  if (potentialEnvLocations.every((p) => !fs.existsSync(p))) {
349
287
  laterWriteFile(
@@ -352,25 +290,18 @@ const Steps = {
352
290
  );
353
291
  return true;
354
292
  }
355
-
356
293
  return false;
357
294
  },
358
-
359
295
  async dryUpdateNextLayoutFile({ appPath, defaultExtension }) {
360
296
  const layoutPathWithoutExtension = path.join(appPath, "layout");
361
- const layoutFileExtension =
362
- (await findJsExtension(layoutPathWithoutExtension)) ?? defaultExtension;
297
+ const layoutFileExtension = await findJsExtension(layoutPathWithoutExtension) ?? defaultExtension;
363
298
  const layoutPath = layoutPathWithoutExtension + "." + layoutFileExtension;
364
- const layoutContent =
365
- (await readFile(layoutPath)) ??
366
- throwErr(
367
- `The layout file at ${layoutPath} does not exist. Stack requires a layout file to be present in the /app folder.`
368
- );
369
- const updatedLayoutResult =
370
- (await getUpdatedLayout(layoutContent)) ??
371
- throwErr(
372
- "Unable to parse root layout file. Make sure it contains a <body> tag. If it still doesn't work, you may need to manually install Stack. See: https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required"
373
- );
299
+ const layoutContent = await readFile(layoutPath) ?? throwErr(
300
+ `The layout file at ${layoutPath} does not exist. Stack requires a layout file to be present in the /app folder.`
301
+ );
302
+ const updatedLayoutResult = await getUpdatedLayout(layoutContent) ?? throwErr(
303
+ "Unable to parse root layout file. Make sure it contains a <body> tag. If it still doesn't work, you may need to manually install Stack. See: https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required"
304
+ );
374
305
  const updatedLayoutContent = updatedLayoutResult.content;
375
306
  return {
376
307
  path: layoutPath,
@@ -379,31 +310,24 @@ const Steps = {
379
310
  indentation: updatedLayoutResult.indentation
380
311
  };
381
312
  },
382
-
383
313
  async updateNextLayoutFile(projectInfo) {
384
314
  const res = await Steps.dryUpdateNextLayoutFile(projectInfo);
385
315
  laterWriteFile(res.path, res.updatedContent);
386
316
  return res;
387
317
  },
388
-
389
318
  async writeStackAppFile({ type, srcPath, defaultExtension, indentation }, clientOrServer) {
390
319
  const packageName = await Steps.getStackPackageName(type);
391
-
392
320
  const clientOrServerCap = {
393
321
  client: "Client",
394
- server: "Server",
322
+ server: "Server"
395
323
  }[clientOrServer] ?? throwErr("unknown clientOrServer " + clientOrServer);
396
-
397
324
  const relativeStackAppPath = {
398
325
  js: `stack/${clientOrServer}`,
399
- next: "stack",
326
+ next: "stack"
400
327
  }[type] ?? throwErr("unknown type");
401
-
402
328
  const stackAppPathWithoutExtension = path.join(srcPath, relativeStackAppPath);
403
- const stackAppFileExtension =
404
- (await findJsExtension(stackAppPathWithoutExtension)) ?? defaultExtension;
405
- const stackAppPath =
406
- stackAppPathWithoutExtension + "." + stackAppFileExtension;
329
+ const stackAppFileExtension = await findJsExtension(stackAppPathWithoutExtension) ?? defaultExtension;
330
+ const stackAppPath = stackAppPathWithoutExtension + "." + stackAppFileExtension;
407
331
  const stackAppContent = await readFile(stackAppPath);
408
332
  if (stackAppContent) {
409
333
  if (!stackAppContent.includes("@stackframe/")) {
@@ -423,23 +347,22 @@ ${type === "next" ? `import "server-only";` : ""}
423
347
  import { Stack${clientOrServerCap}App } from ${JSON.stringify(packageName)};
424
348
 
425
349
  export const stack${clientOrServerCap}App = new Stack${clientOrServerCap}App({
426
- ${indentation}tokenStore: ${type === "next" ? '"nextjs-cookie"' : (clientOrServer === "client" ? '"cookie"' : '"memory"')},${
427
- type === "js" ? `\n\n${indentation}// get your Stack Auth API keys from https://app.stack-auth.com${clientOrServer === "client" ? ` and store them in a safe place (eg. environment variables)` : ""}` : ""}${
428
- type === "js" ? `\n${indentation}publishableClientKey: ${clientOrServer === "server" ? 'process.env.STACK_PUBLISHABLE_CLIENT_KEY' : 'INSERT_YOUR_PUBLISHABLE_CLIENT_KEY_HERE'}` : ""},${
429
- type === "js" && clientOrServer === "server" ? `\n${indentation}secretServerKey: process.env.STACK_SECRET_SERVER_KEY,` : ""}
350
+ ${indentation}tokenStore: ${type === "next" ? '"nextjs-cookie"' : clientOrServer === "client" ? '"cookie"' : '"memory"'},${type === "js" ? `
351
+
352
+ ${indentation}// get your Stack Auth API keys from https://app.stack-auth.com${clientOrServer === "client" ? ` and store them in a safe place (eg. environment variables)` : ""}` : ""}${type === "js" ? `
353
+ ${indentation}publishableClientKey: ${clientOrServer === "server" ? "process.env.STACK_PUBLISHABLE_CLIENT_KEY" : "INSERT_YOUR_PUBLISHABLE_CLIENT_KEY_HERE"},` : ""}${type === "js" && clientOrServer === "server" ? `
354
+ ${indentation}secretServerKey: process.env.STACK_SECRET_SERVER_KEY,` : ""}
430
355
  });
431
356
  `.trim() + "\n"
432
357
  );
433
358
  return { fileName: stackAppPath };
434
359
  },
435
-
436
360
  async writeNextHandlerFile(projectInfo) {
437
361
  const handlerPathWithoutExtension = path.join(
438
362
  projectInfo.appPath,
439
363
  "handler/[...stack]/page"
440
364
  );
441
- const handlerFileExtension =
442
- (await findJsExtension(handlerPathWithoutExtension)) ?? projectInfo.defaultExtension;
365
+ const handlerFileExtension = await findJsExtension(handlerPathWithoutExtension) ?? projectInfo.defaultExtension;
443
366
  const handlerPath = handlerPathWithoutExtension + "." + handlerFileExtension;
444
367
  const handlerContent = await readFile(handlerPath);
445
368
  if (handlerContent && !handlerContent.includes("@stackframe/")) {
@@ -449,28 +372,33 @@ type === "js" && clientOrServer === "server" ? `\n${indentation}secretServerKey:
449
372
  }
450
373
  laterWriteFileIfNotExists(
451
374
  handlerPath,
452
- `\nimport { stackServerApp } from "../../../stack";\n\nexport default function Handler(props${
453
- handlerFileExtension.includes("ts") ? ": unknown" : ""
454
- }) {\n${projectInfo.indentation}return <StackHandler fullPage app={stackServerApp} routeProps={props} />;\n}\n`
375
+ `import { StackHandler } from "@stackframe/stack";
376
+ import { stackServerApp } from "../../../stack";
377
+
378
+ export default function Handler(props${handlerFileExtension.includes("ts") ? ": unknown" : ""}) {
379
+ ${projectInfo.indentation}return <StackHandler fullPage app={stackServerApp} routeProps={props} />;
380
+ }
381
+ `
455
382
  );
456
383
  },
457
-
458
384
  async writeNextLoadingFile(projectInfo) {
459
385
  let loadingPathWithoutExtension = path.join(projectInfo.appPath, "loading");
460
- const loadingFileExtension =
461
- (await findJsExtension(loadingPathWithoutExtension)) ?? projectInfo.defaultExtension;
386
+ const loadingFileExtension = await findJsExtension(loadingPathWithoutExtension) ?? projectInfo.defaultExtension;
462
387
  const loadingPath = loadingPathWithoutExtension + "." + loadingFileExtension;
463
388
  laterWriteFileIfNotExists(
464
389
  loadingPath,
465
- `export default function Loading() {\n${projectInfo.indentation}// Stack uses React Suspense, which will render this page while user data is being fetched.\n${projectInfo.indentation}// See: https://nextjs.org/docs/app/api-reference/file-conventions/loading\n${projectInfo.indentation}return <></>;\n}\n`
390
+ `export default function Loading() {
391
+ ${projectInfo.indentation}// Stack uses React Suspense, which will render this page while user data is being fetched.
392
+ ${projectInfo.indentation}// See: https://nextjs.org/docs/app/api-reference/file-conventions/loading
393
+ ${projectInfo.indentation}return <></>;
394
+ }
395
+ `
466
396
  );
467
397
  },
468
-
469
398
  async getPackageManager() {
470
399
  if (packageManagerFromArgs) return { packageManager: packageManagerFromArgs };
471
400
  const packageManager = await promptPackageManager();
472
401
  const versionCommand = `${packageManager} --version`;
473
-
474
402
  try {
475
403
  await shellNicelyFormatted(versionCommand, { shell: true, quiet: true });
476
404
  } catch (err) {
@@ -479,13 +407,10 @@ type === "js" && clientOrServer === "server" ? `\n${indentation}secretServerKey:
479
407
  `Could not run the package manager command '${versionCommand}'. Please make sure ${packageManager} is installed on your system.`
480
408
  );
481
409
  }
482
-
483
410
  return { packageManager };
484
411
  },
485
-
486
412
  async ensureReady(type) {
487
413
  const projectPath = await getProjectPath();
488
-
489
414
  const typeString = {
490
415
  js: "JavaScript",
491
416
  next: "Next.js"
@@ -494,22 +419,20 @@ type === "js" && clientOrServer === "server" ? `\n${indentation}secretServerKey:
494
419
  {
495
420
  type: "confirm",
496
421
  name: "ready",
497
- message: `Found a ${typeString} project at ${projectPath} ready to install Stack Auth?`,
498
- default: true,
499
- },
422
+ message: `Found a ${typeString} project at ${projectPath} \u2014 ready to install Stack Auth?`,
423
+ default: true
424
+ }
500
425
  ])).ready;
501
426
  if (!isReady) {
502
427
  throw new UserError("Installation aborted.");
503
428
  }
504
429
  },
505
-
506
430
  async getServerOrClientOrBoth() {
507
431
  if (isClient && isServer) return ["server", "client"];
508
432
  if (isServer) return ["server"];
509
433
  if (isClient) return ["client"];
510
-
511
434
  return (await inquirer.prompt([{
512
- type: "list",
435
+ type: "list",
513
436
  name: "type",
514
437
  message: "Do you want to use Stack Auth on the server, or on the client?",
515
438
  choices: [
@@ -519,7 +442,6 @@ type === "js" && clientOrServer === "server" ? `\n${indentation}secretServerKey:
519
442
  ]
520
443
  }])).type;
521
444
  },
522
-
523
445
  /**
524
446
  * note: this is a heuristic, specific frameworks may have better heuristics (eg. the Next.js code uses the extension of the global layout file)
525
447
  */
@@ -530,7 +452,6 @@ type === "js" && clientOrServer === "server" ? `\n${indentation}secretServerKey:
530
452
  );
531
453
  return hasTsConfig ? "ts" : "js";
532
454
  },
533
-
534
455
  /**
535
456
  * note: this is a heuristic, specific frameworks may have better heuristics (eg. the Next.js code uses the location of the app folder)
536
457
  */
@@ -541,38 +462,29 @@ type === "js" && clientOrServer === "server" ? `\n${indentation}secretServerKey:
541
462
  path.join(projectPath, "src")
542
463
  );
543
464
  return hasSrcFolder ? potentialSrcPath : projectPath;
544
- },
545
-
546
-
465
+ }
547
466
  };
548
-
549
-
550
467
  async function getUpdatedLayout(originalLayout) {
551
468
  let layout = originalLayout;
552
469
  const indentation = guessIndentation(originalLayout);
553
-
554
470
  const firstImportLocationM1 = /\simport\s/.exec(layout)?.index;
555
471
  const hasStringAsFirstLine = layout.startsWith('"') || layout.startsWith("'");
556
- const importInsertLocationM1 =
557
- firstImportLocationM1 ?? (hasStringAsFirstLine ? layout.indexOf("\n") : -1);
472
+ const importInsertLocationM1 = firstImportLocationM1 ?? (hasStringAsFirstLine ? layout.indexOf("\n") : -1);
558
473
  const importInsertLocation = importInsertLocationM1 + 1;
559
- const importStatement = `import { StackProvider, StackTheme } from "@stackframe/stack";\nimport { stackServerApp } from "../stack";\n`;
560
- layout =
561
- layout.slice(0, importInsertLocation) +
562
- importStatement +
563
- layout.slice(importInsertLocation);
564
-
474
+ const importStatement = `import { StackProvider, StackTheme } from "@stackframe/stack";
475
+ import { stackServerApp } from "../stack";
476
+ `;
477
+ layout = layout.slice(0, importInsertLocation) + importStatement + layout.slice(importInsertLocation);
565
478
  const bodyOpenTag = /<\s*body[^>]*>/.exec(layout);
566
479
  const bodyCloseTag = /<\s*\/\s*body[^>]*>/.exec(layout);
567
480
  if (!bodyOpenTag || !bodyCloseTag) {
568
- return undefined;
481
+ return void 0;
569
482
  }
570
483
  const bodyOpenEndIndex = bodyOpenTag.index + bodyOpenTag[0].length;
571
484
  const bodyCloseStartIndex = bodyCloseTag.index;
572
485
  if (bodyCloseStartIndex <= bodyOpenEndIndex) {
573
- return undefined;
486
+ return void 0;
574
487
  }
575
-
576
488
  const lines = layout.split("\n");
577
489
  const [bodyOpenEndLine, bodyOpenEndIndexInLine] = getLineIndex(
578
490
  lines,
@@ -582,41 +494,26 @@ async function getUpdatedLayout(originalLayout) {
582
494
  lines,
583
495
  bodyCloseStartIndex
584
496
  );
585
-
586
497
  const insertOpen = "<StackProvider app={stackServerApp}><StackTheme>";
587
498
  const insertClose = "</StackTheme></StackProvider>";
588
-
589
- layout =
590
- layout.slice(0, bodyCloseStartIndex) +
591
- insertClose +
592
- layout.slice(bodyCloseStartIndex);
593
- layout =
594
- layout.slice(0, bodyOpenEndIndex) +
595
- insertOpen +
596
- layout.slice(bodyOpenEndIndex);
597
-
499
+ layout = layout.slice(0, bodyCloseStartIndex) + insertClose + layout.slice(bodyCloseStartIndex);
500
+ layout = layout.slice(0, bodyOpenEndIndex) + insertOpen + layout.slice(bodyOpenEndIndex);
598
501
  return {
599
502
  content: `${layout}`,
600
- indentation,
503
+ indentation
601
504
  };
602
505
  }
603
-
604
506
  function guessIndentation(str) {
605
507
  const lines = str.split("\n");
606
- const linesLeadingWhitespaces = lines
607
- .map((line) => line.match(/^\s*/)[0])
608
- .filter((ws) => ws.length > 0);
609
- const isMostlyTabs =
610
- linesLeadingWhitespaces.filter((ws) => ws.includes("\t")).length >=
611
- (linesLeadingWhitespaces.length * 2) / 3;
612
- if (isMostlyTabs) return "\t";
508
+ const linesLeadingWhitespaces = lines.map((line) => line.match(/^\s*/)[0]).filter((ws) => ws.length > 0);
509
+ const isMostlyTabs = linesLeadingWhitespaces.filter((ws) => ws.includes(" ")).length >= linesLeadingWhitespaces.length * 2 / 3;
510
+ if (isMostlyTabs) return " ";
613
511
  const linesLeadingWhitespacesCount = linesLeadingWhitespaces.map(
614
512
  (ws) => ws.length
615
513
  );
616
514
  const min = Math.min(Infinity, ...linesLeadingWhitespacesCount);
617
515
  return Number.isFinite(min) ? " ".repeat(Math.max(2, min)) : " ";
618
516
  }
619
-
620
517
  function getLineIndex(lines, stringIndex) {
621
518
  let lineIndex = 0;
622
519
  for (let l = 0; l < lines.length; l++) {
@@ -630,30 +527,25 @@ function getLineIndex(lines, stringIndex) {
630
527
  `Index ${stringIndex} is out of bounds for lines ${JSON.stringify(lines)}`
631
528
  );
632
529
  }
633
-
634
530
  async function getProjectPath() {
635
- if (savedProjectPath === undefined) {
531
+ if (savedProjectPath === void 0) {
636
532
  savedProjectPath = process.cwd();
637
-
638
533
  const askForPathModification = !fs.existsSync(
639
534
  path.join(savedProjectPath, "package.json")
640
535
  );
641
536
  if (askForPathModification) {
642
- savedProjectPath = (
643
- assertInteractive() && await inquirer.prompt([
644
- {
645
- type: "input",
646
- name: "newPath",
647
- message: "Please enter the path to your project:",
648
- default: ".",
649
- },
650
- ])
651
- ).newPath;
537
+ savedProjectPath = (await inquirer.prompt([
538
+ {
539
+ type: "input",
540
+ name: "newPath",
541
+ message: "Please enter the path to your project:",
542
+ default: "."
543
+ }
544
+ ])).newPath;
652
545
  }
653
546
  }
654
547
  return savedProjectPath;
655
548
  }
656
-
657
549
  async function findJsExtension(fullPathWithoutExtension) {
658
550
  for (const ext of jsLikeFileExtensions) {
659
551
  const fullPath = fullPathWithoutExtension + "." + ext;
@@ -663,14 +555,12 @@ async function findJsExtension(fullPathWithoutExtension) {
663
555
  }
664
556
  return null;
665
557
  }
666
-
667
558
  async function promptPackageManager() {
668
559
  const projectPath = await getProjectPath();
669
560
  const yarnLock = fs.existsSync(path.join(projectPath, "yarn.lock"));
670
561
  const pnpmLock = fs.existsSync(path.join(projectPath, "pnpm-lock.yaml"));
671
562
  const npmLock = fs.existsSync(path.join(projectPath, "package-lock.json"));
672
563
  const bunLock = fs.existsSync(path.join(projectPath, "bun.lockb"));
673
-
674
564
  if (yarnLock && !pnpmLock && !npmLock && !bunLock) {
675
565
  return "yarn";
676
566
  } else if (!yarnLock && pnpmLock && !npmLock && !bunLock) {
@@ -680,21 +570,20 @@ async function promptPackageManager() {
680
570
  } else if (!yarnLock && !pnpmLock && !npmLock && bunLock) {
681
571
  return "bun";
682
572
  }
683
-
684
- const answers = assertInteractive() && await inquirer.prompt([
573
+ const answers = await inquirer.prompt([
685
574
  {
686
575
  type: "list",
687
576
  name: "packageManager",
688
577
  message: "Which package manager are you using for this project?",
689
- choices: ["npm", "yarn", "pnpm", "bun"],
690
- },
578
+ choices: ["npm", "yarn", "pnpm", "bun"]
579
+ }
691
580
  ]);
692
581
  return answers.packageManager;
693
582
  }
694
-
695
583
  async function shellNicelyFormatted(command, { quiet, ...options }) {
696
- let ui, interval;
697
- if (!quiet) {
584
+ let ui;
585
+ let interval;
586
+ if (!quiet) {
698
587
  console.log();
699
588
  ui = new inquirer.ui.BottomBar();
700
589
  let dots = 4;
@@ -709,7 +598,6 @@ async function shellNicelyFormatted(command, { quiet, ...options }) {
709
598
  }
710
599
  }, 700);
711
600
  }
712
-
713
601
  try {
714
602
  if (!isDryRun) {
715
603
  const child = child_process.spawn(command, options);
@@ -717,7 +605,6 @@ async function shellNicelyFormatted(command, { quiet, ...options }) {
717
605
  child.stdout.pipe(ui.log);
718
606
  child.stderr.pipe(ui.log);
719
607
  }
720
-
721
608
  await new Promise((resolve, reject) => {
722
609
  child.on("exit", (code) => {
723
610
  if (code === 0) {
@@ -730,33 +617,36 @@ async function shellNicelyFormatted(command, { quiet, ...options }) {
730
617
  } else {
731
618
  console.log(`[DRY-RUN] Would have run: ${command}`);
732
619
  }
733
-
734
620
  if (!quiet) {
735
621
  commandsExecuted.push(command);
736
622
  ui.updateBottomBar(
737
- `${colorize.green`√`} Command ${command} succeeded\n`
623
+ `${colorize.green`√`} Command ${command} succeeded
624
+ `
738
625
  );
739
626
  }
740
627
  } catch (e) {
741
628
  if (!quiet) {
742
629
  ui.updateBottomBar(
743
- `${colorize.red`X`} Command ${command} failed\n`
630
+ `${colorize.red`X`} Command ${command} failed
631
+ `
744
632
  );
745
633
  }
746
634
  throw e;
747
635
  } finally {
748
- clearTimeout(interval);
636
+ if (interval) {
637
+ clearTimeout(interval);
638
+ }
749
639
  if (!quiet) {
750
640
  ui.close();
751
641
  }
752
642
  }
753
643
  }
754
-
755
644
  async function readFile(fullPath) {
756
645
  try {
757
646
  if (!isDryRun) {
758
647
  return fs.readFileSync(fullPath, "utf-8");
759
648
  }
649
+ return null;
760
650
  } catch (err) {
761
651
  if (err.code === "ENOENT") {
762
652
  return null;
@@ -764,7 +654,6 @@ async function readFile(fullPath) {
764
654
  throw err;
765
655
  }
766
656
  }
767
-
768
657
  async function writeFile(fullPath, content) {
769
658
  let create = !fs.existsSync(fullPath);
770
659
  if (!isDryRun) {
@@ -780,61 +669,48 @@ async function writeFile(fullPath, content) {
780
669
  filesCreated.push(relativeToProjectPath);
781
670
  }
782
671
  }
783
-
784
- function laterWriteFile(...args) {
672
+ function laterWriteFile(fullPath, content) {
785
673
  writeFileHandlers.push(async () => {
786
- await writeFile(...args);
787
- })
674
+ await writeFile(fullPath, content);
675
+ });
788
676
  }
789
-
790
677
  async function writeFileIfNotExists(fullPath, content) {
791
678
  if (!fs.existsSync(fullPath)) {
792
679
  await writeFile(fullPath, content);
793
680
  }
794
681
  }
795
-
796
- function laterWriteFileIfNotExists(...args) {
682
+ function laterWriteFileIfNotExists(fullPath, content) {
797
683
  writeFileHandlers.push(async () => {
798
- await writeFileIfNotExists(...args);
799
- })
800
- }
801
-
802
- function assertInteractive() {
803
- if (process.env.STACK_DISABLE_INTERACTIVE) {
804
- throw new UserError("STACK_DISABLE_INTERACTIVE is set, but wizard requires interactivity to complete. Make sure you supplied all required command line arguments!");
805
- }
806
- return true;
684
+ await writeFileIfNotExists(fullPath, content);
685
+ });
807
686
  }
808
-
809
687
  function throwErr(message) {
810
688
  throw new Error(message);
811
689
  }
812
-
813
- // TODO import this function from stack-shared instead (but that would require us to fix the build to let us import it)
814
- export function templateIdentity(strings, ...values) {
690
+ function templateIdentity(strings, ...values) {
815
691
  if (strings.length === 0) return "";
816
692
  if (values.length !== strings.length - 1) throw new Error("Invalid number of values; must be one less than strings");
817
-
818
693
  return strings.slice(1).reduce((result, string, i) => `${result}${values[i] ?? "n/a"}${string}`, strings[0]);
819
694
  }
820
-
821
695
  async function clearStdin() {
822
696
  await new Promise((resolve) => {
697
+ if (process.stdin.isTTY) {
698
+ process.stdin.setRawMode(true);
699
+ }
700
+ process.stdin.resume();
701
+ process.stdin.removeAllListeners("data");
702
+ const flush = () => {
703
+ while (process.stdin.read() !== null) {
704
+ }
823
705
  if (process.stdin.isTTY) {
824
- process.stdin.setRawMode(true);
706
+ process.stdin.setRawMode(false);
825
707
  }
826
- process.stdin.resume();
827
- process.stdin.removeAllListeners('data');
828
-
829
- const flush = () => {
830
- while (process.stdin.read() !== null) {}
831
- if (process.stdin.isTTY) {
832
- process.stdin.setRawMode(false);
833
- }
834
- resolve();
835
- };
836
-
837
- // Add a small delay to allow any buffered input to clear
838
- setTimeout(flush, 10);
708
+ resolve();
709
+ };
710
+ setTimeout(flush, 10);
839
711
  });
840
712
  }
713
+ export {
714
+ templateIdentity
715
+ };
716
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import * as child_process from \"child_process\";\nimport * as fs from \"fs\";\nimport inquirer from \"inquirer\";\nimport open from \"open\";\nimport * as path from \"path\";\n\nconst jsLikeFileExtensions: string[] = [\n \"mtsx\",\n \"ctsx\",\n \"tsx\",\n \"mts\",\n \"cts\",\n \"ts\",\n \"mjsx\",\n \"cjsx\",\n \"jsx\",\n \"mjs\",\n \"cjs\",\n \"js\",\n];\n\nclass UserError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"UserError\";\n }\n}\n\nlet savedProjectPath: string | undefined = process.argv[2] || undefined;\n\nconst isDryRun: boolean = process.argv.includes(\"--dry-run\");\nconst isNeon: boolean = process.argv.includes(\"--neon\");\nconst typeFromArgs: string | undefined = [\"js\", \"next\"].find(s => process.argv.includes(`--${s}`));\nconst packageManagerFromArgs: string | undefined = [\"npm\", \"yarn\", \"pnpm\", \"bun\"].find(s => process.argv.includes(`--${s}`));\nconst isClient: boolean = process.argv.includes(\"--client\");\nconst isServer: boolean = process.argv.includes(\"--server\");\n\ntype Ansis = {\n red: string,\n blue: string,\n green: string,\n yellow: string,\n clear: string,\n bold: string,\n};\n\nconst ansis: Ansis = {\n red: \"\\x1b[31m\",\n blue: \"\\x1b[34m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n\n clear: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n};\n\ntype TemplateFunction = (strings: TemplateStringsArray, ...values: any[]) => string;\n\ntype Colorize = {\n red: TemplateFunction,\n blue: TemplateFunction,\n green: TemplateFunction,\n yellow: TemplateFunction,\n bold: TemplateFunction,\n};\n\nconst colorize: Colorize = {\n red: (strings, ...values) => ansis.red + templateIdentity(strings, ...values) + ansis.clear,\n blue: (strings, ...values) => ansis.blue + templateIdentity(strings, ...values) + ansis.clear,\n green: (strings, ...values) => ansis.green + templateIdentity(strings, ...values) + ansis.clear,\n yellow: (strings, ...values) => ansis.yellow + templateIdentity(strings, ...values) + ansis.clear,\n bold: (strings, ...values) => ansis.bold + templateIdentity(strings, ...values) + ansis.clear,\n};\n\nconst filesCreated: string[] = [];\nconst filesModified: string[] = [];\nconst commandsExecuted: string[] = [];\n\nconst packagesToInstall: string[] = [];\nconst writeFileHandlers: Array<() => Promise<void>> = [];\nconst nextSteps: string[] = [\n `Create an account and Stack Auth API key for your project on https://app.stack-auth.com`,\n];\n\nasync function main(): Promise<void> {\n // Welcome message\n console.log();\n console.log(`\n ██████\n ██████████████\n████████████████████\n████████████████████ WELCOME TO\n█████████████████ ╔═╗╔╦╗╔═╗╔═╗╦╔═ ┌─┐┬ ┬┌┬┐┬ ┬\n█████████████ ╚═╗ ║ ╠═╣║ ╠╩╗ ├─┤│ │ │ ├─┤\n█████████████ ████ ╚═╝ ╩ ╩ ╩╚═╝╩ ╩ ┴ ┴└─┘ ┴ ┴ ┴\n █████████████████\n ██████ ██\n████ ████\n █████ █████\n ██████\n `);\n console.log();\n\n\n // Wait just briefly so we can use `Steps` in here (it's defined only after the call to `main()`)\n await new Promise<void>((resolve) => resolve());\n\n\n // Prepare some stuff\n await clearStdin();\n const projectPath = await getProjectPath();\n\n\n // Steps\n const { packageJson } = await Steps.getProject();\n const type = await Steps.getProjectType({ packageJson });\n\n await Steps.addStackPackage(type);\n if (isNeon) packagesToInstall.push('@neondatabase/serverless');\n\n await Steps.writeEnvVars(type);\n\n if (type === \"next\") {\n const projectInfo = await Steps.getNextProjectInfo({ packageJson });\n await Steps.updateNextLayoutFile(projectInfo);\n await Steps.writeStackAppFile(projectInfo, \"server\");\n await Steps.writeNextHandlerFile(projectInfo);\n await Steps.writeNextLoadingFile(projectInfo);\n nextSteps.push(`Copy the environment variables from the new API key into your .env.local file`);\n } else if (type === \"js\") {\n const defaultExtension = await Steps.guessDefaultFileExtension();\n const where = await Steps.getServerOrClientOrBoth();\n const srcPath = await Steps.guessSrcPath();\n const appFiles: string[] = [];\n for (const w of where) {\n const { fileName } = await Steps.writeStackAppFile({\n type,\n defaultExtension,\n indentation: \" \",\n srcPath,\n }, w);\n appFiles.push(fileName);\n }\n nextSteps.push(\n `Copy the environment variables from the new API key into your own environment and reference them in ${appFiles.join(\" and \")}`,\n `Follow the instructions on how to use Stack Auth's vanilla SDK at http://docs.stack-auth.com/others/js-client`,\n );\n } else {\n throw new Error(\"Unknown type: \" + type);\n }\n\n const { packageManager } = await Steps.getPackageManager();\n await Steps.ensureReady(type);\n\n\n // Install dependencies\n console.log();\n console.log(colorize.bold`Installing dependencies...`);\n const installCommand = packageManager === \"yarn\" ? \"yarn add\" : `${packageManager} install`;\n await shellNicelyFormatted(`${installCommand} ${packagesToInstall.join(' ')}`, {\n shell: true,\n cwd: projectPath,\n });\n\n\n // Write files\n console.log();\n console.log(colorize.bold`Writing files...`);\n console.log();\n for (const writeFileHandler of writeFileHandlers) {\n await writeFileHandler();\n }\n console.log(`${colorize.green`√`} Done writing files`);\n\n console.log('\\n\\n\\n');\n console.log(colorize.bold`${colorize.green`Installation succeeded!`}`);\n console.log();\n console.log(\"Commands executed:\");\n for (const command of commandsExecuted) {\n console.log(` ${colorize.blue`${command}`}`);\n }\n console.log();\n console.log(\"Files written:\");\n for (const file of filesModified) {\n console.log(` ${colorize.yellow`${file}`}`);\n }\n for (const file of filesCreated) {\n console.log(` ${colorize.green`${file}`}`);\n }\n console.log();\n\n\n // Success!\n console.log(`\n${colorize.green`===============================================`}\n\n${colorize.green`Successfully installed Stack! 🚀🚀🚀`}\n\nNext steps:\n\n${[...nextSteps.entries()].map(([index, step]) => `${index + 1}. ${step}`).join(\"\\n\")}\n\n${type === \"next\" ? `Then, you will be able to access your sign-in page on http://your-website.example.com/handler/sign-in. That's it!`\n : \"That's it!\"}\n\n${colorize.green`===============================================`}\n\nFor more information, please visit https://docs.stack-auth.com/getting-started/setup\n `.trim());\n if (!process.env.STACK_DISABLE_INTERACTIVE) {\n await open(\"https://app.stack-auth.com/wizard-congrats\");\n }\n}\n\nmain()\n .catch((err) => {\n if (!(err instanceof UserError)) {\n console.error(err);\n }\n console.error('\\n\\n\\n\\n');\n console.log(colorize.red`===============================================`);\n console.error();\n if (err instanceof UserError) {\n console.error(`${colorize.red`ERROR!`} ${err.message}`);\n } else {\n console.error(\"An error occurred during the initialization process.\");\n }\n console.error();\n console.log(colorize.red`===============================================`);\n console.error();\n console.error(\n \"If you need assistance, please try installing Stack manually as described in https://docs.stack-auth.com/getting-started/setup or join our Discord where we're happy to help: https://discord.stack-auth.com\"\n );\n if (!(err instanceof UserError)) {\n console.error(\"\");\n console.error(`Error message: ${err.message}`);\n }\n console.error();\n process.exit(1);\n });\n\n\ntype PackageJson = {\n dependencies?: Record<string, string>,\n devDependencies?: Record<string, string>,\n [key: string]: any,\n}\n\ntype ProjectInfo = {\n type: string,\n srcPath: string,\n appPath: string,\n defaultExtension: string,\n indentation: string,\n}\n\ntype NextProjectInfoError = {\n error: string,\n}\n\ntype NextProjectInfoResult = ProjectInfo | NextProjectInfoError;\n\ntype StackAppFileOptions = {\n type: string,\n srcPath: string,\n defaultExtension: string,\n indentation: string,\n}\n\ntype StackAppFileResult = {\n fileName: string,\n}\n\nconst Steps = {\n async getProject(): Promise<{ packageJson: PackageJson }> {\n let projectPath = await getProjectPath();\n if (!fs.existsSync(projectPath)) {\n throw new UserError(`The project path ${projectPath} does not exist`);\n }\n\n const packageJsonPath = path.join(projectPath, \"package.json\");\n if (!fs.existsSync(packageJsonPath)) {\n throw new UserError(\n `The package.json file does not exist in the project path ${projectPath}. You must initialize a new project first before installing Stack.`\n );\n }\n\n const packageJsonText = fs.readFileSync(packageJsonPath, \"utf-8\");\n let packageJson: PackageJson;\n try {\n packageJson = JSON.parse(packageJsonText);\n } catch (e) {\n throw new UserError(`package.json file is not valid JSON: ${e}`);\n }\n\n return { packageJson };\n },\n\n async getProjectType({ packageJson }: { packageJson: PackageJson }): Promise<string> {\n if (typeFromArgs) return typeFromArgs;\n\n const maybeNextProject = await Steps.maybeGetNextProjectInfo({ packageJson });\n if (!(\"error\" in maybeNextProject)) return \"next\";\n\n const { type } = await inquirer.prompt([\n {\n type: \"list\",\n name: \"type\",\n message: \"Which integration would you like to install?\",\n choices: [\n { name: \"None (vanilla JS, Node.js, etc)\", value: \"js\" },\n { name: \"Next.js\", value: \"next\" },\n ]\n }\n ]);\n\n return type;\n },\n\n async getStackPackageName(type: string, install = false): Promise<string> {\n return {\n \"js\": (install && process.env.STACK_JS_INSTALL_PACKAGE_NAME_OVERRIDE) || \"@stackframe/js\",\n \"next\": (install && process.env.STACK_NEXT_INSTALL_PACKAGE_NAME_OVERRIDE) || \"@stackframe/stack\",\n }[type] ?? throwErr(\"Unknown type in addStackPackage: \" + type);\n },\n\n async addStackPackage(type: string): Promise<void> {\n packagesToInstall.push(await Steps.getStackPackageName(type, true));\n },\n\n async getNextProjectInfo({ packageJson }: { packageJson: PackageJson }): Promise<ProjectInfo> {\n const maybe = await Steps.maybeGetNextProjectInfo({ packageJson });\n if (\"error\" in maybe) throw new UserError(maybe.error);\n return maybe;\n },\n\n async maybeGetNextProjectInfo({ packageJson }: { packageJson: PackageJson }): Promise<NextProjectInfoResult> {\n const projectPath = await getProjectPath();\n\n const nextVersionInPackageJson = packageJson.dependencies?.[\"next\"] ?? packageJson.devDependencies?.[\"next\"];\n if (!nextVersionInPackageJson) {\n return { error: `The project at ${projectPath} does not appear to be a Next.js project, or does not have 'next' installed as a dependency.` };\n }\n if (\n !nextVersionInPackageJson.includes(\"14\") &&\n !nextVersionInPackageJson.includes(\"15\") &&\n nextVersionInPackageJson !== \"latest\"\n ) {\n return { error: `The project at ${projectPath} is using an unsupported version of Next.js (found ${nextVersionInPackageJson}).\\n\\nOnly Next.js 14 & 15 projects are currently supported. See Next's upgrade guide: https://nextjs.org/docs/app/building-your-application/upgrading/version-14` };\n }\n\n const nextConfigPathWithoutExtension = path.join(projectPath, \"next.config\");\n const nextConfigFileExtension = await findJsExtension(\n nextConfigPathWithoutExtension\n );\n const nextConfigPath =\n nextConfigPathWithoutExtension + \".\" + (nextConfigFileExtension ?? \"js\");\n if (!fs.existsSync(nextConfigPath)) {\n return { error: `Expected file at ${nextConfigPath}. Only Next.js projects are currently supported.` };\n }\n\n const hasSrcAppFolder = fs.existsSync(path.join(projectPath, \"src/app\"));\n const srcPath = path.join(projectPath, hasSrcAppFolder ? \"src\" : \"\");\n const appPath = path.join(srcPath, \"app\");\n if (!fs.existsSync(appPath)) {\n return { error: `The app path ${appPath} does not exist. Only the Next.js app router is supported.` };\n }\n\n const dryUpdateNextLayoutFileResult = await Steps.dryUpdateNextLayoutFile({ appPath, defaultExtension: \"jsx\" });\n\n return {\n type: \"next\",\n srcPath,\n appPath,\n defaultExtension: dryUpdateNextLayoutFileResult.fileExtension,\n indentation: dryUpdateNextLayoutFileResult.indentation,\n };\n },\n\n async writeEnvVars(type: string): Promise<boolean> {\n const projectPath = await getProjectPath();\n\n // TODO: in non-Next environments, ask the user what method they prefer for envvars\n if (type !== \"next\") return false;\n\n const envLocalPath = path.join(projectPath, \".env.local\");\n\n const potentialEnvLocations = [\n path.join(projectPath, \".env\"),\n path.join(projectPath, \".env.development\"),\n path.join(projectPath, \".env.default\"),\n path.join(projectPath, \".env.defaults\"),\n path.join(projectPath, \".env.example\"),\n envLocalPath,\n ];\n if (potentialEnvLocations.every((p) => !fs.existsSync(p))) {\n laterWriteFile(\n envLocalPath,\n \"# Stack Auth keys\\n# Get these variables by creating a project on https://app.stack-auth.com.\\nNEXT_PUBLIC_STACK_PROJECT_ID=\\nNEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=\\nSTACK_SECRET_SERVER_KEY=\\n\"\n );\n return true;\n }\n\n return false;\n },\n\n async dryUpdateNextLayoutFile({ appPath, defaultExtension }: { appPath: string, defaultExtension: string }): Promise<{\n path: string,\n updatedContent: string,\n fileExtension: string,\n indentation: string,\n }> {\n const layoutPathWithoutExtension = path.join(appPath, \"layout\");\n const layoutFileExtension =\n (await findJsExtension(layoutPathWithoutExtension)) ?? defaultExtension;\n const layoutPath = layoutPathWithoutExtension + \".\" + layoutFileExtension;\n const layoutContent =\n (await readFile(layoutPath)) ??\n throwErr(\n `The layout file at ${layoutPath} does not exist. Stack requires a layout file to be present in the /app folder.`\n );\n const updatedLayoutResult =\n (await getUpdatedLayout(layoutContent)) ??\n throwErr(\n \"Unable to parse root layout file. Make sure it contains a <body> tag. If it still doesn't work, you may need to manually install Stack. See: https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required\"\n );\n const updatedLayoutContent = updatedLayoutResult.content;\n return {\n path: layoutPath,\n updatedContent: updatedLayoutContent,\n fileExtension: layoutFileExtension,\n indentation: updatedLayoutResult.indentation\n };\n },\n\n async updateNextLayoutFile(projectInfo: ProjectInfo): Promise<{\n path: string,\n updatedContent: string,\n fileExtension: string,\n indentation: string,\n }> {\n const res = await Steps.dryUpdateNextLayoutFile(projectInfo);\n laterWriteFile(res.path, res.updatedContent);\n return res;\n },\n\n async writeStackAppFile({ type, srcPath, defaultExtension, indentation }: StackAppFileOptions, clientOrServer: string): Promise<StackAppFileResult> {\n const packageName = await Steps.getStackPackageName(type);\n\n const clientOrServerCap = {\n client: \"Client\",\n server: \"Server\",\n }[clientOrServer] ?? throwErr(\"unknown clientOrServer \" + clientOrServer);\n\n const relativeStackAppPath = {\n js: `stack/${clientOrServer}`,\n next: \"stack\",\n }[type] ?? throwErr(\"unknown type\");\n\n const stackAppPathWithoutExtension = path.join(srcPath, relativeStackAppPath);\n const stackAppFileExtension =\n (await findJsExtension(stackAppPathWithoutExtension)) ?? defaultExtension;\n const stackAppPath =\n stackAppPathWithoutExtension + \".\" + stackAppFileExtension;\n const stackAppContent = await readFile(stackAppPath);\n if (stackAppContent) {\n if (!stackAppContent.includes(\"@stackframe/\")) {\n throw new UserError(\n `A file at the path ${stackAppPath} already exists. Stack uses the stack.ts file to initialize the Stack SDK. Please remove the existing file and try again.`\n );\n }\n throw new UserError(\n `It seems that you already installed Stack in this project.`\n );\n }\n laterWriteFileIfNotExists(\n stackAppPath,\n `\n${type === \"next\" ? `import \"server-only\";` : \"\"}\n\nimport { Stack${clientOrServerCap}App } from ${JSON.stringify(packageName)};\n\nexport const stack${clientOrServerCap}App = new Stack${clientOrServerCap}App({\n${indentation}tokenStore: ${type === \"next\" ? '\"nextjs-cookie\"' : (clientOrServer === \"client\" ? '\"cookie\"' : '\"memory\"')},${\ntype === \"js\" ? `\\n\\n${indentation}// get your Stack Auth API keys from https://app.stack-auth.com${clientOrServer === \"client\" ? ` and store them in a safe place (eg. environment variables)` : \"\"}` : \"\"}${\ntype === \"js\" ? `\\n${indentation}publishableClientKey: ${clientOrServer === \"server\" ? 'process.env.STACK_PUBLISHABLE_CLIENT_KEY' : 'INSERT_YOUR_PUBLISHABLE_CLIENT_KEY_HERE'},` : \"\"}${\ntype === \"js\" && clientOrServer === \"server\" ? `\\n${indentation}secretServerKey: process.env.STACK_SECRET_SERVER_KEY,` : \"\"}\n});\n `.trim() + \"\\n\"\n );\n return { fileName: stackAppPath };\n },\n\n async writeNextHandlerFile(projectInfo: ProjectInfo): Promise<void> {\n const handlerPathWithoutExtension = path.join(\n projectInfo.appPath,\n \"handler/[...stack]/page\"\n );\n const handlerFileExtension =\n (await findJsExtension(handlerPathWithoutExtension)) ?? projectInfo.defaultExtension;\n const handlerPath = handlerPathWithoutExtension + \".\" + handlerFileExtension;\n const handlerContent = await readFile(handlerPath);\n if (handlerContent && !handlerContent.includes(\"@stackframe/\")) {\n throw new UserError(\n `A file at the path ${handlerPath} already exists. Stack uses the /handler path to handle incoming requests. Please remove the existing file and try again.`\n );\n }\n laterWriteFileIfNotExists(\n handlerPath,\n `import { StackHandler } from \"@stackframe/stack\";\\nimport { stackServerApp } from \"../../../stack\";\\n\\nexport default function Handler(props${\n handlerFileExtension.includes(\"ts\") ? \": unknown\" : \"\"\n }) {\\n${projectInfo.indentation}return <StackHandler fullPage app={stackServerApp} routeProps={props} />;\\n}\\n`\n );\n },\n\n async writeNextLoadingFile(projectInfo: ProjectInfo): Promise<void> {\n let loadingPathWithoutExtension = path.join(projectInfo.appPath, \"loading\");\n const loadingFileExtension =\n (await findJsExtension(loadingPathWithoutExtension)) ?? projectInfo.defaultExtension;\n const loadingPath = loadingPathWithoutExtension + \".\" + loadingFileExtension;\n laterWriteFileIfNotExists(\n loadingPath,\n `export default function Loading() {\\n${projectInfo.indentation}// Stack uses React Suspense, which will render this page while user data is being fetched.\\n${projectInfo.indentation}// See: https://nextjs.org/docs/app/api-reference/file-conventions/loading\\n${projectInfo.indentation}return <></>;\\n}\\n`\n );\n },\n\n async getPackageManager(): Promise<{ packageManager: string }> {\n if (packageManagerFromArgs) return { packageManager: packageManagerFromArgs };\n const packageManager = await promptPackageManager();\n const versionCommand = `${packageManager} --version`;\n\n try {\n await shellNicelyFormatted(versionCommand, { shell: true, quiet: true });\n } catch (err) {\n console.error(err);\n throw new UserError(\n `Could not run the package manager command '${versionCommand}'. Please make sure ${packageManager} is installed on your system.`\n );\n }\n\n return { packageManager };\n },\n\n async ensureReady(type: string): Promise<void> {\n const projectPath = await getProjectPath();\n\n const typeString = {\n js: \"JavaScript\",\n next: \"Next.js\"\n }[type] ?? throwErr(\"unknown type\");\n const isReady = !!process.env.STACK_DISABLE_INTERACTIVE || (await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"ready\",\n message: `Found a ${typeString} project at ${projectPath} — ready to install Stack Auth?`,\n default: true,\n },\n ])).ready;\n if (!isReady) {\n throw new UserError(\"Installation aborted.\");\n }\n },\n\n async getServerOrClientOrBoth(): Promise<string[]> {\n if (isClient && isServer) return [\"server\", \"client\"];\n if (isServer) return [\"server\"];\n if (isClient) return [\"client\"];\n\n return (await inquirer.prompt([{\n type: \"list\",\n name: \"type\",\n message: \"Do you want to use Stack Auth on the server, or on the client?\",\n choices: [\n { name: \"Client (eg. Vite, HTML)\", value: [\"client\"] },\n { name: \"Server (eg. Node.js)\", value: [\"server\"] },\n { name: \"Both\", value: [\"server\", \"client\"] }\n ]\n }])).type;\n },\n\n /**\n * note: this is a heuristic, specific frameworks may have better heuristics (eg. the Next.js code uses the extension of the global layout file)\n */\n async guessDefaultFileExtension(): Promise<string> {\n const projectPath = await getProjectPath();\n const hasTsConfig = fs.existsSync(\n path.join(projectPath, \"tsconfig.json\")\n );\n return hasTsConfig ? \"ts\" : \"js\";\n },\n\n /**\n * note: this is a heuristic, specific frameworks may have better heuristics (eg. the Next.js code uses the location of the app folder)\n */\n async guessSrcPath(): Promise<string> {\n const projectPath = await getProjectPath();\n const potentialSrcPath = path.join(projectPath, \"src\");\n const hasSrcFolder = fs.existsSync(\n path.join(projectPath, \"src\")\n );\n return hasSrcFolder ? potentialSrcPath : projectPath;\n },\n\n\n};\n\n\ntype LayoutResult = {\n content: string,\n indentation: string,\n}\n\nasync function getUpdatedLayout(originalLayout: string): Promise<LayoutResult | undefined> {\n let layout = originalLayout;\n const indentation = guessIndentation(originalLayout);\n\n const firstImportLocationM1 = /\\simport\\s/.exec(layout)?.index;\n const hasStringAsFirstLine = layout.startsWith('\"') || layout.startsWith(\"'\");\n const importInsertLocationM1 =\n firstImportLocationM1 ?? (hasStringAsFirstLine ? layout.indexOf(\"\\n\") : -1);\n const importInsertLocation = importInsertLocationM1 + 1;\n const importStatement = `import { StackProvider, StackTheme } from \"@stackframe/stack\";\\nimport { stackServerApp } from \"../stack\";\\n`;\n layout =\n layout.slice(0, importInsertLocation) +\n importStatement +\n layout.slice(importInsertLocation);\n\n const bodyOpenTag = /<\\s*body[^>]*>/.exec(layout);\n const bodyCloseTag = /<\\s*\\/\\s*body[^>]*>/.exec(layout);\n if (!bodyOpenTag || !bodyCloseTag) {\n return undefined;\n }\n const bodyOpenEndIndex = bodyOpenTag.index + bodyOpenTag[0].length;\n const bodyCloseStartIndex = bodyCloseTag.index;\n if (bodyCloseStartIndex <= bodyOpenEndIndex) {\n return undefined;\n }\n\n const lines = layout.split(\"\\n\");\n const [bodyOpenEndLine, bodyOpenEndIndexInLine] = getLineIndex(\n lines,\n bodyOpenEndIndex\n );\n const [bodyCloseStartLine, bodyCloseStartIndexInLine] = getLineIndex(\n lines,\n bodyCloseStartIndex\n );\n\n const insertOpen = \"<StackProvider app={stackServerApp}><StackTheme>\";\n const insertClose = \"</StackTheme></StackProvider>\";\n\n layout =\n layout.slice(0, bodyCloseStartIndex) +\n insertClose +\n layout.slice(bodyCloseStartIndex);\n layout =\n layout.slice(0, bodyOpenEndIndex) +\n insertOpen +\n layout.slice(bodyOpenEndIndex);\n\n return {\n content: `${layout}`,\n indentation,\n };\n}\n\nfunction guessIndentation(str: string): string {\n const lines = str.split(\"\\n\");\n const linesLeadingWhitespaces = lines\n .map((line) => line.match(/^\\s*/)![0])\n .filter((ws) => ws.length > 0);\n const isMostlyTabs =\n linesLeadingWhitespaces.filter((ws) => ws.includes(\"\\t\")).length >=\n (linesLeadingWhitespaces.length * 2) / 3;\n if (isMostlyTabs) return \"\\t\";\n const linesLeadingWhitespacesCount = linesLeadingWhitespaces.map(\n (ws) => ws.length\n );\n const min = Math.min(Infinity, ...linesLeadingWhitespacesCount);\n return Number.isFinite(min) ? \" \".repeat(Math.max(2, min)) : \" \";\n}\n\nfunction getLineIndex(lines: string[], stringIndex: number): [number, number] {\n let lineIndex = 0;\n for (let l = 0; l < lines.length; l++) {\n const line = lines[l];\n if (stringIndex < lineIndex + line.length) {\n return [l, stringIndex - lineIndex];\n }\n lineIndex += line.length + 1;\n }\n throw new Error(\n `Index ${stringIndex} is out of bounds for lines ${JSON.stringify(lines)}`\n );\n}\n\nasync function getProjectPath(): Promise<string> {\n if (savedProjectPath === undefined) {\n savedProjectPath = process.cwd();\n\n const askForPathModification = !fs.existsSync(\n path.join(savedProjectPath, \"package.json\")\n );\n if (askForPathModification) {\n savedProjectPath = (\n await inquirer.prompt([\n {\n type: \"input\",\n name: \"newPath\",\n message: \"Please enter the path to your project:\",\n default: \".\",\n },\n ])\n ).newPath;\n }\n }\n return savedProjectPath as string;\n}\n\nasync function findJsExtension(fullPathWithoutExtension: string): Promise<string | null> {\n for (const ext of jsLikeFileExtensions) {\n const fullPath = fullPathWithoutExtension + \".\" + ext;\n if (fs.existsSync(fullPath)) {\n return ext;\n }\n }\n return null;\n}\n\nasync function promptPackageManager(): Promise<string> {\n const projectPath = await getProjectPath();\n const yarnLock = fs.existsSync(path.join(projectPath, \"yarn.lock\"));\n const pnpmLock = fs.existsSync(path.join(projectPath, \"pnpm-lock.yaml\"));\n const npmLock = fs.existsSync(path.join(projectPath, \"package-lock.json\"));\n const bunLock = fs.existsSync(path.join(projectPath, \"bun.lockb\"));\n\n if (yarnLock && !pnpmLock && !npmLock && !bunLock) {\n return \"yarn\";\n } else if (!yarnLock && pnpmLock && !npmLock && !bunLock) {\n return \"pnpm\";\n } else if (!yarnLock && !pnpmLock && npmLock && !bunLock) {\n return \"npm\";\n } else if (!yarnLock && !pnpmLock && !npmLock && bunLock) {\n return \"bun\";\n }\n\n const answers = await inquirer.prompt([\n {\n type: \"list\",\n name: \"packageManager\",\n message: \"Which package manager are you using for this project?\",\n choices: [\"npm\", \"yarn\", \"pnpm\", \"bun\"],\n },\n ]);\n return answers.packageManager;\n}\n\ntype ShellOptions = {\n quiet?: boolean,\n shell?: boolean,\n cwd?: string,\n [key: string]: any,\n}\n\nasync function shellNicelyFormatted(command: string, { quiet, ...options }: ShellOptions): Promise<void> {\n let ui: any;\n let interval: NodeJS.Timeout | undefined;\n if (!quiet) {\n console.log();\n ui = new inquirer.ui.BottomBar();\n let dots = 4;\n ui.updateBottomBar(\n colorize.blue`Running command: ${command}...`\n );\n interval = setInterval(() => {\n if (!isDryRun) {\n ui.updateBottomBar(\n colorize.blue`Running command: ${command}${\".\".repeat(dots++ % 5)}`\n );\n }\n }, 700);\n }\n\n try {\n if (!isDryRun) {\n const child = child_process.spawn(command, options);\n if (!quiet) {\n child.stdout.pipe(ui.log);\n child.stderr.pipe(ui.log);\n }\n\n await new Promise<void>((resolve, reject) => {\n child.on(\"exit\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Command ${command} failed with code ${code}`));\n }\n });\n });\n } else {\n console.log(`[DRY-RUN] Would have run: ${command}`);\n }\n\n if (!quiet) {\n commandsExecuted.push(command);\n ui.updateBottomBar(\n `${colorize.green`√`} Command ${command} succeeded\\n`\n );\n }\n } catch (e) {\n if (!quiet) {\n ui.updateBottomBar(\n `${colorize.red`X`} Command ${command} failed\\n`\n );\n }\n throw e;\n } finally {\n if (interval) {\n clearTimeout(interval);\n }\n if (!quiet) {\n ui.close();\n }\n }\n}\n\nasync function readFile(fullPath: string): Promise<string | null> {\n try {\n if (!isDryRun) {\n return fs.readFileSync(fullPath, \"utf-8\");\n }\n return null;\n } catch (err: any) {\n if (err.code === \"ENOENT\") {\n return null;\n }\n throw err;\n }\n}\n\nasync function writeFile(fullPath: string, content: string): Promise<void> {\n let create = !fs.existsSync(fullPath);\n if (!isDryRun) {\n fs.mkdirSync(path.dirname(fullPath), { recursive: true });\n fs.writeFileSync(fullPath, content);\n } else {\n console.log(`[DRY-RUN] Would have written to ${fullPath}`);\n }\n const relativeToProjectPath = path.relative(await getProjectPath(), fullPath);\n if (!create) {\n filesModified.push(relativeToProjectPath);\n } else {\n filesCreated.push(relativeToProjectPath);\n }\n}\n\nfunction laterWriteFile(fullPath: string, content: string): void {\n writeFileHandlers.push(async () => {\n await writeFile(fullPath, content);\n });\n}\n\nasync function writeFileIfNotExists(fullPath: string, content: string): Promise<void> {\n if (!fs.existsSync(fullPath)) {\n await writeFile(fullPath, content);\n }\n}\n\nfunction laterWriteFileIfNotExists(fullPath: string, content: string): void {\n writeFileHandlers.push(async () => {\n await writeFileIfNotExists(fullPath, content);\n });\n}\n\nfunction assertInteractive(): true {\n if (process.env.STACK_DISABLE_INTERACTIVE) {\n throw new UserError(\"STACK_DISABLE_INTERACTIVE is set, but wizard requires interactivity to complete. Make sure you supplied all required command line arguments!\");\n }\n return true;\n}\n\nfunction throwErr(message: string): never {\n throw new Error(message);\n}\n\n// TODO import this function from stack-shared instead (but that would require us to fix the build to let us import it)\nexport function templateIdentity(strings: TemplateStringsArray, ...values: any[]): string {\n if (strings.length === 0) return \"\";\n if (values.length !== strings.length - 1) throw new Error(\"Invalid number of values; must be one less than strings\");\n\n return strings.slice(1).reduce((result, string, i) => `${result}${values[i] ?? \"n/a\"}${string}`, strings[0]);\n}\n\nasync function clearStdin(): Promise<void> {\n await new Promise<void>((resolve) => {\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n process.stdin.resume();\n process.stdin.removeAllListeners('data');\n\n const flush = () => {\n while (process.stdin.read() !== null) {}\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n }\n resolve();\n };\n\n // Add a small delay to allow any buffered input to clear\n setTimeout(flush, 10);\n });\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@stackframe/init-stack",
3
- "version": "2.7.17",
3
+ "version": "2.7.19",
4
4
  "description": "The setup wizard for Stack. https://stack-auth.com",
5
- "main": "index.mjs",
5
+ "main": "dist/index.js",
6
6
  "type": "module",
7
- "bin": "./index.mjs",
7
+ "bin": "./dist/index.js",
8
8
  "files": [
9
9
  "README.md",
10
- "index.mjs",
10
+ "dist",
11
11
  "CHANGELOG.md",
12
12
  "LICENSE"
13
13
  ],
@@ -18,14 +18,25 @@
18
18
  "dependencies": {
19
19
  "inquirer": "^9.2.19",
20
20
  "open": "^10.1.0",
21
- "@stackframe/stack-shared": "2.7.17"
21
+ "@stackframe/stack-shared": "2.7.19"
22
+ },
23
+ "devDependencies": {
24
+ "@types/inquirer": "^9.0.7",
25
+ "@types/node": "^22.13.5",
26
+ "rimraf": "^6.0.1",
27
+ "tsup": "^8.4.0",
28
+ "typescript": "^5.7.3"
22
29
  },
23
30
  "scripts": {
24
- "clean": "rimraf test-run-output && rimraf node_modules",
25
- "init-stack": "node init-stack/index.mjs",
26
- "init-stack:local": "STACK_NEXT_INSTALL_PACKAGE_NAME_OVERRIDE=../../stack STACK_JS_INSTALL_PACKAGE_NAME_OVERRIDE=../../js node index.mjs",
27
- "test-run": "pnpm run test-run-js && pnpm run test-run-node && pnpm run test-run-next && pnpm run test-run-neon",
28
- "test-run:manual": "pnpm run test-run-js:manual && pnpm run test-run-node:manual && pnpm run test-run-next:manual && pnpm run test-run-neon:manual",
31
+ "clean": "rimraf test-run-output && rimraf node_modules && rimraf dist",
32
+ "build": "tsup",
33
+ "dev": "tsup --watch",
34
+ "lint": "eslint --ext .tsx,.ts .",
35
+ "typecheck": "tsc --noEmit",
36
+ "init-stack": "node dist/index.js",
37
+ "init-stack:local": "STACK_NEXT_INSTALL_PACKAGE_NAME_OVERRIDE=../../stack STACK_JS_INSTALL_PACKAGE_NAME_OVERRIDE=../../js node dist/index.js",
38
+ "test-run": "pnpm run build && pnpm run test-run-js && pnpm run test-run-node && pnpm run test-run-next && pnpm run test-run-neon",
39
+ "test-run:manual": "pnpm run build && pnpm run test-run-js:manual && pnpm run test-run-node:manual && pnpm run test-run-next:manual && pnpm run test-run-neon:manual",
29
40
  "ensure-neon": "grep -q '\"@neondatabase/serverless\"' ./test-run-output/package.json && echo 'Initialized Neon successfully!'",
30
41
  "test-run-neon": "pnpm run test-run-node --neon && pnpm run ensure-neon",
31
42
  "test-run-neon:manual": "pnpm run test-run-node:manual --neon && pnpm run ensure-neon",