@kokimoki/kit 1.6.6 → 1.7.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 +76 -0
- package/dist/api.d.ts +63 -0
- package/dist/api.js +95 -0
- package/dist/credentials.d.ts +25 -0
- package/dist/credentials.js +44 -0
- package/dist/dev-app.d.ts +57 -0
- package/dist/dev-app.js +271 -0
- package/dist/dev-frame/index.d.ts +5 -0
- package/dist/dev-frame/index.js +9 -0
- package/dist/dev-frame/render-dev-frame.d.ts +30 -0
- package/dist/dev-frame/render-dev-frame.js +160 -0
- package/dist/dev-frame/styles.d.ts +4 -0
- package/dist/dev-frame/styles.js +191 -0
- package/dist/dev-i18n.d.ts +56 -0
- package/dist/dev-i18n.js +164 -0
- package/dist/dev-overlays.d.ts +19 -0
- package/dist/dev-overlays.js +300 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +7 -0
- package/dist/kokimoki-kit-plugin.d.ts +47 -4
- package/dist/kokimoki-kit-plugin.js +403 -82
- package/dist/preprocess-style.js +13 -14
- package/dist/preprocess-style.spec.js +1 -1
- package/dist/production-loading-screen.d.ts +20 -0
- package/dist/production-loading-screen.js +123 -0
- package/dist/schema-builder.d.ts +89 -74
- package/dist/schema-builder.js +149 -132
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/zod.d.ts +1 -0
- package/dist/zod.js +5 -0
- package/docs/kokimoki-kit.instructions.md +341 -0
- package/llms.txt +46 -0
- package/package.json +10 -3
package/dist/schema-builder.js
CHANGED
|
@@ -1,166 +1,183 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Form =
|
|
3
|
+
exports.Form =
|
|
4
|
+
exports.FormArray =
|
|
5
|
+
exports.FormGroup =
|
|
6
|
+
exports.FloatField =
|
|
7
|
+
exports.IntegerField =
|
|
8
|
+
exports.EnumField =
|
|
9
|
+
exports.TextField =
|
|
10
|
+
exports.ImageField =
|
|
11
|
+
exports.ConstField =
|
|
12
|
+
exports.BooleanField =
|
|
13
|
+
exports.Field =
|
|
14
|
+
void 0;
|
|
4
15
|
const defaultFieldOptions = {};
|
|
5
16
|
class Field {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
17
|
+
options;
|
|
18
|
+
constructor(options) {
|
|
19
|
+
this.options = options;
|
|
20
|
+
}
|
|
10
21
|
}
|
|
11
22
|
exports.Field = Field;
|
|
12
23
|
class BooleanField extends Field {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
value;
|
|
25
|
+
constructor(value, options = defaultFieldOptions) {
|
|
26
|
+
super(options);
|
|
27
|
+
this.value = value;
|
|
28
|
+
}
|
|
29
|
+
get schema() {
|
|
30
|
+
return {
|
|
31
|
+
type: "boolean",
|
|
32
|
+
default: this.value,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
24
35
|
}
|
|
25
36
|
exports.BooleanField = BooleanField;
|
|
26
37
|
class ConstField extends Field {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
value;
|
|
39
|
+
constructor(value, options = defaultFieldOptions) {
|
|
40
|
+
super(options);
|
|
41
|
+
this.value = value;
|
|
42
|
+
}
|
|
43
|
+
get schema() {
|
|
44
|
+
return {
|
|
45
|
+
const: this.value,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
37
48
|
}
|
|
38
49
|
exports.ConstField = ConstField;
|
|
39
50
|
class ImageField extends Field {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
value;
|
|
52
|
+
constructor(value, options = defaultFieldOptions) {
|
|
53
|
+
super(options);
|
|
54
|
+
this.value = value;
|
|
55
|
+
}
|
|
56
|
+
get schema() {
|
|
57
|
+
return {
|
|
58
|
+
type: "string",
|
|
59
|
+
default: this.value,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
51
62
|
}
|
|
52
63
|
exports.ImageField = ImageField;
|
|
53
64
|
class TextField extends Field {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
value;
|
|
66
|
+
constructor(value, options = defaultFieldOptions) {
|
|
67
|
+
super(options);
|
|
68
|
+
this.value = value;
|
|
69
|
+
}
|
|
70
|
+
get schema() {
|
|
71
|
+
return {
|
|
72
|
+
type: "string",
|
|
73
|
+
default: this.value,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
65
76
|
}
|
|
66
77
|
exports.TextField = TextField;
|
|
67
78
|
class EnumField extends Field {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
enumValues;
|
|
80
|
+
value;
|
|
81
|
+
constructor(enumValues, value, options = defaultFieldOptions) {
|
|
82
|
+
super(options);
|
|
83
|
+
this.enumValues = enumValues;
|
|
84
|
+
this.value = value;
|
|
85
|
+
}
|
|
86
|
+
get schema() {
|
|
87
|
+
return {
|
|
88
|
+
enum: Object.keys(this.enumValues),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
80
91
|
}
|
|
81
92
|
exports.EnumField = EnumField;
|
|
82
93
|
class IntegerField extends Field {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
+
value;
|
|
95
|
+
constructor(value, options = defaultFieldOptions) {
|
|
96
|
+
super(options);
|
|
97
|
+
this.value = value;
|
|
98
|
+
}
|
|
99
|
+
get schema() {
|
|
100
|
+
return {
|
|
101
|
+
type: "integer",
|
|
102
|
+
default: this.value,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
94
105
|
}
|
|
95
106
|
exports.IntegerField = IntegerField;
|
|
96
107
|
class FloatField extends Field {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
+
value;
|
|
109
|
+
constructor(value, options = defaultFieldOptions) {
|
|
110
|
+
super(options);
|
|
111
|
+
this.value = value;
|
|
112
|
+
}
|
|
113
|
+
get schema() {
|
|
114
|
+
return {
|
|
115
|
+
type: "number",
|
|
116
|
+
default: this.value,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
108
119
|
}
|
|
109
120
|
exports.FloatField = FloatField;
|
|
110
121
|
class FormGroup extends Field {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
122
|
+
requiredFields;
|
|
123
|
+
optionalFields;
|
|
124
|
+
constructor(
|
|
125
|
+
requiredFields,
|
|
126
|
+
optionalFields = {},
|
|
127
|
+
options = defaultFieldOptions,
|
|
128
|
+
) {
|
|
129
|
+
super(options);
|
|
130
|
+
this.requiredFields = requiredFields;
|
|
131
|
+
this.optionalFields = optionalFields;
|
|
132
|
+
}
|
|
133
|
+
get value() {
|
|
134
|
+
const value = Object.entries(this.requiredFields).reduce(
|
|
135
|
+
(acc, [key, field]) => {
|
|
136
|
+
acc[key] = field.value;
|
|
137
|
+
return acc;
|
|
138
|
+
},
|
|
139
|
+
{},
|
|
140
|
+
);
|
|
141
|
+
Object.entries(this.optionalFields).forEach(([key, field]) => {
|
|
142
|
+
if (field.value !== undefined) {
|
|
143
|
+
value[key] = field.value;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
get schema() {
|
|
149
|
+
const properties = {};
|
|
150
|
+
Object.entries(this.requiredFields).forEach(([key, field]) => {
|
|
151
|
+
properties[key] = field.schema;
|
|
152
|
+
});
|
|
153
|
+
Object.entries(this.optionalFields).forEach(([key, field]) => {
|
|
154
|
+
properties[key] = field.schema;
|
|
155
|
+
});
|
|
156
|
+
return {
|
|
157
|
+
type: "object",
|
|
158
|
+
properties,
|
|
159
|
+
required: Object.keys(this.requiredFields),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
144
162
|
}
|
|
145
163
|
exports.FormGroup = FormGroup;
|
|
146
164
|
class FormArray extends Field {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
165
|
+
factory;
|
|
166
|
+
value;
|
|
167
|
+
constructor(factory, value, options = defaultFieldOptions) {
|
|
168
|
+
super(options);
|
|
169
|
+
this.factory = factory;
|
|
170
|
+
this.value = value;
|
|
171
|
+
}
|
|
172
|
+
get schema() {
|
|
173
|
+
const field = this.factory();
|
|
174
|
+
return {
|
|
175
|
+
type: "array",
|
|
176
|
+
items: field.schema,
|
|
177
|
+
default: this.value,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
162
180
|
}
|
|
163
181
|
exports.FormArray = FormArray;
|
|
164
|
-
class Form extends FormGroup {
|
|
165
|
-
}
|
|
182
|
+
class Form extends FormGroup {}
|
|
166
183
|
exports.Form = Form;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const KOKIMOKI_KIT_VERSION = "1.
|
|
1
|
+
export declare const KOKIMOKI_KIT_VERSION = "1.7.0";
|
package/dist/version.js
CHANGED
package/dist/zod.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { z, type ZodType } from "zod/v4";
|
package/dist/zod.js
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Vite plugin and development tools for Kokimoki apps
|
|
3
|
+
applyTo: "**/vite.config.{ts,js,mts,mjs}"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Kokimoki Kit
|
|
7
|
+
|
|
8
|
+
The `@kokimoki/kit` package provides the Vite plugin and development tools for building Kokimoki apps.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @kokimoki/kit
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Plugin Configuration
|
|
17
|
+
|
|
18
|
+
Add the plugin to your `vite.config.ts`:
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { defineConfig } from "vite";
|
|
22
|
+
import { kokimokiKitPlugin } from "@kokimoki/kit";
|
|
23
|
+
import { z } from "@kokimoki/kit";
|
|
24
|
+
|
|
25
|
+
export default defineConfig({
|
|
26
|
+
plugins: [
|
|
27
|
+
kokimokiKitPlugin({
|
|
28
|
+
// Required: Your concept ID from Kokimoki
|
|
29
|
+
conceptId: "your-concept-id",
|
|
30
|
+
|
|
31
|
+
// Required: Deploy configurations
|
|
32
|
+
deployCodes: [
|
|
33
|
+
{
|
|
34
|
+
name: "default",
|
|
35
|
+
description: "Default game mode",
|
|
36
|
+
clientContext: { mode: "standard" },
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "tournament",
|
|
40
|
+
description: "Tournament mode with stricter rules",
|
|
41
|
+
clientContext: { mode: "tournament", maxPlayers: 100 },
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
|
|
45
|
+
// Optional: Project config schema (validated in admin panel)
|
|
46
|
+
schema: z.object({
|
|
47
|
+
title: z.string(),
|
|
48
|
+
maxPlayers: z.number().min(2).max(100),
|
|
49
|
+
timeLimit: z.number().optional(),
|
|
50
|
+
}),
|
|
51
|
+
|
|
52
|
+
// Optional: Store schemas for validation
|
|
53
|
+
stores: [
|
|
54
|
+
{
|
|
55
|
+
pattern: "game",
|
|
56
|
+
schema: z.object({
|
|
57
|
+
status: z.enum(["waiting", "playing", "finished"]),
|
|
58
|
+
round: z.number(),
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
pattern: "player-*",
|
|
63
|
+
schema: z.object({
|
|
64
|
+
name: z.string(),
|
|
65
|
+
score: z.number(),
|
|
66
|
+
}),
|
|
67
|
+
local: true, // Local store (per-client)
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
|
|
71
|
+
// Optional: i18n configuration
|
|
72
|
+
i18nPath: "./src/i18n",
|
|
73
|
+
i18nPrimaryLng: "en", // Source language for AI translations
|
|
74
|
+
|
|
75
|
+
// Optional: Custom API endpoint
|
|
76
|
+
endpoint: "https://api.kokimoki.com",
|
|
77
|
+
host: "y-wss.kokimoki.com",
|
|
78
|
+
|
|
79
|
+
// Optional: Dev view layout (see Dev Frame section)
|
|
80
|
+
devView: [
|
|
81
|
+
[{ label: "host", clientContext: { mode: "host" } }],
|
|
82
|
+
[
|
|
83
|
+
{ label: "player1", clientContext: { mode: "player" } },
|
|
84
|
+
{ label: "player2", clientContext: { mode: "player" } },
|
|
85
|
+
],
|
|
86
|
+
],
|
|
87
|
+
}),
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Configuration Options
|
|
93
|
+
|
|
94
|
+
### Required Options
|
|
95
|
+
|
|
96
|
+
| Option | Type | Description |
|
|
97
|
+
| ------------- | -------- | --------------------------------- |
|
|
98
|
+
| `conceptId` | `string` | Your concept ID from Kokimoki |
|
|
99
|
+
| `deployCodes` | `array` | List of deployment configurations |
|
|
100
|
+
|
|
101
|
+
### Optional Options
|
|
102
|
+
|
|
103
|
+
| Option | Type | Description |
|
|
104
|
+
| -------------------------- | ---------------- | -------------------------------------------------- |
|
|
105
|
+
| `schema` | `ZodType` | Zod schema for project configuration |
|
|
106
|
+
| `stores` | `array` | Store definitions with patterns and schemas |
|
|
107
|
+
| `i18nPath` | `string` | Path to i18n folder (e.g., `./src/i18n`) |
|
|
108
|
+
| `i18nPrimaryLng` | `string` | Source language code (default: `"en"`) |
|
|
109
|
+
| `endpoint` | `string` | API endpoint (default: `https://api.kokimoki.com`) |
|
|
110
|
+
| `host` | `string` | WebSocket host (default: `y-wss.kokimoki.com`) |
|
|
111
|
+
| `devView` | `array \| false` | Dev frame layout or `false` to disable |
|
|
112
|
+
| `defaultProjectConfigPath` | `string` | Path to default project config file |
|
|
113
|
+
| `defaultProjectStylePath` | `string` | Path to default project style file |
|
|
114
|
+
|
|
115
|
+
## Dev Frame
|
|
116
|
+
|
|
117
|
+
The dev frame provides a multi-window view for testing different player modes simultaneously during development.
|
|
118
|
+
|
|
119
|
+
### Configuration
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
devView: [
|
|
123
|
+
// Row 1: Host and presenter
|
|
124
|
+
[
|
|
125
|
+
{ label: "host", clientContext: { mode: "host", playerCode: "admin" } },
|
|
126
|
+
{ label: "presenter", clientContext: { mode: "presenter" } },
|
|
127
|
+
],
|
|
128
|
+
// Row 2: Three players
|
|
129
|
+
[
|
|
130
|
+
{ label: "player1", clientContext: { mode: "player" } },
|
|
131
|
+
{ label: "player2", clientContext: { mode: "player" } },
|
|
132
|
+
{ label: "player3", clientContext: { mode: "player" } },
|
|
133
|
+
],
|
|
134
|
+
];
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### DevFrameCell Interface
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
interface DevFrameCell {
|
|
141
|
+
/** Label shown in the frame header (must be unique) */
|
|
142
|
+
label: string;
|
|
143
|
+
/** Client context passed to the app via URL */
|
|
144
|
+
clientContext: unknown;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Features
|
|
149
|
+
|
|
150
|
+
- **Grid layout**: Each inner array is a row of frames
|
|
151
|
+
- **Unique labels**: Each cell must have a unique label
|
|
152
|
+
- **New tab button**: Open any frame in a separate tab
|
|
153
|
+
- **Reset button**: Clear frame's local storage and reload
|
|
154
|
+
- **Error overlay**: Shows errors with reload option
|
|
155
|
+
|
|
156
|
+
### Disabling Dev Frame
|
|
157
|
+
|
|
158
|
+
Set `devView: false` to disable the dev frame entirely:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
kokimokiKitPlugin({
|
|
162
|
+
conceptId: "...",
|
|
163
|
+
deployCodes: [...],
|
|
164
|
+
devView: false,
|
|
165
|
+
})
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Store Schemas
|
|
169
|
+
|
|
170
|
+
Define schemas to validate store state during development:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
stores: [
|
|
174
|
+
// Global store - shared across all clients
|
|
175
|
+
{
|
|
176
|
+
pattern: "game",
|
|
177
|
+
schema: z.object({
|
|
178
|
+
status: z.enum(["waiting", "playing", "finished"]),
|
|
179
|
+
players: z.record(
|
|
180
|
+
z.string(),
|
|
181
|
+
z.object({
|
|
182
|
+
name: z.string(),
|
|
183
|
+
score: z.number(),
|
|
184
|
+
})
|
|
185
|
+
),
|
|
186
|
+
}),
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
// Wildcard pattern - matches player-abc123, player-xyz789, etc.
|
|
190
|
+
{
|
|
191
|
+
pattern: "player-*",
|
|
192
|
+
schema: z.object({
|
|
193
|
+
name: z.string(),
|
|
194
|
+
avatar: z.string().optional(),
|
|
195
|
+
}),
|
|
196
|
+
local: true, // Local store (client-specific)
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
// Dynamic stores - chat rooms, teams, etc.
|
|
200
|
+
{
|
|
201
|
+
pattern: "chat-*",
|
|
202
|
+
schema: z.object({
|
|
203
|
+
messages: z.record(
|
|
204
|
+
z.string(),
|
|
205
|
+
z.object({
|
|
206
|
+
text: z.string(),
|
|
207
|
+
sender: z.string(),
|
|
208
|
+
})
|
|
209
|
+
),
|
|
210
|
+
}),
|
|
211
|
+
},
|
|
212
|
+
];
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## i18n Integration
|
|
216
|
+
|
|
217
|
+
The plugin syncs translations to your dev app automatically.
|
|
218
|
+
|
|
219
|
+
### Folder Structure
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
src/i18n/
|
|
223
|
+
├── en/
|
|
224
|
+
│ ├── ui.json
|
|
225
|
+
│ └── game.json
|
|
226
|
+
├── et/
|
|
227
|
+
│ ├── ui.json
|
|
228
|
+
│ └── game.json
|
|
229
|
+
└── de/
|
|
230
|
+
├── ui.json
|
|
231
|
+
└── game.json
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Configuration
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
kokimokiKitPlugin({
|
|
238
|
+
// ...
|
|
239
|
+
i18nPath: "./src/i18n",
|
|
240
|
+
i18nPrimaryLng: "en", // Source language for AI translations
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### HMR Support
|
|
245
|
+
|
|
246
|
+
- Translation files are watched for changes
|
|
247
|
+
- Changes are synced to the dev app in real-time
|
|
248
|
+
- No need to restart the dev server
|
|
249
|
+
|
|
250
|
+
## Zod Re-export
|
|
251
|
+
|
|
252
|
+
The kit re-exports Zod for convenience:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { z } from "@kokimoki/kit";
|
|
256
|
+
|
|
257
|
+
const mySchema = z.object({
|
|
258
|
+
name: z.string(),
|
|
259
|
+
count: z.number(),
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Project Files
|
|
264
|
+
|
|
265
|
+
### .kokimoki Directory
|
|
266
|
+
|
|
267
|
+
The plugin creates a `.kokimoki` directory in your project root:
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
.kokimoki/
|
|
271
|
+
├── app-id # Dev app ID (cached)
|
|
272
|
+
└── stores-hash # Hash of store schemas (for change detection)
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Add to `.gitignore`:**
|
|
276
|
+
|
|
277
|
+
```gitignore
|
|
278
|
+
.kokimoki/
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Credentials
|
|
282
|
+
|
|
283
|
+
Global credentials are stored in `~/.kokimoki`:
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"apiKeys": {
|
|
288
|
+
"org-id-1": "api-key-1",
|
|
289
|
+
"org-id-2": "api-key-2"
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Use `npx @kokimoki/cli login` to authenticate.
|
|
295
|
+
|
|
296
|
+
## Style Preprocessing
|
|
297
|
+
|
|
298
|
+
The plugin processes CSS files with theme color variables:
|
|
299
|
+
|
|
300
|
+
- Converts color names to hex values
|
|
301
|
+
- Generates RGB tuple variables for opacity support
|
|
302
|
+
- Processes palette color scales (50-900)
|
|
303
|
+
|
|
304
|
+
### Supported Variables
|
|
305
|
+
|
|
306
|
+
```css
|
|
307
|
+
:root {
|
|
308
|
+
--color-primary-500: #3b82f6;
|
|
309
|
+
--color-secondary-500: #10b981;
|
|
310
|
+
--on-primary: 255 255 255;
|
|
311
|
+
--on-secondary: 255 255 255;
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Production Build
|
|
316
|
+
|
|
317
|
+
During production builds, the plugin:
|
|
318
|
+
|
|
319
|
+
1. Validates all store schemas
|
|
320
|
+
2. Generates production loading screen
|
|
321
|
+
3. Embeds i18n metadata for runtime loading
|
|
322
|
+
4. Removes dev frame and development overlays
|
|
323
|
+
|
|
324
|
+
## Error Handling
|
|
325
|
+
|
|
326
|
+
### Common Errors
|
|
327
|
+
|
|
328
|
+
| Error | Cause | Solution |
|
|
329
|
+
| --------------------- | ------------------ | -------------------------------- |
|
|
330
|
+
| `CONCEPT_NOT_FOUND` | Invalid concept ID | Check your `conceptId` in config |
|
|
331
|
+
| `NO_CREDENTIALS` | Not logged in | Run `npx @kokimoki/cli login` |
|
|
332
|
+
| `DEV_APP_INIT_FAILED` | API error | Check network and API endpoint |
|
|
333
|
+
|
|
334
|
+
### Store Schema Changes
|
|
335
|
+
|
|
336
|
+
If you change store schemas, the plugin detects this and shows a warning page with two options:
|
|
337
|
+
|
|
338
|
+
- **Keep Current State**: Dismiss the warning and continue with existing data
|
|
339
|
+
- **Reset State**: Clear the dev app state and localStorage to start fresh
|
|
340
|
+
|
|
341
|
+
No dev server restart is required.
|