@korajs/cli 1.0.0-beta.12 → 1.0.0-beta.14

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 (91) hide show
  1. package/README.md +25 -107
  2. package/dist/bin.cjs +808 -340
  3. package/dist/bin.cjs.map +1 -1
  4. package/dist/bin.js +588 -174
  5. package/dist/bin.js.map +1 -1
  6. package/dist/{chunk-G2PBYMMA.js → chunk-7Y4J2GXP.js} +168 -153
  7. package/dist/chunk-7Y4J2GXP.js.map +1 -0
  8. package/dist/{chunk-Z7GCXMGW.js → chunk-BURFQVMV.js} +44 -9
  9. package/dist/chunk-BURFQVMV.js.map +1 -0
  10. package/dist/{chunk-4IKCHRJ6.js → chunk-TVIRMDER.js} +122 -112
  11. package/dist/chunk-TVIRMDER.js.map +1 -0
  12. package/dist/create.cjs +63 -28
  13. package/dist/create.cjs.map +1 -1
  14. package/dist/create.js +2 -2
  15. package/dist/index.cjs +41 -14
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +21 -1
  18. package/dist/index.d.ts +21 -1
  19. package/dist/index.js +8 -2
  20. package/dist/{studio-server-NIFKZI4F.js → studio-server-XLGZNGG5.js} +11 -2
  21. package/dist/studio-server-XLGZNGG5.js.map +1 -0
  22. package/dist/vite.cjs +351 -0
  23. package/dist/vite.cjs.map +1 -0
  24. package/dist/vite.d.cts +161 -0
  25. package/dist/vite.d.ts +161 -0
  26. package/dist/vite.js +321 -0
  27. package/dist/vite.js.map +1 -0
  28. package/package.json +18 -8
  29. package/templates/react-basic/AGENTS.md +5 -5
  30. package/templates/react-basic/vite.config.ts +4 -1
  31. package/templates/react-sync/.env.example +1 -1
  32. package/templates/react-sync/AGENTS.md +5 -5
  33. package/templates/react-sync/server.ts +8 -0
  34. package/templates/react-sync/src/vite-env.d.ts +1 -0
  35. package/templates/react-sync/vite.config.ts +4 -1
  36. package/templates/react-tailwind/AGENTS.md +5 -5
  37. package/templates/react-tailwind/vite.config.ts +10 -1
  38. package/templates/react-tailwind-sync/.env.example +1 -1
  39. package/templates/react-tailwind-sync/AGENTS.md +9 -7
  40. package/templates/react-tailwind-sync/server.ts +8 -0
  41. package/templates/react-tailwind-sync/src/App.tsx +1 -1
  42. package/templates/react-tailwind-sync/src/kora.ts +32 -0
  43. package/templates/react-tailwind-sync/src/main.tsx +1 -23
  44. package/templates/react-tailwind-sync/src/modules/todos/todo.mutations.ts +4 -8
  45. package/templates/react-tailwind-sync/src/modules/todos/todo.queries.ts +2 -2
  46. package/templates/react-tailwind-sync/src/modules/todos/useTodos.ts +1 -1
  47. package/templates/react-tailwind-sync/src/vite-env.d.ts +1 -0
  48. package/templates/react-tailwind-sync/vite.config.ts +10 -1
  49. package/templates/svelte-basic/AGENTS.md +4 -4
  50. package/templates/svelte-basic/package.json.hbs +6 -0
  51. package/templates/svelte-basic/src/App.svelte +2 -1
  52. package/templates/svelte-basic/vite.config.ts +4 -1
  53. package/templates/svelte-sync/.env.example +1 -1
  54. package/templates/svelte-sync/AGENTS.md +4 -4
  55. package/templates/svelte-sync/server.ts +8 -0
  56. package/templates/svelte-sync/src/App.svelte +2 -1
  57. package/templates/svelte-sync/vite.config.ts +4 -1
  58. package/templates/svelte-tailwind/AGENTS.md +4 -4
  59. package/templates/svelte-tailwind/package.json.hbs +7 -1
  60. package/templates/svelte-tailwind/src/App.svelte +2 -1
  61. package/templates/svelte-tailwind/vite.config.ts +10 -1
  62. package/templates/svelte-tailwind-sync/.env.example +1 -1
  63. package/templates/svelte-tailwind-sync/AGENTS.md +4 -4
  64. package/templates/svelte-tailwind-sync/package.json.hbs +1 -1
  65. package/templates/svelte-tailwind-sync/server.ts +8 -0
  66. package/templates/svelte-tailwind-sync/src/App.svelte +2 -1
  67. package/templates/svelte-tailwind-sync/vite.config.ts +10 -1
  68. package/templates/tauri-react/.env.example +1 -1
  69. package/templates/tauri-react/AGENTS.md +5 -5
  70. package/templates/tauri-react/README.md.hbs +2 -2
  71. package/templates/tauri-react/package.json.hbs +1 -1
  72. package/templates/tauri-react/server.ts +10 -2
  73. package/templates/tauri-react/src/vite-env.d.ts +1 -0
  74. package/templates/vue-basic/AGENTS.md +4 -4
  75. package/templates/vue-basic/package.json.hbs +6 -0
  76. package/templates/vue-basic/vite.config.ts +4 -1
  77. package/templates/vue-sync/.env.example +1 -1
  78. package/templates/vue-sync/AGENTS.md +4 -4
  79. package/templates/vue-sync/server.ts +8 -0
  80. package/templates/vue-sync/vite.config.ts +4 -1
  81. package/templates/vue-tailwind/AGENTS.md +4 -4
  82. package/templates/vue-tailwind/package.json.hbs +6 -0
  83. package/templates/vue-tailwind/vite.config.ts +4 -1
  84. package/templates/vue-tailwind-sync/.env.example +1 -1
  85. package/templates/vue-tailwind-sync/AGENTS.md +4 -4
  86. package/templates/vue-tailwind-sync/server.ts +8 -0
  87. package/templates/vue-tailwind-sync/vite.config.ts +4 -1
  88. package/dist/chunk-4IKCHRJ6.js.map +0 -1
  89. package/dist/chunk-G2PBYMMA.js.map +0 -1
  90. package/dist/chunk-Z7GCXMGW.js.map +0 -1
  91. package/dist/studio-server-NIFKZI4F.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -28,14 +28,16 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
