@percepta/create 4.1.15 → 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.
Files changed (38) hide show
  1. package/dist/index.js +24 -152
  2. package/dist/index.js.map +1 -1
  3. package/dist/{register-app-BeSQEsel.js → register-app-BtvxQeo0.js} +91 -1
  4. package/dist/register-app-BtvxQeo0.js.map +1 -0
  5. package/package.json +5 -2
  6. package/template-versions.json +2 -2
  7. package/templates/monorepo/README.md +28 -1
  8. package/templates/monorepo/auth/package.json +1 -1
  9. package/templates/monorepo/auth/src/auth.ts +7 -103
  10. package/templates/monorepo/authentik/blueprints/local-dev.yaml +123 -0
  11. package/templates/monorepo/authentik/initdb/00-authentik.sql +5 -0
  12. package/templates/monorepo/docker-compose.yml +70 -0
  13. package/templates/monorepo/oxlint.config.ts.template +5 -1
  14. package/templates/monorepo/package.json.template +2 -1
  15. package/templates/webapp/.github/workflows/__APP_NAME__-ryvn-release.yaml +22 -89
  16. package/templates/webapp/AGENTS.md +4 -4
  17. package/templates/webapp/README.md +22 -33
  18. package/templates/webapp/agent-skills/langfuse.md +8 -11
  19. package/templates/webapp/agent-skills/oneshot.md +1 -1
  20. package/templates/webapp/e2e/rbac.spec.ts +28 -4
  21. package/templates/webapp/env.example.template +8 -12
  22. package/templates/webapp/package.json.template +4 -5
  23. package/templates/webapp/scripts/seed.ts +28 -52
  24. package/templates/webapp/scripts/with-local-env.ts +12 -64
  25. package/templates/webapp/src/app/(auth)/auth/signin/SignInForm.tsx +59 -0
  26. package/templates/webapp/src/app/(auth)/auth/signin/page.tsx +3 -3
  27. package/templates/webapp/src/drizzle/db.ts +5 -9
  28. package/templates/webapp/src/instrumentation.ts +5 -72
  29. package/templates/webapp/src/lib/auth/index.ts +1 -2
  30. package/templates/webapp/src/services/DatabaseService.ts +3 -51
  31. package/templates/webapp/src/services/observability/initFaro.ts +5 -17
  32. package/dist/register-app-BeSQEsel.js.map +0 -1
  33. package/templates/monorepo/scripts/setup-local-databases.mjs +0 -183
  34. package/templates/webapp/src/app/(auth)/auth/signin/CredentialsSignInForm.tsx +0 -179
  35. package/templates/webapp/src/app/(auth)/auth/signup/CredentialsSignUpForm.tsx +0 -135
  36. package/templates/webapp/src/app/(auth)/auth/signup/page.tsx +0 -53
  37. package/templates/webapp/src/drizzle/schema/utils/jsonbFromZod.ts +0 -25
  38. package/templates/webapp/src/lib/auth/app-auth-mode.ts +0 -20
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, authMode = "username-password") {
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, authMode, createdAt = (/* @__PURE__ */ new Date()).toISOString() }) {
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, config.authMode),
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, authMode = "username-password") {
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, authMode, installSucceeded) {
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, selectedAuthMode);
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, selectedAuthMode);
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, answers.authMode, installSucceeded && checksSucceeded)) return;
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, answers.authMode, installSucceeded && checksSucceeded)) return;
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 (!answers.authMode) return;
1364
- switch (answers.authMode) {
1365
- case "username-password": return;
1366
- case "google":
1367
- console.log();
1368
- console.log(chalk.bold("Google auth setup:"));
1369
- console.log(chalk.dim(" Fill in"), chalk.cyan("GOOGLE_CLIENT_ID"), chalk.dim("and"), chalk.cyan("GOOGLE_CLIENT_SECRET"), chalk.dim("in each app environment before OAuth sign-in."));
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("--auth <mode>", "Workspace auth setup: username-password, google, or okta").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);
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("--auth <mode>", "App auth setup override: username-password, google, or okta").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) => {
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-BeSQEsel.js");
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 () => {