@dereekb/rxjs 13.6.9 → 13.6.11
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/index.cjs.js +579 -1
- package/index.esm.js +571 -3
- package/package.json +2 -2
- package/src/lib/asset/asset.builder.d.ts +112 -0
- package/src/lib/asset/asset.d.ts +114 -0
- package/src/lib/asset/asset.loader.d.ts +34 -0
- package/src/lib/asset/asset.loader.delegated.d.ts +36 -0
- package/src/lib/asset/asset.loader.fetch.d.ts +33 -0
- package/src/lib/asset/asset.loader.memory.d.ts +21 -0
- package/src/lib/asset/index.d.ts +6 -0
- package/src/lib/index.d.ts +1 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { type SlashPath, type WebsiteUrlWithPrefix } from '@dereekb/util';
|
|
2
|
+
import { type AssetLocalPathRef, type AssetRemotePathRef } from './asset';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a local {@link AssetLocalPathRef}.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const DISTRICTS = localAsset('data/school-districts.json');
|
|
9
|
+
* // { sourceType: 'local', path: 'data/school-districts.json' }
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* @param path - Relative path from the environment's base asset directory.
|
|
13
|
+
*/
|
|
14
|
+
export declare function localAsset(path: SlashPath): AssetLocalPathRef;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a remote {@link AssetRemotePathRef}.
|
|
17
|
+
*
|
|
18
|
+
* Remote assets always use absolute URLs with an http:// or https:// prefix.
|
|
19
|
+
* Throws if the provided URL does not have a valid prefix.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const CDN = remoteAsset('https://cdn.example.com/geo.json');
|
|
24
|
+
* // { sourceType: 'remote', url: 'https://cdn.example.com/geo.json' }
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @param url - Absolute URL with http/https prefix to fetch the asset from.
|
|
28
|
+
* @throws Error if the URL does not have a valid http/https prefix.
|
|
29
|
+
*/
|
|
30
|
+
export declare function remoteAsset(url: WebsiteUrlWithPrefix): AssetRemotePathRef;
|
|
31
|
+
/**
|
|
32
|
+
* Fluent builder returned by {@link assetFolder} for creating multiple
|
|
33
|
+
* local asset refs from the same folder.
|
|
34
|
+
*/
|
|
35
|
+
export interface AssetFolderBuilder {
|
|
36
|
+
/**
|
|
37
|
+
* Creates a single local ref for a file in this folder.
|
|
38
|
+
*
|
|
39
|
+
* @param path - Relative path within the folder.
|
|
40
|
+
*/
|
|
41
|
+
asset(path: SlashPath): AssetLocalPathRef;
|
|
42
|
+
/**
|
|
43
|
+
* Creates local refs for multiple files in this folder.
|
|
44
|
+
*
|
|
45
|
+
* @param paths - Array of relative paths within the folder.
|
|
46
|
+
*/
|
|
47
|
+
assets(paths: readonly SlashPath[]): AssetLocalPathRef[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Creates a fluent builder for creating multiple local asset refs
|
|
51
|
+
* from the same folder.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* const DATA = assetFolder('data');
|
|
56
|
+
*
|
|
57
|
+
* const DISTRICTS = DATA.asset('school-districts.json');
|
|
58
|
+
* // { sourceType: 'local', path: 'data/school-districts.json' }
|
|
59
|
+
*
|
|
60
|
+
* const [A, B] = DATA.assets(['a.txt', 'b.txt']);
|
|
61
|
+
* // [
|
|
62
|
+
* // { sourceType: 'local', path: 'data/a.txt' },
|
|
63
|
+
* // { sourceType: 'local', path: 'data/b.txt' }
|
|
64
|
+
* // ]
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @param folder - Base folder path for the assets.
|
|
68
|
+
*/
|
|
69
|
+
export declare function assetFolder(folder: SlashPath): AssetFolderBuilder;
|
|
70
|
+
/**
|
|
71
|
+
* Fluent builder returned by {@link remoteAssetBaseUrl} for creating
|
|
72
|
+
* multiple remote asset refs from the same base URL.
|
|
73
|
+
*/
|
|
74
|
+
export interface RemoteAssetBuilder {
|
|
75
|
+
/**
|
|
76
|
+
* Creates a single remote ref for a path relative to the base URL.
|
|
77
|
+
*
|
|
78
|
+
* @param path - Relative path appended to the base URL.
|
|
79
|
+
*/
|
|
80
|
+
asset(path: SlashPath): AssetRemotePathRef;
|
|
81
|
+
/**
|
|
82
|
+
* Creates remote refs for multiple paths relative to the base URL.
|
|
83
|
+
*
|
|
84
|
+
* @param paths - Array of relative paths appended to the base URL.
|
|
85
|
+
*/
|
|
86
|
+
assets(paths: readonly SlashPath[]): AssetRemotePathRef[];
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Creates a fluent builder for creating multiple remote asset refs
|
|
90
|
+
* from the same base URL.
|
|
91
|
+
*
|
|
92
|
+
* The base URL must be a valid {@link WebsiteUrlWithPrefix}.
|
|
93
|
+
* Each child path is appended to produce a full absolute URL.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* const CDN = remoteAssetBaseUrl('https://cdn.example.com/assets');
|
|
98
|
+
*
|
|
99
|
+
* const GEO = CDN.asset('data/geo.json');
|
|
100
|
+
* // { sourceType: 'remote', url: 'https://cdn.example.com/assets/data/geo.json' }
|
|
101
|
+
*
|
|
102
|
+
* const [A, B] = CDN.assets(['a.json', 'b.json']);
|
|
103
|
+
* // [
|
|
104
|
+
* // { sourceType: 'remote', url: 'https://cdn.example.com/assets/a.json' },
|
|
105
|
+
* // { sourceType: 'remote', url: 'https://cdn.example.com/assets/b.json' }
|
|
106
|
+
* // ]
|
|
107
|
+
* ```
|
|
108
|
+
*
|
|
109
|
+
* @param baseUrl - Base URL with http/https prefix.
|
|
110
|
+
* @throws Error if the base URL does not have a valid http/https prefix.
|
|
111
|
+
*/
|
|
112
|
+
export declare function remoteAssetBaseUrl(baseUrl: WebsiteUrlWithPrefix): RemoteAssetBuilder;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { type SlashPath, type WebsiteUrl } from '@dereekb/util';
|
|
2
|
+
import { type Observable } from 'rxjs';
|
|
3
|
+
/**
|
|
4
|
+
* Discriminator for how an asset's source should be resolved.
|
|
5
|
+
*
|
|
6
|
+
* - `'local'` — bundled file resolved relative to an environment-specific base path
|
|
7
|
+
* - `'remote'` — fetched via HTTP(S) from an absolute URL
|
|
8
|
+
*/
|
|
9
|
+
export type AssetSourceType = 'local' | 'remote';
|
|
10
|
+
/**
|
|
11
|
+
* Self-describing reference to an asset. Carries all the information
|
|
12
|
+
* a loader needs to resolve and load the asset's data.
|
|
13
|
+
*
|
|
14
|
+
* Used directly as the argument to {@link AssetLoader.get}.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const DISTRICTS = localAsset('data/school-districts.json');
|
|
19
|
+
* const GEO = remoteAsset('https://cdn.example.com/geo.json');
|
|
20
|
+
*
|
|
21
|
+
* const instance = loader.get(DISTRICTS);
|
|
22
|
+
* instance.load().subscribe((buffer) => { ... });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export type AssetPathRef = AssetLocalPathRef | AssetRemotePathRef;
|
|
26
|
+
/**
|
|
27
|
+
* Reference to a local/bundled asset file.
|
|
28
|
+
* The loader resolves {@link path} relative to its configured local base path.
|
|
29
|
+
*/
|
|
30
|
+
export interface AssetLocalPathRef {
|
|
31
|
+
readonly sourceType: 'local';
|
|
32
|
+
/**
|
|
33
|
+
* Relative path from the environment's base asset directory.
|
|
34
|
+
*
|
|
35
|
+
* @example `'data/school-districts.json'`
|
|
36
|
+
*/
|
|
37
|
+
readonly path: SlashPath;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Reference to a remote asset fetched via HTTP(S).
|
|
41
|
+
*
|
|
42
|
+
* The {@link url} is always an absolute {@link WebsiteUrl}
|
|
43
|
+
* (e.g., `'https://cdn.example.com/geo.json'`).
|
|
44
|
+
*
|
|
45
|
+
* Any relative asset path should use {@link AssetLocalPathRef} instead.
|
|
46
|
+
*/
|
|
47
|
+
export interface AssetRemotePathRef {
|
|
48
|
+
readonly sourceType: 'remote';
|
|
49
|
+
/**
|
|
50
|
+
* Absolute URL to fetch the asset from.
|
|
51
|
+
*
|
|
52
|
+
* @example `'https://cdn.example.com/geo.json'`
|
|
53
|
+
*/
|
|
54
|
+
readonly url: WebsiteUrl;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Instance returned by {@link AssetLoader.get} for a specific asset.
|
|
58
|
+
*
|
|
59
|
+
* Decouples ref lookup from data loading — callers can hold an instance
|
|
60
|
+
* and load lazily via the Observable.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* const instance = loader.get(PROJECT_ASSETS.DISTRICTS);
|
|
65
|
+
* instance.ref(); // AssetLocalPathRef
|
|
66
|
+
* instance.load().subscribe((buffer) => { ... });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export interface AssetLoaderAssetInstance {
|
|
70
|
+
/**
|
|
71
|
+
* Returns the {@link AssetPathRef} this instance was created for.
|
|
72
|
+
*/
|
|
73
|
+
ref(): AssetPathRef;
|
|
74
|
+
/**
|
|
75
|
+
* Loads the raw bytes of the asset.
|
|
76
|
+
*
|
|
77
|
+
* Returns a cold Observable — the load is triggered on each subscription.
|
|
78
|
+
*/
|
|
79
|
+
load(): Observable<ArrayBuffer>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Promise-based function signature for a leaf asset loader.
|
|
83
|
+
*
|
|
84
|
+
* Used internally by environment-specific loaders (filesystem, fetch, etc.)
|
|
85
|
+
* and composed via {@link delegatedAssetLoader}.
|
|
86
|
+
*/
|
|
87
|
+
export type AssetLoaderGetFn = (ref: AssetPathRef) => Promise<ArrayBuffer>;
|
|
88
|
+
/**
|
|
89
|
+
* Abstract asset loader that serves as a DI token in both Angular and NestJS.
|
|
90
|
+
*
|
|
91
|
+
* Accepts an {@link AssetPathRef} and returns an {@link AssetLoaderAssetInstance}
|
|
92
|
+
* for lazy Observable-based loading.
|
|
93
|
+
*
|
|
94
|
+
* Follows the same abstract-class-as-DI-token pattern as StorageObject.
|
|
95
|
+
* All concrete implementations are functional (factory functions returning
|
|
96
|
+
* objects satisfying this contract), except Angular's DbxCoreAssetLoader
|
|
97
|
+
* which requires @Injectable().
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* // Angular: inject(AssetLoader)
|
|
102
|
+
* // NestJS: @Inject(AssetLoader)
|
|
103
|
+
* const instance = loader.get(PROJECT_ASSETS.SCHOOL_DISTRICTS);
|
|
104
|
+
* instance.load().subscribe((data) => { ... });
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export declare abstract class AssetLoader {
|
|
108
|
+
/**
|
|
109
|
+
* Returns an {@link AssetLoaderAssetInstance} for the given ref.
|
|
110
|
+
*
|
|
111
|
+
* @param ref - Self-describing asset path reference (local or remote).
|
|
112
|
+
*/
|
|
113
|
+
abstract get(ref: AssetPathRef): AssetLoaderAssetInstance;
|
|
114
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type AssetPathRef, type AssetLoaderAssetInstance, type AssetLoaderGetFn, AssetLoader } from './asset';
|
|
2
|
+
/**
|
|
3
|
+
* Creates an {@link AssetLoaderAssetInstance} from a ref and a Promise-based get function.
|
|
4
|
+
*
|
|
5
|
+
* The returned {@link AssetLoaderAssetInstance.load} observable is cold — each subscription
|
|
6
|
+
* invokes the get function anew.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const instance = assetLoaderAssetInstance(ref, (r) => fetch(r.path).then(res => res.arrayBuffer()));
|
|
11
|
+
* instance.load().subscribe((data) => { ... });
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @param ref - The asset path reference this instance represents.
|
|
15
|
+
* @param getFn - Promise-based function that loads the asset bytes.
|
|
16
|
+
*/
|
|
17
|
+
export declare function assetLoaderAssetInstance(ref: AssetPathRef, getFn: AssetLoaderGetFn): AssetLoaderAssetInstance;
|
|
18
|
+
/**
|
|
19
|
+
* Creates an {@link AssetLoader} from a single {@link AssetLoaderGetFn}.
|
|
20
|
+
*
|
|
21
|
+
* This is the primary helper for building functional AssetLoader implementations
|
|
22
|
+
* from a Promise-based leaf loader.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const loader = assetLoaderFromGetFn(async (ref) => {
|
|
27
|
+
* const response = await fetch(resolveUrl(ref));
|
|
28
|
+
* return response.arrayBuffer();
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @param getFn - Promise-based function that loads any asset's bytes.
|
|
33
|
+
*/
|
|
34
|
+
export declare function assetLoaderFromGetFn(getFn: AssetLoaderGetFn): AssetLoader;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AssetLoader } from './asset';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for {@link delegatedAssetLoader}.
|
|
4
|
+
* Specifies which loader handles each source type.
|
|
5
|
+
*/
|
|
6
|
+
export interface DelegatedAssetLoaderConfig {
|
|
7
|
+
/**
|
|
8
|
+
* Loader for {@link AssetLocalPathRef} assets (e.g., filesystem reads).
|
|
9
|
+
*/
|
|
10
|
+
readonly local: AssetLoader;
|
|
11
|
+
/**
|
|
12
|
+
* Loader for {@link AssetRemotePathRef} assets (e.g., HTTP fetch).
|
|
13
|
+
*/
|
|
14
|
+
readonly remote: AssetLoader;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Creates an {@link AssetLoader} that delegates to source-type-specific loaders.
|
|
18
|
+
*
|
|
19
|
+
* This is the primary composition point: wire a local loader and a remote
|
|
20
|
+
* loader together, and the delegated loader routes each {@link AssetPathRef}
|
|
21
|
+
* to the correct one based on {@link AssetPathRef.sourceType}.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const loader = delegatedAssetLoader({
|
|
26
|
+
* local: nodeJsLocalAssetLoader({ basePath: './assets' }),
|
|
27
|
+
* remote: fetchAssetLoader({ baseUrl: 'https://api.example.com/assets/' })
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* loader.get(localAsset('data/districts.json')); // → local loader
|
|
31
|
+
* loader.get(remoteAsset('data/geo.json')); // → remote loader
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @param config - Specifies the local and remote delegate loaders.
|
|
35
|
+
*/
|
|
36
|
+
export declare function delegatedAssetLoader(config: DelegatedAssetLoaderConfig): AssetLoader;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { AssetLoader } from './asset';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for {@link fetchAssetLoader}.
|
|
4
|
+
*/
|
|
5
|
+
export interface FetchAssetLoaderConfig {
|
|
6
|
+
/**
|
|
7
|
+
* Optional pre-configured fetch function.
|
|
8
|
+
* Defaults to the global `fetch` if not provided.
|
|
9
|
+
*
|
|
10
|
+
* Useful for injecting auth headers, timeouts, or test mocks.
|
|
11
|
+
*/
|
|
12
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Creates an {@link AssetLoader} that loads remote assets via HTTP fetch.
|
|
16
|
+
* Works in both browser and Node.js (Node 18+) environments.
|
|
17
|
+
*
|
|
18
|
+
* Remote refs always have absolute URLs, so no base URL resolution is needed.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const loader = fetchAssetLoader();
|
|
23
|
+
* loader.get(remoteAsset('https://cdn.example.com/geo.json')).load().subscribe((data) => {
|
|
24
|
+
* // loaded from https://cdn.example.com/geo.json
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // With a custom fetch function:
|
|
28
|
+
* const loader = fetchAssetLoader({ fetch: myAuthenticatedFetch });
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @param config - Optional fetch configuration with custom fetch function.
|
|
32
|
+
*/
|
|
33
|
+
export declare function fetchAssetLoader(config?: FetchAssetLoaderConfig): AssetLoader;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type AssetPathRef, AssetLoader } from './asset';
|
|
2
|
+
/**
|
|
3
|
+
* Creates an {@link AssetLoader} backed by an in-memory map.
|
|
4
|
+
* Useful for testing without filesystem or network access.
|
|
5
|
+
*
|
|
6
|
+
* Assets are matched by reference identity — the same {@link AssetPathRef}
|
|
7
|
+
* object used to populate the map must be used to retrieve the data.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const DISTRICTS = localAsset('districts.json');
|
|
12
|
+
* const loader = memoryAssetLoader(new Map([
|
|
13
|
+
* [DISTRICTS, new TextEncoder().encode('[]').buffer]
|
|
14
|
+
* ]));
|
|
15
|
+
*
|
|
16
|
+
* loader.get(DISTRICTS).load().subscribe((data) => { ... });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @param assets - Map of asset refs to their raw byte data.
|
|
20
|
+
*/
|
|
21
|
+
export declare function memoryAssetLoader(assets: Map<AssetPathRef, ArrayBuffer>): AssetLoader;
|
package/src/lib/index.d.ts
CHANGED