@expofp/loader 1.0.79 → 1.0.92

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.
Files changed (92) hide show
  1. package/dist/bundle/ImportHttpRuntime.node-B85BNHJG.js +92 -0
  2. package/dist/bundle/ImportHttpRuntime.node-B85BNHJG.js.map +1 -0
  3. package/dist/bundle/bundle.js +238 -683
  4. package/dist/bundle/bundle.js.map +1 -1
  5. package/dist/esm/ImportHttpRuntime.node.d.ts +28 -0
  6. package/dist/esm/ImportHttpRuntime.node.js +139 -0
  7. package/dist/esm/_OLD_resolveRuntimeUrl.d.ts +1 -0
  8. package/dist/esm/_OLD_resolveRuntimeUrl.js +10 -0
  9. package/dist/esm/importHttpRuntime.d.ts +1 -0
  10. package/dist/esm/importHttpRuntime.js +12 -0
  11. package/dist/esm/index.d.ts +10 -7
  12. package/dist/esm/index.js +40 -19
  13. package/dist/esm/resolve.d.ts +10 -44
  14. package/dist/esm/resolve.js +91 -295
  15. package/dist/esm/types.d.ts +11 -26
  16. package/package.json +3 -1
  17. package/dist/bundle/cssTextAssetResolver.offlineFunc-CWvHnYni.js +0 -19
  18. package/dist/bundle/cssTextAssetResolver.offlineFunc-CWvHnYni.js.map +0 -1
  19. package/dist/bundle/downloadOfflineZip-CNz_lUGZ.js +0 -2344
  20. package/dist/bundle/downloadOfflineZip-CNz_lUGZ.js.map +0 -1
  21. package/dist/bundle/legacyDataUrlBaseResolver.offlineFunc-DPaSp_zV.js +0 -87
  22. package/dist/bundle/legacyDataUrlBaseResolver.offlineFunc-DPaSp_zV.js.map +0 -1
  23. package/dist/bundle/makeOffline-Dj-0o5_7.js +0 -76
  24. package/dist/bundle/makeOffline-Dj-0o5_7.js.map +0 -1
  25. package/dist/bundle/makeOfflineBundle-D8tePWGI.js +0 -70
  26. package/dist/bundle/makeOfflineBundle-D8tePWGI.js.map +0 -1
  27. package/dist/bundle/saveOfflineZip.browser-BTQeRUY_.js +0 -7
  28. package/dist/bundle/saveOfflineZip.browser-BTQeRUY_.js.map +0 -1
  29. package/dist/bundle/tools-D0u8lBvQ.js +0 -102
  30. package/dist/bundle/tools-D0u8lBvQ.js.map +0 -1
  31. package/dist/esm/_OLD_fetchWithRetry.d.ts +0 -1
  32. package/dist/esm/_OLD_fetchWithRetry.js +0 -101
  33. package/dist/esm/importJson.d.ts +0 -2
  34. package/dist/esm/importJson.js +0 -59
  35. package/dist/esm/loadScript.d.ts +0 -16
  36. package/dist/esm/loadScript.js +0 -166
  37. package/dist/esm/logger.d.ts +0 -1
  38. package/dist/esm/logger.js +0 -5
  39. package/dist/esm/mutateManifest.d.ts +0 -2
  40. package/dist/esm/mutateManifest.js +0 -10
  41. package/dist/esm/offline/downloadOfflineZip.d.ts +0 -4
  42. package/dist/esm/offline/downloadOfflineZip.js +0 -15
  43. package/dist/esm/offline/generateZip.d.ts +0 -4
  44. package/dist/esm/offline/generateZip.js +0 -41
  45. package/dist/esm/offline/hashString.d.ts +0 -1
  46. package/dist/esm/offline/hashString.js +0 -16
  47. package/dist/esm/offline/index.d.ts +0 -14
  48. package/dist/esm/offline/index.js +0 -41
  49. package/dist/esm/offline/makeOffline.d.ts +0 -2
  50. package/dist/esm/offline/makeOffline.js +0 -144
  51. package/dist/esm/offline/makeOfflineBundle.d.ts +0 -4
  52. package/dist/esm/offline/makeOfflineBundle.js +0 -92
  53. package/dist/esm/offline/saveOfflineZip.browser.d.ts +0 -1
  54. package/dist/esm/offline/saveOfflineZip.browser.js +0 -3
  55. package/dist/esm/offline/saveOfflineZip.d.ts +0 -1
  56. package/dist/esm/offline/saveOfflineZip.js +0 -16
  57. package/dist/esm/offline/slugify.d.ts +0 -1
  58. package/dist/esm/offline/slugify.js +0 -61
  59. package/dist/esm/offline/tools.d.ts +0 -3
  60. package/dist/esm/offline/tools.js +0 -85
  61. package/dist/esm/resolvers/_OLD_expoResolver.d.ts +0 -1
  62. package/dist/esm/resolvers/_OLD_expoResolver.js +0 -49
  63. package/dist/esm/resolvers/assetResolver.d.ts +0 -6
  64. package/dist/esm/resolvers/assetResolver.js +0 -26
  65. package/dist/esm/resolvers/bundleAssetsResolver.d.ts +0 -2
  66. package/dist/esm/resolvers/bundleAssetsResolver.js +0 -20
  67. package/dist/esm/resolvers/cssTextAssetResolver.d.ts +0 -8
  68. package/dist/esm/resolvers/cssTextAssetResolver.js +0 -15
  69. package/dist/esm/resolvers/cssTextAssetResolver.offlineFunc.d.ts +0 -2
  70. package/dist/esm/resolvers/cssTextAssetResolver.offlineFunc.js +0 -22
  71. package/dist/esm/resolvers/expoRuntimeBranchResolver.d.ts +0 -2
  72. package/dist/esm/resolvers/expoRuntimeBranchResolver.js +0 -20
  73. package/dist/esm/resolvers/expoRuntimeGetBranchResolver.d.ts +0 -2
  74. package/dist/esm/resolvers/expoRuntimeGetBranchResolver.js +0 -14
  75. package/dist/esm/resolvers/expoRuntimeResolver.d.ts +0 -2
  76. package/dist/esm/resolvers/expoRuntimeResolver.js +0 -39
  77. package/dist/esm/resolvers/httpResolver.d.ts +0 -5
  78. package/dist/esm/resolvers/httpResolver.js +0 -14
  79. package/dist/esm/resolvers/index.d.ts +0 -2
  80. package/dist/esm/resolvers/index.js +0 -22
  81. package/dist/esm/resolvers/legacyAssetUrlsResolver.d.ts +0 -9
  82. package/dist/esm/resolvers/legacyAssetUrlsResolver.js +0 -116
  83. package/dist/esm/resolvers/legacyDataResolver.d.ts +0 -8
  84. package/dist/esm/resolvers/legacyDataResolver.js +0 -20
  85. package/dist/esm/resolvers/legacyDataUrlBaseResolver.d.ts +0 -8
  86. package/dist/esm/resolvers/legacyDataUrlBaseResolver.js +0 -15
  87. package/dist/esm/resolvers/legacyDataUrlBaseResolver.offlineFunc.d.ts +0 -2
  88. package/dist/esm/resolvers/legacyDataUrlBaseResolver.offlineFunc.js +0 -129
  89. package/dist/esm/returnCachedRef.d.ts +0 -1
  90. package/dist/esm/returnCachedRef.js +0 -12
  91. package/dist/esm/shared.d.ts +0 -8
  92. package/dist/esm/shared.js +0 -273
