@jwilleke/ngdpbase-types 5.41.0 → 5.41.1
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/lib/packages/media-date/index.d.ts +34 -0
- package/lib/src/managers/ConfigurationManager.d.ts +6 -0
- package/lib/src/managers/MediaManager.d.ts +9 -0
- package/lib/src/providers/FileSystemMediaProvider.d.ts +19 -0
- package/lib/src/utils/mediaFolderOverlap.d.ts +50 -0
- package/package.json +1 -1
- package/lib/src/providers/mediaFilenameDate.d.ts +0 -22
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filename → capture-date parser, the one implementation of it.
|
|
3
|
+
*
|
|
4
|
+
* ngdpbase uses it when a media file carries no usable EXIF/QuickTime date, and
|
|
5
|
+
* mjs-media-handling uses a built copy of it to place and stamp files. Both must read a name the same way, which is why it is one package.
|
|
6
|
+
*
|
|
7
|
+
* It is a pure function of the name: no filesystem, no network, no server.
|
|
8
|
+
*
|
|
9
|
+
* Missing parts are filled with fixed, documented values — see FAKE_MONTH below
|
|
10
|
+
* and README.md. Callers that must know what was real read `parseFilenameDate`,
|
|
11
|
+
* whose `month`/`day`/`time` are null where the name did not carry them.
|
|
12
|
+
*/
|
|
13
|
+
/** Written when the name gives a year but no month. */
|
|
14
|
+
export declare const FAKE_MONTH = 6;
|
|
15
|
+
/** Written when the name gives no day of the month. */
|
|
16
|
+
export declare const FAKE_DAY = 15;
|
|
17
|
+
/** Written when the name gives no time of day. */
|
|
18
|
+
export declare const FAKE_TIME = "11:59:00";
|
|
19
|
+
/** What a filename said, with null for each part it did not say. */
|
|
20
|
+
export interface FilenameDate {
|
|
21
|
+
year: number;
|
|
22
|
+
month: number | null;
|
|
23
|
+
day: number | null;
|
|
24
|
+
/** `HH:MM:SS`, only when the name carried a valid time. */
|
|
25
|
+
time: string | null;
|
|
26
|
+
/** Which rule matched, e.g. `filename:YYYY-MM-DD`. */
|
|
27
|
+
source: string;
|
|
28
|
+
}
|
|
29
|
+
/** What the name itself says, nothing filled in. Null when it says nothing. */
|
|
30
|
+
export declare function parseFilenameDate(filename: string): FilenameDate | null;
|
|
31
|
+
/** `YYYY-MM-DD HH:MM:SS`, with FAKE_MONTH, FAKE_DAY and FAKE_TIME where missing. */
|
|
32
|
+
export declare function fillFilenameDate(date: FilenameDate): string;
|
|
33
|
+
/** The capture date a filename gives, filled in; null when it gives none. */
|
|
34
|
+
export declare function parseDateFromFilename(filename: string): string | null;
|
|
@@ -306,6 +306,12 @@ declare class ConfigurationManager extends BaseManager {
|
|
|
306
306
|
* Empty for an addon that ships no file, is disabled, or is unknown.
|
|
307
307
|
*/
|
|
308
308
|
getAddonDeclaredDefaults(slug: string): Record<string, unknown>;
|
|
309
|
+
/**
|
|
310
|
+
* `value` with its environment references resolved as `getProperty` would
|
|
311
|
+
* resolve it under `key`, for checking a value before it is saved (#2195).
|
|
312
|
+
* Throws, as `getProperty` would, on a bare `$VAR` that is not set.
|
|
313
|
+
*/
|
|
314
|
+
resolveValueAs(key: string, value: unknown): unknown;
|
|
309
315
|
/**
|
|
310
316
|
* Resolve environment-variable references in a string config value.
|
|
311
317
|
*
|
|
@@ -37,6 +37,8 @@ declare class MediaManager extends BaseManager implements CatalogSource {
|
|
|
37
37
|
readonly currentSchemaVersion = 1;
|
|
38
38
|
/** Active media provider (null when not yet initialized) */
|
|
39
39
|
private _provider;
|
|
40
|
+
/** Why configured folders were refused for overlapping private storage (#2195). */
|
|
41
|
+
private overlapReasons;
|
|
40
42
|
/** The configured media folders, for the degraded-state reason (#1167). */
|
|
41
43
|
private mediaFolders;
|
|
42
44
|
/** Return the active media provider for use by AssetManager. */
|
|
@@ -105,6 +107,13 @@ declare class MediaManager extends BaseManager implements CatalogSource {
|
|
|
105
107
|
* what degraded means (#1155) — configured, wanted, not working.
|
|
106
108
|
*/
|
|
107
109
|
private recordFolderState;
|
|
110
|
+
/** Log and notify admins of each folder refused for overlapping private storage (#2195). */
|
|
111
|
+
private surfaceOverlaps;
|
|
112
|
+
/**
|
|
113
|
+
* Why each of `folders` may not be a media folder, empty when all may (#2195).
|
|
114
|
+
* The configuration screen asks before saving `ngdpbase.media.folders`.
|
|
115
|
+
*/
|
|
116
|
+
checkFolders(folders: string[]): string[];
|
|
108
117
|
/** One path per line, then "and N more" when the provider capped the list (#2191). */
|
|
109
118
|
private formatFileList;
|
|
110
119
|
/**
|
|
@@ -37,6 +37,12 @@ export interface FileSystemMediaProviderConfig {
|
|
|
37
37
|
readonly: boolean;
|
|
38
38
|
/** Set of file extensions (lowercase, no dot) to index */
|
|
39
39
|
extensions: Set<string>;
|
|
40
|
+
/**
|
|
41
|
+
* Private storage the scanner never walks under or keeps in the index (#2195):
|
|
42
|
+
* the roots `privateStorageRoots` lists. MediaManager already refuses a folder
|
|
43
|
+
* that overlaps them; this holds even if one gets past it.
|
|
44
|
+
*/
|
|
45
|
+
excludedRoots?: string[];
|
|
40
46
|
}
|
|
41
47
|
/** Default supported media file extensions — used when no config override is provided */
|
|
42
48
|
export declare const DEFAULT_MEDIA_EXTENSIONS: string[];
|
|
@@ -54,6 +60,8 @@ declare class FileSystemMediaProvider extends BaseMediaProvider {
|
|
|
54
60
|
private readonly config;
|
|
55
61
|
/** In-memory index: id → MediaIndexEntry */
|
|
56
62
|
private index;
|
|
63
|
+
/** `config.excludedRoots` as real paths, resolved once (#2195). */
|
|
64
|
+
private readonly excludedReal;
|
|
57
65
|
/** Single ExifTool worker process reused across all reads */
|
|
58
66
|
private readonly exiftoolInstance;
|
|
59
67
|
constructor(config: FileSystemMediaProviderConfig);
|
|
@@ -62,6 +70,17 @@ declare class FileSystemMediaProvider extends BaseMediaProvider {
|
|
|
62
70
|
* (before the first background scan).
|
|
63
71
|
*/
|
|
64
72
|
initialize(): Promise<void>;
|
|
73
|
+
/** The private storage root `p` is under, or undefined (#2195). */
|
|
74
|
+
private excludedRootOf;
|
|
75
|
+
/** Whether `p` is under private storage the scanner must not touch (#2195). */
|
|
76
|
+
private isExcluded;
|
|
77
|
+
/**
|
|
78
|
+
* Drop index entries under private storage (#2195): a site that had a media
|
|
79
|
+
* folder overlapping it before the check existed has those files indexed.
|
|
80
|
+
*/
|
|
81
|
+
private dropExcludedEntries;
|
|
82
|
+
/** Delete every cached thumbnail (`{id}-*.webp`) of `ids`: they are copies of the files. */
|
|
83
|
+
private removeThumbnails;
|
|
65
84
|
/**
|
|
66
85
|
* Release the ExifTool worker process.
|
|
67
86
|
*/
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** One place private files are kept, and what to call it in a message. */
|
|
2
|
+
export interface PrivateStorageRoot {
|
|
3
|
+
label: string;
|
|
4
|
+
path: string;
|
|
5
|
+
}
|
|
6
|
+
/** How a media folder overlaps a root: it is the root, holds it, or is inside it. */
|
|
7
|
+
export type OverlapRelation = 'equals' | 'contains' | 'is inside';
|
|
8
|
+
export interface MediaFolderOverlap {
|
|
9
|
+
folder: string;
|
|
10
|
+
/** 1-based position of the folder in `ngdpbase.media.folders`. */
|
|
11
|
+
position: number;
|
|
12
|
+
root: PrivateStorageRoot;
|
|
13
|
+
relation: OverlapRelation;
|
|
14
|
+
}
|
|
15
|
+
/** Minimal configuration surface, so tests need no live engine. */
|
|
16
|
+
export interface StorageRootConfig {
|
|
17
|
+
getProperty(key: string, defaultValue: unknown): unknown;
|
|
18
|
+
getResolvedDataPath(key: string, defaultValue: string): string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Where private files live: the vaults (shared folders' pages and files are
|
|
22
|
+
* the `shared-folders` container's vault, so they are in here), the legacy
|
|
23
|
+
* `private/` root a site may not have moved yet, the shared folders' key
|
|
24
|
+
* storage, and two places in attachment storage: the old private attachments
|
|
25
|
+
* the migration leaves behind and reads as a fallback, and the thumbnail cache,
|
|
26
|
+
* which holds thumbnails of vault images. Attachment paths are the ones
|
|
27
|
+
* BasicAttachmentProvider resolves.
|
|
28
|
+
*/
|
|
29
|
+
export declare function privateStorageRoots(config: StorageRootConfig): PrivateStorageRoot[];
|
|
30
|
+
/**
|
|
31
|
+
* The real path of `p`, or of its nearest existing ancestor with the rest
|
|
32
|
+
* appended. `p` is not normalized first: `link/..` is the parent of where
|
|
33
|
+
* `link` points, not the directory holding `link` (#2195).
|
|
34
|
+
*/
|
|
35
|
+
export declare function realPathOf(p: string): string;
|
|
36
|
+
/** Whether `child` is `parent` or under it; both already real paths. */
|
|
37
|
+
export declare function isSameOrUnder(child: string, parent: string): boolean;
|
|
38
|
+
/** How `folder` overlaps `root`, or null for no overlap. */
|
|
39
|
+
export declare function overlapRelation(folder: string, root: string): OverlapRelation | null;
|
|
40
|
+
/** The first private storage root `folder` overlaps, or null. */
|
|
41
|
+
export declare function findMediaFolderOverlap(folder: string, roots: PrivateStorageRoot[], position?: number): MediaFolderOverlap | null;
|
|
42
|
+
/** Each of `folders` that overlaps a root, with its position in the list. */
|
|
43
|
+
export declare function findMediaFolderOverlaps(folders: string[], roots: PrivateStorageRoot[]): MediaFolderOverlap[];
|
|
44
|
+
/**
|
|
45
|
+
* The message for a refused folder. It names the folder by its position and
|
|
46
|
+
* the kind of storage. It never echoes the folder: one inside a vault would
|
|
47
|
+
* name the vault's owner and id, and the message reaches admin notices and
|
|
48
|
+
* their email.
|
|
49
|
+
*/
|
|
50
|
+
export declare function describeMediaFolderOverlap(o: MediaFolderOverlap): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jwilleke/ngdpbase-types",
|
|
3
|
-
"version": "5.41.
|
|
3
|
+
"version": "5.41.1",
|
|
4
4
|
"description": "TypeScript types for ngdpbase add-ons, and a test kit of core's own values. A dev dependency, versioned with ngdpbase.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Jim Willeke",
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Conservative filename → capture-date parser (#809, slice C of #807).
|
|
3
|
-
*
|
|
4
|
-
* Last-resort fallback used by media providers when a file carries no usable
|
|
5
|
-
* EXIF/QuickTime capture date. Many devices encode the capture time in the
|
|
6
|
-
* filename (e.g. `PXL_20260113_123414708.jpg`, `2026-04-03-IMG_4654.jpg`,
|
|
7
|
-
* `Feb_20_2026_19_25_04.jpg`); without this, those files index with
|
|
8
|
-
* `dateTimeOriginal: null` and sort only by file `mtime`.
|
|
9
|
-
*
|
|
10
|
-
* Design constraints (from the issue):
|
|
11
|
-
* - **Conservative** — only a small set of high-confidence, anchored patterns
|
|
12
|
-
* are accepted. Anything ambiguous returns `null`, and the caller then
|
|
13
|
-
* falls back to `mtime` and surfaces the file to admins.
|
|
14
|
-
* - **Distinguishable provenance** — the caller records that the resulting
|
|
15
|
-
* date came from the filename (`captureDateSource: 'filename'`), so a
|
|
16
|
-
* parsed date never masquerades as authoritative EXIF metadata.
|
|
17
|
-
*
|
|
18
|
-
* Returns a `"YYYY-MM-DD HH:MM:SS"` string (the exact shape produced by the
|
|
19
|
-
* EXIF extractor, so it flows through sort/filter identically), or `null`.
|
|
20
|
-
* A date-only match yields a `00:00:00` time.
|
|
21
|
-
*/
|
|
22
|
-
export declare function parseDateFromFilename(filename: string): string | null;
|