@korajs/cli 0.1.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/bin.cjs +2170 -0
- package/dist/bin.cjs.map +1 -0
- package/dist/bin.js +1640 -0
- package/dist/bin.js.map +1 -0
- package/dist/chunk-N36PFOSA.js +103 -0
- package/dist/chunk-N36PFOSA.js.map +1 -0
- package/dist/chunk-REOTYAM6.js +370 -0
- package/dist/chunk-REOTYAM6.js.map +1 -0
- package/dist/chunk-ZVB4HAB3.js +88 -0
- package/dist/chunk-ZVB4HAB3.js.map +1 -0
- package/dist/create.cjs +313 -0
- package/dist/create.cjs.map +1 -0
- package/dist/create.js +10 -0
- package/dist/create.js.map +1 -0
- package/dist/index.cjs +218 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +72 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
- package/templates/react-basic/index.html.hbs +12 -0
- package/templates/react-basic/kora.config.ts +13 -0
- package/templates/react-basic/package.json.hbs +26 -0
- package/templates/react-basic/src/App.tsx +48 -0
- package/templates/react-basic/src/main.tsx +16 -0
- package/templates/react-basic/src/schema.ts +15 -0
- package/templates/react-basic/tsconfig.json +14 -0
- package/templates/react-basic/vite.config.ts +6 -0
- package/templates/react-sync/index.html.hbs +12 -0
- package/templates/react-sync/kora.config.ts +17 -0
- package/templates/react-sync/package.json.hbs +28 -0
- package/templates/react-sync/server.ts +11 -0
- package/templates/react-sync/src/App.tsx +50 -0
- package/templates/react-sync/src/main.tsx +24 -0
- package/templates/react-sync/src/schema.ts +15 -0
- package/templates/react-sync/tsconfig.json +14 -0
- package/templates/react-sync/vite.config.ts +6 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { KoraError, SchemaDefinition } from '@korajs/core';
|
|
2
|
+
|
|
3
|
+
/** Supported package managers */
|
|
4
|
+
declare const PACKAGE_MANAGERS: readonly ["pnpm", "npm", "yarn", "bun"];
|
|
5
|
+
type PackageManager = (typeof PACKAGE_MANAGERS)[number];
|
|
6
|
+
/** Available project templates */
|
|
7
|
+
declare const TEMPLATES: readonly ["react-basic", "react-sync"];
|
|
8
|
+
type TemplateName = (typeof TEMPLATES)[number];
|
|
9
|
+
/** Metadata for a project template */
|
|
10
|
+
interface TemplateInfo {
|
|
11
|
+
name: TemplateName;
|
|
12
|
+
label: string;
|
|
13
|
+
description: string;
|
|
14
|
+
}
|
|
15
|
+
/** Available templates with their descriptions */
|
|
16
|
+
declare const TEMPLATE_INFO: readonly TemplateInfo[];
|
|
17
|
+
/** Variables available for template substitution */
|
|
18
|
+
interface TemplateContext {
|
|
19
|
+
projectName: string;
|
|
20
|
+
packageManager: PackageManager;
|
|
21
|
+
koraVersion: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Base error class for all CLI errors.
|
|
26
|
+
*/
|
|
27
|
+
declare class CliError extends KoraError {
|
|
28
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Thrown when the target project directory already exists.
|
|
32
|
+
*/
|
|
33
|
+
declare class ProjectExistsError extends KoraError {
|
|
34
|
+
readonly directory: string;
|
|
35
|
+
constructor(directory: string);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Thrown when a schema file cannot be found in the project.
|
|
39
|
+
*/
|
|
40
|
+
declare class SchemaNotFoundError extends KoraError {
|
|
41
|
+
readonly searchedPaths: string[];
|
|
42
|
+
constructor(searchedPaths: string[]);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Thrown when a command is run outside a valid Kora project.
|
|
46
|
+
*/
|
|
47
|
+
declare class InvalidProjectError extends KoraError {
|
|
48
|
+
readonly directory: string;
|
|
49
|
+
constructor(directory: string);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Thrown when a required local dev server binary cannot be found.
|
|
53
|
+
*/
|
|
54
|
+
declare class DevServerError extends KoraError {
|
|
55
|
+
readonly binary: string;
|
|
56
|
+
readonly searchPath: string;
|
|
57
|
+
constructor(binary: string, searchPath: string);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Generates TypeScript interfaces from a SchemaDefinition.
|
|
62
|
+
* For each collection, produces three interfaces:
|
|
63
|
+
* - {Name}Record: full record type (all fields + id)
|
|
64
|
+
* - {Name}InsertInput: insert input (omit auto fields, optional for fields with defaults)
|
|
65
|
+
* - {Name}UpdateInput: update input (all non-auto fields optional)
|
|
66
|
+
*
|
|
67
|
+
* @param schema - A validated SchemaDefinition from defineSchema()
|
|
68
|
+
* @returns A complete TypeScript file as a string
|
|
69
|
+
*/
|
|
70
|
+
declare function generateTypes(schema: SchemaDefinition): string;
|
|
71
|
+
|
|
72
|
+
export { CliError, DevServerError, InvalidProjectError, PACKAGE_MANAGERS, type PackageManager, ProjectExistsError, SchemaNotFoundError, TEMPLATES, TEMPLATE_INFO, type TemplateContext, type TemplateInfo, type TemplateName, generateTypes };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { KoraError, SchemaDefinition } from '@korajs/core';
|
|
2
|
+
|
|
3
|
+
/** Supported package managers */
|
|
4
|
+
declare const PACKAGE_MANAGERS: readonly ["pnpm", "npm", "yarn", "bun"];
|
|
5
|
+
type PackageManager = (typeof PACKAGE_MANAGERS)[number];
|
|
6
|
+
/** Available project templates */
|
|
7
|
+
declare const TEMPLATES: readonly ["react-basic", "react-sync"];
|
|
8
|
+
type TemplateName = (typeof TEMPLATES)[number];
|
|
9
|
+
/** Metadata for a project template */
|
|
10
|
+
interface TemplateInfo {
|
|
11
|
+
name: TemplateName;
|
|
12
|
+
label: string;
|
|
13
|
+
description: string;
|
|
14
|
+
}
|
|
15
|
+
/** Available templates with their descriptions */
|
|
16
|
+
declare const TEMPLATE_INFO: readonly TemplateInfo[];
|
|
17
|
+
/** Variables available for template substitution */
|
|
18
|
+
interface TemplateContext {
|
|
19
|
+
projectName: string;
|
|
20
|
+
packageManager: PackageManager;
|
|
21
|
+
koraVersion: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Base error class for all CLI errors.
|
|
26
|
+
*/
|
|
27
|
+
declare class CliError extends KoraError {
|
|
28
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Thrown when the target project directory already exists.
|
|
32
|
+
*/
|
|
33
|
+
declare class ProjectExistsError extends KoraError {
|
|
34
|
+
readonly directory: string;
|
|
35
|
+
constructor(directory: string);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Thrown when a schema file cannot be found in the project.
|
|
39
|
+
*/
|
|
40
|
+
declare class SchemaNotFoundError extends KoraError {
|
|
41
|
+
readonly searchedPaths: string[];
|
|
42
|
+
constructor(searchedPaths: string[]);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Thrown when a command is run outside a valid Kora project.
|
|
46
|
+
*/
|
|
47
|
+
declare class InvalidProjectError extends KoraError {
|
|
48
|
+
readonly directory: string;
|
|
49
|
+
constructor(directory: string);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Thrown when a required local dev server binary cannot be found.
|
|
53
|
+
*/
|
|
54
|
+
declare class DevServerError extends KoraError {
|
|
55
|
+
readonly binary: string;
|
|
56
|
+
readonly searchPath: string;
|
|
57
|
+
constructor(binary: string, searchPath: string);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Generates TypeScript interfaces from a SchemaDefinition.
|
|
62
|
+
* For each collection, produces three interfaces:
|
|
63
|
+
* - {Name}Record: full record type (all fields + id)
|
|
64
|
+
* - {Name}InsertInput: insert input (omit auto fields, optional for fields with defaults)
|
|
65
|
+
* - {Name}UpdateInput: update input (all non-auto fields optional)
|
|
66
|
+
*
|
|
67
|
+
* @param schema - A validated SchemaDefinition from defineSchema()
|
|
68
|
+
* @returns A complete TypeScript file as a string
|
|
69
|
+
*/
|
|
70
|
+
declare function generateTypes(schema: SchemaDefinition): string;
|
|
71
|
+
|
|
72
|
+
export { CliError, DevServerError, InvalidProjectError, PACKAGE_MANAGERS, type PackageManager, ProjectExistsError, SchemaNotFoundError, TEMPLATES, TEMPLATE_INFO, type TemplateContext, type TemplateInfo, type TemplateName, generateTypes };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
generateTypes
|
|
4
|
+
} from "./chunk-N36PFOSA.js";
|
|
5
|
+
import {
|
|
6
|
+
CliError,
|
|
7
|
+
DevServerError,
|
|
8
|
+
InvalidProjectError,
|
|
9
|
+
PACKAGE_MANAGERS,
|
|
10
|
+
ProjectExistsError,
|
|
11
|
+
SchemaNotFoundError,
|
|
12
|
+
TEMPLATES,
|
|
13
|
+
TEMPLATE_INFO
|
|
14
|
+
} from "./chunk-ZVB4HAB3.js";
|
|
15
|
+
export {
|
|
16
|
+
CliError,
|
|
17
|
+
DevServerError,
|
|
18
|
+
InvalidProjectError,
|
|
19
|
+
PACKAGE_MANAGERS,
|
|
20
|
+
ProjectExistsError,
|
|
21
|
+
SchemaNotFoundError,
|
|
22
|
+
TEMPLATES,
|
|
23
|
+
TEMPLATE_INFO,
|
|
24
|
+
generateTypes
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@korajs/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Kora.js CLI tooling and project scaffolding",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"kora": "./dist/bin.js",
|
|
11
|
+
"create-kora-app": "./dist/create.js"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"require": {
|
|
20
|
+
"types": "./dist/index.d.cts",
|
|
21
|
+
"default": "./dist/index.cjs"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"templates"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"citty": "^0.1.6",
|
|
31
|
+
"@korajs/core": "0.1.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"typescript": "^5.7.3",
|
|
35
|
+
"tsup": "^8.3.6",
|
|
36
|
+
"vitest": "^3.0.4"
|
|
37
|
+
},
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsup",
|
|
41
|
+
"dev": "tsup --watch",
|
|
42
|
+
"test": "vitest run",
|
|
43
|
+
"test:watch": "vitest",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"lint": "biome check src/ tests/",
|
|
46
|
+
"clean": "rm -rf dist .turbo coverage"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>{{projectName}}</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "kora dev",
|
|
8
|
+
"build": "tsc && vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"korajs": "{{koraVersion}}",
|
|
13
|
+
"@korajs/react": "{{koraVersion}}",
|
|
14
|
+
"react": "^19.0.0",
|
|
15
|
+
"react-dom": "^19.0.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@korajs/cli": "{{koraVersion}}",
|
|
19
|
+
"@types/react": "^19.0.0",
|
|
20
|
+
"@types/react-dom": "^19.0.0",
|
|
21
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
22
|
+
"tsx": "^4.19.0",
|
|
23
|
+
"typescript": "^5.7.0",
|
|
24
|
+
"vite": "^6.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useQuery, useMutation, useCollection } from '@korajs/react'
|
|
2
|
+
|
|
3
|
+
export function App() {
|
|
4
|
+
const todos = useCollection('todos')
|
|
5
|
+
const activeTodos = useQuery(todos.where({ completed: false }))
|
|
6
|
+
const { mutate: addTodo } = useMutation(
|
|
7
|
+
(data: { title: string }) => todos.insert(data)
|
|
8
|
+
)
|
|
9
|
+
const { mutate: toggleTodo } = useMutation(
|
|
10
|
+
(id: string, data: { completed: boolean }) => todos.update(id, data)
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div style={{ maxWidth: 600, margin: '0 auto', padding: 20 }}>
|
|
15
|
+
<h1>Kora Todo App</h1>
|
|
16
|
+
|
|
17
|
+
<form
|
|
18
|
+
onSubmit={async (e) => {
|
|
19
|
+
e.preventDefault()
|
|
20
|
+
const form = e.currentTarget
|
|
21
|
+
const input = form.elements.namedItem('title') as HTMLInputElement
|
|
22
|
+
if (input.value.trim()) {
|
|
23
|
+
addTodo({ title: input.value.trim() })
|
|
24
|
+
input.value = ''
|
|
25
|
+
}
|
|
26
|
+
}}
|
|
27
|
+
>
|
|
28
|
+
<input name="title" placeholder="What needs to be done?" />
|
|
29
|
+
<button type="submit">Add</button>
|
|
30
|
+
</form>
|
|
31
|
+
|
|
32
|
+
<ul>
|
|
33
|
+
{activeTodos.map((todo) => (
|
|
34
|
+
<li key={todo.id}>
|
|
35
|
+
<label>
|
|
36
|
+
<input
|
|
37
|
+
type="checkbox"
|
|
38
|
+
checked={!!todo.completed}
|
|
39
|
+
onChange={() => toggleTodo(todo.id, { completed: !todo.completed })}
|
|
40
|
+
/>
|
|
41
|
+
{String(todo.title)}
|
|
42
|
+
</label>
|
|
43
|
+
</li>
|
|
44
|
+
))}
|
|
45
|
+
</ul>
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createApp } from 'korajs'
|
|
2
|
+
import { KoraProvider } from '@korajs/react'
|
|
3
|
+
import { StrictMode } from 'react'
|
|
4
|
+
import { createRoot } from 'react-dom/client'
|
|
5
|
+
import schema from './schema'
|
|
6
|
+
import { App } from './App'
|
|
7
|
+
|
|
8
|
+
const app = createApp({ schema })
|
|
9
|
+
|
|
10
|
+
createRoot(document.getElementById('root')!).render(
|
|
11
|
+
<StrictMode>
|
|
12
|
+
<KoraProvider app={app}>
|
|
13
|
+
<App />
|
|
14
|
+
</KoraProvider>
|
|
15
|
+
</StrictMode>,
|
|
16
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineSchema, t } from 'korajs'
|
|
2
|
+
|
|
3
|
+
export default defineSchema({
|
|
4
|
+
version: 1,
|
|
5
|
+
collections: {
|
|
6
|
+
todos: {
|
|
7
|
+
fields: {
|
|
8
|
+
title: t.string(),
|
|
9
|
+
completed: t.boolean().default(false),
|
|
10
|
+
createdAt: t.timestamp().auto(),
|
|
11
|
+
},
|
|
12
|
+
indexes: ['completed'],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"jsx": "react-jsx",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noUncheckedIndexedAccess": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"outDir": "dist"
|
|
12
|
+
},
|
|
13
|
+
"include": ["src"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>{{projectName}}</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineConfig } from 'korajs/config'
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
schema: './src/schema.ts',
|
|
5
|
+
dev: {
|
|
6
|
+
port: 5173,
|
|
7
|
+
sync: {
|
|
8
|
+
enabled: true,
|
|
9
|
+
port: 3001,
|
|
10
|
+
store: 'memory',
|
|
11
|
+
},
|
|
12
|
+
watch: {
|
|
13
|
+
enabled: true,
|
|
14
|
+
debounceMs: 300,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "kora dev",
|
|
8
|
+
"dev:server": "tsx server.ts",
|
|
9
|
+
"build": "tsc && vite build",
|
|
10
|
+
"preview": "vite preview"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"korajs": "{{koraVersion}}",
|
|
14
|
+
"@korajs/react": "{{koraVersion}}",
|
|
15
|
+
"react": "^19.0.0",
|
|
16
|
+
"react-dom": "^19.0.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@korajs/cli": "{{koraVersion}}",
|
|
20
|
+
"@korajs/server": "{{koraVersion}}",
|
|
21
|
+
"@types/react": "^19.0.0",
|
|
22
|
+
"@types/react-dom": "^19.0.0",
|
|
23
|
+
"@vitejs/plugin-react": "^4.3.0",
|
|
24
|
+
"tsx": "^4.19.0",
|
|
25
|
+
"typescript": "^5.7.0",
|
|
26
|
+
"vite": "^6.0.0"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createKoraServer, MemoryServerStore } from '@korajs/server'
|
|
2
|
+
|
|
3
|
+
const store = new MemoryServerStore()
|
|
4
|
+
const server = createKoraServer({
|
|
5
|
+
store,
|
|
6
|
+
port: 3001,
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
server.start().then(() => {
|
|
10
|
+
console.log('Kora sync server running on ws://localhost:3001')
|
|
11
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useQuery, useMutation, useSyncStatus, useCollection } from '@korajs/react'
|
|
2
|
+
|
|
3
|
+
export function App() {
|
|
4
|
+
const todos = useCollection('todos')
|
|
5
|
+
const activeTodos = useQuery(todos.where({ completed: false }))
|
|
6
|
+
const { mutate: addTodo } = useMutation(
|
|
7
|
+
(data: { title: string }) => todos.insert(data)
|
|
8
|
+
)
|
|
9
|
+
const { mutate: toggleTodo } = useMutation(
|
|
10
|
+
(id: string, data: { completed: boolean }) => todos.update(id, data)
|
|
11
|
+
)
|
|
12
|
+
const status = useSyncStatus()
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div style={{ maxWidth: 600, margin: '0 auto', padding: 20 }}>
|
|
16
|
+
<h1>Kora Todo App</h1>
|
|
17
|
+
<p>Status: {status.status}</p>
|
|
18
|
+
|
|
19
|
+
<form
|
|
20
|
+
onSubmit={async (e) => {
|
|
21
|
+
e.preventDefault()
|
|
22
|
+
const form = e.currentTarget
|
|
23
|
+
const input = form.elements.namedItem('title') as HTMLInputElement
|
|
24
|
+
if (input.value.trim()) {
|
|
25
|
+
addTodo({ title: input.value.trim() })
|
|
26
|
+
input.value = ''
|
|
27
|
+
}
|
|
28
|
+
}}
|
|
29
|
+
>
|
|
30
|
+
<input name="title" placeholder="What needs to be done?" />
|
|
31
|
+
<button type="submit">Add</button>
|
|
32
|
+
</form>
|
|
33
|
+
|
|
34
|
+
<ul>
|
|
35
|
+
{activeTodos.map((todo) => (
|
|
36
|
+
<li key={todo.id}>
|
|
37
|
+
<label>
|
|
38
|
+
<input
|
|
39
|
+
type="checkbox"
|
|
40
|
+
checked={!!todo.completed}
|
|
41
|
+
onChange={() => toggleTodo(todo.id, { completed: !todo.completed })}
|
|
42
|
+
/>
|
|
43
|
+
{String(todo.title)}
|
|
44
|
+
</label>
|
|
45
|
+
</li>
|
|
46
|
+
))}
|
|
47
|
+
</ul>
|
|
48
|
+
</div>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createApp } from 'korajs'
|
|
2
|
+
import { KoraProvider } from '@korajs/react'
|
|
3
|
+
import { StrictMode } from 'react'
|
|
4
|
+
import { createRoot } from 'react-dom/client'
|
|
5
|
+
import schema from './schema'
|
|
6
|
+
import { App } from './App'
|
|
7
|
+
|
|
8
|
+
const app = createApp({
|
|
9
|
+
schema,
|
|
10
|
+
sync: {
|
|
11
|
+
url: 'ws://localhost:3001',
|
|
12
|
+
},
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
// Connect to sync server once the app is ready
|
|
16
|
+
app.ready.then(() => app.sync?.connect())
|
|
17
|
+
|
|
18
|
+
createRoot(document.getElementById('root')!).render(
|
|
19
|
+
<StrictMode>
|
|
20
|
+
<KoraProvider app={app}>
|
|
21
|
+
<App />
|
|
22
|
+
</KoraProvider>
|
|
23
|
+
</StrictMode>,
|
|
24
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineSchema, t } from 'korajs'
|
|
2
|
+
|
|
3
|
+
export default defineSchema({
|
|
4
|
+
version: 1,
|
|
5
|
+
collections: {
|
|
6
|
+
todos: {
|
|
7
|
+
fields: {
|
|
8
|
+
title: t.string(),
|
|
9
|
+
completed: t.boolean().default(false),
|
|
10
|
+
createdAt: t.timestamp().auto(),
|
|
11
|
+
},
|
|
12
|
+
indexes: ['completed'],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"jsx": "react-jsx",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noUncheckedIndexedAccess": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"outDir": "dist"
|
|
12
|
+
},
|
|
13
|
+
"include": ["src"]
|
|
14
|
+
}
|