@kokimoki/kit 1.7.0 → 1.8.1
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/api.js +6 -6
- package/dist/credentials.js +4 -3
- package/dist/dev-app.js +8 -7
- package/dist/dev-frame/render-dev-frame.d.ts +12 -0
- package/dist/dev-frame/render-dev-frame.js +32 -3
- package/dist/dev-i18n.js +5 -4
- package/dist/dev-overlays.js +4 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/kokimoki-kit-plugin.d.ts +8 -0
- package/dist/kokimoki-kit-plugin.js +166 -60
- package/dist/preprocess-style.js +12 -11
- package/dist/production-loading-screen.js +2 -2
- package/dist/schemas/app-meta-schema.d.ts +22 -0
- package/dist/schemas/app-meta-schema.js +31 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/kokimoki-kit.instructions.md +138 -74
- package/package.json +2 -1
package/dist/api.js
CHANGED
|
@@ -4,12 +4,7 @@
|
|
|
4
4
|
* Shared between @kokimoki/cli and @kokimoki/kit
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.DEFAULT_ENDPOINT = void 0;
|
|
8
|
-
exports.createConcept = createConcept;
|
|
9
|
-
exports.getOrganization = getOrganization;
|
|
10
|
-
exports.getConceptOrganization = getConceptOrganization;
|
|
11
|
-
exports.createBuild = createBuild;
|
|
12
|
-
exports.getDeployUrl = getDeployUrl;
|
|
7
|
+
exports.getDeployUrl = exports.createBuild = exports.getConceptOrganization = exports.getOrganization = exports.createConcept = exports.DEFAULT_ENDPOINT = void 0;
|
|
13
8
|
exports.DEFAULT_ENDPOINT = "https://api.kokimoki.com";
|
|
14
9
|
/**
|
|
15
10
|
* Make a request to the Kokimoki API
|
|
@@ -39,6 +34,7 @@ async function createConcept(options, request) {
|
|
|
39
34
|
body: JSON.stringify(request),
|
|
40
35
|
});
|
|
41
36
|
}
|
|
37
|
+
exports.createConcept = createConcept;
|
|
42
38
|
/**
|
|
43
39
|
* Get organization details via the Kokimoki API
|
|
44
40
|
* Used for authentication validation
|
|
@@ -46,6 +42,7 @@ async function createConcept(options, request) {
|
|
|
46
42
|
async function getOrganization(endpoint, apiKey) {
|
|
47
43
|
return kokimokiApiRequest("/auth", { endpoint, apiKey }, { method: "GET" });
|
|
48
44
|
}
|
|
45
|
+
exports.getOrganization = getOrganization;
|
|
49
46
|
/**
|
|
50
47
|
* Get the organization that owns a concept (by concept ID)
|
|
51
48
|
*/
|
|
@@ -63,6 +60,7 @@ async function getConceptOrganization(endpoint, conceptId) {
|
|
|
63
60
|
}
|
|
64
61
|
return await res.json();
|
|
65
62
|
}
|
|
63
|
+
exports.getConceptOrganization = getConceptOrganization;
|
|
66
64
|
/**
|
|
67
65
|
* Create a new build via the Kokimoki API
|
|
68
66
|
*/
|
|
@@ -75,6 +73,7 @@ async function createBuild(options, request, cliVersion) {
|
|
|
75
73
|
body: JSON.stringify(request),
|
|
76
74
|
});
|
|
77
75
|
}
|
|
76
|
+
exports.createBuild = createBuild;
|
|
78
77
|
/**
|
|
79
78
|
* Get the deploy URL for a build
|
|
80
79
|
*/
|
|
@@ -93,3 +92,4 @@ async function getDeployUrl(endpoint, apiKey, buildId) {
|
|
|
93
92
|
}
|
|
94
93
|
return await res.json();
|
|
95
94
|
}
|
|
95
|
+
exports.getDeployUrl = getDeployUrl;
|
package/dist/credentials.js
CHANGED
|
@@ -7,9 +7,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
7
7
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
8
|
};
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.getCredentialsPath =
|
|
11
|
-
exports.readCredentials = readCredentials;
|
|
12
|
-
exports.writeCredentials = writeCredentials;
|
|
10
|
+
exports.writeCredentials = exports.readCredentials = exports.getCredentialsPath = void 0;
|
|
13
11
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
14
12
|
const os_1 = require("os");
|
|
15
13
|
const path_1 = __importDefault(require("path"));
|
|
@@ -19,6 +17,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
19
17
|
function getCredentialsPath() {
|
|
20
18
|
return path_1.default.join((0, os_1.homedir)(), ".kokimoki");
|
|
21
19
|
}
|
|
20
|
+
exports.getCredentialsPath = getCredentialsPath;
|
|
22
21
|
/**
|
|
23
22
|
* Read credentials from the ~/.kokimoki file
|
|
24
23
|
*/
|
|
@@ -35,6 +34,7 @@ async function readCredentials() {
|
|
|
35
34
|
throw e;
|
|
36
35
|
}
|
|
37
36
|
}
|
|
37
|
+
exports.readCredentials = readCredentials;
|
|
38
38
|
/**
|
|
39
39
|
* Write credentials to the ~/.kokimoki file
|
|
40
40
|
*/
|
|
@@ -42,3 +42,4 @@ async function writeCredentials(credentials) {
|
|
|
42
42
|
const credentialsPath = getCredentialsPath();
|
|
43
43
|
await promises_1.default.writeFile(credentialsPath, JSON.stringify(credentials, null, 2));
|
|
44
44
|
}
|
|
45
|
+
exports.writeCredentials = writeCredentials;
|
package/dist/dev-app.js
CHANGED
|
@@ -3,13 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.deleteAppId =
|
|
7
|
-
exports.setDevAppI18n = setDevAppI18n;
|
|
8
|
-
exports.setDevAppTranslation = setDevAppTranslation;
|
|
9
|
-
exports.computeStoresHash = computeStoresHash;
|
|
10
|
-
exports.readStoresHash = readStoresHash;
|
|
11
|
-
exports.writeStoresHash = writeStoresHash;
|
|
12
|
-
exports.getOrCreateDevApp = getOrCreateDevApp;
|
|
6
|
+
exports.getOrCreateDevApp = exports.writeStoresHash = exports.readStoresHash = exports.computeStoresHash = exports.setDevAppTranslation = exports.setDevAppI18n = exports.deleteAppId = void 0;
|
|
13
7
|
const crypto_1 = __importDefault(require("crypto"));
|
|
14
8
|
const bson_objectid_1 = __importDefault(require("bson-objectid"));
|
|
15
9
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
@@ -108,6 +102,7 @@ async function deleteAppId() {
|
|
|
108
102
|
}
|
|
109
103
|
}
|
|
110
104
|
}
|
|
105
|
+
exports.deleteAppId = deleteAppId;
|
|
111
106
|
/**
|
|
112
107
|
* Set i18n metadata for a dev app
|
|
113
108
|
*/
|
|
@@ -126,6 +121,7 @@ async function setDevAppI18n(endpoint, apiKey, appId, i18nMeta) {
|
|
|
126
121
|
throw new Error(`Failed to set dev app i18n: ${res.status} ${errorText}`);
|
|
127
122
|
}
|
|
128
123
|
}
|
|
124
|
+
exports.setDevAppI18n = setDevAppI18n;
|
|
129
125
|
/**
|
|
130
126
|
* Set translations for a specific language and namespace in a dev app
|
|
131
127
|
*/
|
|
@@ -144,6 +140,7 @@ async function setDevAppTranslation(endpoint, apiKey, appId, lng, namespace, tra
|
|
|
144
140
|
throw new Error(`Failed to set dev app translation: ${res.status} ${errorText}`);
|
|
145
141
|
}
|
|
146
142
|
}
|
|
143
|
+
exports.setDevAppTranslation = setDevAppTranslation;
|
|
147
144
|
/**
|
|
148
145
|
* Compute a hash of the stores configuration
|
|
149
146
|
*/
|
|
@@ -151,6 +148,7 @@ function computeStoresHash(stores) {
|
|
|
151
148
|
const content = JSON.stringify(stores ?? []);
|
|
152
149
|
return crypto_1.default.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
153
150
|
}
|
|
151
|
+
exports.computeStoresHash = computeStoresHash;
|
|
154
152
|
/**
|
|
155
153
|
* Read the stored stores hash from .kokimoki/stores-hash
|
|
156
154
|
*/
|
|
@@ -166,6 +164,7 @@ async function readStoresHash() {
|
|
|
166
164
|
throw e;
|
|
167
165
|
}
|
|
168
166
|
}
|
|
167
|
+
exports.readStoresHash = readStoresHash;
|
|
169
168
|
/**
|
|
170
169
|
* Write the stores hash to .kokimoki/stores-hash
|
|
171
170
|
*/
|
|
@@ -173,6 +172,7 @@ async function writeStoresHash(hash) {
|
|
|
173
172
|
await ensureKokimokiDir();
|
|
174
173
|
await promises_1.default.writeFile(path_1.default.join(KOKIMOKI_DIR, STORES_HASH_FILE), hash);
|
|
175
174
|
}
|
|
175
|
+
exports.writeStoresHash = writeStoresHash;
|
|
176
176
|
/**
|
|
177
177
|
* Get or create a dev app for local development.
|
|
178
178
|
*
|
|
@@ -269,3 +269,4 @@ async function getOrCreateDevApp(config) {
|
|
|
269
269
|
};
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
|
+
exports.getOrCreateDevApp = getOrCreateDevApp;
|
|
@@ -10,6 +10,18 @@ export interface DevFrameCell {
|
|
|
10
10
|
export interface DevFrameConfig {
|
|
11
11
|
/** Title shown in browser tab */
|
|
12
12
|
title?: string;
|
|
13
|
+
/**
|
|
14
|
+
* App meta for SEO and social sharing. Title will be appended with " - Dev View".
|
|
15
|
+
*/
|
|
16
|
+
appMeta?: {
|
|
17
|
+
lang?: string;
|
|
18
|
+
title?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
ogTitle?: string;
|
|
21
|
+
ogDescription?: string;
|
|
22
|
+
ogImage?: string;
|
|
23
|
+
favicon?: string;
|
|
24
|
+
};
|
|
13
25
|
/**
|
|
14
26
|
* Grid layout for the dev frame. Each inner array is a row,
|
|
15
27
|
* and each item in the row is a cell/frame.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Renders the dev frame HTML page - a multi-window view for development
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.renderDevFrame =
|
|
6
|
+
exports.renderDevFrame = void 0;
|
|
7
7
|
const styles_1 = require("./styles");
|
|
8
8
|
/**
|
|
9
9
|
* Generate URL for a dev frame iframe
|
|
@@ -138,16 +138,44 @@ function renderScript() {
|
|
|
138
138
|
* Render the complete dev frame HTML page
|
|
139
139
|
*/
|
|
140
140
|
function renderDevFrame(config) {
|
|
141
|
-
const {
|
|
141
|
+
const { rows, appMeta } = config;
|
|
142
|
+
// Build title: use appMeta.title if available, append " - Dev View"
|
|
143
|
+
const baseTitle = appMeta?.title || config.title || "Kokimoki";
|
|
144
|
+
const title = `${baseTitle} - Dev View`;
|
|
145
|
+
// Build meta tags from appMeta
|
|
146
|
+
const lang = appMeta?.lang || "en";
|
|
147
|
+
const description = appMeta?.description || "";
|
|
148
|
+
const ogTitle = appMeta?.ogTitle || baseTitle;
|
|
149
|
+
const ogDescription = appMeta?.ogDescription || description;
|
|
150
|
+
const ogImage = appMeta?.ogImage || "";
|
|
151
|
+
const favicon = appMeta?.favicon || "";
|
|
142
152
|
// Track seen labels across all rows for duplicate detection
|
|
143
153
|
const seenLabels = new Set();
|
|
144
154
|
const rowsHtml = rows.map((row) => renderRow(row, seenLabels)).join("\n");
|
|
155
|
+
// Build optional meta tags
|
|
156
|
+
const metaTags = [];
|
|
157
|
+
if (description) {
|
|
158
|
+
metaTags.push(`<meta name="description" content="${description}">`);
|
|
159
|
+
}
|
|
160
|
+
if (ogTitle) {
|
|
161
|
+
metaTags.push(`<meta property="og:title" content="${ogTitle}">`);
|
|
162
|
+
}
|
|
163
|
+
if (ogDescription) {
|
|
164
|
+
metaTags.push(`<meta property="og:description" content="${ogDescription}">`);
|
|
165
|
+
}
|
|
166
|
+
if (ogImage) {
|
|
167
|
+
metaTags.push(`<meta property="og:image" content="${ogImage}">`);
|
|
168
|
+
}
|
|
169
|
+
if (favicon) {
|
|
170
|
+
metaTags.push(`<link rel="icon" href="${favicon}">`);
|
|
171
|
+
}
|
|
145
172
|
return `<!DOCTYPE html>
|
|
146
|
-
<html lang="
|
|
173
|
+
<html lang="${lang}">
|
|
147
174
|
<head>
|
|
148
175
|
<meta charset="UTF-8">
|
|
149
176
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
150
177
|
<title>${title}</title>
|
|
178
|
+
${metaTags.join("\n ")}
|
|
151
179
|
<style>${styles_1.devFrameStyles}</style>
|
|
152
180
|
</head>
|
|
153
181
|
<body>
|
|
@@ -158,3 +186,4 @@ function renderDevFrame(config) {
|
|
|
158
186
|
</body>
|
|
159
187
|
</html>`;
|
|
160
188
|
}
|
|
189
|
+
exports.renderDevFrame = renderDevFrame;
|
package/dist/dev-i18n.js
CHANGED
|
@@ -3,10 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.loadI18nFromPath =
|
|
7
|
-
exports.getI18nMeta = getI18nMeta;
|
|
8
|
-
exports.syncAllI18nToDevApp = syncAllI18nToDevApp;
|
|
9
|
-
exports.syncI18nFile = syncI18nFile;
|
|
6
|
+
exports.syncI18nFile = exports.syncAllI18nToDevApp = exports.getI18nMeta = exports.loadI18nFromPath = void 0;
|
|
10
7
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
11
8
|
const path_1 = __importDefault(require("path"));
|
|
12
9
|
const dev_app_1 = require("./dev-app");
|
|
@@ -41,6 +38,7 @@ async function loadI18nFromPath(i18nPath) {
|
|
|
41
38
|
}
|
|
42
39
|
return resources;
|
|
43
40
|
}
|
|
41
|
+
exports.loadI18nFromPath = loadI18nFromPath;
|
|
44
42
|
/**
|
|
45
43
|
* Scan an i18n folder and return i18n metadata.
|
|
46
44
|
* Expected structure: `{i18nPath}/{lng}/{namespace}.json`
|
|
@@ -94,6 +92,7 @@ async function getI18nMeta(i18nPath, primaryLng = "en") {
|
|
|
94
92
|
languages,
|
|
95
93
|
};
|
|
96
94
|
}
|
|
95
|
+
exports.getI18nMeta = getI18nMeta;
|
|
97
96
|
/**
|
|
98
97
|
* Sync primary language i18n files to the dev app build directory (initial sync).
|
|
99
98
|
* Only uploads primaryLng since that's what AI translations use as source.
|
|
@@ -135,6 +134,7 @@ async function syncAllI18nToDevApp(devAppInfo, i18nResources, primaryLng = "en")
|
|
|
135
134
|
console.warn(`[kokimoki-kit] Synced i18n: ${syncedFiles.join(", ")}`);
|
|
136
135
|
}
|
|
137
136
|
}
|
|
137
|
+
exports.syncAllI18nToDevApp = syncAllI18nToDevApp;
|
|
138
138
|
/**
|
|
139
139
|
* Sync a single i18n file to the dev app build directory.
|
|
140
140
|
* Only syncs if the file is for the primary language.
|
|
@@ -162,3 +162,4 @@ async function syncI18nFile(devAppInfo, i18nPath, changedFilePath, primaryLng =
|
|
|
162
162
|
console.warn(`[kokimoki-kit] Failed to sync i18n ${lng}/${ns}:`, e instanceof Error ? e.message : e);
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
|
+
exports.syncI18nFile = syncI18nFile;
|
package/dist/dev-overlays.js
CHANGED
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
* Development overlay HTML templates for kokimoki-kit plugin
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.renderLoadingPage =
|
|
7
|
-
exports.renderErrorPage = renderErrorPage;
|
|
8
|
-
exports.renderStoresChangedPage = renderStoresChangedPage;
|
|
6
|
+
exports.renderStoresChangedPage = exports.renderErrorPage = exports.renderLoadingPage = void 0;
|
|
9
7
|
const pageBaseStyles = `
|
|
10
8
|
color: white;
|
|
11
9
|
display: flex;
|
|
@@ -111,6 +109,7 @@ function renderLoadingPage() {
|
|
|
111
109
|
</body>
|
|
112
110
|
</html>`;
|
|
113
111
|
}
|
|
112
|
+
exports.renderLoadingPage = renderLoadingPage;
|
|
114
113
|
/**
|
|
115
114
|
* Generate error page HTML for dev app errors (full page)
|
|
116
115
|
*/
|
|
@@ -176,6 +175,7 @@ function renderErrorPage(error) {
|
|
|
176
175
|
</body>
|
|
177
176
|
</html>`;
|
|
178
177
|
}
|
|
178
|
+
exports.renderErrorPage = renderErrorPage;
|
|
179
179
|
/**
|
|
180
180
|
* Generate stores changed warning page HTML (full page, not overlay)
|
|
181
181
|
*/
|
|
@@ -298,3 +298,4 @@ function renderStoresChangedPage(canReset) {
|
|
|
298
298
|
</body>
|
|
299
299
|
</html>`;
|
|
300
300
|
}
|
|
301
|
+
exports.renderStoresChangedPage = renderStoresChangedPage;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -20,6 +20,8 @@ __exportStar(require("./kokimoki-kit-plugin"), exports);
|
|
|
20
20
|
__exportStar(require("./preprocess-style"), exports);
|
|
21
21
|
// Re-export Zod utilities for schema definition
|
|
22
22
|
__exportStar(require("./zod"), exports);
|
|
23
|
+
// App Meta schema for built-in store
|
|
24
|
+
__exportStar(require("./schemas/app-meta-schema"), exports);
|
|
23
25
|
// Shared utilities (used by both kit and cli)
|
|
24
26
|
__exportStar(require("./api"), exports);
|
|
25
27
|
__exportStar(require("./credentials"), exports);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { PluginOption } from "vite";
|
|
2
2
|
import { ZodType } from "zod/v4";
|
|
3
3
|
import type { DevFrameCell } from "./dev-frame";
|
|
4
|
+
import { type AppMetaState } from "./schemas/app-meta-schema";
|
|
4
5
|
export { getI18nMeta, type I18nMeta } from "./dev-i18n";
|
|
5
6
|
export interface KokimokiKitConfig {
|
|
6
7
|
conceptId: string;
|
|
@@ -27,6 +28,7 @@ export interface KokimokiKitConfig {
|
|
|
27
28
|
pattern: string;
|
|
28
29
|
schema: ZodType;
|
|
29
30
|
local?: boolean;
|
|
31
|
+
isTransferable?: boolean;
|
|
30
32
|
}[];
|
|
31
33
|
/** API endpoint for kokimoki services. Defaults to https://api.kokimoki.com */
|
|
32
34
|
endpoint?: string;
|
|
@@ -53,5 +55,11 @@ export interface KokimokiKitConfig {
|
|
|
53
55
|
* ```
|
|
54
56
|
*/
|
|
55
57
|
devView?: readonly (readonly DevFrameCell[])[] | false;
|
|
58
|
+
/**
|
|
59
|
+
* Default app meta values for SEO and social sharing.
|
|
60
|
+
* These values are used as initial state for the built-in appMetaStore
|
|
61
|
+
* and for server-side HTML meta tag injection.
|
|
62
|
+
*/
|
|
63
|
+
defaultAppMeta?: AppMetaState;
|
|
56
64
|
}
|
|
57
65
|
export declare function kokimokiKitPlugin(config: KokimokiKitConfig): PluginOption;
|
|
@@ -15,30 +15,20 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) ||
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
35
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
27
|
};
|
|
38
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.getI18nMeta = void 0;
|
|
40
|
-
exports.kokimokiKitPlugin = kokimokiKitPlugin;
|
|
29
|
+
exports.kokimokiKitPlugin = exports.getI18nMeta = void 0;
|
|
41
30
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
31
|
+
const node_html_parser_1 = require("node-html-parser");
|
|
42
32
|
const path_1 = __importDefault(require("path"));
|
|
43
33
|
const yaml = __importStar(require("yaml"));
|
|
44
34
|
const v4_1 = require("zod/v4");
|
|
@@ -50,10 +40,23 @@ const dev_i18n_1 = require("./dev-i18n");
|
|
|
50
40
|
const dev_overlays_1 = require("./dev-overlays");
|
|
51
41
|
const preprocess_style_1 = require("./preprocess-style");
|
|
52
42
|
const production_loading_screen_1 = require("./production-loading-screen");
|
|
43
|
+
const app_meta_schema_1 = require("./schemas/app-meta-schema");
|
|
53
44
|
const version_1 = require("./version");
|
|
54
45
|
var dev_i18n_2 = require("./dev-i18n");
|
|
55
46
|
Object.defineProperty(exports, "getI18nMeta", { enumerable: true, get: function () { return dev_i18n_2.getI18nMeta; } });
|
|
47
|
+
/**
|
|
48
|
+
* Built-in app meta store configuration.
|
|
49
|
+
* Automatically injected into all apps for server-side meta tag injection.
|
|
50
|
+
*/
|
|
51
|
+
const BUILT_IN_APP_META_STORE = {
|
|
52
|
+
pattern: app_meta_schema_1.APP_META_STORE_NAME,
|
|
53
|
+
schema: app_meta_schema_1.appMetaStoreSchema,
|
|
54
|
+
local: false,
|
|
55
|
+
isTransferable: true,
|
|
56
|
+
};
|
|
56
57
|
function kokimokiKitPlugin(config) {
|
|
58
|
+
// Combine user stores with built-in stores
|
|
59
|
+
const allStores = [...(config.stores ?? []), BUILT_IN_APP_META_STORE];
|
|
57
60
|
// Cache for loaded i18n resources
|
|
58
61
|
let cachedI18n = null;
|
|
59
62
|
// Cache dev app info for syncing
|
|
@@ -63,6 +66,37 @@ function kokimokiKitPlugin(config) {
|
|
|
63
66
|
let initPromise = null;
|
|
64
67
|
// Cached dev app result
|
|
65
68
|
let cachedDevAppResult = null;
|
|
69
|
+
/**
|
|
70
|
+
* Resolve asset path for meta tags.
|
|
71
|
+
* In production, prepends %KM_ASSETS% placeholder for relative paths.
|
|
72
|
+
* In dev, returns path as-is since assets are served from root.
|
|
73
|
+
*/
|
|
74
|
+
function resolveAssetUrl(path, isProduction) {
|
|
75
|
+
if (!path)
|
|
76
|
+
return path;
|
|
77
|
+
// Only prefix relative paths (starting with /)
|
|
78
|
+
if (isProduction && path.startsWith("/")) {
|
|
79
|
+
return `%KM_ASSETS%${path}`;
|
|
80
|
+
}
|
|
81
|
+
return path;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Resolve asset URLs in defaultAppMeta object.
|
|
85
|
+
* Creates a new object with ogImage and favicon paths resolved.
|
|
86
|
+
*/
|
|
87
|
+
function resolveAppMetaAssets(meta, isProduction) {
|
|
88
|
+
if (!meta)
|
|
89
|
+
return null;
|
|
90
|
+
return {
|
|
91
|
+
...meta,
|
|
92
|
+
ogImage: meta.ogImage
|
|
93
|
+
? resolveAssetUrl(meta.ogImage, isProduction)
|
|
94
|
+
: undefined,
|
|
95
|
+
favicon: meta.favicon
|
|
96
|
+
? resolveAssetUrl(meta.favicon, isProduction)
|
|
97
|
+
: undefined,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
66
100
|
/**
|
|
67
101
|
* Start initialization if not already started.
|
|
68
102
|
* Returns a promise that resolves when initialization is complete.
|
|
@@ -137,11 +171,15 @@ function kokimokiKitPlugin(config) {
|
|
|
137
171
|
if (process.env.NODE_ENV !== "development") {
|
|
138
172
|
// Remove any existing km-loading element from the HTML
|
|
139
173
|
const processedHtml = (0, production_loading_screen_1.removeExistingLoadingScreen)(html);
|
|
140
|
-
//
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
174
|
+
// Parse HTML for DOM manipulation
|
|
175
|
+
const doc = (0, node_html_parser_1.parse)(processedHtml);
|
|
176
|
+
const head = doc.querySelector("head");
|
|
177
|
+
const body = doc.querySelector("body");
|
|
178
|
+
const htmlEl = doc.querySelector("html");
|
|
179
|
+
// Add base tag
|
|
180
|
+
head?.insertAdjacentHTML("afterbegin", `<base href="%KM_BASE%">`);
|
|
181
|
+
// Inject kokimoki-env script
|
|
182
|
+
head?.insertAdjacentHTML("afterbegin", `<script id="kokimoki-env" type="application/json">
|
|
145
183
|
{
|
|
146
184
|
"dev": %KM_DEV%,
|
|
147
185
|
"test": %KM_TEST%,
|
|
@@ -154,10 +192,12 @@ function kokimokiKitPlugin(config) {
|
|
|
154
192
|
"i18nNamespaces": ${JSON.stringify(i18nNamespaces)},
|
|
155
193
|
"i18nLanguages": ${JSON.stringify(i18nLanguages)},
|
|
156
194
|
"base": "%KM_BASE%",
|
|
157
|
-
"assets": "%KM_ASSETS%"
|
|
195
|
+
"assets": "%KM_ASSETS%",
|
|
196
|
+
"defaultAppMeta": ${JSON.stringify(resolveAppMetaAssets(config.defaultAppMeta, true))}
|
|
158
197
|
}
|
|
159
|
-
</script
|
|
160
|
-
|
|
198
|
+
</script>`);
|
|
199
|
+
// Inject assets URL helper script
|
|
200
|
+
head?.insertAdjacentHTML("beforeend", `<script>
|
|
161
201
|
window.__toAssetsUrl = (path) => {
|
|
162
202
|
if (path.startsWith("km-proxy")) {
|
|
163
203
|
return "/%KM_BUILD_ID%/" + path;
|
|
@@ -165,16 +205,50 @@ function kokimokiKitPlugin(config) {
|
|
|
165
205
|
|
|
166
206
|
return "%KM_ASSETS%/" + path;
|
|
167
207
|
};
|
|
168
|
-
</script
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
208
|
+
</script>`);
|
|
209
|
+
// Inject loading screen
|
|
210
|
+
head?.insertAdjacentHTML("beforeend", production_loading_screen_1.loadingScreenStyles);
|
|
211
|
+
head?.insertAdjacentHTML("beforeend", production_loading_screen_1.loadingScreenScript);
|
|
212
|
+
body?.insertAdjacentHTML("afterbegin", production_loading_screen_1.loadingScreenElement);
|
|
213
|
+
// Inject meta tags from defaultAppMeta
|
|
214
|
+
if (config.defaultAppMeta) {
|
|
215
|
+
const meta = config.defaultAppMeta;
|
|
216
|
+
if (meta.lang) {
|
|
217
|
+
htmlEl?.setAttribute("lang", meta.lang);
|
|
218
|
+
}
|
|
219
|
+
if (meta.title) {
|
|
220
|
+
head?.insertAdjacentHTML("beforeend", `<title>${meta.title}</title>`);
|
|
221
|
+
}
|
|
222
|
+
if (meta.description) {
|
|
223
|
+
head?.insertAdjacentHTML("beforeend", `<meta name="description" content="${meta.description}" />`);
|
|
224
|
+
}
|
|
225
|
+
if (meta.ogTitle ?? meta.title) {
|
|
226
|
+
head?.insertAdjacentHTML("beforeend", `<meta property="og:title" content="${meta.ogTitle ?? meta.title}" />`);
|
|
227
|
+
}
|
|
228
|
+
if (meta.ogDescription ?? meta.description) {
|
|
229
|
+
head?.insertAdjacentHTML("beforeend", `<meta property="og:description" content="${meta.ogDescription ?? meta.description}" />`);
|
|
230
|
+
}
|
|
231
|
+
if (meta.ogImage) {
|
|
232
|
+
head?.insertAdjacentHTML("beforeend", `<meta property="og:image" content="${resolveAssetUrl(meta.ogImage, true)}" />`);
|
|
233
|
+
}
|
|
234
|
+
if (meta.favicon) {
|
|
235
|
+
head?.insertAdjacentHTML("beforeend", `<link rel="icon" type="image/png" href="${resolveAssetUrl(meta.favicon, true)}" />`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Update asset URLs in link and script tags
|
|
239
|
+
doc.querySelectorAll("link[href]").forEach((el) => {
|
|
240
|
+
const href = el.getAttribute("href");
|
|
241
|
+
if (href) {
|
|
242
|
+
el.setAttribute("href", `%KM_ASSETS%${href.startsWith("/") ? "" : "/"}${href}`);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
doc.querySelectorAll("script[src]").forEach((el) => {
|
|
246
|
+
const src = el.getAttribute("src");
|
|
247
|
+
if (src) {
|
|
248
|
+
el.setAttribute("src", `%KM_ASSETS%${src.startsWith("/") ? "" : "/"}${src}`);
|
|
249
|
+
}
|
|
176
250
|
});
|
|
177
|
-
return
|
|
251
|
+
return doc.toString();
|
|
178
252
|
}
|
|
179
253
|
// Development mode: ensure initialization is started and wait for it
|
|
180
254
|
if (initState === "pending" || initState === "initializing") {
|
|
@@ -191,7 +265,7 @@ function kokimokiKitPlugin(config) {
|
|
|
191
265
|
error: { code: "INIT_ERROR", message: "Initialization failed" },
|
|
192
266
|
};
|
|
193
267
|
// Check if stores configuration has changed
|
|
194
|
-
const currentStoresHash = (0, dev_app_1.computeStoresHash)(
|
|
268
|
+
const currentStoresHash = (0, dev_app_1.computeStoresHash)(allStores);
|
|
195
269
|
const previousStoresHash = await (0, dev_app_1.readStoresHash)();
|
|
196
270
|
const storesChanged = previousStoresHash !== null && previousStoresHash !== currentStoresHash;
|
|
197
271
|
// Write initial stores hash if it doesn't exist yet
|
|
@@ -212,9 +286,12 @@ function kokimokiKitPlugin(config) {
|
|
|
212
286
|
const defaultProjectConfigFile = await promises_1.default.readFile(config.defaultProjectConfigPath, "utf8");
|
|
213
287
|
defaultProjectConfig = config.schema.parse(yaml.parse(defaultProjectConfigFile));
|
|
214
288
|
}
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
289
|
+
// Parse HTML for DOM manipulation
|
|
290
|
+
const doc = (0, node_html_parser_1.parse)(html);
|
|
291
|
+
const head = doc.querySelector("head");
|
|
292
|
+
const htmlEl = doc.querySelector("html");
|
|
293
|
+
// Inject kokimoki-env script
|
|
294
|
+
const envScript = (0, node_html_parser_1.parse)(`<script id="kokimoki-env" type="application/json">
|
|
218
295
|
{
|
|
219
296
|
"dev": true,
|
|
220
297
|
"test": true,
|
|
@@ -225,15 +302,43 @@ function kokimokiKitPlugin(config) {
|
|
|
225
302
|
"i18nLanguages": ${JSON.stringify(i18nLanguages)},
|
|
226
303
|
"base": "/",
|
|
227
304
|
"assets": "/",
|
|
228
|
-
"buildUrl": ${JSON.stringify(buildUrl ?? null)}
|
|
305
|
+
"buildUrl": ${JSON.stringify(buildUrl ?? null)},
|
|
306
|
+
"defaultAppMeta": ${JSON.stringify(config.defaultAppMeta ?? null)}
|
|
229
307
|
}
|
|
230
308
|
</script>`);
|
|
309
|
+
head?.insertAdjacentHTML("afterbegin", envScript.toString());
|
|
310
|
+
// Inject meta tags from defaultAppMeta in development
|
|
311
|
+
if (config.defaultAppMeta) {
|
|
312
|
+
const meta = config.defaultAppMeta;
|
|
313
|
+
if (meta.lang) {
|
|
314
|
+
htmlEl?.setAttribute("lang", meta.lang);
|
|
315
|
+
}
|
|
316
|
+
if (meta.title) {
|
|
317
|
+
head?.insertAdjacentHTML("beforeend", `<title>${meta.title}</title>`);
|
|
318
|
+
}
|
|
319
|
+
if (meta.description) {
|
|
320
|
+
head?.insertAdjacentHTML("beforeend", `<meta name="description" content="${meta.description}" />`);
|
|
321
|
+
}
|
|
322
|
+
if (meta.ogTitle ?? meta.title) {
|
|
323
|
+
head?.insertAdjacentHTML("beforeend", `<meta property="og:title" content="${meta.ogTitle ?? meta.title}" />`);
|
|
324
|
+
}
|
|
325
|
+
if (meta.ogDescription ?? meta.description) {
|
|
326
|
+
head?.insertAdjacentHTML("beforeend", `<meta property="og:description" content="${meta.ogDescription ?? meta.description}" />`);
|
|
327
|
+
}
|
|
328
|
+
if (meta.ogImage) {
|
|
329
|
+
head?.insertAdjacentHTML("beforeend", `<meta property="og:image" content="${meta.ogImage}" />`);
|
|
330
|
+
}
|
|
331
|
+
if (meta.favicon) {
|
|
332
|
+
head?.insertAdjacentHTML("beforeend", `<link rel="icon" type="image/png" href="${meta.favicon}" />`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
231
335
|
// Inject default project style in development
|
|
232
336
|
if (config.defaultProjectStylePath) {
|
|
233
337
|
const defaultProjectStyle = await promises_1.default.readFile(config.defaultProjectStylePath, "utf8");
|
|
234
|
-
|
|
338
|
+
const body = doc.querySelector("body");
|
|
339
|
+
body?.insertAdjacentHTML("beforeend", `<style id="km-dev-style">${(0, preprocess_style_1.preprocessStyle)(defaultProjectStyle)}</style>`);
|
|
235
340
|
}
|
|
236
|
-
return
|
|
341
|
+
return doc.toString();
|
|
237
342
|
},
|
|
238
343
|
// write kokimoki metadata to .kokimoki directory
|
|
239
344
|
async generateBundle(_, _bundle) {
|
|
@@ -259,6 +364,7 @@ function kokimokiKitPlugin(config) {
|
|
|
259
364
|
build: "dist",
|
|
260
365
|
defaultProjectConfigPath: config.defaultProjectConfigPath,
|
|
261
366
|
defaultProjectStylePath: config.defaultProjectStylePath,
|
|
367
|
+
defaultAppMeta: config.defaultAppMeta,
|
|
262
368
|
i18n,
|
|
263
369
|
}, null, 2));
|
|
264
370
|
// write schema
|
|
@@ -297,19 +403,18 @@ function kokimokiKitPlugin(config) {
|
|
|
297
403
|
properties: {},
|
|
298
404
|
};
|
|
299
405
|
await promises_1.default.writeFile(".kokimoki/schema.json", JSON.stringify(jsonSchema, null, 2));
|
|
300
|
-
// write stores config with JSON schemas to build output
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
}
|
|
406
|
+
// write stores config with JSON schemas to build output (always includes built-in stores)
|
|
407
|
+
const storesWithJsonSchema = allStores.map((store) => ({
|
|
408
|
+
pattern: store.pattern,
|
|
409
|
+
local: store.local,
|
|
410
|
+
schema: v4_1.z.toJSONSchema(store.schema),
|
|
411
|
+
isTransferable: store.isTransferable ?? false,
|
|
412
|
+
}));
|
|
413
|
+
this.emitFile({
|
|
414
|
+
type: "asset",
|
|
415
|
+
fileName: "km-stores.json",
|
|
416
|
+
source: JSON.stringify(storesWithJsonSchema, null, 2),
|
|
417
|
+
});
|
|
313
418
|
// write i18n files to build output as individual files per lng/ns
|
|
314
419
|
const i18nResources = await getI18nResources();
|
|
315
420
|
if (Object.keys(i18nResources).length > 0) {
|
|
@@ -340,7 +445,7 @@ function kokimokiKitPlugin(config) {
|
|
|
340
445
|
startInitialization();
|
|
341
446
|
// Helper to check stores changed status
|
|
342
447
|
async function checkStoresChanged() {
|
|
343
|
-
const currentStoresHash = (0, dev_app_1.computeStoresHash)(
|
|
448
|
+
const currentStoresHash = (0, dev_app_1.computeStoresHash)(allStores);
|
|
344
449
|
const previousStoresHash = await (0, dev_app_1.readStoresHash)();
|
|
345
450
|
return (previousStoresHash !== null &&
|
|
346
451
|
previousStoresHash !== currentStoresHash);
|
|
@@ -387,7 +492,7 @@ function kokimokiKitPlugin(config) {
|
|
|
387
492
|
// API endpoint to acknowledge stores hash change (dismiss the popup)
|
|
388
493
|
server.middlewares.use("/__kokimoki/stores-hash/acknowledge", async (_req, res) => {
|
|
389
494
|
try {
|
|
390
|
-
const currentStoresHash = (0, dev_app_1.computeStoresHash)(
|
|
495
|
+
const currentStoresHash = (0, dev_app_1.computeStoresHash)(allStores);
|
|
391
496
|
await (0, dev_app_1.writeStoresHash)(currentStoresHash);
|
|
392
497
|
res.statusCode = 200;
|
|
393
498
|
res.setHeader("Content-Type", "application/json");
|
|
@@ -407,7 +512,7 @@ function kokimokiKitPlugin(config) {
|
|
|
407
512
|
// Delete the app-id file so a new dev app will be created
|
|
408
513
|
await (0, dev_app_1.deleteAppId)();
|
|
409
514
|
// Update the stores hash
|
|
410
|
-
const currentStoresHash = (0, dev_app_1.computeStoresHash)(
|
|
515
|
+
const currentStoresHash = (0, dev_app_1.computeStoresHash)(allStores);
|
|
411
516
|
await (0, dev_app_1.writeStoresHash)(currentStoresHash);
|
|
412
517
|
// Reset initialization state so next request triggers re-initialization
|
|
413
518
|
initState = "pending";
|
|
@@ -523,8 +628,8 @@ function kokimokiKitPlugin(config) {
|
|
|
523
628
|
}
|
|
524
629
|
// Render dev view HTML at root
|
|
525
630
|
const devViewHtml = (0, dev_frame_1.renderDevFrame)({
|
|
526
|
-
title: "Dev View",
|
|
527
631
|
rows: config.devView,
|
|
632
|
+
appMeta: config.defaultAppMeta,
|
|
528
633
|
});
|
|
529
634
|
res.statusCode = 200;
|
|
530
635
|
res.setHeader("Content-Type", "text/html");
|
|
@@ -534,3 +639,4 @@ function kokimokiKitPlugin(config) {
|
|
|
534
639
|
},
|
|
535
640
|
};
|
|
536
641
|
}
|
|
642
|
+
exports.kokimokiKitPlugin = kokimokiKitPlugin;
|
package/dist/preprocess-style.js
CHANGED
|
@@ -3,17 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.hexToRgb =
|
|
7
|
-
exports.rgbToHex = rgbToHex;
|
|
8
|
-
exports.revertReplaceForColorPickers = revertReplaceForColorPickers;
|
|
9
|
-
exports.hexToTailwindRgbString = hexToTailwindRgbString;
|
|
10
|
-
exports.getLuminance = getLuminance;
|
|
11
|
-
exports.calculateRatio = calculateRatio;
|
|
12
|
-
exports.handleStringColor = handleStringColor;
|
|
13
|
-
exports.destringRgb = destringRgb;
|
|
14
|
-
exports.generateA11yOnColor = generateA11yOnColor;
|
|
15
|
-
exports.generatePalette = generatePalette;
|
|
16
|
-
exports.preprocessStyle = preprocessStyle;
|
|
6
|
+
exports.preprocessStyle = exports.generatePalette = exports.generateA11yOnColor = exports.destringRgb = exports.handleStringColor = exports.calculateRatio = exports.getLuminance = exports.hexToTailwindRgbString = exports.revertReplaceForColorPickers = exports.rgbToHex = exports.hexToRgb = void 0;
|
|
17
7
|
const colorjs_io_1 = __importDefault(require("colorjs.io"));
|
|
18
8
|
const colornames_1 = __importDefault(require("colornames"));
|
|
19
9
|
// List of rgb tuple variable names (possibly temporary system to support color picker for these variables)
|
|
@@ -113,10 +103,12 @@ function hexToRgb(hex) {
|
|
|
113
103
|
b: parseInt(b, 16),
|
|
114
104
|
};
|
|
115
105
|
}
|
|
106
|
+
exports.hexToRgb = hexToRgb;
|
|
116
107
|
function rgbToHex(r, g, b) {
|
|
117
108
|
const toHex = (c) => `0${c.toString(16)}`.slice(-2);
|
|
118
109
|
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
119
110
|
}
|
|
111
|
+
exports.rgbToHex = rgbToHex;
|
|
120
112
|
// export function replaceForColorPickers(code: string) {
|
|
121
113
|
// return code.replace(
|
|
122
114
|
// /--([a-z0-9-]+):\s*(\d+)\s+(\d+)\s+(\d+);/gi,
|
|
@@ -153,6 +145,7 @@ function revertReplaceForColorPickers(code) {
|
|
|
153
145
|
return match;
|
|
154
146
|
});
|
|
155
147
|
}
|
|
148
|
+
exports.revertReplaceForColorPickers = revertReplaceForColorPickers;
|
|
156
149
|
function lighten(hex, intensity) {
|
|
157
150
|
const color = hexToRgb(`#${hex}`);
|
|
158
151
|
if (!color)
|
|
@@ -179,6 +172,7 @@ function hexToTailwindRgbString(hex) {
|
|
|
179
172
|
const [, r, g, b] = colorParts;
|
|
180
173
|
return `${parseInt(r, 16)} ${parseInt(g, 16)} ${parseInt(b, 16)}`;
|
|
181
174
|
}
|
|
175
|
+
exports.hexToTailwindRgbString = hexToTailwindRgbString;
|
|
182
176
|
function getLuminance(r, g, b) {
|
|
183
177
|
const { _r, _g, _b } = typeof r === "object"
|
|
184
178
|
? { _r: r.r, _g: r.g, _b: r.b }
|
|
@@ -192,6 +186,7 @@ function getLuminance(r, g, b) {
|
|
|
192
186
|
});
|
|
193
187
|
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
|
|
194
188
|
}
|
|
189
|
+
exports.getLuminance = getLuminance;
|
|
195
190
|
function calculateRatio(luminance1, luminance2) {
|
|
196
191
|
const lum1 = typeof luminance1 === "string"
|
|
197
192
|
? getLuminance(handleStringColor(luminance1))
|
|
@@ -205,6 +200,7 @@ function calculateRatio(luminance1, luminance2) {
|
|
|
205
200
|
? (lum2 + 0.05) / (lum1 + 0.05)
|
|
206
201
|
: (lum1 + 0.05) / (lum2 + 0.05);
|
|
207
202
|
}
|
|
203
|
+
exports.calculateRatio = calculateRatio;
|
|
208
204
|
function handleStringColor(colorString, returnType = "rgb") {
|
|
209
205
|
// if it's a css variable
|
|
210
206
|
if (colorString.includes("--")) {
|
|
@@ -228,6 +224,7 @@ function handleStringColor(colorString, returnType = "rgb") {
|
|
|
228
224
|
}
|
|
229
225
|
return colorString;
|
|
230
226
|
}
|
|
227
|
+
exports.handleStringColor = handleStringColor;
|
|
231
228
|
function cssColorToHex(colorString) {
|
|
232
229
|
if (colorString.includes("#"))
|
|
233
230
|
return colorString;
|
|
@@ -254,11 +251,13 @@ function destringRgb(rgbString) {
|
|
|
254
251
|
b: parseInt(rgb[3], 10),
|
|
255
252
|
};
|
|
256
253
|
}
|
|
254
|
+
exports.destringRgb = destringRgb;
|
|
257
255
|
function generateA11yOnColor(hex) {
|
|
258
256
|
const black = calculateRatio(hex, "#000000");
|
|
259
257
|
const white = calculateRatio(hex, "#FFFFFF");
|
|
260
258
|
return black < white ? "0 0 0" : "255 255 255";
|
|
261
259
|
}
|
|
260
|
+
exports.generateA11yOnColor = generateA11yOnColor;
|
|
262
261
|
function generatePalette(baseColor) {
|
|
263
262
|
const hexValidation = new RegExp(/^#[0-9a-f]{6}$/i);
|
|
264
263
|
if (!hexValidation.test(baseColor))
|
|
@@ -300,6 +299,7 @@ function generatePalette(baseColor) {
|
|
|
300
299
|
});
|
|
301
300
|
return response;
|
|
302
301
|
}
|
|
302
|
+
exports.generatePalette = generatePalette;
|
|
303
303
|
function preprocessGfcThemeBlock(code) {
|
|
304
304
|
// Generate map of defined css variables
|
|
305
305
|
const cssVariableMap = {};
|
|
@@ -376,3 +376,4 @@ function preprocessStyle(code) {
|
|
|
376
376
|
}
|
|
377
377
|
});
|
|
378
378
|
}
|
|
379
|
+
exports.preprocessStyle = preprocessStyle;
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* This screen is injected into production builds and removed when km:ready is received.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.loadingScreenElement = exports.loadingScreenScript = exports.loadingScreenStyles = void 0;
|
|
8
|
-
exports.removeExistingLoadingScreen = removeExistingLoadingScreen;
|
|
7
|
+
exports.removeExistingLoadingScreen = exports.loadingScreenElement = exports.loadingScreenScript = exports.loadingScreenStyles = void 0;
|
|
9
8
|
/**
|
|
10
9
|
* Loading screen styles
|
|
11
10
|
*/
|
|
@@ -121,3 +120,4 @@ function removeExistingLoadingScreen(html) {
|
|
|
121
120
|
.replace(/<div[^>]*id=["']km-loading["'][^>]*>[\s\S]*?<\/div>/gi, "")
|
|
122
121
|
.replace(/<style[^>]*id=["']km-loading-style["'][^>]*>[\s\S]*?<\/style>/gi, "");
|
|
123
122
|
}
|
|
123
|
+
exports.removeExistingLoadingScreen = removeExistingLoadingScreen;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
|
+
/**
|
|
3
|
+
* Reserved store name for the App Meta store.
|
|
4
|
+
* Stores with the `__km/` prefix are reserved for SDK internal use.
|
|
5
|
+
*/
|
|
6
|
+
export declare const APP_META_STORE_NAME = "__km/app-meta";
|
|
7
|
+
/**
|
|
8
|
+
* Schema for the App Meta store.
|
|
9
|
+
* Used by the server to inject meta tags into the HTML response.
|
|
10
|
+
*
|
|
11
|
+
* All fields are optional - missing fields will fall back to defaults in index.html.
|
|
12
|
+
*/
|
|
13
|
+
export declare const appMetaStoreSchema: z.ZodObject<{
|
|
14
|
+
lang: z.ZodOptional<z.ZodString>;
|
|
15
|
+
title: z.ZodOptional<z.ZodString>;
|
|
16
|
+
description: z.ZodOptional<z.ZodString>;
|
|
17
|
+
ogTitle: z.ZodOptional<z.ZodString>;
|
|
18
|
+
ogDescription: z.ZodOptional<z.ZodString>;
|
|
19
|
+
ogImage: z.ZodOptional<z.ZodString>;
|
|
20
|
+
favicon: z.ZodOptional<z.ZodString>;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
export type AppMetaState = z.infer<typeof appMetaStoreSchema>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.appMetaStoreSchema = exports.APP_META_STORE_NAME = void 0;
|
|
4
|
+
const v4_1 = require("zod/v4");
|
|
5
|
+
/**
|
|
6
|
+
* Reserved store name for the App Meta store.
|
|
7
|
+
* Stores with the `__km/` prefix are reserved for SDK internal use.
|
|
8
|
+
*/
|
|
9
|
+
exports.APP_META_STORE_NAME = "__km/app-meta";
|
|
10
|
+
/**
|
|
11
|
+
* Schema for the App Meta store.
|
|
12
|
+
* Used by the server to inject meta tags into the HTML response.
|
|
13
|
+
*
|
|
14
|
+
* All fields are optional - missing fields will fall back to defaults in index.html.
|
|
15
|
+
*/
|
|
16
|
+
exports.appMetaStoreSchema = v4_1.z.object({
|
|
17
|
+
/** HTML lang attribute (e.g., 'en', 'et', 'de') */
|
|
18
|
+
lang: v4_1.z.string().optional(),
|
|
19
|
+
/** Document title (browser tab) */
|
|
20
|
+
title: v4_1.z.string().optional(),
|
|
21
|
+
/** Meta description */
|
|
22
|
+
description: v4_1.z.string().optional(),
|
|
23
|
+
/** Open Graph title (defaults to title if not set) */
|
|
24
|
+
ogTitle: v4_1.z.string().optional(),
|
|
25
|
+
/** Open Graph description (defaults to description if not set) */
|
|
26
|
+
ogDescription: v4_1.z.string().optional(),
|
|
27
|
+
/** Open Graph image URL */
|
|
28
|
+
ogImage: v4_1.z.string().optional(),
|
|
29
|
+
/** Favicon URL */
|
|
30
|
+
favicon: v4_1.z.string().optional(),
|
|
31
|
+
});
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const KOKIMOKI_KIT_VERSION = "1.
|
|
1
|
+
export declare const KOKIMOKI_KIT_VERSION = "1.8.1";
|
package/dist/version.js
CHANGED
|
@@ -15,77 +15,93 @@ npm install @kokimoki/kit
|
|
|
15
15
|
|
|
16
16
|
## Plugin Configuration
|
|
17
17
|
|
|
18
|
+
Create a `kokimoki.config.ts` file in your project root to define your Kokimoki Kit configuration:
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
export const kokimokiConfig: KokimokiKitConfig = {
|
|
22
|
+
// Required: Your concept ID from Kokimoki
|
|
23
|
+
conceptId: "your-concept-id",
|
|
24
|
+
|
|
25
|
+
// Required: Deploy configurations
|
|
26
|
+
deployCodes: [
|
|
27
|
+
{
|
|
28
|
+
name: "default",
|
|
29
|
+
description: "Default game mode",
|
|
30
|
+
clientContext: { mode: "standard" },
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "tournament",
|
|
34
|
+
description: "Tournament mode with stricter rules",
|
|
35
|
+
clientContext: { mode: "tournament", maxPlayers: 100 },
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Store schemas for validation
|
|
41
|
+
* marking stores as transferable allows their content to be used
|
|
42
|
+
* when creating new apps based on this one.
|
|
43
|
+
*
|
|
44
|
+
* For example, game configuration can contain content and settings
|
|
45
|
+
* that can be reused when setting up a new game instance. Dynamic
|
|
46
|
+
* game state, on the other hand, should not be transferable.
|
|
47
|
+
*/
|
|
48
|
+
stores: [
|
|
49
|
+
{
|
|
50
|
+
pattern: "config",
|
|
51
|
+
schema: z.object({
|
|
52
|
+
mode: z.enum(["standard", "tournament"]),
|
|
53
|
+
duration: z.number().min(1).describe("Game duration in minutes"),
|
|
54
|
+
}),
|
|
55
|
+
isTransferable: true, // This store content can be used to create a new app with the same content
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
pattern: "game",
|
|
59
|
+
schema: z.object({
|
|
60
|
+
status: z.enum(["waiting", "playing", "finished"]),
|
|
61
|
+
round: z.number(),
|
|
62
|
+
}),
|
|
63
|
+
isTransferable: false, // Dynamic game state should not be marked as transferable
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
pattern: "player-*",
|
|
67
|
+
schema: z.object({
|
|
68
|
+
name: z.string(),
|
|
69
|
+
score: z.number(),
|
|
70
|
+
}),
|
|
71
|
+
local: true, // Local store (per-client)
|
|
72
|
+
isTransferable: false, // Local stores cannot be transferable
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
|
|
76
|
+
// Optional: i18n configuration
|
|
77
|
+
i18nPath: "./src/i18n",
|
|
78
|
+
i18nPrimaryLng: "en", // Source language for AI translations
|
|
79
|
+
|
|
80
|
+
// Optional: Custom API endpoint
|
|
81
|
+
endpoint: "https://api.kokimoki.com",
|
|
82
|
+
host: "y-wss.kokimoki.com",
|
|
83
|
+
|
|
84
|
+
// Optional: Dev view layout (see Dev Frame section)
|
|
85
|
+
devView: [
|
|
86
|
+
[{ label: "host", clientContext: { mode: "host" } }],
|
|
87
|
+
[
|
|
88
|
+
{ label: "player1", clientContext: { mode: "player" } },
|
|
89
|
+
{ label: "player2", clientContext: { mode: "player" } },
|
|
90
|
+
],
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
18
95
|
Add the plugin to your `vite.config.ts`:
|
|
19
96
|
|
|
20
97
|
```typescript
|
|
21
98
|
import { defineConfig } from "vite";
|
|
22
99
|
import { kokimokiKitPlugin } from "@kokimoki/kit";
|
|
23
100
|
import { z } from "@kokimoki/kit";
|
|
101
|
+
import { kokimokiConfig } from "./kokimoki.config";
|
|
24
102
|
|
|
25
103
|
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
|
-
],
|
|
104
|
+
plugins: [kokimokiKitPlugin(kokimokiConfig)],
|
|
89
105
|
});
|
|
90
106
|
```
|
|
91
107
|
|
|
@@ -100,17 +116,65 @@ export default defineConfig({
|
|
|
100
116
|
|
|
101
117
|
### Optional Options
|
|
102
118
|
|
|
103
|
-
| Option
|
|
104
|
-
|
|
|
105
|
-
| `schema`
|
|
106
|
-
| `stores`
|
|
107
|
-
| `i18nPath`
|
|
108
|
-
| `i18nPrimaryLng`
|
|
109
|
-
| `endpoint`
|
|
110
|
-
| `host`
|
|
111
|
-
| `devView`
|
|
112
|
-
| `
|
|
113
|
-
| `defaultProjectStylePath`
|
|
119
|
+
| Option | Type | Description |
|
|
120
|
+
| ------------------------- | ---------------- | -------------------------------------------------- |
|
|
121
|
+
| `schema` | `ZodType` | Zod schema for project configuration |
|
|
122
|
+
| `stores` | `array` | Store definitions with patterns and schemas |
|
|
123
|
+
| `i18nPath` | `string` | Path to i18n folder (e.g., `./src/i18n`) |
|
|
124
|
+
| `i18nPrimaryLng` | `string` | Source language code (default: `"en"`) |
|
|
125
|
+
| `endpoint` | `string` | API endpoint (default: `https://api.kokimoki.com`) |
|
|
126
|
+
| `host` | `string` | WebSocket host (default: `y-wss.kokimoki.com`) |
|
|
127
|
+
| `devView` | `array \| false` | Dev frame layout or `false` to disable |
|
|
128
|
+
| `defaultAppMeta` | `object` | Default meta tags for SEO and social sharing |
|
|
129
|
+
| `defaultProjectStylePath` | `string` | Path to default project style file |
|
|
130
|
+
|
|
131
|
+
## App Meta
|
|
132
|
+
|
|
133
|
+
The `defaultAppMeta` option configures HTML meta tags for SEO and social sharing previews. These defaults are injected into the HTML at build time and used as the initial state for `kmClient.metaStore`.
|
|
134
|
+
|
|
135
|
+
### Configuration
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
kokimokiKitPlugin({
|
|
139
|
+
// ...
|
|
140
|
+
defaultAppMeta: {
|
|
141
|
+
lang: "en",
|
|
142
|
+
title: "My Game",
|
|
143
|
+
description: "An awesome multiplayer game",
|
|
144
|
+
ogTitle: "My Game",
|
|
145
|
+
ogDescription: "Join the fun!",
|
|
146
|
+
ogImage: "/og-image.png",
|
|
147
|
+
favicon: "/favicon.png",
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Fields
|
|
153
|
+
|
|
154
|
+
| Field | Description |
|
|
155
|
+
| --------------- | ------------------------------------------------------------- |
|
|
156
|
+
| `lang` | HTML `lang` attribute (e.g., `"en"`, `"de"`) |
|
|
157
|
+
| `title` | Document title (browser tab) |
|
|
158
|
+
| `description` | Meta description for SEO |
|
|
159
|
+
| `ogTitle` | Open Graph title (defaults to `title` if not set) |
|
|
160
|
+
| `ogDescription` | Open Graph description (defaults to `description`) |
|
|
161
|
+
| `ogImage` | Open Graph image URL (use relative path like `/og-image.png`) |
|
|
162
|
+
| `favicon` | Favicon URL (use relative path like `/favicon.png`) |
|
|
163
|
+
|
|
164
|
+
### Asset Path Resolution
|
|
165
|
+
|
|
166
|
+
Relative paths (starting with `/`) for `ogImage` and `favicon` are automatically prefixed with the assets base URL in production builds. This ensures images work correctly when served from a CDN.
|
|
167
|
+
|
|
168
|
+
### Runtime Updates
|
|
169
|
+
|
|
170
|
+
The meta state can be updated at runtime via `kmClient.metaStore`:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
await kmClient.transact([kmClient.metaStore], ([meta]) => {
|
|
174
|
+
meta.title = "Game Room: Epic Battle";
|
|
175
|
+
meta.ogImage = "https://example.com/custom-preview.png";
|
|
176
|
+
});
|
|
177
|
+
```
|
|
114
178
|
|
|
115
179
|
## Dev Frame
|
|
116
180
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kokimoki/kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"bson-objectid": "^2.0.4",
|
|
27
27
|
"colorjs.io": "^0.5.2",
|
|
28
28
|
"colornames": "^1.1.1",
|
|
29
|
+
"node-html-parser": "^7.0.1",
|
|
29
30
|
"yaml": "^2.7.0",
|
|
30
31
|
"zod": "^4.3.5"
|
|
31
32
|
},
|