@korajs/cli 0.3.2 → 0.4.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 (50) hide show
  1. package/dist/bin.cjs +385 -288
  2. package/dist/bin.cjs.map +1 -1
  3. package/dist/bin.js +25 -11
  4. package/dist/bin.js.map +1 -1
  5. package/dist/{chunk-KTSRAPSE.js → chunk-CMSX76KM.js} +108 -65
  6. package/dist/chunk-CMSX76KM.js.map +1 -0
  7. package/dist/{chunk-ZGYRDYXS.js → chunk-MVP5PDT4.js} +22 -4
  8. package/dist/chunk-MVP5PDT4.js.map +1 -0
  9. package/dist/{chunk-E7OCVRYL.js → chunk-YGVO4POI.js} +242 -215
  10. package/dist/chunk-YGVO4POI.js.map +1 -0
  11. package/dist/create.cjs +122 -66
  12. package/dist/create.cjs.map +1 -1
  13. package/dist/create.js +2 -2
  14. package/dist/index.cjs +348 -278
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +31 -26
  17. package/dist/index.d.ts +31 -26
  18. package/dist/index.js +2 -2
  19. package/package.json +2 -2
  20. package/templates/tauri-react/.env.example +7 -0
  21. package/templates/tauri-react/.github/workflows/release-desktop.yml +107 -0
  22. package/templates/tauri-react/README.md.hbs +148 -0
  23. package/templates/tauri-react/dev.ts +37 -0
  24. package/templates/tauri-react/index.html.hbs +16 -0
  25. package/templates/tauri-react/kora.config.ts +17 -0
  26. package/templates/tauri-react/package.json.hbs +44 -0
  27. package/templates/tauri-react/server.ts +23 -0
  28. package/templates/tauri-react/src/App.tsx +578 -0
  29. package/templates/tauri-react/src/AppShell.tsx +116 -0
  30. package/templates/tauri-react/src/SetupScreen.tsx +239 -0
  31. package/templates/tauri-react/src/main.tsx +9 -0
  32. package/templates/tauri-react/src/schema.ts +15 -0
  33. package/templates/tauri-react/src/sync-config.ts +103 -0
  34. package/templates/tauri-react/src/updater.ts +38 -0
  35. package/templates/tauri-react/src-tauri/Cargo.toml +19 -0
  36. package/templates/tauri-react/src-tauri/build.rs +3 -0
  37. package/templates/tauri-react/src-tauri/capabilities/default.json +12 -0
  38. package/templates/tauri-react/src-tauri/icons/128x128.png +0 -0
  39. package/templates/tauri-react/src-tauri/icons/128x128@2x.png +0 -0
  40. package/templates/tauri-react/src-tauri/icons/32x32.png +0 -0
  41. package/templates/tauri-react/src-tauri/icons/icon.icns +0 -0
  42. package/templates/tauri-react/src-tauri/icons/icon.ico +0 -0
  43. package/templates/tauri-react/src-tauri/src/lib.rs +8 -0
  44. package/templates/tauri-react/src-tauri/src/main.rs +6 -0
  45. package/templates/tauri-react/src-tauri/tauri.conf.json +44 -0
  46. package/templates/tauri-react/tsconfig.json +15 -0
  47. package/templates/tauri-react/vite.config.ts +15 -0
  48. package/dist/chunk-E7OCVRYL.js.map +0 -1
  49. package/dist/chunk-KTSRAPSE.js.map +0 -1
  50. package/dist/chunk-ZGYRDYXS.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -91,7 +91,8 @@ var TEMPLATES = [
91
91
  "react-tailwind-sync",
92
92
  "react-tailwind",
93
93
  "react-sync",
94
- "react-basic"
94
+ "react-basic",
95
+ "tauri-react"
95
96
  ];
96
97
  var TEMPLATE_INFO = [
97
98
  {
@@ -113,6 +114,11 @@ var TEMPLATE_INFO = [
113
114
  name: "react-basic",
114
115
  label: "React + CSS (local-only)",
115
116
  description: "Clean CSS app \u2014 no sync server"
117
+ },
118
+ {
119
+ name: "tauri-react",
120
+ label: "Tauri Desktop (native SQLite)",
121
+ description: "Desktop app with native SQLite \u2014 no WASM, includes sync server"
116
122
  }
117
123
  ];
118
124
 
@@ -344,6 +350,7 @@ function promptConfirm(message, defaultValue = false, options) {
344
350
  resolve3(false);
345
351
  return;
346
352
  }
353
+ ;
347
354
  (options?.output ?? process.stdout).write(" Please answer with y or n\n");
348
355
  ask();
349
356
  });
@@ -536,7 +543,15 @@ function createLogger(options) {
536
543
  }
537
544
 
538
545
  // src/commands/deploy/adapters/adapter.ts
