@directus/storage-driver-supabase 1.0.3 → 1.0.4

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 CHANGED
@@ -1,14 +1,15 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- import type { Driver, Range } from '@directus/storage';
1
+ import * as undici from 'undici';
2
+ import { Driver, Range } from '@directus/storage';
3
3
  import { Readable } from 'node:stream';
4
- export type DriverSupabaseConfig = {
4
+
5
+ type DriverSupabaseConfig = {
5
6
  bucket: string;
6
7
  serviceRole: string;
7
8
  projectId?: string;
8
9
  endpoint?: string;
9
10
  root?: string;
10
11
  };
11
- export declare class DriverSupabase implements Driver {
12
+ declare class DriverSupabase implements Driver {
12
13
  private config;
13
14
  private client;
14
15
  private bucket;
@@ -19,7 +20,7 @@ export declare class DriverSupabase implements Driver {
19
20
  private getFullPath;
20
21
  private getAuthenticatedUrl;
21
22
  read(filepath: string, range?: Range): Promise<Readable>;
22
- head(filepath: string): Promise<import("undici").Headers>;
23
+ head(filepath: string): Promise<undici.Headers>;
23
24
  stat(filepath: string): Promise<{
24
25
  size: number;
25
26
  modified: Date;
@@ -31,4 +32,5 @@ export declare class DriverSupabase implements Driver {
31
32
  delete(filepath: string): Promise<void>;
32
33
  list(prefix?: string): AsyncGenerator<string, void, unknown>;
33
34
  }
34
- export default DriverSupabase;
35
+
36
+ export { DriverSupabase, DriverSupabaseConfig, DriverSupabase as default };
package/dist/index.js CHANGED
@@ -1,118 +1,122 @@
1
- import { normalizePath } from '@directus/utils';
2
- import { StorageClient } from '@supabase/storage-js';
3
- import { join } from 'node:path';
4
- import { Readable } from 'node:stream';
5
- import { fetch } from 'undici';
6
- export class DriverSupabase {
7
- config;
8
- client;
9
- bucket;
10
- constructor(config) {
11
- this.config = config;
12
- this.client = this.getClient();
13
- this.bucket = this.getBucket();
1
+ // src/index.ts
2
+ import { normalizePath } from "@directus/utils";
3
+ import { StorageClient } from "@supabase/storage-js";
4
+ import { join } from "path";
5
+ import { Readable } from "stream";
6
+ import { fetch } from "undici";
7
+ var DriverSupabase = class {
8
+ config;
9
+ client;
10
+ bucket;
11
+ constructor(config) {
12
+ this.config = config;
13
+ this.client = this.getClient();
14
+ this.bucket = this.getBucket();
15
+ }
16
+ get endpoint() {
17
+ return this.config.endpoint ?? `https://${this.config.projectId}.supabase.co/storage/v1`;
18
+ }
19
+ getClient() {
20
+ if (!this.config.projectId && !this.config.endpoint) {
21
+ throw new Error("`project_id` or `endpoint` is required");
14
22
  }
15
- get endpoint() {
16
- return this.config.endpoint ?? `https://${this.config.projectId}.supabase.co/storage/v1`;
23
+ if (!this.config.serviceRole) {
24
+ throw new Error("`service_role` is required");
17
25
  }
18
- getClient() {
19
- if (!this.config.projectId && !this.config.endpoint) {
20
- throw new Error('`project_id` or `endpoint` is required');
21
- }
22
- if (!this.config.serviceRole) {
23
- throw new Error('`service_role` is required');
24
- }
25
- return new StorageClient(this.endpoint, {
26
- apikey: this.config.serviceRole,
27
- Authorization: `Bearer ${this.config.serviceRole}`,
28
- });
26
+ return new StorageClient(this.endpoint, {
27
+ apikey: this.config.serviceRole,
28
+ Authorization: `Bearer ${this.config.serviceRole}`
29
+ });
30
+ }
31
+ getBucket() {
32
+ if (!this.config.bucket) {
33
+ throw new Error("`bucket` is required");
29
34
  }
30
- getBucket() {
31
- if (!this.config.bucket) {
32
- throw new Error('`bucket` is required');
33
- }
34
- return this.client.from(this.config.bucket);
35
+ return this.client.from(this.config.bucket);
36
+ }
37
+ getFullPath(filepath) {
38
+ return this.config.root ? normalizePath(join(this.config.root, filepath)) : filepath;
39
+ }
40
+ getAuthenticatedUrl(filepath) {
41
+ return `${this.endpoint}/${join("object/authenticated", this.config.bucket, this.getFullPath(filepath))}`;
42
+ }
43
+ async read(filepath, range) {
44
+ const requestInit = { method: "GET" };
45
+ requestInit.headers = {
46
+ Authorization: `Bearer ${this.config.serviceRole}`
47
+ };
48
+ if (range) {
49
+ requestInit.headers["Range"] = `bytes=${range.start ?? ""}-${range.end ?? ""}`;
35
50
  }
36
- getFullPath(filepath) {
37
- return this.config.root ? normalizePath(join(this.config.root, filepath)) : filepath;
51
+ const response = await fetch(this.getAuthenticatedUrl(filepath), requestInit);
52
+ if (response.status >= 400 || !response.body) {
53
+ throw new Error(`No stream returned for file "${filepath}"`);
38
54
  }
39
- getAuthenticatedUrl(filepath) {
40
- return `${this.endpoint}/${join('object/authenticated', this.config.bucket, this.getFullPath(filepath))}`;
55
+ return Readable.fromWeb(response.body);
56
+ }
57
+ async head(filepath) {
58
+ const response = await fetch(this.getAuthenticatedUrl(filepath), {
59
+ method: "HEAD",
60
+ headers: {
61
+ Authorization: `Bearer ${this.config.serviceRole}`
62
+ }
63
+ });
64
+ if (response.status >= 400) {
65
+ throw new Error("File not found");
41
66
  }
42
- async read(filepath, range) {
43
- const requestInit = { method: 'GET' };
44
- requestInit.headers = {
45
- Authorization: `Bearer ${this.config.serviceRole}`,
46
- };
47
- if (range) {
48
- requestInit.headers['Range'] = `bytes=${range.start ?? ''}-${range.end ?? ''}`;
49
- }
50
- const response = await fetch(this.getAuthenticatedUrl(filepath), requestInit);
51
- if (response.status >= 400 || !response.body) {
52
- throw new Error(`No stream returned for file "${filepath}"`);
53
- }
54
- return Readable.fromWeb(response.body);
67
+ return response.headers;
68
+ }
69
+ async stat(filepath) {
70
+ const headers = await this.head(filepath);
71
+ return {
72
+ size: parseInt(headers.get("content-length") || ""),
73
+ modified: new Date(headers.get("last-modified") || "")
74
+ };
75
+ }
76
+ async exists(filepath) {
77
+ try {
78
+ await this.stat(filepath);
79
+ return true;
80
+ } catch {
81
+ return false;
55
82
  }
56
- async head(filepath) {
57
- const response = await fetch(this.getAuthenticatedUrl(filepath), {
58
- method: 'HEAD',
59
- headers: {
60
- Authorization: `Bearer ${this.config.serviceRole}`,
61
- },
62
- });
63
- if (response.status >= 400) {
64
- throw new Error('File not found');
65
- }
66
- return response.headers;
67
- }
68
- async stat(filepath) {
69
- const headers = await this.head(filepath);
70
- return {
71
- size: parseInt(headers.get('content-length') || ''),
72
- modified: new Date(headers.get('last-modified') || ''),
73
- };
74
- }
75
- async exists(filepath) {
76
- try {
77
- await this.stat(filepath);
78
- return true;
79
- }
80
- catch {
81
- return false;
82
- }
83
- }
84
- async move(src, dest) {
85
- await this.bucket.move(this.getFullPath(src), this.getFullPath(dest));
86
- }
87
- async copy(src, dest) {
88
- await this.bucket.copy(this.getFullPath(src), this.getFullPath(dest));
89
- }
90
- async write(filepath, content, type) {
91
- await this.bucket.upload(this.getFullPath(filepath), content, {
92
- contentType: type ?? '',
93
- cacheControl: '3600',
94
- upsert: true,
95
- duplex: 'half',
96
- });
97
- }
98
- async delete(filepath) {
99
- await this.bucket.remove([this.getFullPath(filepath)]);
100
- }
101
- async *list(prefix = '') {
102
- const limit = 1000;
103
- let offset = 0;
104
- let itemCount = 0;
105
- do {
106
- const { data, error } = await this.bucket.list(this.config.root, { limit, offset, search: prefix });
107
- if (!data || error) {
108
- break;
109
- }
110
- itemCount = data.length;
111
- offset += itemCount;
112
- for (const item of data) {
113
- yield item.name;
114
- }
115
- } while (itemCount === limit);
116
- }
117
- }
118
- export default DriverSupabase;
83
+ }
84
+ async move(src, dest) {
85
+ await this.bucket.move(this.getFullPath(src), this.getFullPath(dest));
86
+ }
87
+ async copy(src, dest) {
88
+ await this.bucket.copy(this.getFullPath(src), this.getFullPath(dest));
89
+ }
90
+ async write(filepath, content, type) {
91
+ await this.bucket.upload(this.getFullPath(filepath), content, {
92
+ contentType: type ?? "",
93
+ cacheControl: "3600",
94
+ upsert: true,
95
+ duplex: "half"
96
+ });
97
+ }
98
+ async delete(filepath) {
99
+ await this.bucket.remove([this.getFullPath(filepath)]);
100
+ }
101
+ async *list(prefix = "") {
102
+ const limit = 1e3;
103
+ let offset = 0;
104
+ let itemCount = 0;
105
+ do {
106
+ const { data, error } = await this.bucket.list(this.config.root, { limit, offset, search: prefix });
107
+ if (!data || error) {
108
+ break;
109
+ }
110
+ itemCount = data.length;
111
+ offset += itemCount;
112
+ for (const item of data) {
113
+ yield item.name;
114
+ }
115
+ } while (itemCount === limit);
116
+ }
117
+ };
118
+ var src_default = DriverSupabase;
119
+ export {
120
+ DriverSupabase,
121
+ src_default as default
122
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@directus/storage-driver-supabase",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Supabase file storage abstraction for `@directus/storage`",
5
5
  "homepage": "https://directus.io",
6
6
  "repository": {
@@ -23,19 +23,20 @@
23
23
  "dependencies": {
24
24
  "@supabase/storage-js": "2.5.1",
25
25
  "undici": "5.22.1",
26
- "@directus/storage": "10.0.5",
27
- "@directus/utils": "10.0.11"
26
+ "@directus/storage": "10.0.6",
27
+ "@directus/utils": "11.0.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@ngneat/falso": "6.4.0",
31
31
  "@vitest/coverage-c8": "0.31.1",
32
- "typescript": "5.0.4",
32
+ "tsup": "7.2.0",
33
+ "typescript": "5.2.2",
33
34
  "vitest": "0.31.1",
34
- "@directus/tsconfig": "1.0.0"
35
+ "@directus/tsconfig": "1.0.1"
35
36
  },
36
37
  "scripts": {
37
- "build": "tsc --project tsconfig.prod.json",
38
- "dev": "tsc --watch",
38
+ "build": "tsup src/index.ts --format=esm --dts",
39
+ "dev": "tsup src/index.ts --format=esm --dts --watch",
39
40
  "test": "vitest --watch=false"
40
41
  }
41
42
  }