@tileflow/dev 0.1.0-alpha.26 → 0.1.0-alpha.28
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 +11 -4
- package/THIRD_PARTY_NOTICES.md +4 -9
- package/dist/artifacts.d.ts +35 -1
- package/dist/artifacts.js +9 -1
- package/dist/{chunk-QAMFAM3S.js → chunk-4HVIEMKM.js} +277 -86
- package/dist/{chunk-6OJICHB3.js → chunk-CJGM6HTT.js} +70 -8
- package/dist/{chunk-UCBGTEQV.js → chunk-YOTMY5XT.js} +13 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +11 -3
- package/dist/preview.d.ts +2 -0
- package/dist/preview.js +1 -1
- package/dist/server.js +2 -2
- package/docs/bounded-vector-feature-inspection.md +4 -4
- package/docs/local-comparison-workbench-and-compiler-inspection.md +3 -5
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -73,6 +73,12 @@ manifest pointer, tracks its own files, and refuses to replace a hosted manifest
|
|
|
73
73
|
Production rejects unresolved local PMTiles; publish data explicitly or provide an application-owned
|
|
74
74
|
production source. Local development snapshots do not publish or redistribute the original dataset.
|
|
75
75
|
|
|
76
|
+
Maps whose labels use a line-fitted `text.background` draw text with derived glyph stacks. Local
|
|
77
|
+
previews and captures route such a map's glyph URL through `__glyphs/<map>/…`. Ordinary stacks pass
|
|
78
|
+
through from the declared provider; derived ranges are computed from their source ranges, which are
|
|
79
|
+
cached under `.tileflow/cache/glyphs/v1`. Production output keeps the declared provider, which must
|
|
80
|
+
serve derived stacks.
|
|
81
|
+
|
|
76
82
|
## Keep a watched request handler
|
|
77
83
|
|
|
78
84
|
Use one session for repeated work and close it when the owning server stops:
|
|
@@ -137,8 +143,9 @@ This is the one normal icon-preparation path. `compileTileflowIconPackages`,
|
|
|
137
143
|
`prepareTileflowCatalogIcons`, `inspectTileflowIconCatalogs` and `getTileflowIconWatchPaths` all use
|
|
138
144
|
it, so `createTileflowBuildArtifacts`, `createTileflowArtifactSession`, and every adapter that
|
|
139
145
|
enters them accept the same explicit `icons` resolution options: `cacheRoot`, `offline`,
|
|
140
|
-
`deliveryOrigins`, `fetch` and `signal`.
|
|
141
|
-
|
|
146
|
+
`deliveryOrigins`, `fetch` and `signal`. An explicit `cacheRoot` takes precedence over
|
|
147
|
+
`TILEFLOW_ICON_CACHE_DIR`, then the OS cache default. Origins and transport use their documented
|
|
148
|
+
defaults unless supplied explicitly; no build or watch polls a catalog head. `prepareTileflowCatalogIcons`
|
|
142
149
|
returns `mapIconCompositions` alongside `mapIconSources`, and build-manifest entries carry the
|
|
143
150
|
receipt as `sourceAssets.iconComposition` with `mapRevisionSchemaVersion: 2`.
|
|
144
151
|
|
|
@@ -159,8 +166,8 @@ Applications may explicitly configure trusted `deliveryOrigins`; locks cannot ad
|
|
|
159
166
|
forbids all fetches and fails on missing or corrupt entries. Complete-map offline rendering still
|
|
160
167
|
depends on unrelated tiles, glyphs, and other external resources.
|
|
161
168
|
|
|
162
|
-
The cache lives under the OS user cache with `tileflow/icons/v1/<contentHash>`. `cacheRoot
|
|
163
|
-
`TILEFLOW_ICON_CACHE_DIR
|
|
169
|
+
The cache lives under the OS user cache with `tileflow/icons/v1/<contentHash>`. `cacheRoot`, then
|
|
170
|
+
`TILEFLOW_ICON_CACHE_DIR`, overrides its parent. Atomic directory installation and exact-entry
|
|
164
171
|
retirement support concurrent writers and corruption repair. Symlink entries are rejected. This is
|
|
165
172
|
a disposable cache, not a security sandbox against another process controlling the same user
|
|
166
173
|
account. Incomplete temporary entries are never accepted as published cache entries.
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -34,15 +34,10 @@ The generic font preparation pipeline reads map-owned TTF, OTF, and WOFF2 direct
|
|
|
34
34
|
embed fonts in `@tileflow/dev`. Each source directory must carry its own `LICENSE.txt`, which is
|
|
35
35
|
copied into the deterministic build artifacts whenever that directory contributes a selected face.
|
|
36
36
|
|
|
37
|
-
The
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
`@tileflow/maps/assets/cyberpunk/fonts/LICENSE.txt`.
|
|
42
|
-
|
|
43
|
-
- Source: <https://github.com/sevmeyer/oxanium/tree/a8f39e0c71186190027a093e9001459410192d1e>
|
|
44
|
-
- Google Fonts specimen: <https://fonts.google.com/specimen/Oxanium>
|
|
45
|
-
- License: <https://github.com/sevmeyer/oxanium/blob/a8f39e0c71186190027a093e9001459410192d1e/OFL.txt>
|
|
37
|
+
The source repository's generic font tests retain pinned Oxanium fixtures and their complete
|
|
38
|
+
SIL Open Font License 1.1 notice under `test/fixtures/fonts/oxanium/`. These fixtures are not
|
|
39
|
+
included in the published package. Community map fonts are owned by
|
|
40
|
+
[Community Maps](https://github.com/tileflow/community-maps).
|
|
46
41
|
|
|
47
42
|
## fontkit 2.0.4
|
|
48
43
|
|
package/dist/artifacts.d.ts
CHANGED
|
@@ -5,6 +5,38 @@ import { TileflowRenderer, TileflowNativeBuildRecord } from '@tileflow/core/nati
|
|
|
5
5
|
import { TileflowBuildAsset, TileflowIconResolutionOptions, PreparedTileflowBuildCatalog, TileflowSourceCatalog, PreparedTileflowCatalog } from './icons.js';
|
|
6
6
|
export { defaultTileflowConfigPath } from './config.js';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Local glyph serving for line-fitted text backgrounds.
|
|
10
|
+
*
|
|
11
|
+
* A style whose text uses a derived `<stack> lines-v1-…` font stack needs a glyph provider that
|
|
12
|
+
* derives those ranges. Local previews and captures route such a map's glyph URL through
|
|
13
|
+
* `__glyphs/<map>/…`: ordinary stacks pass through from the map's declared provider unchanged, and
|
|
14
|
+
* derived stacks are computed from their source stack's range. Production output keeps the
|
|
15
|
+
* declared provider, which must serve derived stacks itself.
|
|
16
|
+
*/
|
|
17
|
+
declare const tileflowLineBackgroundGlyphRoute = "__glyphs";
|
|
18
|
+
/** Map name to the upstream glyph URL template its styles declared. Local only; never serialized. */
|
|
19
|
+
type TileflowLineBackgroundGlyphProviders = Readonly<Record<string, string>>;
|
|
20
|
+
type TileflowLineBackgroundGlyphResponderOptions = {
|
|
21
|
+
/** Project root; ranges are cached under `.tileflow/cache/glyphs/v1`. */
|
|
22
|
+
cwd: string;
|
|
23
|
+
fetch?: typeof globalThis.fetch;
|
|
24
|
+
};
|
|
25
|
+
type TileflowLineBackgroundGlyphResponder = (upstream: string, fontStack: string, range: string) => Promise<Response>;
|
|
26
|
+
/** Whether a compiled style draws text with a derived line-background stack. */
|
|
27
|
+
declare function usesTileflowLineBackgroundGlyphs(style: MapLibreStyle): boolean;
|
|
28
|
+
/** Parses `/__glyphs/<map>/<fontstack>/<range>.pbf` from a decoded route path. */
|
|
29
|
+
declare function parseTileflowLineBackgroundGlyphPath(path: string): {
|
|
30
|
+
fontStack: string;
|
|
31
|
+
mapName: string;
|
|
32
|
+
range: string;
|
|
33
|
+
} | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Serves one glyph range for a declared upstream template. Upstream ranges are cached on disk;
|
|
36
|
+
* derived ranges are recomputed from them and kept in a bounded in-memory cache.
|
|
37
|
+
*/
|
|
38
|
+
declare function createTileflowLineBackgroundGlyphResponder(options: TileflowLineBackgroundGlyphResponderOptions): TileflowLineBackgroundGlyphResponder;
|
|
39
|
+
|
|
8
40
|
type TileflowLocalTilesetFile = Readonly<{
|
|
9
41
|
byteLength: number;
|
|
10
42
|
etag: string;
|
|
@@ -149,6 +181,8 @@ type TileflowBuildArtifacts = {
|
|
|
149
181
|
project: TileflowBuildCatalog;
|
|
150
182
|
/** Local-only archive ports. Paths never enter serialized build artifacts. */
|
|
151
183
|
localTilesets?: TileflowLocalTilesetFile[];
|
|
184
|
+
/** Local-only upstream glyph templates for maps whose text uses line-fitted backgrounds. */
|
|
185
|
+
lineBackgroundGlyphs?: TileflowLineBackgroundGlyphProviders;
|
|
152
186
|
/** Optional local-only provenance. It is never serialized as a build artifact. */
|
|
153
187
|
styleInspections?: TileflowBuildStyleInspections;
|
|
154
188
|
styles: TileflowBuildStyles;
|
|
@@ -222,4 +256,4 @@ declare function assertTileflowSelfHostedManifestTarget(manifestPath: string, op
|
|
|
222
256
|
overwriteHostedManifest?: boolean;
|
|
223
257
|
}): Promise<void>;
|
|
224
258
|
|
|
225
|
-
export { type CreateTileflowArtifactPlanOptions, PreparedTileflowBuildCatalog, PreparedTileflowCatalog, type TileflowArtifactAcquisition, type TileflowArtifactDiagnostic, type TileflowArtifactFile, type TileflowArtifactInputGraph, type TileflowArtifactPlan, type TileflowArtifactSession, type TileflowArtifactSessionOptions, type TileflowArtifactSessionState, type TileflowBuildArtifacts, type TileflowBuildArtifactsOptions, TileflowBuildAsset, type TileflowBuildStyleInspections, TileflowHostedManifestOverwriteError, TileflowIconResolutionOptions, type TileflowLocalTilesetFile, TileflowLocalTilesetProductionError, type TileflowManifestOptions, TileflowSourceCatalog, type WriteTileflowArtifactPlanOptions, type WriteTileflowBuildArtifactsOptions, assertNoLocalTilesetsForProduction, assertTileflowSelfHostedManifestTarget, createTileflowArtifactDiagnostics, createTileflowArtifactPlan, createTileflowArtifactSession, createTileflowBuildArtifacts, createTileflowBuildProvenance, createTileflowManifest, createTileflowStyle, createTileflowStyles, disposeTileflowBuildArtifacts, getTileflowArtifactFiles, getTileflowAssetBasePath, getTileflowAssetFileName, getTileflowWatchPaths, isTileflowArtifactInputPath, joinTileflowPublicUrl, normalizeTileflowBasePath, prepareTileflowHostedNativeDeployment, prepareTileflowLocalTilesets, refreshTileflowArtifactSession, resolveTileflowArtifactPublicUrls, tileflowArtifactInventoryFileName, tileflowArtifactPlanSchemaVersion, tileflowArtifactSessionSchemaVersion, writeTileflowArtifactPlan, writeTileflowBuildArtifacts };
|
|
259
|
+
export { type CreateTileflowArtifactPlanOptions, PreparedTileflowBuildCatalog, PreparedTileflowCatalog, type TileflowArtifactAcquisition, type TileflowArtifactDiagnostic, type TileflowArtifactFile, type TileflowArtifactInputGraph, type TileflowArtifactPlan, type TileflowArtifactSession, type TileflowArtifactSessionOptions, type TileflowArtifactSessionState, type TileflowBuildArtifacts, type TileflowBuildArtifactsOptions, TileflowBuildAsset, type TileflowBuildStyleInspections, TileflowHostedManifestOverwriteError, TileflowIconResolutionOptions, type TileflowLineBackgroundGlyphProviders, type TileflowLineBackgroundGlyphResponder, type TileflowLocalTilesetFile, TileflowLocalTilesetProductionError, type TileflowManifestOptions, TileflowSourceCatalog, type WriteTileflowArtifactPlanOptions, type WriteTileflowBuildArtifactsOptions, assertNoLocalTilesetsForProduction, assertTileflowSelfHostedManifestTarget, createTileflowArtifactDiagnostics, createTileflowArtifactPlan, createTileflowArtifactSession, createTileflowBuildArtifacts, createTileflowBuildProvenance, createTileflowLineBackgroundGlyphResponder, createTileflowManifest, createTileflowStyle, createTileflowStyles, disposeTileflowBuildArtifacts, getTileflowArtifactFiles, getTileflowAssetBasePath, getTileflowAssetFileName, getTileflowWatchPaths, isTileflowArtifactInputPath, joinTileflowPublicUrl, normalizeTileflowBasePath, parseTileflowLineBackgroundGlyphPath, prepareTileflowHostedNativeDeployment, prepareTileflowLocalTilesets, refreshTileflowArtifactSession, resolveTileflowArtifactPublicUrls, tileflowArtifactInventoryFileName, tileflowArtifactPlanSchemaVersion, tileflowArtifactSessionSchemaVersion, tileflowLineBackgroundGlyphRoute, usesTileflowLineBackgroundGlyphs, writeTileflowArtifactPlan, writeTileflowBuildArtifacts };
|
package/dist/artifacts.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
createTileflowArtifactSession,
|
|
9
9
|
createTileflowBuildArtifacts,
|
|
10
10
|
createTileflowBuildProvenance,
|
|
11
|
+
createTileflowLineBackgroundGlyphResponder,
|
|
11
12
|
createTileflowManifest,
|
|
12
13
|
createTileflowStyle,
|
|
13
14
|
createTileflowStyles,
|
|
@@ -15,15 +16,18 @@ import {
|
|
|
15
16
|
getTileflowArtifactFiles,
|
|
16
17
|
getTileflowWatchPaths,
|
|
17
18
|
isTileflowArtifactInputPath,
|
|
19
|
+
parseTileflowLineBackgroundGlyphPath,
|
|
18
20
|
prepareTileflowHostedNativeDeployment,
|
|
19
21
|
prepareTileflowLocalTilesets,
|
|
20
22
|
refreshTileflowArtifactSession,
|
|
21
23
|
tileflowArtifactInventoryFileName,
|
|
22
24
|
tileflowArtifactPlanSchemaVersion,
|
|
23
25
|
tileflowArtifactSessionSchemaVersion,
|
|
26
|
+
tileflowLineBackgroundGlyphRoute,
|
|
27
|
+
usesTileflowLineBackgroundGlyphs,
|
|
24
28
|
writeTileflowArtifactPlan,
|
|
25
29
|
writeTileflowBuildArtifacts
|
|
26
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-4HVIEMKM.js";
|
|
27
31
|
import "./chunk-ONYQNLNA.js";
|
|
28
32
|
import {
|
|
29
33
|
getTileflowAssetBasePath,
|
|
@@ -49,6 +53,7 @@ export {
|
|
|
49
53
|
createTileflowArtifactSession,
|
|
50
54
|
createTileflowBuildArtifacts,
|
|
51
55
|
createTileflowBuildProvenance,
|
|
56
|
+
createTileflowLineBackgroundGlyphResponder,
|
|
52
57
|
createTileflowManifest,
|
|
53
58
|
createTileflowStyle,
|
|
54
59
|
createTileflowStyles,
|
|
@@ -61,6 +66,7 @@ export {
|
|
|
61
66
|
isTileflowArtifactInputPath,
|
|
62
67
|
joinTileflowPublicUrl,
|
|
63
68
|
normalizeTileflowBasePath,
|
|
69
|
+
parseTileflowLineBackgroundGlyphPath,
|
|
64
70
|
prepareTileflowHostedNativeDeployment,
|
|
65
71
|
prepareTileflowLocalTilesets,
|
|
66
72
|
refreshTileflowArtifactSession,
|
|
@@ -68,6 +74,8 @@ export {
|
|
|
68
74
|
tileflowArtifactInventoryFileName,
|
|
69
75
|
tileflowArtifactPlanSchemaVersion,
|
|
70
76
|
tileflowArtifactSessionSchemaVersion,
|
|
77
|
+
tileflowLineBackgroundGlyphRoute,
|
|
78
|
+
usesTileflowLineBackgroundGlyphs,
|
|
71
79
|
writeTileflowArtifactPlan,
|
|
72
80
|
writeTileflowBuildArtifacts
|
|
73
81
|
};
|
|
@@ -28,22 +28,22 @@ import {
|
|
|
28
28
|
} from "./chunk-D4OE4ITL.js";
|
|
29
29
|
|
|
30
30
|
// src/artifacts.ts
|
|
31
|
-
import { createHash as
|
|
31
|
+
import { createHash as createHash4 } from "crypto";
|
|
32
32
|
import { realpathSync as realpathSync2 } from "fs";
|
|
33
33
|
import {
|
|
34
34
|
copyFile as copyFile2,
|
|
35
|
-
lstat as
|
|
36
|
-
mkdir as
|
|
35
|
+
lstat as lstat3,
|
|
36
|
+
mkdir as mkdir3,
|
|
37
37
|
mkdtemp,
|
|
38
38
|
open as open2,
|
|
39
|
-
readFile,
|
|
39
|
+
readFile as readFile2,
|
|
40
40
|
realpath as realpath2,
|
|
41
|
-
rename,
|
|
42
|
-
rm as
|
|
41
|
+
rename as rename2,
|
|
42
|
+
rm as rm3,
|
|
43
43
|
unlink
|
|
44
44
|
} from "fs/promises";
|
|
45
45
|
import { createRequire } from "module";
|
|
46
|
-
import { dirname as dirname2, relative as relative2, resolve as
|
|
46
|
+
import { dirname as dirname2, relative as relative2, resolve as resolve4, sep as sep2 } from "path";
|
|
47
47
|
import {
|
|
48
48
|
compareCodeUnits as compareCodeUnits2,
|
|
49
49
|
getTileflowStyleFontFaces as getTileflowStyleFontFaces2,
|
|
@@ -68,11 +68,194 @@ import {
|
|
|
68
68
|
TileflowNativeCompatibilityError as TileflowNativeCompatibilityError5
|
|
69
69
|
} from "@tileflow/core/native-profile";
|
|
70
70
|
|
|
71
|
+
// src/line-background-glyphs.ts
|
|
72
|
+
import { createHash, randomUUID } from "crypto";
|
|
73
|
+
import { lstat, mkdir, readFile, rename, rm, writeFile } from "fs/promises";
|
|
74
|
+
import { resolve } from "path";
|
|
75
|
+
import {
|
|
76
|
+
deriveTileflowLineBackgroundGlyphs,
|
|
77
|
+
parseTileflowLineBackgroundFontStack
|
|
78
|
+
} from "@tileflow/core";
|
|
79
|
+
var tileflowLineBackgroundGlyphRoute = "__glyphs";
|
|
80
|
+
var RANGE = /^\d{1,6}-\d{1,6}$/u;
|
|
81
|
+
var FONT_STACK = /^[\p{L}\p{N} _.,-]{1,256}$/u;
|
|
82
|
+
var MAP_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
|
|
83
|
+
var MAX_RANGE_BYTES = 8 * 1024 * 1024;
|
|
84
|
+
var MAX_DERIVED_ENTRIES = 512;
|
|
85
|
+
var CACHE_SEGMENTS = [".tileflow", "cache", "glyphs", "v1"];
|
|
86
|
+
function usesTileflowLineBackgroundGlyphs(style) {
|
|
87
|
+
return style.layers.some((layer) => {
|
|
88
|
+
const layout = layer.layout;
|
|
89
|
+
const font = layout?.["text-font"];
|
|
90
|
+
return Array.isArray(font) && font.length === 1 && typeof font[0] === "string" && parseTileflowLineBackgroundFontStack(font[0]) !== void 0;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function prepareTileflowLineBackgroundGlyphs(styles, options) {
|
|
94
|
+
const base = absoluteHttpUrl(options.assetBaseUrl);
|
|
95
|
+
if (!base) return { providers: {}, styles };
|
|
96
|
+
const providers = {};
|
|
97
|
+
const output = {};
|
|
98
|
+
for (const [mapName, themes] of Object.entries(styles)) {
|
|
99
|
+
const family = Object.values(themes);
|
|
100
|
+
const upstream = family.find((style) => typeof style.glyphs === "string")?.glyphs;
|
|
101
|
+
if (!MAP_NAME.test(mapName) || !upstream || !absoluteHttpUrl(upstream) || !family.some(usesTileflowLineBackgroundGlyphs) || family.some((style) => style.glyphs !== upstream)) {
|
|
102
|
+
output[mapName] = themes;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
providers[mapName] = upstream;
|
|
106
|
+
const glyphs = `${base.replace(/\/+$/u, "")}/${tileflowLineBackgroundGlyphRoute}/${mapName}/{fontstack}/{range}.pbf`;
|
|
107
|
+
output[mapName] = Object.fromEntries(
|
|
108
|
+
Object.entries(themes).map(([themeName, style]) => [themeName, { ...style, glyphs }])
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return { providers, styles: output };
|
|
112
|
+
}
|
|
113
|
+
function parseTileflowLineBackgroundGlyphPath(path) {
|
|
114
|
+
const match = /^\/__glyphs\/([^/]+)\/([^/]+)\/([^/]+)\.pbf$/u.exec(path);
|
|
115
|
+
if (!match) return void 0;
|
|
116
|
+
let fontStack;
|
|
117
|
+
try {
|
|
118
|
+
fontStack = decodeURIComponent(match[2]);
|
|
119
|
+
} catch {
|
|
120
|
+
return void 0;
|
|
121
|
+
}
|
|
122
|
+
if (!MAP_NAME.test(match[1]) || !FONT_STACK.test(fontStack) || !RANGE.test(match[3])) {
|
|
123
|
+
return void 0;
|
|
124
|
+
}
|
|
125
|
+
return { fontStack, mapName: match[1], range: match[3] };
|
|
126
|
+
}
|
|
127
|
+
function createTileflowLineBackgroundGlyphResponder(options) {
|
|
128
|
+
const fetchRange = options.fetch ?? globalThis.fetch;
|
|
129
|
+
const derived = /* @__PURE__ */ new Map();
|
|
130
|
+
const upstreamRanges = /* @__PURE__ */ new Map();
|
|
131
|
+
const readUpstream = (upstream, fontStack, range) => {
|
|
132
|
+
const key2 = `${upstream}
|
|
133
|
+
${fontStack}
|
|
134
|
+
${range}`;
|
|
135
|
+
let pending = upstreamRanges.get(key2);
|
|
136
|
+
if (!pending) {
|
|
137
|
+
pending = loadUpstreamRange(options.cwd, fetchRange, upstream, fontStack, range).finally(
|
|
138
|
+
() => upstreamRanges.delete(key2)
|
|
139
|
+
);
|
|
140
|
+
upstreamRanges.set(key2, pending);
|
|
141
|
+
}
|
|
142
|
+
return pending;
|
|
143
|
+
};
|
|
144
|
+
return async (upstream, fontStack, range) => {
|
|
145
|
+
if (!absoluteHttpUrl(upstream) || !FONT_STACK.test(fontStack) || !RANGE.test(range)) {
|
|
146
|
+
return notFound();
|
|
147
|
+
}
|
|
148
|
+
const backed = parseTileflowLineBackgroundFontStack(fontStack);
|
|
149
|
+
if (!backed) {
|
|
150
|
+
if (fontStack.split(",").some((stack) => parseTileflowLineBackgroundFontStack(stack))) {
|
|
151
|
+
return notFound();
|
|
152
|
+
}
|
|
153
|
+
return glyphResponse(await readUpstream(upstream, fontStack, range));
|
|
154
|
+
}
|
|
155
|
+
const key2 = `${upstream}
|
|
156
|
+
${fontStack}
|
|
157
|
+
${range}`;
|
|
158
|
+
let pending = derived.get(key2);
|
|
159
|
+
if (!pending) {
|
|
160
|
+
pending = readUpstream(upstream, backed.source, range).then(
|
|
161
|
+
(source) => source ? deriveTileflowLineBackgroundGlyphs(source, backed.metrics) : void 0
|
|
162
|
+
);
|
|
163
|
+
pending.catch(() => derived.delete(key2));
|
|
164
|
+
derived.set(key2, pending);
|
|
165
|
+
if (derived.size > MAX_DERIVED_ENTRIES) derived.delete(derived.keys().next().value);
|
|
166
|
+
}
|
|
167
|
+
return glyphResponse(await pending);
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
async function loadUpstreamRange(cwd, fetchRange, upstream, fontStack, range) {
|
|
171
|
+
const directory = await cacheDirectory(cwd, upstream);
|
|
172
|
+
const file = resolve(directory, `${digest(fontStack)}-${range}.pbf`);
|
|
173
|
+
const cached = await readFile(file).catch((error) => {
|
|
174
|
+
if (hasCode(error, "ENOENT")) return void 0;
|
|
175
|
+
throw error;
|
|
176
|
+
});
|
|
177
|
+
if (cached) return new Uint8Array(cached);
|
|
178
|
+
const url = upstream.replace("{fontstack}", encodeURIComponent(fontStack)).replace("{range}", range);
|
|
179
|
+
const response = await fetchRange(url, {
|
|
180
|
+
credentials: "omit",
|
|
181
|
+
headers: { Accept: "application/x-protobuf" },
|
|
182
|
+
redirect: "error",
|
|
183
|
+
signal: AbortSignal.timeout(3e4)
|
|
184
|
+
});
|
|
185
|
+
if (response.status === 404) return void 0;
|
|
186
|
+
if (response.status !== 200) {
|
|
187
|
+
throw new Error(`Glyph provider responded ${response.status} for ${fontStack} ${range}.`);
|
|
188
|
+
}
|
|
189
|
+
const length = Number(response.headers.get("content-length") ?? 0);
|
|
190
|
+
if (length > MAX_RANGE_BYTES) throw new Error(`Glyph range ${range} exceeds the size limit.`);
|
|
191
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
192
|
+
if (bytes.byteLength > MAX_RANGE_BYTES)
|
|
193
|
+
throw new Error(`Glyph range ${range} exceeds the size limit.`);
|
|
194
|
+
const temporary = `${file}.${randomUUID()}.tmp`;
|
|
195
|
+
try {
|
|
196
|
+
await writeFile(temporary, bytes, { flag: "wx" });
|
|
197
|
+
await rename(temporary, file);
|
|
198
|
+
} catch {
|
|
199
|
+
await rm(temporary, { force: true }).catch(() => void 0);
|
|
200
|
+
}
|
|
201
|
+
return bytes;
|
|
202
|
+
}
|
|
203
|
+
async function cacheDirectory(cwd, upstream) {
|
|
204
|
+
let current = resolve(cwd);
|
|
205
|
+
for (const segment of [...CACHE_SEGMENTS, digest(upstream)]) {
|
|
206
|
+
current = resolve(current, segment);
|
|
207
|
+
try {
|
|
208
|
+
const stats = await lstat(current);
|
|
209
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) {
|
|
210
|
+
throw new Error(`Glyph cache path is unsafe: ${current}`);
|
|
211
|
+
}
|
|
212
|
+
} catch (error) {
|
|
213
|
+
if (!hasCode(error, "ENOENT")) throw error;
|
|
214
|
+
await mkdir(current).catch((mkdirError) => {
|
|
215
|
+
if (!hasCode(mkdirError, "EEXIST")) throw mkdirError;
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return current;
|
|
220
|
+
}
|
|
221
|
+
function glyphResponse(bytes) {
|
|
222
|
+
if (!bytes) return notFound();
|
|
223
|
+
return new Response(new Uint8Array(bytes), {
|
|
224
|
+
headers: {
|
|
225
|
+
"Access-Control-Allow-Origin": "*",
|
|
226
|
+
"Cache-Control": "no-cache",
|
|
227
|
+
"Content-Type": "application/x-protobuf"
|
|
228
|
+
},
|
|
229
|
+
status: 200
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
function notFound() {
|
|
233
|
+
return new Response(JSON.stringify({ error: "Unknown glyph range." }), {
|
|
234
|
+
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
235
|
+
status: 404
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
function absoluteHttpUrl(value) {
|
|
239
|
+
if (!value) return void 0;
|
|
240
|
+
try {
|
|
241
|
+
const url = new URL(value.replace("{fontstack}", "stack").replace("{range}", "0-255"));
|
|
242
|
+
return url.protocol === "http:" || url.protocol === "https:" ? value : void 0;
|
|
243
|
+
} catch {
|
|
244
|
+
return void 0;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function digest(value) {
|
|
248
|
+
return createHash("sha256").update(value).digest("hex").slice(0, 32);
|
|
249
|
+
}
|
|
250
|
+
function hasCode(error, code) {
|
|
251
|
+
return Boolean(error && typeof error === "object" && "code" in error && error.code === code);
|
|
252
|
+
}
|
|
253
|
+
|
|
71
254
|
// src/local-tilesets.ts
|
|
72
|
-
import { randomUUID } from "crypto";
|
|
255
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
73
256
|
import { constants } from "fs";
|
|
74
|
-
import { chmod, copyFile, lstat, mkdir, open, readdir, realpath, rm, stat } from "fs/promises";
|
|
75
|
-
import { basename, resolve } from "path";
|
|
257
|
+
import { chmod, copyFile, lstat as lstat2, mkdir as mkdir2, open, readdir, realpath, rm as rm2, stat } from "fs/promises";
|
|
258
|
+
import { basename, resolve as resolve2 } from "path";
|
|
76
259
|
import { compareCodeUnits } from "@tileflow/core";
|
|
77
260
|
var minimumLocalPmtilesBytes = 127n;
|
|
78
261
|
var maximumLocalPmtilesBytes = 8000000000n;
|
|
@@ -83,14 +266,14 @@ async function prepareTileflowLocalTilesets(project, styles, options) {
|
|
|
83
266
|
if (!hasSources) {
|
|
84
267
|
return { dispose: async () => void 0, files: [], styles, watchPaths: [] };
|
|
85
268
|
}
|
|
86
|
-
const logicalProjectRoot =
|
|
269
|
+
const logicalProjectRoot = resolve2(options.cwd);
|
|
87
270
|
const projectRoot = await realpath(logicalProjectRoot).catch(() => logicalProjectRoot);
|
|
88
|
-
const snapshotStore =
|
|
271
|
+
const snapshotStore = resolve2(logicalProjectRoot, ".tileflow/cache/pmtiles-snapshots/v1");
|
|
89
272
|
await assertSafeSnapshotStore(logicalProjectRoot, snapshotStore);
|
|
90
273
|
await collectAbandonedSnapshotGenerations(snapshotStore);
|
|
91
|
-
const generationId = `snapshot-${process.pid}-${
|
|
92
|
-
const generationDirectory =
|
|
93
|
-
await
|
|
274
|
+
const generationId = `snapshot-${process.pid}-${randomUUID2().replaceAll("-", "")}`;
|
|
275
|
+
const generationDirectory = resolve2(snapshotStore, generationId);
|
|
276
|
+
await mkdir2(generationDirectory);
|
|
94
277
|
const bindings = /* @__PURE__ */ new Map();
|
|
95
278
|
const files = /* @__PURE__ */ new Map();
|
|
96
279
|
const snapshots = /* @__PURE__ */ new Map();
|
|
@@ -109,7 +292,7 @@ async function prepareTileflowLocalTilesets(project, styles, options) {
|
|
|
109
292
|
if (!isPathWithin(snapshotStore, generationDirectory)) {
|
|
110
293
|
throw new Error("Local PMTiles snapshot generation escaped its store.");
|
|
111
294
|
}
|
|
112
|
-
await
|
|
295
|
+
await rm2(generationDirectory, { force: true, recursive: true });
|
|
113
296
|
};
|
|
114
297
|
try {
|
|
115
298
|
for (const mapName of Object.keys(project.maps).sort(compareCodeUnits)) {
|
|
@@ -117,7 +300,7 @@ async function prepareTileflowLocalTilesets(project, styles, options) {
|
|
|
117
300
|
for (const [sourceId, source] of Object.entries(map.sources ?? {}).sort(
|
|
118
301
|
([left], [right]) => compareCodeUnits(left, right)
|
|
119
302
|
)) {
|
|
120
|
-
const requestedPath =
|
|
303
|
+
const requestedPath = resolve2(options.baseDirectory, source.local);
|
|
121
304
|
const sourcePath = await realpath(requestedPath).catch(() => requestedPath);
|
|
122
305
|
if (!isPathWithin(projectRoot, sourcePath)) {
|
|
123
306
|
throw localTilesetError(
|
|
@@ -126,7 +309,7 @@ async function prepareTileflowLocalTilesets(project, styles, options) {
|
|
|
126
309
|
"Local hosted tileset must stay inside the project root."
|
|
127
310
|
);
|
|
128
311
|
}
|
|
129
|
-
const sourceStat = await
|
|
312
|
+
const sourceStat = await lstat2(sourcePath).catch(() => null);
|
|
130
313
|
if (!sourceStat?.isFile() || sourceStat.isSymbolicLink()) {
|
|
131
314
|
throw localTilesetError(
|
|
132
315
|
"TF_LOCAL_TILESET_NOT_FOUND",
|
|
@@ -197,7 +380,7 @@ async function prepareTileflowLocalTilesets(project, styles, options) {
|
|
|
197
380
|
}
|
|
198
381
|
async function createLocalTilesetSnapshot(sourcePath, generationDirectory, index) {
|
|
199
382
|
const sourceHandle = await open(sourcePath, "r");
|
|
200
|
-
const snapshotPath =
|
|
383
|
+
const snapshotPath = resolve2(generationDirectory, `${index}.pmtiles`);
|
|
201
384
|
try {
|
|
202
385
|
const before = sourceIdentity(await sourceHandle.stat({ bigint: true }));
|
|
203
386
|
if (before.size < minimumLocalPmtilesBytes || before.size > maximumLocalPmtilesBytes) {
|
|
@@ -325,32 +508,32 @@ async function collectAbandonedSnapshotGenerations(store) {
|
|
|
325
508
|
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
326
509
|
const match = /^snapshot-(\d+)-[a-f0-9]{32}$/u.exec(entry.name);
|
|
327
510
|
if (!match?.[1] || processIsAlive(Number(match[1]))) continue;
|
|
328
|
-
const path =
|
|
329
|
-
if (isPathWithin(store, path)) await
|
|
511
|
+
const path = resolve2(store, entry.name);
|
|
512
|
+
if (isPathWithin(store, path)) await rm2(path, { force: true, recursive: true });
|
|
330
513
|
}
|
|
331
514
|
}
|
|
332
515
|
async function assertSafeSnapshotStore(projectRoot, store) {
|
|
333
516
|
const segments = [".tileflow", "cache", "pmtiles-snapshots", "v1"];
|
|
334
517
|
let current = projectRoot;
|
|
335
518
|
for (const segment of segments) {
|
|
336
|
-
current =
|
|
519
|
+
current = resolve2(current, segment);
|
|
337
520
|
try {
|
|
338
|
-
const value = await
|
|
521
|
+
const value = await lstat2(current);
|
|
339
522
|
if (!value.isDirectory() || value.isSymbolicLink()) {
|
|
340
523
|
throw new Error(`Local PMTiles snapshot path is unsafe: ${current}`);
|
|
341
524
|
}
|
|
342
525
|
} catch (error) {
|
|
343
526
|
if (!hasErrorCode(error, "ENOENT")) throw error;
|
|
344
|
-
await
|
|
527
|
+
await mkdir2(current).catch((mkdirError) => {
|
|
345
528
|
if (!hasErrorCode(mkdirError, "EEXIST")) throw mkdirError;
|
|
346
529
|
});
|
|
347
|
-
const created = await
|
|
530
|
+
const created = await lstat2(current);
|
|
348
531
|
if (!created.isDirectory() || created.isSymbolicLink()) {
|
|
349
532
|
throw new Error(`Local PMTiles snapshot path is unsafe: ${current}`);
|
|
350
533
|
}
|
|
351
534
|
}
|
|
352
535
|
}
|
|
353
|
-
if (
|
|
536
|
+
if (resolve2(current) !== resolve2(store)) {
|
|
354
537
|
throw new Error("Local PMTiles snapshot path escaped its project root.");
|
|
355
538
|
}
|
|
356
539
|
}
|
|
@@ -384,7 +567,7 @@ function hasErrorCode(error, code) {
|
|
|
384
567
|
}
|
|
385
568
|
|
|
386
569
|
// src/native-artifacts.ts
|
|
387
|
-
import { createHash } from "crypto";
|
|
570
|
+
import { createHash as createHash2 } from "crypto";
|
|
388
571
|
import {
|
|
389
572
|
convertFilter,
|
|
390
573
|
validateStyleMin
|
|
@@ -982,8 +1165,8 @@ function lowerTileflowNativeCompiledStyles(input) {
|
|
|
982
1165
|
transformations.push({
|
|
983
1166
|
map,
|
|
984
1167
|
theme,
|
|
985
|
-
inputStyleSha256:
|
|
986
|
-
loweredStyleSha256:
|
|
1168
|
+
inputStyleSha256: createHash2("sha256").update(serializeCanonicalJson(original)).digest("hex"),
|
|
1169
|
+
loweredStyleSha256: createHash2("sha256").update(serializeCanonicalJson(lowered.style)).digest("hex"),
|
|
987
1170
|
inputLayers: lowered.inputLayers,
|
|
988
1171
|
outputLayers: lowered.outputLayers,
|
|
989
1172
|
projection: lowered.projection,
|
|
@@ -1097,7 +1280,7 @@ function isNativeFontAsset(asset) {
|
|
|
1097
1280
|
if (!/\.(?:ttf|otf)$/u.test(asset.fileName) || !["00010000", "4f54544f"].includes(signature))
|
|
1098
1281
|
return false;
|
|
1099
1282
|
const expectedHash = /-([a-f0-9]{64})\.(?:ttf|otf)$/u.exec(asset.fileName)?.[1];
|
|
1100
|
-
return expectedHash ===
|
|
1283
|
+
return expectedHash === createHash2("sha256").update(bytes).digest("hex");
|
|
1101
1284
|
}
|
|
1102
1285
|
function assertTileflowNativeGeneratedStyle(style, map, theme) {
|
|
1103
1286
|
const issues = validateTileflowNativePreparedStyle(style, { documentUrl: documentUrl(map, theme) });
|
|
@@ -1171,7 +1354,7 @@ function validNativeSprites(map, assets) {
|
|
|
1171
1354
|
// src/session.ts
|
|
1172
1355
|
import { watch } from "chokidar";
|
|
1173
1356
|
import { realpathSync, statSync } from "fs";
|
|
1174
|
-
import { basename as basename2, dirname, extname, isAbsolute, relative, resolve as
|
|
1357
|
+
import { basename as basename2, dirname, extname, isAbsolute, relative, resolve as resolve3, sep, win32 } from "path";
|
|
1175
1358
|
import { tileflowIconMetadataFileName } from "@tileflow/core";
|
|
1176
1359
|
import { TileflowNativeCompatibilityError as TileflowNativeCompatibilityError2 } from "@tileflow/core/native-profile";
|
|
1177
1360
|
var tileflowArtifactSessionSchemaVersion = 1;
|
|
@@ -1224,13 +1407,13 @@ var TileflowArtifactSessionImpl = class {
|
|
|
1224
1407
|
#watchedArtifactDirectories = /* @__PURE__ */ new Map();
|
|
1225
1408
|
#watchedArtifactPaths = /* @__PURE__ */ new Set();
|
|
1226
1409
|
constructor(options, buildArtifacts, discoverWatchPaths) {
|
|
1227
|
-
this.#cwd =
|
|
1228
|
-
const configPath =
|
|
1229
|
-
this.#configPath =
|
|
1410
|
+
this.#cwd = resolve3(options.cwd ?? process.cwd());
|
|
1411
|
+
const configPath = resolve3(this.#cwd, options.config ?? "tileflow.config.ts");
|
|
1412
|
+
this.#configPath = resolve3(canonicalWatchPath(dirname(configPath)), basename2(configPath));
|
|
1230
1413
|
this.#debounceMs = Math.max(0, Math.min(options.debounceMs ?? 75, 1e3));
|
|
1231
1414
|
this.#watchEnabled = options.watch ?? false;
|
|
1232
1415
|
this.#ignoredPaths = (options.ignoredPaths ?? []).map(
|
|
1233
|
-
(path) => canonicalWatchPath(
|
|
1416
|
+
(path) => canonicalWatchPath(resolve3(this.#cwd, path))
|
|
1234
1417
|
);
|
|
1235
1418
|
this.#buildArtifacts = buildArtifacts;
|
|
1236
1419
|
this.#discoverWatchPaths = discoverWatchPaths;
|
|
@@ -1463,7 +1646,7 @@ var TileflowArtifactSessionImpl = class {
|
|
|
1463
1646
|
}
|
|
1464
1647
|
#updateArtifactWatchPaths(paths) {
|
|
1465
1648
|
if (!this.#watcher) return;
|
|
1466
|
-
const next = new Set(paths.map((path) => canonicalWatchPath(
|
|
1649
|
+
const next = new Set(paths.map((path) => canonicalWatchPath(resolve3(this.#cwd, path))));
|
|
1467
1650
|
const previous = this.#watchedArtifactPaths;
|
|
1468
1651
|
this.#watchedArtifactPaths = next;
|
|
1469
1652
|
const previousDirectories = this.#watchedArtifactDirectories;
|
|
@@ -1528,7 +1711,7 @@ async function disposeArtifacts(artifacts) {
|
|
|
1528
1711
|
await dispose?.();
|
|
1529
1712
|
}
|
|
1530
1713
|
function isSameOrInside(root, candidate) {
|
|
1531
|
-
const path = relative(
|
|
1714
|
+
const path = relative(resolve3(root), resolve3(candidate));
|
|
1532
1715
|
return path === "" || !isAbsolute(path) && path !== ".." && !path.startsWith(`..${sep}`);
|
|
1533
1716
|
}
|
|
1534
1717
|
function directoryModificationTime(path) {
|
|
@@ -1546,15 +1729,15 @@ function resolveRawWatchPath(path, details) {
|
|
|
1546
1729
|
const watchedPath = details.watchedPath;
|
|
1547
1730
|
if (typeof watchedPath !== "string" || !isAbsolute(watchedPath)) return void 0;
|
|
1548
1731
|
return canonicalWatchPath(
|
|
1549
|
-
basename2(watchedPath) === path ? watchedPath :
|
|
1732
|
+
basename2(watchedPath) === path ? watchedPath : resolve3(watchedPath, path)
|
|
1550
1733
|
);
|
|
1551
1734
|
}
|
|
1552
1735
|
function canonicalWatchPath(path) {
|
|
1553
|
-
const resolved =
|
|
1736
|
+
const resolved = resolve3(path);
|
|
1554
1737
|
let ancestor = resolved;
|
|
1555
1738
|
while (true) {
|
|
1556
1739
|
try {
|
|
1557
|
-
return
|
|
1740
|
+
return resolve3(realpathSync.native(ancestor), relative(ancestor, resolved));
|
|
1558
1741
|
} catch {
|
|
1559
1742
|
const parent = dirname(ancestor);
|
|
1560
1743
|
if (parent === ancestor) return resolved;
|
|
@@ -1661,15 +1844,15 @@ function removeSemanticResolutionPath(message, path) {
|
|
|
1661
1844
|
return message.replace(` at ${path}:`, ":");
|
|
1662
1845
|
}
|
|
1663
1846
|
function localPathAliases(path) {
|
|
1664
|
-
return [.../* @__PURE__ */ new Set([
|
|
1847
|
+
return [.../* @__PURE__ */ new Set([resolve3(path), canonicalPath(path)])].sort(
|
|
1665
1848
|
(left, right) => right.length - left.length
|
|
1666
1849
|
);
|
|
1667
1850
|
}
|
|
1668
1851
|
function canonicalPath(path) {
|
|
1669
1852
|
try {
|
|
1670
|
-
return realpathSync.native(
|
|
1853
|
+
return realpathSync.native(resolve3(path));
|
|
1671
1854
|
} catch {
|
|
1672
|
-
return
|
|
1855
|
+
return resolve3(path);
|
|
1673
1856
|
}
|
|
1674
1857
|
}
|
|
1675
1858
|
function normalizeDiagnostics(diagnostics) {
|
|
@@ -1705,7 +1888,7 @@ function boundDiagnosticText(value, limit) {
|
|
|
1705
1888
|
}
|
|
1706
1889
|
|
|
1707
1890
|
// src/hosted-native-artifacts.ts
|
|
1708
|
-
import { createHash as
|
|
1891
|
+
import { createHash as createHash3 } from "crypto";
|
|
1709
1892
|
import { serializeCanonicalJson as serializeCanonicalJson3 } from "@tileflow/core";
|
|
1710
1893
|
import {
|
|
1711
1894
|
inferTileflowDataRequirements,
|
|
@@ -1835,7 +2018,7 @@ function finalizeNativeHostedProvenance(input, lowered, changes) {
|
|
|
1835
2018
|
}
|
|
1836
2019
|
|
|
1837
2020
|
// src/hosted-native-artifacts.ts
|
|
1838
|
-
var
|
|
2021
|
+
var digest2 = (value) => createHash3("sha256").update(serializeCanonicalJson3(value)).digest("hex");
|
|
1839
2022
|
var invalidSource = () => new TileflowNativeCompatibilityError4([
|
|
1840
2023
|
createTileflowNativeDiagnostic3("NATIVE_UNSUPPORTED_SOURCE", "/sources")
|
|
1841
2024
|
]);
|
|
@@ -1881,15 +2064,15 @@ async function prepareTileflowHostedNativeDeployment(input) {
|
|
|
1881
2064
|
if (!theme) throw invalidSource();
|
|
1882
2065
|
mapBuild.themes[name] = {
|
|
1883
2066
|
...theme,
|
|
1884
|
-
styleSha256:
|
|
2067
|
+
styleSha256: digest2(style),
|
|
1885
2068
|
dataRequirements: inferTileflowDataRequirements(style),
|
|
1886
2069
|
sourceRequirements: inferTileflowSourceRequirements(style)
|
|
1887
2070
|
};
|
|
1888
2071
|
}
|
|
1889
2072
|
const transformations = lowered.transformations.map((item) => ({
|
|
1890
2073
|
...item,
|
|
1891
|
-
inputStyleSha256:
|
|
1892
|
-
loweredStyleSha256:
|
|
2074
|
+
inputStyleSha256: digest2(webStyles[item.theme]),
|
|
2075
|
+
loweredStyleSha256: digest2({
|
|
1893
2076
|
...lowered.styles[input.mapId][item.theme],
|
|
1894
2077
|
sources: webStyles[item.theme].sources
|
|
1895
2078
|
})
|
|
@@ -1904,7 +2087,7 @@ async function prepareTileflowHostedNativeDeployment(input) {
|
|
|
1904
2087
|
web: { buildManifest: input.buildManifest, styles: webStyles },
|
|
1905
2088
|
native: {
|
|
1906
2089
|
buildManifest: nativeBuild,
|
|
1907
|
-
buildRecord: createTileflowNativeBuildRecord(
|
|
2090
|
+
buildRecord: createTileflowNativeBuildRecord(digest2(nativeBuild), transformations),
|
|
1908
2091
|
styles: projected
|
|
1909
2092
|
}
|
|
1910
2093
|
}
|
|
@@ -2032,7 +2215,10 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
|
|
|
2032
2215
|
throw error;
|
|
2033
2216
|
});
|
|
2034
2217
|
const assets = [...prepared.assets, ...preparedFonts.assets];
|
|
2035
|
-
const
|
|
2218
|
+
const lineBackgroundGlyphs = renderer === "native" || options.target === "production" ? { providers: {}, styles: preparedFonts.styles } : prepareTileflowLineBackgroundGlyphs(preparedFonts.styles, {
|
|
2219
|
+
assetBaseUrl: resolveRendererAssetBaseUrl(options)
|
|
2220
|
+
});
|
|
2221
|
+
const styles = renderer === "native" ? prepareTileflowNativeStyles(preparedFonts.styles, assets) : lineBackgroundGlyphs.styles;
|
|
2036
2222
|
const provenance = await createTileflowBuildProvenance(prepared.cwd);
|
|
2037
2223
|
const buildManifest = await createTileflowMapBuildManifest(
|
|
2038
2224
|
Object.fromEntries(
|
|
@@ -2092,6 +2278,7 @@ async function createTileflowArtifactPlan(prepared, options = {}) {
|
|
|
2092
2278
|
manifest: stableManifest,
|
|
2093
2279
|
project: prepared.project,
|
|
2094
2280
|
...localTilesets.files.length > 0 ? { localTilesets: localTilesets.files } : {},
|
|
2281
|
+
...Object.keys(lineBackgroundGlyphs.providers).length > 0 ? { lineBackgroundGlyphs: lineBackgroundGlyphs.providers } : {},
|
|
2095
2282
|
...inspected ? { styleInspections: inspected.inspections } : {},
|
|
2096
2283
|
styles,
|
|
2097
2284
|
watchPaths: uniqueStrings([...inputs.files, ...inputs.directories])
|
|
@@ -2292,12 +2479,12 @@ function getMapBuildAssets(mapName, assets, fontAssets) {
|
|
|
2292
2479
|
);
|
|
2293
2480
|
}
|
|
2294
2481
|
function hashBytes(source) {
|
|
2295
|
-
return
|
|
2482
|
+
return createHash4("sha256").update(typeof source === "string" ? Buffer.from(source, "utf8") : Buffer.from(source)).digest("hex");
|
|
2296
2483
|
}
|
|
2297
2484
|
async function createTileflowBuildProvenance(cwd) {
|
|
2298
|
-
const projectDirectory =
|
|
2485
|
+
const projectDirectory = resolve4(cwd);
|
|
2299
2486
|
const projectRequire = createRequire(
|
|
2300
|
-
|
|
2487
|
+
resolve4(projectDirectory, "__tileflow_build_provenance__.cjs")
|
|
2301
2488
|
);
|
|
2302
2489
|
const toolRequire = createRequire(import.meta.url);
|
|
2303
2490
|
const packages = {};
|
|
@@ -2331,7 +2518,7 @@ async function readPackageVersion(expectedName, path) {
|
|
|
2331
2518
|
if (!path) throw new Error(`Unable to resolve build package provenance for ${expectedName}.`);
|
|
2332
2519
|
let parsed;
|
|
2333
2520
|
try {
|
|
2334
|
-
parsed = JSON.parse(await
|
|
2521
|
+
parsed = JSON.parse(await readFile2(path, "utf8"));
|
|
2335
2522
|
} catch {
|
|
2336
2523
|
throw new Error(`Unable to read build package provenance for ${expectedName}.`);
|
|
2337
2524
|
}
|
|
@@ -2354,7 +2541,7 @@ async function findNearestLockfile(cwd) {
|
|
|
2354
2541
|
try {
|
|
2355
2542
|
return {
|
|
2356
2543
|
format: candidate.format,
|
|
2357
|
-
source: await
|
|
2544
|
+
source: await readFile2(resolve4(directory, candidate.fileName))
|
|
2358
2545
|
};
|
|
2359
2546
|
} catch (error) {
|
|
2360
2547
|
if (!hasErrorCode2(error, "ENOENT")) throw error;
|
|
@@ -2430,7 +2617,7 @@ async function writeTileflowArtifactPlan(artifacts, options) {
|
|
|
2430
2617
|
const outDir = artifacts.nativeBuild ? `${options.outDir.replace(/[\\/]$/u, "")}/native` : options.outDir;
|
|
2431
2618
|
const output = await prepareTileflowOutputDirectory(cwd, outDir);
|
|
2432
2619
|
const files = getTileflowArtifactFiles(artifacts);
|
|
2433
|
-
await assertTileflowSelfHostedManifestTarget(
|
|
2620
|
+
await assertTileflowSelfHostedManifestTarget(resolve4(output.outDir, "manifest.json"), options);
|
|
2434
2621
|
await commitTileflowArtifactFiles(output, files);
|
|
2435
2622
|
}
|
|
2436
2623
|
function assertNoLocalTilesetsForProduction(artifacts) {
|
|
@@ -2443,7 +2630,7 @@ async function assertTileflowSelfHostedManifestTarget(manifestPath, options = {}
|
|
|
2443
2630
|
if (options.overwriteHostedManifest) return;
|
|
2444
2631
|
let source;
|
|
2445
2632
|
try {
|
|
2446
|
-
source = await
|
|
2633
|
+
source = await readFile2(resolve4(manifestPath), "utf8");
|
|
2447
2634
|
} catch (error) {
|
|
2448
2635
|
if (hasErrorCode2(error, "ENOENT")) return;
|
|
2449
2636
|
throw error;
|
|
@@ -2451,7 +2638,7 @@ async function assertTileflowSelfHostedManifestTarget(manifestPath, options = {}
|
|
|
2451
2638
|
try {
|
|
2452
2639
|
const manifest = parseTileflowRuntimeManifest(JSON.parse(source));
|
|
2453
2640
|
if (isHostedRuntimeManifest(manifest)) {
|
|
2454
|
-
throw new TileflowHostedManifestOverwriteError(
|
|
2641
|
+
throw new TileflowHostedManifestOverwriteError(resolve4(manifestPath));
|
|
2455
2642
|
}
|
|
2456
2643
|
} catch (error) {
|
|
2457
2644
|
if (error instanceof TileflowHostedManifestOverwriteError) throw error;
|
|
@@ -2499,15 +2686,15 @@ async function commitTileflowArtifactFiles(output, files) {
|
|
|
2499
2686
|
...staleNames,
|
|
2500
2687
|
tileflowArtifactInventoryFileName
|
|
2501
2688
|
]);
|
|
2502
|
-
const stageDir = await mkdtemp(
|
|
2503
|
-
const newDir =
|
|
2504
|
-
const backupDir =
|
|
2689
|
+
const stageDir = await mkdtemp(resolve4(outDir, ".tileflow-stage-"));
|
|
2690
|
+
const newDir = resolve4(stageDir, "new");
|
|
2691
|
+
const backupDir = resolve4(stageDir, "backup");
|
|
2505
2692
|
const backedUp = /* @__PURE__ */ new Set();
|
|
2506
2693
|
const installed = /* @__PURE__ */ new Set();
|
|
2507
2694
|
try {
|
|
2508
2695
|
for (const file of stagedFiles) {
|
|
2509
2696
|
const stagePath = managedPath(newDir, file.fileName);
|
|
2510
|
-
await
|
|
2697
|
+
await mkdir3(dirname2(stagePath), { recursive: true });
|
|
2511
2698
|
await writeFileDurably(stagePath, file.source);
|
|
2512
2699
|
}
|
|
2513
2700
|
for (const name of affectedNames) {
|
|
@@ -2515,7 +2702,7 @@ async function commitTileflowArtifactFiles(output, files) {
|
|
|
2515
2702
|
const targetPath = managedPath(outDir, name);
|
|
2516
2703
|
if (!await isFile(targetPath)) continue;
|
|
2517
2704
|
const backupPath = managedPath(backupDir, name);
|
|
2518
|
-
await
|
|
2705
|
+
await mkdir3(dirname2(backupPath), { recursive: true });
|
|
2519
2706
|
await copyFile2(targetPath, backupPath);
|
|
2520
2707
|
backedUp.add(name);
|
|
2521
2708
|
}
|
|
@@ -2529,8 +2716,8 @@ async function commitTileflowArtifactFiles(output, files) {
|
|
|
2529
2716
|
)) {
|
|
2530
2717
|
const sourcePath = managedPath(newDir, name);
|
|
2531
2718
|
const targetPath = managedPath(outDir, name);
|
|
2532
|
-
await
|
|
2533
|
-
await
|
|
2719
|
+
await mkdir3(dirname2(targetPath), { recursive: true });
|
|
2720
|
+
await rename2(sourcePath, targetPath);
|
|
2534
2721
|
installed.add(name);
|
|
2535
2722
|
}
|
|
2536
2723
|
for (const name of staleNames) {
|
|
@@ -2538,13 +2725,13 @@ async function commitTileflowArtifactFiles(output, files) {
|
|
|
2538
2725
|
}
|
|
2539
2726
|
const stagedInventoryPath = managedPath(newDir, tileflowArtifactInventoryFileName);
|
|
2540
2727
|
const inventoryPath = managedPath(outDir, tileflowArtifactInventoryFileName);
|
|
2541
|
-
await
|
|
2728
|
+
await rename2(stagedInventoryPath, inventoryPath);
|
|
2542
2729
|
installed.add(tileflowArtifactInventoryFileName);
|
|
2543
2730
|
} catch (error) {
|
|
2544
2731
|
await rollbackManagedFiles(outDir, backupDir, affectedNames, backedUp, installed);
|
|
2545
2732
|
throw error;
|
|
2546
2733
|
} finally {
|
|
2547
|
-
await
|
|
2734
|
+
await rm3(stageDir, { force: true, recursive: true });
|
|
2548
2735
|
}
|
|
2549
2736
|
}
|
|
2550
2737
|
function getArtifactGeneration(files) {
|
|
@@ -2576,7 +2763,7 @@ async function rollbackManagedFiles(outDir, backupDir, affectedNames, backedUp,
|
|
|
2576
2763
|
await removeManagedFile(targetPath);
|
|
2577
2764
|
}
|
|
2578
2765
|
if (backedUp.has(name)) {
|
|
2579
|
-
await
|
|
2766
|
+
await mkdir3(dirname2(targetPath), { recursive: true });
|
|
2580
2767
|
await copyFile2(managedPath(backupDir, name), targetPath);
|
|
2581
2768
|
}
|
|
2582
2769
|
} catch (error) {
|
|
@@ -2591,7 +2778,7 @@ async function readTileflowArtifactInventory(outDir) {
|
|
|
2591
2778
|
const inventoryPath = managedPath(outDir, tileflowArtifactInventoryFileName);
|
|
2592
2779
|
let source;
|
|
2593
2780
|
try {
|
|
2594
|
-
source = await
|
|
2781
|
+
source = await readFile2(inventoryPath, "utf8");
|
|
2595
2782
|
} catch (error) {
|
|
2596
2783
|
if (hasErrorCode2(error, "ENOENT")) return void 0;
|
|
2597
2784
|
throw error;
|
|
@@ -2625,7 +2812,7 @@ async function readTileflowArtifactInventory(outDir) {
|
|
|
2625
2812
|
}
|
|
2626
2813
|
async function assertManagedTargetIsSafe(outDir, fileName) {
|
|
2627
2814
|
assertSafeManagedFileName(fileName);
|
|
2628
|
-
const rootStats = await
|
|
2815
|
+
const rootStats = await lstat3(outDir);
|
|
2629
2816
|
if (rootStats.isSymbolicLink()) {
|
|
2630
2817
|
throw new Error(`Tileflow refuses to write through a symbolic link: ${outDir}`);
|
|
2631
2818
|
}
|
|
@@ -2635,9 +2822,9 @@ async function assertManagedTargetIsSafe(outDir, fileName) {
|
|
|
2635
2822
|
const segments = fileName.split("/");
|
|
2636
2823
|
let current = outDir;
|
|
2637
2824
|
for (let index = 0; index < segments.length; index += 1) {
|
|
2638
|
-
current =
|
|
2825
|
+
current = resolve4(current, segments[index]);
|
|
2639
2826
|
try {
|
|
2640
|
-
const stats = await
|
|
2827
|
+
const stats = await lstat3(current);
|
|
2641
2828
|
if (stats.isSymbolicLink()) {
|
|
2642
2829
|
throw new Error(`Tileflow refuses to write through a symbolic link: ${fileName}`);
|
|
2643
2830
|
}
|
|
@@ -2654,12 +2841,12 @@ async function assertManagedTargetIsSafe(outDir, fileName) {
|
|
|
2654
2841
|
}
|
|
2655
2842
|
}
|
|
2656
2843
|
async function prepareTileflowOutputDirectory(cwd, requestedOutDir) {
|
|
2657
|
-
const logicalRoot =
|
|
2658
|
-
const logicalOutDir =
|
|
2844
|
+
const logicalRoot = resolve4(cwd);
|
|
2845
|
+
const logicalOutDir = resolve4(logicalRoot, requestedOutDir);
|
|
2659
2846
|
if (!isPathWithin(logicalRoot, logicalOutDir)) {
|
|
2660
2847
|
throw new Error(`Tileflow artifact output escapes its working directory: ${logicalOutDir}`);
|
|
2661
2848
|
}
|
|
2662
|
-
const rootStats = await
|
|
2849
|
+
const rootStats = await lstat3(logicalRoot);
|
|
2663
2850
|
if (!rootStats.isDirectory()) {
|
|
2664
2851
|
throw new Error(`Tileflow artifact working directory is not a directory: ${logicalRoot}`);
|
|
2665
2852
|
}
|
|
@@ -2668,14 +2855,14 @@ async function prepareTileflowOutputDirectory(cwd, requestedOutDir) {
|
|
|
2668
2855
|
const segments = relativeOutDir ? relativeOutDir.split(sep2) : [];
|
|
2669
2856
|
let current = rootDir;
|
|
2670
2857
|
for (const segment of segments) {
|
|
2671
|
-
current =
|
|
2858
|
+
current = resolve4(current, segment);
|
|
2672
2859
|
let stats;
|
|
2673
2860
|
try {
|
|
2674
|
-
stats = await
|
|
2861
|
+
stats = await lstat3(current);
|
|
2675
2862
|
} catch (error) {
|
|
2676
2863
|
if (!hasErrorCode2(error, "ENOENT")) throw error;
|
|
2677
|
-
await
|
|
2678
|
-
stats = await
|
|
2864
|
+
await mkdir3(current);
|
|
2865
|
+
stats = await lstat3(current);
|
|
2679
2866
|
}
|
|
2680
2867
|
if (stats.isSymbolicLink()) {
|
|
2681
2868
|
throw new Error(`Tileflow refuses to write through a symbolic link: ${current}`);
|
|
@@ -2693,7 +2880,7 @@ async function assertTileflowOutputDirectoryIsSafe(output) {
|
|
|
2693
2880
|
if (!isPathWithin(output.rootDir, output.outDir)) {
|
|
2694
2881
|
throw new Error(`Tileflow artifact output escapes its working directory: ${output.outDir}`);
|
|
2695
2882
|
}
|
|
2696
|
-
const stats = await
|
|
2883
|
+
const stats = await lstat3(output.outDir);
|
|
2697
2884
|
if (stats.isSymbolicLink()) {
|
|
2698
2885
|
throw new Error(`Tileflow refuses to write through a symbolic link: ${output.outDir}`);
|
|
2699
2886
|
}
|
|
@@ -2722,7 +2909,7 @@ function assertTileflowArtifactFileName(fileName) {
|
|
|
2722
2909
|
}
|
|
2723
2910
|
function managedPath(root, fileName) {
|
|
2724
2911
|
assertSafeManagedFileName(fileName);
|
|
2725
|
-
const path =
|
|
2912
|
+
const path = resolve4(root, ...fileName.split("/"));
|
|
2726
2913
|
if (!isPathWithin(root, path)) {
|
|
2727
2914
|
throw new Error(`Unsafe Tileflow artifact file name: ${fileName}`);
|
|
2728
2915
|
}
|
|
@@ -2739,7 +2926,7 @@ async function writeFileDurably(path, source) {
|
|
|
2739
2926
|
}
|
|
2740
2927
|
async function isFile(path) {
|
|
2741
2928
|
try {
|
|
2742
|
-
return (await
|
|
2929
|
+
return (await lstat3(path)).isFile();
|
|
2743
2930
|
} catch (error) {
|
|
2744
2931
|
if (hasErrorCode2(error, "ENOENT")) return false;
|
|
2745
2932
|
throw error;
|
|
@@ -2747,7 +2934,7 @@ async function isFile(path) {
|
|
|
2747
2934
|
}
|
|
2748
2935
|
async function removeManagedFile(path) {
|
|
2749
2936
|
try {
|
|
2750
|
-
const stats = await
|
|
2937
|
+
const stats = await lstat3(path);
|
|
2751
2938
|
if (!stats.isFile()) throw new Error(`Refusing to remove non-file artifact target: ${path}`);
|
|
2752
2939
|
await unlink(path);
|
|
2753
2940
|
} catch (error) {
|
|
@@ -2755,7 +2942,7 @@ async function removeManagedFile(path) {
|
|
|
2755
2942
|
}
|
|
2756
2943
|
}
|
|
2757
2944
|
function hashArtifactGeneration(files) {
|
|
2758
|
-
const hash =
|
|
2945
|
+
const hash = createHash4("sha256");
|
|
2759
2946
|
for (const file of files) {
|
|
2760
2947
|
const source = typeof file.source === "string" ? Buffer.from(file.source, "utf8") : Buffer.from(file.source);
|
|
2761
2948
|
hash.update(`${file.fileName}\0${file.contentType}\0${source.byteLength}\0`, "utf8");
|
|
@@ -2787,12 +2974,12 @@ function hasErrorCode2(error, code) {
|
|
|
2787
2974
|
return Boolean(error && typeof error === "object" && "code" in error && error.code === code);
|
|
2788
2975
|
}
|
|
2789
2976
|
function canonicalInputPath(path) {
|
|
2790
|
-
const resolved =
|
|
2977
|
+
const resolved = resolve4(path);
|
|
2791
2978
|
try {
|
|
2792
2979
|
return realpathSync2.native(resolved);
|
|
2793
2980
|
} catch {
|
|
2794
2981
|
try {
|
|
2795
|
-
return
|
|
2982
|
+
return resolve4(realpathSync2.native(dirname2(resolved)), resolved.split(/[\\/]/).at(-1));
|
|
2796
2983
|
} catch {
|
|
2797
2984
|
return resolved;
|
|
2798
2985
|
}
|
|
@@ -2800,6 +2987,10 @@ function canonicalInputPath(path) {
|
|
|
2800
2987
|
}
|
|
2801
2988
|
|
|
2802
2989
|
export {
|
|
2990
|
+
tileflowLineBackgroundGlyphRoute,
|
|
2991
|
+
usesTileflowLineBackgroundGlyphs,
|
|
2992
|
+
parseTileflowLineBackgroundGlyphPath,
|
|
2993
|
+
createTileflowLineBackgroundGlyphResponder,
|
|
2803
2994
|
prepareTileflowLocalTilesets,
|
|
2804
2995
|
tileflowArtifactSessionSchemaVersion,
|
|
2805
2996
|
createTileflowArtifactDiagnostics,
|
|
@@ -168,7 +168,7 @@ function renderTileflowPreviewHtml(preview, basePath, initialStatus, isSemanticP
|
|
|
168
168
|
body { font-family: ui-sans-serif, system-ui, sans-serif; }
|
|
169
169
|
#map {
|
|
170
170
|
--tileflow-globe-radius: 220px;
|
|
171
|
-
background-color: #2F5070;
|
|
171
|
+
background-color: var(--tileflow-space, #2F5070);
|
|
172
172
|
background-image:
|
|
173
173
|
radial-gradient(circle at 18% 24%, rgba(225, 240, 250, 0.34) 0 1px, transparent 1.4px),
|
|
174
174
|
radial-gradient(circle at 72% 62%, rgba(225, 240, 250, 0.22) 0 1px, transparent 1.3px),
|
|
@@ -191,12 +191,12 @@ function renderTileflowPreviewHtml(preview, basePath, initialStatus, isSemanticP
|
|
|
191
191
|
top: 50%;
|
|
192
192
|
width: calc(var(--tileflow-globe-radius) * 2);
|
|
193
193
|
height: calc(var(--tileflow-globe-radius) * 2);
|
|
194
|
-
border: 1px solid rgba(248, 252, 255, 0.88);
|
|
194
|
+
border: 1px solid var(--tileflow-rim-line, rgba(248, 252, 255, 0.88));
|
|
195
195
|
border-radius: 50%;
|
|
196
196
|
box-shadow:
|
|
197
|
-
0 0 9px 3px rgba(248, 252, 255, 0.9),
|
|
198
|
-
0 0 28px 10px rgba(176, 220, 246, 0.52),
|
|
199
|
-
0 0 58px 20px rgba(132, 195, 232, 0.2);
|
|
197
|
+
0 0 9px 3px var(--tileflow-rim-core, rgba(248, 252, 255, 0.9)),
|
|
198
|
+
0 0 28px 10px var(--tileflow-rim-glow, rgba(176, 220, 246, 0.52)),
|
|
199
|
+
0 0 58px 20px var(--tileflow-rim-haze, rgba(132, 195, 232, 0.2));
|
|
200
200
|
pointer-events: none;
|
|
201
201
|
transform: translate(-50%, -50%);
|
|
202
202
|
}
|
|
@@ -233,7 +233,8 @@ function renderTileflowPreviewHtml(preview, basePath, initialStatus, isSemanticP
|
|
|
233
233
|
white-space: pre-wrap;
|
|
234
234
|
}
|
|
235
235
|
.maplibregl-ctrl-group .tileflow-3d-toggle,
|
|
236
|
-
.maplibregl-ctrl-group .tileflow-tree-toggle
|
|
236
|
+
.maplibregl-ctrl-group .tileflow-tree-toggle,
|
|
237
|
+
.maplibregl-ctrl-group .tileflow-theme-toggle {
|
|
237
238
|
width: auto;
|
|
238
239
|
min-width: 58px;
|
|
239
240
|
padding: 0 9px;
|
|
@@ -247,7 +248,8 @@ function renderTileflowPreviewHtml(preview, basePath, initialStatus, isSemanticP
|
|
|
247
248
|
color: #174EA6;
|
|
248
249
|
}
|
|
249
250
|
.maplibregl-ctrl-group .tileflow-3d-toggle:hover,
|
|
250
|
-
.maplibregl-ctrl-group .tileflow-tree-toggle:hover
|
|
251
|
+
.maplibregl-ctrl-group .tileflow-tree-toggle:hover,
|
|
252
|
+
.maplibregl-ctrl-group .tileflow-theme-toggle:hover {
|
|
251
253
|
background-color: #F1F3F4;
|
|
252
254
|
}
|
|
253
255
|
</style>
|
|
@@ -275,6 +277,8 @@ function renderTileflowPreviewHtml(preview, basePath, initialStatus, isSemanticP
|
|
|
275
277
|
const previewLabel = ${JSON.stringify(preview?.label)};
|
|
276
278
|
const styleUrl = ${JSON.stringify(styleUrl)};
|
|
277
279
|
const previewMapOptions = ${JSON.stringify(mapOptions)};
|
|
280
|
+
const previewTheme = ${serializeInlineJson(preview?.themeName ?? null)};
|
|
281
|
+
const previewThemes = ${serializeInlineJson(preview?.themeNames ?? [])};
|
|
278
282
|
const isSemanticPreview = ${JSON.stringify(isSemanticPreview)};
|
|
279
283
|
const previewFontFaces = ${serializeInlineJson(fontFaces)};
|
|
280
284
|
const treeSearchParameters = new URL(location.href).searchParams;
|
|
@@ -985,6 +989,30 @@ function renderTileflowPreviewHtml(preview, basePath, initialStatus, isSemanticP
|
|
|
985
989
|
);
|
|
986
990
|
container.classList.add("tileflow-globe");
|
|
987
991
|
container.style.setProperty("--tileflow-globe-radius", radius.toFixed(2) + "px");
|
|
992
|
+
applyAtmosphereBackdrop(map, container);
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// Uses the map's declared atmosphere for the preview's space and rim, so a themed globe shows
|
|
996
|
+
// its own colours; maps without one keep the default backdrop.
|
|
997
|
+
function applyAtmosphereBackdrop(map, container) {
|
|
998
|
+
const atmosphere = map.getStyle?.()?.metadata?.["tileflow:atmosphere"];
|
|
999
|
+
const rgba = (hex, alpha) => {
|
|
1000
|
+
const match = /^#([0-9a-f]{6})$/i.exec(String(hex ?? ""));
|
|
1001
|
+
if (!match) return undefined;
|
|
1002
|
+
const value = Number.parseInt(match[1], 16);
|
|
1003
|
+
return "rgba(" + (value >> 16) + ", " + ((value >> 8) & 255) + ", " + (value & 255) + ", " + alpha + ")";
|
|
1004
|
+
};
|
|
1005
|
+
const properties = {
|
|
1006
|
+
"--tileflow-space": rgba(atmosphere?.spaceColor, 1),
|
|
1007
|
+
"--tileflow-rim-line": rgba(atmosphere?.horizonColor, 0.88),
|
|
1008
|
+
"--tileflow-rim-core": rgba(atmosphere?.horizonColor, 0.9),
|
|
1009
|
+
"--tileflow-rim-glow": rgba(atmosphere?.horizonColor, 0.52),
|
|
1010
|
+
"--tileflow-rim-haze": rgba(atmosphere?.skyColor, 0.35),
|
|
1011
|
+
};
|
|
1012
|
+
for (const [name, value] of Object.entries(properties)) {
|
|
1013
|
+
if (value) container.style.setProperty(name, value);
|
|
1014
|
+
else container.style.removeProperty(name);
|
|
1015
|
+
}
|
|
988
1016
|
}
|
|
989
1017
|
|
|
990
1018
|
function createBuildingWireframeLayer(map, styleLayer) {
|
|
@@ -3777,6 +3805,38 @@ function renderTileflowPreviewHtml(preview, basePath, initialStatus, isSemanticP
|
|
|
3777
3805
|
}
|
|
3778
3806
|
}
|
|
3779
3807
|
|
|
3808
|
+
// Switches a map preview between its themes. The preview reloads with the next theme and keeps
|
|
3809
|
+
// the camera and toggles already written to the URL; scene previews own their theme.
|
|
3810
|
+
class ThemeControl {
|
|
3811
|
+
onAdd(map) {
|
|
3812
|
+
this.map = map;
|
|
3813
|
+
this.container = document.createElement("div");
|
|
3814
|
+
this.container.className = "maplibregl-ctrl maplibregl-ctrl-group";
|
|
3815
|
+
this.button = document.createElement("button");
|
|
3816
|
+
this.button.type = "button";
|
|
3817
|
+
this.button.className = "tileflow-theme-toggle";
|
|
3818
|
+
const next = previewThemes[(previewThemes.indexOf(previewTheme) + 1) % previewThemes.length];
|
|
3819
|
+
this.button.textContent = String(previewTheme).toUpperCase();
|
|
3820
|
+
this.button.title = "Switch to the " + next + " theme";
|
|
3821
|
+
this.button.setAttribute("aria-label", "Switch to the " + next + " theme");
|
|
3822
|
+
this.handleClick = () => {
|
|
3823
|
+
writeCameraToUrl(map);
|
|
3824
|
+
const url = new URL(location.href);
|
|
3825
|
+
url.searchParams.set("theme", next);
|
|
3826
|
+
location.assign(url.href);
|
|
3827
|
+
};
|
|
3828
|
+
this.button.addEventListener("click", this.handleClick);
|
|
3829
|
+
this.container.appendChild(this.button);
|
|
3830
|
+
return this.container;
|
|
3831
|
+
}
|
|
3832
|
+
|
|
3833
|
+
onRemove() {
|
|
3834
|
+
this.button?.removeEventListener("click", this.handleClick);
|
|
3835
|
+
this.container?.remove();
|
|
3836
|
+
this.map = undefined;
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
|
|
3780
3840
|
const previewLayerGroupIds = [
|
|
3781
3841
|
"labels", "pois", "roads", "transit", "buildings", "landuse", "water"
|
|
3782
3842
|
];
|
|
@@ -3913,6 +3973,7 @@ function renderTileflowPreviewHtml(preview, basePath, initialStatus, isSemanticP
|
|
|
3913
3973
|
map.addControl(threeDimensionalControl, "top-right");
|
|
3914
3974
|
map.addControl(treeControl, "top-right");
|
|
3915
3975
|
}
|
|
3976
|
+
if (previewThemes.length > 1) map.addControl(new ThemeControl(), "top-right");
|
|
3916
3977
|
let ensuringThreeDimensionalLayers;
|
|
3917
3978
|
const treeRuntimeMinimumZoom = 16;
|
|
3918
3979
|
const ensureThreeDimensionalLayers = () => {
|
|
@@ -4200,7 +4261,8 @@ function resolveTileflowPreview(project, selection = {}) {
|
|
|
4200
4261
|
},
|
|
4201
4262
|
label: `${mapName} / ${selectedTheme.name}`,
|
|
4202
4263
|
mapName,
|
|
4203
|
-
themeName: selectedTheme.name
|
|
4264
|
+
themeName: selectedTheme.name,
|
|
4265
|
+
themeNames: Object.keys(resolvedMap.themes)
|
|
4204
4266
|
};
|
|
4205
4267
|
}
|
|
4206
4268
|
function resolvePreviewTheme(map, requested) {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createTileflowArtifactSession,
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
createTileflowLineBackgroundGlyphResponder,
|
|
4
|
+
parseTileflowLineBackgroundGlyphPath,
|
|
5
|
+
tileflowArtifactSessionSchemaVersion,
|
|
6
|
+
tileflowLineBackgroundGlyphRoute
|
|
7
|
+
} from "./chunk-4HVIEMKM.js";
|
|
5
8
|
import {
|
|
6
9
|
normalizeTileflowBasePath
|
|
7
10
|
} from "./chunk-UTRO4IBQ.js";
|
|
@@ -1709,6 +1712,7 @@ function createTileflowDevRequestHandler(options = {}) {
|
|
|
1709
1712
|
const cwd = options.cwd ?? process.cwd();
|
|
1710
1713
|
const apiBaseUrl = options.apiBaseUrl ?? defaultTileflowApiUrl;
|
|
1711
1714
|
let ownedSessionPromise;
|
|
1715
|
+
const lineBackgroundGlyphs = createTileflowLineBackgroundGlyphResponder({ cwd });
|
|
1712
1716
|
let closed = false;
|
|
1713
1717
|
let lastOrigin;
|
|
1714
1718
|
const loadOwnedSession = (origin) => {
|
|
@@ -1783,6 +1787,12 @@ function createTileflowDevRequestHandler(options = {}) {
|
|
|
1783
1787
|
);
|
|
1784
1788
|
}
|
|
1785
1789
|
if (!artifacts) return unavailableArtifactsResponse(state);
|
|
1790
|
+
if (path.startsWith(`/${tileflowLineBackgroundGlyphRoute}/`)) {
|
|
1791
|
+
const glyphRequest = parseTileflowLineBackgroundGlyphPath(path);
|
|
1792
|
+
const upstream = glyphRequest ? artifacts.lineBackgroundGlyphs?.[glyphRequest.mapName] : void 0;
|
|
1793
|
+
if (!glyphRequest || !upstream) return jsonResponse2({ error: "Unknown glyph range." }, 404);
|
|
1794
|
+
return await lineBackgroundGlyphs(upstream, glyphRequest.fontStack, glyphRequest.range);
|
|
1795
|
+
}
|
|
1786
1796
|
if (path.startsWith("/tilesets/")) {
|
|
1787
1797
|
const fileName = path.replace(/^\/+/, "");
|
|
1788
1798
|
const localTileset = artifacts.localTilesets?.find(
|
|
@@ -1985,7 +1995,7 @@ function getRequestPathname(url) {
|
|
|
1985
1995
|
}
|
|
1986
1996
|
}
|
|
1987
1997
|
function isOwnedTileflowRequestPath(path) {
|
|
1988
|
-
return path === "/" || path === "/build-manifest.json" || path === "/manifest.json" || path === "/__events" || path === "/__status" || getTileflowStyleInspectionSelection(path) !== void 0 || path.startsWith("/generations/") || path.startsWith("/icons/") || path.startsWith("/tilesets/") || getTileflowStyleSelection(path) !== void 0 || path.startsWith("/fonts/") || path.startsWith("/__runtime/");
|
|
1998
|
+
return path === "/" || path === "/build-manifest.json" || path === "/manifest.json" || path === "/__events" || path === "/__status" || getTileflowStyleInspectionSelection(path) !== void 0 || path.startsWith("/generations/") || path.startsWith("/icons/") || path.startsWith("/tilesets/") || getTileflowStyleSelection(path) !== void 0 || path.startsWith("/fonts/") || path.startsWith(`/${tileflowLineBackgroundGlyphRoute}/`) || path.startsWith("/__runtime/");
|
|
1989
1999
|
}
|
|
1990
2000
|
function tileflowErrorResponse(error) {
|
|
1991
2001
|
if (error instanceof Error && "code" in error && error.code === "PREVIEW_SELECTION_INVALID") {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { CreateTileflowArtifactPlanOptions, TileflowArtifactAcquisition, TileflowArtifactDiagnostic, TileflowArtifactFile, TileflowArtifactInputGraph, TileflowArtifactPlan, TileflowArtifactSession, TileflowArtifactSessionOptions, TileflowArtifactSessionState, TileflowBuildArtifacts, TileflowBuildArtifactsOptions, TileflowBuildStyleInspections, TileflowHostedManifestOverwriteError, TileflowLocalTilesetFile, TileflowLocalTilesetProductionError, TileflowManifestOptions, WriteTileflowArtifactPlanOptions, WriteTileflowBuildArtifactsOptions, assertNoLocalTilesetsForProduction, assertTileflowSelfHostedManifestTarget, createTileflowArtifactDiagnostics, createTileflowArtifactPlan, createTileflowArtifactSession, createTileflowBuildArtifacts, createTileflowBuildProvenance, createTileflowManifest, createTileflowStyle, createTileflowStyles, disposeTileflowBuildArtifacts, getTileflowArtifactFiles, getTileflowAssetBasePath, getTileflowAssetFileName, getTileflowWatchPaths, isTileflowArtifactInputPath, joinTileflowPublicUrl, normalizeTileflowBasePath, prepareTileflowHostedNativeDeployment, prepareTileflowLocalTilesets, refreshTileflowArtifactSession, resolveTileflowArtifactPublicUrls, tileflowArtifactInventoryFileName, tileflowArtifactPlanSchemaVersion, tileflowArtifactSessionSchemaVersion, writeTileflowArtifactPlan, writeTileflowBuildArtifacts } from './artifacts.js';
|
|
1
|
+
export { CreateTileflowArtifactPlanOptions, TileflowArtifactAcquisition, TileflowArtifactDiagnostic, TileflowArtifactFile, TileflowArtifactInputGraph, TileflowArtifactPlan, TileflowArtifactSession, TileflowArtifactSessionOptions, TileflowArtifactSessionState, TileflowBuildArtifacts, TileflowBuildArtifactsOptions, TileflowBuildStyleInspections, TileflowHostedManifestOverwriteError, TileflowLineBackgroundGlyphProviders, TileflowLineBackgroundGlyphResponder, TileflowLocalTilesetFile, TileflowLocalTilesetProductionError, TileflowManifestOptions, WriteTileflowArtifactPlanOptions, WriteTileflowBuildArtifactsOptions, assertNoLocalTilesetsForProduction, assertTileflowSelfHostedManifestTarget, createTileflowArtifactDiagnostics, createTileflowArtifactPlan, createTileflowArtifactSession, createTileflowBuildArtifacts, createTileflowBuildProvenance, createTileflowLineBackgroundGlyphResponder, createTileflowManifest, createTileflowStyle, createTileflowStyles, disposeTileflowBuildArtifacts, getTileflowArtifactFiles, getTileflowAssetBasePath, getTileflowAssetFileName, getTileflowWatchPaths, isTileflowArtifactInputPath, joinTileflowPublicUrl, normalizeTileflowBasePath, parseTileflowLineBackgroundGlyphPath, prepareTileflowHostedNativeDeployment, prepareTileflowLocalTilesets, refreshTileflowArtifactSession, resolveTileflowArtifactPublicUrls, tileflowArtifactInventoryFileName, tileflowArtifactPlanSchemaVersion, tileflowArtifactSessionSchemaVersion, tileflowLineBackgroundGlyphRoute, usesTileflowLineBackgroundGlyphs, writeTileflowArtifactPlan, writeTileflowBuildArtifacts } from './artifacts.js';
|
|
2
2
|
export { LoadTileflowConfigOptions, LoadedTileflowConfig, TileflowValidationError, assertValidTileflowConfig, defaultTileflowApiUrl, defaultTileflowConfigPath, defaultTileflowManifestPath, getFirstTileflowMapName, getTileflowMapNames, loadTileflowConfig, loadTileflowConfigWithInputs, loadValidTileflowConfig, loadValidTileflowConfigWithInputs } from './config.js';
|
|
3
3
|
export { CompiledTileflowFontBundle, PrepareTileflowStyleFontsOptions, PreparedTileflowStyleFonts, TileflowFontCompilationError, TileflowFontCompilationIssue, TileflowFontCompilationTarget, bindTileflowStyleFontBundle, getTileflowFontWatchPaths, prepareTileflowStyleFonts, replaceTileflowStyleFontSources } from './fonts.js';
|
|
4
4
|
export { CompileTileflowIconPackagesOptions, CompileTileflowIconPackagesResult, CompiledTileflowIconPackage, CompiledTileflowIconPackageFile, ComposeTileflowIconSourcesOptions, InspectTileflowIconCatalogsOptions, PreparedTileflowBuildCatalog, PreparedTileflowCatalog, ReadTileflowIconDirectoryResult, TileflowBuildAsset, TileflowComposedIconContributor, TileflowComposedIconSources, TileflowComposedIconWinner, TileflowIconCacheOptions, TileflowIconCatalog, TileflowIconCatalogAtlasRectangle, TileflowIconCatalogContributor, TileflowIconCatalogIcon, TileflowIconCatalogIconSource, TileflowIconCatalogInspection, TileflowIconCatalogMap, TileflowIconCatalogRenderedDensity, TileflowIconCatalogSourceFormat, TileflowIconCompilationError, TileflowIconCompilationIssue, TileflowIconCompilationTarget, TileflowIconDirectoryEntry, TileflowIconDirectorySourceFile, TileflowIconReplacement, TileflowIconResolutionOptions, TileflowMapIconPackageBinding, TileflowRenderedIcon, TileflowRenderedIconCell, TileflowSourceCatalog, VerifiedTileflowIconArtifact, compileTileflowIconPackages, composeTileflowIconSources, getTileflowIconCacheDirectory, getTileflowIconWatchPaths, iconFileExtensions, inspectTileflowIconCatalogs, loadTileflowIconSetArtifact, packTileflowRenderedIcons, prepareTileflowCatalogIcons, readTileflowIconDirectory, readTileflowIconsLockfile, readTileflowIconsLockfileText, renderTileflowIconAtlasPreview, storeTileflowIconSetArtifact, verifyTileflowIconArtifact, writeTileflowIconsLockfile } from './icons.js';
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
readBoundedTileflowResponse,
|
|
20
20
|
renderTileflowPreviewHtml,
|
|
21
21
|
resolveTileflowPreview
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-CJGM6HTT.js";
|
|
23
23
|
import {
|
|
24
24
|
createTileflowArtifactStatus,
|
|
25
25
|
createTileflowComparisonRequestHandler,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
isTileflowRequestUrl,
|
|
32
32
|
tileflowComparisonSchemaVersion,
|
|
33
33
|
writeTileflowNodeResponse
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-YOTMY5XT.js";
|
|
35
35
|
import {
|
|
36
36
|
TileflowHostedManifestOverwriteError,
|
|
37
37
|
TileflowLocalTilesetProductionError,
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
createTileflowArtifactSession,
|
|
43
43
|
createTileflowBuildArtifacts,
|
|
44
44
|
createTileflowBuildProvenance,
|
|
45
|
+
createTileflowLineBackgroundGlyphResponder,
|
|
45
46
|
createTileflowManifest,
|
|
46
47
|
createTileflowStyle,
|
|
47
48
|
createTileflowStyles,
|
|
@@ -49,15 +50,18 @@ import {
|
|
|
49
50
|
getTileflowArtifactFiles,
|
|
50
51
|
getTileflowWatchPaths,
|
|
51
52
|
isTileflowArtifactInputPath,
|
|
53
|
+
parseTileflowLineBackgroundGlyphPath,
|
|
52
54
|
prepareTileflowHostedNativeDeployment,
|
|
53
55
|
prepareTileflowLocalTilesets,
|
|
54
56
|
refreshTileflowArtifactSession,
|
|
55
57
|
tileflowArtifactInventoryFileName,
|
|
56
58
|
tileflowArtifactPlanSchemaVersion,
|
|
57
59
|
tileflowArtifactSessionSchemaVersion,
|
|
60
|
+
tileflowLineBackgroundGlyphRoute,
|
|
61
|
+
usesTileflowLineBackgroundGlyphs,
|
|
58
62
|
writeTileflowArtifactPlan,
|
|
59
63
|
writeTileflowBuildArtifacts
|
|
60
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-4HVIEMKM.js";
|
|
61
65
|
import {
|
|
62
66
|
inspectTileflowPmtiles,
|
|
63
67
|
inspectTileflowPmtilesForLocalUse
|
|
@@ -140,6 +144,7 @@ export {
|
|
|
140
144
|
createTileflowCommandSummary,
|
|
141
145
|
createTileflowComparisonRequestHandler,
|
|
142
146
|
createTileflowDevRequestHandler,
|
|
147
|
+
createTileflowLineBackgroundGlyphResponder,
|
|
143
148
|
createTileflowManifest,
|
|
144
149
|
createTileflowNodeRequest,
|
|
145
150
|
createTileflowStructuredDiagnostics,
|
|
@@ -179,6 +184,7 @@ export {
|
|
|
179
184
|
normalizeTileflowBasePath,
|
|
180
185
|
normalizeTileflowLandmarkManifest,
|
|
181
186
|
packTileflowRenderedIcons,
|
|
187
|
+
parseTileflowLineBackgroundGlyphPath,
|
|
182
188
|
prepareTileflowCatalogIcons,
|
|
183
189
|
prepareTileflowHostedNativeDeployment,
|
|
184
190
|
prepareTileflowLocalTilesets,
|
|
@@ -203,6 +209,8 @@ export {
|
|
|
203
209
|
tileflowArtifactSessionSchemaVersion,
|
|
204
210
|
tileflowCommandDocumentSchemaVersion,
|
|
205
211
|
tileflowComparisonSchemaVersion,
|
|
212
|
+
tileflowLineBackgroundGlyphRoute,
|
|
213
|
+
usesTileflowLineBackgroundGlyphs,
|
|
206
214
|
validateTileflowStyle,
|
|
207
215
|
verifyTileflowIconArtifact,
|
|
208
216
|
writeTileflowArtifactPlan,
|
package/dist/preview.d.ts
CHANGED
|
@@ -58,6 +58,8 @@ type ResolvedTileflowPreview = {
|
|
|
58
58
|
label: string;
|
|
59
59
|
mapName: string;
|
|
60
60
|
themeName: string;
|
|
61
|
+
/** Every theme of a map preview, in declaration order. A scene owns its theme and omits this. */
|
|
62
|
+
themeNames?: readonly string[];
|
|
61
63
|
viewport?: NormalizedTileflowCaptureScene['viewport'];
|
|
62
64
|
};
|
|
63
65
|
declare class TileflowPreviewSelectionError extends Error {
|
package/dist/preview.js
CHANGED
package/dist/server.js
CHANGED
|
@@ -9,11 +9,11 @@ import {
|
|
|
9
9
|
isTileflowRequestUrl,
|
|
10
10
|
tileflowComparisonSchemaVersion,
|
|
11
11
|
writeTileflowNodeResponse
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-YOTMY5XT.js";
|
|
13
13
|
import {
|
|
14
14
|
createTileflowArtifactDiagnostics,
|
|
15
15
|
tileflowArtifactSessionSchemaVersion
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-4HVIEMKM.js";
|
|
17
17
|
import "./chunk-ONYQNLNA.js";
|
|
18
18
|
import {
|
|
19
19
|
getTileflowAssetBasePath,
|
|
@@ -41,14 +41,14 @@ const result = await compileTileflowIconPackages(internalCatalog, {
|
|
|
41
41
|
|
|
42
42
|
Streets declares `[streetsIcons]` and keeps light/dark image-token targets in that one closure;
|
|
43
43
|
Cyberpunk and Matrix independently declare `[cyberpunkIcons]` and `[matrixIcons]`. Baedeker,
|
|
44
|
-
Ferraris, Härad, Siegfried, Soundings,
|
|
45
|
-
`[ferrarisIcons]`, `[haradIcons]`, `[siegfriedIcons]`, `[soundingsIcons]`,
|
|
46
|
-
`[
|
|
44
|
+
Ferraris, Härad, Siegfried, Soundings, and Blueprint declare only `[baedekerIcons]`,
|
|
45
|
+
`[ferrarisIcons]`, `[haradIcons]`, `[siegfriedIcons]`, `[soundingsIcons]`, and
|
|
46
|
+
`[blueprintIcons]`, respectively. No official root composes another map's assets even though all
|
|
47
47
|
use the semantic compiler ABI. Baedeker's directory contains eight original travel-atlas patterns;
|
|
48
48
|
its browser-derived Mapterhorn contours use runtime terrain tiles and are not part of the icon
|
|
49
49
|
package. Härad's directory contains nine original Tileflow patterns inspired by Lantmäteriet's CC0
|
|
50
50
|
Häradsekonomiska kartan series from 1859–1934. Soundings owns ten original nautical symbols and
|
|
51
|
-
patterns.
|
|
51
|
+
patterns. Blueprint owns four technical blueprint patterns and one schematic POI node; its
|
|
52
52
|
unbundled Mapterhorn contours remain runtime terrain, and its text uses the canonical Noto Sans
|
|
53
53
|
glyph provider. An application map may inherit a root's exact array, replace it, clear it with `[]`,
|
|
54
54
|
or compose it explicitly with a spread.
|
|
@@ -236,11 +236,9 @@ Directories apply left to right. `<id>.<ext>` publishes an icon as `<id>`;
|
|
|
236
236
|
`<id>.pattern.<ext>` publishes the intrinsic-size pattern as `<id>`. The published ID must already
|
|
237
237
|
be canonical lower-kebab-case. A later file replaces an earlier file only for the same exact ID;
|
|
238
238
|
case-only collisions fail. Package maps export `streetsIcons`, `baedekerIcons`, `civicaIcons`,
|
|
239
|
-
`ferrarisIcons`, `haradIcons`, `siegfriedIcons`, `soundingsIcons`, `
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
`cyberpunkFonts`, `matrixFonts`, `baedekerFonts`, `civicaFonts`, `siegfriedFonts`, and
|
|
243
|
-
`superTileWorldFonts`. Preparation
|
|
239
|
+
`ferrarisIcons`, `haradIcons`, `siegfriedIcons`, `soundingsIcons`, `blueprintIcons` directory descriptors from
|
|
240
|
+
`@tileflow/maps`. Baedeker, Cívica, and Siegfried also export
|
|
241
|
+
`baedekerFonts`, `civicaFonts`, and `siegfriedFonts`. Preparation
|
|
244
242
|
resolves package descriptors inside their owning package, checks real-path containment, and
|
|
245
243
|
compiles them through the same pipeline as a config-relative directory. There are no
|
|
246
244
|
built-in/source/sprite selectors, mappings, icon-specific inheritance, or compatibility aliases.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tileflow/dev",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.28",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Node development utilities for Tileflow configs and builds.",
|
|
6
6
|
"type": "module",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"dependencies": {
|
|
91
91
|
"@mapbox/vector-tile": "3.0.0",
|
|
92
92
|
"@maplibre/maplibre-gl-style-spec": "24.8.5",
|
|
93
|
-
"@tileflow/core": ">=0.1.0-alpha.
|
|
93
|
+
"@tileflow/core": ">=0.1.0-alpha.30 <0.1.0-beta.0",
|
|
94
94
|
"chokidar": "4.0.3",
|
|
95
95
|
"fflate": "0.8.3",
|
|
96
96
|
"fontkit": "2.0.4",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"three": "0.185.1"
|
|
103
103
|
},
|
|
104
104
|
"devDependencies": {
|
|
105
|
-
"@tileflow/maps": "0.1.0-alpha.
|
|
105
|
+
"@tileflow/maps": "0.1.0-alpha.7"
|
|
106
106
|
},
|
|
107
107
|
"optionalDependencies": {
|
|
108
108
|
"sharp": "0.35.4"
|