@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.
package/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # @objectstack/service-storage
2
+
3
+ Storage Service for ObjectStack — implements `IStorageService` with local filesystem and S3-compatible adapters, REST routes for front-end uploads, and presigned URL support.
4
+
5
+ ## Features
6
+
7
+ - **Multiple Adapters**: Local filesystem (development) and S3-compatible storage (production)
8
+ - **Presigned Uploads**: Browser-direct upload via presigned URLs (S3 native, local HMAC-signed tokens)
9
+ - **Chunked / Multipart Upload**: Resumable large file uploads with progress tracking
10
+ - **File Metadata Store**: `system_file` object tracks fileId → key mapping and lifecycle status
11
+ - **REST Routes**: Auto-mounted `/api/v1/storage/*` endpoints consumed by `@objectstack/client`
12
+ - **Type-Safe**: Full TypeScript support with Zod-validated API contracts
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pnpm add @objectstack/service-storage
18
+ ```
19
+
20
+ For S3 adapter (optional peer dependencies):
21
+ ```bash
22
+ pnpm add @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
23
+ ```
24
+
25
+ ## Basic Usage
26
+
27
+ ```typescript
28
+ import { ObjectKernel } from '@objectstack/core';
29
+ import { StorageServicePlugin } from '@objectstack/service-storage';
30
+
31
+ const kernel = new ObjectKernel();
32
+ kernel.use(new StorageServicePlugin({
33
+ adapter: 'local',
34
+ local: { rootDir: './uploads' },
35
+ }));
36
+ await kernel.bootstrap();
37
+
38
+ // Programmatic access
39
+ const storage = kernel.getService('file-storage');
40
+ await storage.upload('files/hello.txt', Buffer.from('hello'));
41
+ ```
42
+
43
+ ## Configuration
44
+
45
+ ### Local Filesystem Adapter (Development)
46
+
47
+ ```typescript
48
+ new StorageServicePlugin({
49
+ adapter: 'local',
50
+ local: {
51
+ rootDir: './uploads',
52
+ baseUrl: 'http://localhost:3000', // for presigned URLs
53
+ signingSecret: 'dev-secret', // auto-generated if omitted
54
+ },
55
+ presignedTtl: 3600, // 1 hour
56
+ sessionTtl: 86400, // 24 hours for chunked uploads
57
+ });
58
+ ```
59
+
60
+ ### S3 Adapter (Production)
61
+
62
+ ```typescript
63
+ new StorageServicePlugin({
64
+ adapter: 's3',
65
+ s3: {
66
+ bucket: 'my-bucket',
67
+ region: 'us-east-1',
68
+ // Optional for S3-compatible services (R2, MinIO, Spaces):
69
+ // endpoint: 'https://r2.cloudflarestorage.com/account-id',
70
+ // forcePathStyle: true,
71
+ },
72
+ });
73
+ ```
74
+
75
+ ## REST API Endpoints
76
+
77
+ All routes are mounted at `/api/v1/storage` (configurable via `basePath`).
78
+
79
+ | Method | Path | Description |
80
+ |--------|------|-------------|
81
+ | POST | `/upload/presigned` | Get presigned upload URL |
82
+ | POST | `/upload/complete` | Mark upload as committed |
83
+ | POST | `/upload/chunked` | Initiate chunked upload |
84
+ | PUT | `/upload/chunked/:uploadId/chunk/:chunkIndex` | Upload a chunk |
85
+ | POST | `/upload/chunked/:uploadId/complete` | Complete chunked upload |
86
+ | GET | `/upload/chunked/:uploadId/progress` | Get upload progress |
87
+ | GET | `/files/:fileId/url` | Get download URL |
88
+ | PUT | `/_local/raw/:token` | Local raw upload (presigned) |
89
+ | GET | `/_local/raw/:token` | Local raw download (presigned) |
90
+
91
+ ## Client SDK Usage
92
+
93
+ ```typescript
94
+ import { ObjectStackClient } from '@objectstack/client';
95
+
96
+ const client = new ObjectStackClient({ baseUrl: 'http://localhost:3000' });
97
+
98
+ // Simple upload (presigned URL flow)
99
+ const result = await client.storage.upload(file, 'user');
100
+
101
+ // Chunked upload for large files
102
+ const session = await client.storage.initChunkedUpload({
103
+ filename: 'large-video.mp4',
104
+ mimeType: 'video/mp4',
105
+ totalSize: file.size,
106
+ });
107
+
108
+ // Resume interrupted upload
109
+ const completed = await client.storage.resumeUpload(
110
+ session.data.uploadId,
111
+ file,
112
+ session.data.chunkSize,
113
+ session.data.resumeToken,
114
+ );
115
+ ```
116
+
117
+ ## Architecture
118
+
119
+ ```
120
+ ┌──────────────┐ ┌─────────────────────┐ ┌──────────────────┐
121
+ │ Client SDK │────▶│ REST Routes │────▶│ IStorageService │
122
+ │ (browser) │ │ /api/v1/storage/* │ │ (adapter) │
123
+ └──────────────┘ └─────────────────────┘ └──────────────────┘
124
+ │ │
125
+ ▼ ▼
126
+ ┌─────────────────┐ ┌─────────────────┐
127
+ │ MetadataStore │ │ Filesystem / S3 │
128
+ │ (system_file) │ │ (actual bytes) │
129
+ └─────────────────┘ └─────────────────┘
130
+ ```
131
+
132
+ ## System Objects
133
+
134
+ The plugin registers two system objects via the manifest service:
135
+
136
+ - **`system_file`** — File metadata (fileId, key, name, mimeType, size, scope, status)
137
+ - **`system_upload_session`** — Chunked upload state (progress, parts, resumeToken)
138
+
139
+ ## License
140
+
141
+ Apache-2.0