@squadbase/react 0.0.1 → 0.0.2-dev.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.cjs +180 -0
- package/dist/index.d.cts +98 -1
- package/dist/index.d.ts +98 -1
- package/dist/index.js +178 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
SquadbaseProvider: () => SquadbaseProvider,
|
|
24
|
+
StorageUploadsClient: () => StorageUploadsClient,
|
|
25
|
+
useStorage: () => useStorage,
|
|
24
26
|
useUser: () => useUser
|
|
25
27
|
});
|
|
26
28
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -70,8 +72,186 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
|
70
72
|
function SquadbaseProvider({ children }) {
|
|
71
73
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(UserProvider, { children });
|
|
72
74
|
}
|
|
75
|
+
|
|
76
|
+
// src/storage.tsx
|
|
77
|
+
var import_zod2 = require("zod");
|
|
78
|
+
var STORAGE_BASE_PATH = "/_sqcore/storage";
|
|
79
|
+
var zApiListItem = import_zod2.z.object({
|
|
80
|
+
key: import_zod2.z.string(),
|
|
81
|
+
size: import_zod2.z.number(),
|
|
82
|
+
lastModified: import_zod2.z.string()
|
|
83
|
+
});
|
|
84
|
+
var zApiListResult = import_zod2.z.object({
|
|
85
|
+
objects: import_zod2.z.array(zApiListItem),
|
|
86
|
+
commonPrefixes: import_zod2.z.array(import_zod2.z.string()).default([]),
|
|
87
|
+
nextCursor: import_zod2.z.string().optional()
|
|
88
|
+
});
|
|
89
|
+
var zApiMetadata = import_zod2.z.object({
|
|
90
|
+
key: import_zod2.z.string(),
|
|
91
|
+
size: import_zod2.z.number(),
|
|
92
|
+
contentType: import_zod2.z.string(),
|
|
93
|
+
createdAt: import_zod2.z.string(),
|
|
94
|
+
createdBy: import_zod2.z.string(),
|
|
95
|
+
source: import_zod2.z.enum(["upload", "agent", "system"])
|
|
96
|
+
});
|
|
97
|
+
var zApiPresignedGet = import_zod2.z.object({
|
|
98
|
+
url: import_zod2.z.string(),
|
|
99
|
+
expiresAt: import_zod2.z.string()
|
|
100
|
+
});
|
|
101
|
+
var zApiPresignedPut = import_zod2.z.object({
|
|
102
|
+
url: import_zod2.z.string(),
|
|
103
|
+
headers: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()),
|
|
104
|
+
expiresAt: import_zod2.z.string()
|
|
105
|
+
});
|
|
106
|
+
var storageUrl = (path, query) => {
|
|
107
|
+
const params = new URLSearchParams();
|
|
108
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
109
|
+
if (value != null) params.set(key, value);
|
|
110
|
+
}
|
|
111
|
+
const qs = params.toString();
|
|
112
|
+
return `${STORAGE_BASE_PATH}${path}${qs.length > 0 ? `?${qs}` : ""}`;
|
|
113
|
+
};
|
|
114
|
+
var throwIfNotOk = async (res, label) => {
|
|
115
|
+
if (res.ok) return;
|
|
116
|
+
const text = await res.text();
|
|
117
|
+
throw new Error(
|
|
118
|
+
`Project Storage ${label} failed: ${res.status} ${res.statusText}: ${text}`
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
var StorageUploadsClient = class {
|
|
122
|
+
/**
|
|
123
|
+
* Lists files under a prefix. Pass `delimiter: "/"` for a folder-style
|
|
124
|
+
* listing, or omit it for a flat recursive listing.
|
|
125
|
+
*/
|
|
126
|
+
async list(prefix, options) {
|
|
127
|
+
const res = await fetch(
|
|
128
|
+
storageUrl("/list", {
|
|
129
|
+
prefix,
|
|
130
|
+
limit: options?.limit != null ? String(options.limit) : void 0,
|
|
131
|
+
cursor: options?.cursor,
|
|
132
|
+
delimiter: options?.delimiter
|
|
133
|
+
}),
|
|
134
|
+
{ credentials: "include" }
|
|
135
|
+
);
|
|
136
|
+
await throwIfNotOk(res, "list");
|
|
137
|
+
const data = zApiListResult.parse(await res.json());
|
|
138
|
+
return {
|
|
139
|
+
objects: data.objects.map((o) => ({
|
|
140
|
+
key: o.key,
|
|
141
|
+
size: o.size,
|
|
142
|
+
lastModified: o.lastModified
|
|
143
|
+
})),
|
|
144
|
+
commonPrefixes: data.commonPrefixes,
|
|
145
|
+
nextCursor: data.nextCursor
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Fetches a file's metadata without reading its body.
|
|
150
|
+
*/
|
|
151
|
+
async head(key) {
|
|
152
|
+
const res = await fetch(storageUrl("/head", { key }), {
|
|
153
|
+
credentials: "include"
|
|
154
|
+
});
|
|
155
|
+
await throwIfNotOk(res, "head");
|
|
156
|
+
const data = zApiMetadata.parse(await res.json());
|
|
157
|
+
return {
|
|
158
|
+
key: data.key,
|
|
159
|
+
size: data.size,
|
|
160
|
+
contentType: data.contentType,
|
|
161
|
+
createdAt: data.createdAt
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Returns a short-lived presigned GET URL for a file. Re-fetch before
|
|
166
|
+
* `expiresAt` to keep the URL valid.
|
|
167
|
+
*/
|
|
168
|
+
async getUrl(key) {
|
|
169
|
+
const res = await fetch(storageUrl("/sign", { key }), {
|
|
170
|
+
credentials: "include"
|
|
171
|
+
});
|
|
172
|
+
await throwIfNotOk(res, "getUrl");
|
|
173
|
+
const data = zApiPresignedGet.parse(await res.json());
|
|
174
|
+
return { url: data.url, expiresAt: data.expiresAt };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Fetches a file's contents and returns the raw `Response`. Use the standard
|
|
178
|
+
* `Response` methods (`.text()` / `.json()` / `.blob()` / `.arrayBuffer()`)
|
|
179
|
+
* to read the body.
|
|
180
|
+
*/
|
|
181
|
+
async get(key) {
|
|
182
|
+
const { url } = await this.getUrl(key);
|
|
183
|
+
const res = await fetch(url, { method: "GET" });
|
|
184
|
+
await throwIfNotOk(res, "get");
|
|
185
|
+
return res;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Uploads a file. `data` may be a `Blob` (including `File`), `ArrayBuffer`,
|
|
189
|
+
* `Uint8Array`, or `string`.
|
|
190
|
+
*/
|
|
191
|
+
async put(key, data, options) {
|
|
192
|
+
const contentType = options?.contentType ?? "application/octet-stream";
|
|
193
|
+
const body = typeof data === "string" ? new Blob([data], { type: contentType }) : data;
|
|
194
|
+
const contentLength = body instanceof Blob ? body.size : body.byteLength;
|
|
195
|
+
const signRes = await fetch(storageUrl("/sign"), {
|
|
196
|
+
method: "POST",
|
|
197
|
+
credentials: "include",
|
|
198
|
+
headers: { "Content-Type": "application/json" },
|
|
199
|
+
body: JSON.stringify({ key, contentType, contentLength })
|
|
200
|
+
});
|
|
201
|
+
await throwIfNotOk(signRes, "put (sign)");
|
|
202
|
+
const signed = zApiPresignedPut.parse(await signRes.json());
|
|
203
|
+
const putRes = await fetch(signed.url, {
|
|
204
|
+
method: "PUT",
|
|
205
|
+
headers: signed.headers,
|
|
206
|
+
body
|
|
207
|
+
});
|
|
208
|
+
await throwIfNotOk(putRes, "put (S3)");
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Deletes a file.
|
|
212
|
+
*/
|
|
213
|
+
async delete(key) {
|
|
214
|
+
const res = await fetch(storageUrl("/objects", { key }), {
|
|
215
|
+
method: "DELETE",
|
|
216
|
+
credentials: "include"
|
|
217
|
+
});
|
|
218
|
+
await throwIfNotOk(res, "delete");
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Copies a file to a new key.
|
|
222
|
+
*/
|
|
223
|
+
async copy(srcKey, destKey, options) {
|
|
224
|
+
const res = await fetch(storageUrl("/copy"), {
|
|
225
|
+
method: "POST",
|
|
226
|
+
credentials: "include",
|
|
227
|
+
headers: { "Content-Type": "application/json" },
|
|
228
|
+
body: JSON.stringify({ srcKey, destKey, overwrite: options?.overwrite })
|
|
229
|
+
});
|
|
230
|
+
await throwIfNotOk(res, "copy");
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Moves (renames) a file to a new key.
|
|
234
|
+
*/
|
|
235
|
+
async move(srcKey, destKey, options) {
|
|
236
|
+
const res = await fetch(storageUrl("/move"), {
|
|
237
|
+
method: "POST",
|
|
238
|
+
credentials: "include",
|
|
239
|
+
headers: { "Content-Type": "application/json" },
|
|
240
|
+
body: JSON.stringify({ srcKey, destKey, overwrite: options?.overwrite })
|
|
241
|
+
});
|
|
242
|
+
await throwIfNotOk(res, "move");
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
var storageClient = {
|
|
246
|
+
uploads: new StorageUploadsClient()
|
|
247
|
+
};
|
|
248
|
+
function useStorage() {
|
|
249
|
+
return storageClient;
|
|
250
|
+
}
|
|
73
251
|
// Annotate the CommonJS export names for ESM import in node:
|
|
74
252
|
0 && (module.exports = {
|
|
75
253
|
SquadbaseProvider,
|
|
254
|
+
StorageUploadsClient,
|
|
255
|
+
useStorage,
|
|
76
256
|
useUser
|
|
77
257
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -26,4 +26,101 @@ type UserState = {
|
|
|
26
26
|
};
|
|
27
27
|
declare function useUser(): UserState;
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
/** A single file in a listing. */
|
|
30
|
+
type StorageObject = {
|
|
31
|
+
/** Relative key within the uploads namespace. */
|
|
32
|
+
key: string;
|
|
33
|
+
/** Size in bytes. */
|
|
34
|
+
size: number;
|
|
35
|
+
/** Last modified time (ISO 8601). */
|
|
36
|
+
lastModified: string;
|
|
37
|
+
};
|
|
38
|
+
type StorageListResult = {
|
|
39
|
+
/** Files under the requested prefix. */
|
|
40
|
+
objects: StorageObject[];
|
|
41
|
+
/** Sub-prefixes (folders) returned when `delimiter` is set; otherwise empty. */
|
|
42
|
+
commonPrefixes: string[];
|
|
43
|
+
/** Cursor to pass back for the next page, if any. */
|
|
44
|
+
nextCursor?: string;
|
|
45
|
+
};
|
|
46
|
+
/** Metadata for a single file. */
|
|
47
|
+
type StorageMetadata = {
|
|
48
|
+
key: string;
|
|
49
|
+
size: number;
|
|
50
|
+
/** MIME type. */
|
|
51
|
+
contentType: string;
|
|
52
|
+
/** Creation time (ISO 8601). */
|
|
53
|
+
createdAt: string;
|
|
54
|
+
};
|
|
55
|
+
/** A presigned URL and its expiry. */
|
|
56
|
+
type PresignedUrl = {
|
|
57
|
+
url: string;
|
|
58
|
+
/** Expiry time (ISO 8601). Re-fetch before it expires. */
|
|
59
|
+
expiresAt: string;
|
|
60
|
+
};
|
|
61
|
+
type StorageListOptions = {
|
|
62
|
+
/** Maximum number of entries to return. */
|
|
63
|
+
limit?: number;
|
|
64
|
+
/** Pagination cursor from a previous `nextCursor`. */
|
|
65
|
+
cursor?: string;
|
|
66
|
+
/**
|
|
67
|
+
* When set to `"/"`, splits the result into direct files and
|
|
68
|
+
* `commonPrefixes` (folders). When omitted, lists every file under the
|
|
69
|
+
* prefix recursively as a flat list.
|
|
70
|
+
*/
|
|
71
|
+
delimiter?: string;
|
|
72
|
+
};
|
|
73
|
+
type StoragePutOptions = {
|
|
74
|
+
/** Defaults to `application/octet-stream`. */
|
|
75
|
+
contentType?: string;
|
|
76
|
+
};
|
|
77
|
+
type StorageCopyOptions = {
|
|
78
|
+
/** When omitted, an existing destination is overwritten. */
|
|
79
|
+
overwrite?: boolean;
|
|
80
|
+
};
|
|
81
|
+
declare class StorageUploadsClient {
|
|
82
|
+
/**
|
|
83
|
+
* Lists files under a prefix. Pass `delimiter: "/"` for a folder-style
|
|
84
|
+
* listing, or omit it for a flat recursive listing.
|
|
85
|
+
*/
|
|
86
|
+
list(prefix?: string, options?: StorageListOptions): Promise<StorageListResult>;
|
|
87
|
+
/**
|
|
88
|
+
* Fetches a file's metadata without reading its body.
|
|
89
|
+
*/
|
|
90
|
+
head(key: string): Promise<StorageMetadata>;
|
|
91
|
+
/**
|
|
92
|
+
* Returns a short-lived presigned GET URL for a file. Re-fetch before
|
|
93
|
+
* `expiresAt` to keep the URL valid.
|
|
94
|
+
*/
|
|
95
|
+
getUrl(key: string): Promise<PresignedUrl>;
|
|
96
|
+
/**
|
|
97
|
+
* Fetches a file's contents and returns the raw `Response`. Use the standard
|
|
98
|
+
* `Response` methods (`.text()` / `.json()` / `.blob()` / `.arrayBuffer()`)
|
|
99
|
+
* to read the body.
|
|
100
|
+
*/
|
|
101
|
+
get(key: string): Promise<Response>;
|
|
102
|
+
/**
|
|
103
|
+
* Uploads a file. `data` may be a `Blob` (including `File`), `ArrayBuffer`,
|
|
104
|
+
* `Uint8Array`, or `string`.
|
|
105
|
+
*/
|
|
106
|
+
put(key: string, data: Blob | ArrayBuffer | Uint8Array | string, options?: StoragePutOptions): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Deletes a file.
|
|
109
|
+
*/
|
|
110
|
+
delete(key: string): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Copies a file to a new key.
|
|
113
|
+
*/
|
|
114
|
+
copy(srcKey: string, destKey: string, options?: StorageCopyOptions): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Moves (renames) a file to a new key.
|
|
117
|
+
*/
|
|
118
|
+
move(srcKey: string, destKey: string, options?: StorageCopyOptions): Promise<void>;
|
|
119
|
+
}
|
|
120
|
+
type StorageClient = {
|
|
121
|
+
uploads: StorageUploadsClient;
|
|
122
|
+
};
|
|
123
|
+
/** Returns the Project Storage client. */
|
|
124
|
+
declare function useStorage(): StorageClient;
|
|
125
|
+
|
|
126
|
+
export { type PresignedUrl, SquadbaseProvider, type StorageClient, type StorageCopyOptions, type StorageListOptions, type StorageListResult, type StorageMetadata, type StorageObject, type StoragePutOptions, StorageUploadsClient, type User, type UserState, useStorage, useUser };
|
package/dist/index.d.ts
CHANGED
|
@@ -26,4 +26,101 @@ type UserState = {
|
|
|
26
26
|
};
|
|
27
27
|
declare function useUser(): UserState;
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
/** A single file in a listing. */
|
|
30
|
+
type StorageObject = {
|
|
31
|
+
/** Relative key within the uploads namespace. */
|
|
32
|
+
key: string;
|
|
33
|
+
/** Size in bytes. */
|
|
34
|
+
size: number;
|
|
35
|
+
/** Last modified time (ISO 8601). */
|
|
36
|
+
lastModified: string;
|
|
37
|
+
};
|
|
38
|
+
type StorageListResult = {
|
|
39
|
+
/** Files under the requested prefix. */
|
|
40
|
+
objects: StorageObject[];
|
|
41
|
+
/** Sub-prefixes (folders) returned when `delimiter` is set; otherwise empty. */
|
|
42
|
+
commonPrefixes: string[];
|
|
43
|
+
/** Cursor to pass back for the next page, if any. */
|
|
44
|
+
nextCursor?: string;
|
|
45
|
+
};
|
|
46
|
+
/** Metadata for a single file. */
|
|
47
|
+
type StorageMetadata = {
|
|
48
|
+
key: string;
|
|
49
|
+
size: number;
|
|
50
|
+
/** MIME type. */
|
|
51
|
+
contentType: string;
|
|
52
|
+
/** Creation time (ISO 8601). */
|
|
53
|
+
createdAt: string;
|
|
54
|
+
};
|
|
55
|
+
/** A presigned URL and its expiry. */
|
|
56
|
+
type PresignedUrl = {
|
|
57
|
+
url: string;
|
|
58
|
+
/** Expiry time (ISO 8601). Re-fetch before it expires. */
|
|
59
|
+
expiresAt: string;
|
|
60
|
+
};
|
|
61
|
+
type StorageListOptions = {
|
|
62
|
+
/** Maximum number of entries to return. */
|
|
63
|
+
limit?: number;
|
|
64
|
+
/** Pagination cursor from a previous `nextCursor`. */
|
|
65
|
+
cursor?: string;
|
|
66
|
+
/**
|
|
67
|
+
* When set to `"/"`, splits the result into direct files and
|
|
68
|
+
* `commonPrefixes` (folders). When omitted, lists every file under the
|
|
69
|
+
* prefix recursively as a flat list.
|
|
70
|
+
*/
|
|
71
|
+
delimiter?: string;
|
|
72
|
+
};
|
|
73
|
+
type StoragePutOptions = {
|
|
74
|
+
/** Defaults to `application/octet-stream`. */
|
|
75
|
+
contentType?: string;
|
|
76
|
+
};
|
|
77
|
+
type StorageCopyOptions = {
|
|
78
|
+
/** When omitted, an existing destination is overwritten. */
|
|
79
|
+
overwrite?: boolean;
|
|
80
|
+
};
|
|
81
|
+
declare class StorageUploadsClient {
|
|
82
|
+
/**
|
|
83
|
+
* Lists files under a prefix. Pass `delimiter: "/"` for a folder-style
|
|
84
|
+
* listing, or omit it for a flat recursive listing.
|
|
85
|
+
*/
|
|
86
|
+
list(prefix?: string, options?: StorageListOptions): Promise<StorageListResult>;
|
|
87
|
+
/**
|
|
88
|
+
* Fetches a file's metadata without reading its body.
|
|
89
|
+
*/
|
|
90
|
+
head(key: string): Promise<StorageMetadata>;
|
|
91
|
+
/**
|
|
92
|
+
* Returns a short-lived presigned GET URL for a file. Re-fetch before
|
|
93
|
+
* `expiresAt` to keep the URL valid.
|
|
94
|
+
*/
|
|
95
|
+
getUrl(key: string): Promise<PresignedUrl>;
|
|
96
|
+
/**
|
|
97
|
+
* Fetches a file's contents and returns the raw `Response`. Use the standard
|
|
98
|
+
* `Response` methods (`.text()` / `.json()` / `.blob()` / `.arrayBuffer()`)
|
|
99
|
+
* to read the body.
|
|
100
|
+
*/
|
|
101
|
+
get(key: string): Promise<Response>;
|
|
102
|
+
/**
|
|
103
|
+
* Uploads a file. `data` may be a `Blob` (including `File`), `ArrayBuffer`,
|
|
104
|
+
* `Uint8Array`, or `string`.
|
|
105
|
+
*/
|
|
106
|
+
put(key: string, data: Blob | ArrayBuffer | Uint8Array | string, options?: StoragePutOptions): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Deletes a file.
|
|
109
|
+
*/
|
|
110
|
+
delete(key: string): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Copies a file to a new key.
|
|
113
|
+
*/
|
|
114
|
+
copy(srcKey: string, destKey: string, options?: StorageCopyOptions): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Moves (renames) a file to a new key.
|
|
117
|
+
*/
|
|
118
|
+
move(srcKey: string, destKey: string, options?: StorageCopyOptions): Promise<void>;
|
|
119
|
+
}
|
|
120
|
+
type StorageClient = {
|
|
121
|
+
uploads: StorageUploadsClient;
|
|
122
|
+
};
|
|
123
|
+
/** Returns the Project Storage client. */
|
|
124
|
+
declare function useStorage(): StorageClient;
|
|
125
|
+
|
|
126
|
+
export { type PresignedUrl, SquadbaseProvider, type StorageClient, type StorageCopyOptions, type StorageListOptions, type StorageListResult, type StorageMetadata, type StorageObject, type StoragePutOptions, StorageUploadsClient, type User, type UserState, useStorage, useUser };
|
package/dist/index.js
CHANGED
|
@@ -48,7 +48,185 @@ import { jsx as jsx2 } from "react/jsx-runtime";
|
|
|
48
48
|
function SquadbaseProvider({ children }) {
|
|
49
49
|
return /* @__PURE__ */ jsx2(UserProvider, { children });
|
|
50
50
|
}
|
|
51
|
+
|
|
52
|
+
// src/storage.tsx
|
|
53
|
+
import { z as z2 } from "zod";
|
|
54
|
+
var STORAGE_BASE_PATH = "/_sqcore/storage";
|
|
55
|
+
var zApiListItem = z2.object({
|
|
56
|
+
key: z2.string(),
|
|
57
|
+
size: z2.number(),
|
|
58
|
+
lastModified: z2.string()
|
|
59
|
+
});
|
|
60
|
+
var zApiListResult = z2.object({
|
|
61
|
+
objects: z2.array(zApiListItem),
|
|
62
|
+
commonPrefixes: z2.array(z2.string()).default([]),
|
|
63
|
+
nextCursor: z2.string().optional()
|
|
64
|
+
});
|
|
65
|
+
var zApiMetadata = z2.object({
|
|
66
|
+
key: z2.string(),
|
|
67
|
+
size: z2.number(),
|
|
68
|
+
contentType: z2.string(),
|
|
69
|
+
createdAt: z2.string(),
|
|
70
|
+
createdBy: z2.string(),
|
|
71
|
+
source: z2.enum(["upload", "agent", "system"])
|
|
72
|
+
});
|
|
73
|
+
var zApiPresignedGet = z2.object({
|
|
74
|
+
url: z2.string(),
|
|
75
|
+
expiresAt: z2.string()
|
|
76
|
+
});
|
|
77
|
+
var zApiPresignedPut = z2.object({
|
|
78
|
+
url: z2.string(),
|
|
79
|
+
headers: z2.record(z2.string(), z2.string()),
|
|
80
|
+
expiresAt: z2.string()
|
|
81
|
+
});
|
|
82
|
+
var storageUrl = (path, query) => {
|
|
83
|
+
const params = new URLSearchParams();
|
|
84
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
85
|
+
if (value != null) params.set(key, value);
|
|
86
|
+
}
|
|
87
|
+
const qs = params.toString();
|
|
88
|
+
return `${STORAGE_BASE_PATH}${path}${qs.length > 0 ? `?${qs}` : ""}`;
|
|
89
|
+
};
|
|
90
|
+
var throwIfNotOk = async (res, label) => {
|
|
91
|
+
if (res.ok) return;
|
|
92
|
+
const text = await res.text();
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Project Storage ${label} failed: ${res.status} ${res.statusText}: ${text}`
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
var StorageUploadsClient = class {
|
|
98
|
+
/**
|
|
99
|
+
* Lists files under a prefix. Pass `delimiter: "/"` for a folder-style
|
|
100
|
+
* listing, or omit it for a flat recursive listing.
|
|
101
|
+
*/
|
|
102
|
+
async list(prefix, options) {
|
|
103
|
+
const res = await fetch(
|
|
104
|
+
storageUrl("/list", {
|
|
105
|
+
prefix,
|
|
106
|
+
limit: options?.limit != null ? String(options.limit) : void 0,
|
|
107
|
+
cursor: options?.cursor,
|
|
108
|
+
delimiter: options?.delimiter
|
|
109
|
+
}),
|
|
110
|
+
{ credentials: "include" }
|
|
111
|
+
);
|
|
112
|
+
await throwIfNotOk(res, "list");
|
|
113
|
+
const data = zApiListResult.parse(await res.json());
|
|
114
|
+
return {
|
|
115
|
+
objects: data.objects.map((o) => ({
|
|
116
|
+
key: o.key,
|
|
117
|
+
size: o.size,
|
|
118
|
+
lastModified: o.lastModified
|
|
119
|
+
})),
|
|
120
|
+
commonPrefixes: data.commonPrefixes,
|
|
121
|
+
nextCursor: data.nextCursor
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Fetches a file's metadata without reading its body.
|
|
126
|
+
*/
|
|
127
|
+
async head(key) {
|
|
128
|
+
const res = await fetch(storageUrl("/head", { key }), {
|
|
129
|
+
credentials: "include"
|
|
130
|
+
});
|
|
131
|
+
await throwIfNotOk(res, "head");
|
|
132
|
+
const data = zApiMetadata.parse(await res.json());
|
|
133
|
+
return {
|
|
134
|
+
key: data.key,
|
|
135
|
+
size: data.size,
|
|
136
|
+
contentType: data.contentType,
|
|
137
|
+
createdAt: data.createdAt
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Returns a short-lived presigned GET URL for a file. Re-fetch before
|
|
142
|
+
* `expiresAt` to keep the URL valid.
|
|
143
|
+
*/
|
|
144
|
+
async getUrl(key) {
|
|
145
|
+
const res = await fetch(storageUrl("/sign", { key }), {
|
|
146
|
+
credentials: "include"
|
|
147
|
+
});
|
|
148
|
+
await throwIfNotOk(res, "getUrl");
|
|
149
|
+
const data = zApiPresignedGet.parse(await res.json());
|
|
150
|
+
return { url: data.url, expiresAt: data.expiresAt };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Fetches a file's contents and returns the raw `Response`. Use the standard
|
|
154
|
+
* `Response` methods (`.text()` / `.json()` / `.blob()` / `.arrayBuffer()`)
|
|
155
|
+
* to read the body.
|
|
156
|
+
*/
|
|
157
|
+
async get(key) {
|
|
158
|
+
const { url } = await this.getUrl(key);
|
|
159
|
+
const res = await fetch(url, { method: "GET" });
|
|
160
|
+
await throwIfNotOk(res, "get");
|
|
161
|
+
return res;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Uploads a file. `data` may be a `Blob` (including `File`), `ArrayBuffer`,
|
|
165
|
+
* `Uint8Array`, or `string`.
|
|
166
|
+
*/
|
|
167
|
+
async put(key, data, options) {
|
|
168
|
+
const contentType = options?.contentType ?? "application/octet-stream";
|
|
169
|
+
const body = typeof data === "string" ? new Blob([data], { type: contentType }) : data;
|
|
170
|
+
const contentLength = body instanceof Blob ? body.size : body.byteLength;
|
|
171
|
+
const signRes = await fetch(storageUrl("/sign"), {
|
|
172
|
+
method: "POST",
|
|
173
|
+
credentials: "include",
|
|
174
|
+
headers: { "Content-Type": "application/json" },
|
|
175
|
+
body: JSON.stringify({ key, contentType, contentLength })
|
|
176
|
+
});
|
|
177
|
+
await throwIfNotOk(signRes, "put (sign)");
|
|
178
|
+
const signed = zApiPresignedPut.parse(await signRes.json());
|
|
179
|
+
const putRes = await fetch(signed.url, {
|
|
180
|
+
method: "PUT",
|
|
181
|
+
headers: signed.headers,
|
|
182
|
+
body
|
|
183
|
+
});
|
|
184
|
+
await throwIfNotOk(putRes, "put (S3)");
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Deletes a file.
|
|
188
|
+
*/
|
|
189
|
+
async delete(key) {
|
|
190
|
+
const res = await fetch(storageUrl("/objects", { key }), {
|
|
191
|
+
method: "DELETE",
|
|
192
|
+
credentials: "include"
|
|
193
|
+
});
|
|
194
|
+
await throwIfNotOk(res, "delete");
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Copies a file to a new key.
|
|
198
|
+
*/
|
|
199
|
+
async copy(srcKey, destKey, options) {
|
|
200
|
+
const res = await fetch(storageUrl("/copy"), {
|
|
201
|
+
method: "POST",
|
|
202
|
+
credentials: "include",
|
|
203
|
+
headers: { "Content-Type": "application/json" },
|
|
204
|
+
body: JSON.stringify({ srcKey, destKey, overwrite: options?.overwrite })
|
|
205
|
+
});
|
|
206
|
+
await throwIfNotOk(res, "copy");
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Moves (renames) a file to a new key.
|
|
210
|
+
*/
|
|
211
|
+
async move(srcKey, destKey, options) {
|
|
212
|
+
const res = await fetch(storageUrl("/move"), {
|
|
213
|
+
method: "POST",
|
|
214
|
+
credentials: "include",
|
|
215
|
+
headers: { "Content-Type": "application/json" },
|
|
216
|
+
body: JSON.stringify({ srcKey, destKey, overwrite: options?.overwrite })
|
|
217
|
+
});
|
|
218
|
+
await throwIfNotOk(res, "move");
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
var storageClient = {
|
|
222
|
+
uploads: new StorageUploadsClient()
|
|
223
|
+
};
|
|
224
|
+
function useStorage() {
|
|
225
|
+
return storageClient;
|
|
226
|
+
}
|
|
51
227
|
export {
|
|
52
228
|
SquadbaseProvider,
|
|
229
|
+
StorageUploadsClient,
|
|
230
|
+
useStorage,
|
|
53
231
|
useUser
|
|
54
232
|
};
|