mirror of
https://github.com/protomaps/PMTiles.git
synced 2026-02-04 10:51:07 +00:00
Pmtiles js v4 (#499)
* pmtiles js v4: remove pmtiles spec v2 compatibility [#287] * restructure ts files into src * add tsup for building ESM/CJS and making types work in ESM * bump fflate dependency * update CHANGELOG for js 4.0.0
This commit is contained in:
2
.github/workflows/actions.yml
vendored
2
.github/workflows/actions.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
- run: cd serverless/cloudflare && cp wrangler.toml.example wrangler.toml && npm ci && npx tsc && npm run biome-check && npm run build && cp dist/index.js ../../app/dist
|
- run: cd serverless/cloudflare && cp wrangler.toml.example wrangler.toml && npm ci && npx tsc && npm run biome-check && npm run build && cp dist/index.js ../../app/dist
|
||||||
- run: cd spec/v3 && cp *.pmtiles ../../app/dist
|
- run: cd spec/v3 && cp *.pmtiles ../../app/dist
|
||||||
- run: cd js/examples && mkdir ../../app/dist/examples && cp *.html ../../app/dist/examples/
|
- run: cd js/examples && mkdir ../../app/dist/examples && cp *.html ../../app/dist/examples/
|
||||||
- run: cd js && npm ci && npx typedoc index.ts --out ../app/dist/typedoc
|
- run: cd js && npm ci && npx typedoc src/index.ts --out ../app/dist/typedoc
|
||||||
- run : cd openlayers && npm ci && npm run tsc
|
- run : cd openlayers && npm ci && npm run tsc
|
||||||
- run: cd openlayers/examples && mkdir ../../app/dist/examples/openlayers && cp *.html ../../app/dist/examples/openlayers
|
- run: cd openlayers/examples && mkdir ../../app/dist/examples/openlayers && cp *.html ../../app/dist/examples/openlayers
|
||||||
- name: build_app
|
- name: build_app
|
||||||
|
|||||||
@@ -5,7 +5,13 @@ import Protobuf from "pbf";
|
|||||||
import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react";
|
import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react";
|
||||||
import { UncontrolledReactSVGPanZoom } from "react-svg-pan-zoom";
|
import { UncontrolledReactSVGPanZoom } from "react-svg-pan-zoom";
|
||||||
import { useMeasure } from "react-use";
|
import { useMeasure } from "react-use";
|
||||||
import { Entry, Header, PMTiles, TileType, tileIdToZxy } from "../../js/index";
|
import {
|
||||||
|
Entry,
|
||||||
|
Header,
|
||||||
|
PMTiles,
|
||||||
|
TileType,
|
||||||
|
tileIdToZxy,
|
||||||
|
} from "../../js/src/index";
|
||||||
import { styled } from "./stitches.config";
|
import { styled } from "./stitches.config";
|
||||||
|
|
||||||
const TableContainer = styled("div", {
|
const TableContainer = styled("div", {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { PMTiles } from "../../js/index";
|
import { PMTiles } from "../../js/src/index";
|
||||||
import { styled } from "./stitches.config";
|
import { styled } from "./stitches.config";
|
||||||
|
|
||||||
import MaplibreMap from "./MaplibreMap";
|
import MaplibreMap from "./MaplibreMap";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
||||||
import { GitHubLogoIcon } from "@radix-ui/react-icons";
|
import { GitHubLogoIcon } from "@radix-ui/react-icons";
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { PMTiles } from "../../js/index";
|
import { PMTiles } from "../../js/src/index";
|
||||||
import { globalStyles, styled } from "./stitches.config";
|
import { globalStyles, styled } from "./stitches.config";
|
||||||
|
|
||||||
import Loader from "./Loader";
|
import Loader from "./Loader";
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import "maplibre-gl/dist/maplibre-gl.css";
|
|||||||
import baseTheme from "protomaps-themes-base";
|
import baseTheme from "protomaps-themes-base";
|
||||||
import React, { useState, useEffect, useRef } from "react";
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
import { renderToString } from "react-dom/server";
|
import { renderToString } from "react-dom/server";
|
||||||
import { Protocol } from "../../js/adapters";
|
import { Protocol } from "../../js/src/adapters";
|
||||||
import { PMTiles, TileType } from "../../js/index";
|
import { PMTiles, TileType } from "../../js/src/index";
|
||||||
import { styled } from "./stitches.config";
|
import { styled } from "./stitches.config";
|
||||||
|
|
||||||
const BASEMAP_THEME = "black";
|
const BASEMAP_THEME = "black";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { JsonViewer } from "@textea/json-viewer";
|
import { JsonViewer } from "@textea/json-viewer";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Header, PMTiles } from "../../js/index";
|
import { Header, PMTiles } from "../../js/src/index";
|
||||||
import { styled } from "./stitches.config";
|
import { styled } from "./stitches.config";
|
||||||
|
|
||||||
const Padded = styled("div", {
|
const Padded = styled("div", {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Dispatch, SetStateAction, useCallback, useState } from "react";
|
import { Dispatch, SetStateAction, useCallback, useState } from "react";
|
||||||
import { useDropzone } from "react-dropzone";
|
import { useDropzone } from "react-dropzone";
|
||||||
import { FileSource, PMTiles } from "../../js/index";
|
import { FileSource, PMTiles } from "../../js/src/index";
|
||||||
import { styled } from "./stitches.config";
|
import { styled } from "./stitches.config";
|
||||||
|
|
||||||
import * as LabelPrimitive from "@radix-ui/react-label";
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { PMTiles } from "../../js/index";
|
import { PMTiles } from "../../js/src/index";
|
||||||
import { globalStyles, styled } from "./stitches.config";
|
import { globalStyles, styled } from "./stitches.config";
|
||||||
import Inspector from "./Inspector";
|
import Inspector from "./Inspector";
|
||||||
import Start from "./Start";
|
import Start from "./Start";
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
4.0.0
|
||||||
|
* remove pmtiles spec v2 support, which reduces bundle size significantly [#287]
|
||||||
|
* use tsup for creating cjs/esm packages, which fixes typescript usage [#498]
|
||||||
|
* re-structure files in js project to be more conventional.
|
||||||
|
|
||||||
3.2.0
|
3.2.0
|
||||||
* MapLibre `Protocol` constructor takes an options object.
|
* MapLibre `Protocol` constructor takes an options object.
|
||||||
* add protocol option `metadata:boolean` that controls whether TileJSON metadata is fetched synchronously on map load. [#247]
|
* add protocol option `metadata:boolean` that controls whether TileJSON metadata is fetched synchronously on map load. [#247]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.0/dist/leaflet.css" />
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.0/dist/leaflet.css" />
|
||||||
<script src="https://unpkg.com/leaflet@1.9.0/dist/leaflet.js"></script>
|
<script src="https://unpkg.com/leaflet@1.9.0/dist/leaflet.js"></script>
|
||||||
<script src="https://unpkg.com/pmtiles@3.2.1/dist/pmtiles.js"></script>
|
<script src="https://unpkg.com/pmtiles@4.0.0/dist/pmtiles.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body, #map {
|
body, #map {
|
||||||
height:100vh;
|
height:100vh;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.css" crossorigin="anonymous">
|
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.css" crossorigin="anonymous">
|
||||||
<script src="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.js" crossorigin="anonymous"></script>
|
<script src="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.js" crossorigin="anonymous"></script>
|
||||||
<script src="https://unpkg.com/pmtiles@3.2.1/dist/pmtiles.js"></script>
|
<script src="https://unpkg.com/pmtiles@4.0.0/dist/pmtiles.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.css" crossorigin="anonymous">
|
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.css" crossorigin="anonymous">
|
||||||
<script src="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.js" crossorigin="anonymous"></script>
|
<script src="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.js" crossorigin="anonymous"></script>
|
||||||
<script src="https://unpkg.com/pmtiles@3.2.1/dist/pmtiles.js"></script>
|
<script src="https://unpkg.com/pmtiles@4.0.0/dist/pmtiles.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.css" crossorigin="anonymous">
|
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.css" crossorigin="anonymous">
|
||||||
<script src="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.js" crossorigin="anonymous"></script>
|
<script src="https://unpkg.com/maplibre-gl@4.7.0/dist/maplibre-gl.js" crossorigin="anonymous"></script>
|
||||||
<script src="https://unpkg.com/pmtiles@3.2.1/dist/pmtiles.js"></script>
|
<script src="https://unpkg.com/pmtiles@4.0.0/dist/pmtiles.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|||||||
3044
js/package-lock.json
generated
3044
js/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,45 +1,52 @@
|
|||||||
{
|
{
|
||||||
"name": "pmtiles",
|
"name": "pmtiles",
|
||||||
"version": "3.2.1",
|
"version": "4.0.0",
|
||||||
"description": "PMTiles archive decoder for browsers",
|
"description": "PMTiles archive decoder for browsers",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"main": "dist/cjs/index.cjs",
|
||||||
|
"module": "dist/esm/index.js",
|
||||||
|
"types": "dist/esm/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
"require":"./dist/index.cjs",
|
"./package.json": "./package.json",
|
||||||
"default":"./dist/index.js"
|
".": {
|
||||||
|
"import": {
|
||||||
|
"types": "./dist/esm/index.d.ts",
|
||||||
|
"default": "./dist/esm/index.js"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"types": "./dist/cjs/index.d.cts",
|
||||||
|
"default": "./dist/cjs/index.cjs"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"source": "index.ts",
|
"source": "index.ts",
|
||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist",
|
||||||
"adapters.ts",
|
"src"
|
||||||
"index.ts",
|
|
||||||
"v2.ts"
|
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build-iife": "esbuild index.ts --outfile=dist/pmtiles.js --target=es6 --global-name=pmtiles --bundle --format=iife",
|
"build": "tsup",
|
||||||
"build-esm": "esbuild index.ts --outfile=dist/index.js --target=es6 --bundle --format=esm",
|
|
||||||
"build-cjs": "esbuild index.ts --outfile=dist/index.cjs --target=es6 --bundle --format=cjs",
|
|
||||||
"build-tsc": "tsc --declaration --emitDeclarationOnly --outdir dist",
|
|
||||||
"build": "npm run build-iife && npm run build-esm && npm run build-cjs && npm run build-tsc",
|
|
||||||
"test": "tsx test/index.test.ts",
|
"test": "tsx test/index.test.ts",
|
||||||
"tsc": "tsc --noEmit --watch",
|
"tsc": "tsc --noEmit --watch",
|
||||||
"biome": "biome check adapters.ts index.ts v2.ts test --apply",
|
"biome": "biome check src test --apply",
|
||||||
"biome-check": "biome check adapters.ts index.ts v2.ts test"
|
"biome-check": "biome check src test"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/protomaps/pmtiles",
|
"homepage": "https://github.com/protomaps/pmtiles",
|
||||||
"author": "Brandon Liu",
|
"author": "Brandon Liu",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^1.5.3",
|
"@biomejs/biome": "^1.5.3",
|
||||||
|
"@types/leaflet": "^1.9.8",
|
||||||
"@types/node": "^20.0.0",
|
"@types/node": "^20.0.0",
|
||||||
"esbuild": "^0.20.0",
|
"esbuild": "^0.20.0",
|
||||||
"msw": "^2.5.0",
|
"msw": "^2.5.0",
|
||||||
|
"tsup": "^8.3.5",
|
||||||
"tsx": "^4.7.0",
|
"tsx": "^4.7.0",
|
||||||
"typedoc": "^0.25.7",
|
"typedoc": "^0.25.7",
|
||||||
"typescript": "^5.0.0"
|
"typescript": "^5.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/leaflet": "^1.9.8",
|
"fflate": "^0.8.2"
|
||||||
"fflate": "^0.8.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { decompressSync } from "fflate";
|
import { decompressSync } from "fflate";
|
||||||
import v2 from "./v2";
|
|
||||||
export * from "./adapters";
|
export * from "./adapters";
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
@@ -566,14 +565,14 @@ function deserializeIndex(buffer: ArrayBuffer): Entry[] {
|
|||||||
function detectVersion(a: ArrayBuffer): number {
|
function detectVersion(a: ArrayBuffer): number {
|
||||||
const v = new DataView(a);
|
const v = new DataView(a);
|
||||||
if (v.getUint16(2, true) === 2) {
|
if (v.getUint16(2, true) === 2) {
|
||||||
console.warn(
|
console.error(
|
||||||
"PMTiles spec version 2 has been deprecated; please see github.com/protomaps/PMTiles for tools to upgrade"
|
"PMTiles spec version 2 is not supported; please see github.com/protomaps/PMTiles for tools to upgrade"
|
||||||
);
|
);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (v.getUint16(2, true) === 1) {
|
if (v.getUint16(2, true) === 1) {
|
||||||
console.warn(
|
console.error(
|
||||||
"PMTiles spec version 1 has been deprecated; please see github.com/protomaps/PMTiles for tools to upgrade"
|
"PMTiles spec version 1 is not supported; please see github.com/protomaps/PMTiles for tools to upgrade"
|
||||||
);
|
);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -597,12 +596,6 @@ export interface Cache {
|
|||||||
length: number,
|
length: number,
|
||||||
header: Header
|
header: Header
|
||||||
) => Promise<Entry[]>;
|
) => Promise<Entry[]>;
|
||||||
getArrayBuffer: (
|
|
||||||
source: Source,
|
|
||||||
offset: number,
|
|
||||||
length: number,
|
|
||||||
header: Header
|
|
||||||
) => Promise<ArrayBuffer>;
|
|
||||||
invalidate: (source: Source) => Promise<void>;
|
invalidate: (source: Source) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,11 +610,6 @@ async function getHeaderAndRoot(
|
|||||||
throw new Error("Wrong magic number for PMTiles archive");
|
throw new Error("Wrong magic number for PMTiles archive");
|
||||||
}
|
}
|
||||||
|
|
||||||
// V2 COMPATIBILITY
|
|
||||||
if (detectVersion(resp.data) < 3) {
|
|
||||||
return [await v2.getHeader(source)];
|
|
||||||
}
|
|
||||||
|
|
||||||
const headerData = resp.data.slice(0, HEADER_SIZE_BYTES);
|
const headerData = resp.data.slice(0, HEADER_SIZE_BYTES);
|
||||||
|
|
||||||
const header = bytesToHeader(headerData, resp.etag);
|
const header = bytesToHeader(headerData, resp.etag);
|
||||||
@@ -744,33 +732,6 @@ export class ResolvedValueCache {
|
|||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for v2 backwards compatibility
|
|
||||||
async getArrayBuffer(
|
|
||||||
source: Source,
|
|
||||||
offset: number,
|
|
||||||
length: number,
|
|
||||||
header: Header
|
|
||||||
): Promise<ArrayBuffer> {
|
|
||||||
const cacheKey = `${source.getKey()}|${
|
|
||||||
header.etag || ""
|
|
||||||
}|${offset}|${length}`;
|
|
||||||
const cacheValue = this.cache.get(cacheKey);
|
|
||||||
if (cacheValue) {
|
|
||||||
cacheValue.lastUsed = this.counter++;
|
|
||||||
const data = await cacheValue.data;
|
|
||||||
return data as ArrayBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const resp = await source.getBytes(offset, length, undefined, header.etag);
|
|
||||||
|
|
||||||
this.cache.set(cacheKey, {
|
|
||||||
lastUsed: this.counter++,
|
|
||||||
data: resp.data,
|
|
||||||
});
|
|
||||||
this.prune();
|
|
||||||
return resp.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
prune() {
|
prune() {
|
||||||
if (this.cache.size > this.maxCacheEntries) {
|
if (this.cache.size > this.maxCacheEntries) {
|
||||||
let minUsed = Infinity;
|
let minUsed = Infinity;
|
||||||
@@ -880,40 +841,6 @@ export class SharedPromiseCache {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for v2 backwards compatibility
|
|
||||||
async getArrayBuffer(
|
|
||||||
source: Source,
|
|
||||||
offset: number,
|
|
||||||
length: number,
|
|
||||||
header: Header
|
|
||||||
): Promise<ArrayBuffer> {
|
|
||||||
const cacheKey = `${source.getKey()}|${
|
|
||||||
header.etag || ""
|
|
||||||
}|${offset}|${length}`;
|
|
||||||
const cacheValue = this.cache.get(cacheKey);
|
|
||||||
if (cacheValue) {
|
|
||||||
cacheValue.lastUsed = this.counter++;
|
|
||||||
const data = await cacheValue.data;
|
|
||||||
return data as ArrayBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const p = new Promise<ArrayBuffer>((resolve, reject) => {
|
|
||||||
source
|
|
||||||
.getBytes(offset, length, undefined, header.etag)
|
|
||||||
.then((resp) => {
|
|
||||||
resolve(resp.data);
|
|
||||||
if (this.cache.has(cacheKey)) {
|
|
||||||
}
|
|
||||||
this.prune();
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
reject(e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.cache.set(cacheKey, { lastUsed: this.counter++, data: p });
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
prune() {
|
prune() {
|
||||||
if (this.cache.size >= this.maxCacheEntries) {
|
if (this.cache.size >= this.maxCacheEntries) {
|
||||||
let minUsed = Infinity;
|
let minUsed = Infinity;
|
||||||
@@ -1003,11 +930,6 @@ export class PMTiles {
|
|||||||
const tileId = zxyToTileId(z, x, y);
|
const tileId = zxyToTileId(z, x, y);
|
||||||
const header = await this.cache.getHeader(this.source);
|
const header = await this.cache.getHeader(this.source);
|
||||||
|
|
||||||
// V2 COMPATIBILITY
|
|
||||||
if (header.specVersion < 3) {
|
|
||||||
return v2.getZxy(header, this.source, this.cache, z, x, y, signal);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (z < header.minZoom || z > header.maxZoom) {
|
if (z < header.minZoom || z > header.maxZoom) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@@ -1,2 +1 @@
|
|||||||
import "./v2.test";
|
|
||||||
import "./v3.test";
|
import "./v3.test";
|
||||||
|
|||||||
@@ -1,160 +0,0 @@
|
|||||||
import assert from "node:assert";
|
|
||||||
import { test } from "node:test";
|
|
||||||
|
|
||||||
import {
|
|
||||||
createDirectory,
|
|
||||||
deriveLeaf,
|
|
||||||
getUint24,
|
|
||||||
getUint48,
|
|
||||||
parseEntry,
|
|
||||||
queryLeafdir,
|
|
||||||
queryTile,
|
|
||||||
} from "../v2";
|
|
||||||
|
|
||||||
test("stub data", () => {
|
|
||||||
const dataview = new DataView(
|
|
||||||
createDirectory([
|
|
||||||
{ z: 5, x: 1000, y: 2000, offset: 1000, length: 2000, isDir: false },
|
|
||||||
{
|
|
||||||
z: 14,
|
|
||||||
x: 16383,
|
|
||||||
y: 16383,
|
|
||||||
offset: 999999,
|
|
||||||
length: 999,
|
|
||||||
isDir: false,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
);
|
|
||||||
const zRaw = dataview.getUint8(17 + 0);
|
|
||||||
const x = getUint24(dataview, 17 + 1);
|
|
||||||
const y = getUint24(dataview, 17 + 4);
|
|
||||||
const offset = getUint48(dataview, 17 + 7);
|
|
||||||
const length = dataview.getUint32(17 + 13, true);
|
|
||||||
assert.strictEqual(zRaw, 14);
|
|
||||||
assert.strictEqual(x, 16383);
|
|
||||||
assert.strictEqual(y, 16383);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("get entry", () => {
|
|
||||||
const view = new DataView(
|
|
||||||
createDirectory([
|
|
||||||
{ z: 5, x: 1000, y: 2000, offset: 1000, length: 2000, isDir: false },
|
|
||||||
{
|
|
||||||
z: 14,
|
|
||||||
x: 16383,
|
|
||||||
y: 16383,
|
|
||||||
offset: 999999,
|
|
||||||
length: 999,
|
|
||||||
isDir: false,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
);
|
|
||||||
const entry = queryTile(view, 14, 16383, 16383);
|
|
||||||
assert.strictEqual(entry?.z, 14);
|
|
||||||
assert.strictEqual(entry?.x, 16383);
|
|
||||||
assert.strictEqual(entry?.y, 16383);
|
|
||||||
assert.strictEqual(entry?.offset, 999999);
|
|
||||||
assert.strictEqual(entry?.length, 999);
|
|
||||||
assert.strictEqual(entry?.isDir, false);
|
|
||||||
assert.strictEqual(queryLeafdir(view, 14, 16383, 16383), null);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("get leafdir", () => {
|
|
||||||
const view = new DataView(
|
|
||||||
createDirectory([
|
|
||||||
{
|
|
||||||
z: 14,
|
|
||||||
x: 16383,
|
|
||||||
y: 16383,
|
|
||||||
offset: 999999,
|
|
||||||
length: 999,
|
|
||||||
isDir: true,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
);
|
|
||||||
const entry = queryLeafdir(view, 14, 16383, 16383);
|
|
||||||
assert.strictEqual(entry?.z, 14);
|
|
||||||
assert.strictEqual(entry?.x, 16383);
|
|
||||||
assert.strictEqual(entry?.y, 16383);
|
|
||||||
assert.strictEqual(entry?.offset, 999999);
|
|
||||||
assert.strictEqual(entry?.length, 999);
|
|
||||||
assert.strictEqual(entry?.isDir, true);
|
|
||||||
assert.strictEqual(queryTile(view, 14, 16383, 16383), null);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("derive the leaf level", () => {
|
|
||||||
let view = new DataView(
|
|
||||||
createDirectory([
|
|
||||||
{
|
|
||||||
z: 6,
|
|
||||||
x: 3,
|
|
||||||
y: 3,
|
|
||||||
offset: 0,
|
|
||||||
length: 0,
|
|
||||||
isDir: true,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
);
|
|
||||||
let leaf = deriveLeaf(view, { z: 7, x: 6, y: 6 });
|
|
||||||
assert.strictEqual(leaf?.z, 6);
|
|
||||||
assert.strictEqual(leaf?.x, 3);
|
|
||||||
assert.strictEqual(leaf?.y, 3);
|
|
||||||
view = new DataView(
|
|
||||||
createDirectory([
|
|
||||||
{
|
|
||||||
z: 6,
|
|
||||||
x: 3,
|
|
||||||
y: 3,
|
|
||||||
offset: 0,
|
|
||||||
length: 0,
|
|
||||||
isDir: false,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
);
|
|
||||||
leaf = deriveLeaf(view, { z: 7, x: 6, y: 6 });
|
|
||||||
assert.strictEqual(leaf, null);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("convert spec v1 directory to spec v2 directory", () => {
|
|
||||||
const view = new DataView(
|
|
||||||
createDirectory([
|
|
||||||
{
|
|
||||||
z: 7,
|
|
||||||
x: 3,
|
|
||||||
y: 3,
|
|
||||||
offset: 3,
|
|
||||||
length: 3,
|
|
||||||
isDir: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
z: 6,
|
|
||||||
x: 2,
|
|
||||||
y: 2,
|
|
||||||
offset: 2,
|
|
||||||
length: 2,
|
|
||||||
isDir: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
z: 6,
|
|
||||||
x: 2,
|
|
||||||
y: 1,
|
|
||||||
offset: 1,
|
|
||||||
length: 1,
|
|
||||||
isDir: false,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
);
|
|
||||||
let entry = queryLeafdir(view, 7, 3, 3);
|
|
||||||
assert.strictEqual(entry?.offset, 3);
|
|
||||||
entry = queryTile(view, 6, 2, 2);
|
|
||||||
assert.strictEqual(entry?.offset, 2);
|
|
||||||
entry = queryTile(view, 6, 2, 1);
|
|
||||||
assert.strictEqual(entry?.offset, 1);
|
|
||||||
|
|
||||||
entry = parseEntry(view, 0);
|
|
||||||
assert.strictEqual(entry?.offset, 1);
|
|
||||||
entry = parseEntry(view, 1);
|
|
||||||
assert.strictEqual(entry?.offset, 2);
|
|
||||||
entry = parseEntry(view, 2);
|
|
||||||
assert.strictEqual(entry?.offset, 3);
|
|
||||||
});
|
|
||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
tileIdToZxy,
|
tileIdToZxy,
|
||||||
tileTypeExt,
|
tileTypeExt,
|
||||||
zxyToTileId,
|
zxyToTileId,
|
||||||
} from "../index";
|
} from "../src/index";
|
||||||
|
|
||||||
class MockServer {
|
class MockServer {
|
||||||
etag?: string;
|
etag?: string;
|
||||||
|
|||||||
42
js/tsup.config.ts
Normal file
42
js/tsup.config.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { defineConfig, type Options } from "tsup";
|
||||||
|
|
||||||
|
const baseOptions: Options = {
|
||||||
|
clean: true,
|
||||||
|
minify: true,
|
||||||
|
skipNodeModulesBundle: true,
|
||||||
|
sourcemap: true,
|
||||||
|
target: "es6",
|
||||||
|
tsconfig: "./tsconfig.json",
|
||||||
|
keepNames: true,
|
||||||
|
cjsInterop: true,
|
||||||
|
splitting: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default [
|
||||||
|
defineConfig({
|
||||||
|
...baseOptions,
|
||||||
|
entry: ["src/index.ts"],
|
||||||
|
outDir: "dist/cjs",
|
||||||
|
format: "cjs",
|
||||||
|
dts: true,
|
||||||
|
}),
|
||||||
|
defineConfig({
|
||||||
|
...baseOptions,
|
||||||
|
entry: ["src/index.ts"],
|
||||||
|
outDir: "dist/esm",
|
||||||
|
format: "esm",
|
||||||
|
dts: true,
|
||||||
|
}),
|
||||||
|
defineConfig({
|
||||||
|
...baseOptions,
|
||||||
|
outDir: "dist",
|
||||||
|
format: "iife",
|
||||||
|
globalName: "pmtiles",
|
||||||
|
entry: {
|
||||||
|
"pmtiles": "src/index.ts",
|
||||||
|
},
|
||||||
|
outExtension: () => {
|
||||||
|
return { js: ".js" };
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
360
js/v2.ts
360
js/v2.ts
@@ -1,360 +0,0 @@
|
|||||||
import { decompressSync } from "fflate";
|
|
||||||
import {
|
|
||||||
Cache,
|
|
||||||
Compression,
|
|
||||||
Header,
|
|
||||||
RangeResponse,
|
|
||||||
Source,
|
|
||||||
TileType,
|
|
||||||
} from "./index";
|
|
||||||
|
|
||||||
export const shift = (n: number, shift: number) => {
|
|
||||||
return n * 2 ** shift;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const unshift = (n: number, shift: number) => {
|
|
||||||
return Math.floor(n / 2 ** shift);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getUint24 = (view: DataView, pos: number) => {
|
|
||||||
return shift(view.getUint16(pos + 1, true), 8) + view.getUint8(pos);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getUint48 = (view: DataView, pos: number) => {
|
|
||||||
return shift(view.getUint32(pos + 2, true), 16) + view.getUint16(pos, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface Zxy {
|
|
||||||
z: number;
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EntryV2 {
|
|
||||||
z: number;
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
offset: number;
|
|
||||||
length: number;
|
|
||||||
isDir: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const compare = (
|
|
||||||
tz: number,
|
|
||||||
tx: number,
|
|
||||||
ty: number,
|
|
||||||
view: DataView,
|
|
||||||
i: number
|
|
||||||
) => {
|
|
||||||
if (tz !== view.getUint8(i)) return tz - view.getUint8(i);
|
|
||||||
const x = getUint24(view, i + 1);
|
|
||||||
if (tx !== x) return tx - x;
|
|
||||||
const y = getUint24(view, i + 4);
|
|
||||||
if (ty !== y) return ty - y;
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const queryLeafdir = (
|
|
||||||
view: DataView,
|
|
||||||
z: number,
|
|
||||||
x: number,
|
|
||||||
y: number
|
|
||||||
): EntryV2 | null => {
|
|
||||||
const offsetLen = queryView(view, z | 0x80, x, y);
|
|
||||||
if (offsetLen) {
|
|
||||||
return {
|
|
||||||
z: z,
|
|
||||||
x: x,
|
|
||||||
y: y,
|
|
||||||
offset: offsetLen[0],
|
|
||||||
length: offsetLen[1],
|
|
||||||
isDir: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const queryTile = (view: DataView, z: number, x: number, y: number) => {
|
|
||||||
const offsetLen = queryView(view, z, x, y);
|
|
||||||
if (offsetLen) {
|
|
||||||
return {
|
|
||||||
z: z,
|
|
||||||
x: x,
|
|
||||||
y: y,
|
|
||||||
offset: offsetLen[0],
|
|
||||||
length: offsetLen[1],
|
|
||||||
isDir: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const queryView = (
|
|
||||||
view: DataView,
|
|
||||||
z: number,
|
|
||||||
x: number,
|
|
||||||
y: number
|
|
||||||
): [number, number] | null => {
|
|
||||||
let m = 0;
|
|
||||||
let n = view.byteLength / 17 - 1;
|
|
||||||
while (m <= n) {
|
|
||||||
const k = (n + m) >> 1;
|
|
||||||
const cmp = compare(z, x, y, view, k * 17);
|
|
||||||
if (cmp > 0) {
|
|
||||||
m = k + 1;
|
|
||||||
} else if (cmp < 0) {
|
|
||||||
n = k - 1;
|
|
||||||
} else {
|
|
||||||
return [getUint48(view, k * 17 + 7), view.getUint32(k * 17 + 13, true)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const entrySort = (a: EntryV2, b: EntryV2): number => {
|
|
||||||
if (a.isDir && !b.isDir) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (!a.isDir && b.isDir) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (a.z !== b.z) {
|
|
||||||
return a.z - b.z;
|
|
||||||
}
|
|
||||||
if (a.x !== b.x) {
|
|
||||||
return a.x - b.x;
|
|
||||||
}
|
|
||||||
return a.y - b.y;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const parseEntry = (dataview: DataView, i: number): EntryV2 => {
|
|
||||||
const zRaw = dataview.getUint8(i * 17);
|
|
||||||
const z = zRaw & 127;
|
|
||||||
return {
|
|
||||||
z: z,
|
|
||||||
x: getUint24(dataview, i * 17 + 1),
|
|
||||||
y: getUint24(dataview, i * 17 + 4),
|
|
||||||
offset: getUint48(dataview, i * 17 + 7),
|
|
||||||
length: dataview.getUint32(i * 17 + 13, true),
|
|
||||||
isDir: zRaw >> 7 === 1,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const sortDir = (a: ArrayBuffer): ArrayBuffer => {
|
|
||||||
const entries: EntryV2[] = [];
|
|
||||||
const view = new DataView(a);
|
|
||||||
for (let i = 0; i < view.byteLength / 17; i++) {
|
|
||||||
entries.push(parseEntry(view, i));
|
|
||||||
}
|
|
||||||
return createDirectory(entries);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createDirectory = (entries: EntryV2[]): ArrayBuffer => {
|
|
||||||
entries.sort(entrySort);
|
|
||||||
|
|
||||||
const buffer = new ArrayBuffer(17 * entries.length);
|
|
||||||
const arr = new Uint8Array(buffer);
|
|
||||||
for (let i = 0; i < entries.length; i++) {
|
|
||||||
const entry = entries[i];
|
|
||||||
let z = entry.z;
|
|
||||||
if (entry.isDir) z = z | 0x80;
|
|
||||||
arr[i * 17] = z;
|
|
||||||
|
|
||||||
arr[i * 17 + 1] = entry.x & 0xff;
|
|
||||||
arr[i * 17 + 2] = (entry.x >> 8) & 0xff;
|
|
||||||
arr[i * 17 + 3] = (entry.x >> 16) & 0xff;
|
|
||||||
|
|
||||||
arr[i * 17 + 4] = entry.y & 0xff;
|
|
||||||
arr[i * 17 + 5] = (entry.y >> 8) & 0xff;
|
|
||||||
arr[i * 17 + 6] = (entry.y >> 16) & 0xff;
|
|
||||||
|
|
||||||
arr[i * 17 + 7] = entry.offset & 0xff;
|
|
||||||
arr[i * 17 + 8] = unshift(entry.offset, 8) & 0xff;
|
|
||||||
arr[i * 17 + 9] = unshift(entry.offset, 16) & 0xff;
|
|
||||||
arr[i * 17 + 10] = unshift(entry.offset, 24) & 0xff;
|
|
||||||
arr[i * 17 + 11] = unshift(entry.offset, 32) & 0xff;
|
|
||||||
arr[i * 17 + 12] = unshift(entry.offset, 48) & 0xff;
|
|
||||||
|
|
||||||
arr[i * 17 + 13] = entry.length & 0xff;
|
|
||||||
arr[i * 17 + 14] = (entry.length >> 8) & 0xff;
|
|
||||||
arr[i * 17 + 15] = (entry.length >> 16) & 0xff;
|
|
||||||
arr[i * 17 + 16] = (entry.length >> 24) & 0xff;
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deriveLeaf = (view: DataView, tile: Zxy): Zxy | null => {
|
|
||||||
if (view.byteLength < 17) return null;
|
|
||||||
const numEntries = view.byteLength / 17;
|
|
||||||
const entry = parseEntry(view, numEntries - 1);
|
|
||||||
if (entry.isDir) {
|
|
||||||
const leafLevel = entry.z;
|
|
||||||
const levelDiff = tile.z - leafLevel;
|
|
||||||
const leafX = Math.trunc(tile.x / (1 << levelDiff));
|
|
||||||
const leafY = Math.trunc(tile.y / (1 << levelDiff));
|
|
||||||
return { z: leafLevel, x: leafX, y: leafY };
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
async function getHeader(source: Source): Promise<Header> {
|
|
||||||
const resp = await source.getBytes(0, 512000);
|
|
||||||
|
|
||||||
const dataview = new DataView(resp.data);
|
|
||||||
|
|
||||||
const jsonSize = dataview.getUint32(4, true);
|
|
||||||
const rootEntries = dataview.getUint16(8, true);
|
|
||||||
|
|
||||||
const dec = new TextDecoder("utf-8");
|
|
||||||
const jsonMetadata = JSON.parse(
|
|
||||||
dec.decode(new DataView(resp.data, 10, jsonSize))
|
|
||||||
);
|
|
||||||
let tileCompression = Compression.Unknown;
|
|
||||||
if (jsonMetadata.compression === "gzip") {
|
|
||||||
tileCompression = Compression.Gzip;
|
|
||||||
}
|
|
||||||
|
|
||||||
let minzoom = 0;
|
|
||||||
if ("minzoom" in jsonMetadata) {
|
|
||||||
minzoom = +jsonMetadata.minzoom;
|
|
||||||
}
|
|
||||||
|
|
||||||
let maxzoom = 0;
|
|
||||||
if ("maxzoom" in jsonMetadata) {
|
|
||||||
maxzoom = +jsonMetadata.maxzoom;
|
|
||||||
}
|
|
||||||
|
|
||||||
let centerLon = 0;
|
|
||||||
let centerLat = 0;
|
|
||||||
let centerZoom = 0;
|
|
||||||
let minLon = -180.0;
|
|
||||||
let minLat = -85.0;
|
|
||||||
let maxLon = 180.0;
|
|
||||||
let maxLat = 85.0;
|
|
||||||
|
|
||||||
if (jsonMetadata.bounds) {
|
|
||||||
const split = jsonMetadata.bounds.split(",");
|
|
||||||
minLon = +split[0];
|
|
||||||
minLat = +split[1];
|
|
||||||
maxLon = +split[2];
|
|
||||||
maxLat = +split[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jsonMetadata.center) {
|
|
||||||
const split = jsonMetadata.center.split(",");
|
|
||||||
centerLon = +split[0];
|
|
||||||
centerLat = +split[1];
|
|
||||||
centerZoom = +split[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
const header = {
|
|
||||||
specVersion: dataview.getUint16(2, true),
|
|
||||||
rootDirectoryOffset: 10 + jsonSize,
|
|
||||||
rootDirectoryLength: rootEntries * 17,
|
|
||||||
jsonMetadataOffset: 10,
|
|
||||||
jsonMetadataLength: jsonSize,
|
|
||||||
leafDirectoryOffset: 0,
|
|
||||||
leafDirectoryLength: undefined,
|
|
||||||
tileDataOffset: 0,
|
|
||||||
tileDataLength: undefined,
|
|
||||||
numAddressedTiles: 0,
|
|
||||||
numTileEntries: 0,
|
|
||||||
numTileContents: 0,
|
|
||||||
clustered: false,
|
|
||||||
internalCompression: Compression.None,
|
|
||||||
tileCompression: tileCompression,
|
|
||||||
tileType: TileType.Mvt,
|
|
||||||
minZoom: minzoom,
|
|
||||||
maxZoom: maxzoom,
|
|
||||||
minLon: minLon,
|
|
||||||
minLat: minLat,
|
|
||||||
maxLon: maxLon,
|
|
||||||
maxLat: maxLat,
|
|
||||||
centerZoom: centerZoom,
|
|
||||||
centerLon: centerLon,
|
|
||||||
centerLat: centerLat,
|
|
||||||
etag: resp.etag,
|
|
||||||
};
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getZxy(
|
|
||||||
header: Header,
|
|
||||||
source: Source,
|
|
||||||
cache: Cache,
|
|
||||||
z: number,
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
signal?: AbortSignal
|
|
||||||
): Promise<RangeResponse | undefined> {
|
|
||||||
let rootDir = await cache.getArrayBuffer(
|
|
||||||
source,
|
|
||||||
header.rootDirectoryOffset,
|
|
||||||
header.rootDirectoryLength,
|
|
||||||
header
|
|
||||||
);
|
|
||||||
if (header.specVersion === 1) {
|
|
||||||
rootDir = sortDir(rootDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
const entry = queryTile(new DataView(rootDir), z, x, y);
|
|
||||||
if (entry) {
|
|
||||||
const resp = await source.getBytes(entry.offset, entry.length, signal);
|
|
||||||
let tileData = resp.data;
|
|
||||||
|
|
||||||
const view = new DataView(tileData);
|
|
||||||
if (view.getUint8(0) === 0x1f && view.getUint8(1) === 0x8b) {
|
|
||||||
tileData = decompressSync(new Uint8Array(tileData));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: tileData,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const leafcoords = deriveLeaf(new DataView(rootDir), { z: z, x: x, y: y });
|
|
||||||
|
|
||||||
if (leafcoords) {
|
|
||||||
const leafdirEntry = queryLeafdir(
|
|
||||||
new DataView(rootDir),
|
|
||||||
leafcoords.z,
|
|
||||||
leafcoords.x,
|
|
||||||
leafcoords.y
|
|
||||||
);
|
|
||||||
if (leafdirEntry) {
|
|
||||||
let leafDir = await cache.getArrayBuffer(
|
|
||||||
source,
|
|
||||||
leafdirEntry.offset,
|
|
||||||
leafdirEntry.length,
|
|
||||||
header
|
|
||||||
);
|
|
||||||
|
|
||||||
if (header.specVersion === 1) {
|
|
||||||
leafDir = sortDir(leafDir);
|
|
||||||
}
|
|
||||||
const tileEntry = queryTile(new DataView(leafDir), z, x, y);
|
|
||||||
if (tileEntry) {
|
|
||||||
const resp = await source.getBytes(
|
|
||||||
tileEntry.offset,
|
|
||||||
tileEntry.length,
|
|
||||||
signal
|
|
||||||
);
|
|
||||||
let tileData = resp.data;
|
|
||||||
|
|
||||||
const view = new DataView(tileData);
|
|
||||||
if (view.getUint8(0) === 0x1f && view.getUint8(1) === 0x8b) {
|
|
||||||
tileData = decompressSync(new Uint8Array(tileData));
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
data: tileData,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
getHeader: getHeader,
|
|
||||||
getZxy: getZxy,
|
|
||||||
};
|
|
||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
ResolvedValueCache,
|
ResolvedValueCache,
|
||||||
Source,
|
Source,
|
||||||
TileType,
|
TileType,
|
||||||
} from "../../../js/index";
|
} from "../../../js/src/index";
|
||||||
import { pmtiles_path, tile_path } from "../../shared/index";
|
import { pmtiles_path, tile_path } from "../../shared/index";
|
||||||
|
|
||||||
import { createHash } from "crypto";
|
import { createHash } from "crypto";
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
ResolvedValueCache,
|
ResolvedValueCache,
|
||||||
Source,
|
Source,
|
||||||
TileType,
|
TileType,
|
||||||
} from "../../../js/index";
|
} from "../../../js/src/index";
|
||||||
import { pmtiles_path, tile_path } from "../../shared/index";
|
import { pmtiles_path, tile_path } from "../../shared/index";
|
||||||
|
|
||||||
interface Env {
|
interface Env {
|
||||||
|
|||||||
Reference in New Issue
Block a user