@tailorkit/app 0.1.0-beta.6 → 0.1.0-beta.8
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 -9
- 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/dist/index.d.ts +3 -3
- package/dist/index.js +7 -8
- 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,19 +100,23 @@ 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
|
});
|
|
48
118
|
|
|
49
119
|
// src/builder/index.ts
|
|
50
|
-
var preactExternal = /^preact(?:\/.*)?$/u;
|
|
51
120
|
var preactPackageJson = "preact/package.json";
|
|
52
121
|
var preactPackageJsonModuleId = "\0tailorkit-preact-package-json";
|
|
53
122
|
var buildApp = async (options = {}) => {
|
|
@@ -69,7 +138,6 @@ var buildApp = async (options = {}) => {
|
|
|
69
138
|
watch: options.watch ? {} : null,
|
|
70
139
|
minify: "oxc",
|
|
71
140
|
rollupOptions: {
|
|
72
|
-
external: (id) => id !== preactPackageJson && id !== preactPackageJsonModuleId && preactExternal.test(id),
|
|
73
141
|
output: {
|
|
74
142
|
comments: {
|
|
75
143
|
annotation: false,
|
|
@@ -104,9 +172,30 @@ var buildApp = async (options = {}) => {
|
|
|
104
172
|
],
|
|
105
173
|
root: loaded.root
|
|
106
174
|
});
|
|
175
|
+
const logoManifest = {};
|
|
176
|
+
for (const variant of ["light", "dark"]) {
|
|
177
|
+
const configuredPath = loaded.config.logos?.[variant];
|
|
178
|
+
if (!configuredPath) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
const extension = path.extname(configuredPath).toLowerCase().slice(1);
|
|
182
|
+
const contentType = {
|
|
183
|
+
png: "image/png",
|
|
184
|
+
svg: "image/svg+xml",
|
|
185
|
+
webp: "image/webp"
|
|
186
|
+
}[extension];
|
|
187
|
+
if (!contentType) {
|
|
188
|
+
throw new Error(`The ${variant} logo must be an SVG, PNG, or WebP file.`);
|
|
189
|
+
}
|
|
190
|
+
const content = await readFile(path.resolve(loaded.root, configuredPath));
|
|
191
|
+
validateLogoAsset(content, contentType);
|
|
192
|
+
const filename = `logo-${variant}.${extension}`;
|
|
193
|
+
await writeFile(path.join(resolvedOutDir, filename), content);
|
|
194
|
+
logoManifest[variant] = filename;
|
|
195
|
+
}
|
|
107
196
|
await writeFile(
|
|
108
197
|
path.join(resolvedOutDir, "tailorkit-upload.json"),
|
|
109
|
-
`${JSON.stringify(createTailorKitUploadManifest(), null, 2)}
|
|
198
|
+
`${JSON.stringify(createTailorKitUploadManifest(logoManifest), null, 2)}
|
|
110
199
|
`,
|
|
111
200
|
"utf-8"
|
|
112
201
|
);
|
|
@@ -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/dist/index.d.ts
CHANGED
|
@@ -62,10 +62,10 @@ export declare const createScreen: <const TPath extends AppScreenPath>(path: TPa
|
|
|
62
62
|
loading?: View<Record<string, never>>;
|
|
63
63
|
}) => ScreenDefinition<TPath>;
|
|
64
64
|
export declare const defineClient: <const TScreens extends ScreenDefinitions>(client: TailorKitClient<TScreens> & RequireScreenPaths<TScreens> & RequireMatchingScreenKeys<TScreens>) => TailorKitClientWithMeta<TScreens>;
|
|
65
|
-
export declare const createRemoteComponent: <TProps extends object,
|
|
65
|
+
export declare const createRemoteComponent: <TProps extends object, TChildren extends boolean = false>(name: string, options?: {
|
|
66
66
|
callbacks?: Record<string, number>;
|
|
67
|
-
|
|
67
|
+
children?: TChildren;
|
|
68
68
|
}) => View<TProps & {
|
|
69
|
-
children?: ComponentChildren;
|
|
69
|
+
children?: TChildren extends true ? ComponentChildren : never;
|
|
70
70
|
}>;
|
|
71
71
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -43,14 +43,9 @@ var componentTagPrefix = "tailorkit-";
|
|
|
43
43
|
var toComponentTagName = (name) => `${componentTagPrefix}${name.replaceAll(/([a-z0-9])([A-Z])/gu, "$1-$2").replaceAll(/[\s_]+/gu, "-").toLowerCase()}`;
|
|
44
44
|
var toCallbackEventName = (name) => `tailorkitcallback${name.replaceAll(/[^A-Za-z0-9_$]/gu, "").toLowerCase()}`;
|
|
45
45
|
var toEventProp = (event) => `on${event}`;
|
|
46
|
-
var createRemoteComponent = (name, options) => {
|
|
46
|
+
var createRemoteComponent = (name, options = {}) => {
|
|
47
47
|
const tagName = toComponentTagName(name);
|
|
48
|
-
const callbacks = options.callbacks;
|
|
49
|
-
if (!callbacks || Object.keys(callbacks).length === 0) {
|
|
50
|
-
return function RemoteComponent({ children, ...props }) {
|
|
51
|
-
return h(tagName, props, children);
|
|
52
|
-
};
|
|
53
|
-
}
|
|
48
|
+
const callbacks = options.callbacks ?? {};
|
|
54
49
|
return function RemoteComponent({ children, ...props }) {
|
|
55
50
|
const nextProps = { ...props };
|
|
56
51
|
const callbackMap = {};
|
|
@@ -66,10 +61,14 @@ var createRemoteComponent = (name, options) => {
|
|
|
66
61
|
callback(...(event.detail ?? []).slice(0, inputCount));
|
|
67
62
|
};
|
|
68
63
|
}
|
|
64
|
+
const serializedProps = Object.fromEntries(
|
|
65
|
+
Object.entries(nextProps).filter(([, value]) => typeof value !== "function")
|
|
66
|
+
);
|
|
67
|
+
nextProps["data-tailorkit-props"] = JSON.stringify(serializedProps);
|
|
69
68
|
if (Object.keys(callbackMap).length > 0) {
|
|
70
69
|
nextProps["data-tailorkit-callbacks"] = JSON.stringify(callbackMap);
|
|
71
70
|
}
|
|
72
|
-
return h(tagName, nextProps, children);
|
|
71
|
+
return h(tagName, nextProps, options.children ? children : void 0);
|
|
73
72
|
};
|
|
74
73
|
};
|
|
75
74
|
export {
|
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.8",
|
|
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.8",
|
|
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",
|