@stackframe/init-stack 2.7.18 → 2.7.20
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 +14 -0
- package/dist/index.d.ts +3 -0
- package/{index.mjs → dist/index.js} +183 -307
- package/dist/index.js.map +1 -0
- package/package.json +21 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @stackframe/init-stack
|
|
2
2
|
|
|
3
|
+
## 2.7.20
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @stackframe/stack-shared@2.7.20
|
|
9
|
+
|
|
10
|
+
## 2.7.19
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Various changes
|
|
15
|
+
- @stackframe/stack-shared@2.7.19
|
|
16
|
+
|
|
3
17
|
## 2.7.18
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
console.error();
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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":
|
|
275
|
-
"next":
|
|
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
|
-
|
|
298
|
-
|
|
299
|
-
|
|
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
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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
|
-
|
|
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"' :
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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
|
-
`import { StackHandler } from "@stackframe/stack"
|
|
453
|
-
|
|
454
|
-
|
|
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() {
|
|
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}
|
|
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"
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
608
|
-
|
|
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 ===
|
|
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
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
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
|
|
697
|
-
|
|
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
|
|
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
|
|
630
|
+
`${colorize.red`X`} Command ${command} failed
|
|
631
|
+
`
|
|
744
632
|
);
|
|
745
633
|
}
|
|
746
634
|
throw e;
|
|
747
635
|
} finally {
|
|
748
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
706
|
+
process.stdin.setRawMode(false);
|
|
825
707
|
}
|
|
826
|
-
|
|
827
|
-
|
|
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.
|
|
3
|
+
"version": "2.7.20",
|
|
4
4
|
"description": "The setup wizard for Stack. https://stack-auth.com",
|
|
5
|
-
"main": "index.
|
|
5
|
+
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"bin": "./index.
|
|
7
|
+
"bin": "./dist/index.js",
|
|
8
8
|
"files": [
|
|
9
9
|
"README.md",
|
|
10
|
-
"
|
|
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.
|
|
21
|
+
"@stackframe/stack-shared": "2.7.20"
|
|
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
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
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",
|