@ocfl/ocfl-fs 0.4.0 → 1.0.0-beta.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/LICENSE +674 -0
- package/README.md +8 -7
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/store.d.ts +37 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +107 -0
- package/dist/store.js.map +1 -0
- package/package.json +36 -32
- package/src/index.ts +10 -0
- package/src/store.ts +129 -0
- package/index.js +0 -14
- package/index.mjs +0 -4
- package/lib/store.js +0 -156
- package/lib/types.d.ts +0 -5
- package/lib/utils.js +0 -62
package/README.md
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
# ocfl-fs - OCFL implementation using Filesystem storage backend for Node.js
|
|
2
|
-
|
|
1
|
+
# @ocfl/ocfl-fs - OCFL implementation using Filesystem storage backend for Node.js
|
|
2
|
+
|
|
3
|
+
TypeScript library to create and interact with Oxford Common File Layout (OCFL) storage and objects within it.
|
|
3
4
|
This package implements the OCFL client that stores storage root and its objects on a locally attached filesystem.
|
|
4
5
|
|
|
5
6
|
## Installation
|
|
@@ -10,13 +11,13 @@ This package implements the OCFL client that stores storage root and its objects
|
|
|
10
11
|
|
|
11
12
|
The storage and object methods accept an optional fs parameter, which can be any module that implements Node.js fs module API. By default, it will use the built in fs module.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
import ocfl from '@ocfl/ocfl-fs';
|
|
14
15
|
const storage = ocfl.storage({root: '/var/data/myocfl'});
|
|
15
16
|
|
|
16
|
-
For example, by passing it memfs (https://www.npmjs.com/package/memfs) the OCFL storage will be created in memory using the memfs module:
|
|
17
|
+
For example, by passing it memfs (https://www.npmjs.com/package/memfs) the OCFL storage will be created in memory using the memfs module:
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
import ocfl from '@ocfl/ocfl-fs';
|
|
20
|
+
import { fs } from 'memfs';
|
|
20
21
|
const storage = ocfl.storage({root: '/var/data/myocfl'}, {fs});
|
|
21
22
|
|
|
22
|
-
For common usage documentation please refer to the [README.md in GitHub](https://github.com/
|
|
23
|
+
For common usage documentation please refer to the [README.md in GitHub](https://github.com/Language-Research-Technology/ocfl-js)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type OcflFsStoreConfig } from './store.ts';
|
|
2
|
+
export type { OcflFsStoreConfig } from './store.ts';
|
|
3
|
+
export { OcflFsStore } from './store.ts';
|
|
4
|
+
declare const ocfl: {
|
|
5
|
+
OCFL_VERSIONS: readonly ["1.1", "1.0"];
|
|
6
|
+
StorageLayout: import("@ocfl/ocfl").StorageLayout;
|
|
7
|
+
storageLayout(config: string | import("@ocfl/ocfl").OcflExtensionConfig): import("@ocfl/ocfl").OcflStorageLayout;
|
|
8
|
+
object(config: import("@ocfl/ocfl").OcflObjectConfig, storeOptions?: OcflFsStoreConfig | undefined): import("@ocfl/ocfl").OcflObject;
|
|
9
|
+
storage(config: import("@ocfl/ocfl").OcflStorageConfig, storeOptions?: OcflFsStoreConfig | undefined): import("@ocfl/ocfl").OcflStorage;
|
|
10
|
+
createStorage(config: import("@ocfl/ocfl").OcflStorageConfig, storeOptions?: OcflFsStoreConfig | undefined): Promise<import("@ocfl/ocfl").OcflStorage>;
|
|
11
|
+
loadStorage(config: import("@ocfl/ocfl").OcflStorageConfig, storeOptions?: OcflFsStoreConfig | undefined): Promise<import("@ocfl/ocfl").OcflStorage>;
|
|
12
|
+
};
|
|
13
|
+
export declare const OCFL_VERSIONS: readonly ["1.1", "1.0"], StorageLayout: import("@ocfl/ocfl").StorageLayout, createStorage: (config: import("@ocfl/ocfl").OcflStorageConfig, storeOptions?: OcflFsStoreConfig | undefined) => Promise<import("@ocfl/ocfl").OcflStorage>, loadStorage: (config: import("@ocfl/ocfl").OcflStorageConfig, storeOptions?: OcflFsStoreConfig | undefined) => Promise<import("@ocfl/ocfl").OcflStorage>, object: (config: import("@ocfl/ocfl").OcflObjectConfig, storeOptions?: OcflFsStoreConfig | undefined) => import("@ocfl/ocfl").OcflObject, storage: (config: import("@ocfl/ocfl").OcflStorageConfig, storeOptions?: OcflFsStoreConfig | undefined) => import("@ocfl/ocfl").OcflStorage, storageLayout: (config: string | import("@ocfl/ocfl").OcflExtensionConfig) => import("@ocfl/ocfl").OcflStorageLayout;
|
|
14
|
+
export default ocfl;
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEjE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,QAAA,MAAM,IAAI;;;;;;;;CAAgD,CAAC;AAE3D,eAAO,MAAQ,aAAa,2BAAE,aAAa,sCAAE,aAAa,+IAAE,WAAW,+IAAE,MAAM,oIAAE,OAAO,sIAAE,aAAa,uGAAS,CAAC;eAClG,IAAI"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { implementOcfl } from '@ocfl/ocfl';
|
|
2
|
+
import { OcflFsStore } from './store.js';
|
|
3
|
+
export { OcflFsStore } from './store.js';
|
|
4
|
+
const ocfl = implementOcfl(OcflFsStore);
|
|
5
|
+
export const { OCFL_VERSIONS, StorageLayout, createStorage, loadStorage, object, storage, storageLayout } = ocfl;
|
|
6
|
+
export default ocfl;
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,WAAW,EAA0B,MAAM,YAAY,CAAC;AAGjE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,IAAI,GAAG,aAAa,CAAoB,WAAW,CAAC,CAAC;AAE3D,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;AACjH,eAAe,IAAI,CAAC"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { type ListedFile, type ListOptions, OcflStore, type WriteFileData } from '@ocfl/ocfl';
|
|
3
|
+
export interface OcflFsStoreConfig {
|
|
4
|
+
/** Custom fs module to use for any file operation */
|
|
5
|
+
fs?: typeof fs | undefined;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* OCFL Object backed by local filesystem
|
|
9
|
+
*/
|
|
10
|
+
declare class OcflFsStore extends OcflStore {
|
|
11
|
+
static instances: Map<object, OcflFsStore>;
|
|
12
|
+
fs: typeof fs;
|
|
13
|
+
/**
|
|
14
|
+
* Create a new backend store that uses the given fs api.
|
|
15
|
+
* A typical use case would be a locally mounted file system.
|
|
16
|
+
*/
|
|
17
|
+
constructor(config?: OcflFsStoreConfig);
|
|
18
|
+
stat(filePath: string): Promise<fs.Stats>;
|
|
19
|
+
createReadStream(filePath: string, options?: Parameters<typeof fs.createReadStream>[1]): Promise<fs.ReadStream>;
|
|
20
|
+
createWriteStream(filePath: string, options?: Parameters<typeof fs.createWriteStream>[1]): Promise<fs.WriteStream>;
|
|
21
|
+
createReadable(filePath: string, options?: Parameters<typeof fs.createReadStream>[1]): Promise<ReadableStream<any>>;
|
|
22
|
+
createWritable(filePath: string, options?: Parameters<typeof fs.createWriteStream>[1]): Promise<import("stream/web").WritableStream<any>>;
|
|
23
|
+
readFile(filePath: string, options: BufferEncoding | {
|
|
24
|
+
encoding: BufferEncoding;
|
|
25
|
+
}): Promise<string>;
|
|
26
|
+
readFile(filePath: string, options?: unknown): Promise<Uint8Array>;
|
|
27
|
+
writeFile(filePath: string, data: WriteFileData, options?: object | string): Promise<void>;
|
|
28
|
+
copyFile(source: string, target: string): Promise<void>;
|
|
29
|
+
opendir(filePath: string, options?: fs.OpenDirOptions): Promise<fs.Dir>;
|
|
30
|
+
readdir(filePath: string): Promise<string[]>;
|
|
31
|
+
list(dirPath: string, { encoding, bufferSize, recursive }?: ListOptions): Promise<AsyncGenerator<ListedFile, any, any>>;
|
|
32
|
+
mkdir(filePath: string, options?: fs.MakeDirectoryOptions): Promise<string | undefined>;
|
|
33
|
+
move(source: string, target: string): Promise<void>;
|
|
34
|
+
remove(filePath: string): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
export { OcflFsStore };
|
|
37
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAGzB,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE9F,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;CAC5B;AAED;;GAEG;AACH,cAAM,WAAY,SAAQ,SAAS;IACjC,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAa;IAEvD,EAAE,EAAE,OAAO,EAAE,CAAC;IAEd;;;OAGG;IACH,YAAY,MAAM,CAAC,EAAE,iBAAiB,EAGrC;IAEK,IAAI,CAAC,QAAQ,EAAE,MAAM,qBAE1B;IAEK,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,0BAE3F;IAEK,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,2BAG7F;IAEK,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,gCAEzF;IAEK,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,qDAG1F;IAEK,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG;QAAE,QAAQ,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACpG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAKnE,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,iBAI/E;IAEK,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,iBAG5C;IAEK,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,cAAc,mBAE1D;IAEK,OAAO,CAAC,QAAQ,EAAE,MAAM,qBAE7B;IAEK,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,QAAiB,EAAE,UAAe,EAAE,SAAiB,EAAE,GAAE,WAAgB,iDA8BtG;IAEK,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,EAAE,CAAC,oBAA0C,+BAEnF;IAEK,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,iBAWxC;IAEK,MAAM,CAAC,QAAQ,EAAE,MAAM,iBAE5B;CACF;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Readable, Writable } from 'node:stream';
|
|
4
|
+
import { OcflStore } from '@ocfl/ocfl';
|
|
5
|
+
/**
|
|
6
|
+
* OCFL Object backed by local filesystem
|
|
7
|
+
*/
|
|
8
|
+
class OcflFsStore extends OcflStore {
|
|
9
|
+
static instances = new Map();
|
|
10
|
+
fs;
|
|
11
|
+
/**
|
|
12
|
+
* Create a new backend store that uses the given fs api.
|
|
13
|
+
* A typical use case would be a locally mounted file system.
|
|
14
|
+
*/
|
|
15
|
+
constructor(config) {
|
|
16
|
+
super();
|
|
17
|
+
this.fs = config?.fs ?? fs;
|
|
18
|
+
}
|
|
19
|
+
async stat(filePath) {
|
|
20
|
+
return this.fs.promises.stat(filePath);
|
|
21
|
+
}
|
|
22
|
+
async createReadStream(filePath, options) {
|
|
23
|
+
return this.fs.createReadStream(filePath, options);
|
|
24
|
+
}
|
|
25
|
+
async createWriteStream(filePath, options) {
|
|
26
|
+
await this.fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
27
|
+
return this.fs.createWriteStream(filePath, options);
|
|
28
|
+
}
|
|
29
|
+
async createReadable(filePath, options) {
|
|
30
|
+
return Readable.toWeb(this.fs.createReadStream(filePath, options));
|
|
31
|
+
}
|
|
32
|
+
async createWritable(filePath, options) {
|
|
33
|
+
await this.fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
34
|
+
return Writable.toWeb(this.fs.createWriteStream(filePath, options));
|
|
35
|
+
}
|
|
36
|
+
async readFile(filePath, options) {
|
|
37
|
+
return this.fs.promises.readFile(filePath, options);
|
|
38
|
+
}
|
|
39
|
+
async writeFile(filePath, data, options) {
|
|
40
|
+
await this.fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
41
|
+
const content = data instanceof ReadableStream ? Readable.fromWeb(data) : data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
|
42
|
+
await this.fs.promises.writeFile(filePath, content, options);
|
|
43
|
+
}
|
|
44
|
+
async copyFile(source, target) {
|
|
45
|
+
await this.fs.promises.mkdir(path.dirname(target), { recursive: true });
|
|
46
|
+
await this.fs.promises.copyFile(source, target);
|
|
47
|
+
}
|
|
48
|
+
async opendir(filePath, options) {
|
|
49
|
+
return this.fs.promises.opendir(filePath, options);
|
|
50
|
+
}
|
|
51
|
+
async readdir(filePath) {
|
|
52
|
+
return this.fs.promises.readdir(filePath);
|
|
53
|
+
}
|
|
54
|
+
async list(dirPath, { encoding = 'utf8', bufferSize = 32, recursive = false } = {}) {
|
|
55
|
+
const { opendir, stat } = this.fs.promises;
|
|
56
|
+
const maxBuffer = bufferSize || 1;
|
|
57
|
+
async function* generator() {
|
|
58
|
+
const buffer = [];
|
|
59
|
+
const dirQueue = [opendir(dirPath, { encoding, bufferSize })];
|
|
60
|
+
for (let dirp = dirQueue.shift(); dirp; dirp = dirQueue.shift()) {
|
|
61
|
+
const dir = await dirp;
|
|
62
|
+
for await (const de of dir) {
|
|
63
|
+
const cdp = path.join(dir.path, de.name);
|
|
64
|
+
if (recursive && de.isDirectory()) {
|
|
65
|
+
dirQueue.push(opendir(cdp, { encoding, bufferSize }));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const f = stat(cdp).then((stats) => ({
|
|
69
|
+
name: de.name,
|
|
70
|
+
path: path.relative(dirPath, cdp),
|
|
71
|
+
size: stats.size,
|
|
72
|
+
lastModified: stats.mtime,
|
|
73
|
+
}));
|
|
74
|
+
buffer.push(f);
|
|
75
|
+
if (buffer.length > maxBuffer) {
|
|
76
|
+
// biome-ignore lint/style/noNonNullAssertion: an item was just pushed
|
|
77
|
+
yield buffer.shift();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
yield* buffer;
|
|
83
|
+
}
|
|
84
|
+
return generator();
|
|
85
|
+
}
|
|
86
|
+
async mkdir(filePath, options = { recursive: true }) {
|
|
87
|
+
return this.fs.promises.mkdir(filePath, options);
|
|
88
|
+
}
|
|
89
|
+
async move(source, target) {
|
|
90
|
+
try {
|
|
91
|
+
await this.fs.promises.mkdir(path.dirname(target), { recursive: true });
|
|
92
|
+
return this.fs.promises.rename(source, target);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error instanceof Error && 'code' in error && error.code === 'EXDEV') {
|
|
96
|
+
await this.fs.promises.cp(source, path.dirname(target), { recursive: true, preserveTimestamps: true });
|
|
97
|
+
return this.fs.promises.rm(target, { recursive: true, force: true });
|
|
98
|
+
}
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async remove(filePath) {
|
|
103
|
+
return this.fs.promises.rm(filePath, { recursive: true, force: true });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export { OcflFsStore };
|
|
107
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,22 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ocfl/ocfl-fs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
4
|
"description": "Oxford Common File Layout (OCFL) JS client library for filesystem storage",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"exports": {
|
|
7
|
-
".": [
|
|
8
|
-
{
|
|
9
|
-
"import": "./index.mjs",
|
|
10
|
-
"require": "./index.js",
|
|
11
|
-
"default": "./index.js"
|
|
12
|
-
},
|
|
13
|
-
"./index.js"
|
|
14
|
-
]
|
|
15
|
-
},
|
|
16
|
-
"scripts": {
|
|
17
|
-
"test": "mocha",
|
|
18
|
-
"build-docs": "typedoc --plugin typedoc-plugin-missing-exports"
|
|
19
|
-
},
|
|
20
5
|
"keywords": [
|
|
21
6
|
"ocfl",
|
|
22
7
|
"Oxford Common File Layout",
|
|
@@ -26,28 +11,47 @@
|
|
|
26
11
|
],
|
|
27
12
|
"repository": {
|
|
28
13
|
"type": "git",
|
|
29
|
-
"url": "https://github.com/Language-Research-Technology/ocfl-js
|
|
14
|
+
"url": "https://github.com/Language-Research-Technology/ocfl-js",
|
|
15
|
+
"directory": "ocfl-fs"
|
|
30
16
|
},
|
|
17
|
+
"license": "GPL-3.0-or-later",
|
|
31
18
|
"author": "Alvin Sebastian (https://orcid.org/0000-0002-9086-1722)",
|
|
32
19
|
"contributors": [
|
|
33
20
|
"Moises Sacal Bonequi (https://orcid.org/0000-0002-4438-2755)",
|
|
34
21
|
"Peter Sefton (https://orcid.org/0000-0002-3545-944X)"
|
|
35
22
|
],
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"typedoc": "^0.28.19",
|
|
43
|
-
"typedoc-plugin-missing-exports": "^4.1.2"
|
|
23
|
+
"type": "module",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"default": "./dist/index.js"
|
|
28
|
+
}
|
|
44
29
|
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"src"
|
|
33
|
+
],
|
|
45
34
|
"dependencies": {
|
|
46
|
-
"@ocfl/ocfl": "0.
|
|
35
|
+
"@ocfl/ocfl": "1.0.0-beta.1"
|
|
47
36
|
},
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
}
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@ocfl/ocfl-tests": "0.0.0",
|
|
39
|
+
"@types/node": "^22.20.5",
|
|
40
|
+
"memfs": "^4.80.0",
|
|
41
|
+
"typescript": "^7.0.2"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public",
|
|
45
|
+
"provenance": true
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=22.12.0"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"pretest": "pnpm --filter @ocfl/ocfl build",
|
|
52
|
+
"test": "node --test 'test/**/*.spec.ts'",
|
|
53
|
+
"build": "tsc",
|
|
54
|
+
"pretypecheck": "pnpm --filter @ocfl/ocfl build",
|
|
55
|
+
"typecheck": "tsc --noEmit && tsc -p test"
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { implementOcfl } from '@ocfl/ocfl';
|
|
2
|
+
import { OcflFsStore, type OcflFsStoreConfig } from './store.ts';
|
|
3
|
+
|
|
4
|
+
export type { OcflFsStoreConfig } from './store.ts';
|
|
5
|
+
export { OcflFsStore } from './store.ts';
|
|
6
|
+
|
|
7
|
+
const ocfl = implementOcfl<OcflFsStoreConfig>(OcflFsStore);
|
|
8
|
+
|
|
9
|
+
export const { OCFL_VERSIONS, StorageLayout, createStorage, loadStorage, object, storage, storageLayout } = ocfl;
|
|
10
|
+
export default ocfl;
|
package/src/store.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Readable, Writable } from 'node:stream';
|
|
4
|
+
import { type ListedFile, type ListOptions, OcflStore, type WriteFileData } from '@ocfl/ocfl';
|
|
5
|
+
|
|
6
|
+
export interface OcflFsStoreConfig {
|
|
7
|
+
/** Custom fs module to use for any file operation */
|
|
8
|
+
fs?: typeof fs | undefined;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* OCFL Object backed by local filesystem
|
|
13
|
+
*/
|
|
14
|
+
class OcflFsStore extends OcflStore {
|
|
15
|
+
static instances: Map<object, OcflFsStore> = new Map();
|
|
16
|
+
|
|
17
|
+
fs: typeof fs;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Create a new backend store that uses the given fs api.
|
|
21
|
+
* A typical use case would be a locally mounted file system.
|
|
22
|
+
*/
|
|
23
|
+
constructor(config?: OcflFsStoreConfig) {
|
|
24
|
+
super();
|
|
25
|
+
this.fs = config?.fs ?? fs;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async stat(filePath: string) {
|
|
29
|
+
return this.fs.promises.stat(filePath);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async createReadStream(filePath: string, options?: Parameters<typeof fs.createReadStream>[1]) {
|
|
33
|
+
return this.fs.createReadStream(filePath, options);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async createWriteStream(filePath: string, options?: Parameters<typeof fs.createWriteStream>[1]) {
|
|
37
|
+
await this.fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
38
|
+
return this.fs.createWriteStream(filePath, options);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async createReadable(filePath: string, options?: Parameters<typeof fs.createReadStream>[1]) {
|
|
42
|
+
return Readable.toWeb(this.fs.createReadStream(filePath, options)) as ReadableStream;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async createWritable(filePath: string, options?: Parameters<typeof fs.createWriteStream>[1]) {
|
|
46
|
+
await this.fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
47
|
+
return Writable.toWeb(this.fs.createWriteStream(filePath, options));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async readFile(filePath: string, options: BufferEncoding | { encoding: BufferEncoding }): Promise<string>;
|
|
51
|
+
async readFile(filePath: string, options?: unknown): Promise<Uint8Array>;
|
|
52
|
+
async readFile(filePath: string, options?: unknown): Promise<string | Uint8Array> {
|
|
53
|
+
return this.fs.promises.readFile(filePath, options as Parameters<typeof fs.promises.readFile>[1]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async writeFile(filePath: string, data: WriteFileData, options?: object | string) {
|
|
57
|
+
await this.fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
58
|
+
const content = data instanceof ReadableStream ? Readable.fromWeb(data) : data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
|
59
|
+
await this.fs.promises.writeFile(filePath, content, options as Parameters<typeof fs.promises.writeFile>[2]);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async copyFile(source: string, target: string) {
|
|
63
|
+
await this.fs.promises.mkdir(path.dirname(target), { recursive: true });
|
|
64
|
+
await this.fs.promises.copyFile(source, target);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async opendir(filePath: string, options?: fs.OpenDirOptions) {
|
|
68
|
+
return this.fs.promises.opendir(filePath, options);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async readdir(filePath: string) {
|
|
72
|
+
return this.fs.promises.readdir(filePath);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async list(dirPath: string, { encoding = 'utf8', bufferSize = 32, recursive = false }: ListOptions = {}) {
|
|
76
|
+
const { opendir, stat } = this.fs.promises;
|
|
77
|
+
const maxBuffer = bufferSize || 1;
|
|
78
|
+
async function* generator(): AsyncGenerator<ListedFile> {
|
|
79
|
+
const buffer: Promise<ListedFile>[] = [];
|
|
80
|
+
const dirQueue = [opendir(dirPath, { encoding, bufferSize })];
|
|
81
|
+
for (let dirp = dirQueue.shift(); dirp; dirp = dirQueue.shift()) {
|
|
82
|
+
const dir = await dirp;
|
|
83
|
+
for await (const de of dir) {
|
|
84
|
+
const cdp = path.join(dir.path, de.name);
|
|
85
|
+
if (recursive && de.isDirectory()) {
|
|
86
|
+
dirQueue.push(opendir(cdp, { encoding, bufferSize }));
|
|
87
|
+
} else {
|
|
88
|
+
const f = stat(cdp).then((stats) => ({
|
|
89
|
+
name: de.name,
|
|
90
|
+
path: path.relative(dirPath, cdp),
|
|
91
|
+
size: stats.size,
|
|
92
|
+
lastModified: stats.mtime,
|
|
93
|
+
}));
|
|
94
|
+
buffer.push(f);
|
|
95
|
+
if (buffer.length > maxBuffer) {
|
|
96
|
+
// biome-ignore lint/style/noNonNullAssertion: an item was just pushed
|
|
97
|
+
yield buffer.shift()!;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
yield* buffer;
|
|
103
|
+
}
|
|
104
|
+
return generator();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async mkdir(filePath: string, options: fs.MakeDirectoryOptions = { recursive: true }) {
|
|
108
|
+
return this.fs.promises.mkdir(filePath, options);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async move(source: string, target: string) {
|
|
112
|
+
try {
|
|
113
|
+
await this.fs.promises.mkdir(path.dirname(target), { recursive: true });
|
|
114
|
+
return this.fs.promises.rename(source, target);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
if (error instanceof Error && 'code' in error && error.code === 'EXDEV') {
|
|
117
|
+
await this.fs.promises.cp(source, path.dirname(target), { recursive: true, preserveTimestamps: true });
|
|
118
|
+
return this.fs.promises.rm(target, { recursive: true, force: true });
|
|
119
|
+
}
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async remove(filePath: string) {
|
|
125
|
+
return this.fs.promises.rm(filePath, { recursive: true, force: true });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export { OcflFsStore };
|
package/index.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
const { OcflFsStore } = require('./lib/store.js');
|
|
3
|
-
const { implementOcfl } = require('@ocfl/ocfl');
|
|
4
|
-
//const { default: ocfl } = require('./index.mjs');
|
|
5
|
-
|
|
6
|
-
/** @type {import('./lib/store.js').OcflFsStoreConfig} */
|
|
7
|
-
let defaultOptions;
|
|
8
|
-
|
|
9
|
-
const ocfl = implementOcfl(OcflFsStore, defaultOptions);
|
|
10
|
-
const { OCFL_VERSIONS, StorageLayout, createStorage, loadStorage, object, storage, storageLayout } = ocfl;
|
|
11
|
-
module.exports = {
|
|
12
|
-
OCFL_VERSIONS, StorageLayout, createStorage, loadStorage, object, storage, storageLayout
|
|
13
|
-
};
|
|
14
|
-
//module.exports.default = module.exports;
|
package/index.mjs
DELETED
package/lib/store.js
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
//@ts-check
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const fs = require('node:fs');
|
|
4
|
-
const { Readable, Writable } = require('node:stream');
|
|
5
|
-
|
|
6
|
-
const { OcflStore, OcflConstants } = require('@ocfl/ocfl');
|
|
7
|
-
const { opendir } = require('./utils.js');
|
|
8
|
-
const { INVENTORY_NAME } = OcflConstants;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @typedef {Object} OcflFsStoreConfig
|
|
12
|
-
* @property {typeof fs} [fs] - Custom fs module to use for any file operation
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* OCFL Object backed by local filesystem
|
|
17
|
-
*/
|
|
18
|
-
class OcflFsStore extends OcflStore {
|
|
19
|
-
/** @type {Map<Object, OcflFsStore>} */
|
|
20
|
-
static instances = new Map();
|
|
21
|
-
|
|
22
|
-
// static getInstance({fs = require('fs')} = {}) {
|
|
23
|
-
// let store = OcflFsStore.instances.get(fs);
|
|
24
|
-
// if (!store) {
|
|
25
|
-
// store = new OcflFsStore({fs});
|
|
26
|
-
// OcflFsStore.instances.set(fs, store);
|
|
27
|
-
// }
|
|
28
|
-
// return store;
|
|
29
|
-
// }
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Create a new backend store that uses the given fs api.
|
|
33
|
-
* A typical use case would be a locally mounted file system.
|
|
34
|
-
* @param {OcflFsStoreConfig} [config]
|
|
35
|
-
*/
|
|
36
|
-
constructor(config) {
|
|
37
|
-
super();
|
|
38
|
-
this.fs = config?.fs ?? fs;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async stat(filePath) {
|
|
42
|
-
return this.fs.promises.stat(filePath);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async createReadStream(filePath, options) {
|
|
46
|
-
//await this.fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
47
|
-
return this.fs.createReadStream(filePath, options);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async createWriteStream(filePath, options) {
|
|
51
|
-
await this.fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
52
|
-
return this.fs.createWriteStream(filePath, options);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async createReadable(filePath, options) {
|
|
56
|
-
return /** @type {ReadableStream} */ (Readable.toWeb(this.fs.createReadStream(filePath, options)));
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async createWritable(filePath, options) {
|
|
60
|
-
await this.fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
61
|
-
return Writable.toWeb(this.fs.createWriteStream(filePath, options));
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async readFile(filePath, options) {
|
|
65
|
-
return this.fs.promises.readFile(filePath, options);
|
|
66
|
-
//if (err.code !== 'ENOENT') throw validation.createError(34, invPath);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async writeFile(filePath, data, options) {
|
|
70
|
-
await this.fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
71
|
-
if (data instanceof ReadableStream) data = fs.ReadStream.fromWeb(data);
|
|
72
|
-
await this.fs.promises.writeFile(filePath, data, options);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async copyFile(source, target) {
|
|
76
|
-
await this.fs.promises.mkdir(path.dirname(target), { recursive: true });
|
|
77
|
-
await this.fs.promises.copyFile(source, target);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async opendir(filePath, options) {
|
|
81
|
-
return this.fs.promises.opendir(filePath, options);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async readdir(filePath, options) {
|
|
85
|
-
return this.fs.promises.readdir(filePath, options);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @param {string} dirPath
|
|
90
|
-
* @param {OpenDirOptions} [options]
|
|
91
|
-
* @return {Promise<AsyncIterableIterator<{name: string, path: string, size: number, lastModified: Date}>> }
|
|
92
|
-
*/
|
|
93
|
-
async list(dirPath, { encoding = 'utf8', bufferSize = 32, recursive = false } = {}) {
|
|
94
|
-
const {opendir, stat} = this.fs.promises;
|
|
95
|
-
const maxBuffer = bufferSize || 1;
|
|
96
|
-
async function* generator() {
|
|
97
|
-
/** @type Promise<{ name: string, path: string, size: number, lastModified: Date}>[] */
|
|
98
|
-
let buffer = [];
|
|
99
|
-
let dirp;
|
|
100
|
-
const dirQueue = [opendir(dirPath, { encoding, bufferSize })];
|
|
101
|
-
while (dirp = dirQueue.shift()) {
|
|
102
|
-
const dir = await dirp;
|
|
103
|
-
for await (const de of dir) {
|
|
104
|
-
const cdp = path.join(dir.path, de.name);
|
|
105
|
-
if (recursive && de.isDirectory()) {
|
|
106
|
-
dirQueue.push(opendir(cdp, { encoding, bufferSize }));
|
|
107
|
-
} else {
|
|
108
|
-
let f = stat(cdp).then(stats => ({
|
|
109
|
-
name: de.name,
|
|
110
|
-
path: path.relative(dirPath, cdp),
|
|
111
|
-
size: stats.size,
|
|
112
|
-
lastModified: stats.mtime
|
|
113
|
-
}));
|
|
114
|
-
if (buffer.length < maxBuffer) {
|
|
115
|
-
buffer.push(f);
|
|
116
|
-
} else {
|
|
117
|
-
yield buffer.shift();
|
|
118
|
-
buffer.push(f);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
let file;
|
|
124
|
-
while (file = buffer.shift()) {
|
|
125
|
-
yield file;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return generator();
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async mkdir(filePath, options = { recursive: true }) {
|
|
132
|
-
return this.fs.promises.mkdir(filePath, options);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async move(source, target) {
|
|
136
|
-
try {
|
|
137
|
-
await this.fs.promises.mkdir(path.dirname(target), { recursive: true });
|
|
138
|
-
return this.fs.promises.rename(source, target);
|
|
139
|
-
} catch (error) {
|
|
140
|
-
if (error.code === 'EXDEV') {
|
|
141
|
-
await this.fs.promises.cp(source, path.dirname(target), { recursive: true, preserveTimestamps: true });
|
|
142
|
-
return this.fs.promises.rm(target, { recursive: true, force: true });
|
|
143
|
-
} else {
|
|
144
|
-
throw error;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async remove(filePath) {
|
|
150
|
-
return this.fs.promises.rm(filePath, { recursive: true, force: true });
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
module.exports = { OcflFsStore };
|