-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathtypes.ts
More file actions
195 lines (178 loc) · 6.33 KB
/
types.ts
File metadata and controls
195 lines (178 loc) · 6.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
import type { S3Client } from '@aws-sdk/client-s3';
/**
* Per-bucket configuration resolved from the storage_module tables.
*/
export interface BucketConfig {
id: string;
key: string;
type: 'public' | 'private' | 'temp';
is_public: boolean;
owner_id: string;
allowed_mime_types: string[] | null;
max_file_size: number | null;
}
/**
* Storage module configuration resolved from metaschema for a given database.
*/
export interface StorageModuleConfig {
/** The metaschema storage_module row ID */
id: string;
/** Resolved schema.table for buckets */
bucketsQualifiedName: string;
/** Resolved schema.table for files */
filesQualifiedName: string;
/** Resolved schema.table for upload_requests */
uploadRequestsQualifiedName: string;
/** Schema name (e.g., "app_public") */
schemaName: string;
/** Buckets table name */
bucketsTableName: string;
/** Files table name */
filesTableName: string;
/** Upload requests table name */
uploadRequestsTableName: string;
// --- S3 connection config (NULL in DB = use global env/plugin defaults) ---
/** S3-compatible API endpoint URL (per-database override) */
endpoint: string | null;
/** Public URL prefix for generating download URLs (per-database override) */
publicUrlPrefix: string | null;
/** Storage provider type: 'minio', 's3', 'gcs', etc. (per-database override) */
provider: string | null;
/** CORS allowed origins (per-database override, NULL = use global fallback) */
allowedOrigins: string[] | null;
// --- Per-database configurable settings ---
/** Presigned PUT URL expiry in seconds (default: 900 = 15 min) */
uploadUrlExpirySeconds: number;
/** Presigned GET URL expiry in seconds (default: 3600 = 1 hour) */
downloadUrlExpirySeconds: number;
/** Default max file size in bytes (default: 200MB). Bucket-level max_file_size overrides this. */
defaultMaxFileSize: number;
/** Max filename length in characters (default: 1024) */
maxFilenameLength: number;
/** Cache TTL in seconds for this config entry (default: 300 dev / 3600 prod) */
cacheTtlSeconds: number;
}
/**
* Input for the requestUploadUrl mutation.
*/
export interface RequestUploadUrlInput {
/** Bucket key (e.g., "public", "private") */
bucketKey: string;
/** SHA-256 content hash computed by the client */
contentHash: string;
/** MIME type of the file */
contentType: string;
/** File size in bytes */
size: number;
/** Original filename (optional, for display/Content-Disposition) */
filename?: string;
}
/**
* Result of the requestUploadUrl mutation.
*/
export interface RequestUploadUrlPayload {
/** Presigned PUT URL (null if deduplicated) */
uploadUrl: string | null;
/** The file ID (existing if dedup, new if fresh upload) */
fileId: string;
/** The S3 key */
key: string;
/** Whether this file was deduplicated (already exists with same hash) */
deduplicated: boolean;
/** Presigned URL expiry time (null if deduplicated) */
expiresAt: string | null;
}
/**
* Input for the confirmUpload mutation.
*/
export interface ConfirmUploadInput {
/** The file ID returned by requestUploadUrl */
fileId: string;
}
/**
* Result of the confirmUpload mutation.
*/
export interface ConfirmUploadPayload {
/** The confirmed file ID */
fileId: string;
/** New file status (should be 'ready') */
status: string;
/** Whether confirmation succeeded */
success: boolean;
}
/**
* S3 configuration for the presigned URL plugin.
*/
export interface S3Config {
/** S3 client instance */
client: S3Client;
/** S3 bucket name (the actual S3 bucket, not the logical bucket key) */
bucket: string;
/** S3 endpoint URL (for MinIO/custom S3) */
endpoint?: string;
/** S3 region */
region?: string;
/** Whether to use path-style URLs (required for MinIO) */
forcePathStyle?: boolean;
/** Public URL prefix for generating download URLs */
publicUrlPrefix?: string;
}
/**
* S3 configuration or a lazy getter that returns it on first use.
* When a function is provided, it will only be called when the first
* mutation or resolver actually needs the S3 client — avoiding eager
* env-var reads and S3Client creation at module import time.
*/
export type S3ConfigOrGetter = S3Config | (() => S3Config);
/**
* Function to derive the actual S3 bucket name for a given database.
*
* When provided, the presigned URL plugin calls this on every request
* to determine which S3 bucket to use — enabling per-database bucket
* isolation. If not provided, falls back to `s3Config.bucket` (global).
*
* @param databaseId - The metaschema database UUID
* @returns The S3 bucket name for this database
*/
export type BucketNameResolver = (databaseId: string) => string;
/**
* Callback to lazily provision an S3 bucket on first use.
*
* Called by the presigned URL plugin before generating a presigned PUT URL
* when the bucket has not been seen before (tracked in an in-memory cache).
* The implementation should create and fully configure the S3 bucket
* (privacy policies, CORS, lifecycle rules, etc.) — or no-op if the
* bucket already exists.
*
* @param bucketName - The S3 bucket name to provision
* @param accessType - The logical bucket type ('public', 'private', 'temp')
* @param databaseId - The metaschema database UUID
* @param allowedOrigins - Per-database CORS origins (from storage_module), or null to use global fallback
*/
export type EnsureBucketProvisioned = (
bucketName: string,
accessType: 'public' | 'private' | 'temp',
databaseId: string,
allowedOrigins: string[] | null,
) => Promise<void>;
/**
* Plugin options for the presigned URL plugin.
*/
export interface PresignedUrlPluginOptions {
/** S3 configuration (concrete or lazy getter) */
s3: S3ConfigOrGetter;
/**
* Optional function to resolve S3 bucket name per-database.
* When set, each database gets its own S3 bucket instead of sharing
* the global `s3Config.bucket`. The S3 credentials (client) remain shared.
*/
resolveBucketName?: BucketNameResolver;
/**
* Optional callback to lazily provision an S3 bucket on first upload.
* When set, the plugin calls this before generating a presigned PUT URL
* for any S3 bucket it hasn't seen yet (tracked in an in-memory cache).
* This enables graceful bucket creation without requiring buckets to
* exist at database provisioning time.
*/
ensureBucketProvisioned?: EnsureBucketProvisioned;
}