@tileflow/core 0.1.0-alpha.20 → 0.1.0-alpha.22
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/GENERATED_OUTPUT_LICENSE.md +21 -0
- package/LICENSE +201 -0
- package/NOTICE +9 -0
- package/README.md +1097 -145
- package/THIRD_PARTY_NOTICES.md +243 -0
- package/TRADEMARKS.md +10 -0
- package/dist/browser.d.ts +182 -13
- package/dist/browser.js +4207 -116
- package/dist/build.d.ts +158 -0
- package/dist/build.js +14836 -0
- package/dist/capture-scene-BK_0J2oR.d.ts +161 -0
- package/dist/capture.d.ts +9 -0
- package/dist/capture.js +206 -0
- package/dist/config-reference.json +31882 -0
- package/dist/index.d.ts +643 -182
- package/dist/index.js +15943 -4352
- package/dist/manifest-B5GKVMFE.d.ts +757 -0
- package/dist/manifest.d.ts +2 -0
- package/dist/manifest.js +245 -0
- package/dist/map-BHL_0Mkx.d.ts +1145 -0
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.js +1172 -0
- package/package.json +37 -5
- package/dist/runtime-DroKDIuB.d.ts +0 -1069
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import 'zod';
|
|
2
|
+
export { aw as TileflowRuntimeColorScheme, T as TileflowRuntimeManifest, ay as TileflowRuntimeManifestMapEntry, az as TileflowRuntimeManifestTheme, aE as TileflowRuntimeSystemThemes, bv as parseTileflowRuntimeManifest, bD as safeParseTileflowRuntimeManifest, bH as tileflowRuntimeManifestLimits, bI as tileflowRuntimeManifestSchema, bJ as tileflowRuntimeManifestVersion } from './manifest-B5GKVMFE.js';
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
// src/manifest.ts
|
|
2
|
+
import { z as z2 } from "zod";
|
|
3
|
+
|
|
4
|
+
// src/portable-identity.ts
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
// src/portable-identity-rules.ts
|
|
8
|
+
var tileflowPortableIdMaximumLength = 64;
|
|
9
|
+
var tileflowPortableIdPattern = /^[a-z][a-z0-9-]{0,63}$/u;
|
|
10
|
+
function isTileflowPortableId(value) {
|
|
11
|
+
return typeof value === "string" && value.length <= tileflowPortableIdMaximumLength && tileflowPortableIdPattern.test(value) && !["constructor", "prototype"].includes(value) && !/^(?:AUX|CON|NUL|PRN|COM[1-9]|LPT[1-9])$/i.test(value);
|
|
12
|
+
}
|
|
13
|
+
function isTileflowThemeName(value) {
|
|
14
|
+
return isTileflowPortableId(value) && value !== "system";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/portable-identity.ts
|
|
18
|
+
var tileflowPortableIdSchema = z.string().min(1).max(tileflowPortableIdMaximumLength).regex(tileflowPortableIdPattern, {
|
|
19
|
+
message: "Expected lowercase kebab-case beginning with a letter"
|
|
20
|
+
}).refine(
|
|
21
|
+
(name) => !["constructor", "prototype"].includes(name) && !/^(?:AUX|CON|NUL|PRN|COM[1-9]|LPT[1-9])$/i.test(name),
|
|
22
|
+
"Expected a portable identifier that is not a reserved filename or prototype key"
|
|
23
|
+
);
|
|
24
|
+
var tileflowThemeNameSchema = tileflowPortableIdSchema.refine(
|
|
25
|
+
isTileflowThemeName,
|
|
26
|
+
"Expected a concrete theme name; system is browser-only"
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// src/themes/model.ts
|
|
30
|
+
var tileflowThemeLimits = Object.freeze({ maxThemes: 64 });
|
|
31
|
+
var themeTypographyStyleKeys = ["fallbacks", "font", "letterSpacing", "transform"];
|
|
32
|
+
var themeTypographyKeys = [
|
|
33
|
+
...themeTypographyStyleKeys,
|
|
34
|
+
"places",
|
|
35
|
+
"poi",
|
|
36
|
+
"roads",
|
|
37
|
+
"water"
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
// src/manifest.ts
|
|
41
|
+
var tileflowRuntimeManifestVersion = 1;
|
|
42
|
+
var tileflowRuntimeManifestLimits = Object.freeze({ maximumBytes: 1024 * 1024 });
|
|
43
|
+
var safeTextSchema = z2.string().min(1).max(2048).refine((value) => value === value.trim(), "Expected text without surrounding whitespace").refine((value) => !/[\p{Cc}\\]/u.test(value), "Expected safe text");
|
|
44
|
+
var publicResourceUrlSchema = safeTextSchema.refine(isPublicResourceUrl, {
|
|
45
|
+
message: "Expected an HTTP(S), root-relative, or path-relative public URL"
|
|
46
|
+
});
|
|
47
|
+
var apiOriginSchema = safeTextSchema.refine(isApiOrigin, {
|
|
48
|
+
message: "Expected an absolute HTTP(S) origin without path, credentials, query, or fragment"
|
|
49
|
+
});
|
|
50
|
+
var viewSchema = z2.object({
|
|
51
|
+
bearing: z2.number().finite().min(-180).max(180).optional(),
|
|
52
|
+
center: z2.tuple([z2.number().finite().min(-180).max(180), z2.number().finite().min(-90).max(90)]).optional(),
|
|
53
|
+
pitch: z2.number().finite().min(0).max(85).optional(),
|
|
54
|
+
zoom: z2.number().finite().min(0).max(24).optional()
|
|
55
|
+
}).strict();
|
|
56
|
+
var fontFaceSchema = z2.object({
|
|
57
|
+
family: safeTextSchema.max(100),
|
|
58
|
+
source: publicResourceUrlSchema,
|
|
59
|
+
style: z2.enum(["italic", "normal", "oblique"]).optional(),
|
|
60
|
+
weight: z2.enum(["100", "200", "300", "400", "500", "600", "700", "800", "900"]).optional()
|
|
61
|
+
}).strict();
|
|
62
|
+
var fontFacesSchema = z2.array(fontFaceSchema).max(16).superRefine(validateUniqueFontFaces);
|
|
63
|
+
var manifestThemeSchema = z2.object({
|
|
64
|
+
colorScheme: z2.enum(["dark", "light"]),
|
|
65
|
+
fontFaces: fontFacesSchema.optional(),
|
|
66
|
+
revision: safeTextSchema.max(128).optional(),
|
|
67
|
+
styleId: safeTextSchema.max(128).optional(),
|
|
68
|
+
styleUrl: publicResourceUrlSchema
|
|
69
|
+
}).strict();
|
|
70
|
+
var manifestMapSchema = z2.object({
|
|
71
|
+
apiUrl: apiOriginSchema.optional(),
|
|
72
|
+
defaultTheme: tileflowThemeNameSchema,
|
|
73
|
+
environment: safeTextSchema.max(128).optional(),
|
|
74
|
+
mapId: safeTextSchema.max(128).optional(),
|
|
75
|
+
systemThemes: z2.object({ dark: tileflowThemeNameSchema, light: tileflowThemeNameSchema }).strict().optional(),
|
|
76
|
+
themes: z2.record(tileflowThemeNameSchema, manifestThemeSchema),
|
|
77
|
+
usageMode: z2.literal("session").optional(),
|
|
78
|
+
view: viewSchema.optional(),
|
|
79
|
+
worldGeneration: z2.literal("v1").optional()
|
|
80
|
+
}).strict().superRefine((entry, context) => {
|
|
81
|
+
const names = Object.keys(entry.themes);
|
|
82
|
+
if (names.length === 0) {
|
|
83
|
+
context.addIssue({ code: "custom", message: "Expected at least one theme", path: ["themes"] });
|
|
84
|
+
}
|
|
85
|
+
if (names.length > tileflowThemeLimits.maxThemes) {
|
|
86
|
+
context.addIssue({
|
|
87
|
+
code: "too_big",
|
|
88
|
+
maximum: tileflowThemeLimits.maxThemes,
|
|
89
|
+
origin: "object",
|
|
90
|
+
path: ["themes"]
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (!Object.hasOwn(entry.themes, entry.defaultTheme)) {
|
|
94
|
+
context.addIssue({
|
|
95
|
+
code: "custom",
|
|
96
|
+
message: "defaultTheme must name a declared theme",
|
|
97
|
+
path: ["defaultTheme"]
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (entry.systemThemes) {
|
|
101
|
+
for (const colorScheme of ["light", "dark"]) {
|
|
102
|
+
const name = entry.systemThemes[colorScheme];
|
|
103
|
+
const theme = entry.themes[name];
|
|
104
|
+
if (!theme) {
|
|
105
|
+
context.addIssue({
|
|
106
|
+
code: "custom",
|
|
107
|
+
message: `systemThemes.${colorScheme} must name a declared theme`,
|
|
108
|
+
path: ["systemThemes", colorScheme]
|
|
109
|
+
});
|
|
110
|
+
} else if (theme.colorScheme !== colorScheme) {
|
|
111
|
+
context.addIssue({
|
|
112
|
+
code: "custom",
|
|
113
|
+
message: `systemThemes.${colorScheme} must reference a ${colorScheme} theme`,
|
|
114
|
+
path: ["systemThemes", colorScheme]
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (entry.usageMode === void 0 !== (entry.worldGeneration === void 0)) {
|
|
120
|
+
context.addIssue({
|
|
121
|
+
code: "custom",
|
|
122
|
+
message: "usageMode and worldGeneration must be declared together"
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
var canonicalManifestSchema = z2.object({
|
|
127
|
+
apiUrl: apiOriginSchema.optional(),
|
|
128
|
+
maps: z2.record(tileflowPortableIdSchema, manifestMapSchema),
|
|
129
|
+
version: z2.literal(tileflowRuntimeManifestVersion)
|
|
130
|
+
}).strict().superRefine((manifest, context) => {
|
|
131
|
+
const mapCount = Object.keys(manifest.maps).length;
|
|
132
|
+
if (mapCount === 0) {
|
|
133
|
+
context.addIssue({ code: "custom", message: "Expected at least one map", path: ["maps"] });
|
|
134
|
+
}
|
|
135
|
+
if (mapCount > 1e3) {
|
|
136
|
+
context.addIssue({ code: "too_big", maximum: 1e3, origin: "object", path: ["maps"] });
|
|
137
|
+
}
|
|
138
|
+
if (new TextEncoder().encode(JSON.stringify(manifest)).byteLength > tileflowRuntimeManifestLimits.maximumBytes) {
|
|
139
|
+
context.addIssue({
|
|
140
|
+
code: "too_big",
|
|
141
|
+
maximum: tileflowRuntimeManifestLimits.maximumBytes,
|
|
142
|
+
origin: "string",
|
|
143
|
+
message: "Manifest JSON exceeds the 1 MiB limit"
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
var safeManifestInputSchema = z2.unknown().superRefine((input, context) => {
|
|
148
|
+
const unsafe = findUnsafeManifestStructure(input);
|
|
149
|
+
if (unsafe) {
|
|
150
|
+
context.addIssue({
|
|
151
|
+
code: "custom",
|
|
152
|
+
message: unsafe.reason === "prototype" ? "Expected plain manifest objects" : "Expected no prototype-mutating keys",
|
|
153
|
+
path: unsafe.path
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
var tileflowRuntimeManifestSchema = safeManifestInputSchema.pipe(canonicalManifestSchema);
|
|
158
|
+
function parseTileflowRuntimeManifest(input) {
|
|
159
|
+
return tileflowRuntimeManifestSchema.parse(input);
|
|
160
|
+
}
|
|
161
|
+
function safeParseTileflowRuntimeManifest(input) {
|
|
162
|
+
return tileflowRuntimeManifestSchema.safeParse(input);
|
|
163
|
+
}
|
|
164
|
+
function validateUniqueFontFaces(fontFaces, context) {
|
|
165
|
+
const seen = /* @__PURE__ */ new Map();
|
|
166
|
+
for (const [index, fontFace] of fontFaces.entries()) {
|
|
167
|
+
const identity = `${fontFace.family}\0${fontFace.style ?? "normal"}\0${fontFace.weight ?? "400"}`;
|
|
168
|
+
const first = seen.get(identity);
|
|
169
|
+
if (first !== void 0) {
|
|
170
|
+
context.addIssue({
|
|
171
|
+
code: "custom",
|
|
172
|
+
message: `Duplicate font face identity; first declared at index ${first}`,
|
|
173
|
+
path: [index]
|
|
174
|
+
});
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
seen.set(identity, index);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function isPublicResourceUrl(value) {
|
|
181
|
+
if (value.startsWith("//")) return false;
|
|
182
|
+
if (!value.startsWith("/") && !value.startsWith("./") && !value.startsWith("../") && !isAbsolutePublicUrl(value)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
return isSafeResolvedPublicUrl(value);
|
|
186
|
+
}
|
|
187
|
+
function isAbsolutePublicUrl(value) {
|
|
188
|
+
try {
|
|
189
|
+
const url = new URL(value);
|
|
190
|
+
return (url.protocol === "http:" || url.protocol === "https:") && !url.username && !url.password && !url.hash && !hasEncodedPathSeparator(value);
|
|
191
|
+
} catch {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function isSafeResolvedPublicUrl(value) {
|
|
196
|
+
try {
|
|
197
|
+
const url = new URL(value, "https://manifest.invalid/owner/manifest.json");
|
|
198
|
+
return (url.protocol === "http:" || url.protocol === "https:") && !url.username && !url.password && !url.hash && !hasEncodedPathSeparator(value);
|
|
199
|
+
} catch {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function hasEncodedPathSeparator(value) {
|
|
204
|
+
return /%(?:2f|5c)/iu.test(value);
|
|
205
|
+
}
|
|
206
|
+
function isApiOrigin(value) {
|
|
207
|
+
try {
|
|
208
|
+
const url = new URL(value);
|
|
209
|
+
return isAbsolutePublicUrl(value) && url.pathname === "/" && !url.search && value.replace(/\/$/u, "") === url.origin;
|
|
210
|
+
} catch {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function findUnsafeManifestStructure(input) {
|
|
215
|
+
if (!input || typeof input !== "object") return void 0;
|
|
216
|
+
const pending = [{ path: [], value: input }];
|
|
217
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
218
|
+
while (pending.length > 0) {
|
|
219
|
+
const current = pending.pop();
|
|
220
|
+
if (visited.has(current.value)) continue;
|
|
221
|
+
visited.add(current.value);
|
|
222
|
+
if (!Array.isArray(current.value)) {
|
|
223
|
+
const prototype = Object.getPrototypeOf(current.value);
|
|
224
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
225
|
+
return { path: current.path, reason: "prototype" };
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
for (const key of Object.keys(current.value)) {
|
|
229
|
+
const path = [...current.path, Array.isArray(current.value) ? Number(key) : key];
|
|
230
|
+
if (key === "__proto__") return { path, reason: "key" };
|
|
231
|
+
const descriptor = Object.getOwnPropertyDescriptor(current.value, key);
|
|
232
|
+
if (descriptor && "value" in descriptor && descriptor.value && typeof descriptor.value === "object") {
|
|
233
|
+
pending.push({ path, value: descriptor.value });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return void 0;
|
|
238
|
+
}
|
|
239
|
+
export {
|
|
240
|
+
parseTileflowRuntimeManifest,
|
|
241
|
+
safeParseTileflowRuntimeManifest,
|
|
242
|
+
tileflowRuntimeManifestLimits,
|
|
243
|
+
tileflowRuntimeManifestSchema,
|
|
244
|
+
tileflowRuntimeManifestVersion
|
|
245
|
+
};
|