makeables 0.10.0 → 0.12.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 +2 -1
- package/dist/assets/brands/paisanos/identity/paisanos-logo.svg +4 -0
- package/dist/assets/brands/paisanos/identity/palette.json +13 -0
- package/dist/assets/brands/paisanos/identity/tokens.css +10 -0
- package/dist/assets/brands/sla/identity/palette.json +13 -0
- package/dist/assets/brands/sla/identity/sla-logo-marfil.svg +4 -0
- package/dist/assets/brands/sla/identity/sla-logo-naranja.svg +4 -0
- package/dist/assets/brands/sla/identity/sla-logo-negro.svg +4 -0
- package/dist/assets/brands/sla/identity/sla-logo-verde.svg +4 -0
- package/dist/assets/brands/sla/identity/tokens.css +13 -0
- package/dist/badge-package-RBQ43DQX.js +53 -0
- package/dist/brand-UNVFUN4H.js +35 -0
- package/dist/brand-preview-C6HBXUXH.js +48 -0
- package/dist/{chunk-TRIRNJSG.js → chunk-7A4TRTVE.js} +13 -11
- package/dist/chunk-BYXBJQAS.js +0 -0
- package/dist/chunk-KLJRRHMY.js +3352 -0
- package/dist/{chunk-G6OTYITI.js → chunk-MXT43NAQ.js} +461 -3509
- package/dist/chunk-WEPC5LJ7.js +81 -0
- package/dist/chunk-YOGNQAYJ.js +712 -0
- package/dist/cli.js +3060 -226
- package/dist/{kit-YXOYCN6F.js → kit-SZ4WFGHZ.js} +3 -2
- package/dist/{mcp-VS5XYXVM.js → mcp-2VMGYAUZ.js} +11 -18
- package/dist/print-NGPUZPVN.js +18219 -0
- package/dist/submission-H3RXUH7T.js +76 -0
- package/package.json +5 -1
- package/dist/chunk-SZTWKHNA.js +0 -95
|
@@ -0,0 +1,3352 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// ../design/dist/chunk-BAQXEQNG.js
|
|
28
|
+
import QRCode from "qrcode";
|
|
29
|
+
function badgeQrLayout(destination, width, maxCellSize = 20) {
|
|
30
|
+
const url = new URL(destination);
|
|
31
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.href.length > 400)
|
|
32
|
+
throw new Error("El destino del QR no es v\xE1lido.");
|
|
33
|
+
const matrix = QRCode.create(url.href, { errorCorrectionLevel: "M" }).modules;
|
|
34
|
+
const cell = Math.min(maxCellSize, Math.floor(width / (matrix.size + 8)));
|
|
35
|
+
if (cell < 2) throw new Error("El QR necesita m\xE1s espacio.");
|
|
36
|
+
return { matrix, cell };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ../design/dist/chunk-J74I2FPH.js
|
|
40
|
+
var MAX_SVG_BYTES = 1e6;
|
|
41
|
+
var TAG = /<([a-z][\w:.-]*)((?:\s+[^\s=<>/]+(?:\s*=\s*(?:"[^"<]*"|'[^'<]*'|[^\s"'<>]+))?)*)\s*\/?>/gi;
|
|
42
|
+
var ATTRIBUTE = /([^\s=<>/]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'<>]+)))?/g;
|
|
43
|
+
var CLOSING_TAG = /<\/[a-z][\w:.-]*\s*>/gi;
|
|
44
|
+
var CSS_URL = /url\(\s*(["']?)(.*?)\1\s*\)/gi;
|
|
45
|
+
var EMBEDDED_IMAGE = /^data:image\/(?:png|jpeg|jpg|webp|gif);base64,[a-z0-9+/=\s]+$/i;
|
|
46
|
+
var FORBIDDEN_ELEMENTS = /* @__PURE__ */ new Set([
|
|
47
|
+
"script",
|
|
48
|
+
"foreignobject",
|
|
49
|
+
"iframe",
|
|
50
|
+
"embed",
|
|
51
|
+
"object",
|
|
52
|
+
"audio",
|
|
53
|
+
"video",
|
|
54
|
+
"canvas",
|
|
55
|
+
"handler",
|
|
56
|
+
"listener"
|
|
57
|
+
]);
|
|
58
|
+
function fail(error) {
|
|
59
|
+
return { ok: false, error };
|
|
60
|
+
}
|
|
61
|
+
function localName(name) {
|
|
62
|
+
return name.toLowerCase().replace(/^[\w.-]+:/, "");
|
|
63
|
+
}
|
|
64
|
+
function checkSubmittedSvg(input) {
|
|
65
|
+
const svg2 = input.replace(/^/, "").trim();
|
|
66
|
+
if (!svg2) return fail("The file is empty.");
|
|
67
|
+
if (new TextEncoder().encode(svg2).byteLength > MAX_SVG_BYTES) {
|
|
68
|
+
return fail("The SVG must be 1 MB or smaller.");
|
|
69
|
+
}
|
|
70
|
+
if (/<!(?:doctype|entity)/i.test(svg2))
|
|
71
|
+
return fail("DOCTYPE and entity declarations are not allowed.");
|
|
72
|
+
if (/(?:java|vb)script\s*:/i.test(svg2)) return fail("Script URLs are not allowed.");
|
|
73
|
+
if (/@import/i.test(svg2)) return fail("CSS @import is not allowed.");
|
|
74
|
+
for (const match of svg2.matchAll(CSS_URL)) {
|
|
75
|
+
if (!match[2]?.trim().startsWith("#")) {
|
|
76
|
+
return fail("CSS url() may only reference elements inside the file (#id).");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const markup = svg2.replace(/^<\?xml[^>]*\?>/i, "").replace(/<!--[\s\S]*?-->/g, "").replace(/<!\[CDATA\[[\s\S]*?\]\]>/g, "").trim();
|
|
80
|
+
if (markup.replace(TAG, "").replace(CLOSING_TAG, "").includes("<")) {
|
|
81
|
+
return fail("The SVG contains malformed markup.");
|
|
82
|
+
}
|
|
83
|
+
const tags2 = [...markup.matchAll(TAG)];
|
|
84
|
+
const [root] = tags2;
|
|
85
|
+
if (root?.index !== 0 || localName(root[1] ?? "") !== "svg") {
|
|
86
|
+
return fail("The file must be an SVG document starting with <svg>.");
|
|
87
|
+
}
|
|
88
|
+
if (!/<\/svg\s*>$/i.test(markup)) return fail("The SVG is incomplete.");
|
|
89
|
+
for (const [index, tag] of tags2.entries()) {
|
|
90
|
+
const element = localName(tag[1] ?? "");
|
|
91
|
+
if (FORBIDDEN_ELEMENTS.has(element)) return fail(`<${tag[1]}> elements are not allowed.`);
|
|
92
|
+
for (const attribute of (tag[2] ?? "").matchAll(ATTRIBUTE)) {
|
|
93
|
+
const name = localName(attribute[1] ?? "");
|
|
94
|
+
const value = (attribute[2] ?? attribute[3] ?? attribute[4] ?? "").trim();
|
|
95
|
+
if (name.startsWith("on")) {
|
|
96
|
+
return fail("Event handler attributes (onload, onclick\u2026) are not allowed.");
|
|
97
|
+
}
|
|
98
|
+
if (name === "href" && !value.startsWith("#") && !EMBEDDED_IMAGE.test(value)) {
|
|
99
|
+
return fail(
|
|
100
|
+
"Links must point inside the file (#id) or embed a base64 PNG, JPEG, WebP, or GIF."
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
if (name === "attributename" && localName(value) === "href") {
|
|
104
|
+
return fail("Animating links is not allowed.");
|
|
105
|
+
}
|
|
106
|
+
if (index === 0 && name === "viewbox") {
|
|
107
|
+
const box2 = value.split(/[\s,]+/).map(Number).join(" ");
|
|
108
|
+
if (box2 !== "0 0 1200 756") return fail('The <svg> element needs viewBox="0 0 1200 756".');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!/\sviewBox\s*=/i.test(root[2] ?? "")) {
|
|
113
|
+
return fail('The <svg> element needs viewBox="0 0 1200 756".');
|
|
114
|
+
}
|
|
115
|
+
return { ok: true, svg: svg2 };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ../design/dist/chunk-HIVKVAE6.js
|
|
119
|
+
var shaderFunctions = [
|
|
120
|
+
"abs",
|
|
121
|
+
"acos",
|
|
122
|
+
"asin",
|
|
123
|
+
"atan",
|
|
124
|
+
"atan2",
|
|
125
|
+
"ceil",
|
|
126
|
+
"clamp",
|
|
127
|
+
"cos",
|
|
128
|
+
"cross",
|
|
129
|
+
"distance",
|
|
130
|
+
"dot",
|
|
131
|
+
"exp",
|
|
132
|
+
"exp2",
|
|
133
|
+
"floor",
|
|
134
|
+
"fract",
|
|
135
|
+
"length",
|
|
136
|
+
"log",
|
|
137
|
+
"log2",
|
|
138
|
+
"max",
|
|
139
|
+
"min",
|
|
140
|
+
"mix",
|
|
141
|
+
"normalize",
|
|
142
|
+
"pow",
|
|
143
|
+
"reflect",
|
|
144
|
+
"round",
|
|
145
|
+
"select",
|
|
146
|
+
"sign",
|
|
147
|
+
"sin",
|
|
148
|
+
"smoothstep",
|
|
149
|
+
"sqrt",
|
|
150
|
+
"step",
|
|
151
|
+
"tan",
|
|
152
|
+
"tanh",
|
|
153
|
+
"trunc",
|
|
154
|
+
"vec2f",
|
|
155
|
+
"vec3f",
|
|
156
|
+
"vec4f",
|
|
157
|
+
"f32",
|
|
158
|
+
"noise2",
|
|
159
|
+
"cells2"
|
|
160
|
+
];
|
|
161
|
+
var functions = new Set(shaderFunctions);
|
|
162
|
+
var inputs = ["p", "t", "pointer", "seed"];
|
|
163
|
+
function shaderCodeIssue(code) {
|
|
164
|
+
if (!code || code.length > 4800) return "Usa una f\xF3rmula de hasta 4800 caracteres.";
|
|
165
|
+
if (!/^[\x20-\x7e\n\r\t]+$/.test(code) || /\/[/*]|\*\//.test(code))
|
|
166
|
+
return "La f\xF3rmula solo admite c\xF3digo sin comentarios.";
|
|
167
|
+
const statements = code.trim().split(";");
|
|
168
|
+
if (statements.pop()?.trim() || statements.length < 1 || statements.length > 40)
|
|
169
|
+
return "La f\xF3rmula debe terminar en return y tener hasta 40 instrucciones.";
|
|
170
|
+
const names = /* @__PURE__ */ new Set([...inputs, ...shaderFunctions, "true", "false"]);
|
|
171
|
+
let tokens = 0;
|
|
172
|
+
let calls = 0;
|
|
173
|
+
let noiseCalls = 0;
|
|
174
|
+
for (const [index, statement] of statements.entries()) {
|
|
175
|
+
const last = index === statements.length - 1;
|
|
176
|
+
const match = last ? /^\s*return\s+([\s\S]+)$/.exec(statement) : /^\s*let\s+([A-Za-z][A-Za-z0-9_]*)\s*=\s*([\s\S]+)$/.exec(statement);
|
|
177
|
+
if (!match) return "Usa declaraciones let y un \xFAnico return final.";
|
|
178
|
+
const name = last ? void 0 : match[1];
|
|
179
|
+
if (name && (names.has(name) || name.startsWith("__"))) return "Nombre reservado o repetido.";
|
|
180
|
+
const expression = last ? match[1] : match[2];
|
|
181
|
+
const parts = expression.match(
|
|
182
|
+
/(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?f?|[A-Za-z_][A-Za-z0-9_]*|\s+|&&|\|\||==|!=|<=|>=|[().,+\-*/%<>!]/g
|
|
183
|
+
) ?? [];
|
|
184
|
+
if (parts.join("") !== expression) return "La f\xF3rmula contiene sintaxis no admitida.";
|
|
185
|
+
const significant = parts.filter((part) => part.trim());
|
|
186
|
+
let depth = 0;
|
|
187
|
+
for (const [i, part] of significant.entries()) {
|
|
188
|
+
if (++tokens > 700) return "La f\xF3rmula es demasiado compleja.";
|
|
189
|
+
if (part === "(" && ++depth > 16) return "Demasiados niveles en la f\xF3rmula.";
|
|
190
|
+
if (part === ")" && --depth < 0) return "Par\xE9ntesis incompletos.";
|
|
191
|
+
if (!/^[A-Za-z_]/.test(part)) continue;
|
|
192
|
+
if (significant[i - 1] === ".") {
|
|
193
|
+
if (!/^[xyzwrgba]{1,4}$/.test(part)) return "Solo se permiten componentes de vectores.";
|
|
194
|
+
} else if (significant[i + 1] === "(") {
|
|
195
|
+
if (!functions.has(part)) return `Funci\xF3n no admitida: ${part}.`;
|
|
196
|
+
if (++calls > 80) return "La f\xF3rmula admite hasta 80 llamadas.";
|
|
197
|
+
if ((part === "noise2" || part === "cells2") && ++noiseCalls > 12)
|
|
198
|
+
return "Usa como m\xE1ximo 12 muestras de ruido.";
|
|
199
|
+
} else if (!names.has(part)) return "La f\xF3rmula usa una variable no disponible.";
|
|
200
|
+
}
|
|
201
|
+
if (depth !== 0) return "Par\xE9ntesis incompletos.";
|
|
202
|
+
if (name) names.add(name);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ../design/dist/chunk-6WXIEGBU.js
|
|
207
|
+
import { z } from "zod";
|
|
208
|
+
var text = (max2) => z.string().trim().min(1).max(max2).regex(/^[^\p{Cc}\p{Cf}]+$/u);
|
|
209
|
+
var range = (min, max2) => z.number().finite().min(min).max(max2);
|
|
210
|
+
var color = z.string().regex(/^#[0-9a-fA-F]{6}$/);
|
|
211
|
+
var prismFieldSchema = z.object({
|
|
212
|
+
layers: z.array(
|
|
213
|
+
z.object({
|
|
214
|
+
basis: z.enum(["noise", "cells", "ribbons", "rings"]),
|
|
215
|
+
scale: range(0.5, 6),
|
|
216
|
+
stretch: range(0.3, 3),
|
|
217
|
+
angle: range(-180, 180),
|
|
218
|
+
warp: range(0, 2),
|
|
219
|
+
drift: range(-0.5, 0.5),
|
|
220
|
+
weight: range(0.1, 1),
|
|
221
|
+
blend: z.enum(["add", "multiply"])
|
|
222
|
+
}).strict()
|
|
223
|
+
).min(1).max(4).refine((layers) => layers[0]?.blend === "add", "Start with an additive layer."),
|
|
224
|
+
relief: range(0, 1),
|
|
225
|
+
refraction: range(0, 0.5),
|
|
226
|
+
film: range(0, 1),
|
|
227
|
+
coverage: range(0.15, 1)
|
|
228
|
+
}).strict();
|
|
229
|
+
var prismShaderSchema = z.object({
|
|
230
|
+
version: z.literal(1),
|
|
231
|
+
code: z.string().max(4800).superRefine((code, ctx) => {
|
|
232
|
+
const issue = shaderCodeIssue(code);
|
|
233
|
+
if (issue) ctx.addIssue({ code: z.ZodIssueCode.custom, message: issue });
|
|
234
|
+
})
|
|
235
|
+
}).strict();
|
|
236
|
+
var prismStyleSchema = z.object({
|
|
237
|
+
version: z.literal(1),
|
|
238
|
+
name: text(48),
|
|
239
|
+
description: text(160),
|
|
240
|
+
surface: z.enum(["prism", "satin", "chrome"]),
|
|
241
|
+
finish: z.enum(["crystal", "opal", "obsidian"]),
|
|
242
|
+
palette: z.array(color).length(3),
|
|
243
|
+
accent: color,
|
|
244
|
+
portrait: z.object({ strength: range(0, 1), saturation: range(0, 1.5), contrast: range(0.65, 1.4) }).strict(),
|
|
245
|
+
texture: z.object({
|
|
246
|
+
pattern: z.enum(["none", "grain", "contours", "brushed", "grid"]),
|
|
247
|
+
amount: range(0, 0.45),
|
|
248
|
+
scale: range(0.25, 2)
|
|
249
|
+
}).strict(),
|
|
250
|
+
material: z.object({ roughness: range(0.12, 0.85), iridescence: range(0, 0.65) }).strict(),
|
|
251
|
+
field: prismFieldSchema.optional(),
|
|
252
|
+
shader: prismShaderSchema.optional(),
|
|
253
|
+
motion: z.object({ speed: range(0, 1), amplitude: range(0, 0.75) }).strict(),
|
|
254
|
+
heading: z.enum(["sans", "serif", "mono"])
|
|
255
|
+
}).strict();
|
|
256
|
+
var prismRecipeSchema = prismStyleSchema.extend({
|
|
257
|
+
material: z.object({ roughness: range(0, 1), iridescence: range(0, 0.65) }).strict(),
|
|
258
|
+
seed: z.number().int().min(0).max(4294967295),
|
|
259
|
+
promptVersion: z.enum([
|
|
260
|
+
"style-director-v1",
|
|
261
|
+
"material-director-v2",
|
|
262
|
+
"material-director-v3",
|
|
263
|
+
"shader-director-v1",
|
|
264
|
+
"shader-director-v2"
|
|
265
|
+
]),
|
|
266
|
+
model: text(100)
|
|
267
|
+
}).strict().refine((recipe) => !recipe.shader || Boolean(recipe.field), {
|
|
268
|
+
path: ["field"],
|
|
269
|
+
message: "A shader material requires a fallback field."
|
|
270
|
+
});
|
|
271
|
+
var styleRequestSchema = z.object({
|
|
272
|
+
prompt: text(600),
|
|
273
|
+
mode: z.enum(["compositor", "shader"]).optional(),
|
|
274
|
+
current: prismRecipeSchema.optional()
|
|
275
|
+
}).strict();
|
|
276
|
+
var styleOutputSchema = z.object({
|
|
277
|
+
styles: z.array(prismStyleSchema.extend({ field: prismFieldSchema })).min(1).max(3)
|
|
278
|
+
}).strict();
|
|
279
|
+
var generatedUnitControl = (bounds) => range(0, 1).transform((value) => Math.min(bounds.maxValue ?? 1, Math.max(bounds.minValue ?? 0, value))).pipe(bounds);
|
|
280
|
+
var generatedColor = z.string().trim().regex(
|
|
281
|
+
/^#{0,2}[0-9a-fA-F]{6}$/,
|
|
282
|
+
"Use six hexadecimal digits, e.g. #e06c9f. Convert color names to hex; no CSS names or functions."
|
|
283
|
+
).transform((value) => `#${value.replace(/^#+/, "")}`).pipe(color).describe("A six-digit hexadecimal color with one #, e.g. #e06c9f. No color names.");
|
|
284
|
+
var styleGenerationSchema = z.object({
|
|
285
|
+
styles: z.array(
|
|
286
|
+
prismStyleSchema.omit({ version: true, shader: true }).extend({
|
|
287
|
+
field: prismFieldSchema,
|
|
288
|
+
palette: z.array(generatedColor).length(3),
|
|
289
|
+
accent: generatedColor,
|
|
290
|
+
material: prismStyleSchema.shape.material.extend({
|
|
291
|
+
roughness: generatedUnitControl(prismStyleSchema.shape.material.shape.roughness),
|
|
292
|
+
iridescence: generatedUnitControl(prismStyleSchema.shape.material.shape.iridescence)
|
|
293
|
+
})
|
|
294
|
+
})
|
|
295
|
+
).min(1).max(3)
|
|
296
|
+
}).strict();
|
|
297
|
+
var shaderGenerationSchema = z.object({
|
|
298
|
+
style: styleGenerationSchema.shape.styles.element.extend({
|
|
299
|
+
shader: prismShaderSchema.omit({ version: true }).extend({
|
|
300
|
+
code: prismShaderSchema.shape.code.refine(
|
|
301
|
+
(code) => !/\bnormalize\s*\(/.test(code),
|
|
302
|
+
"normalize can receive a zero vector. Use v / max(length(v), 0.0001) instead."
|
|
303
|
+
)
|
|
304
|
+
})
|
|
305
|
+
})
|
|
306
|
+
}).strict();
|
|
307
|
+
|
|
308
|
+
// ../design/dist/chunk-UM5HMGRC.js
|
|
309
|
+
import { z as z3 } from "zod";
|
|
310
|
+
import { z as z2 } from "zod";
|
|
311
|
+
import { z as z22 } from "zod";
|
|
312
|
+
var CONTACTLESS_ARCS = [
|
|
313
|
+
"M1060 134 Q1068 143 1060 152",
|
|
314
|
+
"M1072 124 Q1088 143 1072 162",
|
|
315
|
+
"M1084 114 Q1108 143 1084 172",
|
|
316
|
+
"M1096 104 Q1128 143 1096 182"
|
|
317
|
+
];
|
|
318
|
+
var CONTACTLESS_STROKE_WIDTH = 7.5;
|
|
319
|
+
var DEFAULT_CARD_DETAILS = {
|
|
320
|
+
showChip: true,
|
|
321
|
+
chipColor: "#d9b875",
|
|
322
|
+
chipSlot: "middle-left",
|
|
323
|
+
showContactless: true,
|
|
324
|
+
contactlessColor: "#ffffff",
|
|
325
|
+
contactlessSlot: "upper-right",
|
|
326
|
+
network: "mastercard",
|
|
327
|
+
networkColorMode: "brand",
|
|
328
|
+
networkSlot: "lower-right",
|
|
329
|
+
visaVariant: "boxed"
|
|
330
|
+
};
|
|
331
|
+
var CHIP_OFFSET = {
|
|
332
|
+
"middle-left": [0, 0],
|
|
333
|
+
"upper-left": [0, -125]
|
|
334
|
+
};
|
|
335
|
+
var CONTACTLESS_OFFSET = {
|
|
336
|
+
"upper-right": [-70, 60],
|
|
337
|
+
"middle-right": [-70, 245]
|
|
338
|
+
};
|
|
339
|
+
var NETWORK_ORIGIN = {
|
|
340
|
+
"lower-right": {
|
|
341
|
+
mastercard: [990, 585],
|
|
342
|
+
visa: [905, 550],
|
|
343
|
+
amex: [995, 565],
|
|
344
|
+
discover: [925, 600]
|
|
345
|
+
},
|
|
346
|
+
"upper-right": {
|
|
347
|
+
mastercard: [990, 290],
|
|
348
|
+
visa: [905, 290],
|
|
349
|
+
amex: [995, 280],
|
|
350
|
+
discover: [925, 300]
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
var VISA_PATH = "m 651.18503,0.50000002 c -70.93272,0 -134.32163,36.76584998 -134.32163,104.69357998 0,77.90028 112.42264,83.28082 112.42264,122.41576 0,16.47806 -18.88384,31.22851 -51.13668,31.22851 -45.77308,0 -79.98403,-20.61081 -79.98403,-20.61081 l -14.63836,68.54658 c 0,0 39.41037,17.40989 91.73375,17.40989 77.55217,0 138.57651,-38.57104 138.57651,-107.66029 0,-82.3157 -112.89106,-87.53633 -112.89106,-123.86008 0,-12.9082 15.50201,-27.05169 47.66251,-27.05169 36.28682,0 65.89216,14.98968 65.89216,14.98968 l 14.32608,-66.20444 c 0,0 -32.21317,-13.89668998 -77.64189,-13.89668998 z M 2.2175605,5.49657 0.49999253,15.48969 c 0,0 29.84159547,5.46149 56.71878047,16.35593 34.606624,12.4927 37.071853,19.7653 42.900167,42.35367 l 63.51098,244.83152 85.13673,0 131.15974,-313.53424 -84.94155,0 L 210.7069,218.67018 176.3165,37.97422 C 173.1626,17.29371 157.18709,5.49657 137.63219,5.49657 l -135.4146295,0 z m 411.8650095,0 -66.63383,313.53424 80.99895,0 66.39962,-313.53424 -80.76474,0 z m 451.75943,0 c -19.53181,0 -29.88045,10.45695 -37.47421,28.73022 l -118.66834,284.80402 84.94155,0 16.434,-47.46734 103.48348,0 9.99312,47.46734 74.94843,0 -65.3847,-313.53424 -68.27333,0 z m 11.04709,84.70733 25.17799,117.65341 -67.45359,0 42.2756,-117.65341 z";
|
|
354
|
+
function networkMarkup(network, mode, visaVariant) {
|
|
355
|
+
const mono = mode === "white" ? "#ffffff" : "#111111";
|
|
356
|
+
if (network === "mastercard") {
|
|
357
|
+
const red = mode === "brand" ? "#eb001b" : mono;
|
|
358
|
+
const yellow = mode === "brand" ? "#f79e1b" : mono;
|
|
359
|
+
const orange = mode === "brand" ? "#ff5f00" : mono;
|
|
360
|
+
return `<circle cx="50" cy="42" r="39" fill="${red}"/><circle cx="96" cy="42" r="39" fill="${yellow}"/><circle cx="96" cy="42" r="39" fill="${orange}" clip-path="url(#mc-overlap)"/>`;
|
|
361
|
+
}
|
|
362
|
+
if (network === "visa") {
|
|
363
|
+
const color22 = visaVariant === "boxed" || mode === "brand" ? "url(#visa-brand)" : mono;
|
|
364
|
+
const mark = `<path d="${VISA_PATH}" fill="${color22}"/>`;
|
|
365
|
+
return visaVariant === "boxed" ? `<rect width="240" height="120" fill="#ffffff"/><g transform="translate(10 24) scale(.22)">${mark}</g>` : `<g transform="translate(15 0) scale(.22)">${mark}</g>`;
|
|
366
|
+
}
|
|
367
|
+
if (network === "amex") {
|
|
368
|
+
const background = mode === "brand" ? "#2e77bc" : mono;
|
|
369
|
+
const foreground = mode === "black" ? "#ffffff" : mode === "white" ? "#111111" : "#ffffff";
|
|
370
|
+
return `<rect width="142" height="94" rx="4" fill="${background}"/><text x="71" y="42" text-anchor="middle" fill="${foreground}" font-family="Arial,Helvetica,sans-serif" font-size="23" font-weight="900" letter-spacing="-1.5">AMERICAN</text><text x="71" y="70" text-anchor="middle" fill="${foreground}" font-family="Arial,Helvetica,sans-serif" font-size="27" font-weight="900" letter-spacing="-1.8">EXPRESS</text>`;
|
|
371
|
+
}
|
|
372
|
+
const ink = mode === "brand" ? "#202024" : mono;
|
|
373
|
+
const sun = mode === "brand" ? "#f58220" : mono;
|
|
374
|
+
return `<g transform="scale(.88)"><g font-family="Arial,Helvetica,sans-serif" font-size="44" font-weight="900" letter-spacing="-2" fill="${ink}"><text x="0" y="63">DISC</text><text x="153" y="63">VER</text></g><circle cx="132" cy="46" r="19" fill="none" stroke="${sun}" stroke-width="10"/></g>`;
|
|
375
|
+
}
|
|
376
|
+
function cardDetailsSvg(details) {
|
|
377
|
+
const [chipX, chipY] = CHIP_OFFSET[details.chipSlot];
|
|
378
|
+
const [contactlessX, contactlessY] = CONTACTLESS_OFFSET[details.contactlessSlot];
|
|
379
|
+
const [networkX, networkY] = details.network === "none" ? [0, 0] : NETWORK_ORIGIN[details.networkSlot][details.network];
|
|
380
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="756" viewBox="0 0 1200 756">
|
|
381
|
+
<defs>
|
|
382
|
+
<linearGradient id="metal" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#fff" stop-opacity=".8"/><stop offset=".22" stop-color="#000" stop-opacity=".18"/><stop offset=".48" stop-color="#fff" stop-opacity=".55"/><stop offset=".72" stop-color="#000" stop-opacity=".26"/><stop offset="1" stop-color="#fff" stop-opacity=".35"/></linearGradient>
|
|
383
|
+
<linearGradient id="visa-brand" x1="0" y1="0" x2="1000" y2="0" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#20225f"/><stop offset=".2" stop-color="#1a1f61"/><stop offset=".41" stop-color="#172272"/><stop offset=".6" stop-color="#152682"/><stop offset=".8" stop-color="#12288e"/><stop offset="1" stop-color="#0e2c9a"/></linearGradient>
|
|
384
|
+
<clipPath id="mc-overlap"><circle cx="50" cy="42" r="39"/></clipPath>
|
|
385
|
+
</defs>
|
|
386
|
+
${details.showChip ? `<g transform="translate(${chipX} ${chipY})"><rect x="84" y="357" width="151" height="112" rx="17" fill="#100e0b" fill-opacity=".8" stroke="${details.chipColor}" stroke-opacity=".32" stroke-width="2"/><rect x="90" y="363" width="139" height="100" rx="13" fill="${details.chipColor}" stroke="#fff" stroke-opacity=".65" stroke-width="2"/><rect x="90" y="363" width="139" height="100" rx="13" fill="url(#metal)"/><path d="M90 397H229M90 430H229M137 363V463M183 363V463" fill="none" stroke="#1b1715" stroke-opacity=".55" stroke-width="2.4"/><rect x="137" y="397" width="46" height="33" rx="8" fill="none" stroke="#1b1715" stroke-opacity=".7" stroke-width="2.4"/><path d="M137 412H90M183 412H229" stroke="#fff" stroke-opacity=".55" stroke-width="1.2"/></g>` : ""}
|
|
387
|
+
${details.showContactless ? `<g transform="translate(${contactlessX} ${contactlessY}) translate(1086 143) scale(1.3 1.15) translate(-1086 -143)" fill="none" stroke="${details.contactlessColor}" stroke-width="${CONTACTLESS_STROKE_WIDTH}" stroke-linecap="round" stroke-linejoin="round">${CONTACTLESS_ARCS.map((arc) => `<path d="${arc}"/>`).join("")}</g>` : ""}
|
|
388
|
+
${details.network === "none" ? "" : `<g transform="translate(${networkX} ${networkY + (details.network === "visa" && details.visaVariant === "plain" ? 45 : 0)})">${networkMarkup(details.network, details.networkColorMode, details.visaVariant)}</g>`}
|
|
389
|
+
</svg>`;
|
|
390
|
+
}
|
|
391
|
+
var NETWORK_SIZE = {
|
|
392
|
+
mastercard: { x: 8, y: 0, w: 130, h: 84 },
|
|
393
|
+
visa: { x: 0, y: 0, w: 240, h: 120 },
|
|
394
|
+
amex: { x: 0, y: 0, w: 142, h: 94 },
|
|
395
|
+
discover: { x: 0, y: 0, w: 228, h: 66 }
|
|
396
|
+
};
|
|
397
|
+
function cardMarkRegion(spec) {
|
|
398
|
+
if (spec.mark === "chip") {
|
|
399
|
+
const [, dy] = CHIP_OFFSET[spec.slot] ?? [0, 0];
|
|
400
|
+
return { x: 82, y: 355 + dy, w: 155, h: 116 };
|
|
401
|
+
}
|
|
402
|
+
if (spec.mark === "contactless") {
|
|
403
|
+
const [dx, dy] = CONTACTLESS_OFFSET[spec.slot] ?? [0, 0];
|
|
404
|
+
return { x: 1036 + dx, y: 86 + dy, w: 92, h: 114 };
|
|
405
|
+
}
|
|
406
|
+
const network = spec.network ?? "mastercard";
|
|
407
|
+
const [ox, oy] = NETWORK_ORIGIN[spec.slot]?.[network] ?? [0, 0];
|
|
408
|
+
const size = NETWORK_SIZE[network];
|
|
409
|
+
if (network === "visa" && spec.visaVariant === "plain")
|
|
410
|
+
return { x: ox + 15, y: oy + 45, w: 222, h: 76 };
|
|
411
|
+
return { x: ox + size.x, y: oy + size.y, w: size.w, h: size.h };
|
|
412
|
+
}
|
|
413
|
+
function cardMarkSvg(spec) {
|
|
414
|
+
const details = {
|
|
415
|
+
...DEFAULT_CARD_DETAILS,
|
|
416
|
+
showChip: spec.mark === "chip",
|
|
417
|
+
showContactless: spec.mark === "contactless",
|
|
418
|
+
network: spec.mark === "network" ? spec.network ?? "mastercard" : "none"
|
|
419
|
+
};
|
|
420
|
+
if (spec.mark === "chip") {
|
|
421
|
+
details.chipSlot = spec.slot;
|
|
422
|
+
if (spec.color) details.chipColor = spec.color;
|
|
423
|
+
} else if (spec.mark === "contactless") {
|
|
424
|
+
details.contactlessSlot = spec.slot;
|
|
425
|
+
if (spec.color) details.contactlessColor = spec.color;
|
|
426
|
+
} else {
|
|
427
|
+
details.networkSlot = spec.slot;
|
|
428
|
+
details.networkColorMode = spec.colorMode ?? "brand";
|
|
429
|
+
details.visaVariant = spec.visaVariant ?? "boxed";
|
|
430
|
+
}
|
|
431
|
+
const { x, y, w, h } = cardMarkRegion(spec);
|
|
432
|
+
return cardDetailsSvg(details).replace(
|
|
433
|
+
'width="1200" height="756" viewBox="0 0 1200 756"',
|
|
434
|
+
`width="${w}" height="${h}" viewBox="${x} ${y} ${w} ${h}"`
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
var printProductIds = ["badge", "card", "sticker"];
|
|
438
|
+
var digitalProductIds = ["post", "square", "story", "landscape"];
|
|
439
|
+
var productIds = [...printProductIds, ...digitalProductIds];
|
|
440
|
+
var designProfiles = {
|
|
441
|
+
badge: {
|
|
442
|
+
id: "badge",
|
|
443
|
+
label: "Badge",
|
|
444
|
+
width: 1024,
|
|
445
|
+
height: 1536,
|
|
446
|
+
kinds: ["text", "shape", "portrait", "graphic", "effect", "gradient", "image"],
|
|
447
|
+
keepClear: [],
|
|
448
|
+
preview: "lanyard"
|
|
449
|
+
},
|
|
450
|
+
card: {
|
|
451
|
+
id: "card",
|
|
452
|
+
label: "Card",
|
|
453
|
+
width: 1200,
|
|
454
|
+
height: 756,
|
|
455
|
+
kinds: ["text", "shape", "graphic", "gradient", "effect"],
|
|
456
|
+
// Wallet prints the masked card number here; estimated from a Wallet screenshot.
|
|
457
|
+
keepClear: [{ label: "card number", x: 64, y: 615, w: 406, h: 100 }],
|
|
458
|
+
preview: "card"
|
|
459
|
+
},
|
|
460
|
+
sticker: {
|
|
461
|
+
id: "sticker",
|
|
462
|
+
label: "Sticker",
|
|
463
|
+
width: 1024,
|
|
464
|
+
height: 1024,
|
|
465
|
+
kinds: ["text", "shape", "graphic", "gradient", "image"],
|
|
466
|
+
keepClear: [],
|
|
467
|
+
preview: "die-cut"
|
|
468
|
+
},
|
|
469
|
+
post: digitalProfile("post", "Post", 1080, 1350),
|
|
470
|
+
square: digitalProfile("square", "Square", 1080, 1080),
|
|
471
|
+
story: digitalProfile("story", "Story", 1080, 1920),
|
|
472
|
+
landscape: digitalProfile("landscape", "Landscape", 1920, 1080)
|
|
473
|
+
};
|
|
474
|
+
function digitalProfile(id3, label, width, height) {
|
|
475
|
+
return {
|
|
476
|
+
id: id3,
|
|
477
|
+
label,
|
|
478
|
+
width,
|
|
479
|
+
height,
|
|
480
|
+
kinds: ["text", "shape", "portrait", "graphic", "gradient", "effect", "image"],
|
|
481
|
+
keepClear: [],
|
|
482
|
+
preview: "flat",
|
|
483
|
+
digital: true
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
function designProfile(design) {
|
|
487
|
+
return designProfiles[design.product ?? "badge"];
|
|
488
|
+
}
|
|
489
|
+
var stickerMaterialSchema = z2.object({
|
|
490
|
+
finish: z2.enum(["glitter", "holographic", "vinyl"]),
|
|
491
|
+
/** Die-cut border in canvas pixels; `widthMm` gives it a printed size. */
|
|
492
|
+
border: z2.number().min(0).max(40),
|
|
493
|
+
/** Printed width of the square canvas. Defaults to 75 mm. */
|
|
494
|
+
widthMm: z2.number().min(10).max(300).optional(),
|
|
495
|
+
sparkle: z2.number().min(0).max(1),
|
|
496
|
+
gloss: z2.number().min(0).max(1.5),
|
|
497
|
+
seed: z2.number().int().min(0).max(4294967295),
|
|
498
|
+
holography: z2.number().min(0).max(1).optional(),
|
|
499
|
+
relief: z2.number().min(0).max(1.5).optional(),
|
|
500
|
+
flakes: z2.number().min(40).max(500).optional(),
|
|
501
|
+
stock: z2.enum(["white", "holographic", "holo-glitter"]).optional(),
|
|
502
|
+
laminate: z2.enum(["gloss", "matte"]).optional(),
|
|
503
|
+
liner: z2.string().min(1).max(40).optional(),
|
|
504
|
+
/** RGB = foil, glitter, relief. Follow the named image layer's placement and alpha. */
|
|
505
|
+
effectMap: z2.object({
|
|
506
|
+
asset: z2.string().regex(/^[a-z][a-z0-9-]{0,39}$/),
|
|
507
|
+
layer: z2.string().min(1).max(80)
|
|
508
|
+
}).optional(),
|
|
509
|
+
/** Optical overrides follow editable layer geometry, including later transforms. */
|
|
510
|
+
regions: z2.record(
|
|
511
|
+
z2.string().min(1).max(80),
|
|
512
|
+
z2.object({
|
|
513
|
+
foil: z2.number().min(0).max(1),
|
|
514
|
+
glitter: z2.number().min(0).max(1),
|
|
515
|
+
relief: z2.number().min(0).max(1)
|
|
516
|
+
})
|
|
517
|
+
).optional()
|
|
518
|
+
});
|
|
519
|
+
var defaultStickerMaterial = {
|
|
520
|
+
finish: "glitter",
|
|
521
|
+
border: 18,
|
|
522
|
+
sparkle: 0.72,
|
|
523
|
+
gloss: 0.5,
|
|
524
|
+
seed: 280926
|
|
525
|
+
};
|
|
526
|
+
var tags = /* @__PURE__ */ new Set([
|
|
527
|
+
"g",
|
|
528
|
+
"defs",
|
|
529
|
+
"rect",
|
|
530
|
+
"circle",
|
|
531
|
+
"ellipse",
|
|
532
|
+
"path",
|
|
533
|
+
"line",
|
|
534
|
+
"polyline",
|
|
535
|
+
"polygon",
|
|
536
|
+
"text",
|
|
537
|
+
"tspan",
|
|
538
|
+
"image",
|
|
539
|
+
"use",
|
|
540
|
+
"symbol",
|
|
541
|
+
"linearGradient",
|
|
542
|
+
"radialGradient",
|
|
543
|
+
"stop",
|
|
544
|
+
"pattern",
|
|
545
|
+
"clipPath",
|
|
546
|
+
"mask",
|
|
547
|
+
"filter",
|
|
548
|
+
"feTurbulence",
|
|
549
|
+
"feColorMatrix",
|
|
550
|
+
"feGaussianBlur",
|
|
551
|
+
"feMerge",
|
|
552
|
+
"feMergeNode",
|
|
553
|
+
"feDropShadow",
|
|
554
|
+
"feOffset"
|
|
555
|
+
]);
|
|
556
|
+
var attributes = /* @__PURE__ */ new Set([
|
|
557
|
+
"viewBox",
|
|
558
|
+
"width",
|
|
559
|
+
"height",
|
|
560
|
+
"role",
|
|
561
|
+
"aria-label",
|
|
562
|
+
"aria-labelledby",
|
|
563
|
+
"id",
|
|
564
|
+
"x1",
|
|
565
|
+
"y1",
|
|
566
|
+
"x2",
|
|
567
|
+
"y2",
|
|
568
|
+
"offset",
|
|
569
|
+
"stop-color",
|
|
570
|
+
"x",
|
|
571
|
+
"y",
|
|
572
|
+
"type",
|
|
573
|
+
"baseFrequency",
|
|
574
|
+
"numOctaves",
|
|
575
|
+
"seed",
|
|
576
|
+
"stitchTiles",
|
|
577
|
+
"values",
|
|
578
|
+
"fill",
|
|
579
|
+
"d",
|
|
580
|
+
"stroke",
|
|
581
|
+
"stroke-width",
|
|
582
|
+
"opacity",
|
|
583
|
+
"cx",
|
|
584
|
+
"cy",
|
|
585
|
+
"r",
|
|
586
|
+
"style",
|
|
587
|
+
"clip-path",
|
|
588
|
+
"filter",
|
|
589
|
+
"gradientUnits",
|
|
590
|
+
"stop-opacity",
|
|
591
|
+
"stdDeviation",
|
|
592
|
+
"result",
|
|
593
|
+
"in",
|
|
594
|
+
"mask",
|
|
595
|
+
"rx",
|
|
596
|
+
"transform",
|
|
597
|
+
"ry",
|
|
598
|
+
"patternUnits",
|
|
599
|
+
"shape-rendering",
|
|
600
|
+
"href",
|
|
601
|
+
"stroke-opacity",
|
|
602
|
+
"font-family",
|
|
603
|
+
"font-size",
|
|
604
|
+
"font-weight",
|
|
605
|
+
"letter-spacing",
|
|
606
|
+
"fill-opacity",
|
|
607
|
+
"stroke-linecap",
|
|
608
|
+
"stroke-linejoin",
|
|
609
|
+
"text-anchor",
|
|
610
|
+
"stroke-dasharray",
|
|
611
|
+
"points",
|
|
612
|
+
"fill-rule",
|
|
613
|
+
"dx",
|
|
614
|
+
"dy",
|
|
615
|
+
"flood-color",
|
|
616
|
+
"preserveAspectRatio",
|
|
617
|
+
"gradientTransform",
|
|
618
|
+
"spreadMethod",
|
|
619
|
+
"clip-rule",
|
|
620
|
+
"color-interpolation-filters",
|
|
621
|
+
"filterUnits",
|
|
622
|
+
"maskUnits"
|
|
623
|
+
]);
|
|
624
|
+
var blend = /^mix-blend-mode:\s*(normal|multiply|screen|overlay|soft-light|hard-light|color-dodge|color-burn|darken|lighten);?$/;
|
|
625
|
+
var safeAttribute = (value, key) => {
|
|
626
|
+
if (!attributes.has(key)) return false;
|
|
627
|
+
if (key === "href")
|
|
628
|
+
return /^#[\w.-]+$/.test(value) || /^data:image\/(?:png|jpeg|webp|gif);base64,[A-Za-z0-9+/=]+$/.test(value);
|
|
629
|
+
if (key === "style") return blend.test(value);
|
|
630
|
+
if (/url\s*\(/i.test(value)) return /^url\(#[\w.-]+\)$/.test(value);
|
|
631
|
+
return !/[<>]/.test(value);
|
|
632
|
+
};
|
|
633
|
+
var svgNodeSchema = z22.lazy(
|
|
634
|
+
() => z22.object({
|
|
635
|
+
tag: z22.string().refine((tag) => tags.has(tag), "Unsupported SVG element"),
|
|
636
|
+
attrs: z22.record(z22.string().max(28e5)).superRefine((attrs, ctx) => {
|
|
637
|
+
for (const [key, value] of Object.entries(attrs))
|
|
638
|
+
if (!safeAttribute(value, key))
|
|
639
|
+
ctx.addIssue({ code: "custom", message: `Unsupported SVG attribute: ${key}` });
|
|
640
|
+
}).optional(),
|
|
641
|
+
text: z22.string().max(2e3).optional(),
|
|
642
|
+
children: z22.array(svgNodeSchema).max(1e3).optional()
|
|
643
|
+
})
|
|
644
|
+
);
|
|
645
|
+
var svgSourceSchema = z22.object({
|
|
646
|
+
definitions: z22.array(svgNodeSchema).max(100),
|
|
647
|
+
/** Provenance of the original file, not a network location. */
|
|
648
|
+
originalSha256: z22.string().regex(/^[a-f0-9]{64}$/),
|
|
649
|
+
attribution: z22.string().max(5e3).optional()
|
|
650
|
+
});
|
|
651
|
+
var escapeSvg = (value) => value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
652
|
+
function svgNodeXml(node, prefix = "", colors = {}) {
|
|
653
|
+
const attrs = Object.entries(node.attrs ?? {}).map(([key, original]) => {
|
|
654
|
+
let value = colors[original] ?? original;
|
|
655
|
+
if (key === "id") value = `${prefix}${value}`;
|
|
656
|
+
else if (key === "href" && value.startsWith("#")) value = `#${prefix}${value.slice(1)}`;
|
|
657
|
+
else value = value.replace(/url\(#([\w.-]+)\)/g, (_, id3) => `url(#${prefix}${id3})`);
|
|
658
|
+
return ` ${key}="${escapeSvg(value)}"`;
|
|
659
|
+
}).join("");
|
|
660
|
+
return `<${node.tag}${attrs}>${escapeSvg(node.text ?? "")}${(node.children ?? []).map((child) => svgNodeXml(child, prefix, colors)).join("")}</${node.tag}>`;
|
|
661
|
+
}
|
|
662
|
+
var color2 = z3.string().regex(/^#[0-9a-f]{6}(?:[0-9a-f]{2})?$/i);
|
|
663
|
+
var box = {
|
|
664
|
+
id: z3.string().regex(/^[a-z][a-z0-9-]{0,39}$/),
|
|
665
|
+
name: z3.string().min(1).max(80).optional(),
|
|
666
|
+
// Bounds of the largest canvas (story height, landscape width); designIssues checks each
|
|
667
|
+
// product's own canvas.
|
|
668
|
+
x: z3.number().min(0).max(1919),
|
|
669
|
+
y: z3.number().min(0).max(1919),
|
|
670
|
+
w: z3.number().min(1).max(1920),
|
|
671
|
+
h: z3.number().min(1).max(1920),
|
|
672
|
+
rotation: z3.number().min(-180).max(180).optional(),
|
|
673
|
+
opacity: z3.number().min(0).max(1).optional(),
|
|
674
|
+
visible: z3.boolean().optional(),
|
|
675
|
+
channel: z3.enum(["print", "ink"]).optional(),
|
|
676
|
+
protectMaterial: z3.boolean().optional(),
|
|
677
|
+
/** Card-only print finish: foil catches the light, raised is embossed on the front. */
|
|
678
|
+
finish: z3.enum(["foil", "raised"]).optional()
|
|
679
|
+
};
|
|
680
|
+
var text2 = z3.object({
|
|
681
|
+
...box,
|
|
682
|
+
kind: z3.literal("text"),
|
|
683
|
+
text: z3.string().max(160),
|
|
684
|
+
binding: z3.enum([
|
|
685
|
+
"none",
|
|
686
|
+
"name",
|
|
687
|
+
"role",
|
|
688
|
+
"organization",
|
|
689
|
+
"number",
|
|
690
|
+
"event",
|
|
691
|
+
"location",
|
|
692
|
+
"date",
|
|
693
|
+
"bio",
|
|
694
|
+
"roleOrganization",
|
|
695
|
+
"website",
|
|
696
|
+
"roleCode",
|
|
697
|
+
"admissionRole",
|
|
698
|
+
"signature",
|
|
699
|
+
"template"
|
|
700
|
+
]),
|
|
701
|
+
color: color2,
|
|
702
|
+
font: z3.enum([
|
|
703
|
+
"sans",
|
|
704
|
+
"serif",
|
|
705
|
+
"mono",
|
|
706
|
+
"display",
|
|
707
|
+
"brand",
|
|
708
|
+
"script",
|
|
709
|
+
"pixel",
|
|
710
|
+
"archive",
|
|
711
|
+
"rounded"
|
|
712
|
+
]),
|
|
713
|
+
strokeColor: color2.optional(),
|
|
714
|
+
strokeWidth: z3.number().min(0).max(40).optional(),
|
|
715
|
+
size: z3.number().min(12).max(220),
|
|
716
|
+
weight: z3.enum(["400", "500", "600", "700", "800", "900"]),
|
|
717
|
+
align: z3.enum(["left", "center", "right"]),
|
|
718
|
+
tracking: z3.number().min(-8).max(40).optional(),
|
|
719
|
+
lineHeight: z3.number().min(0.7).max(2).optional(),
|
|
720
|
+
transform: z3.enum(["none", "uppercase", "lowercase"]).optional(),
|
|
721
|
+
segment: z3.enum(["all", "first", "last"]).optional(),
|
|
722
|
+
fit: z3.enum(["wrap", "shrink", "spread"]).optional(),
|
|
723
|
+
baseline: z3.enum(["top", "alphabetic"]).optional(),
|
|
724
|
+
italic: z3.boolean().optional(),
|
|
725
|
+
prefix: z3.string().max(30).optional(),
|
|
726
|
+
suffix: z3.string().max(30).optional(),
|
|
727
|
+
highlights: z3.array(z3.object({ text: z3.string().min(1).max(40), color: color2 })).max(8).optional(),
|
|
728
|
+
baselineOffset: z3.number().min(0).max(260).optional(),
|
|
729
|
+
numberDigits: z3.number().int().min(1).max(8).optional()
|
|
730
|
+
});
|
|
731
|
+
var shape = z3.object({
|
|
732
|
+
...box,
|
|
733
|
+
kind: z3.literal("shape"),
|
|
734
|
+
shape: z3.enum(["rectangle", "ellipse", "line", "frame", "corners", "arch", "bevel"]),
|
|
735
|
+
color: color2,
|
|
736
|
+
radius: z3.number().min(0).max(160),
|
|
737
|
+
stroke: z3.number().min(0).max(20),
|
|
738
|
+
opacity: z3.number().min(0).max(1)
|
|
739
|
+
});
|
|
740
|
+
var portrait = z3.object({
|
|
741
|
+
...box,
|
|
742
|
+
kind: z3.literal("portrait"),
|
|
743
|
+
radius: z3.number().min(0).max(400),
|
|
744
|
+
filter: z3.enum([
|
|
745
|
+
"original",
|
|
746
|
+
"mono",
|
|
747
|
+
"rose",
|
|
748
|
+
"blue",
|
|
749
|
+
"warm",
|
|
750
|
+
"thermal",
|
|
751
|
+
"silver",
|
|
752
|
+
"cyanotype",
|
|
753
|
+
"vintage"
|
|
754
|
+
]),
|
|
755
|
+
crop: z3.object({
|
|
756
|
+
x: z3.number().min(0).max(1),
|
|
757
|
+
y: z3.number().min(0).max(1),
|
|
758
|
+
zoom: z3.number().min(1).max(12)
|
|
759
|
+
}).optional(),
|
|
760
|
+
cropMode: z3.enum(["cover", "focus"]).optional(),
|
|
761
|
+
fade: z3.object({
|
|
762
|
+
x: z3.number().min(0).max(0.5),
|
|
763
|
+
right: z3.number().min(0).max(0.5).optional(),
|
|
764
|
+
top: z3.number().min(0).max(0.5),
|
|
765
|
+
bottom: z3.number().min(0).max(0.5)
|
|
766
|
+
}).optional(),
|
|
767
|
+
tint: color2.optional(),
|
|
768
|
+
tintMode: z3.enum(["multiply", "color"]).optional(),
|
|
769
|
+
tintOpacity: z3.number().min(0).max(1).optional(),
|
|
770
|
+
contrast: z3.number().min(0.5).max(2).optional(),
|
|
771
|
+
brightness: z3.number().min(0.3).max(1.8).optional(),
|
|
772
|
+
blur: z3.number().min(0).max(24).optional(),
|
|
773
|
+
saturation: z3.number().min(0).max(2).optional(),
|
|
774
|
+
clip: z3.enum(["rectangle", "arch", "ellipse"]).optional()
|
|
775
|
+
});
|
|
776
|
+
var qr = z3.object({
|
|
777
|
+
...box,
|
|
778
|
+
kind: z3.literal("qr"),
|
|
779
|
+
foreground: color2.optional(),
|
|
780
|
+
background: color2.optional(),
|
|
781
|
+
align: z3.enum(["center", "start"]).optional(),
|
|
782
|
+
maxCellSize: z3.number().int().min(2).max(20).optional()
|
|
783
|
+
});
|
|
784
|
+
var effect = z3.object({
|
|
785
|
+
...box,
|
|
786
|
+
kind: z3.literal("effect"),
|
|
787
|
+
effect: z3.enum(["ribbons", "contours", "orbits", "grain", "chromatic-flow"]),
|
|
788
|
+
colors: z3.array(color2).length(3),
|
|
789
|
+
scale: z3.number().min(0.5).max(6),
|
|
790
|
+
opacity: z3.number().min(0).max(1)
|
|
791
|
+
});
|
|
792
|
+
var graphic = z3.object({
|
|
793
|
+
...box,
|
|
794
|
+
kind: z3.literal("graphic"),
|
|
795
|
+
pattern: z3.enum([
|
|
796
|
+
"grid",
|
|
797
|
+
"snow",
|
|
798
|
+
"sky",
|
|
799
|
+
"grain",
|
|
800
|
+
"terrain",
|
|
801
|
+
"seal",
|
|
802
|
+
"cross",
|
|
803
|
+
"window",
|
|
804
|
+
"stamp",
|
|
805
|
+
"scanlines",
|
|
806
|
+
"path",
|
|
807
|
+
"paper",
|
|
808
|
+
"chromatic-paper",
|
|
809
|
+
"checkerboard"
|
|
810
|
+
]),
|
|
811
|
+
color: color2,
|
|
812
|
+
ink: color2.optional(),
|
|
813
|
+
accent: color2,
|
|
814
|
+
density: z3.number().min(0.1).max(3),
|
|
815
|
+
seed: z3.number().int().min(0).max(4294967295),
|
|
816
|
+
path: z3.string().max(16e3).regex(/^[MmLlHhVvCcSsQqTtAaZz0-9.,eE+\-\s]*$/).optional(),
|
|
817
|
+
viewBox: z3.object({
|
|
818
|
+
width: z3.number().min(1).max(16384),
|
|
819
|
+
height: z3.number().min(1).max(16384)
|
|
820
|
+
}).optional(),
|
|
821
|
+
stroke: z3.number().min(0).max(20).optional(),
|
|
822
|
+
variant: z3.enum(["plain", "technical", "editorial", "postal", "snow", "grid", "waves"]).optional(),
|
|
823
|
+
reverse: z3.boolean().optional(),
|
|
824
|
+
fill: z3.boolean().optional()
|
|
825
|
+
});
|
|
826
|
+
var gradient = z3.object({
|
|
827
|
+
...box,
|
|
828
|
+
kind: z3.literal("gradient"),
|
|
829
|
+
direction: z3.enum(["horizontal", "vertical", "diagonal", "radial"]),
|
|
830
|
+
stops: z3.array(z3.object({ at: z3.number().min(0).max(1), color: color2 })).min(2).max(8)
|
|
831
|
+
});
|
|
832
|
+
var ART_ASSET = "art";
|
|
833
|
+
var assetId = z3.string().regex(/^[a-z][a-z0-9-]{0,39}$/);
|
|
834
|
+
var credit = z3.object({ label: z3.string().min(1).max(120), url: z3.string().url() });
|
|
835
|
+
var designAssetSchema = z3.discriminatedUnion("source", [
|
|
836
|
+
// Unchanged artwork and optical maps from an attributed bundled sticker collection.
|
|
837
|
+
z3.object({
|
|
838
|
+
source: z3.literal("sticker"),
|
|
839
|
+
collection: z3.enum(["typingmind", "community", "moraleja"]),
|
|
840
|
+
slug: z3.string().regex(/^[a-z0-9-]{1,80}$/),
|
|
841
|
+
file: z3.enum(["artwork", "effects"]),
|
|
842
|
+
name: z3.string().min(1).max(80),
|
|
843
|
+
credit
|
|
844
|
+
}),
|
|
845
|
+
// A Petdex sprite bundled with Makeables, served from /stickers/petdex/<slug>.webp.
|
|
846
|
+
z3.object({
|
|
847
|
+
source: z3.literal("petdex"),
|
|
848
|
+
slug: z3.string().regex(/^[a-z0-9-]{1,80}$/),
|
|
849
|
+
name: z3.string().min(1).max(80),
|
|
850
|
+
credit: credit.optional()
|
|
851
|
+
}),
|
|
852
|
+
// A Makeables gallery artwork, served as a raster preview.
|
|
853
|
+
z3.object({
|
|
854
|
+
source: z3.literal("gallery"),
|
|
855
|
+
slug: z3.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/),
|
|
856
|
+
/** editor-artwork.svg is the same art without baked-in card details. */
|
|
857
|
+
file: z3.enum(["artwork.svg", "editor-artwork.svg"]).optional(),
|
|
858
|
+
name: z3.string().min(1).max(80)
|
|
859
|
+
}),
|
|
860
|
+
// An image embedded in the document, so it renders anywhere without a store.
|
|
861
|
+
z3.object({
|
|
862
|
+
source: z3.literal("image"),
|
|
863
|
+
name: z3.string().min(1).max(80),
|
|
864
|
+
data: z3.string().regex(/^data:image\/(png|webp|jpeg|gif|svg\+xml);base64,[A-Za-z0-9+/=]+$/).max(28e5).superRefine((value, context) => {
|
|
865
|
+
if (!value.startsWith("data:image/svg+xml;base64,")) return;
|
|
866
|
+
try {
|
|
867
|
+
const svg2 = new TextDecoder().decode(
|
|
868
|
+
Uint8Array.from(atob(value.split(",")[1]), (c) => c.charCodeAt(0))
|
|
869
|
+
);
|
|
870
|
+
const checked = checkSubmittedSvg(svg2);
|
|
871
|
+
if (!checked.ok) context.addIssue({ code: "custom", message: checked.error });
|
|
872
|
+
} catch {
|
|
873
|
+
context.addIssue({ code: "custom", message: "Invalid embedded SVG." });
|
|
874
|
+
}
|
|
875
|
+
}),
|
|
876
|
+
pixelated: z3.boolean().optional(),
|
|
877
|
+
/** Detail available before resizing; does not claim upsampling adds pixels. */
|
|
878
|
+
sourcePixels: z3.object({
|
|
879
|
+
width: z3.number().int().positive().max(24e3),
|
|
880
|
+
height: z3.number().int().positive().max(24e3)
|
|
881
|
+
}).strict().optional(),
|
|
882
|
+
credit: credit.optional()
|
|
883
|
+
})
|
|
884
|
+
]);
|
|
885
|
+
var image = z3.object({
|
|
886
|
+
...box,
|
|
887
|
+
kind: z3.literal("image"),
|
|
888
|
+
asset: assetId,
|
|
889
|
+
/** cover crops to fill the box (artwork); contain keeps the whole image (stickers). */
|
|
890
|
+
fit: z3.enum(["cover", "contain"]).optional(),
|
|
891
|
+
/** An intentional full-canvas backdrop may contain the image without cropping. */
|
|
892
|
+
background: z3.boolean().optional(),
|
|
893
|
+
opacity: z3.number().min(0).max(1),
|
|
894
|
+
radius: z3.number().min(0).max(160)
|
|
895
|
+
});
|
|
896
|
+
var cardMark = z3.object({
|
|
897
|
+
...box,
|
|
898
|
+
kind: z3.literal("card-mark"),
|
|
899
|
+
mark: z3.enum(["chip", "contactless", "network"]),
|
|
900
|
+
slot: z3.enum(["middle-left", "upper-left", "upper-right", "middle-right", "lower-right"]),
|
|
901
|
+
color: color2.optional(),
|
|
902
|
+
network: z3.enum(["mastercard", "visa", "amex", "discover"]).optional(),
|
|
903
|
+
colorMode: z3.enum(["brand", "white", "black"]).optional(),
|
|
904
|
+
visaVariant: z3.enum(["boxed", "plain"]).optional()
|
|
905
|
+
});
|
|
906
|
+
var svg = z3.object({
|
|
907
|
+
...box,
|
|
908
|
+
kind: z3.literal("svg"),
|
|
909
|
+
nodes: z3.array(svgNodeSchema).min(1).max(1e3),
|
|
910
|
+
sourceBox: z3.object({
|
|
911
|
+
x: z3.number(),
|
|
912
|
+
y: z3.number(),
|
|
913
|
+
w: z3.number().positive(),
|
|
914
|
+
h: z3.number().positive()
|
|
915
|
+
}),
|
|
916
|
+
colors: z3.record(z3.string(), color2).optional()
|
|
917
|
+
});
|
|
918
|
+
var badgeLayerSchema = z3.discriminatedUnion("kind", [
|
|
919
|
+
svg,
|
|
920
|
+
cardMark,
|
|
921
|
+
text2,
|
|
922
|
+
shape,
|
|
923
|
+
portrait,
|
|
924
|
+
qr,
|
|
925
|
+
effect,
|
|
926
|
+
image,
|
|
927
|
+
graphic,
|
|
928
|
+
gradient
|
|
929
|
+
]);
|
|
930
|
+
var face = z3.object({ background: color2, layers: z3.array(badgeLayerSchema).max(96) });
|
|
931
|
+
var badgeDesignObjectSchema = z3.object({
|
|
932
|
+
/** Omitted means badge. */
|
|
933
|
+
product: z3.enum(productIds).optional(),
|
|
934
|
+
sticker: stickerMaterialSchema.optional(),
|
|
935
|
+
version: z3.literal(1),
|
|
936
|
+
source: z3.string().max(60).optional(),
|
|
937
|
+
name: z3.string().min(1).max(60),
|
|
938
|
+
description: z3.string().max(180),
|
|
939
|
+
artwork: z3.object({ assetId: z3.string().uuid() }).optional(),
|
|
940
|
+
assets: z3.record(assetId, designAssetSchema).optional(),
|
|
941
|
+
svgSource: svgSourceSchema.optional(),
|
|
942
|
+
event: z3.string().min(1).max(80),
|
|
943
|
+
artPrompt: z3.string().max(1200),
|
|
944
|
+
material: z3.object({
|
|
945
|
+
/** Physical badge holder; independent of the printed surface. Omitted means bare. */
|
|
946
|
+
holder: z3.enum(["bare", "laminated"]).optional(),
|
|
947
|
+
surface: z3.enum(["satin", "prism", "chrome"]),
|
|
948
|
+
/** Card-only physical stock; omitted keeps the coated `surface`. */
|
|
949
|
+
stock: z3.enum(["metal", "holographic", "soft-touch"]).optional(),
|
|
950
|
+
/** Card-only optics that tune the stock to one design. */
|
|
951
|
+
optics: z3.object({
|
|
952
|
+
/** Brushed-metal or laminate grain: straight at `angle`, rays or rings around `center`. */
|
|
953
|
+
grain: z3.enum(["linear", "radial", "concentric"]).optional(),
|
|
954
|
+
angle: z3.number().min(0).max(180).optional(),
|
|
955
|
+
center: z3.object({ x: z3.number().min(0).max(1), y: z3.number().min(0).max(1) }).optional(),
|
|
956
|
+
grainStrength: z3.number().min(0).max(1).optional(),
|
|
957
|
+
/** Foil color; omitted keeps each layer's own ink. */
|
|
958
|
+
foil: color2.optional(),
|
|
959
|
+
/** Color of the moving highlight. */
|
|
960
|
+
light: color2.optional(),
|
|
961
|
+
/** Three stops the holographic laminate cycles through instead of a full rainbow. */
|
|
962
|
+
spectrum: z3.array(color2).length(3).optional(),
|
|
963
|
+
diffraction: z3.enum(["linear", "radial"]).optional(),
|
|
964
|
+
sparkle: z3.number().min(0).max(1).optional(),
|
|
965
|
+
relief: z3.number().min(0).max(1).optional(),
|
|
966
|
+
/** Width of the moving highlight, from a sharp streak to a broad glow. */
|
|
967
|
+
sheen: z3.number().min(0).max(1).optional()
|
|
968
|
+
}).strict().optional(),
|
|
969
|
+
roughness: z3.number().min(0).max(1),
|
|
970
|
+
iridescence: z3.number().min(0).max(0.65),
|
|
971
|
+
speed: z3.number().min(0).max(1),
|
|
972
|
+
recipe: prismRecipeSchema.optional(),
|
|
973
|
+
effect: z3.enum(["standard", "ribbons", "topographic"]).optional(),
|
|
974
|
+
focus: z3.object({
|
|
975
|
+
x: z3.number().min(0).max(1),
|
|
976
|
+
y: z3.number().min(0).max(1),
|
|
977
|
+
radius: z3.number().min(0.1).max(0.5)
|
|
978
|
+
}).optional()
|
|
979
|
+
}),
|
|
980
|
+
front: face,
|
|
981
|
+
back: face
|
|
982
|
+
});
|
|
983
|
+
function isRoleBoundLayer(layer) {
|
|
984
|
+
return layer.kind === "text" && (["role", "roleOrganization", "admissionRole"].includes(layer.binding) || layer.binding === "template" && /\{(?:role|roleOrganization|admissionRole)\}/.test(layer.text));
|
|
985
|
+
}
|
|
986
|
+
function overlaps(a, b) {
|
|
987
|
+
const aa = designLayerBounds(a);
|
|
988
|
+
const bb = designLayerBounds(b);
|
|
989
|
+
return aa.x < bb.x + bb.w && aa.x + aa.w > bb.x && aa.y < bb.y + bb.h && aa.y + aa.h > bb.y;
|
|
990
|
+
}
|
|
991
|
+
function designLayerBounds(layer) {
|
|
992
|
+
const angle = (layer.rotation ?? 0) * Math.PI / 180;
|
|
993
|
+
const swap = Math.abs(layer.rotation ?? 0) === 90;
|
|
994
|
+
const width = swap ? layer.h : layer.w;
|
|
995
|
+
const height = swap ? layer.w : layer.h;
|
|
996
|
+
const w = Math.abs(Math.cos(angle)) * width + Math.abs(Math.sin(angle)) * height;
|
|
997
|
+
const h = Math.abs(Math.sin(angle)) * width + Math.abs(Math.cos(angle)) * height;
|
|
998
|
+
return { x: layer.x + (layer.w - w) / 2, y: layer.y + (layer.h - h) / 2, w, h };
|
|
999
|
+
}
|
|
1000
|
+
function luminance(hex2) {
|
|
1001
|
+
const rgb = [1, 3, 5].map((start) => Number.parseInt(hex2.slice(start, start + 2), 16) / 255);
|
|
1002
|
+
return rgb.map((value) => value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4).reduce((total, value, index) => total + value * [0.2126, 0.7152, 0.0722][index], 0);
|
|
1003
|
+
}
|
|
1004
|
+
function designIssues(design) {
|
|
1005
|
+
const issues = [];
|
|
1006
|
+
const profile = designProfile(design);
|
|
1007
|
+
const badge = profile.id === "badge";
|
|
1008
|
+
if (!badge && design.material.holder) issues.push("A holder is only available for badges.");
|
|
1009
|
+
if (profile.id !== "card" && (design.material.stock || design.material.optics))
|
|
1010
|
+
issues.push("Stock and optics are only available for cards.");
|
|
1011
|
+
for (const side of ["front", "back"])
|
|
1012
|
+
for (const layer of design[side].layers) {
|
|
1013
|
+
if (!layer.finish) continue;
|
|
1014
|
+
if (profile.id !== "card")
|
|
1015
|
+
issues.push(`${side}.${layer.id}: finish is only available for cards.`);
|
|
1016
|
+
else if (layer.finish === "raised" && side === "back")
|
|
1017
|
+
issues.push(`back.${layer.id}: raised finish is only available on the front.`);
|
|
1018
|
+
}
|
|
1019
|
+
const assets = design.assets ?? {};
|
|
1020
|
+
if (design.sticker?.effectMap) {
|
|
1021
|
+
const { asset, layer } = design.sticker.effectMap;
|
|
1022
|
+
if (!assets[asset]) issues.push(`sticker.effectMap: missing asset ${asset}`);
|
|
1023
|
+
if (!design.front.layers.some((value) => value.id === layer && value.kind === "image"))
|
|
1024
|
+
issues.push(`sticker.effectMap: ${layer} must name a front image layer`);
|
|
1025
|
+
}
|
|
1026
|
+
for (const id3 of Object.keys(design.sticker?.regions ?? {}))
|
|
1027
|
+
if (!design.front.layers.some((layer) => layer.id === id3))
|
|
1028
|
+
issues.push(`sticker.regions: missing front layer ${id3}`);
|
|
1029
|
+
if (profile.id === "sticker" && design.back.layers.length)
|
|
1030
|
+
issues.push("Stickers have one editable face; keep back layers empty.");
|
|
1031
|
+
if (profile.digital && design.back.layers.length)
|
|
1032
|
+
issues.push(`${profile.label} is a single image; keep back layers empty.`);
|
|
1033
|
+
if (Object.keys(assets).length > 24) issues.push("assets: 24 como m\xE1ximo");
|
|
1034
|
+
for (const side of ["front", "back"])
|
|
1035
|
+
for (const layer of design[side].layers)
|
|
1036
|
+
if (layer.kind === "image" && layer.asset !== ART_ASSET && !assets[layer.asset])
|
|
1037
|
+
issues.push(`${side}.${layer.id}: falta el asset ${layer.asset}`);
|
|
1038
|
+
for (const side of ["front", "back"]) {
|
|
1039
|
+
const layers = design[side].layers;
|
|
1040
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1041
|
+
for (const [i, layer] of layers.entries()) {
|
|
1042
|
+
if (ids.has(layer.id)) issues.push(`${side}: ID repetido ${layer.id}`);
|
|
1043
|
+
ids.add(layer.id);
|
|
1044
|
+
const bounds = designLayerBounds(layer);
|
|
1045
|
+
if (bounds.x < -0.01 || bounds.y < -0.01 || bounds.x + bounds.w > profile.width + 0.01 || bounds.y + bounds.h > profile.height + 0.01)
|
|
1046
|
+
issues.push(`${side}.${layer.id}: outside the ${profile.label.toLowerCase()}`);
|
|
1047
|
+
if (profile.id === "sticker" && layer.kind === "text" && layer.binding !== "none")
|
|
1048
|
+
issues.push("Sticker text uses free text, without participant bindings.");
|
|
1049
|
+
if (profile.id === "sticker" && layer.kind === "portrait")
|
|
1050
|
+
issues.push("Stickers use image layers, not participant portraits.");
|
|
1051
|
+
if (!badge && layer.kind === "qr")
|
|
1052
|
+
issues.push(`${side}.${layer.id}: QR codes are for badges`);
|
|
1053
|
+
if (layer.kind === "svg" && !design.svgSource)
|
|
1054
|
+
issues.push(`${side}.${layer.id}: missing original SVG definitions`);
|
|
1055
|
+
if (side === "front" && layer.visible !== false && !isBackground(layer, profile)) {
|
|
1056
|
+
for (const area of profile.keepClear)
|
|
1057
|
+
if (intersects(bounds, area))
|
|
1058
|
+
issues.push(`${side}.${layer.id}: covers the ${area.label} area`);
|
|
1059
|
+
}
|
|
1060
|
+
if (badge && ["text", "portrait", "qr"].includes(layer.kind) && bounds.y < 89.99)
|
|
1061
|
+
issues.push(`${side}.${layer.id}: reserva superior de 90 px`);
|
|
1062
|
+
if ((layer.kind === "portrait" || layer.kind === "image") && layer.channel === "ink")
|
|
1063
|
+
issues.push(`${side}.${layer.id}: las im\xE1genes pertenecen a la impresi\xF3n`);
|
|
1064
|
+
if (layer.kind === "graphic" && layer.pattern === "path") {
|
|
1065
|
+
const path = layer.path?.trim() ?? "";
|
|
1066
|
+
const numbers = path.match(/[-+]?(?:\d*\.?\d+)(?:[eE][-+]?\d+)?/g) ?? [];
|
|
1067
|
+
if (!/^[Mm]/.test(path) || numbers.some(
|
|
1068
|
+
(value) => !Number.isFinite(Number(value)) || Math.abs(Number(value)) > 16384
|
|
1069
|
+
))
|
|
1070
|
+
issues.push(`${side}.${layer.id}: trazado inv\xE1lido o fuera de rango`);
|
|
1071
|
+
}
|
|
1072
|
+
if (layer.kind === "qr") {
|
|
1073
|
+
const minimum = side === "front" ? 128 : 280;
|
|
1074
|
+
if (layer.w < minimum || layer.w !== layer.h || layer.rotation || (layer.opacity ?? 1) !== 1)
|
|
1075
|
+
issues.push(`${side}.${layer.id}: QR cuadrado de al menos ${minimum} px`);
|
|
1076
|
+
const foreground = layer.foreground ?? "#111111";
|
|
1077
|
+
const background = layer.background ?? "#ffffff";
|
|
1078
|
+
const light = Math.max(luminance(foreground), luminance(background));
|
|
1079
|
+
const dark = Math.min(luminance(foreground), luminance(background));
|
|
1080
|
+
if ((light + 0.05) / (dark + 0.05) < 4.5 || [foreground, background].some(
|
|
1081
|
+
(value) => value.length > 7 && value.slice(7).toLowerCase() !== "ff"
|
|
1082
|
+
))
|
|
1083
|
+
issues.push(`${side}.${layer.id}: el QR necesita colores opacos y contrastantes`);
|
|
1084
|
+
if (layer.visible !== false && layers.slice(i + 1).some((l) => l.visible !== false && overlaps(layer, l)))
|
|
1085
|
+
issues.push(`${side}.${layer.id}: QR tapado por otra capa`);
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
if (badge && layers.length < 3) issues.push(`${side}: al menos 3 capas`);
|
|
1089
|
+
if (badge && !layers.some((l) => l.kind === "text" && l.binding === "name"))
|
|
1090
|
+
issues.push(`${side}: falta el nombre vinculado`);
|
|
1091
|
+
}
|
|
1092
|
+
const portraits = design.front.layers.filter((l) => l.kind === "portrait").length;
|
|
1093
|
+
if (badge && (portraits < 1 || portraits > 4)) issues.push("front: debe tener un retrato");
|
|
1094
|
+
if (!badge && portraits > 4) issues.push("front: 4 portraits at most");
|
|
1095
|
+
for (const side of ["front", "back"])
|
|
1096
|
+
if (design[side].layers.filter((layer) => layer.kind === "effect").length > 24)
|
|
1097
|
+
issues.push(`${side}: m\xE1ximo 24 efectos`);
|
|
1098
|
+
if (badge && !design.back.layers.some((l) => l.kind === "qr")) issues.push("back: falta el QR");
|
|
1099
|
+
if (badge && !design.back.layers.some(isRoleBoundLayer))
|
|
1100
|
+
issues.push("back: falta el rol vinculado");
|
|
1101
|
+
return issues;
|
|
1102
|
+
}
|
|
1103
|
+
function intersects(a, b) {
|
|
1104
|
+
return a.x < b.x + b.w && b.x < a.x + a.w && a.y < b.y + b.h && b.y < a.y + a.h;
|
|
1105
|
+
}
|
|
1106
|
+
function isBackground(layer, profile) {
|
|
1107
|
+
if (layer.kind === "svg" && !layer.rotation && ["x", "y", "w", "h"].every((key) => layer[key] === layer.sourceBox[key]))
|
|
1108
|
+
return true;
|
|
1109
|
+
return (layer.kind === "image" || layer.kind === "gradient" || layer.kind === "effect" || layer.kind === "graphic" || layer.kind === "svg") && (layer.kind !== "image" || layer.fit !== "contain" || layer.background === true) && layer.x <= 0 && layer.y <= 0 && layer.x + layer.w >= profile.width && layer.y + layer.h >= profile.height;
|
|
1110
|
+
}
|
|
1111
|
+
var badgeDesignSchema = badgeDesignObjectSchema.transform((design) => {
|
|
1112
|
+
if (design.product !== "card") return design;
|
|
1113
|
+
return {
|
|
1114
|
+
...design,
|
|
1115
|
+
front: {
|
|
1116
|
+
...design.front,
|
|
1117
|
+
layers: design.front.layers.map(
|
|
1118
|
+
(layer) => layer.kind === "card-mark" ? { ...layer, ...cardMarkRegion(layer) } : layer
|
|
1119
|
+
)
|
|
1120
|
+
},
|
|
1121
|
+
back: {
|
|
1122
|
+
...design.back,
|
|
1123
|
+
layers: design.back.layers.map(
|
|
1124
|
+
(layer) => layer.kind === "card-mark" ? { ...layer, ...cardMarkRegion(layer) } : layer
|
|
1125
|
+
)
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
}).superRefine((design, context) => {
|
|
1129
|
+
for (const message of designIssues(design))
|
|
1130
|
+
context.addIssue({ code: z3.ZodIssueCode.custom, message });
|
|
1131
|
+
});
|
|
1132
|
+
var designLockSchema = z3.object({
|
|
1133
|
+
front: z3.array(z3.string()).max(96),
|
|
1134
|
+
back: z3.array(z3.string()).max(96),
|
|
1135
|
+
material: z3.boolean()
|
|
1136
|
+
});
|
|
1137
|
+
function preserveDesignLocks(current, next, locks) {
|
|
1138
|
+
const output = structuredClone(next);
|
|
1139
|
+
if (locks.material) {
|
|
1140
|
+
output.material = structuredClone(current.material);
|
|
1141
|
+
output.sticker = current.sticker ? structuredClone(current.sticker) : void 0;
|
|
1142
|
+
}
|
|
1143
|
+
for (const side of ["front", "back"]) {
|
|
1144
|
+
const locked = new Set(locks[side]);
|
|
1145
|
+
output[side].layers = output[side].layers.filter((l) => !locked.has(l.id));
|
|
1146
|
+
for (const [index, layer] of current[side].layers.entries()) {
|
|
1147
|
+
if (locked.has(layer.id))
|
|
1148
|
+
output[side].layers.splice(
|
|
1149
|
+
Math.min(index, output[side].layers.length),
|
|
1150
|
+
0,
|
|
1151
|
+
structuredClone(layer)
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
return badgeDesignSchema.parse(output);
|
|
1156
|
+
}
|
|
1157
|
+
function referencedDesignAssets(design) {
|
|
1158
|
+
return [
|
|
1159
|
+
.../* @__PURE__ */ new Set([
|
|
1160
|
+
...["front", "back"].flatMap(
|
|
1161
|
+
(side) => design[side].layers.flatMap((layer) => layer.kind === "image" ? [layer.asset] : [])
|
|
1162
|
+
),
|
|
1163
|
+
...design.sticker?.effectMap ? [design.sticker.effectMap.asset] : []
|
|
1164
|
+
])
|
|
1165
|
+
];
|
|
1166
|
+
}
|
|
1167
|
+
function pruneAssets(design) {
|
|
1168
|
+
if (design.sticker) {
|
|
1169
|
+
const ids = new Set(design.front.layers.map((layer) => layer.id));
|
|
1170
|
+
design = {
|
|
1171
|
+
...design,
|
|
1172
|
+
sticker: {
|
|
1173
|
+
...design.sticker,
|
|
1174
|
+
effectMap: design.sticker.effectMap && ids.has(design.sticker.effectMap.layer) ? design.sticker.effectMap : void 0,
|
|
1175
|
+
regions: design.sticker.regions ? Object.fromEntries(Object.entries(design.sticker.regions).filter(([id3]) => ids.has(id3))) : void 0
|
|
1176
|
+
}
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
if (!design.assets) return design;
|
|
1180
|
+
const used = new Set(referencedDesignAssets(design));
|
|
1181
|
+
const assets = Object.fromEntries(Object.entries(design.assets).filter(([id3]) => used.has(id3)));
|
|
1182
|
+
return { ...design, assets };
|
|
1183
|
+
}
|
|
1184
|
+
var STICKER_SIZE = 280;
|
|
1185
|
+
var STICKER_SLOTS = [
|
|
1186
|
+
[0.74, 0.3],
|
|
1187
|
+
[0.26, 0.66],
|
|
1188
|
+
[0.74, 0.66],
|
|
1189
|
+
[0.26, 0.3]
|
|
1190
|
+
];
|
|
1191
|
+
function stickerPosition(layers, w, h, canvas, front) {
|
|
1192
|
+
const count = layers.filter((layer) => layer.kind === "image" && layer.fit === "contain").length;
|
|
1193
|
+
const place = ([cx, cy]) => ({
|
|
1194
|
+
x: Math.round(Math.min(canvas.width - 1 - w, Math.max(0, canvas.width * cx - w / 2))),
|
|
1195
|
+
y: Math.round(Math.min(canvas.height - 1 - h, Math.max(0, canvas.height * cy - h / 2)))
|
|
1196
|
+
});
|
|
1197
|
+
const clear = (position) => !front || canvas.keepClear.every(
|
|
1198
|
+
(area) => !(position.x < area.x + area.w && area.x < position.x + w && position.y < area.y + area.h && area.y < position.y + h)
|
|
1199
|
+
);
|
|
1200
|
+
const slots = STICKER_SLOTS.map(place).filter(clear);
|
|
1201
|
+
const usable = slots.length ? slots : STICKER_SLOTS.map(place);
|
|
1202
|
+
const slot = usable[count % usable.length];
|
|
1203
|
+
const nudge = Math.floor(count / usable.length) * 36;
|
|
1204
|
+
return {
|
|
1205
|
+
x: Math.min(canvas.width - 1 - w, slot.x + nudge),
|
|
1206
|
+
y: Math.min(canvas.height - 1 - h, slot.y + nudge)
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
function addSticker(design, side, asset, size, id3) {
|
|
1210
|
+
const canvas = designProfile(design);
|
|
1211
|
+
const longest = Math.min(STICKER_SIZE, Math.round(Math.min(canvas.width, canvas.height) / 3));
|
|
1212
|
+
const ratio = longest / Math.max(size.width, size.height, 1);
|
|
1213
|
+
const w = Math.max(1, Math.round(size.width * ratio));
|
|
1214
|
+
const h = Math.max(1, Math.round(size.height * ratio));
|
|
1215
|
+
const assetId2 = `sticker-${id3}`;
|
|
1216
|
+
const layer = {
|
|
1217
|
+
id: assetId2,
|
|
1218
|
+
kind: "image",
|
|
1219
|
+
asset: assetId2,
|
|
1220
|
+
fit: "contain",
|
|
1221
|
+
...stickerPosition(design[side].layers, w, h, canvas, side === "front"),
|
|
1222
|
+
w,
|
|
1223
|
+
h,
|
|
1224
|
+
opacity: 1,
|
|
1225
|
+
radius: 0
|
|
1226
|
+
};
|
|
1227
|
+
const layers = [...design[side].layers];
|
|
1228
|
+
const qr2 = layers.findIndex((item) => item.kind === "qr");
|
|
1229
|
+
layers.splice(qr2 < 0 ? layers.length : qr2, 0, layer);
|
|
1230
|
+
return badgeDesignSchema.parse({
|
|
1231
|
+
...design,
|
|
1232
|
+
assets: { ...design.assets, [assetId2]: asset },
|
|
1233
|
+
[side]: { ...design[side], layers }
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
function cardMarkLayer(id3, spec) {
|
|
1237
|
+
const { x, y, w, h } = cardMarkRegion(spec);
|
|
1238
|
+
return { id: id3, kind: "card-mark", ...spec, x, y, w, h };
|
|
1239
|
+
}
|
|
1240
|
+
function createCardDesign(gallery) {
|
|
1241
|
+
const { width, height } = designProfiles.card;
|
|
1242
|
+
return badgeDesignSchema.parse({
|
|
1243
|
+
product: "card",
|
|
1244
|
+
version: 1,
|
|
1245
|
+
name: gallery.title,
|
|
1246
|
+
description: "",
|
|
1247
|
+
event: gallery.title,
|
|
1248
|
+
artPrompt: "",
|
|
1249
|
+
material: { surface: "satin", roughness: 0.4, iridescence: 0, speed: 0 },
|
|
1250
|
+
assets: {
|
|
1251
|
+
artwork: {
|
|
1252
|
+
source: "gallery",
|
|
1253
|
+
slug: gallery.slug,
|
|
1254
|
+
name: gallery.title,
|
|
1255
|
+
...gallery.file ? { file: gallery.file } : {}
|
|
1256
|
+
}
|
|
1257
|
+
},
|
|
1258
|
+
front: {
|
|
1259
|
+
background: "#111111",
|
|
1260
|
+
layers: [
|
|
1261
|
+
{
|
|
1262
|
+
id: "artwork",
|
|
1263
|
+
kind: "image",
|
|
1264
|
+
asset: "artwork",
|
|
1265
|
+
fit: "cover",
|
|
1266
|
+
x: 0,
|
|
1267
|
+
y: 0,
|
|
1268
|
+
w: width,
|
|
1269
|
+
h: height,
|
|
1270
|
+
opacity: 1,
|
|
1271
|
+
radius: 0
|
|
1272
|
+
},
|
|
1273
|
+
cardMarkLayer("chip", { mark: "chip", slot: "middle-left", color: "#d9b875" }),
|
|
1274
|
+
cardMarkLayer("contactless", {
|
|
1275
|
+
mark: "contactless",
|
|
1276
|
+
slot: "upper-right",
|
|
1277
|
+
color: "#ffffff"
|
|
1278
|
+
}),
|
|
1279
|
+
cardMarkLayer("network", {
|
|
1280
|
+
mark: "network",
|
|
1281
|
+
slot: "lower-right",
|
|
1282
|
+
network: "mastercard",
|
|
1283
|
+
colorMode: "brand"
|
|
1284
|
+
})
|
|
1285
|
+
]
|
|
1286
|
+
},
|
|
1287
|
+
back: { background: "#141414", layers: [] }
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
// ../design/dist/chunk-O2KBFMBV.js
|
|
1292
|
+
import { z as z4 } from "zod";
|
|
1293
|
+
var COMMUNITY_IMAGE_LIMIT = 3e6;
|
|
1294
|
+
var COMMUNITY_JSON_LIMIT = 256e3;
|
|
1295
|
+
var digestSchema = z4.string().regex(/^[a-f0-9]{64}$/);
|
|
1296
|
+
var secretSchema = z4.string().regex(/^\d{13}\.[a-f0-9]{64}$/);
|
|
1297
|
+
var COMMUNITY_PREPARATION_TTL = 60 * 60 * 1e3;
|
|
1298
|
+
var communityParticipantSchema = z4.object({
|
|
1299
|
+
name: z4.string().trim().min(1).max(80),
|
|
1300
|
+
role: z4.string().max(100),
|
|
1301
|
+
organization: z4.string().max(100),
|
|
1302
|
+
number: z4.number().int().min(1).max(999999),
|
|
1303
|
+
eventName: z4.string().min(1).max(80),
|
|
1304
|
+
publicUrl: z4.string().url().max(512).refine((value) => ["https:", "http:"].includes(new URL(value).protocol)),
|
|
1305
|
+
signature: z4.object({ seed: z4.number().int().min(0).max(4294967295), version: z4.literal(1) }),
|
|
1306
|
+
metadata: z4.object({
|
|
1307
|
+
roleLabel: z4.string().max(100).default(""),
|
|
1308
|
+
eventName: z4.string().max(80).default(""),
|
|
1309
|
+
eventDate: z4.string().max(100).default(""),
|
|
1310
|
+
location: z4.string().max(100).default(""),
|
|
1311
|
+
website: z4.string().max(200).default(""),
|
|
1312
|
+
bio: z4.string().max(600).default("")
|
|
1313
|
+
}).strict()
|
|
1314
|
+
}).strict();
|
|
1315
|
+
var communitySnapshotSchema = z4.object({
|
|
1316
|
+
format: z4.literal(1),
|
|
1317
|
+
design: badgeDesignSchema,
|
|
1318
|
+
participant: communityParticipantSchema,
|
|
1319
|
+
images: z4.object({ portrait: digestSchema, artwork: digestSchema.nullable() }).strict()
|
|
1320
|
+
}).strict().superRefine(({ design, images, participant }, context) => {
|
|
1321
|
+
const visible = (layer) => layer.visible !== false && (layer.opacity ?? 1) > 0;
|
|
1322
|
+
if (Object.values(design.assets ?? {}).some((asset) => asset.source === "image"))
|
|
1323
|
+
context.addIssue({
|
|
1324
|
+
code: "custom",
|
|
1325
|
+
message: "Uploaded stickers can't be published yet. Keep Petdex stickers or remove your uploads."
|
|
1326
|
+
});
|
|
1327
|
+
for (const side of ["front", "back"]) {
|
|
1328
|
+
if (!design[side].layers.some(
|
|
1329
|
+
(layer) => visible(layer) && layer.kind === "text" && layer.binding === "name"
|
|
1330
|
+
))
|
|
1331
|
+
context.addIssue({ code: "custom", message: `El nombre debe verse en ${side}.` });
|
|
1332
|
+
}
|
|
1333
|
+
if (!design.front.layers.some((layer) => visible(layer) && layer.kind === "portrait"))
|
|
1334
|
+
context.addIssue({ code: "custom", message: "El retrato debe ser visible." });
|
|
1335
|
+
if (!design.back.layers.some((layer) => visible(layer) && isRoleBoundLayer(layer)))
|
|
1336
|
+
context.addIssue({ code: "custom", message: "El rol debe ser visible." });
|
|
1337
|
+
if (!design.back.layers.some((layer) => visible(layer) && layer.kind === "qr"))
|
|
1338
|
+
context.addIssue({ code: "custom", message: "El QR debe ser visible." });
|
|
1339
|
+
for (const layer of [...design.front.layers, ...design.back.layers]) {
|
|
1340
|
+
if (!visible(layer) || layer.kind !== "qr") continue;
|
|
1341
|
+
try {
|
|
1342
|
+
badgeQrLayout(participant.publicUrl, layer.w, layer.maxCellSize);
|
|
1343
|
+
} catch (reason) {
|
|
1344
|
+
context.addIssue({ code: "custom", message: reason.message });
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
if (Boolean(design.artwork) !== Boolean(images.artwork) || [...design.front.layers, ...design.back.layers].some(
|
|
1348
|
+
(layer) => visible(layer) && layer.kind === "image"
|
|
1349
|
+
) && !images.artwork)
|
|
1350
|
+
context.addIssue({ code: "custom", message: "Falta la ilustraci\xF3n de este dise\xF1o." });
|
|
1351
|
+
});
|
|
1352
|
+
var intentBase = {
|
|
1353
|
+
operationId: z4.string().uuid(),
|
|
1354
|
+
snapshotHash: digestSchema,
|
|
1355
|
+
title: z4.string().min(1).max(60),
|
|
1356
|
+
participantName: z4.string().min(1).max(80)
|
|
1357
|
+
};
|
|
1358
|
+
var communityIntentSchema = z4.discriminatedUnion("action", [
|
|
1359
|
+
z4.object({ ...intentBase, action: z4.literal("create") }).strict(),
|
|
1360
|
+
z4.object({
|
|
1361
|
+
...intentBase,
|
|
1362
|
+
action: z4.literal("update"),
|
|
1363
|
+
publicationId: z4.string().uuid(),
|
|
1364
|
+
expectedVersion: z4.number().int().positive()
|
|
1365
|
+
}).strict(),
|
|
1366
|
+
z4.object({
|
|
1367
|
+
...intentBase,
|
|
1368
|
+
action: z4.literal("withdraw"),
|
|
1369
|
+
publicationId: z4.string().uuid(),
|
|
1370
|
+
expectedVersion: z4.number().int().positive()
|
|
1371
|
+
}).strict()
|
|
1372
|
+
]);
|
|
1373
|
+
function canonicalJson(value) {
|
|
1374
|
+
return JSON.stringify(
|
|
1375
|
+
value,
|
|
1376
|
+
(_, item) => item && typeof item === "object" && !Array.isArray(item) ? Object.fromEntries(Object.entries(item).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) : item
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
async function communityDigest(value) {
|
|
1380
|
+
const bytes = typeof value === "string" ? new TextEncoder().encode(value) : await value.arrayBuffer();
|
|
1381
|
+
return Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes))).map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1382
|
+
}
|
|
1383
|
+
var bundleImageSchema = z4.object({
|
|
1384
|
+
mimeType: z4.enum(["image/png", "image/jpeg", "image/webp"]),
|
|
1385
|
+
base64: z4.string().min(4).max(4e6).regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/)
|
|
1386
|
+
}).strict();
|
|
1387
|
+
var badgeBundleSchema = z4.object({
|
|
1388
|
+
format: z4.literal("makeables-bundle"),
|
|
1389
|
+
version: z4.literal(1),
|
|
1390
|
+
snapshot: communitySnapshotSchema,
|
|
1391
|
+
images: z4.object({
|
|
1392
|
+
portrait: bundleImageSchema,
|
|
1393
|
+
artwork: bundleImageSchema.nullable()
|
|
1394
|
+
}).strict()
|
|
1395
|
+
}).strict();
|
|
1396
|
+
function bundleImageBytes(image2) {
|
|
1397
|
+
return Uint8Array.from(atob(image2.base64), (character) => character.charCodeAt(0));
|
|
1398
|
+
}
|
|
1399
|
+
async function validateBadgeBundle(input) {
|
|
1400
|
+
const bundle = badgeBundleSchema.parse(input);
|
|
1401
|
+
const serialized = canonicalJson(bundle.snapshot);
|
|
1402
|
+
if (new TextEncoder().encode(serialized).length > COMMUNITY_JSON_LIMIT)
|
|
1403
|
+
throw new Error("The badge exceeds the 256 KB publication limit.");
|
|
1404
|
+
for (const slot of ["portrait", "artwork"]) {
|
|
1405
|
+
const image2 = bundle.images[slot];
|
|
1406
|
+
if (!image2 && !bundle.snapshot.images[slot]) continue;
|
|
1407
|
+
if (!image2) throw new Error(`Missing ${slot} image.`);
|
|
1408
|
+
const bytes = bundleImageBytes(image2);
|
|
1409
|
+
if (!bytes.length || bytes.length > COMMUNITY_IMAGE_LIMIT)
|
|
1410
|
+
throw new Error(`The ${slot} exceeds the 3 MB publication limit.`);
|
|
1411
|
+
const digest = await communityDigest(new Blob([bytes]));
|
|
1412
|
+
if (digest !== bundle.snapshot.images[slot])
|
|
1413
|
+
throw new Error(`The ${slot} does not match the saved badge.`);
|
|
1414
|
+
}
|
|
1415
|
+
return { bundle, snapshotHash: await communityDigest(serialized) };
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
// ../design/dist/chunk-7TRETK3A.js
|
|
1419
|
+
import { z as z5 } from "zod";
|
|
1420
|
+
var printerPresets = {
|
|
1421
|
+
generic: {
|
|
1422
|
+
name: "Generic kiss-cut printer",
|
|
1423
|
+
cutSpot: "CutContour",
|
|
1424
|
+
whiteSpot: "White",
|
|
1425
|
+
bleedMm: 1,
|
|
1426
|
+
safeMm: 1.5,
|
|
1427
|
+
gapMm: 3,
|
|
1428
|
+
marginMm: 5
|
|
1429
|
+
}
|
|
1430
|
+
};
|
|
1431
|
+
var sheetSizes = {
|
|
1432
|
+
a5: { name: "A5", widthMm: 148, heightMm: 210 },
|
|
1433
|
+
a6: { name: "A6", widthMm: 105, heightMm: 148 },
|
|
1434
|
+
"10x15": { name: "10 \xD7 15 cm", widthMm: 100, heightMm: 150 }
|
|
1435
|
+
};
|
|
1436
|
+
var sheetTypes = {
|
|
1437
|
+
classic: {
|
|
1438
|
+
name: "Classic sheet",
|
|
1439
|
+
cut: "kiss-cut",
|
|
1440
|
+
sizes: ["a5"],
|
|
1441
|
+
stock: "white",
|
|
1442
|
+
laminate: "matte",
|
|
1443
|
+
borderMm: 2,
|
|
1444
|
+
white: false,
|
|
1445
|
+
stickerWidthMm: 45
|
|
1446
|
+
},
|
|
1447
|
+
small: {
|
|
1448
|
+
name: "Small sheet",
|
|
1449
|
+
cut: "kiss-cut",
|
|
1450
|
+
sizes: ["a6", "10x15"],
|
|
1451
|
+
stock: "white",
|
|
1452
|
+
laminate: "gloss",
|
|
1453
|
+
borderMm: 2,
|
|
1454
|
+
white: false,
|
|
1455
|
+
stickerWidthMm: 35
|
|
1456
|
+
},
|
|
1457
|
+
single: {
|
|
1458
|
+
name: "Single sticker",
|
|
1459
|
+
cut: "die-cut",
|
|
1460
|
+
sizes: [],
|
|
1461
|
+
stock: "white",
|
|
1462
|
+
laminate: "gloss",
|
|
1463
|
+
borderMm: 2,
|
|
1464
|
+
white: false,
|
|
1465
|
+
stickerWidthMm: 75
|
|
1466
|
+
},
|
|
1467
|
+
clear: {
|
|
1468
|
+
name: "Clear",
|
|
1469
|
+
cut: "kiss-cut",
|
|
1470
|
+
sizes: ["a6"],
|
|
1471
|
+
stock: "clear",
|
|
1472
|
+
laminate: "gloss",
|
|
1473
|
+
borderMm: 0,
|
|
1474
|
+
white: true,
|
|
1475
|
+
stickerWidthMm: 35
|
|
1476
|
+
},
|
|
1477
|
+
holographic: {
|
|
1478
|
+
name: "Holographic",
|
|
1479
|
+
cut: "kiss-cut",
|
|
1480
|
+
sizes: ["a6"],
|
|
1481
|
+
stock: "holographic",
|
|
1482
|
+
laminate: "gloss",
|
|
1483
|
+
borderMm: 2,
|
|
1484
|
+
white: true,
|
|
1485
|
+
stickerWidthMm: 35
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
var sheetTypeIds = Object.keys(sheetTypes);
|
|
1489
|
+
var id = z5.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/);
|
|
1490
|
+
var sheetItemSchema = z5.object({
|
|
1491
|
+
id,
|
|
1492
|
+
design: badgeDesignSchema,
|
|
1493
|
+
/** Centre of the sticker canvas on the sheet. */
|
|
1494
|
+
x: z5.number().min(-1e3).max(1e3),
|
|
1495
|
+
y: z5.number().min(-1e3).max(1e3),
|
|
1496
|
+
rotation: z5.number().min(-360).max(360),
|
|
1497
|
+
/** Printed width of the square sticker canvas. */
|
|
1498
|
+
widthMm: z5.number().min(5).max(300)
|
|
1499
|
+
});
|
|
1500
|
+
var stickerSheetSchema = z5.object({
|
|
1501
|
+
format: z5.literal("makeables-sheet"),
|
|
1502
|
+
version: z5.literal(1),
|
|
1503
|
+
name: z5.string().min(1).max(80),
|
|
1504
|
+
type: z5.enum(sheetTypeIds),
|
|
1505
|
+
printer: z5.enum(Object.keys(printerPresets)),
|
|
1506
|
+
size: z5.enum(Object.keys(sheetSizes)).optional(),
|
|
1507
|
+
/** Border override for every sticker; the type's border otherwise. */
|
|
1508
|
+
borderMm: z5.number().min(0).max(10).optional(),
|
|
1509
|
+
/** Auto-pack keeps this sticker where it is. */
|
|
1510
|
+
hero: id.optional(),
|
|
1511
|
+
items: z5.array(sheetItemSchema).max(200)
|
|
1512
|
+
}).superRefine((sheet, context) => {
|
|
1513
|
+
const type = sheetTypes[sheet.type];
|
|
1514
|
+
if (type.cut === "kiss-cut" && !sheet.size)
|
|
1515
|
+
context.addIssue({ code: "custom", path: ["size"], message: "Kiss-cut sheets need a size." });
|
|
1516
|
+
if (sheet.size && !type.sizes.includes(sheet.size))
|
|
1517
|
+
context.addIssue({
|
|
1518
|
+
code: "custom",
|
|
1519
|
+
path: ["size"],
|
|
1520
|
+
message: `${type.name} comes in ${type.sizes.join(", ") || "the sticker's own size"}.`
|
|
1521
|
+
});
|
|
1522
|
+
if (type.cut === "die-cut" && sheet.items.length > 1)
|
|
1523
|
+
context.addIssue({
|
|
1524
|
+
code: "custom",
|
|
1525
|
+
path: ["items"],
|
|
1526
|
+
message: "A single sticker file holds one sticker."
|
|
1527
|
+
});
|
|
1528
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1529
|
+
for (const [index, item] of sheet.items.entries()) {
|
|
1530
|
+
if (ids.has(item.id))
|
|
1531
|
+
context.addIssue({
|
|
1532
|
+
code: "custom",
|
|
1533
|
+
path: ["items", index, "id"],
|
|
1534
|
+
message: "Duplicate id."
|
|
1535
|
+
});
|
|
1536
|
+
ids.add(item.id);
|
|
1537
|
+
if (item.design.product !== "sticker")
|
|
1538
|
+
context.addIssue({
|
|
1539
|
+
code: "custom",
|
|
1540
|
+
path: ["items", index, "design"],
|
|
1541
|
+
message: "Sheet items are sticker designs."
|
|
1542
|
+
});
|
|
1543
|
+
}
|
|
1544
|
+
if (sheet.hero && !ids.has(sheet.hero))
|
|
1545
|
+
context.addIssue({ code: "custom", path: ["hero"], message: "Hero is not on the sheet." });
|
|
1546
|
+
});
|
|
1547
|
+
function sheetSpec(sheet) {
|
|
1548
|
+
const type = sheetTypes[sheet.type];
|
|
1549
|
+
const size = sheet.size ? sheetSizes[sheet.size] : void 0;
|
|
1550
|
+
return {
|
|
1551
|
+
...printerPresets[sheet.printer],
|
|
1552
|
+
type,
|
|
1553
|
+
borderMm: sheet.borderMm ?? type.borderMm,
|
|
1554
|
+
widthMm: size?.widthMm,
|
|
1555
|
+
heightMm: size?.heightMm
|
|
1556
|
+
};
|
|
1557
|
+
}
|
|
1558
|
+
function createStickerSheet(type, name = sheetTypes[type].name) {
|
|
1559
|
+
const sizes = sheetTypes[type].sizes;
|
|
1560
|
+
return {
|
|
1561
|
+
format: "makeables-sheet",
|
|
1562
|
+
version: 1,
|
|
1563
|
+
name,
|
|
1564
|
+
type,
|
|
1565
|
+
printer: "generic",
|
|
1566
|
+
...sizes[0] ? { size: sizes[0] } : {},
|
|
1567
|
+
items: []
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
function sheetBorderPixels(borderMm, widthMm, pixels) {
|
|
1571
|
+
return borderMm * pixels / widthMm;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
// ../../node_modules/.pnpm/fflate@0.8.2/node_modules/fflate/esm/index.mjs
|
|
1575
|
+
import { createRequire } from "module";
|
|
1576
|
+
var require2 = createRequire("/");
|
|
1577
|
+
var Worker;
|
|
1578
|
+
try {
|
|
1579
|
+
Worker = require2("worker_threads").Worker;
|
|
1580
|
+
} catch (e) {
|
|
1581
|
+
}
|
|
1582
|
+
var u8 = Uint8Array;
|
|
1583
|
+
var u16 = Uint16Array;
|
|
1584
|
+
var i32 = Int32Array;
|
|
1585
|
+
var fleb = new u8([
|
|
1586
|
+
0,
|
|
1587
|
+
0,
|
|
1588
|
+
0,
|
|
1589
|
+
0,
|
|
1590
|
+
0,
|
|
1591
|
+
0,
|
|
1592
|
+
0,
|
|
1593
|
+
0,
|
|
1594
|
+
1,
|
|
1595
|
+
1,
|
|
1596
|
+
1,
|
|
1597
|
+
1,
|
|
1598
|
+
2,
|
|
1599
|
+
2,
|
|
1600
|
+
2,
|
|
1601
|
+
2,
|
|
1602
|
+
3,
|
|
1603
|
+
3,
|
|
1604
|
+
3,
|
|
1605
|
+
3,
|
|
1606
|
+
4,
|
|
1607
|
+
4,
|
|
1608
|
+
4,
|
|
1609
|
+
4,
|
|
1610
|
+
5,
|
|
1611
|
+
5,
|
|
1612
|
+
5,
|
|
1613
|
+
5,
|
|
1614
|
+
0,
|
|
1615
|
+
/* unused */
|
|
1616
|
+
0,
|
|
1617
|
+
0,
|
|
1618
|
+
/* impossible */
|
|
1619
|
+
0
|
|
1620
|
+
]);
|
|
1621
|
+
var fdeb = new u8([
|
|
1622
|
+
0,
|
|
1623
|
+
0,
|
|
1624
|
+
0,
|
|
1625
|
+
0,
|
|
1626
|
+
1,
|
|
1627
|
+
1,
|
|
1628
|
+
2,
|
|
1629
|
+
2,
|
|
1630
|
+
3,
|
|
1631
|
+
3,
|
|
1632
|
+
4,
|
|
1633
|
+
4,
|
|
1634
|
+
5,
|
|
1635
|
+
5,
|
|
1636
|
+
6,
|
|
1637
|
+
6,
|
|
1638
|
+
7,
|
|
1639
|
+
7,
|
|
1640
|
+
8,
|
|
1641
|
+
8,
|
|
1642
|
+
9,
|
|
1643
|
+
9,
|
|
1644
|
+
10,
|
|
1645
|
+
10,
|
|
1646
|
+
11,
|
|
1647
|
+
11,
|
|
1648
|
+
12,
|
|
1649
|
+
12,
|
|
1650
|
+
13,
|
|
1651
|
+
13,
|
|
1652
|
+
/* unused */
|
|
1653
|
+
0,
|
|
1654
|
+
0
|
|
1655
|
+
]);
|
|
1656
|
+
var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
|
|
1657
|
+
var freb = function(eb, start) {
|
|
1658
|
+
var b = new u16(31);
|
|
1659
|
+
for (var i = 0; i < 31; ++i) {
|
|
1660
|
+
b[i] = start += 1 << eb[i - 1];
|
|
1661
|
+
}
|
|
1662
|
+
var r = new i32(b[30]);
|
|
1663
|
+
for (var i = 1; i < 30; ++i) {
|
|
1664
|
+
for (var j = b[i]; j < b[i + 1]; ++j) {
|
|
1665
|
+
r[j] = j - b[i] << 5 | i;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
return { b, r };
|
|
1669
|
+
};
|
|
1670
|
+
var _a = freb(fleb, 2);
|
|
1671
|
+
var fl = _a.b;
|
|
1672
|
+
var revfl = _a.r;
|
|
1673
|
+
fl[28] = 258, revfl[258] = 28;
|
|
1674
|
+
var _b = freb(fdeb, 0);
|
|
1675
|
+
var fd = _b.b;
|
|
1676
|
+
var revfd = _b.r;
|
|
1677
|
+
var rev = new u16(32768);
|
|
1678
|
+
for (i = 0; i < 32768; ++i) {
|
|
1679
|
+
x = (i & 43690) >> 1 | (i & 21845) << 1;
|
|
1680
|
+
x = (x & 52428) >> 2 | (x & 13107) << 2;
|
|
1681
|
+
x = (x & 61680) >> 4 | (x & 3855) << 4;
|
|
1682
|
+
rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
|
|
1683
|
+
}
|
|
1684
|
+
var x;
|
|
1685
|
+
var i;
|
|
1686
|
+
var hMap = (function(cd, mb, r) {
|
|
1687
|
+
var s = cd.length;
|
|
1688
|
+
var i = 0;
|
|
1689
|
+
var l = new u16(mb);
|
|
1690
|
+
for (; i < s; ++i) {
|
|
1691
|
+
if (cd[i])
|
|
1692
|
+
++l[cd[i] - 1];
|
|
1693
|
+
}
|
|
1694
|
+
var le = new u16(mb);
|
|
1695
|
+
for (i = 1; i < mb; ++i) {
|
|
1696
|
+
le[i] = le[i - 1] + l[i - 1] << 1;
|
|
1697
|
+
}
|
|
1698
|
+
var co;
|
|
1699
|
+
if (r) {
|
|
1700
|
+
co = new u16(1 << mb);
|
|
1701
|
+
var rvb = 15 - mb;
|
|
1702
|
+
for (i = 0; i < s; ++i) {
|
|
1703
|
+
if (cd[i]) {
|
|
1704
|
+
var sv = i << 4 | cd[i];
|
|
1705
|
+
var r_1 = mb - cd[i];
|
|
1706
|
+
var v = le[cd[i] - 1]++ << r_1;
|
|
1707
|
+
for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
|
|
1708
|
+
co[rev[v] >> rvb] = sv;
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
} else {
|
|
1713
|
+
co = new u16(s);
|
|
1714
|
+
for (i = 0; i < s; ++i) {
|
|
1715
|
+
if (cd[i]) {
|
|
1716
|
+
co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
return co;
|
|
1721
|
+
});
|
|
1722
|
+
var flt = new u8(288);
|
|
1723
|
+
for (i = 0; i < 144; ++i)
|
|
1724
|
+
flt[i] = 8;
|
|
1725
|
+
var i;
|
|
1726
|
+
for (i = 144; i < 256; ++i)
|
|
1727
|
+
flt[i] = 9;
|
|
1728
|
+
var i;
|
|
1729
|
+
for (i = 256; i < 280; ++i)
|
|
1730
|
+
flt[i] = 7;
|
|
1731
|
+
var i;
|
|
1732
|
+
for (i = 280; i < 288; ++i)
|
|
1733
|
+
flt[i] = 8;
|
|
1734
|
+
var i;
|
|
1735
|
+
var fdt = new u8(32);
|
|
1736
|
+
for (i = 0; i < 32; ++i)
|
|
1737
|
+
fdt[i] = 5;
|
|
1738
|
+
var i;
|
|
1739
|
+
var flm = /* @__PURE__ */ hMap(flt, 9, 0);
|
|
1740
|
+
var flrm = /* @__PURE__ */ hMap(flt, 9, 1);
|
|
1741
|
+
var fdm = /* @__PURE__ */ hMap(fdt, 5, 0);
|
|
1742
|
+
var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
|
|
1743
|
+
var max = function(a) {
|
|
1744
|
+
var m = a[0];
|
|
1745
|
+
for (var i = 1; i < a.length; ++i) {
|
|
1746
|
+
if (a[i] > m)
|
|
1747
|
+
m = a[i];
|
|
1748
|
+
}
|
|
1749
|
+
return m;
|
|
1750
|
+
};
|
|
1751
|
+
var bits = function(d, p, m) {
|
|
1752
|
+
var o = p / 8 | 0;
|
|
1753
|
+
return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
|
|
1754
|
+
};
|
|
1755
|
+
var bits16 = function(d, p) {
|
|
1756
|
+
var o = p / 8 | 0;
|
|
1757
|
+
return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
|
|
1758
|
+
};
|
|
1759
|
+
var shft = function(p) {
|
|
1760
|
+
return (p + 7) / 8 | 0;
|
|
1761
|
+
};
|
|
1762
|
+
var slc = function(v, s, e) {
|
|
1763
|
+
if (s == null || s < 0)
|
|
1764
|
+
s = 0;
|
|
1765
|
+
if (e == null || e > v.length)
|
|
1766
|
+
e = v.length;
|
|
1767
|
+
return new u8(v.subarray(s, e));
|
|
1768
|
+
};
|
|
1769
|
+
var ec = [
|
|
1770
|
+
"unexpected EOF",
|
|
1771
|
+
"invalid block type",
|
|
1772
|
+
"invalid length/literal",
|
|
1773
|
+
"invalid distance",
|
|
1774
|
+
"stream finished",
|
|
1775
|
+
"no stream handler",
|
|
1776
|
+
,
|
|
1777
|
+
"no callback",
|
|
1778
|
+
"invalid UTF-8 data",
|
|
1779
|
+
"extra field too long",
|
|
1780
|
+
"date not in range 1980-2099",
|
|
1781
|
+
"filename too long",
|
|
1782
|
+
"stream finishing",
|
|
1783
|
+
"invalid zip data"
|
|
1784
|
+
// determined by unknown compression method
|
|
1785
|
+
];
|
|
1786
|
+
var err = function(ind, msg, nt) {
|
|
1787
|
+
var e = new Error(msg || ec[ind]);
|
|
1788
|
+
e.code = ind;
|
|
1789
|
+
if (Error.captureStackTrace)
|
|
1790
|
+
Error.captureStackTrace(e, err);
|
|
1791
|
+
if (!nt)
|
|
1792
|
+
throw e;
|
|
1793
|
+
return e;
|
|
1794
|
+
};
|
|
1795
|
+
var inflt = function(dat, st, buf, dict) {
|
|
1796
|
+
var sl = dat.length, dl = dict ? dict.length : 0;
|
|
1797
|
+
if (!sl || st.f && !st.l)
|
|
1798
|
+
return buf || new u8(0);
|
|
1799
|
+
var noBuf = !buf;
|
|
1800
|
+
var resize = noBuf || st.i != 2;
|
|
1801
|
+
var noSt = st.i;
|
|
1802
|
+
if (noBuf)
|
|
1803
|
+
buf = new u8(sl * 3);
|
|
1804
|
+
var cbuf = function(l2) {
|
|
1805
|
+
var bl = buf.length;
|
|
1806
|
+
if (l2 > bl) {
|
|
1807
|
+
var nbuf = new u8(Math.max(bl * 2, l2));
|
|
1808
|
+
nbuf.set(buf);
|
|
1809
|
+
buf = nbuf;
|
|
1810
|
+
}
|
|
1811
|
+
};
|
|
1812
|
+
var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;
|
|
1813
|
+
var tbts = sl * 8;
|
|
1814
|
+
do {
|
|
1815
|
+
if (!lm) {
|
|
1816
|
+
final = bits(dat, pos, 1);
|
|
1817
|
+
var type = bits(dat, pos + 1, 3);
|
|
1818
|
+
pos += 3;
|
|
1819
|
+
if (!type) {
|
|
1820
|
+
var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
|
|
1821
|
+
if (t > sl) {
|
|
1822
|
+
if (noSt)
|
|
1823
|
+
err(0);
|
|
1824
|
+
break;
|
|
1825
|
+
}
|
|
1826
|
+
if (resize)
|
|
1827
|
+
cbuf(bt + l);
|
|
1828
|
+
buf.set(dat.subarray(s, t), bt);
|
|
1829
|
+
st.b = bt += l, st.p = pos = t * 8, st.f = final;
|
|
1830
|
+
continue;
|
|
1831
|
+
} else if (type == 1)
|
|
1832
|
+
lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
|
|
1833
|
+
else if (type == 2) {
|
|
1834
|
+
var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
|
|
1835
|
+
var tl = hLit + bits(dat, pos + 5, 31) + 1;
|
|
1836
|
+
pos += 14;
|
|
1837
|
+
var ldt = new u8(tl);
|
|
1838
|
+
var clt = new u8(19);
|
|
1839
|
+
for (var i = 0; i < hcLen; ++i) {
|
|
1840
|
+
clt[clim[i]] = bits(dat, pos + i * 3, 7);
|
|
1841
|
+
}
|
|
1842
|
+
pos += hcLen * 3;
|
|
1843
|
+
var clb = max(clt), clbmsk = (1 << clb) - 1;
|
|
1844
|
+
var clm = hMap(clt, clb, 1);
|
|
1845
|
+
for (var i = 0; i < tl; ) {
|
|
1846
|
+
var r = clm[bits(dat, pos, clbmsk)];
|
|
1847
|
+
pos += r & 15;
|
|
1848
|
+
var s = r >> 4;
|
|
1849
|
+
if (s < 16) {
|
|
1850
|
+
ldt[i++] = s;
|
|
1851
|
+
} else {
|
|
1852
|
+
var c = 0, n = 0;
|
|
1853
|
+
if (s == 16)
|
|
1854
|
+
n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
|
|
1855
|
+
else if (s == 17)
|
|
1856
|
+
n = 3 + bits(dat, pos, 7), pos += 3;
|
|
1857
|
+
else if (s == 18)
|
|
1858
|
+
n = 11 + bits(dat, pos, 127), pos += 7;
|
|
1859
|
+
while (n--)
|
|
1860
|
+
ldt[i++] = c;
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
|
|
1864
|
+
lbt = max(lt);
|
|
1865
|
+
dbt = max(dt);
|
|
1866
|
+
lm = hMap(lt, lbt, 1);
|
|
1867
|
+
dm = hMap(dt, dbt, 1);
|
|
1868
|
+
} else
|
|
1869
|
+
err(1);
|
|
1870
|
+
if (pos > tbts) {
|
|
1871
|
+
if (noSt)
|
|
1872
|
+
err(0);
|
|
1873
|
+
break;
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
if (resize)
|
|
1877
|
+
cbuf(bt + 131072);
|
|
1878
|
+
var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
|
|
1879
|
+
var lpos = pos;
|
|
1880
|
+
for (; ; lpos = pos) {
|
|
1881
|
+
var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
|
|
1882
|
+
pos += c & 15;
|
|
1883
|
+
if (pos > tbts) {
|
|
1884
|
+
if (noSt)
|
|
1885
|
+
err(0);
|
|
1886
|
+
break;
|
|
1887
|
+
}
|
|
1888
|
+
if (!c)
|
|
1889
|
+
err(2);
|
|
1890
|
+
if (sym < 256)
|
|
1891
|
+
buf[bt++] = sym;
|
|
1892
|
+
else if (sym == 256) {
|
|
1893
|
+
lpos = pos, lm = null;
|
|
1894
|
+
break;
|
|
1895
|
+
} else {
|
|
1896
|
+
var add = sym - 254;
|
|
1897
|
+
if (sym > 264) {
|
|
1898
|
+
var i = sym - 257, b = fleb[i];
|
|
1899
|
+
add = bits(dat, pos, (1 << b) - 1) + fl[i];
|
|
1900
|
+
pos += b;
|
|
1901
|
+
}
|
|
1902
|
+
var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
|
|
1903
|
+
if (!d)
|
|
1904
|
+
err(3);
|
|
1905
|
+
pos += d & 15;
|
|
1906
|
+
var dt = fd[dsym];
|
|
1907
|
+
if (dsym > 3) {
|
|
1908
|
+
var b = fdeb[dsym];
|
|
1909
|
+
dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
|
|
1910
|
+
}
|
|
1911
|
+
if (pos > tbts) {
|
|
1912
|
+
if (noSt)
|
|
1913
|
+
err(0);
|
|
1914
|
+
break;
|
|
1915
|
+
}
|
|
1916
|
+
if (resize)
|
|
1917
|
+
cbuf(bt + 131072);
|
|
1918
|
+
var end = bt + add;
|
|
1919
|
+
if (bt < dt) {
|
|
1920
|
+
var shift = dl - dt, dend = Math.min(dt, end);
|
|
1921
|
+
if (shift + bt < 0)
|
|
1922
|
+
err(3);
|
|
1923
|
+
for (; bt < dend; ++bt)
|
|
1924
|
+
buf[bt] = dict[shift + bt];
|
|
1925
|
+
}
|
|
1926
|
+
for (; bt < end; ++bt)
|
|
1927
|
+
buf[bt] = buf[bt - dt];
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
st.l = lm, st.p = lpos, st.b = bt, st.f = final;
|
|
1931
|
+
if (lm)
|
|
1932
|
+
final = 1, st.m = lbt, st.d = dm, st.n = dbt;
|
|
1933
|
+
} while (!final);
|
|
1934
|
+
return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
|
|
1935
|
+
};
|
|
1936
|
+
var wbits = function(d, p, v) {
|
|
1937
|
+
v <<= p & 7;
|
|
1938
|
+
var o = p / 8 | 0;
|
|
1939
|
+
d[o] |= v;
|
|
1940
|
+
d[o + 1] |= v >> 8;
|
|
1941
|
+
};
|
|
1942
|
+
var wbits16 = function(d, p, v) {
|
|
1943
|
+
v <<= p & 7;
|
|
1944
|
+
var o = p / 8 | 0;
|
|
1945
|
+
d[o] |= v;
|
|
1946
|
+
d[o + 1] |= v >> 8;
|
|
1947
|
+
d[o + 2] |= v >> 16;
|
|
1948
|
+
};
|
|
1949
|
+
var hTree = function(d, mb) {
|
|
1950
|
+
var t = [];
|
|
1951
|
+
for (var i = 0; i < d.length; ++i) {
|
|
1952
|
+
if (d[i])
|
|
1953
|
+
t.push({ s: i, f: d[i] });
|
|
1954
|
+
}
|
|
1955
|
+
var s = t.length;
|
|
1956
|
+
var t2 = t.slice();
|
|
1957
|
+
if (!s)
|
|
1958
|
+
return { t: et, l: 0 };
|
|
1959
|
+
if (s == 1) {
|
|
1960
|
+
var v = new u8(t[0].s + 1);
|
|
1961
|
+
v[t[0].s] = 1;
|
|
1962
|
+
return { t: v, l: 1 };
|
|
1963
|
+
}
|
|
1964
|
+
t.sort(function(a, b) {
|
|
1965
|
+
return a.f - b.f;
|
|
1966
|
+
});
|
|
1967
|
+
t.push({ s: -1, f: 25001 });
|
|
1968
|
+
var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2;
|
|
1969
|
+
t[0] = { s: -1, f: l.f + r.f, l, r };
|
|
1970
|
+
while (i1 != s - 1) {
|
|
1971
|
+
l = t[t[i0].f < t[i2].f ? i0++ : i2++];
|
|
1972
|
+
r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++];
|
|
1973
|
+
t[i1++] = { s: -1, f: l.f + r.f, l, r };
|
|
1974
|
+
}
|
|
1975
|
+
var maxSym = t2[0].s;
|
|
1976
|
+
for (var i = 1; i < s; ++i) {
|
|
1977
|
+
if (t2[i].s > maxSym)
|
|
1978
|
+
maxSym = t2[i].s;
|
|
1979
|
+
}
|
|
1980
|
+
var tr = new u16(maxSym + 1);
|
|
1981
|
+
var mbt = ln(t[i1 - 1], tr, 0);
|
|
1982
|
+
if (mbt > mb) {
|
|
1983
|
+
var i = 0, dt = 0;
|
|
1984
|
+
var lft = mbt - mb, cst = 1 << lft;
|
|
1985
|
+
t2.sort(function(a, b) {
|
|
1986
|
+
return tr[b.s] - tr[a.s] || a.f - b.f;
|
|
1987
|
+
});
|
|
1988
|
+
for (; i < s; ++i) {
|
|
1989
|
+
var i2_1 = t2[i].s;
|
|
1990
|
+
if (tr[i2_1] > mb) {
|
|
1991
|
+
dt += cst - (1 << mbt - tr[i2_1]);
|
|
1992
|
+
tr[i2_1] = mb;
|
|
1993
|
+
} else
|
|
1994
|
+
break;
|
|
1995
|
+
}
|
|
1996
|
+
dt >>= lft;
|
|
1997
|
+
while (dt > 0) {
|
|
1998
|
+
var i2_2 = t2[i].s;
|
|
1999
|
+
if (tr[i2_2] < mb)
|
|
2000
|
+
dt -= 1 << mb - tr[i2_2]++ - 1;
|
|
2001
|
+
else
|
|
2002
|
+
++i;
|
|
2003
|
+
}
|
|
2004
|
+
for (; i >= 0 && dt; --i) {
|
|
2005
|
+
var i2_3 = t2[i].s;
|
|
2006
|
+
if (tr[i2_3] == mb) {
|
|
2007
|
+
--tr[i2_3];
|
|
2008
|
+
++dt;
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
mbt = mb;
|
|
2012
|
+
}
|
|
2013
|
+
return { t: new u8(tr), l: mbt };
|
|
2014
|
+
};
|
|
2015
|
+
var ln = function(n, l, d) {
|
|
2016
|
+
return n.s == -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d;
|
|
2017
|
+
};
|
|
2018
|
+
var lc = function(c) {
|
|
2019
|
+
var s = c.length;
|
|
2020
|
+
while (s && !c[--s])
|
|
2021
|
+
;
|
|
2022
|
+
var cl = new u16(++s);
|
|
2023
|
+
var cli = 0, cln = c[0], cls = 1;
|
|
2024
|
+
var w = function(v) {
|
|
2025
|
+
cl[cli++] = v;
|
|
2026
|
+
};
|
|
2027
|
+
for (var i = 1; i <= s; ++i) {
|
|
2028
|
+
if (c[i] == cln && i != s)
|
|
2029
|
+
++cls;
|
|
2030
|
+
else {
|
|
2031
|
+
if (!cln && cls > 2) {
|
|
2032
|
+
for (; cls > 138; cls -= 138)
|
|
2033
|
+
w(32754);
|
|
2034
|
+
if (cls > 2) {
|
|
2035
|
+
w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305);
|
|
2036
|
+
cls = 0;
|
|
2037
|
+
}
|
|
2038
|
+
} else if (cls > 3) {
|
|
2039
|
+
w(cln), --cls;
|
|
2040
|
+
for (; cls > 6; cls -= 6)
|
|
2041
|
+
w(8304);
|
|
2042
|
+
if (cls > 2)
|
|
2043
|
+
w(cls - 3 << 5 | 8208), cls = 0;
|
|
2044
|
+
}
|
|
2045
|
+
while (cls--)
|
|
2046
|
+
w(cln);
|
|
2047
|
+
cls = 1;
|
|
2048
|
+
cln = c[i];
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
return { c: cl.subarray(0, cli), n: s };
|
|
2052
|
+
};
|
|
2053
|
+
var clen = function(cf, cl) {
|
|
2054
|
+
var l = 0;
|
|
2055
|
+
for (var i = 0; i < cl.length; ++i)
|
|
2056
|
+
l += cf[i] * cl[i];
|
|
2057
|
+
return l;
|
|
2058
|
+
};
|
|
2059
|
+
var wfblk = function(out, pos, dat) {
|
|
2060
|
+
var s = dat.length;
|
|
2061
|
+
var o = shft(pos + 2);
|
|
2062
|
+
out[o] = s & 255;
|
|
2063
|
+
out[o + 1] = s >> 8;
|
|
2064
|
+
out[o + 2] = out[o] ^ 255;
|
|
2065
|
+
out[o + 3] = out[o + 1] ^ 255;
|
|
2066
|
+
for (var i = 0; i < s; ++i)
|
|
2067
|
+
out[o + i + 4] = dat[i];
|
|
2068
|
+
return (o + 4 + s) * 8;
|
|
2069
|
+
};
|
|
2070
|
+
var wblk = function(dat, out, final, syms, lf, df, eb, li, bs, bl, p) {
|
|
2071
|
+
wbits(out, p++, final);
|
|
2072
|
+
++lf[256];
|
|
2073
|
+
var _a2 = hTree(lf, 15), dlt = _a2.t, mlb = _a2.l;
|
|
2074
|
+
var _b2 = hTree(df, 15), ddt = _b2.t, mdb = _b2.l;
|
|
2075
|
+
var _c = lc(dlt), lclt = _c.c, nlc = _c.n;
|
|
2076
|
+
var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;
|
|
2077
|
+
var lcfreq = new u16(19);
|
|
2078
|
+
for (var i = 0; i < lclt.length; ++i)
|
|
2079
|
+
++lcfreq[lclt[i] & 31];
|
|
2080
|
+
for (var i = 0; i < lcdt.length; ++i)
|
|
2081
|
+
++lcfreq[lcdt[i] & 31];
|
|
2082
|
+
var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;
|
|
2083
|
+
var nlcc = 19;
|
|
2084
|
+
for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)
|
|
2085
|
+
;
|
|
2086
|
+
var flen = bl + 5 << 3;
|
|
2087
|
+
var ftlen = clen(lf, flt) + clen(df, fdt) + eb;
|
|
2088
|
+
var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];
|
|
2089
|
+
if (bs >= 0 && flen <= ftlen && flen <= dtlen)
|
|
2090
|
+
return wfblk(out, p, dat.subarray(bs, bs + bl));
|
|
2091
|
+
var lm, ll, dm, dl;
|
|
2092
|
+
wbits(out, p, 1 + (dtlen < ftlen)), p += 2;
|
|
2093
|
+
if (dtlen < ftlen) {
|
|
2094
|
+
lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;
|
|
2095
|
+
var llm = hMap(lct, mlcb, 0);
|
|
2096
|
+
wbits(out, p, nlc - 257);
|
|
2097
|
+
wbits(out, p + 5, ndc - 1);
|
|
2098
|
+
wbits(out, p + 10, nlcc - 4);
|
|
2099
|
+
p += 14;
|
|
2100
|
+
for (var i = 0; i < nlcc; ++i)
|
|
2101
|
+
wbits(out, p + 3 * i, lct[clim[i]]);
|
|
2102
|
+
p += 3 * nlcc;
|
|
2103
|
+
var lcts = [lclt, lcdt];
|
|
2104
|
+
for (var it = 0; it < 2; ++it) {
|
|
2105
|
+
var clct = lcts[it];
|
|
2106
|
+
for (var i = 0; i < clct.length; ++i) {
|
|
2107
|
+
var len = clct[i] & 31;
|
|
2108
|
+
wbits(out, p, llm[len]), p += lct[len];
|
|
2109
|
+
if (len > 15)
|
|
2110
|
+
wbits(out, p, clct[i] >> 5 & 127), p += clct[i] >> 12;
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
} else {
|
|
2114
|
+
lm = flm, ll = flt, dm = fdm, dl = fdt;
|
|
2115
|
+
}
|
|
2116
|
+
for (var i = 0; i < li; ++i) {
|
|
2117
|
+
var sym = syms[i];
|
|
2118
|
+
if (sym > 255) {
|
|
2119
|
+
var len = sym >> 18 & 31;
|
|
2120
|
+
wbits16(out, p, lm[len + 257]), p += ll[len + 257];
|
|
2121
|
+
if (len > 7)
|
|
2122
|
+
wbits(out, p, sym >> 23 & 31), p += fleb[len];
|
|
2123
|
+
var dst = sym & 31;
|
|
2124
|
+
wbits16(out, p, dm[dst]), p += dl[dst];
|
|
2125
|
+
if (dst > 3)
|
|
2126
|
+
wbits16(out, p, sym >> 5 & 8191), p += fdeb[dst];
|
|
2127
|
+
} else {
|
|
2128
|
+
wbits16(out, p, lm[sym]), p += ll[sym];
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
wbits16(out, p, lm[256]);
|
|
2132
|
+
return p + ll[256];
|
|
2133
|
+
};
|
|
2134
|
+
var deo = /* @__PURE__ */ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);
|
|
2135
|
+
var et = /* @__PURE__ */ new u8(0);
|
|
2136
|
+
var dflt = function(dat, lvl, plvl, pre, post, st) {
|
|
2137
|
+
var s = st.z || dat.length;
|
|
2138
|
+
var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post);
|
|
2139
|
+
var w = o.subarray(pre, o.length - post);
|
|
2140
|
+
var lst = st.l;
|
|
2141
|
+
var pos = (st.r || 0) & 7;
|
|
2142
|
+
if (lvl) {
|
|
2143
|
+
if (pos)
|
|
2144
|
+
w[0] = st.r >> 3;
|
|
2145
|
+
var opt = deo[lvl - 1];
|
|
2146
|
+
var n = opt >> 13, c = opt & 8191;
|
|
2147
|
+
var msk_1 = (1 << plvl) - 1;
|
|
2148
|
+
var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);
|
|
2149
|
+
var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;
|
|
2150
|
+
var hsh = function(i2) {
|
|
2151
|
+
return (dat[i2] ^ dat[i2 + 1] << bs1_1 ^ dat[i2 + 2] << bs2_1) & msk_1;
|
|
2152
|
+
};
|
|
2153
|
+
var syms = new i32(25e3);
|
|
2154
|
+
var lf = new u16(288), df = new u16(32);
|
|
2155
|
+
var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0;
|
|
2156
|
+
for (; i + 2 < s; ++i) {
|
|
2157
|
+
var hv = hsh(i);
|
|
2158
|
+
var imod = i & 32767, pimod = head[hv];
|
|
2159
|
+
prev[imod] = pimod;
|
|
2160
|
+
head[hv] = imod;
|
|
2161
|
+
if (wi <= i) {
|
|
2162
|
+
var rem = s - i;
|
|
2163
|
+
if ((lc_1 > 7e3 || li > 24576) && (rem > 423 || !lst)) {
|
|
2164
|
+
pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos);
|
|
2165
|
+
li = lc_1 = eb = 0, bs = i;
|
|
2166
|
+
for (var j = 0; j < 286; ++j)
|
|
2167
|
+
lf[j] = 0;
|
|
2168
|
+
for (var j = 0; j < 30; ++j)
|
|
2169
|
+
df[j] = 0;
|
|
2170
|
+
}
|
|
2171
|
+
var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;
|
|
2172
|
+
if (rem > 2 && hv == hsh(i - dif)) {
|
|
2173
|
+
var maxn = Math.min(n, rem) - 1;
|
|
2174
|
+
var maxd = Math.min(32767, i);
|
|
2175
|
+
var ml = Math.min(258, rem);
|
|
2176
|
+
while (dif <= maxd && --ch_1 && imod != pimod) {
|
|
2177
|
+
if (dat[i + l] == dat[i + l - dif]) {
|
|
2178
|
+
var nl = 0;
|
|
2179
|
+
for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl)
|
|
2180
|
+
;
|
|
2181
|
+
if (nl > l) {
|
|
2182
|
+
l = nl, d = dif;
|
|
2183
|
+
if (nl > maxn)
|
|
2184
|
+
break;
|
|
2185
|
+
var mmd = Math.min(dif, nl - 2);
|
|
2186
|
+
var md = 0;
|
|
2187
|
+
for (var j = 0; j < mmd; ++j) {
|
|
2188
|
+
var ti = i - dif + j & 32767;
|
|
2189
|
+
var pti = prev[ti];
|
|
2190
|
+
var cd = ti - pti & 32767;
|
|
2191
|
+
if (cd > md)
|
|
2192
|
+
md = cd, pimod = ti;
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
}
|
|
2196
|
+
imod = pimod, pimod = prev[imod];
|
|
2197
|
+
dif += imod - pimod & 32767;
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
if (d) {
|
|
2201
|
+
syms[li++] = 268435456 | revfl[l] << 18 | revfd[d];
|
|
2202
|
+
var lin = revfl[l] & 31, din = revfd[d] & 31;
|
|
2203
|
+
eb += fleb[lin] + fdeb[din];
|
|
2204
|
+
++lf[257 + lin];
|
|
2205
|
+
++df[din];
|
|
2206
|
+
wi = i + l;
|
|
2207
|
+
++lc_1;
|
|
2208
|
+
} else {
|
|
2209
|
+
syms[li++] = dat[i];
|
|
2210
|
+
++lf[dat[i]];
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
for (i = Math.max(i, wi); i < s; ++i) {
|
|
2215
|
+
syms[li++] = dat[i];
|
|
2216
|
+
++lf[dat[i]];
|
|
2217
|
+
}
|
|
2218
|
+
pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos);
|
|
2219
|
+
if (!lst) {
|
|
2220
|
+
st.r = pos & 7 | w[pos / 8 | 0] << 3;
|
|
2221
|
+
pos -= 7;
|
|
2222
|
+
st.h = head, st.p = prev, st.i = i, st.w = wi;
|
|
2223
|
+
}
|
|
2224
|
+
} else {
|
|
2225
|
+
for (var i = st.w || 0; i < s + lst; i += 65535) {
|
|
2226
|
+
var e = i + 65535;
|
|
2227
|
+
if (e >= s) {
|
|
2228
|
+
w[pos / 8 | 0] = lst;
|
|
2229
|
+
e = s;
|
|
2230
|
+
}
|
|
2231
|
+
pos = wfblk(w, pos + 1, dat.subarray(i, e));
|
|
2232
|
+
}
|
|
2233
|
+
st.i = s;
|
|
2234
|
+
}
|
|
2235
|
+
return slc(o, 0, pre + shft(pos) + post);
|
|
2236
|
+
};
|
|
2237
|
+
var crct = /* @__PURE__ */ (function() {
|
|
2238
|
+
var t = new Int32Array(256);
|
|
2239
|
+
for (var i = 0; i < 256; ++i) {
|
|
2240
|
+
var c = i, k = 9;
|
|
2241
|
+
while (--k)
|
|
2242
|
+
c = (c & 1 && -306674912) ^ c >>> 1;
|
|
2243
|
+
t[i] = c;
|
|
2244
|
+
}
|
|
2245
|
+
return t;
|
|
2246
|
+
})();
|
|
2247
|
+
var crc = function() {
|
|
2248
|
+
var c = -1;
|
|
2249
|
+
return {
|
|
2250
|
+
p: function(d) {
|
|
2251
|
+
var cr = c;
|
|
2252
|
+
for (var i = 0; i < d.length; ++i)
|
|
2253
|
+
cr = crct[cr & 255 ^ d[i]] ^ cr >>> 8;
|
|
2254
|
+
c = cr;
|
|
2255
|
+
},
|
|
2256
|
+
d: function() {
|
|
2257
|
+
return ~c;
|
|
2258
|
+
}
|
|
2259
|
+
};
|
|
2260
|
+
};
|
|
2261
|
+
var dopt = function(dat, opt, pre, post, st) {
|
|
2262
|
+
if (!st) {
|
|
2263
|
+
st = { l: 1 };
|
|
2264
|
+
if (opt.dictionary) {
|
|
2265
|
+
var dict = opt.dictionary.subarray(-32768);
|
|
2266
|
+
var newDat = new u8(dict.length + dat.length);
|
|
2267
|
+
newDat.set(dict);
|
|
2268
|
+
newDat.set(dat, dict.length);
|
|
2269
|
+
dat = newDat;
|
|
2270
|
+
st.w = dict.length;
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2273
|
+
return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20 : 12 + opt.mem, pre, post, st);
|
|
2274
|
+
};
|
|
2275
|
+
var mrg = function(a, b) {
|
|
2276
|
+
var o = {};
|
|
2277
|
+
for (var k in a)
|
|
2278
|
+
o[k] = a[k];
|
|
2279
|
+
for (var k in b)
|
|
2280
|
+
o[k] = b[k];
|
|
2281
|
+
return o;
|
|
2282
|
+
};
|
|
2283
|
+
var b2 = function(d, b) {
|
|
2284
|
+
return d[b] | d[b + 1] << 8;
|
|
2285
|
+
};
|
|
2286
|
+
var b4 = function(d, b) {
|
|
2287
|
+
return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
|
|
2288
|
+
};
|
|
2289
|
+
var b8 = function(d, b) {
|
|
2290
|
+
return b4(d, b) + b4(d, b + 4) * 4294967296;
|
|
2291
|
+
};
|
|
2292
|
+
var wbytes = function(d, b, v) {
|
|
2293
|
+
for (; v; ++b)
|
|
2294
|
+
d[b] = v, v >>>= 8;
|
|
2295
|
+
};
|
|
2296
|
+
function deflateSync(data, opts) {
|
|
2297
|
+
return dopt(data, opts || {}, 0, 0);
|
|
2298
|
+
}
|
|
2299
|
+
var Inflate = /* @__PURE__ */ (function() {
|
|
2300
|
+
function Inflate2(opts, cb) {
|
|
2301
|
+
if (typeof opts == "function")
|
|
2302
|
+
cb = opts, opts = {};
|
|
2303
|
+
this.ondata = cb;
|
|
2304
|
+
var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768);
|
|
2305
|
+
this.s = { i: 0, b: dict ? dict.length : 0 };
|
|
2306
|
+
this.o = new u8(32768);
|
|
2307
|
+
this.p = new u8(0);
|
|
2308
|
+
if (dict)
|
|
2309
|
+
this.o.set(dict);
|
|
2310
|
+
}
|
|
2311
|
+
Inflate2.prototype.e = function(c) {
|
|
2312
|
+
if (!this.ondata)
|
|
2313
|
+
err(5);
|
|
2314
|
+
if (this.d)
|
|
2315
|
+
err(4);
|
|
2316
|
+
if (!this.p.length)
|
|
2317
|
+
this.p = c;
|
|
2318
|
+
else if (c.length) {
|
|
2319
|
+
var n = new u8(this.p.length + c.length);
|
|
2320
|
+
n.set(this.p), n.set(c, this.p.length), this.p = n;
|
|
2321
|
+
}
|
|
2322
|
+
};
|
|
2323
|
+
Inflate2.prototype.c = function(final) {
|
|
2324
|
+
this.s.i = +(this.d = final || false);
|
|
2325
|
+
var bts = this.s.b;
|
|
2326
|
+
var dt = inflt(this.p, this.s, this.o);
|
|
2327
|
+
this.ondata(slc(dt, bts, this.s.b), this.d);
|
|
2328
|
+
this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length;
|
|
2329
|
+
this.p = slc(this.p, this.s.p / 8 | 0), this.s.p &= 7;
|
|
2330
|
+
};
|
|
2331
|
+
Inflate2.prototype.push = function(chunk, final) {
|
|
2332
|
+
this.e(chunk), this.c(final);
|
|
2333
|
+
};
|
|
2334
|
+
return Inflate2;
|
|
2335
|
+
})();
|
|
2336
|
+
var fltn = function(d, p, t, o) {
|
|
2337
|
+
for (var k in d) {
|
|
2338
|
+
var val = d[k], n = p + k, op = o;
|
|
2339
|
+
if (Array.isArray(val))
|
|
2340
|
+
op = mrg(o, val[1]), val = val[0];
|
|
2341
|
+
if (val instanceof u8)
|
|
2342
|
+
t[n] = [val, op];
|
|
2343
|
+
else {
|
|
2344
|
+
t[n += "/"] = [new u8(0), op];
|
|
2345
|
+
fltn(val, n, t, o);
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
};
|
|
2349
|
+
var te = typeof TextEncoder != "undefined" && /* @__PURE__ */ new TextEncoder();
|
|
2350
|
+
var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
|
|
2351
|
+
var tds = 0;
|
|
2352
|
+
try {
|
|
2353
|
+
td.decode(et, { stream: true });
|
|
2354
|
+
tds = 1;
|
|
2355
|
+
} catch (e) {
|
|
2356
|
+
}
|
|
2357
|
+
var dutf8 = function(d) {
|
|
2358
|
+
for (var r = "", i = 0; ; ) {
|
|
2359
|
+
var c = d[i++];
|
|
2360
|
+
var eb = (c > 127) + (c > 223) + (c > 239);
|
|
2361
|
+
if (i + eb > d.length)
|
|
2362
|
+
return { s: r, r: slc(d, i - 1) };
|
|
2363
|
+
if (!eb)
|
|
2364
|
+
r += String.fromCharCode(c);
|
|
2365
|
+
else if (eb == 3) {
|
|
2366
|
+
c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023);
|
|
2367
|
+
} else if (eb & 1)
|
|
2368
|
+
r += String.fromCharCode((c & 31) << 6 | d[i++] & 63);
|
|
2369
|
+
else
|
|
2370
|
+
r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63);
|
|
2371
|
+
}
|
|
2372
|
+
};
|
|
2373
|
+
function strToU8(str, latin1) {
|
|
2374
|
+
if (latin1) {
|
|
2375
|
+
var ar_1 = new u8(str.length);
|
|
2376
|
+
for (var i = 0; i < str.length; ++i)
|
|
2377
|
+
ar_1[i] = str.charCodeAt(i);
|
|
2378
|
+
return ar_1;
|
|
2379
|
+
}
|
|
2380
|
+
if (te)
|
|
2381
|
+
return te.encode(str);
|
|
2382
|
+
var l = str.length;
|
|
2383
|
+
var ar = new u8(str.length + (str.length >> 1));
|
|
2384
|
+
var ai = 0;
|
|
2385
|
+
var w = function(v) {
|
|
2386
|
+
ar[ai++] = v;
|
|
2387
|
+
};
|
|
2388
|
+
for (var i = 0; i < l; ++i) {
|
|
2389
|
+
if (ai + 5 > ar.length) {
|
|
2390
|
+
var n = new u8(ai + 8 + (l - i << 1));
|
|
2391
|
+
n.set(ar);
|
|
2392
|
+
ar = n;
|
|
2393
|
+
}
|
|
2394
|
+
var c = str.charCodeAt(i);
|
|
2395
|
+
if (c < 128 || latin1)
|
|
2396
|
+
w(c);
|
|
2397
|
+
else if (c < 2048)
|
|
2398
|
+
w(192 | c >> 6), w(128 | c & 63);
|
|
2399
|
+
else if (c > 55295 && c < 57344)
|
|
2400
|
+
c = 65536 + (c & 1023 << 10) | str.charCodeAt(++i) & 1023, w(240 | c >> 18), w(128 | c >> 12 & 63), w(128 | c >> 6 & 63), w(128 | c & 63);
|
|
2401
|
+
else
|
|
2402
|
+
w(224 | c >> 12), w(128 | c >> 6 & 63), w(128 | c & 63);
|
|
2403
|
+
}
|
|
2404
|
+
return slc(ar, 0, ai);
|
|
2405
|
+
}
|
|
2406
|
+
function strFromU8(dat, latin1) {
|
|
2407
|
+
if (latin1) {
|
|
2408
|
+
var r = "";
|
|
2409
|
+
for (var i = 0; i < dat.length; i += 16384)
|
|
2410
|
+
r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));
|
|
2411
|
+
return r;
|
|
2412
|
+
} else if (td) {
|
|
2413
|
+
return td.decode(dat);
|
|
2414
|
+
} else {
|
|
2415
|
+
var _a2 = dutf8(dat), s = _a2.s, r = _a2.r;
|
|
2416
|
+
if (r.length)
|
|
2417
|
+
err(8);
|
|
2418
|
+
return s;
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
var z64e = function(d, b) {
|
|
2422
|
+
for (; b2(d, b) != 1; b += 4 + b2(d, b + 2))
|
|
2423
|
+
;
|
|
2424
|
+
return [b8(d, b + 12), b8(d, b + 4), b8(d, b + 20)];
|
|
2425
|
+
};
|
|
2426
|
+
var exfl = function(ex) {
|
|
2427
|
+
var le = 0;
|
|
2428
|
+
if (ex) {
|
|
2429
|
+
for (var k in ex) {
|
|
2430
|
+
var l = ex[k].length;
|
|
2431
|
+
if (l > 65535)
|
|
2432
|
+
err(9);
|
|
2433
|
+
le += l + 4;
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
return le;
|
|
2437
|
+
};
|
|
2438
|
+
var wzh = function(d, b, f, fn, u, c, ce, co) {
|
|
2439
|
+
var fl2 = fn.length, ex = f.extra, col = co && co.length;
|
|
2440
|
+
var exl = exfl(ex);
|
|
2441
|
+
wbytes(d, b, ce != null ? 33639248 : 67324752), b += 4;
|
|
2442
|
+
if (ce != null)
|
|
2443
|
+
d[b++] = 20, d[b++] = f.os;
|
|
2444
|
+
d[b] = 20, b += 2;
|
|
2445
|
+
d[b++] = f.flag << 1 | (c < 0 && 8), d[b++] = u && 8;
|
|
2446
|
+
d[b++] = f.compression & 255, d[b++] = f.compression >> 8;
|
|
2447
|
+
var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980;
|
|
2448
|
+
if (y < 0 || y > 119)
|
|
2449
|
+
err(10);
|
|
2450
|
+
wbytes(d, b, y << 25 | dt.getMonth() + 1 << 21 | dt.getDate() << 16 | dt.getHours() << 11 | dt.getMinutes() << 5 | dt.getSeconds() >> 1), b += 4;
|
|
2451
|
+
if (c != -1) {
|
|
2452
|
+
wbytes(d, b, f.crc);
|
|
2453
|
+
wbytes(d, b + 4, c < 0 ? -c - 2 : c);
|
|
2454
|
+
wbytes(d, b + 8, f.size);
|
|
2455
|
+
}
|
|
2456
|
+
wbytes(d, b + 12, fl2);
|
|
2457
|
+
wbytes(d, b + 14, exl), b += 16;
|
|
2458
|
+
if (ce != null) {
|
|
2459
|
+
wbytes(d, b, col);
|
|
2460
|
+
wbytes(d, b + 6, f.attrs);
|
|
2461
|
+
wbytes(d, b + 10, ce), b += 14;
|
|
2462
|
+
}
|
|
2463
|
+
d.set(fn, b);
|
|
2464
|
+
b += fl2;
|
|
2465
|
+
if (exl) {
|
|
2466
|
+
for (var k in ex) {
|
|
2467
|
+
var exf = ex[k], l = exf.length;
|
|
2468
|
+
wbytes(d, b, +k);
|
|
2469
|
+
wbytes(d, b + 2, l);
|
|
2470
|
+
d.set(exf, b + 4), b += 4 + l;
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
if (col)
|
|
2474
|
+
d.set(co, b), b += col;
|
|
2475
|
+
return b;
|
|
2476
|
+
};
|
|
2477
|
+
var wzf = function(o, b, c, d, e) {
|
|
2478
|
+
wbytes(o, b, 101010256);
|
|
2479
|
+
wbytes(o, b + 8, c);
|
|
2480
|
+
wbytes(o, b + 10, c);
|
|
2481
|
+
wbytes(o, b + 12, d);
|
|
2482
|
+
wbytes(o, b + 16, e);
|
|
2483
|
+
};
|
|
2484
|
+
function zipSync(data, opts) {
|
|
2485
|
+
if (!opts)
|
|
2486
|
+
opts = {};
|
|
2487
|
+
var r = {};
|
|
2488
|
+
var files = [];
|
|
2489
|
+
fltn(data, "", r, opts);
|
|
2490
|
+
var o = 0;
|
|
2491
|
+
var tot = 0;
|
|
2492
|
+
for (var fn in r) {
|
|
2493
|
+
var _a2 = r[fn], file2 = _a2[0], p = _a2[1];
|
|
2494
|
+
var compression = p.level == 0 ? 0 : 8;
|
|
2495
|
+
var f = strToU8(fn), s = f.length;
|
|
2496
|
+
var com = p.comment, m = com && strToU8(com), ms = m && m.length;
|
|
2497
|
+
var exl = exfl(p.extra);
|
|
2498
|
+
if (s > 65535)
|
|
2499
|
+
err(11);
|
|
2500
|
+
var d = compression ? deflateSync(file2, p) : file2, l = d.length;
|
|
2501
|
+
var c = crc();
|
|
2502
|
+
c.p(file2);
|
|
2503
|
+
files.push(mrg(p, {
|
|
2504
|
+
size: file2.length,
|
|
2505
|
+
crc: c.d(),
|
|
2506
|
+
c: d,
|
|
2507
|
+
f,
|
|
2508
|
+
m,
|
|
2509
|
+
u: s != fn.length || m && com.length != ms,
|
|
2510
|
+
o,
|
|
2511
|
+
compression
|
|
2512
|
+
}));
|
|
2513
|
+
o += 30 + s + exl + l;
|
|
2514
|
+
tot += 76 + 2 * (s + exl) + (ms || 0) + l;
|
|
2515
|
+
}
|
|
2516
|
+
var out = new u8(tot + 22), oe = o, cdl = tot - o;
|
|
2517
|
+
for (var i = 0; i < files.length; ++i) {
|
|
2518
|
+
var f = files[i];
|
|
2519
|
+
wzh(out, f.o, f, f.f, f.u, f.c.length);
|
|
2520
|
+
var badd = 30 + f.f.length + exfl(f.extra);
|
|
2521
|
+
out.set(f.c, f.o + badd);
|
|
2522
|
+
wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0);
|
|
2523
|
+
}
|
|
2524
|
+
wzf(out, o, files.length, cdl, oe);
|
|
2525
|
+
return out;
|
|
2526
|
+
}
|
|
2527
|
+
var UnzipPassThrough = /* @__PURE__ */ (function() {
|
|
2528
|
+
function UnzipPassThrough2() {
|
|
2529
|
+
}
|
|
2530
|
+
UnzipPassThrough2.prototype.push = function(data, final) {
|
|
2531
|
+
this.ondata(null, data, final);
|
|
2532
|
+
};
|
|
2533
|
+
UnzipPassThrough2.compression = 0;
|
|
2534
|
+
return UnzipPassThrough2;
|
|
2535
|
+
})();
|
|
2536
|
+
var UnzipInflate = /* @__PURE__ */ (function() {
|
|
2537
|
+
function UnzipInflate2() {
|
|
2538
|
+
var _this = this;
|
|
2539
|
+
this.i = new Inflate(function(dat, final) {
|
|
2540
|
+
_this.ondata(null, dat, final);
|
|
2541
|
+
});
|
|
2542
|
+
}
|
|
2543
|
+
UnzipInflate2.prototype.push = function(data, final) {
|
|
2544
|
+
try {
|
|
2545
|
+
this.i.push(data, final);
|
|
2546
|
+
} catch (e) {
|
|
2547
|
+
this.ondata(e, null, final);
|
|
2548
|
+
}
|
|
2549
|
+
};
|
|
2550
|
+
UnzipInflate2.compression = 8;
|
|
2551
|
+
return UnzipInflate2;
|
|
2552
|
+
})();
|
|
2553
|
+
var Unzip = /* @__PURE__ */ (function() {
|
|
2554
|
+
function Unzip2(cb) {
|
|
2555
|
+
this.onfile = cb;
|
|
2556
|
+
this.k = [];
|
|
2557
|
+
this.o = {
|
|
2558
|
+
0: UnzipPassThrough
|
|
2559
|
+
};
|
|
2560
|
+
this.p = et;
|
|
2561
|
+
}
|
|
2562
|
+
Unzip2.prototype.push = function(chunk, final) {
|
|
2563
|
+
var _this = this;
|
|
2564
|
+
if (!this.onfile)
|
|
2565
|
+
err(5);
|
|
2566
|
+
if (!this.p)
|
|
2567
|
+
err(4);
|
|
2568
|
+
if (this.c > 0) {
|
|
2569
|
+
var len = Math.min(this.c, chunk.length);
|
|
2570
|
+
var toAdd = chunk.subarray(0, len);
|
|
2571
|
+
this.c -= len;
|
|
2572
|
+
if (this.d)
|
|
2573
|
+
this.d.push(toAdd, !this.c);
|
|
2574
|
+
else
|
|
2575
|
+
this.k[0].push(toAdd);
|
|
2576
|
+
chunk = chunk.subarray(len);
|
|
2577
|
+
if (chunk.length)
|
|
2578
|
+
return this.push(chunk, final);
|
|
2579
|
+
} else {
|
|
2580
|
+
var f = 0, i = 0, is = void 0, buf = void 0;
|
|
2581
|
+
if (!this.p.length)
|
|
2582
|
+
buf = chunk;
|
|
2583
|
+
else if (!chunk.length)
|
|
2584
|
+
buf = this.p;
|
|
2585
|
+
else {
|
|
2586
|
+
buf = new u8(this.p.length + chunk.length);
|
|
2587
|
+
buf.set(this.p), buf.set(chunk, this.p.length);
|
|
2588
|
+
}
|
|
2589
|
+
var l = buf.length, oc = this.c, add = oc && this.d;
|
|
2590
|
+
var _loop_2 = function() {
|
|
2591
|
+
var _a2;
|
|
2592
|
+
var sig = b4(buf, i);
|
|
2593
|
+
if (sig == 67324752) {
|
|
2594
|
+
f = 1, is = i;
|
|
2595
|
+
this_1.d = null;
|
|
2596
|
+
this_1.c = 0;
|
|
2597
|
+
var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28);
|
|
2598
|
+
if (l > i + 30 + fnl + es) {
|
|
2599
|
+
var chks_3 = [];
|
|
2600
|
+
this_1.k.unshift(chks_3);
|
|
2601
|
+
f = 2;
|
|
2602
|
+
var sc_1 = b4(buf, i + 18), su_1 = b4(buf, i + 22);
|
|
2603
|
+
var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u);
|
|
2604
|
+
if (sc_1 == 4294967295) {
|
|
2605
|
+
_a2 = dd ? [-2] : z64e(buf, i), sc_1 = _a2[0], su_1 = _a2[1];
|
|
2606
|
+
} else if (dd)
|
|
2607
|
+
sc_1 = -1;
|
|
2608
|
+
i += es;
|
|
2609
|
+
this_1.c = sc_1;
|
|
2610
|
+
var d_1;
|
|
2611
|
+
var file_1 = {
|
|
2612
|
+
name: fn_1,
|
|
2613
|
+
compression: cmp_1,
|
|
2614
|
+
start: function() {
|
|
2615
|
+
if (!file_1.ondata)
|
|
2616
|
+
err(5);
|
|
2617
|
+
if (!sc_1)
|
|
2618
|
+
file_1.ondata(null, et, true);
|
|
2619
|
+
else {
|
|
2620
|
+
var ctr = _this.o[cmp_1];
|
|
2621
|
+
if (!ctr)
|
|
2622
|
+
file_1.ondata(err(14, "unknown compression type " + cmp_1, 1), null, false);
|
|
2623
|
+
d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1);
|
|
2624
|
+
d_1.ondata = function(err2, dat3, final2) {
|
|
2625
|
+
file_1.ondata(err2, dat3, final2);
|
|
2626
|
+
};
|
|
2627
|
+
for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) {
|
|
2628
|
+
var dat2 = chks_4[_i];
|
|
2629
|
+
d_1.push(dat2, false);
|
|
2630
|
+
}
|
|
2631
|
+
if (_this.k[0] == chks_3 && _this.c)
|
|
2632
|
+
_this.d = d_1;
|
|
2633
|
+
else
|
|
2634
|
+
d_1.push(et, true);
|
|
2635
|
+
}
|
|
2636
|
+
},
|
|
2637
|
+
terminate: function() {
|
|
2638
|
+
if (d_1 && d_1.terminate)
|
|
2639
|
+
d_1.terminate();
|
|
2640
|
+
}
|
|
2641
|
+
};
|
|
2642
|
+
if (sc_1 >= 0)
|
|
2643
|
+
file_1.size = sc_1, file_1.originalSize = su_1;
|
|
2644
|
+
this_1.onfile(file_1);
|
|
2645
|
+
}
|
|
2646
|
+
return "break";
|
|
2647
|
+
} else if (oc) {
|
|
2648
|
+
if (sig == 134695760) {
|
|
2649
|
+
is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0;
|
|
2650
|
+
return "break";
|
|
2651
|
+
} else if (sig == 33639248) {
|
|
2652
|
+
is = i -= 4, f = 3, this_1.c = 0;
|
|
2653
|
+
return "break";
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
};
|
|
2657
|
+
var this_1 = this;
|
|
2658
|
+
for (; i < l - 4; ++i) {
|
|
2659
|
+
var state_1 = _loop_2();
|
|
2660
|
+
if (state_1 === "break")
|
|
2661
|
+
break;
|
|
2662
|
+
}
|
|
2663
|
+
this.p = et;
|
|
2664
|
+
if (oc < 0) {
|
|
2665
|
+
var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 134695760 && 4)) : buf.subarray(0, i);
|
|
2666
|
+
if (add)
|
|
2667
|
+
add.push(dat, !!f);
|
|
2668
|
+
else
|
|
2669
|
+
this.k[+(f == 2)].push(dat);
|
|
2670
|
+
}
|
|
2671
|
+
if (f & 2)
|
|
2672
|
+
return this.push(buf.subarray(i), final);
|
|
2673
|
+
this.p = buf.subarray(i);
|
|
2674
|
+
}
|
|
2675
|
+
if (final) {
|
|
2676
|
+
if (this.c)
|
|
2677
|
+
err(13);
|
|
2678
|
+
this.p = null;
|
|
2679
|
+
}
|
|
2680
|
+
};
|
|
2681
|
+
Unzip2.prototype.register = function(decoder) {
|
|
2682
|
+
this.o[decoder.compression] = decoder;
|
|
2683
|
+
};
|
|
2684
|
+
return Unzip2;
|
|
2685
|
+
})();
|
|
2686
|
+
|
|
2687
|
+
// ../design/dist/submission.js
|
|
2688
|
+
import { z as z32 } from "zod";
|
|
2689
|
+
import { z as z6 } from "zod";
|
|
2690
|
+
import { z as z23 } from "zod";
|
|
2691
|
+
var id2 = z6.string().regex(/^[a-z0-9][a-z0-9-]{0,39}$/);
|
|
2692
|
+
var hex = z6.string().regex(/^#[0-9a-fA-F]{6}$/);
|
|
2693
|
+
var file = z6.string().min(1).max(4096);
|
|
2694
|
+
var brandSlugSchema = z6.string().regex(/^[a-z0-9][a-z0-9-]{1,39}$/);
|
|
2695
|
+
var brandLayouts = ["editorial", "poster", "grid"];
|
|
2696
|
+
var brandFields = {
|
|
2697
|
+
format: z6.literal("makeables-brand"),
|
|
2698
|
+
version: z6.literal(1),
|
|
2699
|
+
slug: brandSlugSchema,
|
|
2700
|
+
name: z6.string().trim().min(1).max(60),
|
|
2701
|
+
language: z6.enum(["en", "es"]).default("en"),
|
|
2702
|
+
tagline: z6.string().trim().max(80).optional(),
|
|
2703
|
+
description: z6.string().trim().min(1).max(400),
|
|
2704
|
+
website: z6.string().url().max(512).refine((value) => new URL(value).protocol === "https:", "Use an https website.").optional(),
|
|
2705
|
+
palette: z6.object({ paper: hex, ink: hex, accent: hex, accent2: hex.optional() }).strict().default({ paper: "#f4f1eb", ink: "#141414", accent: "#ff5a1f" }),
|
|
2706
|
+
layout: z6.enum(brandLayouts).default("editorial"),
|
|
2707
|
+
/** A design.md read from the brand's own site: palette roles, type, motifs, voice, what to avoid. */
|
|
2708
|
+
guide: z6.string().trim().max(8e3).optional(),
|
|
2709
|
+
logos: z6.array(
|
|
2710
|
+
z6.object({
|
|
2711
|
+
id: id2,
|
|
2712
|
+
name: z6.string().trim().min(1).max(40),
|
|
2713
|
+
file,
|
|
2714
|
+
/** Light art needs a dark backdrop and the reverse. */
|
|
2715
|
+
tone: z6.enum(["light", "dark"]).optional()
|
|
2716
|
+
}).strict()
|
|
2717
|
+
).max(8).default([]),
|
|
2718
|
+
cover: file.optional(),
|
|
2719
|
+
families: z6.array(
|
|
2720
|
+
z6.object({
|
|
2721
|
+
id: id2,
|
|
2722
|
+
name: z6.string().trim().min(1).max(40),
|
|
2723
|
+
headline: z6.string().trim().max(80).default(""),
|
|
2724
|
+
description: z6.string().trim().max(240).default("")
|
|
2725
|
+
}).strict()
|
|
2726
|
+
).max(6).default([]),
|
|
2727
|
+
kits: z6.array(
|
|
2728
|
+
z6.object({
|
|
2729
|
+
id: id2,
|
|
2730
|
+
family: id2.optional(),
|
|
2731
|
+
file: file.optional(),
|
|
2732
|
+
submission: z6.string().uuid().optional()
|
|
2733
|
+
}).strict().refine((kit) => kit.file || kit.submission, "A kit needs a local file or a submission.")
|
|
2734
|
+
).max(12).default([]),
|
|
2735
|
+
/** The agreed art source for this brand; checked by `kit check --brand`. */
|
|
2736
|
+
plan: z6.object({
|
|
2737
|
+
source: z6.enum(["official", "generated", "mixed"]).default("mixed"),
|
|
2738
|
+
generator: z6.string().trim().max(60).optional(),
|
|
2739
|
+
stickers: z6.number().int().min(1).max(24).optional(),
|
|
2740
|
+
generated: z6.array(file).max(64).default([])
|
|
2741
|
+
}).strict().optional()
|
|
2742
|
+
};
|
|
2743
|
+
function uniqueIds(brand, ctx) {
|
|
2744
|
+
for (const key of ["logos", "families", "kits"])
|
|
2745
|
+
if (new Set(brand[key].map((entry) => entry.id)).size !== brand[key].length)
|
|
2746
|
+
ctx.addIssue({ code: "custom", path: [key], message: "Duplicate IDs." });
|
|
2747
|
+
const families = new Set(brand.families.map((family) => family.id));
|
|
2748
|
+
for (const kit of brand.kits)
|
|
2749
|
+
if (kit.family && !families.has(kit.family))
|
|
2750
|
+
ctx.addIssue({ code: "custom", path: ["kits"], message: `Unknown family: ${kit.family}.` });
|
|
2751
|
+
}
|
|
2752
|
+
var brandDocumentSchema = z6.object(brandFields).strict().superRefine(uniqueIds);
|
|
2753
|
+
var brandPackageDocumentSchema = brandDocumentSchema.superRefine((brand, ctx) => {
|
|
2754
|
+
if (!brand.kits.length)
|
|
2755
|
+
ctx.addIssue({ code: "custom", path: ["kits"], message: "Add at least one kit." });
|
|
2756
|
+
for (const kit of brand.kits)
|
|
2757
|
+
if (!kit.submission || kit.file)
|
|
2758
|
+
ctx.addIssue({
|
|
2759
|
+
code: "custom",
|
|
2760
|
+
path: ["kits"],
|
|
2761
|
+
message: `Submit kit ${kit.id} before the brand; published brands reference kit submissions.`
|
|
2762
|
+
});
|
|
2763
|
+
for (const path of [brand.cover, ...brand.logos.map((logo) => logo.file)])
|
|
2764
|
+
if (path && !/^identity\/[a-z0-9-]+\.(png|webp|jpg|jpeg)$/.test(path))
|
|
2765
|
+
ctx.addIssue({ code: "custom", message: `Brand files live under identity/: ${path}.` });
|
|
2766
|
+
if (brand.plan) ctx.addIssue({ code: "custom", message: "The local art plan is not published." });
|
|
2767
|
+
});
|
|
2768
|
+
var id22 = z23.string().regex(/^[a-z0-9][a-z0-9-]{0,39}$/);
|
|
2769
|
+
var member = z23.object({ id: id22, file: z23.string().min(1).max(4096) }).strict();
|
|
2770
|
+
var kitDocumentSchema = z23.object({
|
|
2771
|
+
format: z23.literal("makeables-kit"),
|
|
2772
|
+
version: z23.literal(1),
|
|
2773
|
+
name: z23.string().trim().min(1).max(60),
|
|
2774
|
+
items: z23.array(member).max(24),
|
|
2775
|
+
sheets: z23.array(member).max(4).default([])
|
|
2776
|
+
}).strict().superRefine((kit, ctx) => {
|
|
2777
|
+
for (const key of ["items", "sheets"])
|
|
2778
|
+
if (new Set(kit[key].map((item) => item.id)).size !== kit[key].length)
|
|
2779
|
+
ctx.addIssue({ code: "custom", path: [key], message: "Duplicate member IDs." });
|
|
2780
|
+
});
|
|
2781
|
+
var FILE_LIMIT = 5e6;
|
|
2782
|
+
var PACKAGE_LIMIT = 24e6;
|
|
2783
|
+
var FILE_COUNT_LIMIT = 40;
|
|
2784
|
+
var KIT_FILE_COUNT_LIMIT = 160;
|
|
2785
|
+
var MANIFEST_LIMIT = 2e5;
|
|
2786
|
+
var providers = { ...designProfiles, kit: { label: "Kit" }, brand: { label: "Brand" } };
|
|
2787
|
+
var pathPattern = /^[a-zA-Z0-9_-]+(?:\/[a-zA-Z0-9_-]+)*\.(?:json|svg|png|webp|jpg|jpeg|gif|pdf)$/;
|
|
2788
|
+
var pathSchema = z32.string().max(100).regex(pathPattern);
|
|
2789
|
+
var archivePathSchema = z32.string().max(147).regex(pathPattern);
|
|
2790
|
+
var mimeSchema = z32.enum([
|
|
2791
|
+
"application/json",
|
|
2792
|
+
"image/svg+xml",
|
|
2793
|
+
"image/png",
|
|
2794
|
+
"image/webp",
|
|
2795
|
+
"image/jpeg",
|
|
2796
|
+
"image/gif",
|
|
2797
|
+
"application/pdf"
|
|
2798
|
+
]);
|
|
2799
|
+
var submissionMetadataSchema = z32.object({
|
|
2800
|
+
title: z32.string().trim().min(1).max(60),
|
|
2801
|
+
category: z32.enum(["Anime", "Gaming", "Minimal", "Abstract"]).default("Abstract"),
|
|
2802
|
+
creditName: z32.string().trim().min(1).max(60),
|
|
2803
|
+
creditUrl: z32.string().url().max(512).refine((value) => new URL(value).protocol === "https:").nullable().default(null)
|
|
2804
|
+
}).strict();
|
|
2805
|
+
var manifestBase = z32.object({
|
|
2806
|
+
format: z32.literal("makeables-package"),
|
|
2807
|
+
version: z32.literal(1),
|
|
2808
|
+
// Digital formats are screen assets; only printed products are submitted.
|
|
2809
|
+
product: z32.enum(printProductIds),
|
|
2810
|
+
finish: stickerMaterialSchema.shape.finish.optional(),
|
|
2811
|
+
title: z32.string().min(1).max(60),
|
|
2812
|
+
document: pathSchema.optional(),
|
|
2813
|
+
source: pathSchema.optional(),
|
|
2814
|
+
front: pathSchema,
|
|
2815
|
+
back: pathSchema.optional(),
|
|
2816
|
+
portrait: pathSchema.optional(),
|
|
2817
|
+
artwork: pathSchema.optional(),
|
|
2818
|
+
assets: z32.record(z32.string().max(60), pathSchema).default({}),
|
|
2819
|
+
files: z32.array(
|
|
2820
|
+
z32.object({
|
|
2821
|
+
path: pathSchema,
|
|
2822
|
+
mime: mimeSchema,
|
|
2823
|
+
bytes: z32.number().int().min(1).max(FILE_LIMIT),
|
|
2824
|
+
sha256: z32.string().regex(/^[a-f0-9]{64}$/)
|
|
2825
|
+
}).strict()
|
|
2826
|
+
).min(1).max(FILE_COUNT_LIMIT)
|
|
2827
|
+
}).strict();
|
|
2828
|
+
var designManifestSchema = manifestBase.superRefine((m, ctx) => {
|
|
2829
|
+
const paths = new Set(m.files.map((f) => f.path));
|
|
2830
|
+
const issue = (message) => ctx.addIssue({ code: "custom", message });
|
|
2831
|
+
if (paths.has("manifest.json")) issue("manifest.json is reserved for the package index.");
|
|
2832
|
+
if (paths.size !== m.files.length) issue("Duplicate asset paths.");
|
|
2833
|
+
if (m.files.reduce((n, f) => n + f.bytes, 0) > PACKAGE_LIMIT) issue("The package exceeds 24 MB.");
|
|
2834
|
+
if (!m.document && !m.source) issue("Include the editable document or original artwork.");
|
|
2835
|
+
if (m.document && m.product !== "sticker" && !m.back) issue("Include previews of both faces.");
|
|
2836
|
+
if (m.product === "sticker" && !m.finish) issue("Include the sticker finish.");
|
|
2837
|
+
if (m.product !== "sticker" && m.finish) issue("Only stickers have a sticker finish.");
|
|
2838
|
+
if (m.product === "sticker" && (m.back || m.portrait))
|
|
2839
|
+
issue("Stickers contain one face and no participant portrait.");
|
|
2840
|
+
for (const path of [
|
|
2841
|
+
m.document,
|
|
2842
|
+
m.source,
|
|
2843
|
+
m.front,
|
|
2844
|
+
m.back,
|
|
2845
|
+
m.portrait,
|
|
2846
|
+
m.artwork,
|
|
2847
|
+
...Object.values(m.assets)
|
|
2848
|
+
])
|
|
2849
|
+
if (path && !paths.has(path)) issue(`Missing asset: ${path}.`);
|
|
2850
|
+
for (const file2 of m.files) {
|
|
2851
|
+
if (file2.mime === "application/pdf") issue("Print PDFs belong to kit sheets.");
|
|
2852
|
+
if (![
|
|
2853
|
+
m.document,
|
|
2854
|
+
m.source,
|
|
2855
|
+
m.front,
|
|
2856
|
+
m.back,
|
|
2857
|
+
m.portrait,
|
|
2858
|
+
m.artwork,
|
|
2859
|
+
...Object.values(m.assets)
|
|
2860
|
+
].includes(file2.path))
|
|
2861
|
+
issue(`Unreferenced file: ${file2.path}.`);
|
|
2862
|
+
if (file2.path === m.document !== (file2.mime === "application/json"))
|
|
2863
|
+
issue("Only the editable document may contain JSON.");
|
|
2864
|
+
if (file2.path === m.source && (m.product !== "card" || !["image/svg+xml", "image/png", "image/jpeg", "image/webp"].includes(file2.mime)))
|
|
2865
|
+
issue("Original artwork must be a card SVG, PNG, JPEG or WebP.");
|
|
2866
|
+
if ([m.front, m.back].includes(file2.path) && file2.path !== m.source && file2.mime === "image/svg+xml")
|
|
2867
|
+
issue("Use raster previews for layered documents.");
|
|
2868
|
+
}
|
|
2869
|
+
});
|
|
2870
|
+
var kitId = z32.string().regex(/^[a-z0-9][a-z0-9-]{0,39}$/);
|
|
2871
|
+
var kitManifestSchema = manifestBase.extend({
|
|
2872
|
+
product: z32.literal("kit"),
|
|
2873
|
+
files: z32.array(manifestBase.shape.files.element.extend({ path: archivePathSchema })).min(1).max(KIT_FILE_COUNT_LIMIT),
|
|
2874
|
+
items: z32.array(z32.object({ id: kitId, manifest: designManifestSchema }).strict()).min(1).max(24),
|
|
2875
|
+
sheets: z32.array(
|
|
2876
|
+
z32.object({
|
|
2877
|
+
id: kitId,
|
|
2878
|
+
document: pathSchema,
|
|
2879
|
+
preview: pathSchema,
|
|
2880
|
+
pdf: pathSchema.optional()
|
|
2881
|
+
}).strict()
|
|
2882
|
+
).max(4).default([])
|
|
2883
|
+
}).superRefine((m, ctx) => {
|
|
2884
|
+
const issue = (message) => ctx.addIssue({ code: "custom", message });
|
|
2885
|
+
if (m.document || m.source || m.back || m.portrait || m.artwork || m.finish)
|
|
2886
|
+
issue("A kit has a cover and member documents, not a single design.");
|
|
2887
|
+
if (Object.keys(m.assets).length) issue("Kit images belong to their member manifests.");
|
|
2888
|
+
if (new Set(m.items.map((item) => item.id)).size !== m.items.length)
|
|
2889
|
+
issue("Duplicate kit item IDs.");
|
|
2890
|
+
if (new Set(m.sheets.map((sheet) => sheet.id)).size !== m.sheets.length)
|
|
2891
|
+
issue("Duplicate kit sheet IDs.");
|
|
2892
|
+
const expected = /* @__PURE__ */ new Map([
|
|
2893
|
+
[m.front, { mime: "image/png" }]
|
|
2894
|
+
]);
|
|
2895
|
+
const add = (path, file2) => {
|
|
2896
|
+
if (expected.has(path)) issue(`Duplicate kit file: ${path}.`);
|
|
2897
|
+
expected.set(path, file2);
|
|
2898
|
+
};
|
|
2899
|
+
for (const item of m.items)
|
|
2900
|
+
for (const file2 of item.manifest.files) add(`items/${item.id}/${file2.path}`, file2);
|
|
2901
|
+
for (const sheet of m.sheets) {
|
|
2902
|
+
add(sheet.document, { mime: "application/json" });
|
|
2903
|
+
add(sheet.preview, { mime: "image/png" });
|
|
2904
|
+
if (sheet.pdf) add(sheet.pdf, { mime: "application/pdf" });
|
|
2905
|
+
}
|
|
2906
|
+
if (expected.has("manifest.json")) issue("manifest.json is reserved.");
|
|
2907
|
+
if (new Set(m.files.map((file2) => file2.path)).size !== m.files.length || m.files.length !== expected.size)
|
|
2908
|
+
issue("The kit file list must contain exactly its cover, members and sheets.");
|
|
2909
|
+
if (m.files.reduce((sum, file2) => sum + file2.bytes, 0) > PACKAGE_LIMIT)
|
|
2910
|
+
issue("The package exceeds 24 MB.");
|
|
2911
|
+
for (const file2 of m.files) {
|
|
2912
|
+
const wanted = expected.get(file2.path);
|
|
2913
|
+
if (!wanted || wanted.mime !== file2.mime || wanted.bytes !== void 0 && wanted.bytes !== file2.bytes || wanted.sha256 !== void 0 && wanted.sha256 !== file2.sha256)
|
|
2914
|
+
issue(`Kit member metadata does not match: ${file2.path}.`);
|
|
2915
|
+
if (file2.mime === "application/pdf" && !file2.path.endsWith(".pdf"))
|
|
2916
|
+
issue("Print PDFs must use .pdf paths.");
|
|
2917
|
+
}
|
|
2918
|
+
for (const path of expected.keys())
|
|
2919
|
+
if (!m.files.some((file2) => file2.path === path)) issue(`Missing kit file: ${path}.`);
|
|
2920
|
+
});
|
|
2921
|
+
var BRAND_FILE_COUNT_LIMIT = 12;
|
|
2922
|
+
var brandManifestSchema = manifestBase.extend({
|
|
2923
|
+
product: z32.literal("brand"),
|
|
2924
|
+
slug: brandSlugSchema,
|
|
2925
|
+
document: z32.literal("brand.json"),
|
|
2926
|
+
front: z32.literal("cover.png"),
|
|
2927
|
+
files: manifestBase.shape.files.max(BRAND_FILE_COUNT_LIMIT),
|
|
2928
|
+
kits: z32.array(z32.string().uuid()).min(1).max(12)
|
|
2929
|
+
}).superRefine((m, ctx) => {
|
|
2930
|
+
const issue = (message) => ctx.addIssue({ code: "custom", message });
|
|
2931
|
+
if (m.source || m.back || m.portrait || m.artwork || m.finish || Object.keys(m.assets).length)
|
|
2932
|
+
issue("A brand has a cover, its brand.json and identity files.");
|
|
2933
|
+
if (new Set(m.kits).size !== m.kits.length) issue("Duplicate brand kits.");
|
|
2934
|
+
const paths = new Set(m.files.map((file2) => file2.path));
|
|
2935
|
+
if (paths.size !== m.files.length) issue("Duplicate brand files.");
|
|
2936
|
+
if (!paths.has("brand.json") || !paths.has("cover.png"))
|
|
2937
|
+
issue("Include brand.json and cover.png.");
|
|
2938
|
+
for (const file2 of m.files) {
|
|
2939
|
+
if (file2.path === "brand.json" ? file2.mime !== "application/json" : !["image/png", "image/webp", "image/jpeg"].includes(file2.mime))
|
|
2940
|
+
issue(`Unexpected brand file: ${file2.path}.`);
|
|
2941
|
+
if (file2.path !== "brand.json" && file2.path !== "cover.png" && !file2.path.startsWith("identity/"))
|
|
2942
|
+
issue(`Brand files live under identity/: ${file2.path}.`);
|
|
2943
|
+
}
|
|
2944
|
+
if (m.files.reduce((sum, file2) => sum + file2.bytes, 0) > PACKAGE_LIMIT)
|
|
2945
|
+
issue("The package exceeds 24 MB.");
|
|
2946
|
+
});
|
|
2947
|
+
var manifestSchema = z32.union([
|
|
2948
|
+
designManifestSchema,
|
|
2949
|
+
kitManifestSchema,
|
|
2950
|
+
brandManifestSchema
|
|
2951
|
+
]);
|
|
2952
|
+
var documentSchema = z32.object({ design: badgeDesignSchema, participant: communityParticipantSchema.optional() }).strict();
|
|
2953
|
+
var encoder = new TextEncoder();
|
|
2954
|
+
var jsonBytes = (value) => encoder.encode(canonicalJson(value));
|
|
2955
|
+
var parseJson = (bytes) => JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
2956
|
+
var hashBytes = (bytes) => communityDigest(new Blob([new Uint8Array(bytes)]));
|
|
2957
|
+
function requiredAssets(design) {
|
|
2958
|
+
const layers = [...design.front.layers, ...design.back.layers];
|
|
2959
|
+
return {
|
|
2960
|
+
portrait: layers.some((l) => l.kind === "portrait"),
|
|
2961
|
+
artwork: Boolean(design.artwork) || layers.some((l) => l.kind === "image" && l.asset === "art"),
|
|
2962
|
+
assets: [
|
|
2963
|
+
...referencedDesignAssets(design).filter(
|
|
2964
|
+
(id3) => id3 !== "art" && design.assets?.[id3]?.source !== "image"
|
|
2965
|
+
)
|
|
2966
|
+
]
|
|
2967
|
+
};
|
|
2968
|
+
}
|
|
2969
|
+
function missingAssets(draft) {
|
|
2970
|
+
const required = requiredAssets(draft.design);
|
|
2971
|
+
return [
|
|
2972
|
+
...required.portrait && !draft.portrait ? ["portrait"] : [],
|
|
2973
|
+
...required.artwork && !draft.artwork ? ["artwork"] : [],
|
|
2974
|
+
...required.assets.filter((id3) => !draft.assets[id3])
|
|
2975
|
+
];
|
|
2976
|
+
}
|
|
2977
|
+
async function importDraft(value) {
|
|
2978
|
+
if (value && typeof value === "object" && "format" in value && value.format === "makeables-bundle") {
|
|
2979
|
+
const { bundle } = await validateBadgeBundle(value);
|
|
2980
|
+
const draft = {
|
|
2981
|
+
design: bundle.snapshot.design,
|
|
2982
|
+
participant: bundle.snapshot.participant,
|
|
2983
|
+
files: {},
|
|
2984
|
+
mime: {},
|
|
2985
|
+
assets: {}
|
|
2986
|
+
};
|
|
2987
|
+
for (const slot of ["portrait", "artwork"]) {
|
|
2988
|
+
const image2 = bundle.images[slot];
|
|
2989
|
+
if (!image2) continue;
|
|
2990
|
+
const path = `${slot}.${image2.mimeType.split("/")[1]}`;
|
|
2991
|
+
draft[slot] = path;
|
|
2992
|
+
draft.files[path] = bundleImageBytes(image2);
|
|
2993
|
+
draft.mime[path] = image2.mimeType;
|
|
2994
|
+
}
|
|
2995
|
+
return draft;
|
|
2996
|
+
}
|
|
2997
|
+
const document = documentSchema.parse(
|
|
2998
|
+
value && typeof value === "object" && "design" in value ? value : { design: value }
|
|
2999
|
+
);
|
|
3000
|
+
return { ...document, files: {}, mime: {}, assets: {} };
|
|
3001
|
+
}
|
|
3002
|
+
async function assemblePackage(input, files, mime) {
|
|
3003
|
+
const manifest = manifestSchema.parse({
|
|
3004
|
+
...input,
|
|
3005
|
+
format: "makeables-package",
|
|
3006
|
+
version: 1,
|
|
3007
|
+
files: await Promise.all(
|
|
3008
|
+
Object.entries(files).map(async ([path, bytes]) => ({
|
|
3009
|
+
path,
|
|
3010
|
+
mime: mime[path],
|
|
3011
|
+
bytes: bytes.length,
|
|
3012
|
+
sha256: await hashBytes(bytes)
|
|
3013
|
+
}))
|
|
3014
|
+
)
|
|
3015
|
+
});
|
|
3016
|
+
const result = { manifest, files };
|
|
3017
|
+
await validatePackage(result);
|
|
3018
|
+
return result;
|
|
3019
|
+
}
|
|
3020
|
+
async function draftPackage(draft, previews) {
|
|
3021
|
+
const product = draft.design.product ?? "badge";
|
|
3022
|
+
if (!printProductIds.includes(product))
|
|
3023
|
+
throw new Error("Digital formats are exported as images, not submitted.");
|
|
3024
|
+
const sticker = product === "sticker";
|
|
3025
|
+
if (!sticker && !previews.back) throw new Error("Include previews of both faces.");
|
|
3026
|
+
const missing = missingAssets(draft);
|
|
3027
|
+
if (missing.length) throw new Error(`Add the missing images: ${missing.join(", ")}.`);
|
|
3028
|
+
return assemblePackage(
|
|
3029
|
+
{
|
|
3030
|
+
product,
|
|
3031
|
+
...sticker ? { finish: draft.design.sticker?.finish ?? defaultStickerMaterial.finish } : {},
|
|
3032
|
+
title: draft.design.name,
|
|
3033
|
+
document: "design.json",
|
|
3034
|
+
front: "front.png",
|
|
3035
|
+
...sticker ? {} : { back: "back.png" },
|
|
3036
|
+
portrait: draft.portrait,
|
|
3037
|
+
artwork: draft.artwork,
|
|
3038
|
+
assets: draft.assets
|
|
3039
|
+
},
|
|
3040
|
+
{
|
|
3041
|
+
...draft.files,
|
|
3042
|
+
"design.json": jsonBytes({
|
|
3043
|
+
design: draft.design,
|
|
3044
|
+
...!sticker && draft.participant ? { participant: draft.participant } : {}
|
|
3045
|
+
}),
|
|
3046
|
+
"front.png": previews.front,
|
|
3047
|
+
...!sticker && previews.back ? { "back.png": previews.back } : {}
|
|
3048
|
+
},
|
|
3049
|
+
{
|
|
3050
|
+
...draft.mime,
|
|
3051
|
+
"design.json": "application/json",
|
|
3052
|
+
"front.png": "image/png",
|
|
3053
|
+
...sticker ? {} : { "back.png": "image/png" }
|
|
3054
|
+
}
|
|
3055
|
+
);
|
|
3056
|
+
}
|
|
3057
|
+
async function svgPackage(bytes, title = "Untitled card") {
|
|
3058
|
+
const check = checkSubmittedSvg(new TextDecoder().decode(bytes));
|
|
3059
|
+
if (!check.ok) throw new Error(check.error);
|
|
3060
|
+
return assemblePackage(
|
|
3061
|
+
{ product: "card", title, source: "artwork.svg", front: "artwork.svg", assets: {} },
|
|
3062
|
+
{ "artwork.svg": bytes },
|
|
3063
|
+
{ "artwork.svg": "image/svg+xml" }
|
|
3064
|
+
);
|
|
3065
|
+
}
|
|
3066
|
+
async function rasterPackage(bytes, mime, title = "Untitled card") {
|
|
3067
|
+
const extension = mime === "image/jpeg" ? "jpg" : mime.split("/")[1];
|
|
3068
|
+
const path = `artwork.${extension}`;
|
|
3069
|
+
return assemblePackage(
|
|
3070
|
+
{ product: "card", title, source: path, front: path, assets: {} },
|
|
3071
|
+
{ [path]: bytes },
|
|
3072
|
+
{ [path]: mime }
|
|
3073
|
+
);
|
|
3074
|
+
}
|
|
3075
|
+
async function validatePackage(pkg) {
|
|
3076
|
+
const manifest = manifestSchema.parse(pkg.manifest);
|
|
3077
|
+
if (jsonBytes(manifest).length > MANIFEST_LIMIT)
|
|
3078
|
+
throw new Error("The package manifest exceeds 200 KB.");
|
|
3079
|
+
if (Object.keys(pkg.files).length !== manifest.files.length)
|
|
3080
|
+
throw new Error("The package file list does not match its manifest.");
|
|
3081
|
+
for (const file2 of manifest.files) {
|
|
3082
|
+
const bytes = pkg.files[file2.path];
|
|
3083
|
+
if (!bytes || bytes.length !== file2.bytes || await hashBytes(bytes) !== file2.sha256)
|
|
3084
|
+
throw new Error(`Missing or changed asset: ${file2.path}.`);
|
|
3085
|
+
}
|
|
3086
|
+
if (manifest.product === "kit") {
|
|
3087
|
+
for (const item of manifest.items) await validatePackage(kitMemberPackage(pkg, item.id));
|
|
3088
|
+
for (const sheet of manifest.sheets) {
|
|
3089
|
+
const document = stickerSheetSchema.parse(parseJson(pkg.files[sheet.document]));
|
|
3090
|
+
if (!document.items.length) throw new Error("A kit sheet must contain stickers.");
|
|
3091
|
+
for (const item of document.items)
|
|
3092
|
+
if (requiredAssets(item.design).assets.length || requiredAssets(item.design).artwork)
|
|
3093
|
+
throw new Error("Kit sheets must embed their artwork.");
|
|
3094
|
+
if (sheet.pdf) {
|
|
3095
|
+
const text3 = new TextDecoder("latin1").decode(pkg.files[sheet.pdf]);
|
|
3096
|
+
if (!text3.startsWith("%PDF-") || !text3.trimEnd().endsWith("%%EOF"))
|
|
3097
|
+
throw new Error("Invalid print PDF.");
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
return manifest;
|
|
3101
|
+
}
|
|
3102
|
+
if (manifest.product === "brand") {
|
|
3103
|
+
const brand = brandPackageDocumentSchema.parse(parseJson(pkg.files["brand.json"]));
|
|
3104
|
+
const paths = new Set(manifest.files.map((file2) => file2.path));
|
|
3105
|
+
for (const path of [brand.cover, ...brand.logos.map((logo) => logo.file)])
|
|
3106
|
+
if (path && !paths.has(path)) throw new Error(`Missing brand file: ${path}.`);
|
|
3107
|
+
if (brand.slug !== manifest.slug) throw new Error("The brand slug and manifest do not match.");
|
|
3108
|
+
if (brand.kits.map((kit) => kit.submission).join() !== manifest.kits.join())
|
|
3109
|
+
throw new Error("The brand kits and manifest do not match.");
|
|
3110
|
+
return manifest;
|
|
3111
|
+
}
|
|
3112
|
+
for (const file2 of manifest.files.filter((f) => f.mime === "image/svg+xml")) {
|
|
3113
|
+
const check = checkSubmittedSvg(new TextDecoder().decode(pkg.files[file2.path]));
|
|
3114
|
+
if (!check.ok) throw new Error(check.error);
|
|
3115
|
+
}
|
|
3116
|
+
if (manifest.document) {
|
|
3117
|
+
const document = documentSchema.parse(parseJson(pkg.files[manifest.document]));
|
|
3118
|
+
if ((document.design.product ?? "badge") !== manifest.product)
|
|
3119
|
+
throw new Error("The document and product do not match.");
|
|
3120
|
+
if (manifest.product === "sticker" && manifest.finish !== (document.design.sticker?.finish ?? defaultStickerMaterial.finish))
|
|
3121
|
+
throw new Error("The sticker finish and document do not match.");
|
|
3122
|
+
if (manifest.product === "sticker" && document.participant)
|
|
3123
|
+
throw new Error("Sticker packages must not contain participant information.");
|
|
3124
|
+
const missing = missingAssets({ ...document, ...manifest, files: pkg.files, mime: {} });
|
|
3125
|
+
if (missing.length) throw new Error(`Missing images: ${missing.join(", ")}.`);
|
|
3126
|
+
if (requiredAssets(document.design).portrait && !document.participant)
|
|
3127
|
+
throw new Error(
|
|
3128
|
+
"Include participant details with a personalized badge. Export a package from the editor."
|
|
3129
|
+
);
|
|
3130
|
+
}
|
|
3131
|
+
return manifest;
|
|
3132
|
+
}
|
|
3133
|
+
function checkArchive(bytes) {
|
|
3134
|
+
if (bytes.length > PACKAGE_LIMIT + MANIFEST_LIMIT) throw new Error("The ZIP exceeds 24 MB.");
|
|
3135
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
3136
|
+
if (bytes.length < 22) throw new Error("Invalid ZIP archive.");
|
|
3137
|
+
let end = bytes.length - 22;
|
|
3138
|
+
while (end >= Math.max(0, bytes.length - 65557) && view.getUint32(end, true) !== 101010256)
|
|
3139
|
+
end--;
|
|
3140
|
+
if (end < 0 || end < bytes.length - 65557) throw new Error("Invalid ZIP directory.");
|
|
3141
|
+
const count = view.getUint16(end + 10, true);
|
|
3142
|
+
if (count > KIT_FILE_COUNT_LIMIT + 1 || view.getUint16(end + 4, true) || view.getUint16(end + 6, true))
|
|
3143
|
+
throw new Error("Unsupported ZIP archive.");
|
|
3144
|
+
let offset = view.getUint32(end + 16, true), total = 0;
|
|
3145
|
+
const names = /* @__PURE__ */ new Set();
|
|
3146
|
+
for (let index = 0; index < count; index++) {
|
|
3147
|
+
if (offset + 46 > end || view.getUint32(offset, true) !== 33639248)
|
|
3148
|
+
throw new Error("Invalid ZIP entry.");
|
|
3149
|
+
const flags = view.getUint16(offset + 8, true), size = view.getUint32(offset + 24, true), length = view.getUint16(offset + 28, true);
|
|
3150
|
+
const name = new TextDecoder().decode(bytes.subarray(offset + 46, offset + 46 + length));
|
|
3151
|
+
if (flags & 1 || names.has(name) || name !== "manifest.json" && !archivePathSchema.safeParse(name).success || size > (name === "manifest.json" ? MANIFEST_LIMIT : FILE_LIMIT))
|
|
3152
|
+
throw new Error("Unsafe, duplicate or oversized ZIP entry.");
|
|
3153
|
+
total += size;
|
|
3154
|
+
if (total > PACKAGE_LIMIT + MANIFEST_LIMIT) throw new Error("The expanded ZIP exceeds 24 MB.");
|
|
3155
|
+
names.add(name);
|
|
3156
|
+
offset += 46 + length + view.getUint16(offset + 30, true) + view.getUint16(offset + 32, true);
|
|
3157
|
+
}
|
|
3158
|
+
if (offset !== end || !names.has("manifest.json"))
|
|
3159
|
+
throw new Error("Use a Makeables ZIP with manifest.json at its root.");
|
|
3160
|
+
return names;
|
|
3161
|
+
}
|
|
3162
|
+
async function readPackageZip(bytes) {
|
|
3163
|
+
const names = checkArchive(bytes);
|
|
3164
|
+
const files = {};
|
|
3165
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3166
|
+
let total = 0;
|
|
3167
|
+
const archive = new Unzip((file2) => {
|
|
3168
|
+
if (!names.has(file2.name) || seen.has(file2.name) || (file2.originalSize ?? 0) > FILE_LIMIT)
|
|
3169
|
+
throw new Error("Invalid ZIP entry.");
|
|
3170
|
+
seen.add(file2.name);
|
|
3171
|
+
const chunks = [];
|
|
3172
|
+
let size = 0;
|
|
3173
|
+
file2.ondata = (error, chunk, final) => {
|
|
3174
|
+
if (error) throw error;
|
|
3175
|
+
size += chunk.length;
|
|
3176
|
+
total += chunk.length;
|
|
3177
|
+
if (size > (file2.name === "manifest.json" ? MANIFEST_LIMIT : FILE_LIMIT) || total > PACKAGE_LIMIT + MANIFEST_LIMIT) {
|
|
3178
|
+
file2.terminate();
|
|
3179
|
+
throw new Error("The expanded ZIP exceeds its size limit.");
|
|
3180
|
+
}
|
|
3181
|
+
chunks.push(chunk);
|
|
3182
|
+
if (final) {
|
|
3183
|
+
const data = new Uint8Array(size);
|
|
3184
|
+
let offset = 0;
|
|
3185
|
+
for (const part of chunks) {
|
|
3186
|
+
data.set(part, offset);
|
|
3187
|
+
offset += part.length;
|
|
3188
|
+
}
|
|
3189
|
+
files[file2.name] = data;
|
|
3190
|
+
}
|
|
3191
|
+
};
|
|
3192
|
+
file2.start();
|
|
3193
|
+
});
|
|
3194
|
+
archive.register(UnzipInflate);
|
|
3195
|
+
for (let offset = 0; offset < bytes.length; offset += 1024)
|
|
3196
|
+
archive.push(bytes.subarray(offset, offset + 1024), offset + 1024 >= bytes.length);
|
|
3197
|
+
if (Object.keys(files).length !== names.size) throw new Error("Incomplete ZIP archive.");
|
|
3198
|
+
const manifest = manifestSchema.parse(parseJson(files["manifest.json"]));
|
|
3199
|
+
delete files["manifest.json"];
|
|
3200
|
+
const pkg = { manifest, files };
|
|
3201
|
+
await validatePackage(pkg);
|
|
3202
|
+
return pkg;
|
|
3203
|
+
}
|
|
3204
|
+
async function packageZip(pkg) {
|
|
3205
|
+
await validatePackage(pkg);
|
|
3206
|
+
return zipSync({ "manifest.json": jsonBytes(pkg.manifest), ...pkg.files }, { level: 0 });
|
|
3207
|
+
}
|
|
3208
|
+
function draftFromPackage(pkg) {
|
|
3209
|
+
if (pkg.manifest.product === "brand") throw new Error("A brand package has no single design.");
|
|
3210
|
+
if (pkg.manifest.product === "kit")
|
|
3211
|
+
throw new Error("Choose a kit member before opening its design.");
|
|
3212
|
+
if (!pkg.manifest.document)
|
|
3213
|
+
throw new Error("This package contains an original SVG, not a layered document.");
|
|
3214
|
+
const doc = documentSchema.parse(parseJson(pkg.files[pkg.manifest.document]));
|
|
3215
|
+
const paths = /* @__PURE__ */ new Set([
|
|
3216
|
+
pkg.manifest.portrait,
|
|
3217
|
+
pkg.manifest.artwork,
|
|
3218
|
+
...Object.values(pkg.manifest.assets)
|
|
3219
|
+
]);
|
|
3220
|
+
return {
|
|
3221
|
+
...doc,
|
|
3222
|
+
portrait: pkg.manifest.portrait,
|
|
3223
|
+
artwork: pkg.manifest.artwork,
|
|
3224
|
+
assets: pkg.manifest.assets,
|
|
3225
|
+
files: Object.fromEntries(Object.entries(pkg.files).filter(([path]) => paths.has(path))),
|
|
3226
|
+
mime: Object.fromEntries(
|
|
3227
|
+
pkg.manifest.files.filter((f) => paths.has(f.path)).map((f) => [f.path, f.mime])
|
|
3228
|
+
)
|
|
3229
|
+
};
|
|
3230
|
+
}
|
|
3231
|
+
function productOf(pkg) {
|
|
3232
|
+
return pkg.manifest.product;
|
|
3233
|
+
}
|
|
3234
|
+
function packageJson(pkg) {
|
|
3235
|
+
return {
|
|
3236
|
+
format: "makeables-package",
|
|
3237
|
+
version: 1,
|
|
3238
|
+
manifest: pkg.manifest,
|
|
3239
|
+
files: Object.fromEntries(
|
|
3240
|
+
Object.entries(pkg.files).map(([path, bytes]) => {
|
|
3241
|
+
let binary = "";
|
|
3242
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
3243
|
+
return [path, btoa(binary)];
|
|
3244
|
+
})
|
|
3245
|
+
)
|
|
3246
|
+
};
|
|
3247
|
+
}
|
|
3248
|
+
async function readPackageJson(value) {
|
|
3249
|
+
const input = z32.object({
|
|
3250
|
+
format: z32.literal("makeables-package"),
|
|
3251
|
+
version: z32.literal(1),
|
|
3252
|
+
manifest: manifestSchema,
|
|
3253
|
+
files: z32.record(
|
|
3254
|
+
archivePathSchema,
|
|
3255
|
+
z32.string().max(Math.ceil(FILE_LIMIT / 3) * 4).regex(/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/)
|
|
3256
|
+
)
|
|
3257
|
+
}).strict().parse(value);
|
|
3258
|
+
if (Object.keys(input.files).length !== input.manifest.files.length)
|
|
3259
|
+
throw new Error("The package file list does not match its manifest.");
|
|
3260
|
+
for (const file2 of input.manifest.files) {
|
|
3261
|
+
const encoded = input.files[file2.path];
|
|
3262
|
+
const length = encoded ? encoded.length / 4 * 3 - (encoded.endsWith("==") ? 2 : encoded.endsWith("=") ? 1 : 0) : 0;
|
|
3263
|
+
if (length !== file2.bytes) throw new Error(`Missing or changed asset: ${file2.path}.`);
|
|
3264
|
+
}
|
|
3265
|
+
const files = Object.fromEntries(
|
|
3266
|
+
Object.entries(input.files).map(([path, base64]) => [
|
|
3267
|
+
path,
|
|
3268
|
+
Uint8Array.from(atob(base64), (c) => c.charCodeAt(0))
|
|
3269
|
+
])
|
|
3270
|
+
);
|
|
3271
|
+
const pkg = { manifest: input.manifest, files };
|
|
3272
|
+
await validatePackage(pkg);
|
|
3273
|
+
return pkg;
|
|
3274
|
+
}
|
|
3275
|
+
function kitMemberPackage(pkg, id3) {
|
|
3276
|
+
if (pkg.manifest.product !== "kit") throw new Error("This package is not a kit.");
|
|
3277
|
+
const item = pkg.manifest.items.find((item2) => item2.id === id3);
|
|
3278
|
+
if (!item) throw new Error("Unknown kit piece.");
|
|
3279
|
+
return {
|
|
3280
|
+
manifest: item.manifest,
|
|
3281
|
+
files: Object.fromEntries(
|
|
3282
|
+
item.manifest.files.map((file2) => [file2.path, pkg.files[`items/${id3}/${file2.path}`]])
|
|
3283
|
+
)
|
|
3284
|
+
};
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
export {
|
|
3288
|
+
__commonJS,
|
|
3289
|
+
__toESM,
|
|
3290
|
+
checkSubmittedSvg,
|
|
3291
|
+
cardMarkSvg,
|
|
3292
|
+
designProfile,
|
|
3293
|
+
stickerMaterialSchema,
|
|
3294
|
+
defaultStickerMaterial,
|
|
3295
|
+
svgNodeSchema,
|
|
3296
|
+
svgNodeXml,
|
|
3297
|
+
badgeLayerSchema,
|
|
3298
|
+
badgeDesignObjectSchema,
|
|
3299
|
+
badgeDesignSchema,
|
|
3300
|
+
preserveDesignLocks,
|
|
3301
|
+
pruneAssets,
|
|
3302
|
+
addSticker,
|
|
3303
|
+
cardMarkLayer,
|
|
3304
|
+
createCardDesign,
|
|
3305
|
+
sheetSizes,
|
|
3306
|
+
sheetTypes,
|
|
3307
|
+
sheetTypeIds,
|
|
3308
|
+
stickerSheetSchema,
|
|
3309
|
+
sheetSpec,
|
|
3310
|
+
createStickerSheet,
|
|
3311
|
+
sheetBorderPixels,
|
|
3312
|
+
badgeQrLayout,
|
|
3313
|
+
communityParticipantSchema,
|
|
3314
|
+
strToU8,
|
|
3315
|
+
zipSync,
|
|
3316
|
+
brandSlugSchema,
|
|
3317
|
+
brandLayouts,
|
|
3318
|
+
brandDocumentSchema,
|
|
3319
|
+
brandPackageDocumentSchema,
|
|
3320
|
+
kitDocumentSchema,
|
|
3321
|
+
FILE_LIMIT,
|
|
3322
|
+
PACKAGE_LIMIT,
|
|
3323
|
+
FILE_COUNT_LIMIT,
|
|
3324
|
+
KIT_FILE_COUNT_LIMIT,
|
|
3325
|
+
MANIFEST_LIMIT,
|
|
3326
|
+
providers,
|
|
3327
|
+
submissionMetadataSchema,
|
|
3328
|
+
designManifestSchema,
|
|
3329
|
+
kitManifestSchema,
|
|
3330
|
+
BRAND_FILE_COUNT_LIMIT,
|
|
3331
|
+
brandManifestSchema,
|
|
3332
|
+
manifestSchema,
|
|
3333
|
+
documentSchema,
|
|
3334
|
+
jsonBytes,
|
|
3335
|
+
parseJson,
|
|
3336
|
+
hashBytes,
|
|
3337
|
+
requiredAssets,
|
|
3338
|
+
missingAssets,
|
|
3339
|
+
importDraft,
|
|
3340
|
+
assemblePackage,
|
|
3341
|
+
draftPackage,
|
|
3342
|
+
svgPackage,
|
|
3343
|
+
rasterPackage,
|
|
3344
|
+
validatePackage,
|
|
3345
|
+
readPackageZip,
|
|
3346
|
+
packageZip,
|
|
3347
|
+
draftFromPackage,
|
|
3348
|
+
productOf,
|
|
3349
|
+
packageJson,
|
|
3350
|
+
readPackageJson,
|
|
3351
|
+
kitMemberPackage
|
|
3352
|
+
};
|