@anvilkit/plugin-asset-manager 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -18
- package/dist/index.cjs +7 -0
- package/dist/index.d.cts +11 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +11 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/plugin.cjs +67 -4
- package/dist/plugin.d.cts +3 -2
- package/dist/plugin.d.cts.map +1 -1
- package/dist/plugin.d.ts +3 -2
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +67 -4
- package/dist/sources/composite-source.cjs +137 -0
- package/dist/sources/composite-source.d.cts +39 -0
- package/dist/sources/composite-source.d.cts.map +1 -0
- package/dist/sources/composite-source.d.ts +39 -0
- package/dist/sources/composite-source.d.ts.map +1 -0
- package/dist/sources/composite-source.js +99 -0
- package/dist/sources/federated-search.cjs +163 -0
- package/dist/sources/federated-search.d.cts +33 -0
- package/dist/sources/federated-search.d.cts.map +1 -0
- package/dist/sources/federated-search.d.ts +33 -0
- package/dist/sources/federated-search.d.ts.map +1 -0
- package/dist/sources/federated-search.js +113 -0
- package/dist/sources/provider.cjs +18 -0
- package/dist/sources/provider.d.cts +51 -0
- package/dist/sources/provider.d.cts.map +1 -0
- package/dist/sources/provider.d.ts +51 -0
- package/dist/sources/provider.d.ts.map +1 -0
- package/dist/sources/provider.js +1 -0
- package/dist/sources/unsplash/client.cjs +189 -0
- package/dist/sources/unsplash/client.d.cts +87 -0
- package/dist/sources/unsplash/client.d.cts.map +1 -0
- package/dist/sources/unsplash/client.d.ts +87 -0
- package/dist/sources/unsplash/client.d.ts.map +1 -0
- package/dist/sources/unsplash/client.js +151 -0
- package/dist/sources/unsplash/index.cjs +192 -0
- package/dist/sources/unsplash/index.d.cts +16 -0
- package/dist/sources/unsplash/index.d.cts.map +1 -0
- package/dist/sources/unsplash/index.d.ts +16 -0
- package/dist/sources/unsplash/index.d.ts.map +1 -0
- package/dist/sources/unsplash/index.js +148 -0
- package/dist/sources/unsplash/themes.cjs +141 -0
- package/dist/sources/unsplash/themes.d.cts +18 -0
- package/dist/sources/unsplash/themes.d.cts.map +1 -0
- package/dist/sources/unsplash/themes.d.ts +18 -0
- package/dist/sources/unsplash/themes.d.ts.map +1 -0
- package/dist/sources/unsplash/themes.js +93 -0
- package/dist/sources/unsplash/throttle-cache.cjs +86 -0
- package/dist/sources/unsplash/throttle-cache.d.cts +25 -0
- package/dist/sources/unsplash/throttle-cache.d.cts.map +1 -0
- package/dist/sources/unsplash/throttle-cache.d.ts +25 -0
- package/dist/sources/unsplash/throttle-cache.d.ts.map +1 -0
- package/dist/sources/unsplash/throttle-cache.js +45 -0
- package/dist/types/categories.cjs +18 -0
- package/dist/types/categories.d.cts +48 -0
- package/dist/types/categories.d.cts.map +1 -0
- package/dist/types/categories.d.ts +48 -0
- package/dist/types/categories.d.ts.map +1 -0
- package/dist/types/categories.js +1 -0
- package/dist/types/data-source.cjs +18 -0
- package/dist/types/data-source.d.cts +59 -0
- package/dist/types/data-source.d.cts.map +1 -0
- package/dist/types/data-source.d.ts +59 -0
- package/dist/types/data-source.d.ts.map +1 -0
- package/dist/types/data-source.js +1 -0
- package/dist/types/filter.cjs +18 -0
- package/dist/types/filter.d.cts +55 -0
- package/dist/types/filter.d.cts.map +1 -0
- package/dist/types/filter.d.ts +55 -0
- package/dist/types/filter.d.ts.map +1 -0
- package/dist/types/filter.js +1 -0
- package/dist/types/folders.cjs +42 -0
- package/dist/types/folders.d.cts +46 -0
- package/dist/types/folders.d.cts.map +1 -0
- package/dist/types/folders.d.ts +46 -0
- package/dist/types/folders.d.ts.map +1 -0
- package/dist/types/folders.js +4 -0
- package/dist/types/options.cjs +18 -0
- package/dist/types/options.d.cts +68 -0
- package/dist/types/options.d.cts.map +1 -0
- package/dist/types/options.d.ts +68 -0
- package/dist/types/options.d.ts.map +1 -0
- package/dist/types/options.js +1 -0
- package/dist/types/types.d.cts +15 -27
- package/dist/types/types.d.cts.map +1 -1
- package/dist/types/types.d.ts +15 -27
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/unsplash.cjs +18 -0
- package/dist/types/unsplash.d.cts +60 -0
- package/dist/types/unsplash.d.cts.map +1 -0
- package/dist/types/unsplash.d.ts +60 -0
- package/dist/types/unsplash.d.ts.map +1 -0
- package/dist/types/unsplash.js +1 -0
- package/dist/ui/AssetBrowser.cjs +33 -12
- package/dist/ui/AssetBrowser.d.cts +12 -1
- package/dist/ui/AssetBrowser.d.cts.map +1 -1
- package/dist/ui/AssetBrowser.d.ts +12 -1
- package/dist/ui/AssetBrowser.d.ts.map +1 -1
- package/dist/ui/AssetBrowser.js +33 -12
- package/dist/ui/AssetManagerUI.cjs +8 -2
- package/dist/ui/AssetManagerUI.d.cts +19 -3
- package/dist/ui/AssetManagerUI.d.cts.map +1 -1
- package/dist/ui/AssetManagerUI.d.ts +19 -3
- package/dist/ui/AssetManagerUI.d.ts.map +1 -1
- package/dist/ui/AssetManagerUI.js +8 -2
- package/dist/ui/DeleteFolderDialog.cjs +78 -0
- package/dist/ui/DeleteFolderDialog.d.cts +11 -0
- package/dist/ui/DeleteFolderDialog.d.cts.map +1 -0
- package/dist/ui/DeleteFolderDialog.d.ts +11 -0
- package/dist/ui/DeleteFolderDialog.d.ts.map +1 -0
- package/dist/ui/DeleteFolderDialog.js +40 -0
- package/dist/ui/EmptyFolderState.cjs +53 -0
- package/dist/ui/EmptyFolderState.d.cts +6 -0
- package/dist/ui/EmptyFolderState.d.cts.map +1 -0
- package/dist/ui/EmptyFolderState.d.ts +6 -0
- package/dist/ui/EmptyFolderState.d.ts.map +1 -0
- package/dist/ui/EmptyFolderState.js +15 -0
- package/dist/ui/FolderBreadcrumb.cjs +73 -0
- package/dist/ui/FolderBreadcrumb.d.cts +9 -0
- package/dist/ui/FolderBreadcrumb.d.cts.map +1 -0
- package/dist/ui/FolderBreadcrumb.d.ts +9 -0
- package/dist/ui/FolderBreadcrumb.d.ts.map +1 -0
- package/dist/ui/FolderBreadcrumb.js +35 -0
- package/dist/ui/FolderNameDialog.cjs +98 -0
- package/dist/ui/FolderNameDialog.d.cts +14 -0
- package/dist/ui/FolderNameDialog.d.cts.map +1 -0
- package/dist/ui/FolderNameDialog.d.ts +14 -0
- package/dist/ui/FolderNameDialog.d.ts.map +1 -0
- package/dist/ui/FolderNameDialog.js +60 -0
- package/dist/ui/FolderTree.cjs +83 -0
- package/dist/ui/FolderTree.d.cts +13 -0
- package/dist/ui/FolderTree.d.cts.map +1 -0
- package/dist/ui/FolderTree.d.ts +13 -0
- package/dist/ui/FolderTree.d.ts.map +1 -0
- package/dist/ui/FolderTree.js +42 -0
- package/dist/ui/MetadataPanel.cjs +7 -4
- package/dist/ui/MetadataPanel.d.cts.map +1 -1
- package/dist/ui/MetadataPanel.d.ts.map +1 -1
- package/dist/ui/MetadataPanel.js +7 -4
- package/dist/ui/MoveTargetPicker.cjs +84 -0
- package/dist/ui/MoveTargetPicker.d.cts +16 -0
- package/dist/ui/MoveTargetPicker.d.cts.map +1 -0
- package/dist/ui/MoveTargetPicker.d.ts +16 -0
- package/dist/ui/MoveTargetPicker.d.ts.map +1 -0
- package/dist/ui/MoveTargetPicker.js +46 -0
- package/dist/ui/ReplaceAssetDialog.d.cts +2 -1
- package/dist/ui/ReplaceAssetDialog.d.cts.map +1 -1
- package/dist/ui/ReplaceAssetDialog.d.ts +2 -1
- package/dist/ui/ReplaceAssetDialog.d.ts.map +1 -1
- package/dist/ui/UnsplashPanel.cjs +134 -0
- package/dist/ui/UnsplashPanel.d.cts +28 -0
- package/dist/ui/UnsplashPanel.d.cts.map +1 -0
- package/dist/ui/UnsplashPanel.d.ts +28 -0
- package/dist/ui/UnsplashPanel.d.ts.map +1 -0
- package/dist/ui/UnsplashPanel.js +96 -0
- package/dist/ui/UploadButton.cjs +1 -5
- package/dist/ui/UploadButton.d.cts +9 -2
- package/dist/ui/UploadButton.d.cts.map +1 -1
- package/dist/ui/UploadButton.d.ts +9 -2
- package/dist/ui/UploadButton.d.ts.map +1 -1
- package/dist/ui/UploadButton.js +1 -5
- package/dist/ui/index.cjs +37 -0
- package/dist/ui/index.d.cts +14 -0
- package/dist/ui/index.d.cts.map +1 -1
- package/dist/ui/index.d.ts +14 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +7 -0
- package/dist/utils/data-source.cjs +177 -0
- package/dist/utils/data-source.d.cts +63 -0
- package/dist/utils/data-source.d.cts.map +1 -0
- package/dist/utils/data-source.d.ts +63 -0
- package/dist/utils/data-source.d.ts.map +1 -0
- package/dist/utils/data-source.js +136 -0
- package/dist/utils/errors.cjs +18 -0
- package/dist/utils/errors.d.cts +27 -0
- package/dist/utils/errors.d.cts.map +1 -1
- package/dist/utils/errors.d.ts +27 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +16 -1
- package/dist/utils/folders.cjs +261 -0
- package/dist/utils/folders.d.cts +49 -0
- package/dist/utils/folders.d.cts.map +1 -0
- package/dist/utils/folders.d.ts +49 -0
- package/dist/utils/folders.d.ts.map +1 -0
- package/dist/utils/folders.js +223 -0
- package/dist/utils/registry.cjs +27 -12
- package/dist/utils/registry.d.cts +21 -1
- package/dist/utils/registry.d.cts.map +1 -1
- package/dist/utils/registry.d.ts +21 -1
- package/dist/utils/registry.d.ts.map +1 -1
- package/dist/utils/registry.js +20 -11
- package/dist/utils/studio-asset-source.cjs +5 -2
- package/dist/utils/studio-asset-source.d.cts +6 -1
- package/dist/utils/studio-asset-source.d.cts.map +1 -1
- package/dist/utils/studio-asset-source.d.ts +6 -1
- package/dist/utils/studio-asset-source.d.ts.map +1 -1
- package/dist/utils/studio-asset-source.js +1 -1
- package/dist/utils/validate-upload-result.d.cts +2 -1
- package/dist/utils/validate-upload-result.d.cts.map +1 -1
- package/dist/utils/validate-upload-result.d.ts +2 -1
- package/dist/utils/validate-upload-result.d.ts.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.d.cts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/meta/config.json +1 -1
- package/package.json +12 -2
package/dist/utils/errors.cjs
CHANGED
|
@@ -36,6 +36,21 @@ class AssetValidationError extends Error {
|
|
|
36
36
|
if (options && "cause" in options) this.cause = options.cause;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
class AssetSourceError extends Error {
|
|
40
|
+
code;
|
|
41
|
+
retryable;
|
|
42
|
+
status;
|
|
43
|
+
retryAfterMs;
|
|
44
|
+
constructor(code, message, options){
|
|
45
|
+
super(message);
|
|
46
|
+
this.name = "AssetSourceError";
|
|
47
|
+
this.code = code;
|
|
48
|
+
this.retryable = options?.retryable ?? false;
|
|
49
|
+
this.status = options?.status;
|
|
50
|
+
this.retryAfterMs = options?.retryAfterMs;
|
|
51
|
+
if (options && "cause" in options) this.cause = options.cause;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
39
54
|
class AssetResolutionError extends Error {
|
|
40
55
|
assetId;
|
|
41
56
|
code;
|
|
@@ -49,12 +64,15 @@ class AssetResolutionError extends Error {
|
|
|
49
64
|
}
|
|
50
65
|
__webpack_require__.d(__webpack_exports__, {
|
|
51
66
|
AssetResolutionError: ()=>AssetResolutionError,
|
|
67
|
+
AssetSourceError: ()=>AssetSourceError,
|
|
52
68
|
AssetValidationError: ()=>AssetValidationError
|
|
53
69
|
});
|
|
54
70
|
exports.AssetResolutionError = __webpack_exports__.AssetResolutionError;
|
|
71
|
+
exports.AssetSourceError = __webpack_exports__.AssetSourceError;
|
|
55
72
|
exports.AssetValidationError = __webpack_exports__.AssetValidationError;
|
|
56
73
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
57
74
|
"AssetResolutionError",
|
|
75
|
+
"AssetSourceError",
|
|
58
76
|
"AssetValidationError"
|
|
59
77
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
60
78
|
Object.defineProperty(exports, '__esModule', {
|
package/dist/utils/errors.d.cts
CHANGED
|
@@ -4,6 +4,33 @@ export declare class AssetValidationError extends Error {
|
|
|
4
4
|
readonly cause?: unknown;
|
|
5
5
|
});
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Failure codes raised by the async data-source / folder / external-provider
|
|
9
|
+
* surfaces (PRD 0002 §3.6). Distinct from {@link AssetValidationError}
|
|
10
|
+
* (upload validation) and {@link AssetResolutionError} (resolver domain) — in
|
|
11
|
+
* particular `ASSET_NOT_FOUND` belongs to the resolver, never here.
|
|
12
|
+
*/
|
|
13
|
+
export type AssetSourceErrorCode = "DATA_SOURCE_UNAVAILABLE" | "DATA_SOURCE_TIMEOUT" | "ASSET_MUTATION_REJECTED" | "FOLDER_NOT_FOUND" | "FOLDER_CYCLE" | "FOLDER_NAME_CONFLICT" | "FOLDER_NOT_EMPTY" | "MOVE_REJECTED" | "PROVIDER_RATE_LIMITED" | "PROVIDER_UNAUTHORIZED" | "PROVIDER_NETWORK" | "PROVIDER_BAD_RESPONSE" | "READ_ONLY_SOURCE" | "OPTIMISTIC_ROLLBACK";
|
|
14
|
+
/**
|
|
15
|
+
* Error for async catalog operations: host `dataSource` failures, folder
|
|
16
|
+
* mutations, and external `AssetSourceProvider` calls (e.g. Unsplash). Carries
|
|
17
|
+
* retry metadata so callers can drive backoff (`./retry`) without re-deriving
|
|
18
|
+
* it: `retryable` gates whether a retry is attempted at all, `status` mirrors
|
|
19
|
+
* an HTTP status (429, 401, …), and `retryAfterMs` is sourced from a
|
|
20
|
+
* `Retry-After` / `X-Ratelimit-Reset` header when present.
|
|
21
|
+
*/
|
|
22
|
+
export declare class AssetSourceError extends Error {
|
|
23
|
+
readonly code: AssetSourceErrorCode;
|
|
24
|
+
readonly retryable: boolean;
|
|
25
|
+
readonly status?: number;
|
|
26
|
+
readonly retryAfterMs?: number;
|
|
27
|
+
constructor(code: AssetSourceErrorCode, message: string, options?: {
|
|
28
|
+
readonly cause?: unknown;
|
|
29
|
+
readonly retryable?: boolean;
|
|
30
|
+
readonly status?: number;
|
|
31
|
+
readonly retryAfterMs?: number;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
7
34
|
export type AssetResolutionErrorCode = "ASSET_NOT_FOUND" | "ASSET_URL_REJECTED" | "ASSET_VALIDATION_FAILED";
|
|
8
35
|
export declare class AssetResolutionError extends Error {
|
|
9
36
|
readonly assetId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.cts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAGrB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAUvC;AAED,MAAM,MAAM,wBAAwB,GACjC,iBAAiB,GACjB,oBAAoB,GACpB,yBAAyB,CAAC;AAE7B,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;gBAGvC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,wBAA4C,EAClD,OAAO,SAAyC,EAChD,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAWvC"}
|
|
1
|
+
{"version":3,"file":"errors.d.cts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAGrB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAUvC;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAC7B,yBAAyB,GACzB,qBAAqB,GACrB,yBAAyB,GACzB,kBAAkB,GAClB,cAAc,GACd,sBAAsB,GACtB,kBAAkB,GAClB,eAAe,GACf,uBAAuB,GACvB,uBAAuB,GACvB,kBAAkB,GAClB,uBAAuB,GACvB,kBAAkB,GAClB,qBAAqB,CAAC;AAEzB;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;gBAG9B,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QACT,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;KAC/B;CAaF;AAED,MAAM,MAAM,wBAAwB,GACjC,iBAAiB,GACjB,oBAAoB,GACpB,yBAAyB,CAAC;AAE7B,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;gBAGvC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,wBAA4C,EAClD,OAAO,SAAyC,EAChD,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAWvC"}
|
package/dist/utils/errors.d.ts
CHANGED
|
@@ -4,6 +4,33 @@ export declare class AssetValidationError extends Error {
|
|
|
4
4
|
readonly cause?: unknown;
|
|
5
5
|
});
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Failure codes raised by the async data-source / folder / external-provider
|
|
9
|
+
* surfaces (PRD 0002 §3.6). Distinct from {@link AssetValidationError}
|
|
10
|
+
* (upload validation) and {@link AssetResolutionError} (resolver domain) — in
|
|
11
|
+
* particular `ASSET_NOT_FOUND` belongs to the resolver, never here.
|
|
12
|
+
*/
|
|
13
|
+
export type AssetSourceErrorCode = "DATA_SOURCE_UNAVAILABLE" | "DATA_SOURCE_TIMEOUT" | "ASSET_MUTATION_REJECTED" | "FOLDER_NOT_FOUND" | "FOLDER_CYCLE" | "FOLDER_NAME_CONFLICT" | "FOLDER_NOT_EMPTY" | "MOVE_REJECTED" | "PROVIDER_RATE_LIMITED" | "PROVIDER_UNAUTHORIZED" | "PROVIDER_NETWORK" | "PROVIDER_BAD_RESPONSE" | "READ_ONLY_SOURCE" | "OPTIMISTIC_ROLLBACK";
|
|
14
|
+
/**
|
|
15
|
+
* Error for async catalog operations: host `dataSource` failures, folder
|
|
16
|
+
* mutations, and external `AssetSourceProvider` calls (e.g. Unsplash). Carries
|
|
17
|
+
* retry metadata so callers can drive backoff (`./retry`) without re-deriving
|
|
18
|
+
* it: `retryable` gates whether a retry is attempted at all, `status` mirrors
|
|
19
|
+
* an HTTP status (429, 401, …), and `retryAfterMs` is sourced from a
|
|
20
|
+
* `Retry-After` / `X-Ratelimit-Reset` header when present.
|
|
21
|
+
*/
|
|
22
|
+
export declare class AssetSourceError extends Error {
|
|
23
|
+
readonly code: AssetSourceErrorCode;
|
|
24
|
+
readonly retryable: boolean;
|
|
25
|
+
readonly status?: number;
|
|
26
|
+
readonly retryAfterMs?: number;
|
|
27
|
+
constructor(code: AssetSourceErrorCode, message: string, options?: {
|
|
28
|
+
readonly cause?: unknown;
|
|
29
|
+
readonly retryable?: boolean;
|
|
30
|
+
readonly status?: number;
|
|
31
|
+
readonly retryAfterMs?: number;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
7
34
|
export type AssetResolutionErrorCode = "ASSET_NOT_FOUND" | "ASSET_URL_REJECTED" | "ASSET_VALIDATION_FAILED";
|
|
8
35
|
export declare class AssetResolutionError extends Error {
|
|
9
36
|
readonly assetId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAGrB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAUvC;AAED,MAAM,MAAM,wBAAwB,GACjC,iBAAiB,GACjB,oBAAoB,GACpB,yBAAyB,CAAC;AAE7B,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;gBAGvC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,wBAA4C,EAClD,OAAO,SAAyC,EAChD,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAWvC"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAGrB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAUvC;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAC7B,yBAAyB,GACzB,qBAAqB,GACrB,yBAAyB,GACzB,kBAAkB,GAClB,cAAc,GACd,sBAAsB,GACtB,kBAAkB,GAClB,eAAe,GACf,uBAAuB,GACvB,uBAAuB,GACvB,kBAAkB,GAClB,uBAAuB,GACvB,kBAAkB,GAClB,qBAAqB,CAAC;AAEzB;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;gBAG9B,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QACT,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;KAC/B;CAaF;AAED,MAAM,MAAM,wBAAwB,GACjC,iBAAiB,GACjB,oBAAoB,GACpB,yBAAyB,CAAC;AAE7B,qBAAa,oBAAqB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;gBAGvC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,wBAA4C,EAClD,OAAO,SAAyC,EAChD,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAWvC"}
|
package/dist/utils/errors.js
CHANGED
|
@@ -7,6 +7,21 @@ class AssetValidationError extends Error {
|
|
|
7
7
|
if (options && "cause" in options) this.cause = options.cause;
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
+
class AssetSourceError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
retryable;
|
|
13
|
+
status;
|
|
14
|
+
retryAfterMs;
|
|
15
|
+
constructor(code, message, options){
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "AssetSourceError";
|
|
18
|
+
this.code = code;
|
|
19
|
+
this.retryable = options?.retryable ?? false;
|
|
20
|
+
this.status = options?.status;
|
|
21
|
+
this.retryAfterMs = options?.retryAfterMs;
|
|
22
|
+
if (options && "cause" in options) this.cause = options.cause;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
10
25
|
class AssetResolutionError extends Error {
|
|
11
26
|
assetId;
|
|
12
27
|
code;
|
|
@@ -18,4 +33,4 @@ class AssetResolutionError extends Error {
|
|
|
18
33
|
if (options && "cause" in options) this.cause = options.cause;
|
|
19
34
|
}
|
|
20
35
|
}
|
|
21
|
-
export { AssetResolutionError, AssetValidationError };
|
|
36
|
+
export { AssetResolutionError, AssetSourceError, AssetValidationError };
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
5
|
+
var define = (defs, kind)=>{
|
|
6
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
[kind]: defs[key]
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
define(getters, "get");
|
|
12
|
+
define(values, "value");
|
|
13
|
+
};
|
|
14
|
+
})();
|
|
15
|
+
(()=>{
|
|
16
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
17
|
+
})();
|
|
18
|
+
(()=>{
|
|
19
|
+
__webpack_require__.r = (exports1)=>{
|
|
20
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
21
|
+
value: 'Module'
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
24
|
+
value: true
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
})();
|
|
28
|
+
var __webpack_exports__ = {};
|
|
29
|
+
__webpack_require__.r(__webpack_exports__);
|
|
30
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
31
|
+
createFolderStore: ()=>createFolderStore
|
|
32
|
+
});
|
|
33
|
+
const folders_cjs_namespaceObject = require("../types/folders.cjs");
|
|
34
|
+
const external_errors_cjs_namespaceObject = require("./errors.cjs");
|
|
35
|
+
function createFolderStore(options = {}) {
|
|
36
|
+
const now = options.now ?? (()=>Date.now());
|
|
37
|
+
const records = new Map();
|
|
38
|
+
const assetFolder = new Map();
|
|
39
|
+
const listeners = new Set();
|
|
40
|
+
let seq = 0;
|
|
41
|
+
const notify = ()=>{
|
|
42
|
+
for (const listener of listeners)listener();
|
|
43
|
+
};
|
|
44
|
+
const requireRecord = (id)=>{
|
|
45
|
+
const rec = records.get(id);
|
|
46
|
+
if (void 0 === rec) throw new external_errors_cjs_namespaceObject.AssetSourceError("FOLDER_NOT_FOUND", `Unknown folder "${id}".`);
|
|
47
|
+
return rec;
|
|
48
|
+
};
|
|
49
|
+
const childFolderCount = (id)=>{
|
|
50
|
+
let n = 0;
|
|
51
|
+
for (const rec of records.values())if (rec.parentId === id) n += 1;
|
|
52
|
+
return n;
|
|
53
|
+
};
|
|
54
|
+
const directAssetCount = (id)=>{
|
|
55
|
+
let n = 0;
|
|
56
|
+
for (const folderId of assetFolder.values())if (folderId === id) n += 1;
|
|
57
|
+
return n;
|
|
58
|
+
};
|
|
59
|
+
const project = (rec)=>Object.freeze({
|
|
60
|
+
id: rec.id,
|
|
61
|
+
name: rec.name,
|
|
62
|
+
parentId: rec.parentId,
|
|
63
|
+
createdAt: rec.createdAt,
|
|
64
|
+
updatedAt: rec.updatedAt,
|
|
65
|
+
counts: Object.freeze({
|
|
66
|
+
assets: directAssetCount(rec.id),
|
|
67
|
+
folders: childFolderCount(rec.id)
|
|
68
|
+
})
|
|
69
|
+
});
|
|
70
|
+
const depthOf = (id)=>{
|
|
71
|
+
let depth = 0;
|
|
72
|
+
let cursor = id;
|
|
73
|
+
while(null !== cursor){
|
|
74
|
+
const rec = records.get(cursor);
|
|
75
|
+
if (void 0 === rec) break;
|
|
76
|
+
depth += 1;
|
|
77
|
+
cursor = rec.parentId;
|
|
78
|
+
}
|
|
79
|
+
return depth;
|
|
80
|
+
};
|
|
81
|
+
const subtree = (id)=>{
|
|
82
|
+
const out = new Set([
|
|
83
|
+
id
|
|
84
|
+
]);
|
|
85
|
+
let added = true;
|
|
86
|
+
while(added){
|
|
87
|
+
added = false;
|
|
88
|
+
for (const rec of records.values())if (null !== rec.parentId && out.has(rec.parentId) && !out.has(rec.id)) {
|
|
89
|
+
out.add(rec.id);
|
|
90
|
+
added = true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
};
|
|
95
|
+
const heightOf = (id)=>{
|
|
96
|
+
let height = 0;
|
|
97
|
+
const ids = subtree(id);
|
|
98
|
+
for (const fid of ids){
|
|
99
|
+
const d = depthOf(fid) - depthOf(id);
|
|
100
|
+
if (d > height) height = d;
|
|
101
|
+
}
|
|
102
|
+
return height;
|
|
103
|
+
};
|
|
104
|
+
const assertNameFree = (parentId, name, exceptId)=>{
|
|
105
|
+
const lowered = name.toLowerCase();
|
|
106
|
+
for (const rec of records.values())if (rec.parentId === parentId) {
|
|
107
|
+
if (rec.id !== exceptId) {
|
|
108
|
+
if (rec.name.toLowerCase() === lowered) throw new external_errors_cjs_namespaceObject.AssetSourceError("FOLDER_NAME_CONFLICT", `A folder named "${name}" already exists here.`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const normalizeName = (name)=>{
|
|
113
|
+
const trimmed = name.trim();
|
|
114
|
+
if ("" === trimmed) throw new external_errors_cjs_namespaceObject.AssetSourceError("FOLDER_NAME_CONFLICT", "Folder name must not be empty.");
|
|
115
|
+
return trimmed;
|
|
116
|
+
};
|
|
117
|
+
const assertDepthOk = (parentDepth, extraHeight, maxDepth)=>{
|
|
118
|
+
if (void 0 === maxDepth) return;
|
|
119
|
+
if (parentDepth + 1 + extraHeight > maxDepth) throw new external_errors_cjs_namespaceObject.AssetSourceError("MOVE_REJECTED", `Operation would exceed the maximum folder depth of ${maxDepth}.`);
|
|
120
|
+
};
|
|
121
|
+
return {
|
|
122
|
+
listChildren (parentId) {
|
|
123
|
+
const target = (0, folders_cjs_namespaceObject.resolveFolderId)(parentId);
|
|
124
|
+
const out = [];
|
|
125
|
+
for (const rec of records.values())if (rec.parentId === target) out.push(project(rec));
|
|
126
|
+
return Object.freeze(out);
|
|
127
|
+
},
|
|
128
|
+
listAll () {
|
|
129
|
+
return Object.freeze([
|
|
130
|
+
...records.values()
|
|
131
|
+
].map(project));
|
|
132
|
+
},
|
|
133
|
+
get (id) {
|
|
134
|
+
const rec = records.get(id);
|
|
135
|
+
return void 0 === rec ? void 0 : project(rec);
|
|
136
|
+
},
|
|
137
|
+
path (id) {
|
|
138
|
+
const target = (0, folders_cjs_namespaceObject.resolveFolderId)(id);
|
|
139
|
+
if (null === target) return Object.freeze([]);
|
|
140
|
+
const chain = [];
|
|
141
|
+
let cursor = target;
|
|
142
|
+
const seen = new Set();
|
|
143
|
+
while(null !== cursor){
|
|
144
|
+
if (seen.has(cursor)) break;
|
|
145
|
+
seen.add(cursor);
|
|
146
|
+
const rec = records.get(cursor);
|
|
147
|
+
if (void 0 === rec) break;
|
|
148
|
+
chain.unshift(project(rec));
|
|
149
|
+
cursor = rec.parentId;
|
|
150
|
+
}
|
|
151
|
+
return Object.freeze(chain);
|
|
152
|
+
},
|
|
153
|
+
createFolder (parentId, name, maxDepth) {
|
|
154
|
+
const target = (0, folders_cjs_namespaceObject.resolveFolderId)(parentId);
|
|
155
|
+
if (null !== target) requireRecord(target);
|
|
156
|
+
const clean = normalizeName(name);
|
|
157
|
+
assertNameFree(target, clean);
|
|
158
|
+
assertDepthOk(depthOf(target), 0, maxDepth);
|
|
159
|
+
const ts = now();
|
|
160
|
+
const rec = {
|
|
161
|
+
id: `folder-${seq += 1}`,
|
|
162
|
+
name: clean,
|
|
163
|
+
parentId: target,
|
|
164
|
+
createdAt: ts,
|
|
165
|
+
updatedAt: ts
|
|
166
|
+
};
|
|
167
|
+
records.set(rec.id, rec);
|
|
168
|
+
notify();
|
|
169
|
+
return project(rec);
|
|
170
|
+
},
|
|
171
|
+
renameFolder (id, name) {
|
|
172
|
+
const rec = requireRecord(id);
|
|
173
|
+
const clean = normalizeName(name);
|
|
174
|
+
assertNameFree(rec.parentId, clean, id);
|
|
175
|
+
rec.name = clean;
|
|
176
|
+
rec.updatedAt = now();
|
|
177
|
+
notify();
|
|
178
|
+
return project(rec);
|
|
179
|
+
},
|
|
180
|
+
moveFolder (id, parentId, maxDepth) {
|
|
181
|
+
const rec = requireRecord(id);
|
|
182
|
+
const target = (0, folders_cjs_namespaceObject.resolveFolderId)(parentId);
|
|
183
|
+
if (target === id) throw new external_errors_cjs_namespaceObject.AssetSourceError("FOLDER_CYCLE", "A folder cannot be moved into itself.");
|
|
184
|
+
if (null !== target) {
|
|
185
|
+
requireRecord(target);
|
|
186
|
+
if (subtree(id).has(target)) throw new external_errors_cjs_namespaceObject.AssetSourceError("FOLDER_CYCLE", "A folder cannot be moved into one of its own descendants.");
|
|
187
|
+
}
|
|
188
|
+
if (rec.parentId === target) return project(rec);
|
|
189
|
+
assertNameFree(target, rec.name, id);
|
|
190
|
+
assertDepthOk(depthOf(target), heightOf(id), maxDepth);
|
|
191
|
+
rec.parentId = target;
|
|
192
|
+
rec.updatedAt = now();
|
|
193
|
+
notify();
|
|
194
|
+
return project(rec);
|
|
195
|
+
},
|
|
196
|
+
removeFolder (id, opts) {
|
|
197
|
+
const rec = requireRecord(id);
|
|
198
|
+
if (opts?.cascade) {
|
|
199
|
+
const ids = subtree(id);
|
|
200
|
+
const removedAssetIds = [];
|
|
201
|
+
for (const [assetId, folderId] of assetFolder)if (ids.has(folderId)) {
|
|
202
|
+
removedAssetIds.push(assetId);
|
|
203
|
+
assetFolder.delete(assetId);
|
|
204
|
+
}
|
|
205
|
+
for (const fid of ids)records.delete(fid);
|
|
206
|
+
notify();
|
|
207
|
+
return {
|
|
208
|
+
removedAssetIds: Object.freeze(removedAssetIds)
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
const newParent = rec.parentId;
|
|
212
|
+
for (const child of records.values())if (child.parentId === id) {
|
|
213
|
+
child.parentId = newParent;
|
|
214
|
+
child.updatedAt = now();
|
|
215
|
+
}
|
|
216
|
+
for (const [assetId, folderId] of assetFolder)if (folderId === id) if (null === newParent) assetFolder.delete(assetId);
|
|
217
|
+
else assetFolder.set(assetId, newParent);
|
|
218
|
+
records.delete(id);
|
|
219
|
+
notify();
|
|
220
|
+
return {
|
|
221
|
+
removedAssetIds: Object.freeze([])
|
|
222
|
+
};
|
|
223
|
+
},
|
|
224
|
+
folderOf (assetId) {
|
|
225
|
+
return assetFolder.get(assetId) ?? null;
|
|
226
|
+
},
|
|
227
|
+
moveAsset (assetId, folderId) {
|
|
228
|
+
const target = (0, folders_cjs_namespaceObject.resolveFolderId)(folderId);
|
|
229
|
+
if (null !== target) requireRecord(target);
|
|
230
|
+
if (null === target) assetFolder.delete(assetId);
|
|
231
|
+
else assetFolder.set(assetId, target);
|
|
232
|
+
notify();
|
|
233
|
+
},
|
|
234
|
+
moveAssets (assetIds, folderId) {
|
|
235
|
+
const target = (0, folders_cjs_namespaceObject.resolveFolderId)(folderId);
|
|
236
|
+
if (null !== target) requireRecord(target);
|
|
237
|
+
for (const assetId of assetIds)if (null === target) assetFolder.delete(assetId);
|
|
238
|
+
else assetFolder.set(assetId, target);
|
|
239
|
+
notify();
|
|
240
|
+
},
|
|
241
|
+
removeAsset (assetId) {
|
|
242
|
+
if (assetFolder.delete(assetId)) notify();
|
|
243
|
+
},
|
|
244
|
+
subtreeIds (id) {
|
|
245
|
+
return subtree(id);
|
|
246
|
+
},
|
|
247
|
+
subscribe (listener) {
|
|
248
|
+
listeners.add(listener);
|
|
249
|
+
return ()=>{
|
|
250
|
+
listeners.delete(listener);
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
exports.createFolderStore = __webpack_exports__.createFolderStore;
|
|
256
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
257
|
+
"createFolderStore"
|
|
258
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
259
|
+
Object.defineProperty(exports, '__esModule', {
|
|
260
|
+
value: true
|
|
261
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file In-memory folder store (PRD 0002 §7). Lazy-importable from the factory
|
|
3
|
+
* so flat callers pay zero headless bytes for it.
|
|
4
|
+
*
|
|
5
|
+
* Owns the folder tree (records) and the asset→folder side-index. Membership is
|
|
6
|
+
* stored ONLY for non-root assets (absence ⇒ root), so `UploadResult` is never
|
|
7
|
+
* extended and the registry's freeze reconstructor can't strip a folder field.
|
|
8
|
+
* `AssetFolder.counts` is computed fresh on read (never denormalized) so it can
|
|
9
|
+
* never drift from the side-index.
|
|
10
|
+
*/
|
|
11
|
+
import type { AssetFolder, FolderId } from "../types/folders.js";
|
|
12
|
+
export interface CreateFolderStoreOptions {
|
|
13
|
+
/** Injectable clock for deterministic timestamps in tests. Defaults to `Date.now`. */
|
|
14
|
+
readonly now?: () => number;
|
|
15
|
+
}
|
|
16
|
+
export interface FolderStore {
|
|
17
|
+
/** Direct child folders of `parentId` (`null`/undefined ⇒ root's children). */
|
|
18
|
+
listChildren(parentId?: FolderId | null): readonly AssetFolder[];
|
|
19
|
+
/** All folders, flat. */
|
|
20
|
+
listAll(): readonly AssetFolder[];
|
|
21
|
+
get(id: FolderId): AssetFolder | undefined;
|
|
22
|
+
/** Root → … → `id` (inclusive). `[]` for root/undefined. */
|
|
23
|
+
path(id?: FolderId | null): readonly AssetFolder[];
|
|
24
|
+
createFolder(parentId: FolderId | null, name: string, maxDepth?: number): AssetFolder;
|
|
25
|
+
renameFolder(id: FolderId, name: string): AssetFolder;
|
|
26
|
+
moveFolder(id: FolderId, parentId: FolderId | null, maxDepth?: number): AssetFolder;
|
|
27
|
+
/**
|
|
28
|
+
* Remove a folder. Default policy reparents children (folders + assets) to
|
|
29
|
+
* the removed folder's parent; `{ cascade: true }` instead returns every
|
|
30
|
+
* descendant asset id for the caller to delete from the registry.
|
|
31
|
+
*/
|
|
32
|
+
removeFolder(id: FolderId, opts?: {
|
|
33
|
+
readonly cascade?: boolean;
|
|
34
|
+
}): {
|
|
35
|
+
readonly removedAssetIds: readonly string[];
|
|
36
|
+
};
|
|
37
|
+
/** Owning folder of an asset (`null` ⇒ root). */
|
|
38
|
+
folderOf(assetId: string): FolderId | null;
|
|
39
|
+
moveAsset(assetId: string, folderId: FolderId | null): void;
|
|
40
|
+
/** Batch move — validates the target once (all-or-nothing) before applying. */
|
|
41
|
+
moveAssets(assetIds: readonly string[], folderId: FolderId | null): void;
|
|
42
|
+
/** Drop an asset's membership (call when the asset is deleted from the registry). */
|
|
43
|
+
removeAsset(assetId: string): void;
|
|
44
|
+
/** Folder id + every descendant folder id (for recursive listing). */
|
|
45
|
+
subtreeIds(id: FolderId): ReadonlySet<FolderId>;
|
|
46
|
+
subscribe(listener: () => void): () => void;
|
|
47
|
+
}
|
|
48
|
+
export declare function createFolderStore(options?: CreateFolderStoreOptions): FolderStore;
|
|
49
|
+
//# sourceMappingURL=folders.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folders.d.cts","sourceRoot":"","sources":["../../src/utils/folders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAYjE,MAAM,WAAW,wBAAwB;IACxC,sFAAsF;IACtF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IACjE,yBAAyB;IACzB,OAAO,IAAI,SAAS,WAAW,EAAE,CAAC;IAClC,GAAG,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;IAC3C,4DAA4D;IAC5D,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IAEnD,YAAY,CACX,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACtD,UAAU,CACT,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf;;;;OAIG;IACH,YAAY,CACX,EAAE,EAAE,QAAQ,EACZ,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GACnC;QAAE,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IAEnD,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC3C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IAC5D,+EAA+E;IAC/E,UAAU,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IACzE,qFAAqF;IACrF,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC,sEAAsE;IACtE,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IAEhD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC5C;AAED,wBAAgB,iBAAiB,CAChC,OAAO,GAAE,wBAA6B,GACpC,WAAW,CAsSb"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file In-memory folder store (PRD 0002 §7). Lazy-importable from the factory
|
|
3
|
+
* so flat callers pay zero headless bytes for it.
|
|
4
|
+
*
|
|
5
|
+
* Owns the folder tree (records) and the asset→folder side-index. Membership is
|
|
6
|
+
* stored ONLY for non-root assets (absence ⇒ root), so `UploadResult` is never
|
|
7
|
+
* extended and the registry's freeze reconstructor can't strip a folder field.
|
|
8
|
+
* `AssetFolder.counts` is computed fresh on read (never denormalized) so it can
|
|
9
|
+
* never drift from the side-index.
|
|
10
|
+
*/
|
|
11
|
+
import type { AssetFolder, FolderId } from "../types/folders.js";
|
|
12
|
+
export interface CreateFolderStoreOptions {
|
|
13
|
+
/** Injectable clock for deterministic timestamps in tests. Defaults to `Date.now`. */
|
|
14
|
+
readonly now?: () => number;
|
|
15
|
+
}
|
|
16
|
+
export interface FolderStore {
|
|
17
|
+
/** Direct child folders of `parentId` (`null`/undefined ⇒ root's children). */
|
|
18
|
+
listChildren(parentId?: FolderId | null): readonly AssetFolder[];
|
|
19
|
+
/** All folders, flat. */
|
|
20
|
+
listAll(): readonly AssetFolder[];
|
|
21
|
+
get(id: FolderId): AssetFolder | undefined;
|
|
22
|
+
/** Root → … → `id` (inclusive). `[]` for root/undefined. */
|
|
23
|
+
path(id?: FolderId | null): readonly AssetFolder[];
|
|
24
|
+
createFolder(parentId: FolderId | null, name: string, maxDepth?: number): AssetFolder;
|
|
25
|
+
renameFolder(id: FolderId, name: string): AssetFolder;
|
|
26
|
+
moveFolder(id: FolderId, parentId: FolderId | null, maxDepth?: number): AssetFolder;
|
|
27
|
+
/**
|
|
28
|
+
* Remove a folder. Default policy reparents children (folders + assets) to
|
|
29
|
+
* the removed folder's parent; `{ cascade: true }` instead returns every
|
|
30
|
+
* descendant asset id for the caller to delete from the registry.
|
|
31
|
+
*/
|
|
32
|
+
removeFolder(id: FolderId, opts?: {
|
|
33
|
+
readonly cascade?: boolean;
|
|
34
|
+
}): {
|
|
35
|
+
readonly removedAssetIds: readonly string[];
|
|
36
|
+
};
|
|
37
|
+
/** Owning folder of an asset (`null` ⇒ root). */
|
|
38
|
+
folderOf(assetId: string): FolderId | null;
|
|
39
|
+
moveAsset(assetId: string, folderId: FolderId | null): void;
|
|
40
|
+
/** Batch move — validates the target once (all-or-nothing) before applying. */
|
|
41
|
+
moveAssets(assetIds: readonly string[], folderId: FolderId | null): void;
|
|
42
|
+
/** Drop an asset's membership (call when the asset is deleted from the registry). */
|
|
43
|
+
removeAsset(assetId: string): void;
|
|
44
|
+
/** Folder id + every descendant folder id (for recursive listing). */
|
|
45
|
+
subtreeIds(id: FolderId): ReadonlySet<FolderId>;
|
|
46
|
+
subscribe(listener: () => void): () => void;
|
|
47
|
+
}
|
|
48
|
+
export declare function createFolderStore(options?: CreateFolderStoreOptions): FolderStore;
|
|
49
|
+
//# sourceMappingURL=folders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folders.d.ts","sourceRoot":"","sources":["../../src/utils/folders.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAYjE,MAAM,WAAW,wBAAwB;IACxC,sFAAsF;IACtF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IACjE,yBAAyB;IACzB,OAAO,IAAI,SAAS,WAAW,EAAE,CAAC;IAClC,GAAG,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;IAC3C,4DAA4D;IAC5D,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,WAAW,EAAE,CAAC;IAEnD,YAAY,CACX,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACtD,UAAU,CACT,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,MAAM,GACf,WAAW,CAAC;IACf;;;;OAIG;IACH,YAAY,CACX,EAAE,EAAE,QAAQ,EACZ,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GACnC;QAAE,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IAEnD,iDAAiD;IACjD,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC3C,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IAC5D,+EAA+E;IAC/E,UAAU,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC;IACzE,qFAAqF;IACrF,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC,sEAAsE;IACtE,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IAEhD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC5C;AAED,wBAAgB,iBAAiB,CAChC,OAAO,GAAE,wBAA6B,GACpC,WAAW,CAsSb"}
|