539
- var DEPLOY_PLATFORMS = ["fly", "railway", "aws-ecs", "aws-lightsail", "render", "docker", "kora-cloud"];
546
+ var DEPLOY_PLATFORMS = [
547
+ "fly",
548
+ "railway",
549
+ "aws-ecs",
550
+ "aws-lightsail",
551
+ "render",
552
+ "docker",
553
+ "kora-cloud"
554
+ ];
540
555
  function isDeployPlatform(value) {
541
556
  return DEPLOY_PLATFORMS.includes(value);
542
557
  }
@@ -547,8 +562,8 @@ var import_node_path4 = require("path");
547
562
 
548
563
  // src/commands/deploy/builder/client-builder.ts
549
564
  var import_node_child_process = require("child_process");
550
- var import_promises2 = require("fs/promises");
551
565
  var import_node_fs = require("fs");
566
+ var import_promises2 = require("fs/promises");
552
567
  var import_node_path2 = require("path");
553
568
  async function buildClient(options) {
554
569
  const viteEntryPoint = await resolveProjectBinaryEntryPoint(options.projectRoot, "vite", "vite");
@@ -706,37 +721,46 @@ var AwsEcsAdapter = class {
706
721
  };
707
722
  const region = config.region ?? "us-east-1";
708
723
  const repoName = `kora/${config.appName}`;
709
- const createRepo = await this.runner.run("aws", [
710
- "ecr",
711
- "create-repository",
712
- "--repository-name",
713
- repoName,
714
- "--region",
715
- region,
716
- "--image-scanning-configuration",
717
- "scanOnPush=true"
718
- ], config.projectRoot);
724
+ const createRepo = await this.runner.run(
725
+ "aws",
726
+ [
727
+ "ecr",
728
+ "create-repository",
729
+ "--repository-name",
730
+ repoName,
731
+ "--region",
732
+ region,
733
+ "--image-scanning-configuration",
734
+ "scanOnPush=true"
735
+ ],
736
+ config.projectRoot
737
+ );
719
738
  if (createRepo.exitCode !== 0 && !createRepo.stderr.includes("RepositoryAlreadyExistsException")) {
720
739
  throw new Error(`Failed to create ECR repository: ${createRepo.stderr}`);
721
740
  }
722
- const identity = await this.runner.run("aws", ["sts", "get-caller-identity", "--query", "Account", "--output", "text"], config.projectRoot);
741
+ const identity = await this.runner.run(
742
+ "aws",
743
+ ["sts", "get-caller-identity", "--query", "Account", "--output", "text"],
744
+ config.projectRoot
745
+ );
723
746
  const accountId = identity.stdout.trim();
724
- await this.runner.run("aws", [
725
- "ecs",
726
- "create-cluster",
727
- "--cluster-name",
728
- config.appName,
729
- "--region",
730
- region
731
- ], config.projectRoot);
732
- await this.runner.run("aws", [
733
- "logs",
734
- "create-log-group",
735
- "--log-group-name",
736
- `/ecs/${config.appName}`,
737
- "--region",
738
- region
739
- ], config.projectRoot);
747
+ await this.runner.run(
748
+ "aws",
749
+ ["ecs", "create-cluster", "--cluster-name", config.appName, "--region", region],
750
+ config.projectRoot
751
+ );
752
+ await this.runner.run(
753
+ "aws",
754
+ [
755
+ "logs",
756
+ "create-log-group",
757
+ "--log-group-name",
758
+ `/ecs/${config.appName}`,
759
+ "--region",
760
+ region
761
+ ],
762
+ config.projectRoot
763
+ );
740
764
  return {
741
765
  applicationId: `${accountId}.dkr.ecr.${region}.amazonaws.com/${repoName}`,
742
766
  databaseId: null,
@@ -769,50 +793,42 @@ var AwsEcsAdapter = class {
769
793
  const context = this.requireContext();
770
794
  const region = context.region ?? "us-east-1";
771
795
  const repoName = `kora/${context.appName}`;
772
- const loginPassword = await this.runner.run("aws", [
773
- "ecr",
774
- "get-login-password",
775
- "--region",
776
- region
777
- ], context.projectRoot);
796
+ const loginPassword = await this.runner.run(
797
+ "aws",
798
+ ["ecr", "get-login-password", "--region", region],
799
+ context.projectRoot
800
+ );
778
801
  if (loginPassword.exitCode !== 0) {
779
802
  throw new Error(`ECR login failed: ${loginPassword.stderr}`);
780
803
  }
781
- const identity = await this.runner.run("aws", [
782
- "sts",
783
- "get-caller-identity",
784
- "--query",
785
- "Account",
786
- "--output",
787
- "text"
788
- ], context.projectRoot);
804
+ const identity = await this.runner.run(
805
+ "aws",
806
+ ["sts", "get-caller-identity", "--query", "Account", "--output", "text"],
807
+ context.projectRoot
808
+ );
789
809
  const accountId = identity.stdout.trim();
790
810
  const ecrUri = `${accountId}.dkr.ecr.${region}.amazonaws.com`;
791
811
  const imageUri = `${ecrUri}/${repoName}:latest`;
792
- const dockerLogin = await this.runner.run("docker", [
793
- "login",
794
- "--username",
795
- "AWS",
796
- "--password-stdin",
797
- ecrUri
798
- ], artifacts.deployDirectory);
812
+ const dockerLogin = await this.runner.run(
813
+ "docker",
814
+ ["login", "--username", "AWS", "--password-stdin", ecrUri],
815
+ artifacts.deployDirectory
816
+ );
799
817
  this.logger.step("Building Docker image...");
800
- const dockerBuild = await this.runner.run("docker", [
801
- "build",
802
- "--platform",
803
- "linux/amd64",
804
- "-t",
805
- imageUri,
806
- "."
807
- ], artifacts.deployDirectory);
818
+ const dockerBuild = await this.runner.run(
819
+ "docker",
820
+ ["build", "--platform", "linux/amd64", "-t", imageUri, "."],
821
+ artifacts.deployDirectory
822
+ );
808
823
  if (dockerBuild.exitCode !== 0) {
809
824
  throw new Error(`Docker build failed: ${dockerBuild.stderr}`);
810
825
  }
811
826
  this.logger.step("Pushing image to ECR...");
812
- const dockerPush = await this.runner.run("docker", [
813
- "push",
814
- imageUri
815
- ], artifacts.deployDirectory);
827
+ const dockerPush = await this.runner.run(
828
+ "docker",
829
+ ["push", imageUri],
830
+ artifacts.deployDirectory
831
+ );
816
832
  if (dockerPush.exitCode !== 0) {
817
833
  throw new Error(`Docker push failed: ${dockerPush.stderr}`);
818
834
  }
@@ -823,52 +839,55 @@ var AwsEcsAdapter = class {
823
839
  cpu: "256",
824
840
  memory: "512",
825
841
  executionRoleArn: `arn:aws:iam::${accountId}:role/ecsTaskExecutionRole`,
826
- containerDefinitions: [{
827
- name: context.appName,
828
- image: imageUri,
829
- essential: true,
830
- portMappings: [{ containerPort: 3001, protocol: "tcp" }],
831
- logConfiguration: {
832
- logDriver: "awslogs",
833
- options: {
834
- "awslogs-group": `/ecs/${context.appName}`,
835
- "awslogs-region": region,
836
- "awslogs-stream-prefix": "ecs"
842
+ containerDefinitions: [
843
+ {
844
+ name: context.appName,
845
+ image: imageUri,
846
+ essential: true,
847
+ portMappings: [{ containerPort: 3001, protocol: "tcp" }],
848
+ logConfiguration: {
849
+ logDriver: "awslogs",
850
+ options: {
851
+ "awslogs-group": `/ecs/${context.appName}`,
852
+ "awslogs-region": region,
853
+ "awslogs-stream-prefix": "ecs"
854
+ }
855
+ },
856
+ healthCheck: {
857
+ command: ["CMD-SHELL", "curl -f http://localhost:3001/health || exit 1"],
858
+ interval: 30,
859
+ timeout: 5,
860
+ retries: 3,
861
+ startPeriod: 60
837
862
  }
838
- },
839
- healthCheck: {
840
- command: ["CMD-SHELL", "curl -f http://localhost:3001/health || exit 1"],
841
- interval: 30,
842
- timeout: 5,
843
- retries: 3,
844
- startPeriod: 60
845
863
  }
846
- }]
864
+ ]
847
865
  });
848
- const registerTask = await this.runner.run("aws", [
849
- "ecs",
850
- "register-task-definition",
851
- "--cli-input-json",
852
- taskDef,
853
- "--region",
854
- region
855
- ], context.projectRoot);
866
+ const registerTask = await this.runner.run(
867
+ "aws",
868
+ ["ecs", "register-task-definition", "--cli-input-json", taskDef, "--region", region],
869
+ context.projectRoot
870
+ );
856
871
  if (registerTask.exitCode !== 0) {
857
872
  throw new Error(`Task definition registration failed: ${registerTask.stderr}`);
858
873
  }
859
- const updateService = await this.runner.run("aws", [
860
- "ecs",
861
- "update-service",
862
- "--cluster",
863
- context.appName,
864
- "--service",
865
- context.appName,
866
- "--task-definition",
867
- context.appName,
868
- "--force-new-deployment",
869
- "--region",
870
- region
871
- ], context.projectRoot);
874
+ const updateService = await this.runner.run(
875
+ "aws",
876
+ [
877
+ "ecs",
878
+ "update-service",
879
+ "--cluster",
880
+ context.appName,
881
+ "--service",
882
+ context.appName,
883
+ "--task-definition",
884
+ context.appName,
885
+ "--force-new-deployment",
886
+ "--region",
887
+ region
888
+ ],
889
+ context.projectRoot
890
+ );
872
891
  const deploymentId = (/* @__PURE__ */ new Date()).toISOString();
873
892
  if (updateService.exitCode !== 0) {
874
893
  this.logger.step("Service not found, creating new service...");
@@ -893,19 +912,23 @@ var AwsEcsAdapter = class {
893
912
  async rollback(deploymentId) {
894
913
  const context = this.requireContext();
895
914
  const region = context.region ?? "us-east-1";
896
- const result = await this.runner.run("aws", [
897
- "ecs",
898
- "update-service",
899
- "--cluster",
900
- context.appName,
901
- "--service",
902
- context.appName,
903
- "--task-definition",
904
- `${context.appName}:${deploymentId}`,
905
- "--force-new-deployment",
906
- "--region",
907
- region
908
- ], context.projectRoot);
915
+ const result = await this.runner.run(
916
+ "aws",
917
+ [
918
+ "ecs",
919
+ "update-service",
920
+ "--cluster",
921
+ context.appName,
922
+ "--service",
923
+ context.appName,
924
+ "--task-definition",
925
+ `${context.appName}:${deploymentId}`,
926
+ "--force-new-deployment",
927
+ "--region",
928
+ region
929
+ ],
930
+ context.projectRoot
931
+ );
909
932
  if (result.exitCode !== 0) {
910
933
  throw new Error(`ECS rollback failed: ${result.stderr}`);
911
934
  }
@@ -948,16 +971,20 @@ var AwsEcsAdapter = class {
948
971
  async status() {
949
972
  const context = this.requireContext();
950
973
  const region = context.region ?? "us-east-1";
951
- const result = await this.runner.run("aws", [
952
- "ecs",
953
- "describe-services",
954
- "--cluster",
955
- context.appName,
956
- "--services",
957
- context.appName,
958
- "--region",
959
- region
960
- ], context.projectRoot);
974
+ const result = await this.runner.run(
975
+ "aws",
976
+ [
977
+ "ecs",
978
+ "describe-services",
979
+ "--cluster",
980
+ context.appName,
981
+ "--services",
982
+ context.appName,
983
+ "--region",
984
+ region
985
+ ],
986
+ context.projectRoot
987
+ );
961
988
  if (result.exitCode !== 0) {
962
989
  return { state: "failed", message: result.stderr };
963
990
  }
@@ -1066,18 +1093,22 @@ var AwsLightsailAdapter = class {
1066
1093
  };
1067
1094
  const region = config.region ?? "us-east-1";
1068
1095
  const serviceName = sanitizeLightsailName(config.appName);
1069
- const createService = await this.runner.run("aws", [
1070
- "lightsail",
1071
- "create-container-service",
1072
- "--service-name",
1073
- serviceName,
1074
- "--power",
1075
- "nano",
1076
- "--scale",
1077
- "1",
1078
- "--region",
1079
- region
1080
- ], config.projectRoot);
1096
+ const createService = await this.runner.run(
1097
+ "aws",
1098
+ [
1099
+ "lightsail",
1100
+ "create-container-service",
1101
+ "--service-name",
1102
+ serviceName,
1103
+ "--power",
1104
+ "nano",
1105
+ "--scale",
1106
+ "1",
1107
+ "--region",
1108
+ region
1109
+ ],
1110
+ config.projectRoot
1111
+ );
1081
1112
  if (createService.exitCode !== 0 && !createService.stderr.includes("already exists")) {
1082
1113
  throw new Error(`Failed to create Lightsail container service: ${createService.stderr}`);
1083
1114
  }
@@ -1115,30 +1146,31 @@ var AwsLightsailAdapter = class {
1115
1146
  const serviceName = sanitizeLightsailName(context.appName);
1116
1147
  const imageTag = `${serviceName}:latest`;
1117
1148
  this.logger.step("Building Docker image...");
1118
- const dockerBuild = await this.runner.run("docker", [
1119
- "build",
1120
- "--platform",
1121
- "linux/amd64",
1122
- "-t",
1123
- imageTag,
1124
- "."
1125
- ], artifacts.deployDirectory);
1149
+ const dockerBuild = await this.runner.run(
1150
+ "docker",
1151
+ ["build", "--platform", "linux/amd64", "-t", imageTag, "."],
1152
+ artifacts.deployDirectory
1153
+ );
1126
1154
  if (dockerBuild.exitCode !== 0) {
1127
1155
  throw new Error(`Docker build failed: ${dockerBuild.stderr}`);
1128
1156
  }
1129
1157
  this.logger.step("Pushing image to Lightsail...");
1130
- const pushImage = await this.runner.run("aws", [
1131
- "lightsail",
1132
- "push-container-image",
1133
- "--service-name",
1134
- serviceName,
1135
- "--label",
1136
- "latest",
1137
- "--image",
1138
- imageTag,
1139
- "--region",
1140
- region
1141
- ], artifacts.deployDirectory);
1158
+ const pushImage = await this.runner.run(
1159
+ "aws",
1160
+ [
1161
+ "lightsail",
1162
+ "push-container-image",
1163
+ "--service-name",
1164
+ serviceName,
1165
+ "--label",
1166
+ "latest",
1167
+ "--image",
1168
+ imageTag,
1169
+ "--region",
1170
+ region
1171
+ ],
1172
+ artifacts.deployDirectory
1173
+ );
1142
1174
  if (pushImage.exitCode !== 0) {
1143
1175
  throw new Error(`Lightsail image push failed: ${pushImage.stderr}`);
1144
1176
  }
@@ -1169,29 +1201,30 @@ var AwsLightsailAdapter = class {
1169
1201
  unhealthyThreshold: 3
1170
1202
  }
1171
1203
  });
1172
- const createDeploy = await this.runner.run("aws", [
1173
- "lightsail",
1174
- "create-container-service-deployment",
1175
- "--service-name",
1176
- serviceName,
1177
- "--containers",
1178
- containers,
1179
- "--public-endpoint",
1180
- publicEndpoint,
1181
- "--region",
1182
- region
1183
- ], context.projectRoot);
1204
+ const createDeploy = await this.runner.run(
1205
+ "aws",
1206
+ [
1207
+ "lightsail",
1208
+ "create-container-service-deployment",
1209
+ "--service-name",
1210
+ serviceName,
1211
+ "--containers",
1212
+ containers,
1213
+ "--public-endpoint",
1214
+ publicEndpoint,
1215
+ "--region",
1216
+ region
1217
+ ],
1218
+ context.projectRoot
1219
+ );
1184
1220
  if (createDeploy.exitCode !== 0) {
1185
1221
  throw new Error(`Lightsail deployment failed: ${createDeploy.stderr}`);
1186
1222
  }
1187
- const serviceInfo = await this.runner.run("aws", [
1188
- "lightsail",
1189
- "get-container-services",
1190
- "--service-name",
1191
- serviceName,
1192
- "--region",
1193
- region
1194
- ], context.projectRoot);
1223
+ const serviceInfo = await this.runner.run(
1224
+ "aws",
1225
+ ["lightsail", "get-container-services", "--service-name", serviceName, "--region", region],
1226
+ context.projectRoot
1227
+ );
1195
1228
  const rawUrl = parseLightsailUrl(serviceInfo.stdout) ?? `https://${serviceName}.${region}.cs.amazonlightsail.com`;
1196
1229
  const serviceUrl = rawUrl.replace(/\/+$/, "");
1197
1230
  const deploymentId = (/* @__PURE__ */ new Date()).toISOString();
@@ -1205,14 +1238,18 @@ var AwsLightsailAdapter = class {
1205
1238
  const context = this.requireContext();
1206
1239
  const region = context.region ?? "us-east-1";
1207
1240
  const serviceName = sanitizeLightsailName(context.appName);
1208
- const deployments = await this.runner.run("aws", [
1209
- "lightsail",
1210
- "get-container-service-deployments",
1211
- "--service-name",
1212
- serviceName,
1213
- "--region",
1214
- region
1215
- ], context.projectRoot);
1241
+ const deployments = await this.runner.run(
1242
+ "aws",
1243
+ [
1244
+ "lightsail",
1245
+ "get-container-service-deployments",
1246
+ "--service-name",
1247
+ serviceName,
1248
+ "--region",
1249
+ region
1250
+ ],
1251
+ context.projectRoot
1252
+ );
1216
1253
  if (deployments.exitCode !== 0) {
1217
1254
  throw new Error(`Lightsail rollback failed: ${deployments.stderr}`);
1218
1255
  }
@@ -1220,18 +1257,22 @@ var AwsLightsailAdapter = class {
1220
1257
  if (!previousDeployment) {
1221
1258
  throw new Error("No previous deployment found to rollback to.");
1222
1259
  }
1223
- const redeploy = await this.runner.run("aws", [
1224
- "lightsail",
1225
- "create-container-service-deployment",
1226
- "--service-name",
1227
- serviceName,
1228
- "--containers",
1229
- JSON.stringify(previousDeployment.containers),
1230
- "--public-endpoint",
1231
- JSON.stringify(previousDeployment.publicEndpoint),
1232
- "--region",
1233
- region
1234
- ], context.projectRoot);
1260
+ const redeploy = await this.runner.run(
1261
+ "aws",
1262
+ [
1263
+ "lightsail",
1264
+ "create-container-service-deployment",
1265
+ "--service-name",
1266
+ serviceName,
1267
+ "--containers",
1268
+ JSON.stringify(previousDeployment.containers),
1269
+ "--public-endpoint",
1270
+ JSON.stringify(previousDeployment.publicEndpoint),
1271
+ "--region",
1272
+ region
1273
+ ],
1274
+ context.projectRoot
1275
+ );
1235
1276
  if (redeploy.exitCode !== 0) {
1236
1277
  throw new Error(`Lightsail rollback deployment failed: ${redeploy.stderr}`);
1237
1278
  }
@@ -1278,14 +1319,11 @@ var AwsLightsailAdapter = class {
1278
1319
  const context = this.requireContext();
1279
1320
  const region = context.region ?? "us-east-1";
1280
1321
  const serviceName = sanitizeLightsailName(context.appName);
1281
- const result = await this.runner.run("aws", [
1282
- "lightsail",
1283
- "get-container-services",
1284
- "--service-name",
1285
- serviceName,
1286
- "--region",
1287
- region
1288
- ], context.projectRoot);
1322
+ const result = await this.runner.run(
1323
+ "aws",
1324
+ ["lightsail", "get-container-services", "--service-name", serviceName, "--region", region],
1325
+ context.projectRoot
1326
+ );
1289
1327
  if (result.exitCode !== 0) {
1290
1328
  return { state: "failed", message: result.stderr };
1291
1329
  }
@@ -1350,12 +1388,7 @@ ${error.message}` });
1350
1388
  });
1351
1389
  }
1352
1390
  };
1353
- var PASSTHROUGH_ENV_VARS = [
1354
- "DATABASE_URL",
1355
- "AUTH_SECRET",
1356
- "PUBLIC_URL",
1357
- "NODE_ENV"
1358
- ];
1391
+ var PASSTHROUGH_ENV_VARS = ["DATABASE_URL", "AUTH_SECRET", "PUBLIC_URL", "NODE_ENV"];
1359
1392
  function sanitizeLightsailName(name) {
1360
1393
  return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-{2,}/g, "-").replace(/^-|-$/g, "").slice(0, 255) || "kora-app";
1361
1394
  }
@@ -2234,7 +2267,8 @@ function generateDeployPackageJson(nativeDependencies) {
2234
2267
  type: "module",
2235
2268
  dependencies: nativeDependencies
2236
2269
  };
2237
- return JSON.stringify(pkg, null, 2) + "\n";
2270
+ return `${JSON.stringify(pkg, null, 2)}
2271
+ `;
2238
2272
  }
2239
2273
  function generateDockerIgnore() {
2240
2274
  return [
@@ -2566,7 +2600,7 @@ var deployCommand = (0, import_citty.defineCommand)({
2566
2600
  nativeDependencies: {
2567
2601
  "better-sqlite3": "^11.0.0",
2568
2602
  "drizzle-orm": "^0.45.2",
2569
- "postgres": "^3.4.0"
2603
+ postgres: "^3.4.0"
2570
2604
  }
2571
2605
  });
2572
2606
  await writeDockerIgnoreArtifact(deployDirectory);
@@ -2731,12 +2765,16 @@ function validateProjectName(name) {
2731
2765
 
2732
2766
  // src/commands/create/options.ts
2733
2767
  function determineTemplateFromSelections(input) {
2768
+ if (input.platform === "desktop-tauri") return "tauri-react";
2734
2769
  const shouldSync = input.sync && input.db !== "none";
2735
2770
  if (input.tailwind && shouldSync) return "react-tailwind-sync";
2736
2771
  if (input.tailwind && !shouldSync) return "react-tailwind";
2737
2772
  if (!input.tailwind && shouldSync) return "react-sync";
2738
2773
  return "react-basic";
2739
2774
  }
2775
+ function isPlatformValue(value) {
2776
+ return value === "web" || value === "desktop-tauri";
2777
+ }
2740
2778
  function isFrameworkValue(value) {
2741
2779
  return value === "react" || value === "vue" || value === "svelte" || value === "solid";
2742
2780
  }
@@ -2753,6 +2791,7 @@ function isDatabaseProviderValue(value) {
2753
2791
  // src/prompts/preferences.ts
2754
2792
  var import_conf = __toESM(require("conf"), 1);
2755
2793
  var DEFAULT_PREFERENCES = {
2794
+ platform: "web",
2756
2795
  framework: "react",
2757
2796
  tailwind: true,
2758
2797
  sync: true,
@@ -2807,83 +2846,110 @@ async function resolveCreatePreferencesFlow(params) {
2807
2846
  usedStoredPreferences = true;
2808
2847
  }
2809
2848
  }
2810
- if (flags.framework !== void 0) {
2811
- if (!isFrameworkValue(flags.framework)) {
2849
+ if (flags.platform !== void 0) {
2850
+ if (!isPlatformValue(flags.platform)) {
2812
2851
  throw new Error(
2813
- `Invalid --framework value "${flags.framework}". Expected one of: react, vue, svelte, solid.`
2852
+ `Invalid --platform value "${flags.platform}". Expected one of: web, desktop-tauri.`
2814
2853
  );
2815
2854
  }
2816
- effective.framework = flags.framework;
2817
- } else if (!flags.useDefaults && !usedStoredPreferences) {
2818
- effective.framework = await prompts.select("UI framework:", [
2819
- { label: "React", value: "react" },
2820
- { label: "Vue (coming soon)", value: "vue", disabled: true },
2821
- { label: "Svelte (coming soon)", value: "svelte", disabled: true },
2822
- { label: "Solid (coming soon)", value: "solid", disabled: true }
2823
- ]);
2824
- }
2825
- if (flags.auth !== void 0) {
2826
- if (!isAuthValue(flags.auth)) {
2827
- throw new Error(
2828
- `Invalid --auth value "${flags.auth}". Expected one of: none, email-password, oauth.`
2829
- );
2830
- }
2831
- effective.auth = flags.auth;
2832
- } else if (!flags.useDefaults && !usedStoredPreferences) {
2833
- effective.auth = await prompts.select("Authentication:", [
2834
- { label: "None", value: "none" },
2835
- { label: "Email + Password (coming soon)", value: "email-password", disabled: true },
2836
- { label: "OAuth (coming soon)", value: "oauth", disabled: true }
2837
- ]);
2838
- }
2839
- if (flags.tailwind !== void 0) {
2840
- effective.tailwind = flags.tailwind;
2841
- } else if (!flags.useDefaults && !usedStoredPreferences) {
2842
- effective.tailwind = await prompts.confirm("Use Tailwind CSS?", true);
2843
- }
2844
- if (flags.sync !== void 0) {
2845
- effective.sync = flags.sync;
2846
- } else if (!flags.useDefaults && !usedStoredPreferences) {
2847
- effective.sync = await prompts.confirm("Enable multi-device sync?", true);
2848
- }
2849
- if (flags.db !== void 0) {
2850
- if (!isDatabaseValue(flags.db)) {
2851
- throw new Error(`Invalid --db value "${flags.db}". Expected one of: none, sqlite, postgres.`);
2852
- }
2853
- effective.db = flags.db;
2854
- } else if (!effective.sync) {
2855
- effective.db = "none";
2855
+ effective.platform = flags.platform;
2856
2856
  } else if (!flags.useDefaults && !usedStoredPreferences) {
2857
- effective.db = await prompts.select("Server-side database:", [
2858
- { label: "SQLite (zero-config)", value: "sqlite" },
2859
- { label: "PostgreSQL (production-scale)", value: "postgres" }
2857
+ effective.platform = await prompts.select("Platform:", [
2858
+ { label: "Web (browser)", value: "web" },
2859
+ { label: "Desktop (Tauri \u2014 native SQLite)", value: "desktop-tauri" }
2860
2860
  ]);
2861
2861
  }
2862
- if (effective.db !== "postgres") {
2862
+ const isTauri = effective.platform === "desktop-tauri";
2863
+ if (isTauri) {
2864
+ effective.framework = "react";
2865
+ effective.tailwind = false;
2866
+ effective.sync = true;
2867
+ effective.db = "sqlite";
2863
2868
  effective.dbProvider = "none";
2864
- } else if (flags.dbProvider !== void 0) {
2865
- if (!isDatabaseProviderValue(flags.dbProvider)) {
2866
- throw new Error(
2867
- `Invalid --db-provider value "${flags.dbProvider}". Expected one of: none, local, supabase, neon, railway, vercel-postgres, custom.`
2868
- );
2869
+ effective.auth = "none";
2870
+ } else {
2871
+ if (flags.framework !== void 0) {
2872
+ if (!isFrameworkValue(flags.framework)) {
2873
+ throw new Error(
2874
+ `Invalid --framework value "${flags.framework}". Expected one of: react, vue, svelte, solid.`
2875
+ );
2876
+ }
2877
+ effective.framework = flags.framework;
2878
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
2879
+ effective.framework = await prompts.select("UI framework:", [
2880
+ { label: "React", value: "react" },
2881
+ { label: "Vue (coming soon)", value: "vue", disabled: true },
2882
+ { label: "Svelte (coming soon)", value: "svelte", disabled: true },
2883
+ { label: "Solid (coming soon)", value: "solid", disabled: true }
2884
+ ]);
2885
+ }
2886
+ if (flags.auth !== void 0) {
2887
+ if (!isAuthValue(flags.auth)) {
2888
+ throw new Error(
2889
+ `Invalid --auth value "${flags.auth}". Expected one of: none, email-password, oauth.`
2890
+ );
2891
+ }
2892
+ effective.auth = flags.auth;
2893
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
2894
+ effective.auth = await prompts.select("Authentication:", [
2895
+ { label: "None", value: "none" },
2896
+ { label: "Email + Password (coming soon)", value: "email-password", disabled: true },
2897
+ { label: "OAuth (coming soon)", value: "oauth", disabled: true }
2898
+ ]);
2899
+ }
2900
+ if (flags.tailwind !== void 0) {
2901
+ effective.tailwind = flags.tailwind;
2902
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
2903
+ effective.tailwind = await prompts.confirm("Use Tailwind CSS?", true);
2904
+ }
2905
+ if (flags.sync !== void 0) {
2906
+ effective.sync = flags.sync;
2907
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
2908
+ effective.sync = await prompts.confirm("Enable multi-device sync?", true);
2909
+ }
2910
+ if (flags.db !== void 0) {
2911
+ if (!isDatabaseValue(flags.db)) {
2912
+ throw new Error(
2913
+ `Invalid --db value "${flags.db}". Expected one of: none, sqlite, postgres.`
2914
+ );
2915
+ }
2916
+ effective.db = flags.db;
2917
+ } else if (!effective.sync) {
2918
+ effective.db = "none";
2919
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
2920
+ effective.db = await prompts.select("Server-side database:", [
2921
+ { label: "SQLite (zero-config)", value: "sqlite" },
2922
+ { label: "PostgreSQL (production-scale)", value: "postgres" }
2923
+ ]);
2924
+ }
2925
+ if (effective.db !== "postgres") {
2926
+ effective.dbProvider = "none";
2927
+ } else if (flags.dbProvider !== void 0) {
2928
+ if (!isDatabaseProviderValue(flags.dbProvider)) {
2929
+ throw new Error(
2930
+ `Invalid --db-provider value "${flags.dbProvider}". Expected one of: none, local, supabase, neon, railway, vercel-postgres, custom.`
2931
+ );
2932
+ }
2933
+ effective.dbProvider = flags.dbProvider;
2934
+ } else if (!flags.useDefaults && !usedStoredPreferences) {
2935
+ effective.dbProvider = await prompts.select("Database provider:", [
2936
+ { label: "Local Postgres", value: "local" },
2937
+ { label: "Supabase", value: "supabase" },
2938
+ { label: "Neon", value: "neon" },
2939
+ { label: "Railway", value: "railway" },
2940
+ { label: "Vercel Postgres", value: "vercel-postgres" },
2941
+ { label: "Custom connection string", value: "custom" }
2942
+ ]);
2869
2943
  }
2870
- effective.dbProvider = flags.dbProvider;
2871
- } else if (!flags.useDefaults && !usedStoredPreferences) {
2872
- effective.dbProvider = await prompts.select("Database provider:", [
2873
- { label: "Local Postgres", value: "local" },
2874
- { label: "Supabase", value: "supabase" },
2875
- { label: "Neon", value: "neon" },
2876
- { label: "Railway", value: "railway" },
2877
- { label: "Vercel Postgres", value: "vercel-postgres" },
2878
- { label: "Custom connection string", value: "custom" }
2879
- ]);
2880
2944
  }
2881
2945
  const template = determineTemplateFromSelections({
2946
+ platform: effective.platform,
2882
2947
  tailwind: effective.tailwind,
2883
2948
  sync: effective.sync,
2884
2949
  db: effective.db
2885
2950
  });
2886
2951
  return {
2952
+ platform: effective.platform,
2887
2953
  framework: effective.framework,
2888
2954
  auth: effective.auth,
2889
2955
  db: effective.db,
@@ -2899,6 +2965,7 @@ function shouldSavePreferences(flags) {
2899
2965
  }
2900
2966
  function saveResolvedPreferences(store, resolution) {
2901
2967
  store.saveCreatePreferences({
2968
+ platform: resolution.platform,
2902
2969
  framework: resolution.framework,
2903
2970
  tailwind: resolution.tailwind,
2904
2971
  sync: resolution.sync,
@@ -2909,12 +2976,15 @@ function saveResolvedPreferences(store, resolution) {
2909
2976
  });
2910
2977
  }
2911
2978
  function hasExplicitPreferenceFlags(flags) {
2912
- return flags.framework !== void 0 || flags.auth !== void 0 || flags.db !== void 0 || flags.dbProvider !== void 0 || flags.tailwind !== void 0 || flags.sync !== void 0;
2979
+ return flags.platform !== void 0 || flags.framework !== void 0 || flags.auth !== void 0 || flags.db !== void 0 || flags.dbProvider !== void 0 || flags.tailwind !== void 0 || flags.sync !== void 0;
2913
2980
  }
2914
2981
  function promptSupportsRichOptions() {
2915
2982
  return typeof process !== "undefined" && process.stdin.isTTY && process.stdout.isTTY;
2916
2983
  }
2917
2984
  function formatStoredPreferenceLabel(preferences) {
2985
+ if (preferences.platform === "desktop-tauri") {
2986
+ return `Use previous settings (tauri-desktop + ${preferences.packageManager})`;
2987
+ }
2918
2988
  const syncLabel = preferences.sync ? `sync/${preferences.db}` : "local-only";
2919
2989
  const styleLabel = preferences.tailwind ? "tailwind" : "css";
2920
2990
  return `Use previous settings (${preferences.framework} + ${styleLabel} + ${syncLabel} + ${preferences.packageManager})`;
@@ -2992,7 +3062,7 @@ async function applySyncProviderPreset(options) {
2992
3062
  await (0, import_promises9.writeFile)(readmePath, readmeTemplate, "utf-8");
2993
3063
  }
2994
3064
  function isSyncTemplate(template) {
2995
- return template === "react-sync" || template === "react-tailwind-sync";
3065
+ return template === "react-sync" || template === "react-tailwind-sync" || template === "tauri-react";
2996
3066
  }
2997
3067
  function getProviderDisplayName(provider) {
2998
3068
  switch (provider) {