@tailorkit/app 0.1.0-beta.6 → 0.1.0-beta.7
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/builder/upload-manifest.d.ts +5 -1
- package/dist/builder.js +98 -7
- package/dist/{chunk-7L6ZZHCK.js → chunk-EKCUETAV.js} +1 -1
- package/dist/{chunk-AGGRUUWG.js → chunk-ZFYKVXDO.js} +6 -1
- package/dist/config/config.d.ts +4 -0
- package/dist/config-loader.js +2 -2
- package/dist/config.js +1 -1
- package/package.json +3 -2
|
@@ -2,8 +2,12 @@ import { z } from "zod";
|
|
|
2
2
|
export declare const tailorkitUploadManifestSchema: z.ZodObject<{
|
|
3
3
|
assets: z.ZodObject<{
|
|
4
4
|
client: z.ZodLiteral<"client.js">;
|
|
5
|
+
logos: z.ZodOptional<z.ZodObject<{
|
|
6
|
+
dark: z.ZodOptional<z.ZodString>;
|
|
7
|
+
light: z.ZodOptional<z.ZodString>;
|
|
8
|
+
}, z.core.$strip>>;
|
|
5
9
|
}, z.core.$strip>;
|
|
6
10
|
version: z.ZodLiteral<1>;
|
|
7
11
|
}, z.core.$strip>;
|
|
8
12
|
export type TailorKitUploadManifest = z.output<typeof tailorkitUploadManifestSchema>;
|
|
9
|
-
export declare const createTailorKitUploadManifest: () => TailorKitUploadManifest;
|
|
13
|
+
export declare const createTailorKitUploadManifest: (logos?: TailorKitUploadManifest["assets"]["logos"]) => TailorKitUploadManifest;
|
package/dist/builder.js
CHANGED
|
@@ -1,12 +1,77 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadTailorKitConfig
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-EKCUETAV.js";
|
|
4
|
+
import "./chunk-ZFYKVXDO.js";
|
|
5
5
|
|
|
6
6
|
// src/builder/index.ts
|
|
7
7
|
import path from "path";
|
|
8
8
|
import { createRequire } from "module";
|
|
9
|
-
import { writeFile } from "fs/promises";
|
|
9
|
+
import { readFile, writeFile } from "fs/promises";
|
|
10
|
+
|
|
11
|
+
// ../asset-delivery/dist/logo-validation.mjs
|
|
12
|
+
var maxLogoBytes = 262144;
|
|
13
|
+
var maxLogoDimension = 2048;
|
|
14
|
+
var readPngDimensions = (content) => {
|
|
15
|
+
if (content.length < 33 || ![
|
|
16
|
+
137,
|
|
17
|
+
80,
|
|
18
|
+
78,
|
|
19
|
+
71,
|
|
20
|
+
13,
|
|
21
|
+
10,
|
|
22
|
+
26,
|
|
23
|
+
10
|
|
24
|
+
].every((byte, index) => content[index] === byte)) throw new Error("Logo content is not a valid PNG file.");
|
|
25
|
+
const view = new DataView(content.buffer, content.byteOffset, content.byteLength);
|
|
26
|
+
const isIhdr = content[12] === 73 && content[13] === 72 && content[14] === 68 && content[15] === 82;
|
|
27
|
+
if (view.getUint32(8) !== 13 || !isIhdr) throw new Error("Logo content is not a valid PNG file.");
|
|
28
|
+
return {
|
|
29
|
+
width: view.getUint32(16),
|
|
30
|
+
height: view.getUint32(20)
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
var readWebpDimensions = (content) => {
|
|
34
|
+
const text = (start, end) => new TextDecoder().decode(content.subarray(start, end));
|
|
35
|
+
if (content.length < 30 || text(0, 4) !== "RIFF" || text(8, 12) !== "WEBP") throw new Error("Logo content is not a valid WebP file.");
|
|
36
|
+
const view = new DataView(content.buffer, content.byteOffset, content.byteLength);
|
|
37
|
+
const chunk = text(12, 16);
|
|
38
|
+
if (chunk === "VP8X") return {
|
|
39
|
+
width: 1 + view.getUint16(24, true) + (content[26] ?? 0) * 65536,
|
|
40
|
+
height: 1 + view.getUint16(27, true) + (content[29] ?? 0) * 65536
|
|
41
|
+
};
|
|
42
|
+
if (chunk === "VP8L" && content[20] === 47) {
|
|
43
|
+
const bits = view.getUint32(21, true);
|
|
44
|
+
return {
|
|
45
|
+
width: bits % 16384 + 1,
|
|
46
|
+
height: Math.floor(bits / 16384) % 16384 + 1
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (chunk === "VP8 " && content[23] === 157 && content[24] === 1 && content[25] === 42) return {
|
|
50
|
+
width: view.getUint16(26, true) % 16384,
|
|
51
|
+
height: view.getUint16(28, true) % 16384
|
|
52
|
+
};
|
|
53
|
+
throw new Error("Logo content is not a supported WebP file.");
|
|
54
|
+
};
|
|
55
|
+
var validateSvg = (content) => {
|
|
56
|
+
const svg = new TextDecoder("utf-8", {
|
|
57
|
+
fatal: true,
|
|
58
|
+
ignoreBOM: false
|
|
59
|
+
}).decode(content);
|
|
60
|
+
if (!/<svg(?:\s|>)/iu.test(svg)) throw new Error("Logo content is not a valid SVG file.");
|
|
61
|
+
if (/<(?:script|foreignObject|iframe|object|embed)(?:\s|>)/iu.test(svg) || /\son[a-z]+\s*=/iu.test(svg) || /(?:href|src)\s*=\s*["'](?!#)/iu.test(svg) || /(?:@import|url\(\s*(?!["']?#))/iu.test(svg) || /<!DOCTYPE|<!ENTITY|<\?xml-stylesheet/iu.test(svg)) throw new Error("SVG logos cannot contain scripts or external resources.");
|
|
62
|
+
};
|
|
63
|
+
function validateLogoAsset(content, contentType) {
|
|
64
|
+
if (content.byteLength < 1 || content.byteLength > 262144) throw new Error(`Logo must be between 1 and ${maxLogoBytes} bytes.`);
|
|
65
|
+
if (contentType === "image/svg+xml") {
|
|
66
|
+
validateSvg(content);
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
const dimensions = contentType === "image/png" ? readPngDimensions(content) : readWebpDimensions(content);
|
|
70
|
+
if (dimensions.width < 1 || dimensions.height < 1 || dimensions.width > 2048 || dimensions.height > 2048) throw new Error(`Raster logos cannot exceed ${maxLogoDimension} by ${maxLogoDimension} pixels.`);
|
|
71
|
+
return dimensions;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/builder/index.ts
|
|
10
75
|
import { build as viteBuild } from "vite";
|
|
11
76
|
|
|
12
77
|
// src/preact-version.ts
|
|
@@ -35,13 +100,18 @@ var assertSupportedPreactVersion = (version) => {
|
|
|
35
100
|
import { z } from "zod";
|
|
36
101
|
var tailorkitUploadManifestSchema = z.object({
|
|
37
102
|
assets: z.object({
|
|
38
|
-
client: z.literal("client.js")
|
|
103
|
+
client: z.literal("client.js"),
|
|
104
|
+
logos: z.object({
|
|
105
|
+
dark: z.string().regex(/^logo-dark\.(?:png|svg|webp)$/u).optional(),
|
|
106
|
+
light: z.string().regex(/^logo-light\.(?:png|svg|webp)$/u).optional()
|
|
107
|
+
}).optional()
|
|
39
108
|
}),
|
|
40
109
|
version: z.literal(1)
|
|
41
110
|
});
|
|
42
|
-
var createTailorKitUploadManifest = () => tailorkitUploadManifestSchema.parse({
|
|
111
|
+
var createTailorKitUploadManifest = (logos) => tailorkitUploadManifestSchema.parse({
|
|
43
112
|
assets: {
|
|
44
|
-
client: "client.js"
|
|
113
|
+
client: "client.js",
|
|
114
|
+
...logos && Object.keys(logos).length > 0 ? { logos } : {}
|
|
45
115
|
},
|
|
46
116
|
version: 1
|
|
47
117
|
});
|
|
@@ -104,9 +174,30 @@ var buildApp = async (options = {}) => {
|
|
|
104
174
|
],
|
|
105
175
|
root: loaded.root
|
|
106
176
|
});
|
|
177
|
+
const logoManifest = {};
|
|
178
|
+
for (const variant of ["light", "dark"]) {
|
|
179
|
+
const configuredPath = loaded.config.logos?.[variant];
|
|
180
|
+
if (!configuredPath) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const extension = path.extname(configuredPath).toLowerCase().slice(1);
|
|
184
|
+
const contentType = {
|
|
185
|
+
png: "image/png",
|
|
186
|
+
svg: "image/svg+xml",
|
|
187
|
+
webp: "image/webp"
|
|
188
|
+
}[extension];
|
|
189
|
+
if (!contentType) {
|
|
190
|
+
throw new Error(`The ${variant} logo must be an SVG, PNG, or WebP file.`);
|
|
191
|
+
}
|
|
192
|
+
const content = await readFile(path.resolve(loaded.root, configuredPath));
|
|
193
|
+
validateLogoAsset(content, contentType);
|
|
194
|
+
const filename = `logo-${variant}.${extension}`;
|
|
195
|
+
await writeFile(path.join(resolvedOutDir, filename), content);
|
|
196
|
+
logoManifest[variant] = filename;
|
|
197
|
+
}
|
|
107
198
|
await writeFile(
|
|
108
199
|
path.join(resolvedOutDir, "tailorkit-upload.json"),
|
|
109
|
-
`${JSON.stringify(createTailorKitUploadManifest(), null, 2)}
|
|
200
|
+
`${JSON.stringify(createTailorKitUploadManifest(logoManifest), null, 2)}
|
|
110
201
|
`,
|
|
111
202
|
"utf-8"
|
|
112
203
|
);
|
|
@@ -6,11 +6,16 @@ var clientConfigSchema = z.object({
|
|
|
6
6
|
var buildConfigSchema = z.object({
|
|
7
7
|
outDir: z.string().default(".tailorkit")
|
|
8
8
|
});
|
|
9
|
+
var logosConfigSchema = z.object({
|
|
10
|
+
dark: z.string().min(1).optional(),
|
|
11
|
+
light: z.string().min(1).optional()
|
|
12
|
+
});
|
|
9
13
|
var tailorkitConfigSchema = z.object({
|
|
10
14
|
appId: z.string().min(1).optional(),
|
|
11
15
|
build: buildConfigSchema.optional(),
|
|
12
16
|
client: clientConfigSchema.optional(),
|
|
13
|
-
host: z.string().url()
|
|
17
|
+
host: z.string().url(),
|
|
18
|
+
logos: logosConfigSchema.optional()
|
|
14
19
|
});
|
|
15
20
|
var defineConfig = (config) => config;
|
|
16
21
|
var defineTailorKitConfig = defineConfig;
|
package/dist/config/config.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ declare const tailorkitConfigSchema: z.ZodObject<{
|
|
|
8
8
|
entry: z.ZodDefault<z.ZodString>;
|
|
9
9
|
}, z.core.$strip>>;
|
|
10
10
|
host: z.ZodString;
|
|
11
|
+
logos: z.ZodOptional<z.ZodObject<{
|
|
12
|
+
dark: z.ZodOptional<z.ZodString>;
|
|
13
|
+
light: z.ZodOptional<z.ZodString>;
|
|
14
|
+
}, z.core.$strip>>;
|
|
11
15
|
}, z.core.$strip>;
|
|
12
16
|
export type TailorKitConfig = z.input<typeof tailorkitConfigSchema>;
|
|
13
17
|
export type ResolvedTailorKitConfig = z.output<typeof tailorkitConfigSchema>;
|
package/dist/config-loader.js
CHANGED
package/dist/config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailorkit/app",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.7",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,12 +33,13 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@tailorkit/core": "0.1.0-beta.
|
|
36
|
+
"@tailorkit/core": "0.1.0-beta.7",
|
|
37
37
|
"cosmiconfig": "^10.0.0",
|
|
38
38
|
"vite": "^8.2.2",
|
|
39
39
|
"zod": "^4.4.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
+
"@tailorkit/asset-delivery": "0.0.0",
|
|
42
43
|
"@tailorkit/config": "0.0.0",
|
|
43
44
|
"@types/node": "26.2.0",
|
|
44
45
|
"preact": "^10.29.8",
|