@expofp/offline 3.0.0-alpha.9 → 3.0.1
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
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
## Offline: generating ZIPs
|
|
2
|
+
|
|
3
|
+
The `@expofp/offline` package provides a CLI (`expofp-offline`) that creates self-contained ZIP archives of floor plans. The ZIP can be opened 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
|
+
Use a dist-tag or exact version to match the deployed floor plan (e.g. `@latest`, `@next`, `@customer1`, `@3.0.0-alpha.9`).
|
|
12
|
+
|
|
13
|
+
| Option | Description | Default |
|
|
14
|
+
| ----------------- | ------------------- | ------------- |
|
|
15
|
+
| `-o`, `--output` | Output file path | `offline.zip` |
|
|
16
|
+
| `-h`, `--help` | Show help message | |
|
|
17
|
+
| `-v`, `--version` | Show version number | |
|
|
18
|
+
|
|
19
|
+
### Example
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx @expofp/offline@next https://demo.expofp.com/manifest.json -o offline.zip
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Debugging
|
|
26
|
+
|
|
27
|
+
Enable debug output with the `DEBUG` env variable:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
DEBUG=efp:offline:* npx @expofp/offline https://...
|
|
31
|
+
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolve } from '@expofp/resolve';
|
|
2
|
-
import { deepClone,
|
|
2
|
+
import { deepClone, fetchWithRetry, makeLocalPath } from '@expofp/utils';
|
|
3
3
|
import debug from 'debug';
|
|
4
4
|
import { offlinizeAssetsInPlace } from './offlinize-assets-in-place.js';
|
|
5
5
|
const log = debug('efp:offline:generate-offline-data-legacy');
|
|
@@ -53,7 +53,7 @@ export async function* generateOfflineDataLegacy(manifest, options) {
|
|
|
53
53
|
* (the function itself is Node-only).
|
|
54
54
|
*/
|
|
55
55
|
async function execScriptInSandbox(url, signal) {
|
|
56
|
-
const response = await
|
|
56
|
+
const response = await fetchWithRetry(url, { signal });
|
|
57
57
|
if (!response.ok) {
|
|
58
58
|
throw new Error(`Failed to fetch script (HTTP ${response.status}): ${url}`);
|
|
59
59
|
}
|
|
@@ -9,20 +9,35 @@ const log = debug('efp:offline:generate-offline-data');
|
|
|
9
9
|
export async function* generateOfflineData(inputManifest, options) {
|
|
10
10
|
const manifest = deepClone(await resolve(inputManifest));
|
|
11
11
|
log(`Generating offline files for expo: ${manifest.expo}`);
|
|
12
|
+
const pathPrefix = manifest.expo;
|
|
13
|
+
// this is a requirement of mobile SDK, paths in the ZIP must be prefixed with the expo name
|
|
14
|
+
// TODO: make sure SDK works with unprefixed paths, and remove the prefixing logic from this function
|
|
15
|
+
const prefixPath = (path) => `${pathPrefix}/${path}`;
|
|
12
16
|
if (manifest.legacyDataUrlBase) {
|
|
13
|
-
|
|
17
|
+
for await (const d of generateOfflineDataLegacy(manifest, options)) {
|
|
18
|
+
yield { ...d, targetFilePath: prefixPath(d.targetFilePath) };
|
|
19
|
+
}
|
|
14
20
|
}
|
|
15
21
|
// transform entire manifest + assets
|
|
16
22
|
const data = await offlinizeAssetsInPlace(manifest, options);
|
|
17
23
|
for (const d of data) {
|
|
18
|
-
yield d;
|
|
24
|
+
yield { ...d, targetFilePath: prefixPath(d.targetFilePath) };
|
|
19
25
|
}
|
|
20
|
-
// add runtime files
|
|
21
|
-
const
|
|
26
|
+
// add runtime files — manually iterate to prefix paths while capturing return value
|
|
27
|
+
const runtimeGen = generateRuntimeFilesData(options.runtimeBaseUrl);
|
|
28
|
+
let runtimeResult = await runtimeGen.next();
|
|
29
|
+
while (!runtimeResult.done) {
|
|
30
|
+
yield {
|
|
31
|
+
...runtimeResult.value,
|
|
32
|
+
targetFilePath: prefixPath(runtimeResult.value.targetFilePath),
|
|
33
|
+
};
|
|
34
|
+
runtimeResult = await runtimeGen.next();
|
|
35
|
+
}
|
|
36
|
+
const { entry } = runtimeResult.value;
|
|
22
37
|
// generate index.html
|
|
23
38
|
yield {
|
|
24
39
|
text: getIndexHtml(entry, manifest),
|
|
25
|
-
targetFilePath: '
|
|
40
|
+
targetFilePath: prefixPath('index.html'),
|
|
26
41
|
};
|
|
27
42
|
}
|
|
28
43
|
/** Build a complete offline ZIP archive from a manifest. */
|
|
@@ -31,13 +46,17 @@ export async function buildOfflineZip(manifest, options) {
|
|
|
31
46
|
const files = dataToFiles(data, { signal: options.signal });
|
|
32
47
|
return await buildZipArchive(files);
|
|
33
48
|
}
|
|
49
|
+
/** Known path — file lives in `packages/floorplan/public/` and is copied to dist by Vite. */
|
|
50
|
+
const COMPAT_HELPER = 'compat-helper.js';
|
|
34
51
|
function getIndexHtml(entry, manifest) {
|
|
52
|
+
// entry is "./runtime/index.js", derive the runtime base path
|
|
53
|
+
const runtimeBase = entry.slice(0, entry.lastIndexOf('/') + 1);
|
|
35
54
|
return `\
|
|
36
55
|
<!DOCTYPE html>
|
|
56
|
+
<script src="${runtimeBase}${COMPAT_HELPER}"></script>
|
|
37
57
|
<script type="module">
|
|
38
58
|
import { load } from ${JSON.stringify(entry)};
|
|
39
59
|
await load(${JSON.stringify(manifest)});
|
|
40
|
-
console.info('loaded');
|
|
41
60
|
</script>
|
|
42
61
|
`;
|
|
43
62
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { importJson } from '@expofp/utils';
|
|
2
2
|
import debug from 'debug';
|
|
3
3
|
const log = debug('efp:offline:generate-runtime-files-data');
|
|
4
4
|
export async function* generateRuntimeFilesData(runtimeBaseUrl) {
|
|
5
5
|
const bundleJsonUrl = new URL('bundle.json', runtimeBaseUrl).href;
|
|
6
|
-
const bundleJson = await
|
|
6
|
+
const bundleJson = await importJson(bundleJsonUrl);
|
|
7
7
|
log(`Generating runtime files from ${bundleJsonUrl}, ${bundleJson.files.length} files found`);
|
|
8
|
-
const basePath = '
|
|
8
|
+
const basePath = 'runtime/';
|
|
9
9
|
for (const file of bundleJson.files) {
|
|
10
10
|
yield {
|
|
11
11
|
url: new URL(file.file, runtimeBaseUrl),
|
|
12
12
|
targetFilePath: `${basePath}${file.file}`,
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
return { entry:
|
|
15
|
+
return { entry: `./${basePath}${bundleJson.entry}` };
|
|
16
16
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { fetchWithRetry, makeLocalPath } from '@expofp/utils';
|
|
2
2
|
import debug from 'debug';
|
|
3
3
|
import { offlinizeAssetUrl } from './offlinize-asset-url.js';
|
|
4
4
|
import { offlinizeCssAssetText } from './offlinize-css-asset-text.js';
|
|
@@ -66,7 +66,7 @@ export async function offlinizeAssetsInPlace(data, opts) {
|
|
|
66
66
|
// Mark as fetched to prevent duplicates
|
|
67
67
|
log(`Offlinizing $ref: ${refValue} -> ${targetFilePath}${fragment}`);
|
|
68
68
|
// Fetch and recursively process the referenced document
|
|
69
|
-
const response = await
|
|
69
|
+
const response = await fetchWithRetry(urlKey, { signal: opts.signal });
|
|
70
70
|
if (response.ok) {
|
|
71
71
|
const referencedData = await response.json();
|
|
72
72
|
processedRefs.set(urlKey, referencedData);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expofp/offline",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI tool for creating offline copies of ExpoFP floor plans",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"debug": "^4.4.3",
|
|
32
32
|
"tslib": "^2.3.0",
|
|
33
|
-
"@expofp/
|
|
34
|
-
"@expofp/
|
|
35
|
-
"@expofp/
|
|
36
|
-
"@expofp/
|
|
33
|
+
"@expofp/data": "3.0.1",
|
|
34
|
+
"@expofp/floorplan": "3.0.1",
|
|
35
|
+
"@expofp/resolve": "3.0.1",
|
|
36
|
+
"@expofp/utils": "3.0.1"
|
|
37
37
|
}
|
|
38
38
|
}
|