@percepta/create 4.1.16 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +24 -152
- package/dist/index.js.map +1 -1
- package/dist/{register-app-BeSQEsel.js → register-app-BtvxQeo0.js} +91 -1
- package/dist/register-app-BtvxQeo0.js.map +1 -0
- package/package.json +1 -1
- package/template-versions.json +2 -2
- package/templates/monorepo/README.md +28 -1
- package/templates/monorepo/auth/src/auth.ts +2 -4
- package/templates/monorepo/authentik/blueprints/local-dev.yaml +123 -0
- package/templates/monorepo/authentik/initdb/00-authentik.sql +5 -0
- package/templates/monorepo/docker-compose.yml +70 -0
- package/templates/webapp/AGENTS.md +3 -3
- package/templates/webapp/README.md +22 -33
- package/templates/webapp/agent-skills/oneshot.md +1 -1
- package/templates/webapp/e2e/rbac.spec.ts +28 -4
- package/templates/webapp/env.example.template +8 -12
- package/templates/webapp/scripts/seed.ts +14 -45
- package/templates/webapp/src/app/(auth)/auth/signin/SignInForm.tsx +59 -0
- package/templates/webapp/src/app/(auth)/auth/signin/page.tsx +3 -3
- package/templates/webapp/src/lib/auth/index.ts +1 -2
- package/dist/register-app-BeSQEsel.js.map +0 -1
- package/templates/webapp/src/app/(auth)/auth/signin/CredentialsSignInForm.tsx +0 -179
- package/templates/webapp/src/app/(auth)/auth/signup/CredentialsSignUpForm.tsx +0 -135
- package/templates/webapp/src/app/(auth)/auth/signup/page.tsx +0 -53
- package/templates/webapp/src/lib/auth/app-auth-mode.ts +0 -12
package/dist/index.js
CHANGED
|
@@ -171,7 +171,7 @@ async function writeManifest(dir, manifest) {
|
|
|
171
171
|
async function manifestExists(dir) {
|
|
172
172
|
return fs.pathExists(getManifestPath(dir));
|
|
173
173
|
}
|
|
174
|
-
function derivePlaceholders(appName, appTitle, repoName = appName, customerSlug = repoName, designTheme = DEFAULT_MOSAIC_DESIGN_THEME
|
|
174
|
+
function derivePlaceholders(appName, appTitle, repoName = appName, customerSlug = repoName, designTheme = DEFAULT_MOSAIC_DESIGN_THEME) {
|
|
175
175
|
const nameSnake = appName.replace(/-/g, "_");
|
|
176
176
|
const repoNameSnake = repoName.replace(/-/g, "_");
|
|
177
177
|
return {
|
|
@@ -183,8 +183,7 @@ function derivePlaceholders(appName, appTitle, repoName = appName, customerSlug
|
|
|
183
183
|
__REPO_NAME__: repoName,
|
|
184
184
|
__REPO_NAME_SNAKE__: repoNameSnake,
|
|
185
185
|
__CUSTOMER_SLUG__: customerSlug,
|
|
186
|
-
__MOSAIC_DESIGN_THEME__: designTheme
|
|
187
|
-
__AUTH_MODE__: authMode
|
|
186
|
+
__MOSAIC_DESIGN_THEME__: designTheme
|
|
188
187
|
};
|
|
189
188
|
}
|
|
190
189
|
function resolveMosaicRepoPath(options) {
|
|
@@ -226,14 +225,6 @@ const VALID_PROJECT_TYPES = [
|
|
|
226
225
|
"webapp",
|
|
227
226
|
"library"
|
|
228
227
|
];
|
|
229
|
-
const VALID_AUTH_MODES = [
|
|
230
|
-
"username-password",
|
|
231
|
-
"google",
|
|
232
|
-
"okta"
|
|
233
|
-
];
|
|
234
|
-
function isValidAuthMode(value) {
|
|
235
|
-
return typeof value === "string" && VALID_AUTH_MODES.includes(value);
|
|
236
|
-
}
|
|
237
228
|
function isValidProjectType(value) {
|
|
238
229
|
return typeof value === "string" && VALID_PROJECT_TYPES.includes(value);
|
|
239
230
|
}
|
|
@@ -289,68 +280,6 @@ async function resolveDesignTheme(projectType, defaults) {
|
|
|
289
280
|
if (defaults.projectType && defaults.name) return DEFAULT_MOSAIC_DESIGN_THEME;
|
|
290
281
|
return promptDesignTheme();
|
|
291
282
|
}
|
|
292
|
-
async function promptWorkspaceAuthMode() {
|
|
293
|
-
const { authMode } = await inquirer.prompt([{
|
|
294
|
-
type: "rawlist",
|
|
295
|
-
name: "authMode",
|
|
296
|
-
message: "Workspace auth setup?",
|
|
297
|
-
default: "username-password",
|
|
298
|
-
choices: [
|
|
299
|
-
{
|
|
300
|
-
name: "Username/password — local Better Auth credentials",
|
|
301
|
-
value: "username-password"
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
name: "Google — Google OAuth via Better Auth",
|
|
305
|
-
value: "google"
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
name: "Okta — Okta OIDC via Better Auth",
|
|
309
|
-
value: "okta"
|
|
310
|
-
}
|
|
311
|
-
]
|
|
312
|
-
}]);
|
|
313
|
-
return authMode;
|
|
314
|
-
}
|
|
315
|
-
async function promptAppAuthMode(defaultAuthMode) {
|
|
316
|
-
const overrideChoices = [
|
|
317
|
-
{
|
|
318
|
-
name: "Username/password — local Better Auth credentials",
|
|
319
|
-
value: "username-password"
|
|
320
|
-
},
|
|
321
|
-
{
|
|
322
|
-
name: "Google — Google OAuth via Better Auth",
|
|
323
|
-
value: "google"
|
|
324
|
-
},
|
|
325
|
-
{
|
|
326
|
-
name: "Okta — Okta OIDC via Better Auth",
|
|
327
|
-
value: "okta"
|
|
328
|
-
}
|
|
329
|
-
].filter((choice) => choice.value !== defaultAuthMode);
|
|
330
|
-
const { authMode } = await inquirer.prompt([{
|
|
331
|
-
type: "rawlist",
|
|
332
|
-
name: "authMode",
|
|
333
|
-
message: "App auth setup?",
|
|
334
|
-
default: defaultAuthMode,
|
|
335
|
-
choices: [{
|
|
336
|
-
name: "Use workspace default",
|
|
337
|
-
value: defaultAuthMode
|
|
338
|
-
}, ...overrideChoices]
|
|
339
|
-
}]);
|
|
340
|
-
return authMode;
|
|
341
|
-
}
|
|
342
|
-
async function resolveWorkspaceAuthMode(defaults) {
|
|
343
|
-
if (defaults.authMode) return defaults.authMode;
|
|
344
|
-
if (defaults.projectType && defaults.name) return "username-password";
|
|
345
|
-
return promptWorkspaceAuthMode();
|
|
346
|
-
}
|
|
347
|
-
async function resolvePackageAuthMode(projectType, defaults) {
|
|
348
|
-
if (projectType !== "webapp") return void 0;
|
|
349
|
-
if (defaults.authMode) return defaults.authMode;
|
|
350
|
-
const workspaceAuthMode = defaults.workspaceAuthMode ?? "username-password";
|
|
351
|
-
if (defaults.projectType && defaults.name) return workspaceAuthMode;
|
|
352
|
-
return promptAppAuthMode(workspaceAuthMode);
|
|
353
|
-
}
|
|
354
283
|
/**
|
|
355
284
|
* Outside a monorepo we collect monorepo-level settings first, then ask a
|
|
356
285
|
* single "is it a webapp?" Y/n. Yes (default) → monorepo + webapp, no → bare
|
|
@@ -401,7 +330,6 @@ async function promptProjectDetails(defaults) {
|
|
|
401
330
|
const customerSlug = await resolveCustomerSlug(defaults);
|
|
402
331
|
const repoName = defaults.repoName || (defaults.projectType === "monorepo" ? defaults.name : void 0) || await promptName("Repo name?", `${customerSlug}-os`);
|
|
403
332
|
const repoTitle = toTitleCase(repoName);
|
|
404
|
-
const authMode = await resolveWorkspaceAuthMode(defaults);
|
|
405
333
|
projectType = defaults.projectType ?? await promptOutsideMonorepoType();
|
|
406
334
|
await defaults.beforeNamePrompt?.(projectType);
|
|
407
335
|
if (projectType === "monorepo") {
|
|
@@ -415,7 +343,6 @@ async function promptProjectDetails(defaults) {
|
|
|
415
343
|
title: finalTitle,
|
|
416
344
|
installDeps: !defaults.skipInstall,
|
|
417
345
|
customerSlug,
|
|
418
|
-
authMode,
|
|
419
346
|
monorepoName: repoName,
|
|
420
347
|
monorepoTitle: repoTitle
|
|
421
348
|
};
|
|
@@ -433,14 +360,12 @@ async function promptProjectDetails(defaults) {
|
|
|
433
360
|
installDeps: !defaults.skipInstall,
|
|
434
361
|
customerSlug,
|
|
435
362
|
designTheme,
|
|
436
|
-
authMode,
|
|
437
363
|
monorepoName: repoName,
|
|
438
364
|
monorepoTitle: repoTitle
|
|
439
365
|
};
|
|
440
366
|
}
|
|
441
367
|
const finalTitle = finalName ? toTitleCase(finalName) : "";
|
|
442
368
|
const designTheme = await resolveDesignTheme(projectType, defaults);
|
|
443
|
-
const authMode = await resolvePackageAuthMode(projectType, defaults);
|
|
444
369
|
const finalDirectory = !inMonorepo && finalName ? path.resolve(cwd, finalName) : "";
|
|
445
370
|
return {
|
|
446
371
|
projectType,
|
|
@@ -448,8 +373,7 @@ async function promptProjectDetails(defaults) {
|
|
|
448
373
|
name: finalName,
|
|
449
374
|
title: finalTitle,
|
|
450
375
|
installDeps: !defaults.skipInstall,
|
|
451
|
-
designTheme
|
|
452
|
-
authMode
|
|
376
|
+
designTheme
|
|
453
377
|
};
|
|
454
378
|
}
|
|
455
379
|
//#endregion
|
|
@@ -495,9 +419,7 @@ const PLACEHOLDERS = {
|
|
|
495
419
|
__CUSTOMER_SLUG__: "customerSlug",
|
|
496
420
|
__CREATE_PACKAGE__: "createPackage",
|
|
497
421
|
__CREATE_VERSION__: "createVersion",
|
|
498
|
-
__MOSAIC_DESIGN_THEME__: "designTheme"
|
|
499
|
-
__AUTH_MODE__: "authMode",
|
|
500
|
-
__AUTH_MODE_LABEL__: "authModeLabel"
|
|
422
|
+
__MOSAIC_DESIGN_THEME__: "designTheme"
|
|
501
423
|
};
|
|
502
424
|
const SKIP_DIRS = new Set([
|
|
503
425
|
"node_modules",
|
|
@@ -615,12 +537,11 @@ const WORKSPACE_MANIFEST_FILENAME = ".mosaic-workspace.json";
|
|
|
615
537
|
function getWorkspaceManifestPath(rootDir) {
|
|
616
538
|
return path.join(rootDir, WORKSPACE_MANIFEST_FILENAME);
|
|
617
539
|
}
|
|
618
|
-
function createWorkspaceManifest({ customerSlug,
|
|
540
|
+
function createWorkspaceManifest({ customerSlug, createdAt = (/* @__PURE__ */ new Date()).toISOString() }) {
|
|
619
541
|
const createPackage = readCreatePackageMetadata();
|
|
620
542
|
return {
|
|
621
543
|
schemaVersion: 1,
|
|
622
544
|
customerSlug,
|
|
623
|
-
authMode,
|
|
624
545
|
createPackage: createPackage.name,
|
|
625
546
|
createVersion: createPackage.version,
|
|
626
547
|
monorepoTemplateVersion: getTemplateVersion("monorepo"),
|
|
@@ -631,9 +552,6 @@ function createWorkspaceManifest({ customerSlug, authMode, createdAt = (/* @__PU
|
|
|
631
552
|
createdAt
|
|
632
553
|
};
|
|
633
554
|
}
|
|
634
|
-
function getWorkspaceAuthMode(manifest) {
|
|
635
|
-
return manifest?.authMode ?? "username-password";
|
|
636
|
-
}
|
|
637
555
|
async function readWorkspaceManifest(rootDir) {
|
|
638
556
|
const manifestPath = getWorkspaceManifestPath(rootDir);
|
|
639
557
|
if (!await fs.pathExists(manifestPath)) return null;
|
|
@@ -860,13 +778,13 @@ async function writeMosaicFiles(packageDir, config, projectType, templateVersion
|
|
|
860
778
|
templateVersion,
|
|
861
779
|
templateCommit,
|
|
862
780
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
863
|
-
placeholders: derivePlaceholders(config.name, config.title, config.repoName, config.customerSlug, config.designTheme
|
|
781
|
+
placeholders: derivePlaceholders(config.name, config.title, config.repoName, config.customerSlug, config.designTheme),
|
|
864
782
|
source: { templatePath: `packages/blueberry/templates/${projectType}` }
|
|
865
783
|
});
|
|
866
784
|
const notesPath = path.join(packageDir, "mosaic-template-notes.md");
|
|
867
785
|
await fs.writeFile(notesPath, `# Mosaic Divergence Notes\n\nDocument intentional differences from the ${projectType} template here.\nClaude reads this file during sync to preserve your customizations.\n\n## Intentional Divergences\n\n_None yet — freshly created from template._\n`);
|
|
868
786
|
}
|
|
869
|
-
function buildAppConfig(name, title = toTitleCase(name), repoName = name, customerSlug = repoName, designTheme = DEFAULT_MOSAIC_DESIGN_THEME
|
|
787
|
+
function buildAppConfig(name, title = toTitleCase(name), repoName = name, customerSlug = repoName, designTheme = DEFAULT_MOSAIC_DESIGN_THEME) {
|
|
870
788
|
const createPackage = readCreatePackageMetadata();
|
|
871
789
|
return {
|
|
872
790
|
name,
|
|
@@ -879,9 +797,7 @@ function buildAppConfig(name, title = toTitleCase(name), repoName = name, custom
|
|
|
879
797
|
customerSlug,
|
|
880
798
|
createPackage: createPackage.name,
|
|
881
799
|
createVersion: createPackage.version,
|
|
882
|
-
designTheme
|
|
883
|
-
authMode,
|
|
884
|
-
authModeLabel: getAuthModeLabel(authMode)
|
|
800
|
+
designTheme
|
|
885
801
|
};
|
|
886
802
|
}
|
|
887
803
|
/** Copy the monorepo template into `targetDir` and replace its placeholders. */
|
|
@@ -1026,9 +942,8 @@ async function runGeneratedProjectChecks(args) {
|
|
|
1026
942
|
* Gated on `installSucceeded` because starting setup without node_modules
|
|
1027
943
|
* leaves an orphan Docker container.
|
|
1028
944
|
*/
|
|
1029
|
-
async function maybeAutoRunWebapp(packageDir, monorepoRoot, projectType,
|
|
945
|
+
async function maybeAutoRunWebapp(packageDir, monorepoRoot, projectType, installSucceeded) {
|
|
1030
946
|
if (!packageDir || projectType !== "webapp" || !installSucceeded) return false;
|
|
1031
|
-
if (authMode !== "username-password") return false;
|
|
1032
947
|
return autoRunWebapp(packageDir, monorepoRoot);
|
|
1033
948
|
}
|
|
1034
949
|
function getProjectTypeLabel(projectType) {
|
|
@@ -1039,14 +954,6 @@ function getProjectTypeLabel(projectType) {
|
|
|
1039
954
|
default: throw new Error(`Unknown project type: ${String(projectType)}`);
|
|
1040
955
|
}
|
|
1041
956
|
}
|
|
1042
|
-
function getAuthModeLabel(authMode) {
|
|
1043
|
-
switch (authMode) {
|
|
1044
|
-
case "username-password": return "Username/password";
|
|
1045
|
-
case "google": return "Google OAuth";
|
|
1046
|
-
case "okta": return "Okta OIDC";
|
|
1047
|
-
default: throw new Error(`Unknown auth mode: ${String(authMode)}`);
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
957
|
function requireNpmTokenForWebappInstall(projectType, installDeps) {
|
|
1051
958
|
if (projectType !== "webapp" || !installDeps || process.env.NPM_TOKEN) return;
|
|
1052
959
|
console.log();
|
|
@@ -1089,10 +996,6 @@ async function createProject(options) {
|
|
|
1089
996
|
console.error(chalk.red(`Error: Invalid design theme "${options.theme}". Valid themes are: ${VALID_MOSAIC_DESIGN_THEMES.join(", ")}`));
|
|
1090
997
|
process.exit(1);
|
|
1091
998
|
}
|
|
1092
|
-
if (options.auth !== void 0 && !isValidAuthMode(options.auth)) {
|
|
1093
|
-
console.error(chalk.red(`Error: Invalid auth setup "${options.auth}". Valid auth setups are: ${VALID_AUTH_MODES.join(", ")}`));
|
|
1094
|
-
process.exit(1);
|
|
1095
|
-
}
|
|
1096
999
|
console.log();
|
|
1097
1000
|
console.log(chalk.bold("Creating a new Mosaic package..."));
|
|
1098
1001
|
console.log();
|
|
@@ -1109,10 +1012,8 @@ async function createProject(options) {
|
|
|
1109
1012
|
else console.log(chalk.dim(" No monorepo detected. A new monorepo will be created."));
|
|
1110
1013
|
console.log();
|
|
1111
1014
|
const workspaceManifest = monorepoContext.found ? await readWorkspaceManifest(monorepoContext.rootDir) : null;
|
|
1112
|
-
const workspaceAuthMode = getWorkspaceAuthMode(workspaceManifest);
|
|
1113
1015
|
if (workspaceManifest) {
|
|
1114
1016
|
console.log(chalk.dim(" Workspace create version:"), chalk.cyan(`${workspaceManifest.createPackage}@${workspaceManifest.createVersion}`));
|
|
1115
|
-
console.log(chalk.dim(" Workspace auth setup:"), chalk.cyan(getAuthModeLabel(workspaceAuthMode)));
|
|
1116
1017
|
console.log();
|
|
1117
1018
|
} else if (monorepoContext.found) {
|
|
1118
1019
|
console.log(chalk.yellow("!"), "No .mosaic-workspace.json found; using this CLI's bundled templates.");
|
|
@@ -1161,7 +1062,6 @@ async function createProject(options) {
|
|
|
1161
1062
|
installDeps: !options.skipInstall,
|
|
1162
1063
|
customerSlug: monorepoContext.found ? void 0 : customerSlug ?? kebabRepoName,
|
|
1163
1064
|
designTheme: projectType === "webapp" ? options.theme ?? "modern" : void 0,
|
|
1164
|
-
authMode: options.auth ?? (monorepoContext.found ? workspaceAuthMode : "username-password"),
|
|
1165
1065
|
monorepoName: monorepoContext.found ? void 0 : kebabRepoName,
|
|
1166
1066
|
monorepoTitle: monorepoContext.found ? void 0 : toTitleCase(kebabRepoName)
|
|
1167
1067
|
};
|
|
@@ -1171,8 +1071,6 @@ async function createProject(options) {
|
|
|
1171
1071
|
name: projectName ? toKebabCase(projectName) : void 0,
|
|
1172
1072
|
customerSlug,
|
|
1173
1073
|
designTheme: options.theme,
|
|
1174
|
-
authMode: options.auth,
|
|
1175
|
-
workspaceAuthMode: monorepoContext.found ? workspaceAuthMode : void 0,
|
|
1176
1074
|
repoName: repoName ? toKebabCase(repoName) : void 0,
|
|
1177
1075
|
skipInstall: options.skipInstall,
|
|
1178
1076
|
monorepoContext,
|
|
@@ -1184,15 +1082,13 @@ async function createProject(options) {
|
|
|
1184
1082
|
});
|
|
1185
1083
|
if (monorepoContext.found && monorepoContext.packageDir && !answers.directory) answers.directory = path.join(monorepoContext.packageDir, answers.name);
|
|
1186
1084
|
}
|
|
1187
|
-
const selectedAuthMode = answers.authMode ?? (monorepoContext.found ? workspaceAuthMode : "username-password");
|
|
1188
|
-
answers.authMode = selectedAuthMode;
|
|
1189
1085
|
const monorepoName = answers.monorepoName ?? answers.name;
|
|
1190
1086
|
const monorepoTitle = answers.monorepoTitle ?? toTitleCase(monorepoName);
|
|
1191
1087
|
const newWorkspaceCustomerSlug = answers.customerSlug ?? monorepoName;
|
|
1192
|
-
const monorepoConfig = buildAppConfig(monorepoName, monorepoTitle, monorepoName, newWorkspaceCustomerSlug, DEFAULT_MOSAIC_DESIGN_THEME
|
|
1088
|
+
const monorepoConfig = buildAppConfig(monorepoName, monorepoTitle, monorepoName, newWorkspaceCustomerSlug, DEFAULT_MOSAIC_DESIGN_THEME);
|
|
1193
1089
|
const configRepoName = monorepoContext.found ? path.basename(monorepoContext.rootDir) : monorepoName;
|
|
1194
1090
|
const effectiveCustomerSlug = monorepoContext.found ? workspaceManifest?.customerSlug ?? configRepoName : newWorkspaceCustomerSlug;
|
|
1195
|
-
const config = buildAppConfig(answers.name, answers.title, configRepoName, effectiveCustomerSlug, answers.designTheme
|
|
1091
|
+
const config = buildAppConfig(answers.name, answers.title, configRepoName, effectiveCustomerSlug, answers.designTheme);
|
|
1196
1092
|
const typeLabel = getProjectTypeLabel(answers.projectType);
|
|
1197
1093
|
if (monorepoContext.found) {
|
|
1198
1094
|
const monorepoRoot = monorepoContext.rootDir;
|
|
@@ -1204,8 +1100,6 @@ async function createProject(options) {
|
|
|
1204
1100
|
if (answers.projectType === "webapp") {
|
|
1205
1101
|
console.log(chalk.dim(" Database:"), config.dbName);
|
|
1206
1102
|
console.log(chalk.dim(" Design theme:"), config.designTheme);
|
|
1207
|
-
console.log(chalk.dim(" App auth setup:"), config.authModeLabel);
|
|
1208
|
-
if (selectedAuthMode !== workspaceAuthMode) console.log(chalk.dim(" Workspace auth default:"), getAuthModeLabel(workspaceAuthMode));
|
|
1209
1103
|
}
|
|
1210
1104
|
console.log();
|
|
1211
1105
|
if (await fs.pathExists(packageDir)) {
|
|
@@ -1234,7 +1128,7 @@ async function createProject(options) {
|
|
|
1234
1128
|
console.log();
|
|
1235
1129
|
console.log(chalk.green("✔"), chalk.bold(`Created ${typeLabel} at`), chalk.cyan(path.relative(monorepoRoot, packageDir)));
|
|
1236
1130
|
console.log();
|
|
1237
|
-
if (await maybeAutoRunWebapp(packageDir, monorepoRoot, answers.projectType,
|
|
1131
|
+
if (await maybeAutoRunWebapp(packageDir, monorepoRoot, answers.projectType, installSucceeded && checksSucceeded)) return;
|
|
1238
1132
|
printNextStepsExisting(answers, packageDir, !installSucceeded);
|
|
1239
1133
|
} else {
|
|
1240
1134
|
const isBareMonorepo = answers.projectType === "monorepo";
|
|
@@ -1246,13 +1140,11 @@ async function createProject(options) {
|
|
|
1246
1140
|
console.log(chalk.dim(" Customer:"), newWorkspaceCustomerSlug);
|
|
1247
1141
|
console.log(chalk.dim(" Repo name:"), monorepoConfig.name);
|
|
1248
1142
|
console.log(chalk.dim(" Title:"), monorepoConfig.title);
|
|
1249
|
-
console.log(chalk.dim(" Workspace auth setup:"), monorepoConfig.authModeLabel);
|
|
1250
1143
|
} else {
|
|
1251
1144
|
console.log(chalk.dim(" Package type:"), typeLabel);
|
|
1252
1145
|
console.log(chalk.dim(" Monorepo directory:"), monorepoRoot);
|
|
1253
1146
|
console.log(chalk.dim(" Customer:"), newWorkspaceCustomerSlug);
|
|
1254
1147
|
console.log(chalk.dim(" Repo name:"), monorepoConfig.name);
|
|
1255
|
-
console.log(chalk.dim(" Workspace auth setup:"), monorepoConfig.authModeLabel);
|
|
1256
1148
|
console.log(chalk.dim(" Package:"), `packages/${answers.name}/`);
|
|
1257
1149
|
console.log(chalk.dim(" Name:"), config.name);
|
|
1258
1150
|
console.log(chalk.dim(" Title:"), config.title);
|
|
@@ -1269,10 +1161,7 @@ async function createProject(options) {
|
|
|
1269
1161
|
}
|
|
1270
1162
|
}
|
|
1271
1163
|
await scaffoldMonorepo(monorepoRoot, monorepoConfig);
|
|
1272
|
-
const newWorkspaceManifest = createWorkspaceManifest({
|
|
1273
|
-
customerSlug: newWorkspaceCustomerSlug,
|
|
1274
|
-
authMode: selectedAuthMode
|
|
1275
|
-
});
|
|
1164
|
+
const newWorkspaceManifest = createWorkspaceManifest({ customerSlug: newWorkspaceCustomerSlug });
|
|
1276
1165
|
await writeWorkspaceManifest(monorepoRoot, newWorkspaceManifest);
|
|
1277
1166
|
if (packageDir && answers.projectType !== "monorepo") await addPackageToMonorepo({
|
|
1278
1167
|
packageDir,
|
|
@@ -1295,7 +1184,7 @@ async function createProject(options) {
|
|
|
1295
1184
|
console.log(chalk.green("✔"), chalk.bold(isBareMonorepo ? `Created ${typeLabel} at` : "Created monorepo at"), chalk.cyan(monorepoRoot));
|
|
1296
1185
|
if (!isBareMonorepo) console.log(chalk.green("✔"), chalk.bold(`Created ${typeLabel} at`), chalk.cyan(`packages/${answers.name}/`));
|
|
1297
1186
|
console.log();
|
|
1298
|
-
if (await maybeAutoRunWebapp(packageDir, monorepoRoot, answers.projectType,
|
|
1187
|
+
if (await maybeAutoRunWebapp(packageDir, monorepoRoot, answers.projectType, installSucceeded && checksSucceeded)) return;
|
|
1299
1188
|
printNextStepsNew(answers, monorepoRoot, !installSucceeded);
|
|
1300
1189
|
}
|
|
1301
1190
|
}
|
|
@@ -1360,30 +1249,13 @@ function printWebappNextSteps(params) {
|
|
|
1360
1249
|
console.log(chalk.dim(` ${step++}.`), devStep);
|
|
1361
1250
|
}
|
|
1362
1251
|
function printAuthSetupNotes(answers) {
|
|
1363
|
-
if (
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
console.log(chalk.dim(" Optional: set"), chalk.cyan("GOOGLE_HOSTED_DOMAIN"), chalk.dim("to hint/restrict the Google Workspace domain."));
|
|
1371
|
-
console.log(chalk.dim(" Register redirect URIs:"), chalk.cyan("http://localhost:3000/api/auth/callback/google"), chalk.dim("and"), chalk.cyan("https://<app-host>/api/auth/callback/google"));
|
|
1372
|
-
console.log(chalk.dim(" Provider users still need SpiceDB app access after sign-in; seed or grant access for their user."));
|
|
1373
|
-
return;
|
|
1374
|
-
case "okta":
|
|
1375
|
-
console.log();
|
|
1376
|
-
console.log(chalk.bold("Okta auth setup:"));
|
|
1377
|
-
console.log(chalk.dim(" Fill in"), chalk.cyan("OKTA_CLIENT_ID"), chalk.dim(","), chalk.cyan("OKTA_CLIENT_SECRET"), chalk.dim("and"), chalk.cyan("OKTA_ISSUER"), chalk.dim("in each app environment before OAuth sign-in."));
|
|
1378
|
-
console.log(chalk.dim(" Example issuer:"), chalk.cyan("https://dev-xxxxx.okta.com/oauth2/default"));
|
|
1379
|
-
console.log(chalk.dim(" Register redirect URIs:"), chalk.cyan("http://localhost:3000/api/auth/oauth2/callback/okta"), chalk.dim("and"), chalk.cyan("https://<app-host>/api/auth/oauth2/callback/okta"));
|
|
1380
|
-
console.log(chalk.dim(" Provider users still need SpiceDB app access after sign-in; seed or grant access for their user."));
|
|
1381
|
-
return;
|
|
1382
|
-
default: {
|
|
1383
|
-
const exhaustiveCheck = answers.authMode;
|
|
1384
|
-
throw new Error(`Unknown auth mode: ${String(exhaustiveCheck)}`);
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1252
|
+
if (answers.projectType !== "webapp") return;
|
|
1253
|
+
console.log();
|
|
1254
|
+
console.log(chalk.bold("Authentik SSO setup (deployed apps):"));
|
|
1255
|
+
console.log(chalk.dim(" Set"), chalk.cyan("AUTHENTIK_ISSUER"), chalk.dim(","), chalk.cyan("AUTHENTIK_CLIENT_ID"), chalk.dim("and"), chalk.cyan("AUTHENTIK_CLIENT_SECRET"), chalk.dim("for each deployed environment (required — there is no fallback)."));
|
|
1256
|
+
console.log(chalk.dim(" Example issuer:"), chalk.cyan("https://authentik.<domain>/application/o/<app-slug>"));
|
|
1257
|
+
console.log(chalk.dim(" Register redirect URI:"), chalk.cyan("https://<app-host>/api/auth/oauth2/callback/authentik"));
|
|
1258
|
+
console.log(chalk.dim(" Users still need SpiceDB app access after sign-in; seed or grant access for their user."));
|
|
1387
1259
|
}
|
|
1388
1260
|
async function warnIfMissingRootNpmrc(rootDir) {
|
|
1389
1261
|
const rootNpmrc = path.join(rootDir, ".npmrc");
|
|
@@ -1482,8 +1354,8 @@ function printNextStepsExisting(answers, packageDir, installNeeded) {
|
|
|
1482
1354
|
//#region src/index.ts
|
|
1483
1355
|
const packageJson = readCreatePackageMetadata();
|
|
1484
1356
|
program.name("create").description("Scaffold and manage Mosaic packages").version(packageJson.version);
|
|
1485
|
-
program.command("create", { isDefault: true }).description("Scaffold a new Mosaic package").option("-t, --type <type>", "Package type: monorepo, webapp, or library").option("--name <name>", "Package/app name").option("--customer <slug>", "Customer slug for the new monorepo").option("--theme <theme>", "Webapp design theme: modern, paper, or dense").option("--
|
|
1486
|
-
program.command("add").description("Add a Mosaic package to the current monorepo").argument("[typeOrName]", "Package type (webapp/library) or package name").argument("[name]", "Package/app name").option("-t, --type <type>", "Package type: webapp or library").option("--name <name>", "Package/app name").option("--theme <theme>", "Webapp design theme: modern, paper, or dense").option("--
|
|
1357
|
+
program.command("create", { isDefault: true }).description("Scaffold a new Mosaic package").option("-t, --type <type>", "Package type: monorepo, webapp, or library").option("--name <name>", "Package/app name").option("--customer <slug>", "Customer slug for the new monorepo").option("--theme <theme>", "Webapp design theme: modern, paper, or dense").option("--repo-name <name>", "Repository name when creating a new monorepo").option("--cwd <dir>", "Run create as if started from this directory").option("--skip-install", "Skip dependency installation (also skips the auto-run setup + dev + browser)", false).option("-y, --yes", "Skip all prompts and use defaults", false).action(createProject);
|
|
1358
|
+
program.command("add").description("Add a Mosaic package to the current monorepo").argument("[typeOrName]", "Package type (webapp/library) or package name").argument("[name]", "Package/app name").option("-t, --type <type>", "Package type: webapp or library").option("--name <name>", "Package/app name").option("--theme <theme>", "Webapp design theme: modern, paper, or dense").option("--skip-install", "Skip dependency installation (also skips the auto-run setup + dev + browser)", false).option("-y, --yes", "Skip all prompts and use defaults", false).action(async (typeOrName, name, options) => {
|
|
1487
1359
|
let projectType = options.type;
|
|
1488
1360
|
let projectName = options.name;
|
|
1489
1361
|
if (typeOrName === "webapp" || typeOrName === "library") {
|
|
@@ -1507,7 +1379,7 @@ infra.command("register-os-blueprint").description("Register this customer monor
|
|
|
1507
1379
|
await registerOsBlueprintCommand();
|
|
1508
1380
|
});
|
|
1509
1381
|
infra.command("register-app").description("Register a webapp database in this customer OS blueprint").argument("<app>", "Webapp package name").action(async (appName) => {
|
|
1510
|
-
const { registerAppCommand } = await import("./register-app-
|
|
1382
|
+
const { registerAppCommand } = await import("./register-app-BtvxQeo0.js");
|
|
1511
1383
|
await registerAppCommand(appName);
|
|
1512
1384
|
});
|
|
1513
1385
|
program.command("status").description("Show template sync status for current app").action(async () => {
|