@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
package/dist/esm/index.js CHANGED
@@ -1,24 +1,45 @@
1
- import { log } from './logger';
2
- import { createFunction } from './shared';
3
- const info = globalThis.__efpLoaderBuildInfo;
4
- if (info) {
5
- log('Initialized', { version: info[0], builtAt: info[1] });
1
+ import debug from 'debug';
2
+ import { importHttpRuntime } from './importHttpRuntime';
3
+ import { resolve } from './resolve';
4
+ const log = debug('efp:loader');
5
+ if (typeof __efpLoaderBuildInfo !== 'undefined') {
6
+ log('Initialized', { version: __efpLoaderBuildInfo[0], builtAt: __efpLoaderBuildInfo[1] });
6
7
  }
7
8
  else {
8
9
  log('Initialized');
9
10
  }
10
- export const mount = createFunction('mount');
11
- export const load = createFunction('load');
12
- export const initialize = createFunction('initialize');
13
- // extra
14
- // export const createFloorPlan = createFunction('createFloorPlan');
15
- // export const rewriteManifestToLocalFiles = createFunction('rewriteManifestToLocalFiles');
16
- export async function callFunction_Experimental(name, manifest, ...args) {
17
- const fn = createFunction(name);
18
- return await fn(manifest, ...args);
11
+ export async function loadApi(manifest, options) {
12
+ log('Loading manifest:', manifest);
13
+ if (typeof manifest === 'string') {
14
+ manifest = { $ref: manifest };
15
+ }
16
+ manifest = await resolve(manifest, { fetchCallback: options?.fetchCallback });
17
+ const runtime = await resolve(manifest.runtime, {
18
+ fetchCallback: options?.fetchCallback,
19
+ });
20
+ log('Resolved runtime URL:', runtime);
21
+ if (typeof runtime !== 'string') {
22
+ throw new Error('Resolved runtime is not a string ');
23
+ }
24
+ const api = await importHttpRuntime(runtime);
25
+ api.meta = { runtime };
26
+ return api; //{ ...api, runtime } as LoaderApi;
19
27
  }
20
- export { mutateManifest } from './mutateManifest';
21
- export { downloadOfflineZip, makeOfflineBundle, saveOfflineZip, makeOffline } from './offline';
22
- export { resolve } from './resolve';
23
- // preloadJson('https://efp-runtime.expofp.com/branches/main.json');
24
- // preconnectUrl('https://efp-runtime.expofp.com/');
28
+ // allow calling api functions directly from here
29
+ const api = new Proxy({}, {
30
+ get: (_, prop) => {
31
+ return async (...args) => {
32
+ const manifest = args[0];
33
+ const runtimeApi = await loadApi(manifest);
34
+ const fn = runtimeApi[prop];
35
+ if (typeof fn !== 'function') {
36
+ throw new Error(`API has no function named '${prop}'`);
37
+ }
38
+ return fn.apply(runtimeApi, args);
39
+ };
40
+ },
41
+ });
42
+ export async function load(manifest, ...args) {
43
+ return api.load(manifest, ...args);
44
+ }
45
+ export default api;
@@ -1,45 +1,11 @@
1
- import type { Resolver } from './types';
2
- export interface ResolveContextInternal {
3
- forceFetch: boolean;
4
- refCache: Map<string, Promise<any>>;
5
- /**
6
- * Callback invoked when a URL is fetched or imported.
7
- */
8
- importCallback?: (url: string, type: 'json' | 'script') => void;
9
- signal: AbortSignal | null;
10
- preResolvedRefs?: Map<string, any>;
11
- }
12
- interface ResolveOptionsNotMutate extends Partial<ResolveContextInternal> {
13
- mutate?: false;
1
+ export type ResolveOptions = {
2
+ maxHops?: number;
14
3
  signal?: AbortSignal;
15
- }
16
- interface ResolveOptionMutate extends Omit<ResolveOptionsNotMutate, 'mutate'> {
17
- /**
18
- * Mutate original object during resolution.
19
- */
20
- mutate: true;
21
- }
22
- export type ResolveOptions = ResolveOptionsNotMutate | ResolveOptionMutate;
23
- /**
24
- * Resolves a value from an object using a JSON Pointer RFC 6901.
25
- *
26
- * @param object - The object to resolve the value from
27
- * @param jsonPointer - A JSON Pointer string that must start with '/'
28
- * @param options - Optional context for resolution, including cache and fetch callback
29
- * @returns A promise that resolves to the value at the specified JSON Pointer path
30
- * @throws {Error} If the JSON Pointer is not valid or if a $ref cannot be resolved
31
- *
32
- * @example
33
- * ```typescript
34
- * const obj = { foo: { bar: 'baz' } };
35
- * const result = await resolve(obj, '/foo/bar');
36
- * // result === 'baz'
37
- * ```
38
- */
39
- export declare function resolve(object: any, jsonPointer: string, options: ResolveOptionMutate): Promise<void>;
40
- export declare function resolve<T = any>(object: any, jsonPointer: string, options?: ResolveOptionsNotMutate): Promise<T>;
41
- export declare function resolverResolve(resolver: Resolver, ref: string, context: ResolveContextInternal): Promise<any>;
42
- export declare function canResolve(resolver: Resolver, ref: string): boolean;
43
- export declare function canResolveRefSchema(ref: string, prefixBase: string): boolean;
44
- export declare function parseRefValue(ref: string): string;
45
- export {};
4
+ onHop?: (info: {
5
+ hop: number;
6
+ ref: string;
7
+ via: 'import' | 'fetch';
8
+ }) => void;
9
+ fetchCallback?: (ref: string) => void;
10
+ };
11
+ export declare function resolve<T>(input: unknown, options?: ResolveOptions): Promise<T>;
@@ -1,304 +1,100 @@
1
- import { log } from './logger';
2
- import { resolvers } from './resolvers';
3
- import { createMergedObjectWithOverridenNonRefProps, deepFreeze, replaceObjectFields, } from './shared';
4
- const globalRefCache = new Map();
5
- export async function resolve(object, jsonPointer, options) {
6
- log('Resolving:', jsonPointer, 'of', object, options);
7
- // if (typeof window !== 'undefined') {
8
- // (window as any)['__lastResolveObject'] = object;
9
- // }
10
- const resolveContext = {
11
- importCallback: options?.importCallback,
12
- refCache: options?.refCache || globalRefCache,
13
- forceFetch: !!options?.forceFetch,
14
- signal: options?.signal || null,
15
- preResolvedRefs: options?.preResolvedRefs,
16
- };
17
- if (typeof jsonPointer !== 'string') {
18
- throw new Error(`Invalid JSON Pointer (not a string): ${jsonPointer}`);
19
- }
20
- if (!jsonPointer.startsWith('/')) {
21
- throw new Error(`Invalid JSON Pointer: ${jsonPointer}`);
22
- }
23
- if (jsonPointer.length > 1 && jsonPointer.endsWith('/')) {
24
- throw new Error(`Invalid JSON Pointer: ${jsonPointer}`);
25
- }
26
- // if (jsonPointer === '/') {
27
- // const result = await resolveObject(object, resolveContext);
28
- // if (options?.mutate) {
29
- // replaceObjectFields(object, result);
30
- // }
31
- // return result;
32
- // }
33
- let parts;
34
- if (jsonPointer === '/') {
35
- parts = [];
36
- }
37
- else {
38
- parts = jsonPointer.substring(1).split('/');
39
- }
40
- if (parts.some((part) => part.length === 0))
41
- throw new Error(`Invalid JSON Pointer (empty part): ${jsonPointer}`);
42
- if (options?.mutate) {
43
- // prepend parts with 'root'
44
- parts.unshift('root');
45
- const target = { root: object };
46
- await resovlePartsRecursiveMutate(target, parts, 0, resolveContext);
47
- replaceObjectFields(object, target.root);
48
- }
49
- else {
50
- return await resovlePartsRecursive(object, parts, 0, resolveContext);
51
- }
52
- // prepend parts with 'root'
53
- // parts.unshift('root');
54
- // // if (parts.some((part) => part.length === 0))
55
- // // throw new Error(`Invalid JSON Pointer (empty part): ${jsonPointer}`);
56
- // const target = { root: object };
57
- // const value = await resovlePartsRecursiveMutate(
58
- // target,
59
- // // 'root',
60
- // parts,
61
- // 0,
62
- // resolveContext
63
- // );
64
- // if (options?.mutate) {
65
- // replaceObjectFields(object, target.root);
66
- // }
67
- // log(`Resolved ${jsonPointer}:`, value);
68
- // return value;
69
- }
70
- // TODO: use library for JSON Pointer resolution
71
- async function resovlePartsRecursiveMutate(node,
72
- // key: string,
73
- parts, partsIndex, context) {
74
- const key = parts[partsIndex];
75
- // console.warn('in', key);
76
- await resolveObjectMutate(node, key, context);
77
- if (partsIndex == parts.length - 1)
78
- return;
79
- if (node[key] === null || typeof node[key] !== 'object') {
80
- // console.error('Cannot resolve path, encountered non-object:', node, key);
81
- throw new Error(`Cannot resolve path, encountered non-object at part '${parts.slice(1).join('/')}', index ${partsIndex - 1}'`);
82
- }
83
- return await resovlePartsRecursiveMutate(node[key], parts, partsIndex + 1, context);
84
- }
85
- async function resolveObjectMutate(node, key, context) {
86
- log('resolveObjectMutate:', node, key);
87
- let obj = node[key];
88
- const result = await resolveObject(obj, context);
89
- if (result !== undefined)
90
- node[key] = result;
91
- }
92
- // TODO: use library for JSON Pointer resolution
93
- async function resovlePartsRecursive(object, parts, index, context) {
94
- // should return undefined if last part not found
95
- // if not last part found - throw error
96
- // do not resolve object if its children are not needed (needed part exist as key)
97
- if (index === parts.length) {
98
- // console.warn('Resolving last part:', object);
99
- return await resolveObject(object, context);
100
- }
101
- if (object === null || typeof object !== 'object') {
102
- throw new Error(`Cannot resolve path, encountered non-object at part '${parts.join('/')}', index ${index}'`);
103
- }
104
- const part = parts[index];
105
- let child = object[part];
106
- if (child === undefined) {
107
- // console.warn('Resolving, part not found during resolve:', part, object);
108
- const resolvedObject = await resolveObject(object, context);
109
- child = resolvedObject[part];
110
- }
111
- return await resovlePartsRecursive(child, parts, index + 1, context);
112
- }
113
- async function resolveObject(object, context) {
114
- log('resolveObject:', object);
115
- let obj = object;
116
- do {
117
- if (typeof obj !== 'object' || obj === null || !('$ref' in obj)) {
118
- return obj;
119
- }
120
- const resolversToUse = resolvers.filter((r) => canResolve(r, obj.$ref));
121
- if (resolversToUse.length === 0) {
122
- if (obj.$ref) {
123
- throw new Error(`No resolver found for ref: ${obj.$ref}`);
1
+ // resolveHttpRefToString.ts
2
+ // Follows $ref chains until finding a value without $ref.
3
+ //
4
+ // Rules:
5
+ // - If value is an object with {$ref: string} -> follow it (fetch if http/https URL)
6
+ // - Otherwise -> return the value as-is
7
+ //
8
+ // Browser: tries `import(url, { with: { type: 'json' } })` first, falls back to fetch.
9
+ // Node: uses fetch (Node 18+ has global fetch).
10
+ import debug from 'debug';
11
+ import { fetch } from './fetch';
12
+ const log = debug('efp:loader:resolve');
13
+ export async function resolve(input, options = {}) {
14
+ const maxHops = options.maxHops ?? 32;
15
+ const seen = new Set();
16
+ let cur = input;
17
+ for (let hop = 0; hop < maxHops; hop++) {
18
+ // If it's an object with $ref, follow it
19
+ if (cur && typeof cur === 'object' && '$ref' in cur) {
20
+ const obj = cur;
21
+ const ref = obj.$ref;
22
+ if (typeof ref !== 'string') {
23
+ throw new Error(`$ref must be a string, got: ${typeof ref}`);
124
24
  }
125
- deepFreeze(obj);
126
- return obj;
127
- }
128
- if (resolversToUse.length > 1) {
129
- throw new Error(`Multiple resolvers can resolve ref: ${obj.$ref}`);
25
+ // If it's an http/https URL, fetch it
26
+ if (isHttpUrl(ref)) {
27
+ if (seen.has(ref)) {
28
+ throw new Error(`Circular $ref detected at: ${ref}`);
29
+ }
30
+ seen.add(ref);
31
+ log('Loading JSON ref:', ref);
32
+ options.fetchCallback?.(ref);
33
+ const json = await loadJson(ref, options.signal);
34
+ options.onHop?.({ hop, ref, via: json.__via });
35
+ cur = json.value;
36
+ continue;
37
+ }
38
+ // Non-http $ref (e.g., relative, custom schema) - return the object as-is
39
+ // (caller is responsible for handling these)
40
+ return cur;
130
41
  }
131
- const data = await resolverResolve(resolversToUse[0], obj.$ref, context);
132
- obj = createMergedObjectWithOverridenNonRefProps(data, obj);
133
- } while (true);
134
- }
135
- export async function resolverResolve(resolver, ref, context) {
136
- if (!canResolve(resolver, ref)) {
137
- throw new Error(`Unexpected ref: ${ref}`);
42
+ // No $ref found - return current value
43
+ return cur;
138
44
  }
139
- return resolver.resolveRef(ref, context);
45
+ throw new Error(`Too many ref hops (>${maxHops}). Possible loop or unexpectedly deep chain.`);
140
46
  }
141
- export function canResolve(resolver, ref) {
142
- if (resolver.canResolve) {
143
- return resolver.canResolve(ref);
144
- }
145
- if (resolver.schema) {
146
- return canResolveRefSchema(ref, resolver.schema);
147
- }
148
- throw new Error('Resolver is missing canResolve method and schema property');
47
+ function isHttpUrl(s) {
48
+ return s.startsWith('http://') || s.startsWith('https://');
149
49
  }
150
- export function canResolveRefSchema(ref, prefixBase) {
151
- const prefixes = [`${prefixBase}+`, `${prefixBase}:`];
152
- for (const prefix of prefixes) {
153
- if (ref.startsWith(prefix)) {
154
- return true;
155
- }
50
+ async function loadJson(url, signal) {
51
+ // Try import() JSON first (browser-friendly; depends on runtime/bundler support + CORS)
52
+ const imported = await tryImportJson(url);
53
+ if (imported.ok)
54
+ return { value: imported.value, __via: 'import' };
55
+ // Fallback to fetch
56
+ const res = await fetch(url, {
57
+ method: 'GET',
58
+ signal,
59
+ headers: {
60
+ // Helps some CDNs/content negotiation setups
61
+ Accept: 'application/json, text/plain;q=0.9, */*;q=0.1',
62
+ },
63
+ });
64
+ if (!res.ok) {
65
+ throw new Error(`Failed to fetch JSON ref: ${url} (${res.status} ${res.statusText})`);
66
+ }
67
+ // Prefer JSON; if server mislabels, fallback to text->JSON parse.
68
+ const ct = res.headers.get('content-type') || '';
69
+ if (ct.includes('application/json') || ct.includes('+json')) {
70
+ return { value: await res.json(), __via: 'fetch' };
71
+ }
72
+ const text = await res.text();
73
+ try {
74
+ return { value: JSON.parse(text), __via: 'fetch' };
75
+ }
76
+ catch {
77
+ // If the endpoint literally returns a plain string (not JSON), accept it.
78
+ return { value: text, __via: 'fetch' };
156
79
  }
157
- return false;
158
80
  }
159
- export function parseRefValue(ref) {
160
- // look for anything before ":" or before +https:// or before +http://
161
- // https://www -> https://www
162
- // so some+base+https://www -> https://www
163
- // base+https://www -> https://www
164
- // base:abc -> abc
165
- // "some-base" can contain only non-:
166
- if (ref.startsWith('http://') || ref.startsWith('https://')) {
167
- return ref;
168
- }
169
- // if it is something+http:// or something+https://
170
- const plusHttpIndex = ref.indexOf('+http://');
171
- const plusHttpsIndex = ref.indexOf('+https://');
172
- if (plusHttpIndex !== -1) {
173
- return ref.substring(plusHttpIndex + 1);
174
- }
175
- if (plusHttpsIndex !== -1) {
176
- return ref.substring(plusHttpsIndex + 1);
177
- }
178
- // if it is something:abc
179
- const colonIndex = ref.indexOf(':');
180
- if (colonIndex !== -1) {
181
- return ref.substring(colonIndex + 1);
81
+ async function tryImportJson(url) {
82
+ // `with: { type: 'json' }` is the modern import assertion form.
83
+ // Some environments still only accept `assert: { type: 'json' }`.
84
+ try {
85
+ //// @ts-expect-error - TS lib definitions differ across versions
86
+ const mod = await import(/* @vite-ignore */ url, { with: { type: 'json' } });
87
+ log('Imported JSON via import():', url);
88
+ return { ok: true, value: mod?.default ?? mod };
89
+ }
90
+ catch (e1) {
91
+ try {
92
+ //// @ts-expect-error - fallback for older assertion syntax
93
+ const mod = await import(/* @vite-ignore */ url, { assert: { type: 'json' } });
94
+ return { ok: true, value: mod?.default ?? mod };
95
+ }
96
+ catch (e2) {
97
+ return { ok: false, error: e2 ?? e1 };
98
+ }
182
99
  }
183
- throw new Error(`Error getting URL from: ${ref}, no valid prefix found`);
184
- }
185
- // export function parseRefValue(ref: string): string {
186
- // // look for anything before ":" or before +https:// or before +http://
187
- // // https://www -> https://www
188
- // // so some+base+https://www -> https://www
189
- // // base+https://www -> https://www
190
- // // base:abc -> abc
191
- // // "some-base" can contain only non-:
192
- // if (ref.startsWith('http://') || ref.startsWith('https://')) {
193
- // return ref;
194
- // }
195
- // // if it is something+http:// or something+https://
196
- // const plusHttpIndex = ref.indexOf('+http://');
197
- // const plusHttpsIndex = ref.indexOf('+https://');
198
- // if (plusHttpIndex !== -1) {
199
- // return ref.substring(plusHttpIndex + 1);
200
- // }
201
- // if (plusHttpsIndex !== -1) {
202
- // return ref.substring(plusHttpsIndex + 1);
203
- // }
204
- // // if it is something:abc
205
- // const colonIndex = ref.indexOf(':');
206
- // if (colonIndex !== -1) {
207
- // return ref.substring(colonIndex + 1);
208
- // }
209
- // throw new Error(`Error getting URL from: ${ref}, no valid prefix found`);
210
- // // const prefixBase = ref.split('+')[0].split(':')[0];
211
- // // if (!prefixBase) {
212
- // // throw new Error(`Invalid ref, missing prefix: ${ref}`);
213
- // // }
214
- // // return ref.substring(prefixBase.length + 1);
215
- // // const prefixes = [`${prefixBase}+`, `${prefixBase}:`];
216
- // // for (const prefix of prefixes) {
217
- // // if (ref.startsWith(prefix)) {
218
- // // const url = ref.substring(prefix.length);
219
- // // if (!url) {
220
- // // throw new Error(`Invalid ref, missing URL after prefix "${prefix}": ${ref}`);
221
- // // }
222
- // // return url;
223
- // // }
224
- // // }
225
- // // throw new Error(
226
- // // `Error getting URL from: ${ref}, none of the prefixes matched: ${prefixes.join(', ')}`
227
- // // );
228
- // }
229
- // export function parseRefValue(ref: string, prefixBase: string): string {
230
- // const prefixes = [`${prefixBase}+`, `${prefixBase}:`];
231
- // for (const prefix of prefixes) {
232
- // if (ref.startsWith(prefix)) {
233
- // const url = ref.substring(prefix.length);
234
- // if (!url) {
235
- // throw new Error(`Invalid ref, missing URL after prefix "${prefix}": ${ref}`);
236
- // }
237
- // return url;
238
- // }
239
- // }
240
- // throw new Error(
241
- // `Error getting URL from: ${ref}, none of the prefixes matched: ${prefixes.join(', ')}`
242
- // );
243
- // }
244
- // const importJsonNative = new Function('url', 'return import(url, { with: { type: "json" } });') as (
245
- // url: string
246
- // ) => Promise<any>;
247
- if (typeof window !== 'undefined') {
248
- window['__debugResolve'] = async function debugResolve(object, jsonPointer, options) {
249
- return await resolve(object, jsonPointer, options);
250
- };
251
- // (window as any)['__dd'] = async function dd() {
252
- // const url = 'https://demo.expofp.com/manifest.json';
253
- // // const imp = import;
254
- // const zz = (await importJsonNative(url)).default;
255
- // console.warn('debugResolve demo manifest:', zz);
256
- // // let object: any;
257
- // // let ref: string;
258
- // // let resolveContext: ResolveOptions | undefined;
259
- // // if (typeof objectOrRef === 'string') {
260
- // // object = (window as any)['__lastResolveObject'];
261
- // // ref = objectOrRef;
262
- // // resolveContext = refOrContext;
263
- // // } else {
264
- // // object = objectOrRef;
265
- // // ref = refOrContext;
266
- // // resolveContext = context;
267
- // // }
268
- // // return await resolve(object, ref, resolveContext);
269
- // };
270
100
  }
271
- // if (index === parts.length - 1) {
272
- // return await resolveObject(object, context);
273
- // }
274
- // if (object === null || typeof object !== 'object') {
275
- // throw new Error(
276
- // `Cannot resolve path, encountered non-object at part '${parts.join('/')}', index ${index}'`
277
- // );
278
- // }
279
- // if (!(parts[0] in object)) {
280
- // return undefined;
281
- // }
282
- // let partIndex = 0;
283
- // let currentObject = await resolveObject(object, context);
284
- // while (partIndex < parts.length) {
285
- // const part = parts[partIndex];
286
- // if (typeof currentObject !== 'object' || currentObject === null) {
287
- // throw new Error(
288
- // `Cannot resolve path, encountered non-object at part '${parts.join(
289
- // '/'
290
- // )}, index ${partIndex}'`
291
- // );
292
- // }
293
- // // console.info(
294
- // // 'resolvePath currentObject:',
295
- // // part,
296
- // // JSON.stringify(currentObject, null, 2),
297
- // // currentObject[part]
298
- // // );
299
- // // debugger;
300
- // const child = currentObject[part];
301
- // currentObject = await resolveObject(child, context);
302
- // partIndex++;
303
- // }
304
- // return currentObject;
@@ -1,26 +1,11 @@
1
- import type { ResolveContextInternal } from './resolve';
2
- export interface Resolver {
3
- schema?: string;
4
- canResolve?(ref: string): boolean;
5
- resolveRef(ref: string, context: ResolveContextInternal): Promise<any>;
6
- offlineFunc: 'localizeRef' | 'resolveRef' | OfflineFunc;
7
- }
8
- export interface LocalFetchFile {
9
- url: string;
10
- targetFilePath: string;
11
- }
12
- export interface LocalTextFile {
13
- text: string;
14
- targetFilePath: string;
15
- }
16
- export interface LocalJsonFile {
17
- data: unknown;
18
- targetFilePath: string;
19
- }
20
- export type ManifestData = any;
21
- export type LocalFile = LocalFetchFile | LocalJsonFile | LocalTextFile;
22
- export interface MakeOfflineResult {
23
- manifest: any;
24
- files: AsyncGenerator<LocalFile, ManifestData, void>;
25
- }
26
- export type OfflineFunc = (ref: string, context: ResolveContextInternal) => AsyncGenerator<LocalFile, string, void>;
1
+ export type Ref = {
2
+ $ref: string;
3
+ };
4
+ export type Runtime = string;
5
+ export type Manifest = {
6
+ runtime: Runtime | Ref | string;
7
+ };
8
+ export type LoaderFn = (manifest: Manifest | Ref | string, ...args: unknown[]) => Promise<unknown>;
9
+ export type LoaderApi = {
10
+ [key: string]: LoaderFn | undefined;
11
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expofp/loader",
3
- "version": "1.0.79",
3
+ "version": "1.0.92",
4
4
  "description": "ExpoFP JavaScript loader library",
5
5
  "license": "MIT",
6
6
  "homepage": "https://expofp.com",
@@ -28,12 +28,14 @@
28
28
  "clean": "rm -rf dist",
29
29
  "build": "pnpm clean && tsc && vite build",
30
30
  "preview": "vite preview",
31
+ "test": "DEBUG=efp:* tsx watch ./scripts/test.ts",
31
32
  "css": "tsx watch ./scripts/css.ts",
32
33
  "offline:build": "tsx ./scripts/buildOffline.ts",
33
34
  "offline:serve": "http-server ./tmp/offline",
34
35
  "prepare": "husky"
35
36
  },
36
37
  "dependencies": {
38
+ "@apidevtools/json-schema-ref-parser": "^15.1.3",
37
39
  "debug": "^4.4.3",
38
40
  "fetch-retry": "^6.0.0",
39
41
  "jszip": "^3.10.1"
@@ -1,19 +0,0 @@
1
- import { a as i } from "./tools-D0u8lBvQ.js";
2
- import { p, S as u, l as f } from "./bundle.js";
3
- const U = async function* (e, c) {
4
- const t = p(e), { urls: r, css: a } = g(t, i);
5
- for (const { originalUrl: o, replacedUrl: s } of r)
6
- yield { url: o, targetFilePath: s };
7
- return `${u}:${a}`;
8
- };
9
- function g(e, c) {
10
- const t = /url\(\s*(['"]?)(.*?)\1\s*\)/g, r = [], a = e.replace(t, (o, s, l) => {
11
- const n = c(l);
12
- return r.push({ originalUrl: l, replacedUrl: n }), f("Extracted and replaced URL in CSS:", l, "->", n), `url(${s}${n}${s})`;
13
- });
14
- return { urls: r, css: a };
15
- }
16
- export {
17
- U as offlineFunc
18
- };
19
- //# sourceMappingURL=cssTextAssetResolver.offlineFunc-CWvHnYni.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cssTextAssetResolver.offlineFunc-CWvHnYni.js","sources":["../../src/resolvers/cssTextAssetResolver.offlineFunc.ts"],"sourcesContent":["import { makeTargetPathFromUrl } from '../offline/tools';\nimport { parseRefValue } from '../resolve';\nimport { OfflineFunc } from '../types';\nimport { log, SCHEMA } from './cssTextAssetResolver';\n\nexport const offlineFunc: OfflineFunc = async function* (ref: string, _context: any) {\n const originalCss = parseRefValue(ref);\n const { urls, css } = extractCssUrls(originalCss, makeTargetPathFromUrl);\n\n for (const { originalUrl, replacedUrl } of urls) {\n yield { url: originalUrl, targetFilePath: replacedUrl };\n }\n\n return `${SCHEMA}:${css}`;\n};\n\ninterface UrlReplacement {\n originalUrl: string;\n replacedUrl: string;\n}\n\nfunction extractCssUrls(\n css: string,\n replace: (url: string) => string\n): { urls: UrlReplacement[]; css: string } {\n const urlRegex = /url\\(\\s*(['\"]?)(.*?)\\1\\s*\\)/g;\n const urls: UrlReplacement[] = [];\n\n const replacedCss = css.replace(urlRegex, (_match, quote, url) => {\n const replacedUrl = replace(url);\n urls.push({ originalUrl: url, replacedUrl });\n log('Extracted and replaced URL in CSS:', url, '->', replacedUrl);\n return `url(${quote}${replacedUrl}${quote})`;\n });\n\n return { urls, css: replacedCss };\n}\n"],"names":["offlineFunc","ref","_context","originalCss","parseRefValue","urls","css","extractCssUrls","makeTargetPathFromUrl","originalUrl","replacedUrl","SCHEMA","replace","urlRegex","replacedCss","_match","quote","url","log"],"mappings":";;AAKO,MAAMA,IAA2B,iBAAiBC,GAAaC,GAAe;AACnF,QAAMC,IAAcC,EAAcH,CAAG,GAC/B,EAAE,MAAAI,GAAM,KAAAC,EAAA,IAAQC,EAAeJ,GAAaK,CAAqB;AAEvE,aAAW,EAAE,aAAAC,GAAa,aAAAC,EAAA,KAAiBL;AACzC,UAAM,EAAE,KAAKI,GAAa,gBAAgBC,EAAA;AAG5C,SAAO,GAAGC,CAAM,IAAIL,CAAG;AACzB;AAOA,SAASC,EACPD,GACAM,GACyC;AACzC,QAAMC,IAAW,gCACXR,IAAyB,CAAA,GAEzBS,IAAcR,EAAI,QAAQO,GAAU,CAACE,GAAQC,GAAOC,MAAQ;AAChE,UAAMP,IAAcE,EAAQK,CAAG;AAC/B,WAAAZ,EAAK,KAAK,EAAE,aAAaY,GAAK,aAAAP,GAAa,GAC3CQ,EAAI,sCAAsCD,GAAK,MAAMP,CAAW,GACzD,OAAOM,CAAK,GAAGN,CAAW,GAAGM,CAAK;AAAA,EAC3C,CAAC;AAED,SAAO,EAAE,MAAAX,GAAM,KAAKS,EAAA;AACtB;"}