@@ -1,166 +0,0 @@
1
- import debug from 'debug';
2
- import { fetch } from './fetch';
3
- const log = debug('efp:loader:loadScript');
4
- /**
5
- * @deprecated Use loadScript directly instead.
6
- * Load a script from `scriptUrl` and optionally wait until `globalVar` appears.
7
- * Works in both browser (via <script>) and Node 18+ (via fetch + eval).
8
- */
9
- export async function loadAndWaitGlobal(scriptUrl, options) {
10
- const { globalVar, timeoutMs = 10_000, pollIntervalMs = 10 } = options;
11
- if (isBrowser()) {
12
- if (globalVar && window[globalVar] !== undefined) {
13
- delete window[globalVar];
14
- }
15
- await loadInBrowser(scriptUrl, options.signal);
16
- if (globalVar) {
17
- await waitForGlobal(() => window[globalVar], globalVar, timeoutMs, pollIntervalMs, options.signal);
18
- }
19
- }
20
- else {
21
- if (globalVar && globalThis[globalVar] !== undefined) {
22
- delete globalThis[globalVar];
23
- }
24
- await loadInNode(scriptUrl, options.signal);
25
- if (globalVar) {
26
- await waitForGlobal(() => globalThis[globalVar], globalVar, timeoutMs, pollIntervalMs, options.signal);
27
- }
28
- }
29
- }
30
- function isBrowser() {
31
- return typeof window !== 'undefined' && typeof document !== 'undefined';
32
- }
33
- export async function loadScript(scriptUrl, signal) {
34
- log('Loading', scriptUrl);
35
- if (isBrowser()) {
36
- await loadInBrowser(scriptUrl, signal);
37
- }
38
- else {
39
- await loadInNode(scriptUrl, signal);
40
- }
41
- }
42
- /* -------------------- Browser implementation -------------------- */
43
- function loadInBrowser(scriptUrl, signal) {
44
- return new Promise((resolve, reject) => {
45
- const script = document.createElement('script');
46
- script.src = scriptUrl;
47
- script.async = true;
48
- const cleanup = () => {
49
- script.onload = null;
50
- script.onerror = null;
51
- script.remove();
52
- };
53
- const onAbort = () => {
54
- cleanup();
55
- reject(new Error('Script load aborted'));
56
- };
57
- if (signal?.aborted) {
58
- cleanup();
59
- reject(new Error('Script load aborted'));
60
- return;
61
- }
62
- signal?.addEventListener('abort', onAbort, { once: true });
63
- script.onload = () => {
64
- signal?.removeEventListener('abort', onAbort);
65
- cleanup();
66
- resolve();
67
- };
68
- script.onerror = () => {
69
- signal?.removeEventListener('abort', onAbort);
70
- cleanup();
71
- reject(new Error(`Failed to load script: ${scriptUrl}`));
72
- };
73
- document.head.appendChild(script);
74
- });
75
- }
76
- /* -------------------- Node implementation -------------------- */
77
- async function loadInNode(scriptUrl, signal) {
78
- if (signal?.aborted) {
79
- throw new Error('Script load aborted');
80
- }
81
- let res;
82
- try {
83
- res = await fetch(scriptUrl, { signal });
84
- }
85
- catch (err) {
86
- // Node / WHATWG fetch uses AbortError on abort
87
- if (err && err.name === 'AbortError') {
88
- throw new Error('Script load aborted');
89
- }
90
- throw err;
91
- }
92
- if (!res.ok) {
93
- throw new Error(`Failed to load script in Node (HTTP ${res.status}): ${scriptUrl}`);
94
- }
95
- // If it was aborted between headers and body:
96
- if (signal?.aborted) {
97
- throw new Error('Script load aborted');
98
- }
99
- let code;
100
- try {
101
- code = await res.text();
102
- }
103
- catch (err) {
104
- if (err && err.name === 'AbortError') {
105
- throw new Error('Script load aborted');
106
- }
107
- throw err;
108
- }
109
- if (signal?.aborted) {
110
- throw new Error('Script load aborted');
111
- }
112
- // TEMPORARILY expose window for browser-style UMDs that expect it
113
- const g = globalThis;
114
- const prevWindow = g.window;
115
- g.window = g;
116
- try {
117
- // Indirect eval -> global scope in Node
118
- // Assumes the loaded script attaches itself to globalThis/window/global.
119
- (0, eval)(code);
120
- }
121
- finally {
122
- // Restore previous window (if any)
123
- if (prevWindow === undefined) {
124
- delete g.window;
125
- }
126
- else {
127
- g.window = prevWindow;
128
- }
129
- }
130
- }
131
- /* -------------------- Shared helper -------------------- */
132
- function waitForGlobal(getter, name, timeoutMs, pollIntervalMs, abortSignal) {
133
- return new Promise((resolve, reject) => {
134
- const start = Date.now();
135
- const onAbort = () => {
136
- reject(new Error('Wait for global aborted'));
137
- };
138
- if (abortSignal?.aborted) {
139
- reject(new Error('Wait for global aborted'));
140
- return;
141
- }
142
- abortSignal?.addEventListener('abort', onAbort, { once: true });
143
- const check = () => {
144
- if (abortSignal?.aborted) {
145
- return reject(new Error('Wait for global aborted'));
146
- }
147
- try {
148
- if (getter() !== undefined) {
149
- abortSignal?.removeEventListener('abort', onAbort);
150
- // log(`loadAndWaitGlobal: global "${name}" is now available`);
151
- return resolve();
152
- }
153
- }
154
- catch {
155
- // ignore access errors and keep polling
156
- }
157
- if (Date.now() - start >= timeoutMs) {
158
- abortSignal?.removeEventListener('abort', onAbort);
159
- // console.error(`loadAndWaitGlobal: timed out waiting for global "${name}"`);
160
- return reject(new Error(`Timed out after ${timeoutMs} ms waiting for global "${name}"`));
161
- }
162
- setTimeout(check, pollIntervalMs);
163
- };
164
- check();
165
- });
166
- }
@@ -1 +0,0 @@
1
- export declare function log(...args: any[]): void;
@@ -1,5 +0,0 @@
1
- import debug from 'debug';
2
- const logger = debug('efp:loader');
3
- export function log(...args) {
4
- logger(...args);
5
- }
@@ -1,2 +0,0 @@
1
- import type { ResolveOptions } from './resolve';
2
- export declare function mutateManifest(manifest: any, paths: string[], resolveContext?: Omit<ResolveOptions, 'mutate'>): Promise<void>;
@@ -1,10 +0,0 @@
1
- import { resolve } from './resolve';
2
- export async function mutateManifest(manifest, paths, resolveContext) {
3
- resolveContext = resolveContext || {};
4
- for (const path of paths) {
5
- await resolve(manifest, path, { ...resolveContext, mutate: true });
6
- }
7
- }
8
- if (typeof window !== 'undefined') {
9
- window['__debugMutateManifest'] = mutateManifest;
10
- }
@@ -1,4 +0,0 @@
1
- export declare function downloadOfflineZip(manifest: unknown, extraFiles?: Array<{
2
- path: string;
3
- data: Uint8Array;
4
- }>): Promise<void>;
@@ -1,15 +0,0 @@
1
- import { generateZip } from './generateZip';
2
- export async function downloadOfflineZip(manifest, extraFiles) {
3
- // check browser only
4
- if (typeof window === 'undefined' || typeof document === 'undefined') {
5
- throw new Error('downloadOfflineZip can only be used in a browser environment');
6
- }
7
- // Generate archive
8
- const blob = await generateZip(manifest, extraFiles);
9
- // Create link & trigger download
10
- const a = document.createElement('a');
11
- a.href = URL.createObjectURL(blob);
12
- a.download = 'offline.zip';
13
- a.click();
14
- URL.revokeObjectURL(a.href);
15
- }
@@ -1,4 +0,0 @@
1
- export declare function generateZip(manifest: unknown, extraFiles?: Array<{
2
- path: string;
3
- data: Uint8Array;
4
- }>): Promise<Blob>;
@@ -1,41 +0,0 @@
1
- import debug from 'debug';
2
- import JSZip from 'jszip';
3
- import { makeOfflineBundle } from './makeOfflineBundle';
4
- const log = debug('efp:loader:generateZip');
5
- const MAX_CONCURRENT_DOWNLOADS = 10;
6
- async function processConcurrently(iterator, concurrency, processor) {
7
- const activePromises = new Set();
8
- for await (const item of iterator) {
9
- const promise = Promise.resolve(processor(item)).then(() => {
10
- activePromises.delete(promise);
11
- });
12
- activePromises.add(promise);
13
- if (activePromises.size >= concurrency) {
14
- await Promise.race(activePromises);
15
- }
16
- }
17
- await Promise.all(activePromises);
18
- }
19
- export async function generateZip(manifest, extraFiles) {
20
- const zip = new JSZip();
21
- const bundle = await makeOfflineBundle(manifest);
22
- let hasFiles = false;
23
- await processConcurrently(bundle, MAX_CONCURRENT_DOWNLOADS, (file) => {
24
- log('Adding file to zip:', file.path, 'size:', file.data.byteLength);
25
- zip.file(file.path, file.data);
26
- hasFiles = true;
27
- });
28
- for (const extraFile of extraFiles ?? []) {
29
- log('Adding extra file to zip:', extraFile.path, 'size:', extraFile.data.byteLength);
30
- zip.file(extraFile.path, extraFile.data);
31
- hasFiles = true;
32
- }
33
- if (!hasFiles) {
34
- throw new Error('No files were added to the ZIP archive');
35
- }
36
- // Generate archive
37
- const blob = await zip.generateAsync({ type: 'blob' });
38
- // console.info('Manifest for HTML:', offlineData.manifest);
39
- log('Generated offline ZIP bundle, size:', blob.size);
40
- return blob;
41
- }
@@ -1 +0,0 @@
1
- export declare function hashString(str: string): string;
@@ -1,16 +0,0 @@
1
- // 32-bit murmur-ish hash with configurable seed
2
- function murmur32WithSeed(str, seed) {
3
- let h = seed >>> 0;
4
- for (let i = 0; i < str.length; i++) {
5
- h ^= str.charCodeAt(i);
6
- h = Math.imul(h, 0x01000193); // FNV-ish prime, good mixer
7
- }
8
- return (h >>> 0).toString(16).padStart(8, '0'); // 8 hex chars
9
- }
10
- // 128-bit (MD5-width) hash: 4 × 32-bit parts concatenated
11
- export function hashString(str) {
12
- return (murmur32WithSeed(str, 0x811c9dc5) + // your original seed
13
- murmur32WithSeed(str, 0x21f0aaad) +
14
- murmur32WithSeed(str, 0x1b873593) +
15
- murmur32WithSeed(str, 0x85ebca6b));
16
- }
@@ -1,14 +0,0 @@
1
- export declare function makeOffline(manifest: unknown): Promise<import("../types").MakeOfflineResult>;
2
- export declare function makeOfflineBundle(manifest: unknown): Promise<AsyncGenerator<{
3
- path: string;
4
- data: ArrayBuffer;
5
- }, any, any>>;
6
- export declare function generateZip(manifest: unknown, extraFiles?: Array<{
7
- path: string;
8
- data: Uint8Array;
9
- }>): Promise<Blob>;
10
- export declare function downloadOfflineZip(manifest: unknown, extraFiles?: Array<{
11
- path: string;
12
- data: Uint8Array;
13
- }>): Promise<void>;
14
- export declare function saveOfflineZip(manifest: unknown, path: string): Promise<void>;
@@ -1,41 +0,0 @@
1
- export async function makeOffline(manifest) {
2
- const { makeOffline } = await import('./makeOffline');
3
- return await makeOffline(manifest);
4
- }
5
- export async function makeOfflineBundle(manifest) {
6
- const { makeOfflineBundle } = await import('./makeOfflineBundle');
7
- return await makeOfflineBundle(manifest);
8
- }
9
- export async function generateZip(manifest, extraFiles) {
10
- const { generateZip } = await import('./generateZip');
11
- return await generateZip(manifest, extraFiles);
12
- }
13
- export async function downloadOfflineZip(manifest, extraFiles) {
14
- const { downloadOfflineZip } = await import('./downloadOfflineZip');
15
- return await downloadOfflineZip(manifest, extraFiles);
16
- }
17
- export async function saveOfflineZip(manifest, path) {
18
- const { saveOfflineZip } = await import('./saveOfflineZip');
19
- return await saveOfflineZip(manifest, path);
20
- }
21
- async function debugLogOfflineManifestFiles(manifest) {
22
- // console.log('Offline files:');
23
- const { makeOffline } = await import('./makeOffline');
24
- const result = await makeOffline(manifest);
25
- // const allFiles = [];
26
- for await (const file of (await result).files) {
27
- if ('data' in file) {
28
- console.info(`🗳️ Put ${file.targetFilePath} <=`, file.data);
29
- }
30
- else if ('url' in file) {
31
- console.info(`🗳️ Download ${file.targetFilePath} <= ${file.url}`);
32
- }
33
- // allFiles.push(file);
34
- }
35
- console.info('Offline data: ', result.manifest);
36
- }
37
- if (typeof window !== 'undefined') {
38
- window['__debugDownloadOfflineZip'] = downloadOfflineZip;
39
- window['__debugMakeOfflineBundle'] = makeOfflineBundle;
40
- window['__debugLogOfflineManifestFiles'] = debugLogOfflineManifestFiles;
41
- }
@@ -1,2 +0,0 @@
1
- import type { MakeOfflineResult } from '../types';
2
- export declare function makeOffline(manifest: any): Promise<MakeOfflineResult>;
@@ -1,144 +0,0 @@
1
- import debug from 'debug';
2
- import { canResolve, parseRefValue, resolverResolve, } from '../resolve';
3
- import { resolvers } from '../resolvers';
4
- import { createMergedObjectWithOverridenNonRefProps, deepClone, shallowClone } from '../shared';
5
- import { makeTargetPathFromUrl, makeUniqueJsonTargetPathFromString } from './tools';
6
- const log = debug('efp:loader:makeOffline');
7
- const logWalk = debug('efp:loader:makeOffline:walk');
8
- export async function makeOffline(manifest) {
9
- log('makeOffline', manifest);
10
- // if (typeof manifest !== 'object' || manifest === null) {
11
- // throw new Error('Manifest must be an object');
12
- // }
13
- const res = await makeOfflineInternal(manifest);
14
- let done = false;
15
- let resultManifest;
16
- async function* files() {
17
- resultManifest = yield* res;
18
- done = true;
19
- }
20
- return {
21
- get manifest() {
22
- if (!done)
23
- throw new Error('Iterate over files before getting manifest');
24
- return resultManifest;
25
- },
26
- files: files(),
27
- };
28
- }
29
- async function* makeOfflineInternal(manifest) {
30
- log('makeOfflineInternal', manifest);
31
- const resolveContext = {
32
- refCache: new Map(),
33
- forceFetch: true,
34
- signal: null,
35
- };
36
- const parent = { manifest };
37
- yield* walk(parent, 'manifest');
38
- return parent.manifest;
39
- async function* walk(node, key) {
40
- // console.log('walk', node, key, node[key]);
41
- logWalk(key, node[key]);
42
- // let node[key] = node[key];
43
- if (typeof node[key] !== 'object' || node[key] === null) {
44
- return;
45
- }
46
- // let resolversToUse1 = resolvers.filter((r) => r.canResolve(node[key].$ref));
47
- // const usedResolvers = new Set<Resolver>();
48
- // do {
49
- if ('$ref' in node[key]) {
50
- logWalk('Found $ref:', node[key].$ref);
51
- const resolversToUse = resolvers.filter((r) => canResolve(r, node[key].$ref));
52
- if (resolversToUse.length === 0) {
53
- throw new Error(`No resolver found for ref: ${node[key].$ref}`);
54
- }
55
- if (resolversToUse.length > 1) {
56
- throw new Error(`Multiple resolvers can make offline ref: ${node[key].$ref}`);
57
- }
58
- const resolver = resolversToUse[0];
59
- let func;
60
- switch (resolver.offlineFunc) {
61
- case 'localizeRef':
62
- func = offlineLocalizeRef;
63
- break;
64
- case 'resolveRef':
65
- func = offlineResolveRef;
66
- break;
67
- default:
68
- const m = resolver.offlineFunc;
69
- func = (_resolver, ref, context) => m(ref, context);
70
- // throw new Error(`Unknown offlineMethod: ${resolver.offlineMethod}`);
71
- }
72
- const mergeRef = yield* func(resolver, node[key].$ref, resolveContext);
73
- if (Object.isFrozen(node))
74
- throw new Error('Unexpected frozen node during makeOffline');
75
- node[key] = createMergedObjectWithOverridenNonRefProps({ $ref: mergeRef }, node[key]);
76
- }
77
- else {
78
- node[key] = shallowClone(node[key]);
79
- }
80
- // recurse
81
- if (Array.isArray(node[key])) {
82
- for (const [index] of node[key].entries()) {
83
- yield* walk(node[key], index);
84
- }
85
- }
86
- else if (typeof node[key] === 'object' && node[key] !== null) {
87
- for (const key1 of Object.keys(node[key])) {
88
- // debugger;
89
- yield* walk(node[key], key1);
90
- }
91
- }
92
- }
93
- }
94
- // function canResolve(resolver: Resolver, ref: string): boolean {
95
- // if (resolver.canResolve) {
96
- // return resolver.canResolve(ref);
97
- // }
98
- // if (resolver.schema) {
99
- // return canResolveRefSchema(ref, resolver.schema);
100
- // }
101
- // throw new Error('Resolver is missing canResolve method and schema property');
102
- // }
103
- async function* offlineLocalizeRef(resolver, ref, context) {
104
- const refData = deepClone(await resolverResolve(resolver, ref, context));
105
- // emit assets
106
- yield* makeOfflineInternal(refData);
107
- const url = parseRefValue(ref);
108
- const targetFilePath = makeTargetPathFromUrl(url);
109
- // TODO: handle CSS and other text files that may reference other assets
110
- yield { url, targetFilePath };
111
- const schema = ref.substring(0, ref.length - url.length - 1);
112
- return `${schema}:${targetFilePath}`;
113
- }
114
- async function* offlineResolveRef(resolver, ref, context) {
115
- const refData = deepClone(await resolverResolve(resolver, ref, context));
116
- const targetFilePath = makeUniqueJsonTargetPathFromString(ref);
117
- const data = yield* makeOfflineInternal(refData);
118
- yield { data, targetFilePath };
119
- return targetFilePath;
120
- }
121
- // export function createMakeOfflineResult(
122
- // manifest: any,
123
- // walk: (node: any, key: string | number) => AsyncGenerator<LocalFile>
124
- // ): MakeOfflineResult {
125
- // log('createMakeOfflineResult', manifest);
126
- // if (typeof manifest !== 'object' || manifest === null) {
127
- // throw new Error('Manifest must be an object');
128
- // }
129
- // const parent = { manifest };
130
- // let done = false;
131
- // async function* files() {
132
- // yield* walk(parent, 'manifest');
133
- // done = true;
134
- // }
135
- // return {
136
- // get manifest() {
137
- // if (!done) {
138
- // throw new Error('Cannot access manifest before all files are generated');
139
- // }
140
- // return parent.manifest;
141
- // },
142
- // files: files(),
143
- // };
144
- // }
@@ -1,4 +0,0 @@
1
- export declare function makeOfflineBundle(manifest: unknown): AsyncGenerator<{
2
- path: string;
3
- data: ArrayBuffer;
4
- }>;
@@ -1,92 +0,0 @@
1
- import debug from 'debug';
2
- import { resolve } from '..';
3
- import { makeOffline } from './makeOffline';
4
- import { deepFreeze } from '../shared';
5
- const log = debug('efp:loader:makeOfflineBundle');
6
- export async function* makeOfflineBundle(manifest) {
7
- log('Bundling', manifest);
8
- deepFreeze(manifest);
9
- const offlineData = await makeOffline(manifest);
10
- const preResolvedRefs = new Map();
11
- for await (const file of offlineData.files) {
12
- if ('data' in file) {
13
- preResolvedRefs.set(file.targetFilePath, file.data);
14
- const jsonString = JSON.stringify(file.data, null, 2);
15
- log('Bundling file with data', file.targetFilePath, jsonString);
16
- yield {
17
- path: file.targetFilePath,
18
- data: new TextEncoder().encode(jsonString).buffer,
19
- };
20
- }
21
- else if ('url' in file) {
22
- const blob = await downloadFile(file.url);
23
- if (!blob) {
24
- console.warn(`Skipping file ${file.url} as it could not be downloaded`);
25
- }
26
- else {
27
- log('Bundling file from url', file.targetFilePath);
28
- yield {
29
- path: file.targetFilePath,
30
- data: await blob.arrayBuffer(),
31
- };
32
- }
33
- }
34
- else if ('text' in file) {
35
- log('Bundling text file', file.targetFilePath);
36
- yield {
37
- path: file.targetFilePath,
38
- data: new TextEncoder().encode(file.text).buffer,
39
- };
40
- }
41
- else {
42
- throw new Error('Unknown file type');
43
- }
44
- }
45
- if (await resolve(offlineData.manifest, '/runtime', { preResolvedRefs })) {
46
- const html = await getIndexHtml(offlineData.manifest, preResolvedRefs);
47
- yield {
48
- path: './index.html',
49
- data: new TextEncoder().encode(html).buffer,
50
- };
51
- }
52
- }
53
- const MAX_CONCURRENT_DOWNLOADS = 10;
54
- const queue = new Set();
55
- // have a queue to limit concurrent downloads
56
- async function downloadFile(url) {
57
- while (queue.size >= MAX_CONCURRENT_DOWNLOADS) {
58
- await Promise.race(queue);
59
- }
60
- const downloadPromise = (async () => {
61
- log('Fetching file for zip:', url);
62
- const response = await fetch(url);
63
- if (!response.ok) {
64
- // Rodion's bug. May be missing file.
65
- if (!url.includes('/data/fp.svg.ViewBox.js')) {
66
- // throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
67
- }
68
- // console.warn(`Warning: Failed to fetch ${url}: ${response.status}`);
69
- return;
70
- }
71
- return await response.blob();
72
- })();
73
- queue.add(downloadPromise);
74
- try {
75
- return await downloadPromise;
76
- }
77
- finally {
78
- queue.delete(downloadPromise);
79
- }
80
- }
81
- async function getIndexHtml(manifest, preResolvedRefs) {
82
- const entryPoint = await resolve(manifest, '/runtime/entry', { preResolvedRefs });
83
- const html = `
84
- <!DOCTYPE html>
85
- <script type="module">
86
- import { load } from ${JSON.stringify(entryPoint)};
87
- await load(${JSON.stringify(manifest)});
88
- console.info('🚀 loaded');
89
- </script>
90
- `;
91
- return html;
92
- }
@@ -1 +0,0 @@
1
- export declare function saveOfflineZip(): void;
@@ -1,3 +0,0 @@
1
- export function saveOfflineZip() {
2
- throw new Error('saveOfflineZip is not available in the browser');
3
- }
@@ -1 +0,0 @@
1
- export declare function saveOfflineZip(manifest: unknown, path: string): Promise<void>;
@@ -1,16 +0,0 @@
1
- import { generateZip } from './generateZip';
2
- import fs from 'fs/promises';
3
- export async function saveOfflineZip(manifest, path) {
4
- if (!path) {
5
- throw new Error('Path is required to save the ZIP file');
6
- }
7
- // should be zip path
8
- if (!path.endsWith('.zip')) {
9
- throw new Error('The specified path must end with .zip');
10
- }
11
- // Generate archive
12
- const blob = await generateZip(manifest);
13
- const arrayBuffer = await blob.arrayBuffer();
14
- await fs.writeFile(path, Buffer.from(arrayBuffer));
15
- console.log('Generated offline ZIP bundle at', path);
16
- }
@@ -1 +0,0 @@
1
- export declare function slugifyFsUnique(input: string): string;