@tileflow/core 0.1.0-alpha.25 → 0.1.0-alpha.27
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 +47 -6
- package/THIRD_PARTY_NOTICES.md +84 -0
- package/dist/build.d.ts +417 -6
- package/dist/build.js +12095 -2197
- package/dist/{capture-scene-BK_0J2oR.d.ts → capture-scene-D6soWztE.d.ts} +1 -1
- package/dist/capture.d.ts +2 -2
- package/dist/capture.js +107 -37
- package/dist/{icon-composition-BssSKOKF.d.ts → icon-composition-C2bVldOJ.d.ts} +89 -7
- package/dist/index.d.ts +156 -27
- package/dist/index.js +5217 -4678
- package/dist/{manifest-B5GKVMFE.d.ts → manifest-types-BdGjIYy-.d.ts} +2 -11
- package/dist/manifest.d.ts +9 -2
- package/dist/manifest.js +316 -193
- package/dist/native-profile.d.ts +187 -0
- package/dist/native-profile.js +9316 -0
- package/dist/native.d.ts +196 -5
- package/dist/native.js +4813 -95
- package/dist/runtime.d.ts +1 -2
- package/dist/runtime.js +338 -221
- package/docs/authoring-model.md +5 -4
- package/docs/data-is-separate-from-design.md +8 -8
- package/docs/hosted-session-authorization.md +11 -2
- package/docs/native-artifact-profile.md +145 -0
- package/docs/native-resource-urls.md +257 -7
- package/docs/public-api-and-browser-subpath.md +14 -8
- package/package.json +10 -4
package/dist/runtime.d.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import 'zod';
|
|
1
|
+
export { z as TileflowAnalytics, $ as TileflowManifestFetchOptions, a0 as TileflowManifestLoadOptions, a1 as TileflowMapMode, a2 as TileflowMapModeOptions, ae as TileflowResolvedRuntimeTheme, aB as TileflowRuntimeCenterLike, a as TileflowRuntimeColorScheme, T as TileflowRuntimeManifest, aC as TileflowRuntimeManifestMap, b as TileflowRuntimeManifestMapEntry, c as TileflowRuntimeManifestTheme, aD as TileflowRuntimeSource, aE as TileflowRuntimeSourceValidation, aF as TileflowRuntimeStyle, aG as TileflowRuntimeStyleOptions, d as TileflowRuntimeSystemThemes, aH as TileflowRuntimeViewOptions, aI as TileflowSessionController, aJ as TileflowSessionGrantResponse, aM as TileflowStyleFontFace, b9 as TileflowThemeSelection, bh as assertValidTileflowRuntimeSource, bi as clearTileflowManifestCache, bk as createTileflowSessionController, bl as createTileflowSessionId, bm as defaultTileflowManifestUrl, bn as defaultTileflowRuntimeView, bp as getTileflowAnalyticsApiUrl, bq as getTileflowStyleFontFaces, br as inferTileflowAnalyticsFromStyleUrl, bs as loadTileflowManifest, bt as mergeTileflowAnalytics, bu as normalizeTileflowRuntimeCenter, bv as normalizeTileflowStaticImageSize, bQ as normalizeTileflowSurfaceId, bw as normalizeTileflowUrl, bx as resolveTileflowAnalyticsRequestUrl, by as resolveTileflowManifestMap, bz as resolveTileflowMapMode, bA as resolveTileflowRuntimeStyle, bB as resolveTileflowRuntimeTheme, bC as resolveTileflowRuntimeView, bD as resolveTileflowStaticImageUrl, bE as shouldLoadTileflowManifest, bF as startTileflowSession, bH as tileflowStyleFontFaceLimits, bI as tileflowStyleFontFacesMetadataKey, bL as validateTileflowRuntimeSource, bM as validateTileflowThemeSelection } from './manifest-types-BdGjIYy-.js';
|
package/dist/runtime.js
CHANGED
|
@@ -29,29 +29,59 @@ var init_portable_identity_rules = __esm({
|
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
// src/
|
|
33
|
-
|
|
34
|
-
var
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
// src/manifest-types.ts
|
|
33
|
+
var tileflowRuntimeManifestVersion, tileflowRuntimeManifestLimits;
|
|
34
|
+
var init_manifest_types = __esm({
|
|
35
|
+
"src/manifest-types.ts"() {
|
|
36
|
+
"use strict";
|
|
37
|
+
tileflowRuntimeManifestVersion = 1;
|
|
38
|
+
tileflowRuntimeManifestLimits = Object.freeze({ maximumBytes: 1024 * 1024 });
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// src/portable-identity-schema.ts
|
|
43
|
+
function createPortableIdentitySchemas(operations) {
|
|
44
|
+
const bounded = operations.maxLength(
|
|
45
|
+
operations.minLength(operations.string(), 1),
|
|
46
|
+
tileflowPortableIdMaximumLength
|
|
47
|
+
);
|
|
48
|
+
const pattern = operations.regex(
|
|
49
|
+
bounded,
|
|
50
|
+
tileflowPortableIdPattern,
|
|
51
|
+
"Expected lowercase kebab-case beginning with a letter"
|
|
52
|
+
);
|
|
53
|
+
const tileflowPortableIdSchema2 = operations.refine(
|
|
54
|
+
pattern,
|
|
55
|
+
(name) => !["constructor", "prototype"].includes(name) && !/^(?:AUX|CON|NUL|PRN|COM[1-9]|LPT[1-9])$/i.test(name),
|
|
56
|
+
"Expected a portable identifier that is not a reserved filename or prototype key"
|
|
57
|
+
);
|
|
58
|
+
const tileflowThemeNameSchema2 = operations.refine(
|
|
59
|
+
tileflowPortableIdSchema2,
|
|
60
|
+
isTileflowThemeName,
|
|
61
|
+
"Expected a concrete theme name; system is browser-only"
|
|
62
|
+
);
|
|
63
|
+
return { tileflowPortableIdSchema: tileflowPortableIdSchema2, tileflowThemeNameSchema: tileflowThemeNameSchema2 };
|
|
64
|
+
}
|
|
65
|
+
var init_portable_identity_schema = __esm({
|
|
66
|
+
"src/portable-identity-schema.ts"() {
|
|
37
67
|
"use strict";
|
|
38
68
|
init_portable_identity_rules();
|
|
39
|
-
tileflowPortableIdSchema = z.string().min(1).max(tileflowPortableIdMaximumLength).regex(tileflowPortableIdPattern, {
|
|
40
|
-
message: "Expected lowercase kebab-case beginning with a letter"
|
|
41
|
-
}).refine(
|
|
42
|
-
(name) => !["constructor", "prototype"].includes(name) && !/^(?:AUX|CON|NUL|PRN|COM[1-9]|LPT[1-9])$/i.test(name),
|
|
43
|
-
"Expected a portable identifier that is not a reserved filename or prototype key"
|
|
44
|
-
);
|
|
45
|
-
tileflowThemeNameSchema = tileflowPortableIdSchema.refine(
|
|
46
|
-
isTileflowThemeName,
|
|
47
|
-
"Expected a concrete theme name; system is browser-only"
|
|
48
|
-
);
|
|
49
69
|
}
|
|
50
70
|
});
|
|
51
71
|
|
|
52
|
-
// src/
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
// src/runtime-view-schema.ts
|
|
73
|
+
function createTileflowRuntimeViewSchema(operations) {
|
|
74
|
+
return operations.object({
|
|
75
|
+
bearing: operations.optional(operations.number(-180, 180)),
|
|
76
|
+
center: operations.optional(
|
|
77
|
+
operations.tuplePair(operations.number(-180, 180), operations.number(-90, 90))
|
|
78
|
+
),
|
|
79
|
+
pitch: operations.optional(operations.number(0, 85)),
|
|
80
|
+
zoom: operations.optional(operations.number(0, 24))
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
var init_runtime_view_schema = __esm({
|
|
84
|
+
"src/runtime-view-schema.ts"() {
|
|
55
85
|
"use strict";
|
|
56
86
|
}
|
|
57
87
|
});
|
|
@@ -73,155 +103,73 @@ var init_model = __esm({
|
|
|
73
103
|
}
|
|
74
104
|
});
|
|
75
105
|
|
|
76
|
-
// src/
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
} catch {
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
function hasEncodedPathSeparator(value) {
|
|
141
|
-
return /%(?:2f|5c)/iu.test(value);
|
|
142
|
-
}
|
|
143
|
-
function isApiOrigin(value) {
|
|
144
|
-
try {
|
|
145
|
-
const url = new URL(value);
|
|
146
|
-
return isAbsolutePublicUrl(value) && url.pathname === "/" && !url.search && value.replace(/\/$/u, "") === url.origin;
|
|
147
|
-
} catch {
|
|
148
|
-
return false;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
function findUnsafeManifestStructure(input) {
|
|
152
|
-
if (!input || typeof input !== "object") return void 0;
|
|
153
|
-
const pending = [{ path: [], value: input }];
|
|
154
|
-
const visited = /* @__PURE__ */ new WeakSet();
|
|
155
|
-
while (pending.length > 0) {
|
|
156
|
-
const current = pending.pop();
|
|
157
|
-
if (visited.has(current.value)) continue;
|
|
158
|
-
visited.add(current.value);
|
|
159
|
-
if (!Array.isArray(current.value)) {
|
|
160
|
-
const prototype = Object.getPrototypeOf(current.value);
|
|
161
|
-
if (prototype !== Object.prototype && prototype !== null) {
|
|
162
|
-
return { path: current.path, reason: "prototype" };
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
for (const key of Object.keys(current.value)) {
|
|
166
|
-
const path = [...current.path, Array.isArray(current.value) ? Number(key) : key];
|
|
167
|
-
if (key === "__proto__") return { path, reason: "key" };
|
|
168
|
-
const descriptor = Object.getOwnPropertyDescriptor(current.value, key);
|
|
169
|
-
if (descriptor && "value" in descriptor && descriptor.value && typeof descriptor.value === "object") {
|
|
170
|
-
pending.push({ path, value: descriptor.value });
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return void 0;
|
|
175
|
-
}
|
|
176
|
-
var tileflowRuntimeManifestVersion, tileflowRuntimeManifestLimits, safeTextSchema, publicResourceUrlSchema, apiOriginSchema, viewSchema, fontFaceSchema, fontFacesSchema, manifestThemeSchema, manifestMapSchema, canonicalManifestSchema, safeManifestInputSchema, tileflowRuntimeManifestSchema;
|
|
177
|
-
var init_manifest = __esm({
|
|
178
|
-
"src/manifest.ts"() {
|
|
179
|
-
"use strict";
|
|
180
|
-
init_portable_identity();
|
|
181
|
-
init_themes();
|
|
182
|
-
tileflowRuntimeManifestVersion = 1;
|
|
183
|
-
tileflowRuntimeManifestLimits = Object.freeze({ maximumBytes: 1024 * 1024 });
|
|
184
|
-
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");
|
|
185
|
-
publicResourceUrlSchema = safeTextSchema.refine(isPublicResourceUrl, {
|
|
186
|
-
message: "Expected an HTTP(S), root-relative, or path-relative public URL"
|
|
187
|
-
});
|
|
188
|
-
apiOriginSchema = safeTextSchema.refine(isApiOrigin, {
|
|
189
|
-
message: "Expected an absolute HTTP(S) origin without path, credentials, query, or fragment"
|
|
190
|
-
});
|
|
191
|
-
viewSchema = z2.object({
|
|
192
|
-
bearing: z2.number().finite().min(-180).max(180).optional(),
|
|
193
|
-
center: z2.tuple([z2.number().finite().min(-180).max(180), z2.number().finite().min(-90).max(90)]).optional(),
|
|
194
|
-
pitch: z2.number().finite().min(0).max(85).optional(),
|
|
195
|
-
zoom: z2.number().finite().min(0).max(24).optional()
|
|
196
|
-
}).strict();
|
|
197
|
-
fontFaceSchema = z2.object({
|
|
198
|
-
family: safeTextSchema.max(100),
|
|
199
|
-
source: publicResourceUrlSchema,
|
|
200
|
-
style: z2.enum(["italic", "normal", "oblique"]).optional(),
|
|
201
|
-
weight: z2.enum(["100", "200", "300", "400", "500", "600", "700", "800", "900"]).optional()
|
|
202
|
-
}).strict();
|
|
203
|
-
fontFacesSchema = z2.array(fontFaceSchema).max(16).superRefine(validateUniqueFontFaces);
|
|
204
|
-
manifestThemeSchema = z2.object({
|
|
205
|
-
colorScheme: z2.enum(["dark", "light"]),
|
|
206
|
-
fontFaces: fontFacesSchema.optional(),
|
|
207
|
-
revision: safeTextSchema.max(128).optional(),
|
|
208
|
-
styleId: safeTextSchema.max(128).optional(),
|
|
209
|
-
styleUrl: publicResourceUrlSchema
|
|
210
|
-
}).strict();
|
|
211
|
-
manifestMapSchema = z2.object({
|
|
212
|
-
apiUrl: apiOriginSchema.optional(),
|
|
213
|
-
defaultTheme: tileflowThemeNameSchema,
|
|
214
|
-
environment: safeTextSchema.max(128).optional(),
|
|
215
|
-
mapId: safeTextSchema.max(128).optional(),
|
|
216
|
-
systemThemes: z2.object({ dark: tileflowThemeNameSchema, light: tileflowThemeNameSchema }).strict().optional(),
|
|
217
|
-
themes: z2.record(tileflowThemeNameSchema, manifestThemeSchema),
|
|
218
|
-
usageMode: z2.literal("session").optional(),
|
|
219
|
-
view: viewSchema.optional(),
|
|
220
|
-
worldGeneration: z2.literal("v1").optional()
|
|
221
|
-
}).strict().superRefine((entry, context) => {
|
|
106
|
+
// src/manifest-schema.ts
|
|
107
|
+
function createTileflowRuntimeManifestSchema(primitives, operations, identities = createPortableIdentitySchemas(operations)) {
|
|
108
|
+
const { tileflowPortableIdSchema: tileflowPortableIdSchema2, tileflowThemeNameSchema: tileflowThemeNameSchema2 } = identities;
|
|
109
|
+
const safeTextSchema = operations.refine(
|
|
110
|
+
operations.refine(
|
|
111
|
+
operations.maxLength(operations.minLength(operations.string(), 1), 2048),
|
|
112
|
+
(value) => value === value.trim(),
|
|
113
|
+
"Expected text without surrounding whitespace"
|
|
114
|
+
),
|
|
115
|
+
(value) => !/[\p{Cc}\\]/u.test(value),
|
|
116
|
+
"Expected safe text"
|
|
117
|
+
);
|
|
118
|
+
const publicResourceUrlSchema = operations.refine(
|
|
119
|
+
safeTextSchema,
|
|
120
|
+
isPublicResourceUrl,
|
|
121
|
+
"Expected an HTTP(S), root-relative, or path-relative public URL"
|
|
122
|
+
);
|
|
123
|
+
const apiOriginSchema = operations.refine(
|
|
124
|
+
safeTextSchema,
|
|
125
|
+
isApiOrigin,
|
|
126
|
+
"Expected an absolute HTTP(S) origin without path, credentials, query, or fragment"
|
|
127
|
+
);
|
|
128
|
+
const viewSchema = createTileflowRuntimeViewSchema(operations);
|
|
129
|
+
const fontFaceSchema = operations.object({
|
|
130
|
+
family: operations.maxLength(safeTextSchema, 100),
|
|
131
|
+
source: publicResourceUrlSchema,
|
|
132
|
+
style: operations.optional(operations.enum(["italic", "normal", "oblique"])),
|
|
133
|
+
weight: operations.optional(
|
|
134
|
+
operations.enum(["100", "200", "300", "400", "500", "600", "700", "800", "900"])
|
|
135
|
+
)
|
|
136
|
+
});
|
|
137
|
+
const fontFacesSchema = operations.superRefine(
|
|
138
|
+
operations.maxLength(operations.array(fontFaceSchema), 16),
|
|
139
|
+
validateUniqueFontFaces
|
|
140
|
+
);
|
|
141
|
+
const manifestThemeSchema = operations.object({
|
|
142
|
+
colorScheme: operations.enum(["dark", "light"]),
|
|
143
|
+
fontFaces: operations.optional(fontFacesSchema),
|
|
144
|
+
revision: operations.optional(operations.maxLength(safeTextSchema, 128)),
|
|
145
|
+
styleId: operations.optional(operations.maxLength(safeTextSchema, 128)),
|
|
146
|
+
styleUrl: publicResourceUrlSchema
|
|
147
|
+
});
|
|
148
|
+
const manifestMapSchema = operations.superRefine(
|
|
149
|
+
operations.object({
|
|
150
|
+
apiUrl: operations.optional(apiOriginSchema),
|
|
151
|
+
defaultTheme: tileflowThemeNameSchema2,
|
|
152
|
+
environment: operations.optional(operations.maxLength(safeTextSchema, 128)),
|
|
153
|
+
mapId: operations.optional(operations.maxLength(safeTextSchema, 128)),
|
|
154
|
+
systemThemes: operations.optional(
|
|
155
|
+
operations.object({
|
|
156
|
+
dark: tileflowThemeNameSchema2,
|
|
157
|
+
light: tileflowThemeNameSchema2
|
|
158
|
+
})
|
|
159
|
+
),
|
|
160
|
+
themes: operations.record(tileflowThemeNameSchema2, manifestThemeSchema),
|
|
161
|
+
usageMode: operations.optional(operations.literal("session")),
|
|
162
|
+
view: operations.optional(viewSchema),
|
|
163
|
+
worldGeneration: operations.optional(operations.literal("v1"))
|
|
164
|
+
}),
|
|
165
|
+
(entry, context) => {
|
|
222
166
|
const names = Object.keys(entry.themes);
|
|
223
167
|
if (names.length === 0) {
|
|
224
|
-
context.addIssue({
|
|
168
|
+
context.addIssue({
|
|
169
|
+
code: "custom",
|
|
170
|
+
message: "Expected at least one theme",
|
|
171
|
+
path: ["themes"]
|
|
172
|
+
});
|
|
225
173
|
}
|
|
226
174
|
if (names.length > tileflowThemeLimits.maxThemes) {
|
|
227
175
|
context.addIssue({
|
|
@@ -263,12 +211,15 @@ var init_manifest = __esm({
|
|
|
263
211
|
message: "usageMode and worldGeneration must be declared together"
|
|
264
212
|
});
|
|
265
213
|
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
const canonicalManifestSchema = operations.superRefine(
|
|
217
|
+
operations.object({
|
|
218
|
+
apiUrl: operations.optional(apiOriginSchema),
|
|
219
|
+
maps: operations.record(tileflowPortableIdSchema2, manifestMapSchema),
|
|
220
|
+
version: operations.literal(tileflowRuntimeManifestVersion)
|
|
221
|
+
}),
|
|
222
|
+
(manifest, context) => {
|
|
272
223
|
const mapCount = Object.keys(manifest.maps).length;
|
|
273
224
|
if (mapCount === 0) {
|
|
274
225
|
context.addIssue({ code: "custom", message: "Expected at least one map", path: ["maps"] });
|
|
@@ -276,7 +227,7 @@ var init_manifest = __esm({
|
|
|
276
227
|
if (mapCount > 1e3) {
|
|
277
228
|
context.addIssue({ code: "too_big", maximum: 1e3, origin: "object", path: ["maps"] });
|
|
278
229
|
}
|
|
279
|
-
if (
|
|
230
|
+
if (primitives.utf8ByteLength(JSON.stringify(manifest)) > tileflowRuntimeManifestLimits.maximumBytes) {
|
|
280
231
|
context.addIssue({
|
|
281
232
|
code: "too_big",
|
|
282
233
|
maximum: tileflowRuntimeManifestLimits.maximumBytes,
|
|
@@ -284,18 +235,217 @@ var init_manifest = __esm({
|
|
|
284
235
|
message: "Manifest JSON exceeds the 1 MiB limit"
|
|
285
236
|
});
|
|
286
237
|
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
const safeManifestInputSchema = operations.superRefine(operations.unknown(), (input, context) => {
|
|
241
|
+
const unsafe = findUnsafeManifestStructure(input);
|
|
242
|
+
if (unsafe) {
|
|
243
|
+
context.addIssue({
|
|
244
|
+
code: "custom",
|
|
245
|
+
message: unsafe.reason === "prototype" ? "Expected plain manifest objects" : "Expected no prototype-mutating keys",
|
|
246
|
+
path: unsafe.path
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
function validateUniqueFontFaces(fontFaces, context) {
|
|
251
|
+
const seen = /* @__PURE__ */ new Map();
|
|
252
|
+
for (const [index, fontFace] of fontFaces.entries()) {
|
|
253
|
+
const identity = `${fontFace.family}\0${fontFace.style ?? "normal"}\0${fontFace.weight ?? "400"}`;
|
|
254
|
+
const first = seen.get(identity);
|
|
255
|
+
if (first !== void 0) {
|
|
291
256
|
context.addIssue({
|
|
292
257
|
code: "custom",
|
|
293
|
-
message:
|
|
294
|
-
path:
|
|
258
|
+
message: `Duplicate font face identity; first declared at index ${first}`,
|
|
259
|
+
path: [index]
|
|
295
260
|
});
|
|
261
|
+
continue;
|
|
296
262
|
}
|
|
297
|
-
|
|
298
|
-
|
|
263
|
+
seen.set(identity, index);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function isPublicResourceUrl(value) {
|
|
267
|
+
if (value.startsWith("//")) return false;
|
|
268
|
+
if (!value.startsWith("/") && !value.startsWith("./") && !value.startsWith("../") && !isAbsolutePublicUrl(value)) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
return isSafeResolvedPublicUrl(value);
|
|
272
|
+
}
|
|
273
|
+
function isAbsolutePublicUrl(value) {
|
|
274
|
+
try {
|
|
275
|
+
const url = primitives.parseUrl(value);
|
|
276
|
+
return (url.protocol === "http:" || url.protocol === "https:") && !url.username && !url.password && !url.hash && !hasEncodedPathSeparator(value);
|
|
277
|
+
} catch {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function isSafeResolvedPublicUrl(value) {
|
|
282
|
+
try {
|
|
283
|
+
const url = primitives.parseUrl(value, "https://manifest.invalid/owner/manifest.json");
|
|
284
|
+
return (url.protocol === "http:" || url.protocol === "https:") && !url.username && !url.password && !url.hash && !hasEncodedPathSeparator(value);
|
|
285
|
+
} catch {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function hasEncodedPathSeparator(value) {
|
|
290
|
+
return /%(?:2f|5c)/iu.test(value);
|
|
291
|
+
}
|
|
292
|
+
function isApiOrigin(value) {
|
|
293
|
+
try {
|
|
294
|
+
const url = primitives.parseUrl(value);
|
|
295
|
+
return isAbsolutePublicUrl(value) && url.pathname === "/" && !url.search && value.replace(/\/$/u, "") === url.origin;
|
|
296
|
+
} catch {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function findUnsafeManifestStructure(input) {
|
|
301
|
+
if (!input || typeof input !== "object") return void 0;
|
|
302
|
+
const pending = [
|
|
303
|
+
{ path: [], value: input }
|
|
304
|
+
];
|
|
305
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
306
|
+
while (pending.length > 0) {
|
|
307
|
+
const current = pending.pop();
|
|
308
|
+
if (visited.has(current.value)) continue;
|
|
309
|
+
visited.add(current.value);
|
|
310
|
+
if (!Array.isArray(current.value)) {
|
|
311
|
+
const prototype = Object.getPrototypeOf(current.value);
|
|
312
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
313
|
+
return { path: current.path, reason: "prototype" };
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
for (const key of Object.keys(current.value)) {
|
|
317
|
+
const path = [...current.path, Array.isArray(current.value) ? Number(key) : key];
|
|
318
|
+
if (key === "__proto__") return { path, reason: "key" };
|
|
319
|
+
const descriptor = Object.getOwnPropertyDescriptor(current.value, key);
|
|
320
|
+
if (descriptor && "value" in descriptor && descriptor.value && typeof descriptor.value === "object") {
|
|
321
|
+
pending.push({ path, value: descriptor.value });
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return void 0;
|
|
326
|
+
}
|
|
327
|
+
return operations.pipe(safeManifestInputSchema, canonicalManifestSchema);
|
|
328
|
+
}
|
|
329
|
+
var init_manifest_schema = __esm({
|
|
330
|
+
"src/manifest-schema.ts"() {
|
|
331
|
+
"use strict";
|
|
332
|
+
init_manifest_types();
|
|
333
|
+
init_portable_identity_schema();
|
|
334
|
+
init_runtime_view_schema();
|
|
335
|
+
init_model();
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// src/native-zod-object.ts
|
|
340
|
+
import { z } from "zod";
|
|
341
|
+
function strictNativeObject(shape) {
|
|
342
|
+
const object = new z.core.$ZodObject({
|
|
343
|
+
type: "object",
|
|
344
|
+
shape,
|
|
345
|
+
catchall: z.never()
|
|
346
|
+
});
|
|
347
|
+
return z.lazy(() => object);
|
|
348
|
+
}
|
|
349
|
+
var init_native_zod_object = __esm({
|
|
350
|
+
"src/native-zod-object.ts"() {
|
|
351
|
+
"use strict";
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// src/manifest-schema-classic.ts
|
|
356
|
+
import { z as z2 } from "zod";
|
|
357
|
+
function classic(schema) {
|
|
358
|
+
return schema;
|
|
359
|
+
}
|
|
360
|
+
var classicManifestStringOperations, classicManifestSchemaOperations;
|
|
361
|
+
var init_manifest_schema_classic = __esm({
|
|
362
|
+
"src/manifest-schema-classic.ts"() {
|
|
363
|
+
"use strict";
|
|
364
|
+
init_native_zod_object();
|
|
365
|
+
classicManifestStringOperations = {
|
|
366
|
+
string: () => z2.string(),
|
|
367
|
+
minLength(schema, minimum) {
|
|
368
|
+
return schema.min(
|
|
369
|
+
minimum
|
|
370
|
+
);
|
|
371
|
+
},
|
|
372
|
+
maxLength(schema, maximum) {
|
|
373
|
+
return schema.max(
|
|
374
|
+
maximum
|
|
375
|
+
);
|
|
376
|
+
},
|
|
377
|
+
regex: (schema, pattern, message) => schema.regex(pattern, { message }),
|
|
378
|
+
refine: (schema, check, message) => classic(schema).refine(check, message)
|
|
379
|
+
};
|
|
380
|
+
classicManifestSchemaOperations = {
|
|
381
|
+
...classicManifestStringOperations,
|
|
382
|
+
number: (minimum, maximum) => z2.number().finite().min(minimum).max(maximum),
|
|
383
|
+
unknown: () => z2.unknown(),
|
|
384
|
+
optional: (schema) => classic(schema).optional(),
|
|
385
|
+
array: (schema) => z2.array(classic(schema)),
|
|
386
|
+
enum(values) {
|
|
387
|
+
return z2.enum(values);
|
|
388
|
+
},
|
|
389
|
+
literal: (value) => z2.literal(value),
|
|
390
|
+
tuplePair(left, right) {
|
|
391
|
+
return z2.tuple([classic(left), classic(right)]);
|
|
392
|
+
},
|
|
393
|
+
object(shape) {
|
|
394
|
+
return strictNativeObject(shape);
|
|
395
|
+
},
|
|
396
|
+
record(key, value) {
|
|
397
|
+
return z2.record(classic(key), classic(value));
|
|
398
|
+
},
|
|
399
|
+
superRefine: (schema, check) => classic(schema).superRefine(check),
|
|
400
|
+
pipe: (input, output) => classic(input).pipe(classic(output))
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// src/portable-identity.ts
|
|
406
|
+
var schemas, tileflowPortableIdSchema, tileflowThemeNameSchema;
|
|
407
|
+
var init_portable_identity = __esm({
|
|
408
|
+
"src/portable-identity.ts"() {
|
|
409
|
+
"use strict";
|
|
410
|
+
init_manifest_schema_classic();
|
|
411
|
+
init_portable_identity_schema();
|
|
412
|
+
schemas = createPortableIdentitySchemas(classicManifestStringOperations);
|
|
413
|
+
tileflowPortableIdSchema = schemas.tileflowPortableIdSchema;
|
|
414
|
+
tileflowThemeNameSchema = schemas.tileflowThemeNameSchema;
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// src/manifest.ts
|
|
419
|
+
var manifest_exports = {};
|
|
420
|
+
__export(manifest_exports, {
|
|
421
|
+
parseTileflowRuntimeManifest: () => parseTileflowRuntimeManifest,
|
|
422
|
+
safeParseTileflowRuntimeManifest: () => safeParseTileflowRuntimeManifest,
|
|
423
|
+
tileflowRuntimeManifestLimits: () => tileflowRuntimeManifestLimits,
|
|
424
|
+
tileflowRuntimeManifestSchema: () => tileflowRuntimeManifestSchema,
|
|
425
|
+
tileflowRuntimeManifestVersion: () => tileflowRuntimeManifestVersion
|
|
426
|
+
});
|
|
427
|
+
function parseTileflowRuntimeManifest(input) {
|
|
428
|
+
return tileflowRuntimeManifestSchema.parse(input);
|
|
429
|
+
}
|
|
430
|
+
function safeParseTileflowRuntimeManifest(input) {
|
|
431
|
+
return tileflowRuntimeManifestSchema.safeParse(input);
|
|
432
|
+
}
|
|
433
|
+
var tileflowRuntimeManifestSchema;
|
|
434
|
+
var init_manifest = __esm({
|
|
435
|
+
"src/manifest.ts"() {
|
|
436
|
+
"use strict";
|
|
437
|
+
init_manifest_schema();
|
|
438
|
+
init_manifest_schema_classic();
|
|
439
|
+
init_portable_identity();
|
|
440
|
+
init_manifest_types();
|
|
441
|
+
tileflowRuntimeManifestSchema = createTileflowRuntimeManifestSchema(
|
|
442
|
+
{
|
|
443
|
+
parseUrl: (value, base) => base === void 0 ? new URL(value) : new URL(value, base),
|
|
444
|
+
utf8ByteLength: (value) => new TextEncoder().encode(value).byteLength
|
|
445
|
+
},
|
|
446
|
+
classicManifestSchemaOperations,
|
|
447
|
+
{ tileflowPortableIdSchema, tileflowThemeNameSchema }
|
|
448
|
+
);
|
|
299
449
|
}
|
|
300
450
|
});
|
|
301
451
|
|
|
@@ -325,7 +475,7 @@ var maximumSessionGrantBytes = 64 * 1024;
|
|
|
325
475
|
var manifestCache = new globalThis.Map();
|
|
326
476
|
var missingStaticMapIdWarnings = /* @__PURE__ */ new Set();
|
|
327
477
|
function shouldLoadTileflowManifest(options) {
|
|
328
|
-
return options.source.
|
|
478
|
+
return validateTileflowRuntimeSource(options.source).ok;
|
|
329
479
|
}
|
|
330
480
|
function validateTileflowRuntimeSource(source) {
|
|
331
481
|
if (source === void 0) {
|
|
@@ -334,32 +484,14 @@ function validateTileflowRuntimeSource(source) {
|
|
|
334
484
|
if (!isPlainRuntimeRecord(source)) {
|
|
335
485
|
return { code: "invalid-source", error: "source must be an object", ok: false };
|
|
336
486
|
}
|
|
337
|
-
if (source.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
return { ok: true };
|
|
346
|
-
}
|
|
347
|
-
if (source.kind === "maplibre") {
|
|
348
|
-
const style = source.style;
|
|
349
|
-
if ((typeof style !== "string" || style.length === 0) && (!style || typeof style !== "object" || Array.isArray(style))) {
|
|
350
|
-
return {
|
|
351
|
-
code: "invalid-source",
|
|
352
|
-
error: "a maplibre source requires a style object or non-empty style URL",
|
|
353
|
-
ok: false
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
return { ok: true };
|
|
487
|
+
if ("kind" in source || "style" in source || !isTileflowPortableId(source.map) || source.manifestUrl !== void 0 && (typeof source.manifestUrl !== "string" || source.manifestUrl.length === 0)) {
|
|
488
|
+
return {
|
|
489
|
+
code: "invalid-source",
|
|
490
|
+
error: "source requires a portable map id and an optional non-empty manifestUrl; renderer inputs are not supported",
|
|
491
|
+
ok: false
|
|
492
|
+
};
|
|
357
493
|
}
|
|
358
|
-
return {
|
|
359
|
-
code: "invalid-source",
|
|
360
|
-
error: "source.kind must be 'tileflow' or 'maplibre'",
|
|
361
|
-
ok: false
|
|
362
|
-
};
|
|
494
|
+
return { ok: true };
|
|
363
495
|
}
|
|
364
496
|
function validateTileflowThemeSelection(value) {
|
|
365
497
|
return value === "system" || isTileflowThemeName(value);
|
|
@@ -372,21 +504,6 @@ function assertValidTileflowRuntimeSource(source) {
|
|
|
372
504
|
}
|
|
373
505
|
function resolveTileflowRuntimeStyle(options) {
|
|
374
506
|
assertValidTileflowRuntimeSource(options.source);
|
|
375
|
-
if (options.source.kind === "maplibre") {
|
|
376
|
-
if (options.theme !== void 0) {
|
|
377
|
-
throw new TypeError("The theme option is only valid for a Tileflow map source.");
|
|
378
|
-
}
|
|
379
|
-
if (typeof options.source.style !== "string") {
|
|
380
|
-
return {
|
|
381
|
-
fontFaces: getTileflowStyleFontFaces(options.source.style),
|
|
382
|
-
style: options.source.style
|
|
383
|
-
};
|
|
384
|
-
}
|
|
385
|
-
return {
|
|
386
|
-
analytics: inferTileflowAnalyticsFromStyleUrl(options.source.style),
|
|
387
|
-
style: options.source.style
|
|
388
|
-
};
|
|
389
|
-
}
|
|
390
507
|
if (options.manifestMap) {
|
|
391
508
|
const theme = resolveTileflowRuntimeTheme(
|
|
392
509
|
options.manifestMap,
|
package/docs/authoring-model.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Start with the [@tileflow/core guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/README.md) for installation and a complete first example.
|
|
4
4
|
|
|
5
5
|
Tileflow exposes one authoring concept and one constructor: `defineMap()`. A complete map omits
|
|
6
|
-
`extends`; an inherited map sets `extends` to another imported map object. All
|
|
6
|
+
`extends`; an inherited map sets `extends` to another imported map object. All first-party
|
|
7
7
|
maps are independent standalone maps. They use the sole semantic compiler while defining
|
|
8
8
|
their complete designs and asset providers directly; no official map imports or extends another
|
|
9
9
|
official map. Applications can extend any of those maps through the same public API. Streets
|
|
@@ -106,7 +106,7 @@ const companyBase = defineMap({
|
|
|
106
106
|
version: 1,
|
|
107
107
|
glyphs: {
|
|
108
108
|
kind: 'url',
|
|
109
|
-
url: 'https://api.tileflow.dev/
|
|
109
|
+
url: 'https://api.tileflow.dev/base/33d4de5e8086d9d629d67d3f39fedb87e23686c4c1ac653c27e2a52aee9d00b3/glyphs/{fontstack}/{range}.pbf',
|
|
110
110
|
fontStacks: ['Noto Sans Regular', 'Noto Sans Bold'],
|
|
111
111
|
},
|
|
112
112
|
icons: [streetsIcons],
|
|
@@ -126,8 +126,9 @@ export default defineMap({
|
|
|
126
126
|
The standalone map above is complete as written. A map always owns its complete text provider; Core does not
|
|
127
127
|
obtain fonts or sprites from World and never invents a fallback URL. The URL-backed first-party
|
|
128
128
|
`streets`, `ferraris`, `harad`, `soundings`, `verdant`, and `sanFrancisto` maps declare their glyph
|
|
129
|
-
providers directly
|
|
130
|
-
maps compile without out-of-band release
|
|
129
|
+
providers directly. `baedeker`, `civica`, `cyberpunk`, `matrix`, `siegfried`, and `superTileWorld`
|
|
130
|
+
declare packaged fonts, so ordinary imports and derived maps compile without out-of-band release
|
|
131
|
+
metadata.
|
|
131
132
|
|
|
132
133
|
```mermaid
|
|
133
134
|
flowchart LR
|