@loaders.gl/core 4.5.3 → 5.0.0-alpha.10
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/LICENSE +14 -3
- package/dist/dist.dev.js +1789 -352
- package/dist/dist.min.js +4 -3
- package/dist/index.cjs +3087 -311
- package/dist/index.cjs.map +3 -4
- package/dist/index.d.ts +8 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/iterators/make-iterator/make-stream-iterator.js +48 -9
- package/dist/iterators/make-iterator/make-stream-iterator.js.map +1 -1
- package/dist/lib/api/core-api.d.ts +6 -0
- package/dist/lib/api/core-api.d.ts.map +1 -0
- package/dist/lib/api/core-api.js +23 -0
- package/dist/lib/api/core-api.js.map +1 -0
- package/dist/lib/api/create-data-source.d.ts +2 -2
- package/dist/lib/api/create-data-source.d.ts.map +1 -1
- package/dist/lib/api/create-data-source.js +36 -14
- package/dist/lib/api/create-data-source.js.map +1 -1
- package/dist/lib/api/load-in-batches.d.ts +4 -4
- package/dist/lib/api/load-in-batches.d.ts.map +1 -1
- package/dist/lib/api/load-in-batches.js +17 -6
- package/dist/lib/api/load-in-batches.js.map +1 -1
- package/dist/lib/api/load-loader.d.ts +10 -0
- package/dist/lib/api/load-loader.d.ts.map +1 -0
- package/dist/lib/api/load-loader.js +222 -0
- package/dist/lib/api/load-loader.js.map +1 -0
- package/dist/lib/api/load.d.ts +3 -3
- package/dist/lib/api/load.d.ts.map +1 -1
- package/dist/lib/api/load.js +84 -5
- package/dist/lib/api/load.js.map +1 -1
- package/dist/lib/api/parse-file.d.ts +15 -0
- package/dist/lib/api/parse-file.d.ts.map +1 -0
- package/dist/lib/api/parse-file.js +74 -0
- package/dist/lib/api/parse-file.js.map +1 -0
- package/dist/lib/api/parse-in-batches.d.ts +2 -2
- package/dist/lib/api/parse-in-batches.d.ts.map +1 -1
- package/dist/lib/api/parse-in-batches.js +18 -7
- package/dist/lib/api/parse-in-batches.js.map +1 -1
- package/dist/lib/api/parse-sync.d.ts +2 -2
- package/dist/lib/api/parse-sync.d.ts.map +1 -1
- package/dist/lib/api/parse-sync.js +10 -1
- package/dist/lib/api/parse-sync.js.map +1 -1
- package/dist/lib/api/parse.d.ts +2 -2
- package/dist/lib/api/parse.d.ts.map +1 -1
- package/dist/lib/api/parse.js +34 -17
- package/dist/lib/api/parse.js.map +1 -1
- package/dist/lib/api/preload.d.ts +14 -0
- package/dist/lib/api/preload.d.ts.map +1 -0
- package/dist/lib/api/preload.js +13 -0
- package/dist/lib/api/preload.js.map +1 -0
- package/dist/lib/api/register-loaders.js +1 -1
- package/dist/lib/api/register-loaders.js.map +1 -1
- package/dist/lib/api/select-loader.d.ts.map +1 -1
- package/dist/lib/api/select-loader.js +48 -5
- package/dist/lib/api/select-loader.js.map +1 -1
- package/dist/lib/api/select-source.d.ts +3 -3
- package/dist/lib/api/select-source.d.ts.map +1 -1
- package/dist/lib/api/select-source.js +2 -5
- package/dist/lib/api/select-source.js.map +1 -1
- package/dist/lib/fetch/fetch-error-message.js +1 -1
- package/dist/lib/fetch/fetch-error-message.js.map +1 -1
- package/dist/lib/filesystems/browser-filesystem.d.ts.map +1 -1
- package/dist/lib/filesystems/browser-filesystem.js +25 -11
- package/dist/lib/filesystems/browser-filesystem.js.map +1 -1
- package/dist/lib/init.js +1 -1
- package/dist/lib/init.js.map +1 -1
- package/dist/lib/loader-utils/check-errors.js +1 -1
- package/dist/lib/loader-utils/check-errors.js.map +1 -1
- package/dist/lib/loader-utils/get-data.d.ts +4 -0
- package/dist/lib/loader-utils/get-data.d.ts.map +1 -1
- package/dist/lib/loader-utils/get-data.js +26 -0
- package/dist/lib/loader-utils/get-data.js.map +1 -1
- package/dist/lib/loader-utils/get-fetch-function.d.ts +1 -1
- package/dist/lib/loader-utils/get-fetch-function.d.ts.map +1 -1
- package/dist/lib/loader-utils/get-fetch-function.js +16 -10
- package/dist/lib/loader-utils/get-fetch-function.js.map +1 -1
- package/dist/lib/loader-utils/loader-context.d.ts +2 -2
- package/dist/lib/loader-utils/loader-context.d.ts.map +1 -1
- package/dist/lib/loader-utils/loader-context.js +11 -4
- package/dist/lib/loader-utils/loader-context.js.map +1 -1
- package/dist/lib/loader-utils/loggers.d.ts +19 -0
- package/dist/lib/loader-utils/loggers.d.ts.map +1 -1
- package/dist/lib/loader-utils/loggers.js +28 -2
- package/dist/lib/loader-utils/loggers.js.map +1 -1
- package/dist/lib/loader-utils/option-defaults.d.ts +1 -0
- package/dist/lib/loader-utils/option-defaults.d.ts.map +1 -1
- package/dist/lib/loader-utils/option-defaults.js +5 -0
- package/dist/lib/loader-utils/option-defaults.js.map +1 -1
- package/dist/lib/loader-utils/option-utils.d.ts +7 -0
- package/dist/lib/loader-utils/option-utils.d.ts.map +1 -1
- package/dist/lib/loader-utils/option-utils.js +91 -3
- package/dist/lib/loader-utils/option-utils.js.map +1 -1
- package/dist/lib/utils/response-utils.js +5 -14
- package/dist/lib/utils/response-utils.js.map +1 -1
- package/dist/null-loader.d.ts.map +1 -1
- package/dist/null-loader.js +1 -1
- package/dist/null-loader.js.map +1 -1
- package/dist/null-worker-node.js +270 -42
- package/dist/null-worker.js +270 -42
- package/package.json +6 -6
- package/src/index.ts +10 -1
- package/src/iterators/make-iterator/make-stream-iterator.ts +47 -9
- package/src/lib/api/core-api.ts +25 -0
- package/src/lib/api/create-data-source.ts +53 -24
- package/src/lib/api/load-in-batches.ts +33 -21
- package/src/lib/api/load-loader.ts +306 -0
- package/src/lib/api/load.ts +160 -9
- package/src/lib/api/parse-file.ts +156 -0
- package/src/lib/api/parse-in-batches.ts +35 -8
- package/src/lib/api/parse-sync.ts +27 -2
- package/src/lib/api/parse.ts +61 -20
- package/src/lib/api/preload.ts +46 -0
- package/src/lib/api/register-loaders.ts +1 -1
- package/src/lib/api/select-loader.ts +57 -5
- package/src/lib/api/select-source.ts +7 -10
- package/src/lib/fetch/fetch-error-message.ts +1 -1
- package/src/lib/filesystems/browser-filesystem.ts +25 -11
- package/src/lib/loader-utils/check-errors.ts +1 -1
- package/src/lib/loader-utils/get-data.ts +36 -0
- package/src/lib/loader-utils/get-fetch-function.ts +17 -15
- package/src/lib/loader-utils/loader-context.ts +13 -5
- package/src/lib/loader-utils/loggers.ts +28 -2
- package/src/lib/loader-utils/option-defaults.ts +5 -0
- package/src/lib/loader-utils/option-utils.ts +106 -3
- package/src/lib/utils/response-utils.ts +5 -15
- package/src/null-loader.ts +3 -3
|
@@ -2,26 +2,23 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type {SourceLoader} from '@loaders.gl/loader-utils';
|
|
6
|
+
import {selectLoaderSync} from './select-loader';
|
|
6
7
|
|
|
7
8
|
/** Guess service type from URL */
|
|
8
9
|
export function selectSource(
|
|
9
10
|
url: string | Blob,
|
|
10
|
-
sources:
|
|
11
|
+
sources: SourceLoader[],
|
|
11
12
|
options?: {
|
|
12
13
|
/** Provide id of a source to select that source. Omit or provide 'auto' to test the source*/
|
|
13
14
|
type?: string;
|
|
14
15
|
nothrow?: boolean;
|
|
15
16
|
}
|
|
16
|
-
):
|
|
17
|
+
): SourceLoader | null {
|
|
17
18
|
const type = options?.type || 'auto';
|
|
18
|
-
let selectedSource:
|
|
19
|
+
let selectedSource: SourceLoader | null = null;
|
|
19
20
|
if (type === 'auto') {
|
|
20
|
-
|
|
21
|
-
if (typeof url === 'string' && source.testURL && source.testURL(url)) {
|
|
22
|
-
return source;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
21
|
+
selectedSource = selectLoaderSync(url, sources, {core: {nothrow: true}}) as SourceLoader | null;
|
|
25
22
|
} else {
|
|
26
23
|
selectedSource = getSourceOfType(type, sources);
|
|
27
24
|
}
|
|
@@ -34,7 +31,7 @@ export function selectSource(
|
|
|
34
31
|
}
|
|
35
32
|
|
|
36
33
|
/** Guess service type from URL */
|
|
37
|
-
function getSourceOfType(type: string, sources:
|
|
34
|
+
function getSourceOfType(type: string, sources: SourceLoader[]): SourceLoader | null {
|
|
38
35
|
for (const service of sources) {
|
|
39
36
|
if (service.type === type) {
|
|
40
37
|
return service;
|
|
@@ -50,23 +50,34 @@ export class BrowserFileSystem implements FileSystem {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
// Local fetches are served from the list of files
|
|
53
|
-
const file = this.
|
|
53
|
+
const file = this._getFile(path, true);
|
|
54
54
|
if (!file) {
|
|
55
55
|
return new Response(path, {status: 400, statusText: 'NOT FOUND'});
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
const headers = new Headers(options?.headers);
|
|
59
59
|
const range = headers.get('Range');
|
|
60
|
-
const bytes = range && /bytes=(
|
|
60
|
+
const bytes = range && /bytes=(\d+)-(\d+)/.exec(range);
|
|
61
61
|
|
|
62
62
|
if (bytes) {
|
|
63
63
|
const start = parseInt(bytes[1]);
|
|
64
|
-
const end = parseInt(bytes[2]);
|
|
64
|
+
const end = Math.min(parseInt(bytes[2]), file.size - 1);
|
|
65
|
+
if (start > end) {
|
|
66
|
+
const response = new Response(null, {
|
|
67
|
+
status: 416,
|
|
68
|
+
headers: {'Content-Range': `bytes */${file.size}`}
|
|
69
|
+
});
|
|
70
|
+
Object.defineProperty(response, 'url', {value: path});
|
|
71
|
+
return response;
|
|
72
|
+
}
|
|
65
73
|
// The trick when reading File objects is to read successive "slices" of the File
|
|
66
74
|
// Per spec https://w3c.github.io/FileAPI/, slicing a File should only update the start and end fields
|
|
67
75
|
// Actually reading from file should happen in `readAsArrayBuffer` (and as far we can tell it does)
|
|
68
|
-
const data = await file.slice(start, end).arrayBuffer();
|
|
69
|
-
const response = new Response(data
|
|
76
|
+
const data = await file.slice(start, end + 1).arrayBuffer();
|
|
77
|
+
const response = new Response(data, {
|
|
78
|
+
status: 206,
|
|
79
|
+
headers: {'Content-Range': `bytes ${start}-${end}/${file.size}`}
|
|
80
|
+
});
|
|
70
81
|
Object.defineProperty(response, 'url', {value: path});
|
|
71
82
|
return response;
|
|
72
83
|
}
|
|
@@ -95,7 +106,7 @@ export class BrowserFileSystem implements FileSystem {
|
|
|
95
106
|
* Return information (size) about files in this file system
|
|
96
107
|
*/
|
|
97
108
|
async stat(path: string, options?: object): Promise<{size: number}> {
|
|
98
|
-
const file = this.
|
|
109
|
+
const file = this._getFile(path, false);
|
|
99
110
|
if (!file) {
|
|
100
111
|
throw new Error(path);
|
|
101
112
|
}
|
|
@@ -106,16 +117,19 @@ export class BrowserFileSystem implements FileSystem {
|
|
|
106
117
|
* Just removes the file from the list
|
|
107
118
|
*/
|
|
108
119
|
async unlink(path: string): Promise<void> {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
const file = this._getFile(path, false);
|
|
121
|
+
if (file) {
|
|
122
|
+
delete this.files[file.name];
|
|
123
|
+
delete this.lowerCaseFiles[file.name.toLowerCase()];
|
|
124
|
+
this.usedFiles[file.name] = true;
|
|
125
|
+
}
|
|
112
126
|
}
|
|
113
127
|
|
|
114
128
|
// implements IRandomAccessFileSystem
|
|
115
129
|
|
|
116
130
|
// RANDOM ACCESS
|
|
117
131
|
async openReadableFile(pathname: string, flags: unknown): Promise<ReadableFile> {
|
|
118
|
-
return new BlobFile(this.
|
|
132
|
+
return new BlobFile(this._getFile(pathname, true));
|
|
119
133
|
}
|
|
120
134
|
|
|
121
135
|
// PRIVATE
|
|
@@ -123,7 +137,7 @@ export class BrowserFileSystem implements FileSystem {
|
|
|
123
137
|
// Supports case independent paths, and file usage tracking
|
|
124
138
|
_getFile(path: string, used: boolean): File {
|
|
125
139
|
// Prefer case match, but fall back to case independent.
|
|
126
|
-
const file = this.files[path] || this.lowerCaseFiles[path];
|
|
140
|
+
const file = this.files[path] || this.lowerCaseFiles[path.toLowerCase()];
|
|
127
141
|
if (file && used) {
|
|
128
142
|
this.usedFiles[path] = true;
|
|
129
143
|
}
|
|
@@ -95,6 +95,42 @@ export async function getArrayBufferOrStringFromData(
|
|
|
95
95
|
throw new Error(ERR_DATA);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Resolves the provided data into an {@link ArrayBuffer}, preserving bytes for worker transfer.
|
|
100
|
+
*/
|
|
101
|
+
export async function getArrayBufferFromData(
|
|
102
|
+
data: DataType,
|
|
103
|
+
options: LoaderOptions
|
|
104
|
+
): Promise<ArrayBuffer> {
|
|
105
|
+
if (typeof data === 'string') {
|
|
106
|
+
return new TextEncoder().encode(data).buffer;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (isArrayBufferLike(data)) {
|
|
110
|
+
return toArrayBuffer(toArrayBufferView(data));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (isBlob(data)) {
|
|
114
|
+
data = await makeResponse(data);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (isResponse(data)) {
|
|
118
|
+
await checkResponse(data);
|
|
119
|
+
return await data.arrayBuffer();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (isReadableStream(data)) {
|
|
123
|
+
// @ts-expect-error TS2559 options type
|
|
124
|
+
data = makeIterator(data as ReadableStream, options);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (isIterable(data) || isAsyncIterable(data)) {
|
|
128
|
+
return concatenateArrayBuffersAsync(data as AsyncIterable<ArrayBufferLike>);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
throw new Error(ERR_DATA);
|
|
132
|
+
}
|
|
133
|
+
|
|
98
134
|
/**
|
|
99
135
|
* Normalizes batchable inputs into async iterables for batch parsing flows.
|
|
100
136
|
* Supports synchronous iterables, async iterables, fetch responses, readable streams, and
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import type {LoaderContext, LoaderOptions, FetchLike} from '@loaders.gl/loader-utils';
|
|
6
|
-
import {isObject} from '@loaders.gl/loader-utils';
|
|
6
|
+
import {createAuthenticatedFetch, isObject} from '@loaders.gl/loader-utils';
|
|
7
7
|
import {fetchFile} from '../fetch/fetch-file';
|
|
8
8
|
import {getGlobalLoaderOptions} from './option-utils';
|
|
9
9
|
|
|
@@ -14,28 +14,30 @@ import {getGlobalLoaderOptions} from './option-utils';
|
|
|
14
14
|
*/
|
|
15
15
|
export function getFetchFunction(
|
|
16
16
|
options?: LoaderOptions,
|
|
17
|
-
context?: Omit<LoaderContext, 'fetch'
|
|
17
|
+
context?: Omit<LoaderContext, 'fetch' | 'coreApi'> &
|
|
18
|
+
Partial<Pick<LoaderContext, 'fetch' | 'coreApi'>>
|
|
18
19
|
): FetchLike {
|
|
19
20
|
const globalOptions = getGlobalLoaderOptions();
|
|
20
21
|
|
|
21
22
|
const loaderOptions = options || globalOptions;
|
|
22
23
|
const fetchOption = loaderOptions.fetch ?? loaderOptions.core?.fetch;
|
|
24
|
+
let fetchFunction: FetchLike;
|
|
23
25
|
|
|
24
26
|
// options.fetch can be a function
|
|
25
27
|
if (typeof fetchOption === 'function') {
|
|
26
|
-
|
|
28
|
+
fetchFunction = fetchOption;
|
|
29
|
+
} else if (isObject(fetchOption)) {
|
|
30
|
+
fetchFunction = context?.fetch || fetchFile;
|
|
31
|
+
} else if (context?.fetch) {
|
|
32
|
+
fetchFunction = context.fetch;
|
|
33
|
+
} else {
|
|
34
|
+
fetchFunction = fetchFile;
|
|
27
35
|
}
|
|
28
36
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (context?.fetch) {
|
|
36
|
-
return context?.fetch;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// else return the default fetch function
|
|
40
|
-
return fetchFile;
|
|
37
|
+
return createAuthenticatedFetch({
|
|
38
|
+
fetch: fetchFunction,
|
|
39
|
+
credentials: loaderOptions.core?.credentials || [],
|
|
40
|
+
authentications: loaderOptions.core?.authentications,
|
|
41
|
+
fetchOptions: isObject(fetchOption) ? (fetchOption as RequestInit) : undefined
|
|
42
|
+
});
|
|
41
43
|
}
|
|
@@ -6,9 +6,11 @@ import type {Loader, LoaderContext, StrictLoaderOptions} from '@loaders.gl/loade
|
|
|
6
6
|
import {getFetchFunction} from './get-fetch-function';
|
|
7
7
|
import {extractQueryString, stripQueryString} from '../utils/url-utils';
|
|
8
8
|
import {path} from '@loaders.gl/loader-utils';
|
|
9
|
+
import {coreApi} from '../api/core-api';
|
|
9
10
|
|
|
10
11
|
/** Properties for creating an updated context */
|
|
11
|
-
type LoaderContextProps = Omit<LoaderContext, 'fetch'
|
|
12
|
+
type LoaderContextProps = Omit<LoaderContext, 'fetch' | 'coreApi'> &
|
|
13
|
+
Partial<Pick<LoaderContext, 'fetch' | 'coreApi'>>;
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* "sub" loaders invoked by other loaders get a "context" injected on `this`
|
|
@@ -17,22 +19,28 @@ type LoaderContextProps = Omit<LoaderContext, 'fetch'> & Partial<Pick<LoaderCont
|
|
|
17
19
|
*
|
|
18
20
|
* @param context
|
|
19
21
|
* @param options
|
|
20
|
-
* @param
|
|
22
|
+
* @param parentContext
|
|
21
23
|
*/
|
|
22
24
|
export function getLoaderContext(
|
|
23
25
|
context: LoaderContextProps,
|
|
24
26
|
options: StrictLoaderOptions,
|
|
25
27
|
parentContext: LoaderContext | null
|
|
26
28
|
): LoaderContext {
|
|
27
|
-
// For recursive calls,
|
|
29
|
+
// For recursive calls, preserve the context while applying this loader's options
|
|
28
30
|
// TODO - add any additional loaders to context?
|
|
29
31
|
if (parentContext) {
|
|
30
|
-
return
|
|
32
|
+
return {
|
|
33
|
+
...parentContext,
|
|
34
|
+
coreApi: parentContext.coreApi || context.coreApi || coreApi,
|
|
35
|
+
_parse: parentContext._parse || context._parse,
|
|
36
|
+
fetch: getFetchFunction(options, parentContext)
|
|
37
|
+
};
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
const newContext: LoaderContext = {
|
|
41
|
+
...context,
|
|
34
42
|
fetch: getFetchFunction(options, context),
|
|
35
|
-
|
|
43
|
+
coreApi: context.coreApi || coreApi
|
|
36
44
|
};
|
|
37
45
|
|
|
38
46
|
// Parse URLs so that subloaders can easily generate correct strings
|
|
@@ -6,42 +6,68 @@
|
|
|
6
6
|
|
|
7
7
|
import {Log} from '@probe.gl/log';
|
|
8
8
|
|
|
9
|
+
/** Default probe.gl logger used by loaders.gl. */
|
|
9
10
|
export const probeLog = new Log({id: 'loaders.gl'});
|
|
10
11
|
|
|
11
12
|
type LogFunction = () => void;
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
/** Logger implementation that intentionally drops all messages. */
|
|
14
15
|
export class NullLog {
|
|
16
|
+
/** Drops a log message. */
|
|
15
17
|
log(): LogFunction {
|
|
16
18
|
return () => {};
|
|
17
19
|
}
|
|
20
|
+
/** Drops an info message. */
|
|
18
21
|
info(): LogFunction {
|
|
19
22
|
return () => {};
|
|
20
23
|
}
|
|
24
|
+
/** Logs one message once; no-op for the null logger. */
|
|
25
|
+
once(): LogFunction {
|
|
26
|
+
return () => {};
|
|
27
|
+
}
|
|
28
|
+
/** Drops a warning message. */
|
|
21
29
|
warn(): LogFunction {
|
|
22
30
|
return () => {};
|
|
23
31
|
}
|
|
32
|
+
/** Drops an error message. */
|
|
24
33
|
error(): LogFunction {
|
|
25
34
|
return () => {};
|
|
26
35
|
}
|
|
27
36
|
}
|
|
28
37
|
|
|
29
|
-
|
|
38
|
+
/** Logger implementation that forwards messages to the global console. */
|
|
30
39
|
export class ConsoleLog {
|
|
40
|
+
/** Console-like object used for message output. */
|
|
31
41
|
console;
|
|
42
|
+
/** Messages already emitted through `once`. */
|
|
43
|
+
private onceMessages = new Set<string>();
|
|
32
44
|
|
|
45
|
+
/** Creates a console-backed logger. */
|
|
33
46
|
constructor() {
|
|
34
47
|
this.console = console; // eslint-disable-line
|
|
35
48
|
}
|
|
49
|
+
/** Logs a message to the console. */
|
|
36
50
|
log(...args: unknown[]): LogFunction {
|
|
37
51
|
return this.console.log.bind(this.console, ...args);
|
|
38
52
|
}
|
|
53
|
+
/** Logs an informational message to the console. */
|
|
39
54
|
info(...args: unknown[]): LogFunction {
|
|
40
55
|
return this.console.info.bind(this.console, ...args);
|
|
41
56
|
}
|
|
57
|
+
/** Logs one message once to the console. */
|
|
58
|
+
once(...args: unknown[]): LogFunction {
|
|
59
|
+
const message = String(args[0]);
|
|
60
|
+
if (this.onceMessages.has(message)) {
|
|
61
|
+
return () => {};
|
|
62
|
+
}
|
|
63
|
+
this.onceMessages.add(message);
|
|
64
|
+
return this.console.info.bind(this.console, ...args);
|
|
65
|
+
}
|
|
66
|
+
/** Logs a warning message to the console. */
|
|
42
67
|
warn(...args: unknown[]): LogFunction {
|
|
43
68
|
return this.console.warn.bind(this.console, ...args);
|
|
44
69
|
}
|
|
70
|
+
/** Logs an error message to the console. */
|
|
45
71
|
error(...args: unknown[]): LogFunction {
|
|
46
72
|
return this.console.error.bind(this.console, ...args);
|
|
47
73
|
}
|
|
@@ -7,6 +7,7 @@ import {isBrowser} from '@loaders.gl/loader-utils';
|
|
|
7
7
|
import {ConsoleLog} from './loggers';
|
|
8
8
|
|
|
9
9
|
export const DEFAULT_LOADER_OPTIONS: LoaderOptions = {
|
|
10
|
+
searchParams: undefined,
|
|
10
11
|
core: {
|
|
11
12
|
baseUrl: undefined,
|
|
12
13
|
// baseUrl
|
|
@@ -15,11 +16,14 @@ export const DEFAULT_LOADER_OPTIONS: LoaderOptions = {
|
|
|
15
16
|
fallbackMimeType: undefined,
|
|
16
17
|
ignoreRegisteredLoaders: undefined,
|
|
17
18
|
nothrow: false,
|
|
19
|
+
shape: undefined,
|
|
18
20
|
log: new ConsoleLog(), // A probe.gl compatible (`log.log()()` syntax) that just logs to console
|
|
19
21
|
useLocalLibraries: false,
|
|
22
|
+
subloaders: undefined,
|
|
20
23
|
|
|
21
24
|
CDN: 'https://unpkg.com/@loaders.gl',
|
|
22
25
|
worker: true, // By default, use worker if provided by loader.
|
|
26
|
+
workerThreshold: 0.1,
|
|
23
27
|
maxConcurrency: 3, // How many worker instances should be created for each loader.
|
|
24
28
|
maxMobileConcurrency: 1, // How many worker instances should be created for each loader on mobile devices.
|
|
25
29
|
reuseWorkers: isBrowser, // By default reuse workers in browser (Node.js refuses to terminate if browsers are running)
|
|
@@ -57,6 +61,7 @@ export const REMOVED_LOADER_OPTIONS = {
|
|
|
57
61
|
|
|
58
62
|
limit: 'core.limit',
|
|
59
63
|
_limitMB: 'core._limitMB',
|
|
64
|
+
shape: 'core.shape',
|
|
60
65
|
batchSize: 'core.batchSize',
|
|
61
66
|
batchDebounceMs: 'core.batchDebounceMs',
|
|
62
67
|
metadata: 'core.metadata',
|
|
@@ -26,19 +26,56 @@ const CORE_LOADER_OPTION_KEYS = [
|
|
|
26
26
|
'useLocalLibraries',
|
|
27
27
|
'CDN',
|
|
28
28
|
'worker',
|
|
29
|
+
'workerThreshold',
|
|
29
30
|
'maxConcurrency',
|
|
30
31
|
'maxMobileConcurrency',
|
|
31
32
|
'reuseWorkers',
|
|
33
|
+
'workerTransferBufferCopy',
|
|
32
34
|
'_nodeWorkers',
|
|
33
35
|
'_workerType',
|
|
34
36
|
'limit',
|
|
35
37
|
'_limitMB',
|
|
38
|
+
'shape',
|
|
36
39
|
'batchSize',
|
|
37
40
|
'batchDebounceMs',
|
|
38
41
|
'metadata',
|
|
39
42
|
'transforms'
|
|
40
43
|
] as const;
|
|
41
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Appends loader search parameters to a URL while preserving existing parameters and fragments.
|
|
47
|
+
* @param url URL to update
|
|
48
|
+
* @param options Loader options containing optional search parameters
|
|
49
|
+
* @returns URL with the configured parameters appended
|
|
50
|
+
*/
|
|
51
|
+
export function applySearchParamsToUrl(url: string, options?: LoaderOptions): string {
|
|
52
|
+
const searchParams = options?.searchParams;
|
|
53
|
+
if (!searchParams || Object.keys(searchParams).length === 0 || /^(?:data|blob):/i.test(url)) {
|
|
54
|
+
return url;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const hashIndex = url.indexOf('#');
|
|
58
|
+
const hash = hashIndex >= 0 ? url.slice(hashIndex) : '';
|
|
59
|
+
const urlWithoutHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url;
|
|
60
|
+
const queryIndex = urlWithoutHash.indexOf('?');
|
|
61
|
+
const path = queryIndex >= 0 ? urlWithoutHash.slice(0, queryIndex) : urlWithoutHash;
|
|
62
|
+
const query = queryIndex >= 0 ? urlWithoutHash.slice(queryIndex + 1) : '';
|
|
63
|
+
const existingSearchParams = new URLSearchParams(query);
|
|
64
|
+
const appendedSearchParams = new URLSearchParams();
|
|
65
|
+
for (const [key, value] of Object.entries(searchParams)) {
|
|
66
|
+
if (!existingSearchParams.has(key)) {
|
|
67
|
+
appendedSearchParams.set(key, String(value));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const serializedAppendedSearchParams = appendedSearchParams.toString();
|
|
72
|
+
return `${path}${queryIndex >= 0 ? `?${query}` : ''}${
|
|
73
|
+
serializedAppendedSearchParams
|
|
74
|
+
? `${queryIndex >= 0 ? '&' : '?'}${serializedAppendedSearchParams}`
|
|
75
|
+
: ''
|
|
76
|
+
}${hash}`;
|
|
77
|
+
}
|
|
78
|
+
|
|
42
79
|
/**
|
|
43
80
|
* Global state for loaders.gl. Stored on `globalThis.loaders._state`
|
|
44
81
|
*/
|
|
@@ -109,7 +146,10 @@ export function normalizeOptions(
|
|
|
109
146
|
loaders = Array.isArray(loaders) ? loaders : [loaders];
|
|
110
147
|
|
|
111
148
|
validateOptions(options, loaders);
|
|
112
|
-
|
|
149
|
+
validateWorkerThreshold(options);
|
|
150
|
+
const normalizedOptions = normalizeLoaderOptions(normalizeOptionsInternal(loader, options, url));
|
|
151
|
+
validateWorkerThreshold(normalizedOptions);
|
|
152
|
+
return normalizedOptions;
|
|
113
153
|
}
|
|
114
154
|
|
|
115
155
|
/**
|
|
@@ -157,6 +197,14 @@ function validateOptions(options: LoaderOptions, loaders: Loader[]): void {
|
|
|
157
197
|
}
|
|
158
198
|
}
|
|
159
199
|
|
|
200
|
+
/** Validates the automatic worker-selection threshold. */
|
|
201
|
+
function validateWorkerThreshold(options: LoaderOptions): void {
|
|
202
|
+
const threshold = options.core?.workerThreshold;
|
|
203
|
+
if (threshold !== undefined && (!Number.isFinite(threshold) || threshold < 0 || threshold > 1)) {
|
|
204
|
+
throw new Error('core.workerThreshold must be a finite number between 0 and 1');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
160
208
|
// eslint-disable-next-line max-params, complexity
|
|
161
209
|
function validateOptionsObject(
|
|
162
210
|
options: LoaderOptions,
|
|
@@ -235,6 +283,7 @@ function normalizeOptionsInternal(
|
|
|
235
283
|
|
|
236
284
|
const userOptions = normalizeLoaderOptions(options);
|
|
237
285
|
mergeNestedFields(mergedOptions, userOptions);
|
|
286
|
+
applyCoreShapeDefault(mergedOptions, userOptions, loader);
|
|
238
287
|
|
|
239
288
|
addUrlOptions(mergedOptions, url);
|
|
240
289
|
addDeprecatedTopLevelOptions(mergedOptions);
|
|
@@ -242,7 +291,50 @@ function normalizeOptionsInternal(
|
|
|
242
291
|
return mergedOptions;
|
|
243
292
|
}
|
|
244
293
|
|
|
245
|
-
|
|
294
|
+
/**
|
|
295
|
+
* Applies `options.core.shape` to a loader's scoped `shape` option when that loader declares
|
|
296
|
+
* shape support and neither global nor user-supplied loader-scoped options override it.
|
|
297
|
+
* @param mergedOptions fully merged options object being normalized
|
|
298
|
+
* @param userOptions normalized user-supplied options
|
|
299
|
+
* @param loader selected loader
|
|
300
|
+
*/
|
|
301
|
+
function applyCoreShapeDefault(
|
|
302
|
+
mergedOptions: LoaderOptions,
|
|
303
|
+
userOptions: LoaderOptions,
|
|
304
|
+
loader: Loader
|
|
305
|
+
): void {
|
|
306
|
+
const coreShape = mergedOptions.core?.shape;
|
|
307
|
+
if (coreShape === undefined) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const loaderScopedDefaults = loader.options?.[loader.id];
|
|
312
|
+
if (!isPureObject(loaderScopedDefaults) || !('shape' in loaderScopedDefaults)) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const globalLoaderScopedOptions = getGlobalLoaderOptions()[loader.id];
|
|
317
|
+
if (isPureObject(globalLoaderScopedOptions) && 'shape' in globalLoaderScopedOptions) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const userLoaderScopedOptions = userOptions[loader.id];
|
|
322
|
+
if (isPureObject(userLoaderScopedOptions) && 'shape' in userLoaderScopedOptions) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const loaderScopedOptions = mergedOptions[loader.id];
|
|
327
|
+
mergedOptions[loader.id] = {
|
|
328
|
+
...(isPureObject(loaderScopedOptions) ? loaderScopedOptions : {}),
|
|
329
|
+
shape: coreShape
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Merges one level of nested option objects into the target options record.
|
|
335
|
+
* @param mergedOptions target options object to mutate
|
|
336
|
+
* @param options source options object
|
|
337
|
+
*/
|
|
246
338
|
function mergeNestedFields(mergedOptions: LoaderOptions, options: LoaderOptions): void {
|
|
247
339
|
for (const key in options) {
|
|
248
340
|
// Check for nested options
|
|
@@ -288,6 +380,11 @@ function cloneLoaderOptions(options: LoaderOptions): LoaderOptions {
|
|
|
288
380
|
return clonedOptions;
|
|
289
381
|
}
|
|
290
382
|
|
|
383
|
+
/**
|
|
384
|
+
* Moves deprecated top-level core option aliases into `options.core` without overwriting
|
|
385
|
+
* explicitly provided `options.core` values.
|
|
386
|
+
* @param options loader options to normalize in place
|
|
387
|
+
*/
|
|
291
388
|
function moveDeprecatedTopLevelOptionsToCore(options: LoaderOptions): void {
|
|
292
389
|
if (options.baseUri !== undefined) {
|
|
293
390
|
options.core ||= {};
|
|
@@ -298,7 +395,8 @@ function moveDeprecatedTopLevelOptionsToCore(options: LoaderOptions): void {
|
|
|
298
395
|
|
|
299
396
|
for (const key of CORE_LOADER_OPTION_KEYS) {
|
|
300
397
|
if ((options as Record<string, unknown>)[key] !== undefined) {
|
|
301
|
-
|
|
398
|
+
options.core ||= {};
|
|
399
|
+
const coreOptions = options.core;
|
|
302
400
|
const coreRecord = coreOptions as Record<string, unknown>;
|
|
303
401
|
// Treat deprecated top-level core options as aliases to `options.core`, but never override an explicitly
|
|
304
402
|
// provided `options.core` value.
|
|
@@ -318,6 +416,11 @@ function moveDeprecatedTopLevelOptionsToCore(options: LoaderOptions): void {
|
|
|
318
416
|
}
|
|
319
417
|
}
|
|
320
418
|
|
|
419
|
+
/**
|
|
420
|
+
* Rehydrates deprecated top-level aliases from `options.core` for compatibility with older
|
|
421
|
+
* call sites that still read normalized options from the top level.
|
|
422
|
+
* @param options normalized loader options to mutate in place
|
|
423
|
+
*/
|
|
321
424
|
function addDeprecatedTopLevelOptions(options: LoaderOptions): void {
|
|
322
425
|
const coreOptions = options.core as Record<string, unknown> | undefined;
|
|
323
426
|
if (!coreOptions) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import {isResponse} from '@loaders.gl/loader-utils';
|
|
5
|
+
import {encodeArrayBufferToBase64, isResponse} from '@loaders.gl/loader-utils';
|
|
6
6
|
import {FetchError} from '../fetch/fetch-error';
|
|
7
7
|
import {getResourceContentLength, getResourceUrl, getResourceMIMEType} from './resource-utils';
|
|
8
8
|
import {shortenUrlForDisplay} from './url-utils';
|
|
@@ -97,7 +97,7 @@ async function getResponseError(response: Response): Promise<Error> {
|
|
|
97
97
|
!response.bodyUsed && contentType?.includes('application/json')
|
|
98
98
|
? await response.json()
|
|
99
99
|
: await response.text();
|
|
100
|
-
} catch (
|
|
100
|
+
} catch (_error) {
|
|
101
101
|
// eslint forbids return in a finally statement, so we just catch here
|
|
102
102
|
}
|
|
103
103
|
return new FetchError(message, info);
|
|
@@ -112,26 +112,16 @@ async function getInitialDataUrl(
|
|
|
112
112
|
}
|
|
113
113
|
if (resource instanceof Blob) {
|
|
114
114
|
const blobSlice = resource.slice(0, 5);
|
|
115
|
-
return await new Promise(
|
|
115
|
+
return await new Promise(resolve => {
|
|
116
116
|
const reader = new FileReader();
|
|
117
|
-
reader.onload =
|
|
117
|
+
reader.onload = event => resolve(event?.target?.result as string);
|
|
118
118
|
reader.readAsDataURL(blobSlice);
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
121
|
if (resource instanceof ArrayBuffer) {
|
|
122
122
|
const slice = resource.slice(0, INITIAL_DATA_LENGTH);
|
|
123
|
-
const base64 =
|
|
123
|
+
const base64 = encodeArrayBufferToBase64(slice);
|
|
124
124
|
return `data:base64,${base64}`;
|
|
125
125
|
}
|
|
126
126
|
return null;
|
|
127
127
|
}
|
|
128
|
-
|
|
129
|
-
// https://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string
|
|
130
|
-
function arrayBufferToBase64(buffer: ArrayBuffer): string {
|
|
131
|
-
let binary = '';
|
|
132
|
-
const bytes = new Uint8Array(buffer);
|
|
133
|
-
for (let i = 0; i < bytes.byteLength; i++) {
|
|
134
|
-
binary += String.fromCharCode(bytes[i]);
|
|
135
|
-
}
|
|
136
|
-
return btoa(binary);
|
|
137
|
-
}
|
package/src/null-loader.ts
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
+
import type {Loader, LoaderWithParser, LoaderOptions} from '@loaders.gl/loader-utils';
|
|
6
|
+
import {LoaderContext} from '@loaders.gl/loader-utils';
|
|
7
|
+
|
|
5
8
|
// __VERSION__ is injected by babel-plugin-version-inline
|
|
6
9
|
// @ts-ignore TS2304: Cannot find name '__VERSION__'.
|
|
7
10
|
const VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';
|
|
8
11
|
|
|
9
|
-
import type {Loader, LoaderWithParser, LoaderOptions} from '@loaders.gl/loader-utils';
|
|
10
|
-
import {LoaderContext} from '@loaders.gl/loader-utils';
|
|
11
|
-
|
|
12
12
|
export type NullLoaderOptions = LoaderOptions & {
|
|
13
13
|
null?: {};
|
|
14
14
|
};
|