@expofp/offline 0.0.0-experimental.cf063fc
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 +22 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +98 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/lib/abort-signal.d.ts +2 -0
- package/dist/lib/abort-signal.js +6 -0
- package/dist/lib/data-to-files.d.ts +9 -0
- package/dist/lib/data-to-files.js +35 -0
- package/dist/lib/download-offline-zip.d.ts +5 -0
- package/dist/lib/download-offline-zip.js +14 -0
- package/dist/lib/generate-offline-data.d.ts +14 -0
- package/dist/lib/generate-offline-data.js +160 -0
- package/dist/lib/generate-offline-map-data.d.ts +20 -0
- package/dist/lib/generate-offline-map-data.js +343 -0
- package/dist/lib/generate-runtime-files-data.d.ts +5 -0
- package/dist/lib/generate-runtime-files-data.js +16 -0
- package/dist/lib/map-theme.d.ts +15 -0
- package/dist/lib/map-theme.js +48 -0
- package/dist/lib/offline-map-style.d.ts +51 -0
- package/dist/lib/offline-map-style.js +284 -0
- package/dist/lib/resolve-floorplan-dir.d.ts +8 -0
- package/dist/lib/resolve-floorplan-dir.js +34 -0
- package/dist/lib/save-offline-zip.d.ts +5 -0
- package/dist/lib/save-offline-zip.js +21 -0
- package/dist/lib/types.d.ts +21 -0
- package/dist/lib/types.js +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# @expofp/offline
|
|
2
|
+
|
|
3
|
+
CLI (`expofp-offline`) that creates self-contained ZIP archives of floor plans — openable in any browser without internet connectivity.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @expofp/offline@<tag-or-version> <manifest-url> [options]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
| Option | Description | Default |
|
|
12
|
+
| ------------------------ | ------------------------------------------------ | -------------------------------------- |
|
|
13
|
+
| `-o`, `--output` | Output file path | `offline.zip` |
|
|
14
|
+
| `--debug-no-offline-map` | Disable automatic MapLibre basemap detection. | |
|
|
15
|
+
| `--debug-map-source` | Global PMTiles source URL/path for offline maps. | Latest available Protomaps daily build |
|
|
16
|
+
| `-h`, `--help` | Show help message | |
|
|
17
|
+
|
|
18
|
+
## Example
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx @expofp/offline https://demo.expofp.com/manifest.json -o offline.zip
|
|
22
|
+
```
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { parseArgs } from 'node:util';
|
|
4
|
+
import { resolveFloorplanDir } from './lib/resolve-floorplan-dir.js';
|
|
5
|
+
import { saveOfflineZip } from './lib/save-offline-zip.js';
|
|
6
|
+
const HELP = `
|
|
7
|
+
Usage: expofp-offline <manifest-url> [options]
|
|
8
|
+
|
|
9
|
+
Create an offline ZIP archive of an ExpoFP floor plan.
|
|
10
|
+
|
|
11
|
+
Arguments:
|
|
12
|
+
manifest-url URL to the floor plan manifest JSON
|
|
13
|
+
|
|
14
|
+
Options:
|
|
15
|
+
-o, --output Output file path (default: offline.zip)
|
|
16
|
+
--debug-no-offline-map
|
|
17
|
+
Disable automatic offline MapLibre basemap detection
|
|
18
|
+
--debug-map-source <source>
|
|
19
|
+
Global PMTiles source URL/path used for the offline map
|
|
20
|
+
Defaults to the latest available Protomaps daily build
|
|
21
|
+
-h, --help Show this help message
|
|
22
|
+
-v, --version Show version number
|
|
23
|
+
`.trim();
|
|
24
|
+
async function main() {
|
|
25
|
+
const abortController = new AbortController();
|
|
26
|
+
const abortOnSigint = () => {
|
|
27
|
+
console.error('\nAborting offline ZIP creation...');
|
|
28
|
+
abortController.abort(new Error('Aborted by SIGINT'));
|
|
29
|
+
};
|
|
30
|
+
process.once('SIGINT', abortOnSigint);
|
|
31
|
+
const { values, positionals } = parseArgs({
|
|
32
|
+
args: process.argv.slice(2),
|
|
33
|
+
allowPositionals: true,
|
|
34
|
+
options: {
|
|
35
|
+
output: { type: 'string', short: 'o', default: 'offline.zip' },
|
|
36
|
+
'debug-no-offline-map': { type: 'boolean', default: false },
|
|
37
|
+
'debug-map-source': { type: 'string' },
|
|
38
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
39
|
+
version: { type: 'boolean', short: 'v', default: false },
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
if (values.help) {
|
|
43
|
+
console.log(HELP);
|
|
44
|
+
process.exit(0);
|
|
45
|
+
}
|
|
46
|
+
if (values.version) {
|
|
47
|
+
const require = createRequire(import.meta.url);
|
|
48
|
+
const pkg = require('../package.json');
|
|
49
|
+
console.log(pkg.version);
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
const manifestUrl = positionals[0];
|
|
53
|
+
if (!manifestUrl) {
|
|
54
|
+
console.error('Error: manifest URL is required.\n');
|
|
55
|
+
console.error(HELP);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
// Validate URL
|
|
59
|
+
try {
|
|
60
|
+
new URL(manifestUrl);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
console.error(`Error: "${manifestUrl}" is not a valid URL.\n`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
const outputPath = values.output;
|
|
67
|
+
if (!outputPath.endsWith('.zip')) {
|
|
68
|
+
console.error('Error: output path must end with .zip\n');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
if (values['debug-no-offline-map'] && values['debug-map-source']) {
|
|
72
|
+
console.error('Error: --debug-map-source cannot be used with --debug-no-offline-map\n');
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
const offlineMap = values['debug-map-source']
|
|
76
|
+
? { mapSource: values['debug-map-source'] }
|
|
77
|
+
: undefined;
|
|
78
|
+
const inferOfflineMap = !values['debug-no-offline-map'];
|
|
79
|
+
console.log(`Resolving @expofp/floorplan runtime...`);
|
|
80
|
+
const runtimeBaseUrl = await resolveFloorplanDir();
|
|
81
|
+
console.log(`Creating offline ZIP from ${manifestUrl}...`);
|
|
82
|
+
try {
|
|
83
|
+
await saveOfflineZip({ $ref: manifestUrl }, outputPath, {
|
|
84
|
+
runtimeBaseUrl,
|
|
85
|
+
offlineMap,
|
|
86
|
+
inferOfflineMap,
|
|
87
|
+
signal: abortController.signal,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
process.removeListener('SIGINT', abortOnSigint);
|
|
92
|
+
}
|
|
93
|
+
console.log(`Done! Offline ZIP saved to ${outputPath}`);
|
|
94
|
+
}
|
|
95
|
+
main().catch((err) => {
|
|
96
|
+
console.error('Error:', err instanceof Error ? err.message : err);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { downloadOfflineZip } from './lib/download-offline-zip.js';
|
|
2
|
+
export { buildOfflineZip } from './lib/generate-offline-data.js';
|
|
3
|
+
export { saveOfflineZip } from './lib/save-offline-zip.js';
|
|
4
|
+
export type { OfflineOptions } from './lib/types.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type LocalData } from './types.js';
|
|
2
|
+
export declare const FILE_FETCH_TIMEOUT_MS = 60000;
|
|
3
|
+
export declare function dataToFiles(data: AsyncIterable<LocalData>, options?: {
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
}): AsyncIterable<{
|
|
6
|
+
path: string;
|
|
7
|
+
data: Uint8Array;
|
|
8
|
+
}>;
|
|
9
|
+
//# sourceMappingURL=data-to-files.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { readFileFromUrl } from '@expofp/utils';
|
|
2
|
+
import debug from 'debug';
|
|
3
|
+
import { withTimeout } from './abort-signal.js';
|
|
4
|
+
const log = debug('efp:offline:data-to-files');
|
|
5
|
+
export const FILE_FETCH_TIMEOUT_MS = 60_000;
|
|
6
|
+
export async function* dataToFiles(data, options) {
|
|
7
|
+
for await (const file of data) {
|
|
8
|
+
if ('url' in file) {
|
|
9
|
+
const signal = withTimeout(options?.signal, FILE_FETCH_TIMEOUT_MS);
|
|
10
|
+
const response = await readFileFromUrl(file.url, { signal });
|
|
11
|
+
if (!response.ok) {
|
|
12
|
+
// only expected-missing resources (fabricated variant URLs) may be
|
|
13
|
+
// skipped — an archive silently missing anything else is broken
|
|
14
|
+
if (!file.optional) {
|
|
15
|
+
throw new Error(`Failed to download ${file.url}`);
|
|
16
|
+
}
|
|
17
|
+
console.warn(`Skipping optional file ${file.url} as it could not be downloaded`);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
log('Bundling file from url', file.targetFilePath);
|
|
21
|
+
yield {
|
|
22
|
+
path: file.targetFilePath,
|
|
23
|
+
data: response.data,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
log('Bundling text file', file.targetFilePath);
|
|
29
|
+
yield {
|
|
30
|
+
path: file.targetFilePath,
|
|
31
|
+
data: new TextEncoder().encode(file.text),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Manifest } from '@expofp/config';
|
|
2
|
+
import { type Ref } from '@expofp/resolve';
|
|
3
|
+
import { type OfflineOptions } from './types.js';
|
|
4
|
+
export declare function downloadOfflineZip(manifest: Manifest | Ref<Manifest>, options: OfflineOptions): Promise<void>;
|
|
5
|
+
//# sourceMappingURL=download-offline-zip.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { buildOfflineZip } from './generate-offline-data.js';
|
|
2
|
+
export async function downloadOfflineZip(manifest, options) {
|
|
3
|
+
if (typeof window === 'undefined' || typeof document === 'undefined') {
|
|
4
|
+
throw new Error('downloadOfflineZip can only be used in a browser environment');
|
|
5
|
+
}
|
|
6
|
+
const blob = await buildOfflineZip(manifest, options);
|
|
7
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
8
|
+
const a = document.createElement('a');
|
|
9
|
+
a.href = objectUrl;
|
|
10
|
+
a.download = 'offline.zip';
|
|
11
|
+
a.click();
|
|
12
|
+
// revoke to prevent race conditions with the download
|
|
13
|
+
setTimeout(() => URL.revokeObjectURL(objectUrl), 60_000);
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Manifest } from '@expofp/config';
|
|
2
|
+
import { type Ref } from '@expofp/resolve';
|
|
3
|
+
import { type LocalData, type OfflineOptions } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* An offline copy is nothing but a serialized config: `loadConfig` produces
|
|
6
|
+
* the complete event data document (refs warm, every asset URL absolute), and
|
|
7
|
+
* `serializeConfigResources` walks it — this package only decides WHERE
|
|
8
|
+
* things go (page-relative archive-local paths, so the copy resolves against
|
|
9
|
+
* wherever `index.html` is mounted) and zips the result with the runtime.
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateOfflineData(inputManifest: Manifest | Ref<Manifest>, options: OfflineOptions): AsyncIterable<LocalData, void>;
|
|
12
|
+
/** Build a complete offline ZIP archive from a manifest. */
|
|
13
|
+
export declare function buildOfflineZip(manifest: Manifest | Ref<Manifest>, options: OfflineOptions): Promise<Blob>;
|
|
14
|
+
//# sourceMappingURL=generate-offline-data.d.ts.map
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { loadConfig, serializeConfigResources, } from '@expofp/config';
|
|
2
|
+
import { getResolved, resolve } from '@expofp/resolve';
|
|
3
|
+
import { buildZipArchive, deepClone, makeLocalPath, readFileFromUrl } from '@expofp/utils';
|
|
4
|
+
import debug from 'debug';
|
|
5
|
+
import { withTimeout } from './abort-signal.js';
|
|
6
|
+
import { dataToFiles, FILE_FETCH_TIMEOUT_MS } from './data-to-files.js';
|
|
7
|
+
import { generateOfflineMapData, inferOfflineMapOptions, validateOfflineMapOptions, } from './generate-offline-map-data.js';
|
|
8
|
+
import { generateRuntimeFilesData } from './generate-runtime-files-data.js';
|
|
9
|
+
const log = debug('efp:offline:generate-offline-data');
|
|
10
|
+
/**
|
|
11
|
+
* An offline copy is nothing but a serialized config: `loadConfig` produces
|
|
12
|
+
* the complete event data document (refs warm, every asset URL absolute), and
|
|
13
|
+
* `serializeConfigResources` walks it — this package only decides WHERE
|
|
14
|
+
* things go (page-relative archive-local paths, so the copy resolves against
|
|
15
|
+
* wherever `index.html` is mounted) and zips the result with the runtime.
|
|
16
|
+
*/
|
|
17
|
+
export async function* generateOfflineData(inputManifest, options) {
|
|
18
|
+
const manifest = deepClone(await resolve(inputManifest, { signal: options.signal }));
|
|
19
|
+
log(`Generating offline files for expo: ${manifest.expo}`);
|
|
20
|
+
const config = await loadConfig(manifest, {});
|
|
21
|
+
const pathPrefix = config.expo;
|
|
22
|
+
// this is a requirement of mobile SDK, paths in the ZIP must be prefixed with the expo name
|
|
23
|
+
// TODO: make sure SDK works with unprefixed paths, and remove the prefixing logic from this function
|
|
24
|
+
const prefixPath = (path) => `${pathPrefix}/${path}`;
|
|
25
|
+
const offlineMap = await resolveOfflineMapOptions(config, options);
|
|
26
|
+
const { files, localManifest } = await serializeConfig(config, options.signal);
|
|
27
|
+
for (const d of files) {
|
|
28
|
+
yield { ...d, targetFilePath: prefixPath(d.targetFilePath) };
|
|
29
|
+
}
|
|
30
|
+
if (offlineMap) {
|
|
31
|
+
const mapData = generateOfflineMapData({
|
|
32
|
+
...offlineMap,
|
|
33
|
+
fpSvgContext: getFpSvgJs(config),
|
|
34
|
+
signal: options.signal,
|
|
35
|
+
});
|
|
36
|
+
for await (const d of mapData.files) {
|
|
37
|
+
yield { ...d, targetFilePath: prefixPath(d.targetFilePath) };
|
|
38
|
+
}
|
|
39
|
+
localManifest.maplibre = { ...mapData.maplibre };
|
|
40
|
+
}
|
|
41
|
+
// add runtime files — manually iterate to prefix paths while capturing return value
|
|
42
|
+
const runtimeGen = generateRuntimeFilesData(options.runtimeBaseUrl);
|
|
43
|
+
let runtimeResult = await runtimeGen.next();
|
|
44
|
+
while (!runtimeResult.done) {
|
|
45
|
+
yield {
|
|
46
|
+
...runtimeResult.value,
|
|
47
|
+
targetFilePath: prefixPath(runtimeResult.value.targetFilePath),
|
|
48
|
+
};
|
|
49
|
+
runtimeResult = await runtimeGen.next();
|
|
50
|
+
}
|
|
51
|
+
const { entry } = runtimeResult.value;
|
|
52
|
+
// the archive's manifest — the whole event data document, everything resolved
|
|
53
|
+
yield {
|
|
54
|
+
text: JSON.stringify(localManifest, null, 2),
|
|
55
|
+
targetFilePath: prefixPath('manifest.json'),
|
|
56
|
+
};
|
|
57
|
+
// generate index.html
|
|
58
|
+
yield {
|
|
59
|
+
text: getIndexHtml(entry, 'manifest.json'),
|
|
60
|
+
targetFilePath: prefixPath('index.html'),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The storage policy behind `serializeConfigResources`: assets land at their
|
|
65
|
+
* `makeLocalPath`, referenced documents are saved as `.json` files, and
|
|
66
|
+
* everything is addressed with **page-relative** URLs — bare `makeLocalPath`
|
|
67
|
+
* output, no leading slash — so the archive resolves wherever `index.html` is
|
|
68
|
+
* mounted (inside the expo folder, a parent at `/<expo>/`, or the SDK mount)
|
|
69
|
+
* alike. Non-remote (already-local or `data:`) resources pass through as-is.
|
|
70
|
+
*/
|
|
71
|
+
async function serializeConfig(config, signal) {
|
|
72
|
+
const files = [];
|
|
73
|
+
const seenPaths = new Set();
|
|
74
|
+
const add = (entry) => {
|
|
75
|
+
if (!seenPaths.has(entry.targetFilePath)) {
|
|
76
|
+
seenPaths.add(entry.targetFilePath);
|
|
77
|
+
files.push(entry);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const isRemote = (url) => /^https?:\/\//i.test(url);
|
|
81
|
+
const store = {
|
|
82
|
+
async asset(url, optional) {
|
|
83
|
+
if (!isRemote(url))
|
|
84
|
+
return url;
|
|
85
|
+
const targetFilePath = await makeLocalPath(new URL(url));
|
|
86
|
+
add({ url: new URL(url), targetFilePath, optional });
|
|
87
|
+
return targetFilePath;
|
|
88
|
+
},
|
|
89
|
+
async document(refUrl, document) {
|
|
90
|
+
const targetFilePath = documentPath(await makeLocalPath(new URL(refUrl)));
|
|
91
|
+
add({ text: JSON.stringify(document), targetFilePath });
|
|
92
|
+
return targetFilePath;
|
|
93
|
+
},
|
|
94
|
+
// @import'ed stylesheets (e.g. Google Fonts css2) are spliced into the
|
|
95
|
+
// importing CSS rather than saved as files — an extension-less saved
|
|
96
|
+
// stylesheet would be served with the wrong MIME type, and splicing lets
|
|
97
|
+
// the ordinary asset pass localize the fonts the import pulls in.
|
|
98
|
+
async stylesheetText(url) {
|
|
99
|
+
const response = await readFileFromUrl(new URL(url), {
|
|
100
|
+
signal: withTimeout(signal, FILE_FETCH_TIMEOUT_MS),
|
|
101
|
+
});
|
|
102
|
+
if (!response.ok)
|
|
103
|
+
throw new Error(`Failed to download @import'ed stylesheet ${url}`);
|
|
104
|
+
return new TextDecoder().decode(response.data);
|
|
105
|
+
},
|
|
106
|
+
documentError(refUrl, error) {
|
|
107
|
+
// The wayfinding graph is optional — an expo without one is normal, so
|
|
108
|
+
// (like the fabricated __small/__tiny logo variants) warn and drop the
|
|
109
|
+
// ref. Any other document missing means a broken archive: fail the build.
|
|
110
|
+
if (refUrl === config.wfDataJsRef?.$ref) {
|
|
111
|
+
console.warn(`Skipping wayfinding graph ${refUrl} as it could not be resolved`, error);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
const localManifest = await serializeConfigResources(config, store, { signal });
|
|
118
|
+
return { files, localManifest };
|
|
119
|
+
}
|
|
120
|
+
/** Saved documents are resolved JSON, whatever the live file was called. */
|
|
121
|
+
function documentPath(localPath) {
|
|
122
|
+
if (localPath.endsWith('.json'))
|
|
123
|
+
return localPath;
|
|
124
|
+
return localPath.replace(/\.js$/i, '') + '.json';
|
|
125
|
+
}
|
|
126
|
+
/** The eagerly-resolved drawing payload (loadConfig warmed the ref). */
|
|
127
|
+
function getFpSvgJs(config) {
|
|
128
|
+
if (!config.fpSvgJsRef)
|
|
129
|
+
throw new Error('config has no drawing (fpSvgJsRef)');
|
|
130
|
+
return getResolved(config.fpSvgJsRef);
|
|
131
|
+
}
|
|
132
|
+
async function resolveOfflineMapOptions(config, options) {
|
|
133
|
+
if (options.inferOfflineMap) {
|
|
134
|
+
return await inferOfflineMapOptions(getFpSvgJs(config), options.offlineMap, options.signal);
|
|
135
|
+
}
|
|
136
|
+
if (options.offlineMap) {
|
|
137
|
+
return await validateOfflineMapOptions(options.offlineMap, options.signal);
|
|
138
|
+
}
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
/** Build a complete offline ZIP archive from a manifest. */
|
|
142
|
+
export async function buildOfflineZip(manifest, options) {
|
|
143
|
+
const data = generateOfflineData(manifest, options);
|
|
144
|
+
const files = dataToFiles(data, { signal: options.signal });
|
|
145
|
+
return await buildZipArchive(files);
|
|
146
|
+
}
|
|
147
|
+
/** Known path — file lives in `packages/floorplan/public/` and is copied to dist by Vite. */
|
|
148
|
+
const COMPAT_HELPER = 'compat-helper.js';
|
|
149
|
+
function getIndexHtml(entry, manifestRef) {
|
|
150
|
+
// entry is "./runtime/index.js", derive the runtime base path
|
|
151
|
+
const runtimeBase = entry.slice(0, entry.lastIndexOf('/') + 1);
|
|
152
|
+
return `\
|
|
153
|
+
<!DOCTYPE html>
|
|
154
|
+
<script src="${runtimeBase}${COMPAT_HELPER}"></script>
|
|
155
|
+
<script type="module">
|
|
156
|
+
import { load } from ${JSON.stringify(entry)};
|
|
157
|
+
await load({ $ref: ${JSON.stringify(manifestRef)} });
|
|
158
|
+
</script>
|
|
159
|
+
`;
|
|
160
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { MaplibreOptions } from '@expofp/schema';
|
|
2
|
+
import { type LocalData, type OfflineMapOptions } from './types.js';
|
|
3
|
+
type FpSvgContext = Record<string, unknown>;
|
|
4
|
+
export type ValidatedOfflineMapOptions = OfflineMapOptions & {
|
|
5
|
+
mapSource: string;
|
|
6
|
+
fpSvgContext?: FpSvgContext;
|
|
7
|
+
};
|
|
8
|
+
export interface OfflineMapResult {
|
|
9
|
+
files: AsyncIterable<LocalData>;
|
|
10
|
+
maplibre: MaplibreOptions;
|
|
11
|
+
}
|
|
12
|
+
export declare function generateOfflineMapData(options: ValidatedOfflineMapOptions & {
|
|
13
|
+
fpSvgContext: FpSvgContext;
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}): OfflineMapResult;
|
|
16
|
+
export declare function validateOfflineMapOptions(options: OfflineMapOptions, signal?: AbortSignal): Promise<ValidatedOfflineMapOptions>;
|
|
17
|
+
/** An offline map applies only when the (already-loaded) drawing is geo-referenced. */
|
|
18
|
+
export declare function inferOfflineMapOptions(fpSvgContext: FpSvgContext, options: OfflineMapOptions | undefined, signal?: AbortSignal): Promise<ValidatedOfflineMapOptions | undefined>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=generate-offline-map-data.d.ts.map
|