@getstrata/starter 0.1.12 → 1.0.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # create-strata
2
2
 
3
- Interactive starter for [Strata](https://github.com/EyK-26/strata). The wizard always asks each layer. Extras (MFA, email verification, SCIM, metrics) are toggled one by one. SQLite APIs and Postgres HTML apps use the same generator.
3
+ Interactive starter for [Strata](https://github.com/EyK-26/strata). The wizard always asks each layer. In a terminal, lists use ↑/↓ and Enter (or a number). Extras (MFA, email verification, SCIM, metrics) are toggled one by one. SQLite APIs and Postgres HTML apps use the same generator.
4
4
 
5
5
  ## Usage
6
6
 
package/dist/cli.js CHANGED
@@ -508,10 +508,36 @@ function layersFromFlags(flags) {
508
508
  }
509
509
 
510
510
  // src/prompt.ts
511
- import { stdin as input, stdout as output } from "process";
512
511
  import { createInterface } from "readline/promises";
512
+ import tty2 from "tty";
513
513
 
514
514
  // src/selectPrompt.ts
515
+ import tty from "tty";
516
+ function hasRawMode(input) {
517
+ return Boolean(input.isTTY && typeof input.setRawMode === "function");
518
+ }
519
+ var cachedFdIo;
520
+ function resolveSelectIo(preferred) {
521
+ if (preferred) {
522
+ return preferred;
523
+ }
524
+ const live = { input: process.stdin, output: process.stdout };
525
+ if (hasRawMode(live.input)) {
526
+ return live;
527
+ }
528
+ if (cachedFdIo && hasRawMode(cachedFdIo.input)) {
529
+ return cachedFdIo;
530
+ }
531
+ if (tty.isatty(0)) {
532
+ cachedFdIo = {
533
+ input: new tty.ReadStream(0),
534
+ output: tty.isatty(1) ? new tty.WriteStream(1) : process.stdout
535
+ };
536
+ return cachedFdIo;
537
+ }
538
+ return live;
539
+ }
540
+
515
541
  class PromptCancelledError extends Error {
516
542
  constructor() {
517
543
  super("Cancelled");
@@ -851,54 +877,51 @@ function isInteractive(flags) {
851
877
  if (flags.yes || flags.noInteractive) {
852
878
  return false;
853
879
  }
854
- return Boolean(input.isTTY && output.isTTY);
855
- }
856
- function canUseRawKeys() {
857
- return Boolean(input.isTTY && typeof input.setRawMode === "function");
880
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY || tty2.isatty(0) && tty2.isatty(1));
858
881
  }
859
- function createReadlinePrompter() {
860
- const rl = createInterface({ input, output });
861
- const io = { input, output };
882
+ function createReadlinePrompter(io) {
883
+ const stdio = () => resolveSelectIo(io);
884
+ async function askLine(message) {
885
+ const current = stdio();
886
+ const rl = createInterface({ input: current.input, output: current.output });
887
+ try {
888
+ return (await rl.question(message)).trim();
889
+ } finally {
890
+ rl.close();
891
+ }
892
+ }
862
893
  return {
863
894
  async question(message, defaultValue) {
864
895
  const suffix = defaultValue ? ` [${defaultValue}]` : "";
865
- const answer = (await rl.question(`${message}${suffix}: `)).trim();
896
+ const answer = await askLine(`${message}${suffix}: `);
866
897
  return answer || defaultValue || "";
867
898
  },
868
899
  async confirm(message, defaultValue = false) {
869
- if (canUseRawKeys()) {
870
- rl.pause();
871
- try {
872
- return await promptConfirm(message, defaultValue, io);
873
- } finally {
874
- input.setRawMode?.(false);
875
- rl.resume();
876
- }
900
+ const current = stdio();
901
+ if (hasRawMode(current.input)) {
902
+ return promptConfirm(message, defaultValue, current);
877
903
  }
878
904
  const hint = defaultValue ? "Y/n" : "y/N";
879
- const answer = (await rl.question(`${message} (${hint}): `)).trim().toLowerCase();
905
+ const answer = (await askLine(`${message} (${hint}): `)).toLowerCase();
880
906
  if (!answer) {
881
907
  return defaultValue;
882
908
  }
883
909
  return answer === "y" || answer === "yes";
884
910
  },
885
911
  async select(message, choices, defaultValue) {
886
- if (canUseRawKeys()) {
887
- rl.pause();
888
- try {
889
- return await promptSelect(message, choices, defaultValue, io);
890
- } finally {
891
- input.setRawMode?.(false);
892
- rl.resume();
893
- }
912
+ const current = stdio();
913
+ if (hasRawMode(current.input)) {
914
+ return promptSelect(message, choices, defaultValue, current);
894
915
  }
895
- console.log(message);
916
+ current.output.write(`${message}
917
+ `);
896
918
  for (const [index, choice] of choices.entries()) {
897
919
  const marker = choice.value === defaultValue ? "*" : " ";
898
- console.log(` ${index + 1}) ${marker} ${choice.label}`);
920
+ current.output.write(` ${index + 1}) ${marker} ${choice.label}
921
+ `);
899
922
  }
900
923
  const defaultIndex = choices.findIndex((choice) => choice.value === defaultValue) + 1;
901
- const answer = (await rl.question(`Choose [${defaultIndex}]: `)).trim();
924
+ const answer = await askLine(`Choose [${defaultIndex}]: `);
902
925
  if (!answer) {
903
926
  return defaultValue;
904
927
  }
@@ -911,20 +934,16 @@ function createReadlinePrompter() {
911
934
  return match?.value ?? defaultValue;
912
935
  },
913
936
  async multiSelect(message, choices) {
914
- if (canUseRawKeys()) {
915
- rl.pause();
916
- try {
917
- return await promptMultiSelect(message, choices, io);
918
- } finally {
919
- input.setRawMode?.(false);
920
- rl.resume();
921
- }
937
+ const current = stdio();
938
+ if (hasRawMode(current.input)) {
939
+ return promptMultiSelect(message, choices, current);
922
940
  }
923
941
  const enabled = new Set(choices.filter((choice) => choice.enabled).map((choice) => choice.value));
924
- console.log(`${message} (yes/no each)`);
942
+ current.output.write(`${message} (yes/no each)
943
+ `);
925
944
  for (const choice of choices) {
926
945
  const hint = enabled.has(choice.value) ? "Y/n" : "y/N";
927
- const answer = (await rl.question(` ${choice.label} (${hint}): `)).trim().toLowerCase();
946
+ const answer = (await askLine(` ${choice.label} (${hint}): `)).toLowerCase();
928
947
  if (!answer) {
929
948
  continue;
930
949
  }
@@ -937,7 +956,7 @@ function createReadlinePrompter() {
937
956
  return [...enabled];
938
957
  },
939
958
  close() {
940
- rl.close();
959
+ return;
941
960
  }
942
961
  };
943
962
  }
@@ -2415,9 +2434,9 @@ function renderPackageJson(projectName, options = {}) {
2415
2434
  "@getstrata/cli": "workspace:*",
2416
2435
  "@getstrata/core": "workspace:*"
2417
2436
  } : {
2418
- "@getstrata/bootstrap": "^0.4.3",
2419
- "@getstrata/cli": "^0.2.0",
2420
- "@getstrata/core": "^0.7.5"
2437
+ "@getstrata/bootstrap": "^1.0.0",
2438
+ "@getstrata/cli": "^1.0.0",
2439
+ "@getstrata/core": "^1.0.0"
2421
2440
  };
2422
2441
  if (options.layers?.database === "mysql") {
2423
2442
  coreDeps.mysql2 = "^3.24.3";
@@ -2852,13 +2871,13 @@ function renderMigrateTs(layers) {
2852
2871
  }
2853
2872
  const list = statements.map((sql) => ` \`${sql}\`,`).join(`
2854
2873
  `);
2855
- const ph2 = layers.database === "postgres";
2856
- const notePlaceholder = ph2 ? "$1" : "?";
2874
+ const ph = layers.database === "postgres";
2875
+ const notePlaceholder = ph ? "$1" : "?";
2857
2876
  const verifyOn = layers.extras.emailVerification && authNeedsUsers(layers.auth);
2858
2877
  const userColumns = verifyOn ? "name, email, password, is_admin, email_verified_at" : "name, email, password, is_admin";
2859
- const userPlaceholders = verifyOn ? ph2 ? "$1, $2, $3, $4, $5), ($6, $7, $8, $9, $10" : "?, ?, ?, ?, ?), (?, ?, ?, ?, ?" : ph2 ? "$1, $2, $3, $4), ($5, $6, $7, $8" : "?, ?, ?, ?), (?, ?, ?, ?";
2860
- const adminFlag = ph2 ? "false" : "0";
2861
- const adminTrue = ph2 ? "true" : "1";
2878
+ const userPlaceholders = verifyOn ? ph ? "$1, $2, $3, $4, $5), ($6, $7, $8, $9, $10" : "?, ?, ?, ?, ?), (?, ?, ?, ?, ?" : ph ? "$1, $2, $3, $4), ($5, $6, $7, $8" : "?, ?, ?, ?), (?, ?, ?, ?";
2879
+ const adminFlag = ph ? "false" : "0";
2880
+ const adminTrue = ph ? "true" : "1";
2862
2881
  const verifiedNow = "new Date().toISOString()";
2863
2882
  const userValues = verifyOn ? `["Demo User", "demo@example.com", password, ${adminFlag}, ${verifiedNow}, "Admin User", "admin@example.test", password, ${adminTrue}, ${verifiedNow}]` : `["Demo User", "demo@example.com", password, ${adminFlag}, "Admin User", "admin@example.test", password, ${adminTrue}]`;
2864
2883
  const seedTenant = tenancyOn ? `
@@ -2867,7 +2886,7 @@ function renderMigrateTs(layers) {
2867
2886
  );
2868
2887
  if (Number(tenantCount) === 0) {
2869
2888
  await sql.unsafe(
2870
- "INSERT INTO tenant (slug, plan, region) VALUES (${ph2 ? "$1, $2, $3" : "?, ?, ?"})",
2889
+ "INSERT INTO tenant (slug, plan, region) VALUES (${ph ? "$1, $2, $3" : "?, ?, ?"})",
2871
2890
  ["default", "enterprise", "eu"],
2872
2891
  );
2873
2892
  }` : "";
@@ -3166,7 +3185,6 @@ function adminCandidateUrls(url: string): string[] {
3166
3185
  names.push(current);
3167
3186
  }
3168
3187
  } catch {
3169
- // keep the built-in admin databases
3170
3188
  }
3171
3189
  return names.map((name) => {
3172
3190
  const admin = new URL(url);
@@ -11,9 +11,9 @@
11
11
  "check": "tsc --noEmit"
12
12
  },
13
13
  "dependencies": {
14
- "@getstrata/bootstrap": "^0.4.3",
15
- "@getstrata/cli": "^0.2.0",
16
- "@getstrata/core": "^0.7.5"
14
+ "@getstrata/bootstrap": "^1.0.0",
15
+ "@getstrata/cli": "^1.0.0",
16
+ "@getstrata/core": "^1.0.0"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@types/bun": "^1.4.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getstrata/starter",
3
- "version": "0.1.12",
3
+ "version": "1.0.0",
4
4
  "description": "Interactive create-strata wizard. Choose each layer; one database engine.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,6 +24,6 @@
24
24
  "access": "public"
25
25
  },
26
26
  "engines": {
27
- "bun": ">=1.1.0"
27
+ "bun": ">=1.4.0"
28
28
  }
29
29
  }