30
  // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
33
  AGENTS_FRAMEWORKS: () => AGENTS_FRAMEWORKS,
34
34
  ClackPromptClient: () => ClackPromptClient,
35
35
  CliError: () => CliError,
36
36
  DEPLOY_PLATFORMS: () => DEPLOY_PLATFORMS,
37
+ DeployPlatformUnavailableError: () => DeployPlatformUnavailableError,
37
38
  DevServerError: () => DevServerError,
38
39
  FlyAdapter: () => FlyAdapter,
40
+ IMPLEMENTED_DEPLOY_PLATFORMS: () => IMPLEMENTED_DEPLOY_PLATFORMS,
39
41
  InvalidProjectError: () => InvalidProjectError,
40
42
  NodeFlyCommandRunner: () => NodeFlyCommandRunner,
41
43
  NodeRailwayCommandRunner: () => NodeRailwayCommandRunner,
@@ -73,6 +75,7 @@ __export(index_exports, {
73
75
  isDatabaseValue: () => isDatabaseValue,
74
76
  isDeployPlatform: () => isDeployPlatform,
75
77
  isFrameworkValue: () => isFrameworkValue,
78
+ isImplementedDeployPlatform: () => isImplementedDeployPlatform,
76
79
  readDeployState: () => readDeployState,
77
80
  resetDeployState: () => resetDeployState,
78
81
  resolveCreatePreferencesFlow: () => resolveCreatePreferencesFlow,
@@ -88,7 +91,7 @@ __export(index_exports, {
88
91
  writeFlyTomlArtifact: () => writeFlyTomlArtifact,
89
92
  writeRailwayJsonArtifact: () => writeRailwayJsonArtifact
90
93
  });
91
- module.exports = __toCommonJS(index_exports);
94
+ module.exports = __toCommonJS(src_exports);
92
95
 
93
96
  // src/types.ts
94
97
  var PACKAGE_MANAGERS = ["pnpm", "npm", "yarn", "bun"];
@@ -183,6 +186,20 @@ var CliError = class extends import_core.KoraError {
183
186
  this.name = "CliError";
184
187
  }
185
188
  };
189
+ var DeployPlatformUnavailableError = class extends import_core.KoraError {
190
+ constructor(platform, available) {
191
+ super(
192
+ `Deploying to "${platform}" is coming soon and not available yet. Choose one of: ${available.join(", ")}. To self-host, run the production server (\`pnpm build && pnpm start\`) in any Node 20+ environment.`,
193
+ "DEPLOY_PLATFORM_UNAVAILABLE",
194
+ { platform, available }
195
+ );
196
+ this.platform = platform;
197
+ this.available = available;
198
+ this.name = "DeployPlatformUnavailableError";
199
+ }
200
+ platform;
201
+ available;
202
+ };
186
203
  var ProjectExistsError = class extends import_core.KoraError {
187
204
  constructor(directory) {
188
205
  super(
@@ -371,7 +388,7 @@ await addTodo.mutateAsync({ title: 'x' }) // resolves with the result; throw
371
388
  const status = useSyncStatus() // status.status, status.pendingOperations
372
389
  \`\`\`
373
390
 
374
- Rules: always render \`mutation.error\` somewhere. Keep \`<StrictMode>\` in place; the hooks are StrictMode-safe. \`useQuery\` returns data synchronously from the local store, so do not add loading spinners for local reads.`,
391
+ Rules: always render \`mutation.error\` somewhere. Keep \`<StrictMode>\` in place; the hooks are StrictMode-safe. \`useQuery\` reads the local store: no network, no spinner. Its very first render returns \`[]\` before the local query has run; use \`useQueryState\` when you must tell "loading" from "no rows".`,
375
392
  vue: `## Vue bindings
376
393
 
377
394
  \`\`\`ts
@@ -384,7 +401,7 @@ addTodo.mutate({ title: 'x' }) // fire-and-forget; errors land in
384
401
  const status = useSyncStatus() // status.status, status.pendingOperations
385
402
  \`\`\`
386
403
 
387
- Rules: surface the mutation's error state in the UI. \`useQuery\` reads synchronously from the local store, so avoid loading spinners for local data. The Kora context comes from \`KoraProvider\`, wired in your app entry (for example \`src/main.ts\`).`,
404
+ Rules: surface the mutation's error state in the UI. \`useQuery\` reads the local store (no network, no spinner); the ref holds \`[]\` until the first local result. The Kora context comes from \`KoraProvider\`, wired in your app entry (for example \`src/main.ts\`).`,
388
405
  svelte: `## Svelte bindings
389
406
 
390
407
  Kora's Svelte bindings from \`@korajs/svelte\` expose \`useCollection\`, \`useQuery\`, \`useMutation\`, and \`useSyncStatus\`, wired through the provider set up in your app entry.
@@ -399,7 +416,7 @@ addTodo.mutate({ title: 'x' }) // fire-and-forget; errors land in
399
416
  const status = useSyncStatus() // readable store; read $status.status in markup
400
417
  \`\`\`
401
418
 
402
- Rules: queries are reactive stores that read synchronously from the local database, so avoid loading spinners for local reads. Mutations expose an \`error\` state that must be surfaced in the UI.`
419
+ Rules: queries are reactive stores over the local database (no network, no spinner; \`[]\` until the first local result). Mutations expose an \`error\` state that must be surfaced in the UI.`
403
420
  };
404
421
  function generateAgentsMd(framework) {
405
422
  return `# AGENTS.md
@@ -416,9 +433,9 @@ This project uses **Kora.js**, an offline-first application framework. All appli
416
433
  2. **Never fetch application data over HTTP.** Do not add REST or GraphQL calls for app data, and do not talk to the sync server directly. Read and write through Kora collections only; sync happens automatically in the background.
417
434
  3. **Await readiness before direct collection access.** Outside the UI bindings, \`await app.ready\` before calling \`app.<collection>\` methods. The framework bindings handle this for you inside components.
418
435
  4. **Offline must keep working.** Any feature you add must function with the network off. Never gate a read or write on connectivity. If you are checking \`navigator.onLine\` before a data operation, you are doing it wrong.
419
- 5. **Surface mutation errors.** Fire-and-forget \`mutate\` calls fold errors into the mutation state. Always render the mutation's \`error\`, or handle the promise from the \`mutateAsync\` variant. Silent failure is the worst failure.
436
+ 5. **Surface mutation errors.** Fire-and-forget \`mutate\` calls put errors into the mutation state. Always render the mutation's \`error\`, or handle the promise from the \`mutateAsync\` variant. Silent failure is the worst failure.
420
437
  6. **Do not add a state library for server or app data.** Kora's reactive queries are the store. Do not reach for react-query, SWR, Redux, Zustand, or similar for data that lives in a collection. Local UI state (form inputs, toggles) can use your framework's normal state tools.
421
- 7. **Do not add loading spinners for local reads.** \`useQuery\` returns data synchronously from the local store, so there is no loading state to wait on for local data.
438
+ 7. **Do not add network-style loading states for local reads.** \`useQuery\` reads the local database, which answers within a frame; its very first render returns an empty result. Use \`useQueryState\` only where "loading" and "no rows" must look different.
422
439
 
423
440
  ## Data API cheat sheet
424
441
 
@@ -456,15 +473,15 @@ export default defineSchema({
456
473
  })
457
474
  \`\`\`
458
475
 
459
- If you change collection shapes, increment \`version\` and run \`npx kora migrate\`.
476
+ If you change a collection's shape, increment \`version\` and add a \`migrations\` entry for it (\`migrate().addField(...)\`): each device migrates its local database on its next open. \`npx kora migrate\` generates the matching migration for server databases and a transform stub for clients still on the older version.
460
477
 
461
478
  ## Conflict handling
462
479
 
463
- Concurrent edits merge automatically: last-write-wins per field, add-wins for arrays, and character-level CRDT for \`t.richtext()\` fields. When a field needs domain-specific merging (counters, quantities), add a \`resolve\` function in the schema rather than writing sync logic by hand. Never write your own conflict or merge code.
480
+ Concurrent edits merge automatically: last-write-wins per field, arrays as multisets that keep every device's additions and removals, objects per top-level key, and character-level CRDT for \`t.richtext()\` fields. When a field needs domain-specific merging (counters, quantities), add a \`resolve\` function in the schema rather than writing sync logic by hand. Never write your own conflict or merge code.
464
481
 
465
482
  ## Sync and auth
466
483
 
467
- Enable sync by adding one line to \`createApp\`: \`createApp({ schema, sync: { url } })\`. When the app is offline, writes queue locally and sync when connectivity returns. If the project uses \`@korajs/auth\`, pass its client as \`createApp({ schema, sync: { url, authClient } })\`. Local writes work without sign-in; sync requires the server to accept the connection.
484
+ Enable sync with one option on \`createApp\`: \`createApp({ schema, sync: { url, autoConnect: true } })\` (without \`autoConnect\`, call \`await app.sync?.connect()\` after \`app.ready\`). When the app is offline, writes queue locally and sync when connectivity returns. If the project uses \`@korajs/auth\`, pass its binding as \`createApp({ schema, sync: { url, authClient: createKoraAuthSync({ authClient, schema }) } })\`; the server grants what each user may sync. Local writes work without sign-in; sync requires the server to accept the connection.
468
485
 
469
486
  ${FRAMEWORK_BINDINGS[framework]}
470
487
 
@@ -472,7 +489,7 @@ ${FRAMEWORK_BINDINGS[framework]}
472
489
 
473
490
  - \`npx kora dev\` runs the dev environment (app server, local sync server when configured, schema watcher).
474
491
  - \`npx kora doctor\` diagnoses a broken setup.
475
- - \`npx kora migrate\` applies a schema change to the local store.
492
+ - \`npx kora migrate\` generates a migration from a schema change (\`--apply\` runs it against a SQLite or Postgres database).
476
493
  - In a running app, the DevTools overlay (Ctrl+Shift+K, Cmd+Shift+K on macOS) inspects operations, merges, and sync status.
477
494
  `;
478
495
  }
@@ -819,6 +836,10 @@ var DEPLOY_PLATFORMS = [
819
836
  "docker",
820
837
  "kora-cloud"
821
838
  ];
839
+ var IMPLEMENTED_DEPLOY_PLATFORMS = ["fly", "railway", "aws-ecs", "aws-lightsail"];
840
+ function isImplementedDeployPlatform(platform) {
841
+ return IMPLEMENTED_DEPLOY_PLATFORMS.includes(platform);
842
+ }
822
843
  function isDeployPlatform(value) {
823
844
  return DEPLOY_PLATFORMS.includes(value);
824
845
  }
@@ -2841,6 +2862,9 @@ var deployCommand = (0, import_citty2.defineCommand)({
2841
2862
  storedPlatform: existingState?.platform,
2842
2863
  confirm: confirmMode
2843
2864
  });
2865
+ if (!isImplementedDeployPlatform(platform)) {
2866
+ throw new DeployPlatformUnavailableError(platform, IMPLEMENTED_DEPLOY_PLATFORMS);
2867
+ }
2844
2868
  const appName = resolveAppName(args.app, existingState?.appName, projectRoot, confirmMode);
2845
2869
  const region = resolveRegion(args.region, existingState?.region, confirmMode);
2846
2870
  const deployDirectory = resolveDeployDirectory(projectRoot);
@@ -2951,11 +2975,11 @@ async function resolvePlatform(options) {
2951
2975
  value: "aws-lightsail"
2952
2976
  },
2953
2977
  {
2954
- label: "Render",
2978
+ label: "Render (coming soon)",
2955
2979
  value: "render"
2956
2980
  },
2957
2981
  {
2958
- label: "Docker (self-hosted)",
2982
+ label: "Docker (self-hosted, coming soon)",
2959
2983
  value: "docker"
2960
2984
  },
2961
2985
  {
@@ -3405,8 +3429,10 @@ function getProviderConnectionStringExample(provider) {
3405
3429
  ClackPromptClient,
3406
3430
  CliError,
3407
3431
  DEPLOY_PLATFORMS,
3432
+ DeployPlatformUnavailableError,
3408
3433
  DevServerError,
3409
3434
  FlyAdapter,
3435
+ IMPLEMENTED_DEPLOY_PLATFORMS,
3410
3436
  InvalidProjectError,
3411
3437
  NodeFlyCommandRunner,
3412
3438
  NodeRailwayCommandRunner,
@@ -3444,6 +3470,7 @@ function getProviderConnectionStringExample(provider) {
3444
3470
  isDatabaseValue,
3445
3471
  isDeployPlatform,
3446
3472
  isFrameworkValue,
3473
+ isImplementedDeployPlatform,
3447
3474
  readDeployState,
3448
3475
  resetDeployState,
3449
3476
  resolveCreatePreferencesFlow,