@objectstack/service-storage 4.0.3 → 4.0.5

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.
@@ -1,100 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import { promises as fs } from 'node:fs';
4
- import { join, dirname } from 'node:path';
5
- import type { IStorageService, StorageUploadOptions, StorageFileInfo } from '@objectstack/spec/contracts';
6
-
7
- /**
8
- * Configuration options for LocalStorageAdapter.
9
- */
10
- export interface LocalStorageAdapterOptions {
11
- /** Root directory for file storage */
12
- rootDir: string;
13
- }
14
-
15
- /**
16
- * Local filesystem storage adapter implementing IStorageService.
17
- *
18
- * Stores files on the local disk under a configurable root directory.
19
- * Suitable for development, testing, and single-server deployments.
20
- */
21
- export class LocalStorageAdapter implements IStorageService {
22
- private readonly rootDir: string;
23
-
24
- constructor(options: LocalStorageAdapterOptions) {
25
- this.rootDir = options.rootDir;
26
- }
27
-
28
- private resolvePath(key: string): string {
29
- return join(this.rootDir, key);
30
- }
31
-
32
- async upload(key: string, data: Buffer | ReadableStream, _options?: StorageUploadOptions): Promise<void> {
33
- const filePath = this.resolvePath(key);
34
- await fs.mkdir(dirname(filePath), { recursive: true });
35
-
36
- if (data instanceof Buffer) {
37
- await fs.writeFile(filePath, data);
38
- } else {
39
- // Convert ReadableStream to Buffer
40
- const chunks: Uint8Array[] = [];
41
- const reader = (data as ReadableStream).getReader();
42
- let done = false;
43
- while (!done) {
44
- const result = await reader.read();
45
- done = result.done;
46
- if (result.value) chunks.push(result.value);
47
- }
48
- await fs.writeFile(filePath, Buffer.concat(chunks));
49
- }
50
- }
51
-
52
- async download(key: string): Promise<Buffer> {
53
- const filePath = this.resolvePath(key);
54
- return fs.readFile(filePath);
55
- }
56
-
57
- async delete(key: string): Promise<void> {
58
- const filePath = this.resolvePath(key);
59
- await fs.unlink(filePath);
60
- }
61
-
62
- async exists(key: string): Promise<boolean> {
63
- try {
64
- await fs.access(this.resolvePath(key));
65
- return true;
66
- } catch {
67
- return false;
68
- }
69
- }
70
-
71
- async getInfo(key: string): Promise<StorageFileInfo> {
72
- const filePath = this.resolvePath(key);
73
- const stat = await fs.stat(filePath);
74
- return {
75
- key,
76
- size: stat.size,
77
- lastModified: stat.mtime,
78
- };
79
- }
80
-
81
- async list(prefix: string): Promise<StorageFileInfo[]> {
82
- const dirPath = this.resolvePath(prefix);
83
- try {
84
- const entries = await fs.readdir(dirPath);
85
- const results: StorageFileInfo[] = [];
86
- for (const entry of entries) {
87
- const fullKey = prefix ? `${prefix}/${entry}` : entry;
88
- try {
89
- const info = await this.getInfo(fullKey);
90
- results.push(info);
91
- } catch {
92
- // Skip entries that can't be stat'd
93
- }
94
- }
95
- return results;
96
- } catch {
97
- return [];
98
- }
99
- }
100
- }
@@ -1,88 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import type { IStorageService, StorageUploadOptions, StorageFileInfo } from '@objectstack/spec/contracts';
4
-
5
- /**
6
- * Configuration for the S3 storage adapter.
7
- */
8
- export interface S3StorageAdapterOptions {
9
- /** S3 bucket name */
10
- bucket: string;
11
- /** AWS region (e.g. 'us-east-1') */
12
- region: string;
13
- /** Optional endpoint URL for S3-compatible services (MinIO, etc.) */
14
- endpoint?: string;
15
- /** AWS access key ID */
16
- accessKeyId?: string;
17
- /** AWS secret access key */
18
- secretAccessKey?: string;
19
- }
20
-
21
- /**
22
- * S3 storage adapter skeleton implementing IStorageService.
23
- *
24
- * This is a placeholder for future AWS S3 integration.
25
- * Concrete implementation will use the `@aws-sdk/client-s3` package.
26
- *
27
- * @example
28
- * ```ts
29
- * const storage = new S3StorageAdapter({
30
- * bucket: 'my-bucket',
31
- * region: 'us-east-1',
32
- * });
33
- * await storage.upload('path/to/file.txt', buffer);
34
- * ```
35
- */
36
- export class S3StorageAdapter implements IStorageService {
37
- private readonly bucket: string;
38
- private readonly region: string;
39
-
40
- constructor(options: S3StorageAdapterOptions) {
41
- this.bucket = options.bucket;
42
- this.region = options.region;
43
- }
44
-
45
- async upload(_key: string, _data: Buffer | ReadableStream, _options?: StorageUploadOptions): Promise<void> {
46
- throw new Error(`S3StorageAdapter not yet implemented (bucket: ${this.bucket}, region: ${this.region})`);
47
- }
48
-
49
- async download(_key: string): Promise<Buffer> {
50
- throw new Error('S3StorageAdapter not yet implemented');
51
- }
52
-
53
- async delete(_key: string): Promise<void> {
54
- throw new Error('S3StorageAdapter not yet implemented');
55
- }
56
-
57
- async exists(_key: string): Promise<boolean> {
58
- throw new Error('S3StorageAdapter not yet implemented');
59
- }
60
-
61
- async getInfo(_key: string): Promise<StorageFileInfo> {
62
- throw new Error('S3StorageAdapter not yet implemented');
63
- }
64
-
65
- async list(_prefix: string): Promise<StorageFileInfo[]> {
66
- throw new Error('S3StorageAdapter not yet implemented');
67
- }
68
-
69
- async getSignedUrl(_key: string, _expiresIn: number): Promise<string> {
70
- throw new Error('S3StorageAdapter not yet implemented');
71
- }
72
-
73
- async initiateChunkedUpload(_key: string, _options?: StorageUploadOptions): Promise<string> {
74
- throw new Error('S3StorageAdapter.initiateChunkedUpload not yet implemented');
75
- }
76
-
77
- async uploadChunk(_uploadId: string, _partNumber: number, _data: Buffer): Promise<string> {
78
- throw new Error('S3StorageAdapter.uploadChunk not yet implemented');
79
- }
80
-
81
- async completeChunkedUpload(_uploadId: string, _parts: Array<{ partNumber: number; eTag: string }>): Promise<string> {
82
- throw new Error('S3StorageAdapter.completeChunkedUpload not yet implemented');
83
- }
84
-
85
- async abortChunkedUpload(_uploadId: string): Promise<void> {
86
- throw new Error('S3StorageAdapter.abortChunkedUpload not yet implemented');
87
- }
88
- }
@@ -1,66 +0,0 @@
1
- // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2
-
3
- import type { Plugin, PluginContext } from '@objectstack/core';
4
- import { LocalStorageAdapter } from './local-storage-adapter.js';
5
- import type { LocalStorageAdapterOptions } from './local-storage-adapter.js';
6
-
7
- /**
8
- * Configuration options for the StorageServicePlugin.
9
- */
10
- export interface StorageServicePluginOptions {
11
- /** Storage adapter type (default: 'local') */
12
- adapter?: 'local' | 's3';
13
- /** Options for the local storage adapter */
14
- local?: LocalStorageAdapterOptions;
15
- /** S3 configuration (used when adapter is 's3') */
16
- s3?: { bucket: string; region: string; endpoint?: string };
17
- }
18
-
19
- /**
20
- * StorageServicePlugin — Production IStorageService implementation.
21
- *
22
- * Registers a file storage service with the kernel during the init phase.
23
- * Supports local filesystem and S3 adapters.
24
- *
25
- * @example
26
- * ```ts
27
- * import { ObjectKernel } from '@objectstack/core';
28
- * import { StorageServicePlugin } from '@objectstack/service-storage';
29
- *
30
- * const kernel = new ObjectKernel();
31
- * kernel.use(new StorageServicePlugin({
32
- * adapter: 'local',
33
- * local: { rootDir: './uploads' },
34
- * }));
35
- * await kernel.bootstrap();
36
- *
37
- * const storage = kernel.getService('file-storage');
38
- * await storage.upload('file.txt', Buffer.from('hello'));
39
- * ```
40
- */
41
- export class StorageServicePlugin implements Plugin {
42
- name = 'com.objectstack.service.storage';
43
- version = '1.0.0';
44
- type = 'standard';
45
-
46
- private readonly options: StorageServicePluginOptions;
47
-
48
- constructor(options: StorageServicePluginOptions = {}) {
49
- this.options = { adapter: 'local', ...options };
50
- }
51
-
52
- async init(ctx: PluginContext): Promise<void> {
53
- const adapter = this.options.adapter;
54
- if (adapter === 's3') {
55
- throw new Error(
56
- 'S3 storage adapter is not yet implemented. ' +
57
- 'Use adapter: "local" or provide a custom IStorageService via ctx.registerService("file-storage", impl).'
58
- );
59
- }
60
-
61
- const rootDir = this.options.local?.rootDir ?? './storage';
62
- const storage = new LocalStorageAdapter({ rootDir });
63
- ctx.registerService('file-storage', storage);
64
- ctx.logger.info(`StorageServicePlugin: registered local storage adapter (root: ${rootDir})`);
65
- }
66
- }
package/tsconfig.json DELETED
@@ -1,17 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "dist",
5
- "rootDir": "src",
6
- "types": [
7
- "node"
8
- ]
9
- },
10
- "include": [
11
- "src"
12
- ],
13
- "exclude": [
14
- "node_modules",
15
- "dist"
16
- ]
17
- }