@protobase/server 0.30.0 → 0.30.2
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/admin-options.d.ts +1 -1
- package/dist/api-keys/caller-settings.js +27 -0
- package/dist/create-admin.d.ts +1 -1
- package/dist/create-admin.js +20 -2
- package/dist/files/download.js +2 -1
- package/dist/files/limits.d.ts +5 -0
- package/dist/files/limits.js +10 -4
- package/dist/files/local-files.js +3 -1
- package/dist/files/options.d.ts +9 -0
- package/dist/files/runtime.js +14 -5
- package/dist/files/s3-files.js +3 -1
- package/dist/files/storage-provider.d.ts +12 -0
- package/dist/files/storage-provider.js +18 -0
- package/dist/files/store.d.ts +2 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/dist/storage/bucket-routes.js +78 -0
- package/dist/storage/bucket-sql.js +29 -0
- package/dist/storage/list-sql.js +29 -0
- package/dist/storage/move-copy.js +63 -0
- package/dist/storage/multipart.js +47 -0
- package/dist/storage/object-body.js +75 -0
- package/dist/storage/object-key.d.ts +9 -0
- package/dist/storage/object-key.js +32 -0
- package/dist/storage/object-routes.js +130 -0
- package/dist/storage/object-sql.js +56 -0
- package/dist/storage/serve-object.js +51 -0
- package/dist/storage/signed-routes.js +121 -0
- package/dist/storage/storage-context.js +25 -0
- package/dist/storage/storage-db.js +23 -0
- package/dist/storage/storage-error.js +63 -0
- package/dist/storage/storage-routes.js +28 -0
- package/dist/storage/storage-token.js +28 -0
- package/dist/storage/upload-object.js +37 -0
- package/dist/storage/write-object.js +85 -0
- package/package.json +4 -4
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { accepts } from "../files/media-types.js";
|
|
2
|
+
import { findBucket } from "./bucket-sql.js";
|
|
3
|
+
import { bucketNotFound, mimeTypeRefused } from "./storage-error.js";
|
|
4
|
+
import { asApp } from "./storage-db.js";
|
|
5
|
+
import { writeObject } from "./write-object.js";
|
|
6
|
+
import { incomingObject } from "./object-body.js";
|
|
7
|
+
//#region src/storage/upload-object.ts
|
|
8
|
+
/** The bucket an upload goes to, read as the app, as Supabase Storage reads it: its size limit and allowed types. */
|
|
9
|
+
const uploadBucket = async (deps, id) => {
|
|
10
|
+
const bucket = await asApp(deps, (trx) => findBucket(trx, id));
|
|
11
|
+
if (!bucket) throw bucketNotFound();
|
|
12
|
+
return bucket;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Stores the object a request uploads at `target` (see `writeObject`), within the bucket's size limit and the app's,
|
|
16
|
+
* and of a type the bucket allows. Answers what storage-js reads back: the row's id and `<bucket>/<name>`.
|
|
17
|
+
*/
|
|
18
|
+
const uploadObject = async (deps, request, target) => {
|
|
19
|
+
const bucket = await uploadBucket(deps, target.bucket);
|
|
20
|
+
const maxBytes = Math.min(bucket.file_size_limit ?? Infinity, deps.maxBytes);
|
|
21
|
+
const incoming = await incomingObject(request, maxBytes);
|
|
22
|
+
const type = incoming.type.split(";", 1)[0].trim().toLowerCase();
|
|
23
|
+
if (bucket.allowed_mime_types?.length && !accepts(bucket.allowed_mime_types, type)) {
|
|
24
|
+
await incoming.body.cancel();
|
|
25
|
+
throw mimeTypeRefused(type);
|
|
26
|
+
}
|
|
27
|
+
const { id } = await writeObject(deps, target, {
|
|
28
|
+
...incoming,
|
|
29
|
+
store: (key) => deps.store.put(key, incoming.body)
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
Id: id,
|
|
33
|
+
Key: `${target.bucket}/${target.name}`
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
export { uploadBucket, uploadObject };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { accessDenied, alreadyExists } from "./storage-error.js";
|
|
2
|
+
import { objectKey } from "./object-key.js";
|
|
3
|
+
import { findObject, insertObject, updateObject } from "./object-sql.js";
|
|
4
|
+
import { asApp, becomeCaller } from "./storage-db.js";
|
|
5
|
+
//#region src/storage/write-object.ts
|
|
6
|
+
/** The owner Supabase records for a write: the signed-in user, or nobody for the keys alone. */
|
|
7
|
+
const ownerOf = (caller) => caller.role === "authenticated" && typeof caller.claims.sub === "string" ? caller.claims.sub : null;
|
|
8
|
+
const writeRow = async (trx, deps, target, write) => {
|
|
9
|
+
const existing = await findObject(trx, target.bucket, target.name, true);
|
|
10
|
+
if (existing && !target.upsert) throw alreadyExists();
|
|
11
|
+
await becomeCaller(trx, deps, target.caller);
|
|
12
|
+
if (!existing) return {
|
|
13
|
+
id: await insertObject(trx, target.bucket, target.name, write),
|
|
14
|
+
replaced: void 0
|
|
15
|
+
};
|
|
16
|
+
if (!await updateObject(trx, existing.id, write)) throw accessDenied();
|
|
17
|
+
return {
|
|
18
|
+
id: existing.id,
|
|
19
|
+
replaced: existing
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
var ProbeDone = class extends Error {};
|
|
23
|
+
/**
|
|
24
|
+
* Whether the caller may write the object, decided by the restored policies on a row written and rolled back, before
|
|
25
|
+
* any byte is stored: a refused upload costs no storage. Throws the refusal.
|
|
26
|
+
*/
|
|
27
|
+
const probeWrite = async (deps, target, type) => {
|
|
28
|
+
const metadata = {
|
|
29
|
+
eTag: "",
|
|
30
|
+
size: 0,
|
|
31
|
+
mimetype: type,
|
|
32
|
+
cacheControl: "",
|
|
33
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
34
|
+
contentLength: 0,
|
|
35
|
+
httpStatusCode: 200
|
|
36
|
+
};
|
|
37
|
+
await asApp(deps, async (trx) => {
|
|
38
|
+
await writeRow(trx, deps, target, {
|
|
39
|
+
owner: target.owner,
|
|
40
|
+
version: crypto.randomUUID(),
|
|
41
|
+
metadata,
|
|
42
|
+
user_metadata: null
|
|
43
|
+
});
|
|
44
|
+
throw new ProbeDone();
|
|
45
|
+
}).catch((error) => {
|
|
46
|
+
if (!(error instanceof ProbeDone)) throw error;
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Writes an object: checks the caller may (`probeWrite`), stores the bytes under a new version, then writes the row
|
|
51
|
+
* as the caller in one transaction, so the policies decide again on the real row. When that fails, the new bytes are
|
|
52
|
+
* deleted; once it commits, the bytes of the object it replaced are.
|
|
53
|
+
*/
|
|
54
|
+
const writeObject = async (deps, target, bytes) => {
|
|
55
|
+
await probeWrite(deps, target, bytes.type);
|
|
56
|
+
const version = crypto.randomUUID();
|
|
57
|
+
const key = await objectKey(target.bucket, target.name, version);
|
|
58
|
+
const { size } = await bytes.store(key);
|
|
59
|
+
const metadata = {
|
|
60
|
+
eTag: `"${version}"`,
|
|
61
|
+
size,
|
|
62
|
+
mimetype: bytes.type,
|
|
63
|
+
cacheControl: bytes.cacheControl,
|
|
64
|
+
lastModified: (/* @__PURE__ */ new Date()).toUTCString(),
|
|
65
|
+
contentLength: size,
|
|
66
|
+
httpStatusCode: 200
|
|
67
|
+
};
|
|
68
|
+
const write = {
|
|
69
|
+
owner: target.owner,
|
|
70
|
+
version,
|
|
71
|
+
metadata,
|
|
72
|
+
user_metadata: bytes.userMetadata
|
|
73
|
+
};
|
|
74
|
+
const written = await asApp(deps, (trx) => writeRow(trx, deps, target, write)).catch(async (error) => {
|
|
75
|
+
await deps.store.delete(key);
|
|
76
|
+
throw error;
|
|
77
|
+
});
|
|
78
|
+
if (written.replaced) await deps.store.delete(await objectKey(target.bucket, target.name, written.replaced.version));
|
|
79
|
+
return {
|
|
80
|
+
id: written.id,
|
|
81
|
+
metadata
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
//#endregion
|
|
85
|
+
export { ownerOf, probeWrite, writeObject };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/server",
|
|
3
|
-
"version": "0.30.
|
|
3
|
+
"version": "0.30.2",
|
|
4
4
|
"description": "The Protobase REST API as a Hono app, with Better Auth sign-in.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@better-auth/passkey": "^1.7.7",
|
|
34
34
|
"@better-auth/sso": "^1.7.7",
|
|
35
|
-
"@protobase/layout": "0.30.
|
|
36
|
-
"@protobase/query": "0.30.
|
|
37
|
-
"@protobase/schema": "0.30.
|
|
35
|
+
"@protobase/layout": "0.30.2",
|
|
36
|
+
"@protobase/query": "0.30.2",
|
|
37
|
+
"@protobase/schema": "0.30.2",
|
|
38
38
|
"@react-email/render": "^2.1.0",
|
|
39
39
|
"@scalar/hono-api-reference": "^0.12.10",
|
|
40
40
|
"@sentry/core": "^11.7.0",
|