@directus/storage-driver-supabase 2.0.2 → 2.1.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/dist/index.d.ts +12 -2
- package/dist/index.js +82 -0
- package/package.json +5 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TusDriver, ReadOptions, ChunkedUploadContext } from '@directus/storage';
|
|
2
2
|
import { Readable } from 'node:stream';
|
|
3
3
|
|
|
4
4
|
type DriverSupabaseConfig = {
|
|
@@ -8,17 +8,22 @@ type DriverSupabaseConfig = {
|
|
|
8
8
|
/** Allows a custom Supabase endpoint for self-hosting */
|
|
9
9
|
endpoint?: string;
|
|
10
10
|
root?: string;
|
|
11
|
+
tus?: {
|
|
12
|
+
chunkSize?: number;
|
|
13
|
+
};
|
|
11
14
|
};
|
|
12
|
-
declare class DriverSupabase implements
|
|
15
|
+
declare class DriverSupabase implements TusDriver {
|
|
13
16
|
private config;
|
|
14
17
|
private client;
|
|
15
18
|
private bucket;
|
|
19
|
+
private readonly preferredChunkSize;
|
|
16
20
|
constructor(config: DriverSupabaseConfig);
|
|
17
21
|
private get endpoint();
|
|
18
22
|
private getClient;
|
|
19
23
|
private getBucket;
|
|
20
24
|
private fullPath;
|
|
21
25
|
private getAuthenticatedUrl;
|
|
26
|
+
private getResumableUrl;
|
|
22
27
|
read(filepath: string, options?: ReadOptions): Promise<Readable>;
|
|
23
28
|
stat(filepath: string): Promise<{
|
|
24
29
|
size: any;
|
|
@@ -31,6 +36,11 @@ declare class DriverSupabase implements Driver {
|
|
|
31
36
|
delete(filepath: string): Promise<void>;
|
|
32
37
|
list(prefix?: string): AsyncIterable<string>;
|
|
33
38
|
listGenerator(prefix: string): AsyncIterable<string>;
|
|
39
|
+
get tusExtensions(): string[];
|
|
40
|
+
createChunkedUpload(_filepath: string, context: ChunkedUploadContext): Promise<ChunkedUploadContext>;
|
|
41
|
+
writeChunk(filepath: string, content: Readable, offset: number, context: ChunkedUploadContext): Promise<number>;
|
|
42
|
+
finishChunkedUpload(_filepath: string, _context: ChunkedUploadContext): Promise<void>;
|
|
43
|
+
deleteChunkedUpload(filepath: string, _context: ChunkedUploadContext): Promise<void>;
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
export { DriverSupabase, type DriverSupabaseConfig, DriverSupabase as default };
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
+
import { DEFAULT_CHUNK_SIZE } from "@directus/constants";
|
|
2
3
|
import { normalizePath } from "@directus/utils";
|
|
3
4
|
import { StorageClient } from "@supabase/storage-js";
|
|
4
5
|
import { join } from "node:path";
|
|
5
6
|
import { Readable } from "node:stream";
|
|
7
|
+
import * as tus from "tus-js-client";
|
|
6
8
|
import { fetch } from "undici";
|
|
7
9
|
var DriverSupabase = class {
|
|
8
10
|
config;
|
|
9
11
|
client;
|
|
10
12
|
bucket;
|
|
13
|
+
// TUS specific members
|
|
14
|
+
preferredChunkSize;
|
|
11
15
|
constructor(config) {
|
|
12
16
|
this.config = {
|
|
13
17
|
...config,
|
|
14
18
|
root: normalizePath(config.root ?? "", { removeLeading: true })
|
|
15
19
|
};
|
|
20
|
+
this.preferredChunkSize = this.config.tus?.chunkSize ?? DEFAULT_CHUNK_SIZE;
|
|
16
21
|
this.client = this.getClient();
|
|
17
22
|
this.bucket = this.getBucket();
|
|
18
23
|
}
|
|
@@ -45,6 +50,9 @@ var DriverSupabase = class {
|
|
|
45
50
|
getAuthenticatedUrl(filepath) {
|
|
46
51
|
return `${this.endpoint}/${join("object/authenticated", this.config.bucket, this.fullPath(filepath))}`;
|
|
47
52
|
}
|
|
53
|
+
getResumableUrl() {
|
|
54
|
+
return `${this.endpoint}/upload/resumable`;
|
|
55
|
+
}
|
|
48
56
|
async read(filepath, options) {
|
|
49
57
|
const { range } = options || {};
|
|
50
58
|
const requestInit = { method: "GET" };
|
|
@@ -130,11 +138,85 @@ var DriverSupabase = class {
|
|
|
130
138
|
}
|
|
131
139
|
} while (itemCount === limit);
|
|
132
140
|
}
|
|
141
|
+
get tusExtensions() {
|
|
142
|
+
return ["creation", "termination", "expiration"];
|
|
143
|
+
}
|
|
144
|
+
async createChunkedUpload(_filepath, context) {
|
|
145
|
+
return context;
|
|
146
|
+
}
|
|
147
|
+
async writeChunk(filepath, content, offset, context) {
|
|
148
|
+
let bytesUploaded = offset || 0;
|
|
149
|
+
const metadata = {
|
|
150
|
+
bucketName: this.config.bucket,
|
|
151
|
+
objectName: this.fullPath(filepath),
|
|
152
|
+
contentType: context.metadata["type"] ?? "image/png",
|
|
153
|
+
cacheControl: "3600"
|
|
154
|
+
};
|
|
155
|
+
await new Promise((resolve, reject) => {
|
|
156
|
+
const upload = new tus.Upload(content, {
|
|
157
|
+
endpoint: this.getResumableUrl(),
|
|
158
|
+
// @ts-expect-error
|
|
159
|
+
fileReader: new FileReader(),
|
|
160
|
+
headers: {
|
|
161
|
+
Authorization: `Bearer ${this.config.serviceRole}`,
|
|
162
|
+
"x-upsert": "true"
|
|
163
|
+
},
|
|
164
|
+
metadata,
|
|
165
|
+
chunkSize: this.preferredChunkSize,
|
|
166
|
+
uploadSize: context.size,
|
|
167
|
+
retryDelays: null,
|
|
168
|
+
onError(error) {
|
|
169
|
+
reject(error);
|
|
170
|
+
},
|
|
171
|
+
onChunkComplete: function(chunkSize) {
|
|
172
|
+
bytesUploaded += chunkSize;
|
|
173
|
+
resolve(null);
|
|
174
|
+
},
|
|
175
|
+
onSuccess() {
|
|
176
|
+
resolve(null);
|
|
177
|
+
},
|
|
178
|
+
onUploadUrlAvailable() {
|
|
179
|
+
if (!context.metadata["upload-url"]) {
|
|
180
|
+
context.metadata["upload-url"] = upload.url;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
if (context.metadata["upload-url"]) {
|
|
185
|
+
upload.resumeFromPreviousUpload({
|
|
186
|
+
size: context.size,
|
|
187
|
+
creationTime: context.metadata["creation_date"],
|
|
188
|
+
metadata,
|
|
189
|
+
uploadUrl: context.metadata["upload-url"]
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
upload.start();
|
|
193
|
+
});
|
|
194
|
+
return bytesUploaded;
|
|
195
|
+
}
|
|
196
|
+
async finishChunkedUpload(_filepath, _context) {
|
|
197
|
+
}
|
|
198
|
+
async deleteChunkedUpload(filepath, _context) {
|
|
199
|
+
await this.delete(filepath);
|
|
200
|
+
}
|
|
133
201
|
};
|
|
134
202
|
var src_default = DriverSupabase;
|
|
135
203
|
function dirname(path) {
|
|
136
204
|
return path.split("/").slice(0, -1).join("/");
|
|
137
205
|
}
|
|
206
|
+
var StreamSource2 = class extends tus.StreamSource {
|
|
207
|
+
_streamEnded = false;
|
|
208
|
+
// @ts-expect-error
|
|
209
|
+
async slice(start, end) {
|
|
210
|
+
if (this._streamEnded) return null;
|
|
211
|
+
this._streamEnded = true;
|
|
212
|
+
return super.slice(0, end - start);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
var FileReader = class {
|
|
216
|
+
async openFile(input, _) {
|
|
217
|
+
return new StreamSource2(input);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
138
220
|
export {
|
|
139
221
|
DriverSupabase,
|
|
140
222
|
src_default as default
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@directus/storage-driver-supabase",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Supabase file storage abstraction for `@directus/storage`",
|
|
5
5
|
"homepage": "https://directus.io",
|
|
6
6
|
"repository": {
|
|
@@ -22,9 +22,11 @@
|
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@supabase/storage-js": "2.7.1",
|
|
25
|
+
"tus-js-client": "4.2.3",
|
|
25
26
|
"undici": "6.20.0",
|
|
26
|
-
"@directus/
|
|
27
|
-
"@directus/storage": "11.0.1"
|
|
27
|
+
"@directus/constants": "12.0.1",
|
|
28
|
+
"@directus/storage": "11.0.1",
|
|
29
|
+
"@directus/utils": "12.0.4"
|
|
28
30
|
},
|
|
29
31
|
"devDependencies": {
|
|
30
32
|
"@ngneat/falso": "7.2.0",
|