@rebasepro/server 0.12.0 → 0.12.1-canary.g06f263c

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.
Files changed (60) hide show
  1. package/dist/GCSStorageController-BEmDYFKc.js +216 -0
  2. package/dist/GCSStorageController-BEmDYFKc.js.map +1 -0
  3. package/dist/S3StorageController-CK7r5yZb.js +243 -0
  4. package/dist/S3StorageController-CK7r5yZb.js.map +1 -0
  5. package/dist/admin_block-BGQFSAuV.js +123 -0
  6. package/dist/admin_block-BGQFSAuV.js.map +1 -0
  7. package/dist/auth-DQv2_Z3S.js +8923 -0
  8. package/dist/auth-DQv2_Z3S.js.map +1 -0
  9. package/dist/backend-CIxN4FVm.js +15 -0
  10. package/dist/backend-CIxN4FVm.js.map +1 -0
  11. package/dist/backup-CVggVhR2.js +163 -0
  12. package/dist/backup-CVggVhR2.js.map +1 -0
  13. package/dist/boot/boot.d.ts +53 -0
  14. package/dist/boot/driver.d.ts +35 -1
  15. package/dist/boot/fetch-bundle.d.ts +43 -0
  16. package/dist/boot/version-skew.d.ts +77 -0
  17. package/dist/contract-routes-Dj8i5AiM.js +264 -0
  18. package/dist/contract-routes-Dj8i5AiM.js.map +1 -0
  19. package/dist/cron/cron-scheduler.d.ts +34 -0
  20. package/dist/cron-loader-B1S2MCSl.js +63 -0
  21. package/dist/cron-loader-B1S2MCSl.js.map +1 -0
  22. package/dist/cron-routes-CrQ0tK-_.js +62 -0
  23. package/dist/cron-routes-CrQ0tK-_.js.map +1 -0
  24. package/dist/cron-scheduler-B3RFt0HS.js +647 -0
  25. package/dist/cron-scheduler-B3RFt0HS.js.map +1 -0
  26. package/dist/cron-store-BywZsyfZ.js +164 -0
  27. package/dist/cron-store-BywZsyfZ.js.map +1 -0
  28. package/dist/dynamic-import-Dvh-K5fl.js.map +1 -1
  29. package/dist/errors-CgkCzoj7.js +226 -0
  30. package/dist/errors-CgkCzoj7.js.map +1 -0
  31. package/dist/function-loader-B_1fYfUY.js +86 -0
  32. package/dist/function-loader-B_1fYfUY.js.map +1 -0
  33. package/dist/function-routes-C0cLIy3N.js +28 -0
  34. package/dist/function-routes-C0cLIy3N.js.map +1 -0
  35. package/dist/index.es.js +7943 -17923
  36. package/dist/index.es.js.map +1 -1
  37. package/dist/init.d.ts +20 -0
  38. package/dist/{jwt-D-eI6TTu.js → jwt-DD6EtpGj.js} +32 -13
  39. package/dist/{jwt-D-eI6TTu.js.map → jwt-DD6EtpGj.js.map} +1 -1
  40. package/dist/logger-BYU66ENZ.js.map +1 -1
  41. package/dist/logs-routes-BYA72C_C.js +100 -0
  42. package/dist/logs-routes-BYA72C_C.js.map +1 -0
  43. package/dist/{openapi-generator-Bjzmb5cn.js → openapi-generator-5re-77gM.js} +9 -3
  44. package/dist/openapi-generator-5re-77gM.js.map +1 -0
  45. package/dist/policy-B5d-asZT.js +115 -0
  46. package/dist/policy-B5d-asZT.js.map +1 -0
  47. package/dist/{schema-editor-routes-DDxfOIid.js → schema-editor-routes-Doil0rrr.js} +4 -3
  48. package/dist/{schema-editor-routes-DDxfOIid.js.map → schema-editor-routes-Doil0rrr.js.map} +1 -1
  49. package/dist/{src-CoOAMnBh.js → src-By2xYed6.js} +238 -66
  50. package/dist/src-By2xYed6.js.map +1 -0
  51. package/dist/src-_qQ3RNCK.js +279 -0
  52. package/dist/src-_qQ3RNCK.js.map +1 -0
  53. package/dist/types-DSnOC4mF.js +38 -0
  54. package/dist/types-DSnOC4mF.js.map +1 -0
  55. package/package.json +10 -10
  56. package/dist/openapi-generator-Bjzmb5cn.js.map +0 -1
  57. package/dist/src-CoOAMnBh.js.map +0 -1
  58. package/dist/src-Ivjud8jD.js +0 -957
  59. package/dist/src-Ivjud8jD.js.map +0 -1
  60. /package/dist/{chunk-DSJWtz9O.js → rolldown-runtime-DSJWtz9O.js} +0 -0
@@ -0,0 +1,216 @@
1
+ import { createRequire as __createRequire } from "module";
2
+ import "process";
3
+ __createRequire(import.meta.url);
4
+ import { n as __exportAll } from "./rolldown-runtime-DSJWtz9O.js";
5
+ import "./types-DSnOC4mF.js";
6
+ //#region src/storage/GCSStorageController.ts
7
+ /**
8
+ * Google Cloud Storage controller (works with GCS and Firebase Storage)
9
+ *
10
+ * The `@google-cloud/storage` package is loaded lazily so it remains an
11
+ * optional peer dependency — users who don't need GCS never pay for the
12
+ * import cost or need it installed.
13
+ */
14
+ var GCSStorageController_exports = /* @__PURE__ */ __exportAll({ GCSStorageController: () => GCSStorageController });
15
+ var gcsModule = null;
16
+ async function loadGCS() {
17
+ if (gcsModule) return gcsModule;
18
+ try {
19
+ gcsModule = await import("@google-cloud/storage");
20
+ return gcsModule;
21
+ } catch {
22
+ throw new Error("Google Cloud Storage is required for the GCS storage controller. Install it with: pnpm add @google-cloud/storage");
23
+ }
24
+ }
25
+ /**
26
+ * Google Cloud Storage implementation of `StorageController`.
27
+ *
28
+ * Works with standard GCS buckets **and** Firebase Storage buckets
29
+ * (e.g. `"my-project.appspot.com"`).
30
+ */
31
+ var GCSStorageController = class {
32
+ config;
33
+ client = null;
34
+ constructor(config) {
35
+ this.config = config;
36
+ }
37
+ async getClient() {
38
+ if (this.client) return this.client;
39
+ const { Storage } = await loadGCS();
40
+ this.client = new Storage({
41
+ projectId: this.config.projectId,
42
+ keyFilename: this.config.keyFilename,
43
+ credentials: this.config.credentials
44
+ });
45
+ return this.client;
46
+ }
47
+ getType() {
48
+ return "gcs";
49
+ }
50
+ async putObject({ file, key, metadata, bucket }) {
51
+ this.validateFile(file);
52
+ const usedBucket = this.getBucket(bucket);
53
+ const gcsFile = (await this.getClient()).bucket(usedBucket).file(key);
54
+ const arrayBuffer = await file.arrayBuffer();
55
+ const buffer = Buffer.from(arrayBuffer);
56
+ await gcsFile.save(buffer, {
57
+ contentType: file.type,
58
+ metadata: metadata ? { metadata: this.flattenMetadata(metadata) } : void 0
59
+ });
60
+ return {
61
+ key,
62
+ bucket: usedBucket,
63
+ storageUrl: `gs://${usedBucket}/${key}`
64
+ };
65
+ }
66
+ async getSignedUrl(key, bucket) {
67
+ let resolvedPath = key;
68
+ let resolvedBucket = this.getBucket(bucket);
69
+ const match = key.match(/^(gs|s3):\/\//);
70
+ if (match) {
71
+ const protocolLength = match[0].length;
72
+ const withoutProtocol = key.substring(protocolLength);
73
+ const firstSlash = withoutProtocol.indexOf("/");
74
+ if (firstSlash > 0) {
75
+ resolvedBucket = withoutProtocol.substring(0, firstSlash);
76
+ resolvedPath = withoutProtocol.substring(firstSlash + 1);
77
+ }
78
+ }
79
+ try {
80
+ const gcsFile = (await this.getClient()).bucket(resolvedBucket).file(resolvedPath);
81
+ const [fileMetadata] = await gcsFile.getMetadata();
82
+ const expiresIn = this.config.signedUrlExpiration ?? 3600;
83
+ const [url] = await gcsFile.getSignedUrl({
84
+ action: "read",
85
+ expires: Date.now() + expiresIn * 1e3
86
+ });
87
+ return {
88
+ url,
89
+ metadata: {
90
+ bucket: resolvedBucket,
91
+ fullPath: resolvedPath,
92
+ name: resolvedPath.split("/").pop() || resolvedPath,
93
+ size: Number(fileMetadata.size) || 0,
94
+ contentType: fileMetadata.contentType || "application/octet-stream",
95
+ customMetadata: fileMetadata.metadata || {}
96
+ }
97
+ };
98
+ } catch (error) {
99
+ if (isNotFoundError(error)) return {
100
+ url: null,
101
+ fileNotFound: true
102
+ };
103
+ throw error;
104
+ }
105
+ }
106
+ async getObject(key, bucket) {
107
+ let resolvedPath = key;
108
+ let resolvedBucket = this.getBucket(bucket);
109
+ const match = key.match(/^(gs|s3):\/\//);
110
+ if (match) {
111
+ const protocolLength = match[0].length;
112
+ const withoutProtocol = key.substring(protocolLength);
113
+ const firstSlash = withoutProtocol.indexOf("/");
114
+ if (firstSlash > 0) {
115
+ resolvedBucket = withoutProtocol.substring(0, firstSlash);
116
+ resolvedPath = withoutProtocol.substring(firstSlash + 1);
117
+ }
118
+ }
119
+ try {
120
+ const gcsFile = (await this.getClient()).bucket(resolvedBucket).file(resolvedPath);
121
+ const [contents] = await gcsFile.download();
122
+ const [fileMetadata] = await gcsFile.getMetadata();
123
+ const contentType = fileMetadata.contentType || "application/octet-stream";
124
+ const fileName = resolvedPath.split("/").pop() || resolvedPath;
125
+ const blob = new Blob([new Uint8Array(contents)], { type: contentType });
126
+ return new File([blob], fileName, { type: contentType });
127
+ } catch (error) {
128
+ if (isNotFoundError(error)) return null;
129
+ throw error;
130
+ }
131
+ }
132
+ async deleteObject(key, bucket) {
133
+ let resolvedPath = key;
134
+ let resolvedBucket = this.getBucket(bucket);
135
+ const match = key.match(/^(gs|s3):\/\//);
136
+ if (match) {
137
+ const protocolLength = match[0].length;
138
+ const withoutProtocol = key.substring(protocolLength);
139
+ const firstSlash = withoutProtocol.indexOf("/");
140
+ if (firstSlash > 0) {
141
+ resolvedBucket = withoutProtocol.substring(0, firstSlash);
142
+ resolvedPath = withoutProtocol.substring(firstSlash + 1);
143
+ }
144
+ }
145
+ await (await this.getClient()).bucket(resolvedBucket).file(resolvedPath).delete({ ignoreNotFound: true });
146
+ }
147
+ async listObjects(prefix, options) {
148
+ const resolvedBucket = this.getBucket(options?.bucket);
149
+ const [files, , filesApiResponse] = await (await this.getClient()).bucket(resolvedBucket).getFiles({
150
+ prefix: prefix || void 0,
151
+ delimiter: "/",
152
+ maxResults: options?.maxResults ?? 1e3,
153
+ pageToken: options?.pageToken,
154
+ autoPaginate: false
155
+ });
156
+ return {
157
+ items: files.map((file) => ({
158
+ bucket: resolvedBucket,
159
+ fullPath: file.name,
160
+ name: file.name.split("/").pop() || "",
161
+ parent: null,
162
+ root: null,
163
+ toString: () => `gs://${resolvedBucket}/${file.name}`
164
+ })),
165
+ prefixes: (filesApiResponse?.prefixes ?? []).map((p) => ({
166
+ bucket: resolvedBucket,
167
+ fullPath: p,
168
+ name: p.replace(/\/$/, "").split("/").pop() || "",
169
+ parent: null,
170
+ root: null,
171
+ toString: () => `gs://${resolvedBucket}/${p}`
172
+ })),
173
+ nextPageToken: filesApiResponse?.nextPageToken
174
+ };
175
+ }
176
+ /**
177
+ * Validate file before upload
178
+ */
179
+ validateFile(file) {
180
+ const maxSize = this.config.maxFileSize ?? 52428800;
181
+ if (file.size > maxSize) throw new Error(`File size ${file.size} exceeds maximum allowed size ${maxSize}`);
182
+ if (this.config.allowedMimeTypes && this.config.allowedMimeTypes.length > 0) {
183
+ if (!this.config.allowedMimeTypes.includes(file.type)) throw new Error(`File type ${file.type} is not allowed. Allowed types: ${this.config.allowedMimeTypes.join(", ")}`);
184
+ }
185
+ }
186
+ /**
187
+ * Get the bucket name — either from parameter or config.
188
+ */
189
+ getBucket(bucket) {
190
+ if (!bucket || bucket === "default") return this.config.bucket;
191
+ return bucket;
192
+ }
193
+ /**
194
+ * Flatten nested metadata to string values (GCS custom metadata requirement)
195
+ */
196
+ flattenMetadata(metadata) {
197
+ const flattened = {};
198
+ for (const [key, value] of Object.entries(metadata)) if (typeof value === "string") flattened[key] = value;
199
+ else if (value !== void 0 && value !== null) flattened[key] = JSON.stringify(value);
200
+ return flattened;
201
+ }
202
+ };
203
+ /**
204
+ * Check whether an error represents a 404 / Not Found from the GCS client.
205
+ */
206
+ function isNotFoundError(error) {
207
+ if (typeof error !== "object" || error === null) return false;
208
+ const err = error;
209
+ if (err["code"] === 404) return true;
210
+ if (typeof err["message"] === "string" && /not found/i.test(err["message"])) return true;
211
+ return false;
212
+ }
213
+ //#endregion
214
+ export { GCSStorageController_exports as n, GCSStorageController as t };
215
+
216
+ //# sourceMappingURL=GCSStorageController-BEmDYFKc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GCSStorageController-BEmDYFKc.js","names":[],"sources":["../src/storage/GCSStorageController.ts"],"sourcesContent":["/**\n * Google Cloud Storage controller (works with GCS and Firebase Storage)\n *\n * The `@google-cloud/storage` package is loaded lazily so it remains an\n * optional peer dependency — users who don't need GCS never pay for the\n * import cost or need it installed.\n */\n\nimport {\n StorageController,\n GCSStorageConfig,\n DEFAULT_MAX_FILE_SIZE\n} from \"./types\";\nimport {\n UploadFileProps,\n UploadFileResult,\n DownloadConfig,\n DownloadMetadata,\n StorageListResult,\n StorageReference\n} from \"@rebasepro/types\";\n\n// ---------------------------------------------------------------------------\n// Lazy import of @google-cloud/storage\n// ---------------------------------------------------------------------------\n\nlet gcsModule: typeof import(\"@google-cloud/storage\") | null = null;\n\nasync function loadGCS(): Promise<typeof import(\"@google-cloud/storage\")> {\n if (gcsModule) return gcsModule;\n try {\n gcsModule = await import(\"@google-cloud/storage\");\n return gcsModule;\n } catch {\n throw new Error(\n \"Google Cloud Storage is required for the GCS storage controller. \" +\n \"Install it with: pnpm add @google-cloud/storage\"\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// GCSStorageController\n// ---------------------------------------------------------------------------\n\n/**\n * Google Cloud Storage implementation of `StorageController`.\n *\n * Works with standard GCS buckets **and** Firebase Storage buckets\n * (e.g. `\"my-project.appspot.com\"`).\n */\nexport class GCSStorageController implements StorageController {\n private config: GCSStorageConfig;\n private client: InstanceType<typeof import(\"@google-cloud/storage\").Storage> | null = null;\n\n constructor(config: GCSStorageConfig) {\n this.config = config;\n }\n\n // ------------------------------------------------------------------\n // Lazy client initialisation\n // ------------------------------------------------------------------\n\n private async getClient(): Promise<InstanceType<typeof import(\"@google-cloud/storage\").Storage>> {\n if (this.client) return this.client;\n const { Storage } = await loadGCS();\n this.client = new Storage({\n projectId: this.config.projectId,\n keyFilename: this.config.keyFilename,\n credentials: this.config.credentials\n });\n return this.client;\n }\n\n // ------------------------------------------------------------------\n // StorageController interface\n // ------------------------------------------------------------------\n\n getType(): \"gcs\" {\n return \"gcs\";\n }\n\n async putObject({\n file,\n key,\n metadata,\n bucket\n }: UploadFileProps): Promise<UploadFileResult> {\n this.validateFile(file);\n\n const usedBucket = this.getBucket(bucket);\n const client = await this.getClient();\n const gcsFile = client.bucket(usedBucket).file(key);\n\n // Convert File to Buffer\n const arrayBuffer = await file.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n\n await gcsFile.save(buffer, {\n contentType: file.type,\n metadata: metadata ? { metadata: this.flattenMetadata(metadata) } : undefined\n });\n\n return {\n key,\n bucket: usedBucket,\n storageUrl: `gs://${usedBucket}/${key}`\n };\n }\n\n async getSignedUrl(key: string, bucket?: string): Promise<DownloadConfig> {\n // Handle gs:// and s3:// URLs\n let resolvedPath = key;\n let resolvedBucket = this.getBucket(bucket);\n\n const match = key.match(/^(gs|s3):\\/\\//);\n if (match) {\n const protocolLength = match[0].length;\n const withoutProtocol = key.substring(protocolLength);\n const firstSlash = withoutProtocol.indexOf(\"/\");\n if (firstSlash > 0) {\n resolvedBucket = withoutProtocol.substring(0, firstSlash);\n resolvedPath = withoutProtocol.substring(firstSlash + 1);\n }\n }\n\n try {\n const client = await this.getClient();\n const gcsFile = client.bucket(resolvedBucket).file(resolvedPath);\n\n // Get metadata first to check existence and populate response\n const [fileMetadata] = await gcsFile.getMetadata();\n\n // Generate a signed URL\n const expiresIn = this.config.signedUrlExpiration ?? 3600;\n const [url] = await gcsFile.getSignedUrl({\n action: \"read\",\n expires: Date.now() + expiresIn * 1000\n });\n\n const metadata: DownloadMetadata = {\n bucket: resolvedBucket,\n fullPath: resolvedPath,\n name: resolvedPath.split(\"/\").pop() || resolvedPath,\n size: Number(fileMetadata.size) || 0,\n contentType: fileMetadata.contentType || \"application/octet-stream\",\n customMetadata: (fileMetadata.metadata as Record<string, string> | undefined) || {}\n };\n\n return {\n url,\n metadata\n };\n } catch (error: unknown) {\n if (isNotFoundError(error)) {\n return {\n url: null,\n fileNotFound: true\n };\n }\n throw error;\n }\n }\n\n async getObject(key: string, bucket?: string): Promise<File | null> {\n // Handle gs:// and s3:// URLs\n let resolvedPath = key;\n let resolvedBucket = this.getBucket(bucket);\n\n const match = key.match(/^(gs|s3):\\/\\//);\n if (match) {\n const protocolLength = match[0].length;\n const withoutProtocol = key.substring(protocolLength);\n const firstSlash = withoutProtocol.indexOf(\"/\");\n if (firstSlash > 0) {\n resolvedBucket = withoutProtocol.substring(0, firstSlash);\n resolvedPath = withoutProtocol.substring(firstSlash + 1);\n }\n }\n\n try {\n const client = await this.getClient();\n const gcsFile = client.bucket(resolvedBucket).file(resolvedPath);\n\n const [contents] = await gcsFile.download();\n\n // Get content type from metadata\n const [fileMetadata] = await gcsFile.getMetadata();\n const contentType = fileMetadata.contentType || \"application/octet-stream\";\n const fileName = resolvedPath.split(\"/\").pop() || resolvedPath;\n\n const blob = new Blob([new Uint8Array(contents)], { type: contentType });\n return new File([blob], fileName, { type: contentType });\n } catch (error: unknown) {\n if (isNotFoundError(error)) {\n return null;\n }\n throw error;\n }\n }\n\n async deleteObject(key: string, bucket?: string): Promise<void> {\n // Handle gs:// and s3:// URLs\n let resolvedPath = key;\n let resolvedBucket = this.getBucket(bucket);\n\n const match = key.match(/^(gs|s3):\\/\\//);\n if (match) {\n const protocolLength = match[0].length;\n const withoutProtocol = key.substring(protocolLength);\n const firstSlash = withoutProtocol.indexOf(\"/\");\n if (firstSlash > 0) {\n resolvedBucket = withoutProtocol.substring(0, firstSlash);\n resolvedPath = withoutProtocol.substring(firstSlash + 1);\n }\n }\n\n const client = await this.getClient();\n const gcsFile = client.bucket(resolvedBucket).file(resolvedPath);\n\n await gcsFile.delete({ ignoreNotFound: true });\n }\n\n async listObjects(prefix: string, options?: {\n bucket?: string;\n maxResults?: number;\n pageToken?: string;\n }): Promise<StorageListResult> {\n const resolvedBucket = this.getBucket(options?.bucket);\n const client = await this.getClient();\n const gcsBucket = client.bucket(resolvedBucket);\n\n // Fetch files (objects) matching the prefix\n const [files, , filesApiResponse] = await gcsBucket.getFiles({\n prefix: prefix || undefined,\n delimiter: \"/\",\n maxResults: options?.maxResults ?? 1000,\n pageToken: options?.pageToken,\n autoPaginate: false\n });\n\n const items: StorageReference[] = files.map(file => ({\n bucket: resolvedBucket,\n fullPath: file.name,\n name: file.name.split(\"/\").pop() || \"\",\n parent: null as never,\n root: null as never,\n toString: () => `gs://${resolvedBucket}/${file.name}`\n }));\n\n // Common prefixes (folder-like entries) come from the API response\n const apiPrefixes: string[] =\n (filesApiResponse as Record<string, unknown> | undefined)?.prefixes as string[] ?? [];\n\n const prefixes: StorageReference[] = apiPrefixes.map(p => ({\n bucket: resolvedBucket,\n fullPath: p,\n name: p.replace(/\\/$/, \"\").split(\"/\").pop() || \"\",\n parent: null as never,\n root: null as never,\n toString: () => `gs://${resolvedBucket}/${p}`\n }));\n\n // The next page token is returned on the query object (second element)\n const nextPageToken =\n (filesApiResponse as Record<string, unknown> | undefined)?.nextPageToken as string | undefined;\n\n return {\n items,\n prefixes,\n nextPageToken\n };\n }\n\n // ------------------------------------------------------------------\n // Private helpers\n // ------------------------------------------------------------------\n\n /**\n * Validate file before upload\n */\n private validateFile(file: File): void {\n const maxSize = this.config.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;\n if (file.size > maxSize) {\n throw new Error(`File size ${file.size} exceeds maximum allowed size ${maxSize}`);\n }\n\n if (this.config.allowedMimeTypes && this.config.allowedMimeTypes.length > 0) {\n if (!this.config.allowedMimeTypes.includes(file.type)) {\n throw new Error(`File type ${file.type} is not allowed. Allowed types: ${this.config.allowedMimeTypes.join(\", \")}`);\n }\n }\n }\n\n /**\n * Get the bucket name — either from parameter or config.\n */\n private getBucket(bucket?: string): string {\n // \"default\" is a logical bucket name used by local storage;\n // for GCS it should resolve to the configured bucket.\n if (!bucket || bucket === \"default\") return this.config.bucket;\n return bucket;\n }\n\n /**\n * Flatten nested metadata to string values (GCS custom metadata requirement)\n */\n private flattenMetadata(metadata: Record<string, unknown>): Record<string, string> {\n const flattened: Record<string, string> = {};\n for (const [key, value] of Object.entries(metadata)) {\n if (typeof value === \"string\") {\n flattened[key] = value;\n } else if (value !== undefined && value !== null) {\n flattened[key] = JSON.stringify(value);\n }\n }\n return flattened;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Check whether an error represents a 404 / Not Found from the GCS client.\n */\nfunction isNotFoundError(error: unknown): boolean {\n if (typeof error !== \"object\" || error === null) return false;\n const err = error as Record<string, unknown>;\n if (err[\"code\"] === 404) return true;\n if (typeof err[\"message\"] === \"string\" && /not found/i.test(err[\"message\"])) return true;\n return false;\n}\n"],"mappings":"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"}
@@ -0,0 +1,243 @@
1
+ import { createRequire as __createRequire } from "module";
2
+ import "process";
3
+ __createRequire(import.meta.url);
4
+ import { n as __exportAll } from "./rolldown-runtime-DSJWtz9O.js";
5
+ import "./types-DSnOC4mF.js";
6
+ //#region src/storage/S3StorageController.ts
7
+ var S3StorageController_exports = /* @__PURE__ */ __exportAll({ S3StorageController: () => S3StorageController });
8
+ var _s3Module;
9
+ var _presignerModule;
10
+ async function loadS3() {
11
+ if (!_s3Module) try {
12
+ _s3Module = await import("@aws-sdk/client-s3");
13
+ } catch {
14
+ throw new Error("@aws-sdk/client-s3 is required for S3 storage. Install it: pnpm add @aws-sdk/client-s3 @aws-sdk/s3-request-presigner");
15
+ }
16
+ return _s3Module;
17
+ }
18
+ async function loadPresigner() {
19
+ if (!_presignerModule) try {
20
+ _presignerModule = await import("@aws-sdk/s3-request-presigner");
21
+ } catch {
22
+ throw new Error("@aws-sdk/s3-request-presigner is required for S3 storage. Install it: pnpm add @aws-sdk/client-s3 @aws-sdk/s3-request-presigner");
23
+ }
24
+ return _presignerModule;
25
+ }
26
+ /**
27
+ * S3-compatible storage implementation
28
+ * Works with AWS S3 and MinIO (with forcePathStyle option)
29
+ */
30
+ var S3StorageController = class {
31
+ config;
32
+ _client;
33
+ constructor(config) {
34
+ this.config = config;
35
+ }
36
+ /**
37
+ * Lazily create and cache the S3 client on first use
38
+ */
39
+ async getClient() {
40
+ if (!this._client) {
41
+ const s3 = await loadS3();
42
+ this._client = new s3.S3Client({
43
+ region: this.config.region || "us-east-1",
44
+ endpoint: this.config.endpoint,
45
+ forcePathStyle: this.config.forcePathStyle ?? !!this.config.endpoint,
46
+ credentials: {
47
+ accessKeyId: this.config.accessKeyId,
48
+ secretAccessKey: this.config.secretAccessKey
49
+ }
50
+ });
51
+ }
52
+ return this._client;
53
+ }
54
+ getType() {
55
+ return "s3";
56
+ }
57
+ /**
58
+ * Validate file before upload
59
+ */
60
+ validateFile(file) {
61
+ const maxSize = this.config.maxFileSize ?? 52428800;
62
+ if (file.size > maxSize) throw new Error(`File size ${file.size} exceeds maximum allowed size ${maxSize}`);
63
+ if (this.config.allowedMimeTypes && this.config.allowedMimeTypes.length > 0) {
64
+ if (!this.config.allowedMimeTypes.includes(file.type)) throw new Error(`File type ${file.type} is not allowed. Allowed types: ${this.config.allowedMimeTypes.join(", ")}`);
65
+ }
66
+ }
67
+ /**
68
+ * Get the bucket name - either from parameter or config
69
+ */
70
+ getBucket(bucket) {
71
+ if (!bucket || bucket === "default") return this.config.bucket;
72
+ return bucket;
73
+ }
74
+ async putObject({ file, key, metadata, bucket }) {
75
+ this.validateFile(file);
76
+ const usedBucket = this.getBucket(bucket);
77
+ const arrayBuffer = await file.arrayBuffer();
78
+ const buffer = Buffer.from(arrayBuffer);
79
+ const s3 = await loadS3();
80
+ const client = await this.getClient();
81
+ const command = new s3.PutObjectCommand({
82
+ Bucket: usedBucket,
83
+ Key: key,
84
+ Body: buffer,
85
+ ContentType: file.type,
86
+ Metadata: metadata ? this.flattenMetadata(metadata) : void 0
87
+ });
88
+ await client.send(command);
89
+ return {
90
+ key,
91
+ bucket: usedBucket,
92
+ storageUrl: `s3://${usedBucket}/${key}`
93
+ };
94
+ }
95
+ /**
96
+ * Flatten nested metadata to string values (S3 requirement)
97
+ */
98
+ flattenMetadata(metadata) {
99
+ const flattened = {};
100
+ for (const [key, value] of Object.entries(metadata)) if (typeof value === "string") flattened[key] = value;
101
+ else if (value !== void 0 && value !== null) flattened[key] = JSON.stringify(value);
102
+ return flattened;
103
+ }
104
+ async getSignedUrl(key, bucket) {
105
+ let resolvedPath = key;
106
+ let resolvedBucket = this.getBucket(bucket);
107
+ const match = key.match(/^(s3|gs):\/\//);
108
+ if (match) {
109
+ const protocolLength = match[0].length;
110
+ const withoutProtocol = key.substring(protocolLength);
111
+ const firstSlash = withoutProtocol.indexOf("/");
112
+ if (firstSlash > 0) {
113
+ resolvedBucket = withoutProtocol.substring(0, firstSlash);
114
+ resolvedPath = withoutProtocol.substring(firstSlash + 1);
115
+ }
116
+ }
117
+ try {
118
+ const s3 = await loadS3();
119
+ const presigner = await loadPresigner();
120
+ const client = await this.getClient();
121
+ const headCommand = new s3.HeadObjectCommand({
122
+ Bucket: resolvedBucket,
123
+ Key: resolvedPath
124
+ });
125
+ const headResult = await client.send(headCommand);
126
+ const getCommand = new s3.GetObjectCommand({
127
+ Bucket: resolvedBucket,
128
+ Key: resolvedPath
129
+ });
130
+ const expiresIn = this.config.signedUrlExpiration ?? 3600;
131
+ return {
132
+ url: await presigner.getSignedUrl(client, getCommand, { expiresIn }),
133
+ metadata: {
134
+ bucket: resolvedBucket,
135
+ fullPath: resolvedPath,
136
+ name: resolvedPath.split("/").pop() || resolvedPath,
137
+ size: headResult.ContentLength || 0,
138
+ contentType: headResult.ContentType || "application/octet-stream",
139
+ customMetadata: headResult.Metadata || {}
140
+ }
141
+ };
142
+ } catch (error) {
143
+ const s3Error = error;
144
+ if (s3Error.name === "NotFound" || s3Error.$metadata?.httpStatusCode === 404) return {
145
+ url: null,
146
+ fileNotFound: true
147
+ };
148
+ throw error;
149
+ }
150
+ }
151
+ async getObject(key, bucket) {
152
+ let resolvedPath = key;
153
+ let resolvedBucket = this.getBucket(bucket);
154
+ const match = key.match(/^(s3|gs):\/\//);
155
+ if (match) {
156
+ const protocolLength = match[0].length;
157
+ const withoutProtocol = key.substring(protocolLength);
158
+ const firstSlash = withoutProtocol.indexOf("/");
159
+ if (firstSlash > 0) {
160
+ resolvedBucket = withoutProtocol.substring(0, firstSlash);
161
+ resolvedPath = withoutProtocol.substring(firstSlash + 1);
162
+ }
163
+ }
164
+ try {
165
+ const s3 = await loadS3();
166
+ const client = await this.getClient();
167
+ const command = new s3.GetObjectCommand({
168
+ Bucket: resolvedBucket,
169
+ Key: resolvedPath
170
+ });
171
+ const response = await client.send(command);
172
+ if (!response.Body) return null;
173
+ const chunks = [];
174
+ for await (const chunk of response.Body) chunks.push(chunk);
175
+ const buffer = Buffer.concat(chunks);
176
+ const contentType = response.ContentType || "application/octet-stream";
177
+ const fileName = resolvedPath.split("/").pop() || resolvedPath;
178
+ const blob = new Blob([buffer], { type: contentType });
179
+ return new File([blob], fileName, { type: contentType });
180
+ } catch (error) {
181
+ const s3Error = error;
182
+ if (s3Error.name === "NoSuchKey" || s3Error.$metadata?.httpStatusCode === 404) return null;
183
+ throw error;
184
+ }
185
+ }
186
+ async deleteObject(key, bucket) {
187
+ let resolvedPath = key;
188
+ let resolvedBucket = this.getBucket(bucket);
189
+ const match = key.match(/^(s3|gs):\/\//);
190
+ if (match) {
191
+ const protocolLength = match[0].length;
192
+ const withoutProtocol = key.substring(protocolLength);
193
+ const firstSlash = withoutProtocol.indexOf("/");
194
+ if (firstSlash > 0) {
195
+ resolvedBucket = withoutProtocol.substring(0, firstSlash);
196
+ resolvedPath = withoutProtocol.substring(firstSlash + 1);
197
+ }
198
+ }
199
+ const s3 = await loadS3();
200
+ const client = await this.getClient();
201
+ const command = new s3.DeleteObjectCommand({
202
+ Bucket: resolvedBucket,
203
+ Key: resolvedPath
204
+ });
205
+ await client.send(command);
206
+ }
207
+ async listObjects(prefix, options) {
208
+ const resolvedBucket = this.getBucket(options?.bucket);
209
+ const s3 = await loadS3();
210
+ const client = await this.getClient();
211
+ const command = new s3.ListObjectsV2Command({
212
+ Bucket: resolvedBucket,
213
+ Prefix: prefix || void 0,
214
+ MaxKeys: options?.maxResults ?? 1e3,
215
+ ContinuationToken: options?.pageToken,
216
+ Delimiter: "/"
217
+ });
218
+ const response = await client.send(command);
219
+ return {
220
+ items: (response.Contents || []).map((obj) => ({
221
+ bucket: resolvedBucket,
222
+ fullPath: obj.Key || "",
223
+ name: (obj.Key || "").split("/").pop() || "",
224
+ parent: null,
225
+ root: null,
226
+ toString: () => `s3://${resolvedBucket}/${obj.Key}`
227
+ })),
228
+ prefixes: (response.CommonPrefixes || []).map((prefix) => ({
229
+ bucket: resolvedBucket,
230
+ fullPath: prefix.Prefix || "",
231
+ name: (prefix.Prefix || "").replace(/\/$/, "").split("/").pop() || "",
232
+ parent: null,
233
+ root: null,
234
+ toString: () => `s3://${resolvedBucket}/${prefix.Prefix}`
235
+ })),
236
+ nextPageToken: response.NextContinuationToken
237
+ };
238
+ }
239
+ };
240
+ //#endregion
241
+ export { S3StorageController_exports as n, S3StorageController as t };
242
+
243
+ //# sourceMappingURL=S3StorageController-CK7r5yZb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"S3StorageController-CK7r5yZb.js","names":[],"sources":["../src/storage/S3StorageController.ts"],"sourcesContent":["/**\n * S3-compatible storage controller (works with AWS S3 and MinIO)\n */\n\nimport type { S3Client as S3ClientType, } from \"@aws-sdk/client-s3\";\nimport { DEFAULT_MAX_FILE_SIZE, S3StorageConfig, StorageController } from \"./types\";\nimport {\n DownloadConfig,\n DownloadMetadata,\n StorageListResult,\n StorageReference,\n UploadFileProps,\n UploadFileResult\n} from \"@rebasepro/types\";\n\nlet _s3Module: typeof import(\"@aws-sdk/client-s3\") | undefined;\nlet _presignerModule: typeof import(\"@aws-sdk/s3-request-presigner\") | undefined;\n\nasync function loadS3() {\n if (!_s3Module) {\n try {\n _s3Module = await import(\"@aws-sdk/client-s3\");\n } catch {\n throw new Error(\n \"@aws-sdk/client-s3 is required for S3 storage. \" +\n \"Install it: pnpm add @aws-sdk/client-s3 @aws-sdk/s3-request-presigner\"\n );\n }\n }\n return _s3Module;\n}\n\nasync function loadPresigner() {\n if (!_presignerModule) {\n try {\n _presignerModule = await import(\"@aws-sdk/s3-request-presigner\");\n } catch {\n throw new Error(\n \"@aws-sdk/s3-request-presigner is required for S3 storage. \" +\n \"Install it: pnpm add @aws-sdk/client-s3 @aws-sdk/s3-request-presigner\"\n );\n }\n }\n return _presignerModule;\n}\n\n/**\n * S3-compatible storage implementation\n * Works with AWS S3 and MinIO (with forcePathStyle option)\n */\nexport class S3StorageController implements StorageController {\n private config: S3StorageConfig;\n private _client: S3ClientType | undefined;\n\n constructor(config: S3StorageConfig) {\n this.config = config;\n }\n\n /**\n * Lazily create and cache the S3 client on first use\n */\n private async getClient(): Promise<S3ClientType> {\n if (!this._client) {\n const s3 = await loadS3();\n this._client = new s3.S3Client({\n region: this.config.region || \"us-east-1\",\n endpoint: this.config.endpoint,\n forcePathStyle: this.config.forcePathStyle ?? !!this.config.endpoint, // Auto-enable for custom endpoints (MinIO)\n credentials: {\n accessKeyId: this.config.accessKeyId,\n secretAccessKey: this.config.secretAccessKey\n }\n });\n }\n return this._client;\n }\n\n getType(): \"s3\" {\n return \"s3\";\n }\n\n /**\n * Validate file before upload\n */\n private validateFile(file: File): void {\n const maxSize = this.config.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;\n if (file.size > maxSize) {\n throw new Error(`File size ${file.size} exceeds maximum allowed size ${maxSize}`);\n }\n\n if (this.config.allowedMimeTypes && this.config.allowedMimeTypes.length > 0) {\n if (!this.config.allowedMimeTypes.includes(file.type)) {\n throw new Error(`File type ${file.type} is not allowed. Allowed types: ${this.config.allowedMimeTypes.join(\", \")}`);\n }\n }\n }\n\n /**\n * Get the bucket name - either from parameter or config\n */\n private getBucket(bucket?: string): string {\n // \"default\" is a logical bucket name used by local storage;\n // for S3 it should resolve to the configured bucket.\n if (!bucket || bucket === \"default\") return this.config.bucket;\n return bucket;\n }\n\n async putObject({\n file,\n key,\n metadata,\n bucket\n }: UploadFileProps): Promise<UploadFileResult> {\n this.validateFile(file);\n\n const usedBucket = this.getBucket(bucket);\n\n // Convert File to Buffer\n const arrayBuffer = await file.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n\n const s3 = await loadS3();\n const client = await this.getClient();\n\n const command = new s3.PutObjectCommand({\n Bucket: usedBucket,\n Key: key,\n Body: buffer,\n ContentType: file.type,\n Metadata: metadata ? this.flattenMetadata(metadata) : undefined\n });\n\n await client.send(command);\n\n return {\n key,\n bucket: usedBucket,\n storageUrl: `s3://${usedBucket}/${key}`\n };\n }\n\n /**\n * Flatten nested metadata to string values (S3 requirement)\n */\n private flattenMetadata(metadata: Record<string, unknown>): Record<string, string> {\n const flattened: Record<string, string> = {};\n for (const [key, value] of Object.entries(metadata)) {\n if (typeof value === \"string\") {\n flattened[key] = value;\n } else if (value !== undefined && value !== null) {\n flattened[key] = JSON.stringify(value);\n }\n }\n return flattened;\n }\n\n async getSignedUrl(key: string, bucket?: string): Promise<DownloadConfig> {\n // Handle s3:// and gs:// URLs for backward compatibility\n let resolvedPath = key;\n let resolvedBucket = this.getBucket(bucket);\n\n const match = key.match(/^(s3|gs):\\/\\//);\n if (match) {\n const protocolLength = match[0].length;\n const withoutProtocol = key.substring(protocolLength);\n const firstSlash = withoutProtocol.indexOf(\"/\");\n if (firstSlash > 0) {\n resolvedBucket = withoutProtocol.substring(0, firstSlash);\n resolvedPath = withoutProtocol.substring(firstSlash + 1);\n }\n }\n\n try {\n const s3 = await loadS3();\n const presigner = await loadPresigner();\n const client = await this.getClient();\n\n // First check if the object exists and get metadata\n const headCommand = new s3.HeadObjectCommand({\n Bucket: resolvedBucket,\n Key: resolvedPath\n });\n\n const headResult = await client.send(headCommand);\n\n // Generate a signed URL\n const getCommand = new s3.GetObjectCommand({\n Bucket: resolvedBucket,\n Key: resolvedPath\n });\n\n const expiresIn = this.config.signedUrlExpiration ?? 3600;\n const url = await presigner.getSignedUrl(client, getCommand, { expiresIn });\n\n const metadata: DownloadMetadata = {\n bucket: resolvedBucket,\n fullPath: resolvedPath,\n name: resolvedPath.split(\"/\").pop() || resolvedPath,\n size: headResult.ContentLength || 0,\n contentType: headResult.ContentType || \"application/octet-stream\",\n customMetadata: headResult.Metadata || {}\n };\n\n return {\n url,\n metadata\n };\n } catch (error: unknown) {\n const s3Error = error as { name?: string; $metadata?: { httpStatusCode?: number } };\n if (s3Error.name === \"NotFound\" || s3Error.$metadata?.httpStatusCode === 404) {\n return {\n url: null,\n fileNotFound: true\n };\n }\n throw error;\n }\n }\n\n async getObject(key: string, bucket?: string): Promise<File | null> {\n // Handle s3:// and gs:// URLs\n let resolvedPath = key;\n let resolvedBucket = this.getBucket(bucket);\n\n const match = key.match(/^(s3|gs):\\/\\//);\n if (match) {\n const protocolLength = match[0].length;\n const withoutProtocol = key.substring(protocolLength);\n const firstSlash = withoutProtocol.indexOf(\"/\");\n if (firstSlash > 0) {\n resolvedBucket = withoutProtocol.substring(0, firstSlash);\n resolvedPath = withoutProtocol.substring(firstSlash + 1);\n }\n }\n\n try {\n const s3 = await loadS3();\n const client = await this.getClient();\n\n const command = new s3.GetObjectCommand({\n Bucket: resolvedBucket,\n Key: resolvedPath\n });\n\n const response = await client.send(command);\n\n if (!response.Body) {\n return null;\n }\n\n // Convert stream to buffer\n const chunks: Uint8Array[] = [];\n for await (const chunk of response.Body as AsyncIterable<Uint8Array>) {\n chunks.push(chunk);\n }\n const buffer = Buffer.concat(chunks);\n\n const contentType = response.ContentType || \"application/octet-stream\";\n const fileName = resolvedPath.split(\"/\").pop() || resolvedPath;\n\n const blob = new Blob([buffer], { type: contentType });\n return new File([blob], fileName, { type: contentType });\n } catch (error: unknown) {\n const s3Error = error as { name?: string; $metadata?: { httpStatusCode?: number } };\n if (s3Error.name === \"NoSuchKey\" || s3Error.$metadata?.httpStatusCode === 404) {\n return null;\n }\n throw error;\n }\n }\n\n async deleteObject(key: string, bucket?: string): Promise<void> {\n // Handle s3:// and gs:// URLs\n let resolvedPath = key;\n let resolvedBucket = this.getBucket(bucket);\n\n const match = key.match(/^(s3|gs):\\/\\//);\n if (match) {\n const protocolLength = match[0].length;\n const withoutProtocol = key.substring(protocolLength);\n const firstSlash = withoutProtocol.indexOf(\"/\");\n if (firstSlash > 0) {\n resolvedBucket = withoutProtocol.substring(0, firstSlash);\n resolvedPath = withoutProtocol.substring(firstSlash + 1);\n }\n }\n\n const s3 = await loadS3();\n const client = await this.getClient();\n\n const command = new s3.DeleteObjectCommand({\n Bucket: resolvedBucket,\n Key: resolvedPath\n });\n\n await client.send(command);\n }\n\n async listObjects(prefix: string, options?: {\n bucket?: string;\n maxResults?: number;\n pageToken?: string;\n }): Promise<StorageListResult> {\n const resolvedBucket = this.getBucket(options?.bucket);\n\n const s3 = await loadS3();\n const client = await this.getClient();\n\n const command = new s3.ListObjectsV2Command({\n Bucket: resolvedBucket,\n Prefix: prefix || undefined,\n MaxKeys: options?.maxResults ?? 1000,\n ContinuationToken: options?.pageToken,\n Delimiter: \"/\" // This gives us folder-like behavior\n });\n\n const response = await client.send(command);\n\n const items: StorageReference[] = (response.Contents || []).map(obj => ({\n bucket: resolvedBucket,\n fullPath: obj.Key || \"\",\n name: (obj.Key || \"\").split(\"/\").pop() || \"\",\n parent: null as never,\n root: null as never,\n toString: () => `s3://${resolvedBucket}/${obj.Key}`\n }));\n\n const prefixes: StorageReference[] = (response.CommonPrefixes || []).map(prefix => ({\n bucket: resolvedBucket,\n fullPath: prefix.Prefix || \"\",\n name: (prefix.Prefix || \"\").replace(/\\/$/, \"\").split(\"/\").pop() || \"\",\n parent: null as never,\n root: null as never,\n toString: () => `s3://${resolvedBucket}/${prefix.Prefix}`\n }));\n\n return {\n items,\n prefixes,\n nextPageToken: response.NextContinuationToken\n };\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,123 @@
1
+ import { createRequire as __createRequire } from "module";
2
+ import "process";
3
+ __createRequire(import.meta.url);
4
+ //#region ../types/src/types/admin_block.ts
5
+ /**
6
+ * The keys of a collection's admin block, as data.
7
+ *
8
+ * There is no *type* for the block in this package any more, and that is the point:
9
+ * `admin` is not declared on `BaseCollectionConfig` or on any property here, so a
10
+ * BaaS install cannot even write one. `@rebasepro/admin-types` adds the field back by
11
+ * declaration merging, which is why installing it is what makes the admin surface
12
+ * appear.
13
+ *
14
+ * The *list* still has to live here, because three runtime consumers need it and two
15
+ * of them are core — see below.
16
+ */
17
+ /**
18
+ * Every key that belongs inside a collection's `admin` block, as data.
19
+ *
20
+ * The type that describes these fields is `AdminCollectionOptions` in
21
+ * `@rebasepro/admin-types`, and it is erased at build time — but three runtime
22
+ * consumers need the list, and two of them are core:
23
+ *
24
+ * - `serializeCollections`, to drop the block from the contract
25
+ * - the ts-morph schema editor in `@rebasepro/server`, which rewrites collection
26
+ * files on disk from the admin panel and has to know where each key goes. A key
27
+ * missing from this list gets written to the *top level* of the file, where the
28
+ * backend ignores it and the panel never finds it again.
29
+ * - the `collections-admin-block` codemod
30
+ *
31
+ * `@rebasepro/admin-types` re-exports this and asserts it names only real option
32
+ * keys; the count is pinned by a test there.
33
+ *
34
+ * @group Models
35
+ */
36
+ var ADMIN_COLLECTION_KEYS = [
37
+ "Actions",
38
+ "additionalFields",
39
+ "alwaysApplyDefaultValues",
40
+ "components",
41
+ "defaultEntityAction",
42
+ "defaultFilter",
43
+ "defaultSelectedView",
44
+ "defaultSize",
45
+ "defaultViewMode",
46
+ "disableDefaultActions",
47
+ "enabledViews",
48
+ "entityActions",
49
+ "entityViews",
50
+ "exportable",
51
+ "filterPresets",
52
+ "fixedFilter",
53
+ "formAutoSave",
54
+ "formView",
55
+ "group",
56
+ "hideFromNavigation",
57
+ "hideIdFromCollection",
58
+ "hideIdFromForm",
59
+ "icon",
60
+ "includeJsonView",
61
+ "inlineEditing",
62
+ "kanban",
63
+ "listProperties",
64
+ "localChangesBackup",
65
+ "openEntityMode",
66
+ "orderProperty",
67
+ "pagination",
68
+ "previewProperties",
69
+ "propertiesOrder",
70
+ "selectionController",
71
+ "selectionEnabled",
72
+ "sideDialogWidth",
73
+ "sort",
74
+ "titleProperty"
75
+ ];
76
+ /**
77
+ * Every key that belongs inside a *property's* `admin` block, as data.
78
+ *
79
+ * The union of `AdminPropertyOptions` and its per-type extensions
80
+ * (`AdminStringOptions`, `AdminArrayOptions`, …) in `@rebasepro/admin-types`.
81
+ * It lives here for the same reason {@link ADMIN_COLLECTION_KEYS} does: the
82
+ * runtime consumers are core packages that the BaaS guard forbids from
83
+ * importing `@rebasepro/admin-types`. Here it is the boot-time collection
84
+ * validator in `@rebasepro/server`, which has to tell "you left `readOnly` at
85
+ * the top of the property, where nothing reads it" apart from "you invented a
86
+ * key we have never heard of".
87
+ *
88
+ * `@rebasepro/admin-types` re-exports this and asserts it names only real
89
+ * option keys.
90
+ *
91
+ * @group Models
92
+ */
93
+ var ADMIN_PROPERTY_KEYS = [
94
+ "canAddElements",
95
+ "clearable",
96
+ "columnWidth",
97
+ "customProps",
98
+ "disabled",
99
+ "expanded",
100
+ "Field",
101
+ "Filter",
102
+ "filterOperators",
103
+ "fixedFilter",
104
+ "hideFromCollection",
105
+ "includeEntityLink",
106
+ "includeId",
107
+ "markdown",
108
+ "minimalistView",
109
+ "multiline",
110
+ "Preview",
111
+ "previewAsTag",
112
+ "previewProperties",
113
+ "readOnly",
114
+ "sortable",
115
+ "spreadChildren",
116
+ "urlPreview",
117
+ "widget",
118
+ "widthPercentage"
119
+ ];
120
+ //#endregion
121
+ export { ADMIN_PROPERTY_KEYS as n, ADMIN_COLLECTION_KEYS as t };
122
+
123
+ //# sourceMappingURL=admin_block-BGQFSAuV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin_block-BGQFSAuV.js","names":[],"sources":["../../types/src/types/admin_block.ts"],"sourcesContent":["/**\n * The keys of a collection's admin block, as data.\n *\n * There is no *type* for the block in this package any more, and that is the point:\n * `admin` is not declared on `BaseCollectionConfig` or on any property here, so a\n * BaaS install cannot even write one. `@rebasepro/admin-types` adds the field back by\n * declaration merging, which is why installing it is what makes the admin surface\n * appear.\n *\n * The *list* still has to live here, because three runtime consumers need it and two\n * of them are core — see below.\n */\n\n/**\n * Every key that belongs inside a collection's `admin` block, as data.\n *\n * The type that describes these fields is `AdminCollectionOptions` in\n * `@rebasepro/admin-types`, and it is erased at build time — but three runtime\n * consumers need the list, and two of them are core:\n *\n * - `serializeCollections`, to drop the block from the contract\n * - the ts-morph schema editor in `@rebasepro/server`, which rewrites collection\n * files on disk from the admin panel and has to know where each key goes. A key\n * missing from this list gets written to the *top level* of the file, where the\n * backend ignores it and the panel never finds it again.\n * - the `collections-admin-block` codemod\n *\n * `@rebasepro/admin-types` re-exports this and asserts it names only real option\n * keys; the count is pinned by a test there.\n *\n * @group Models\n */\nexport const ADMIN_COLLECTION_KEYS = [\n \"Actions\",\n \"additionalFields\",\n \"alwaysApplyDefaultValues\",\n \"components\",\n \"defaultEntityAction\",\n \"defaultFilter\",\n \"defaultSelectedView\",\n \"defaultSize\",\n \"defaultViewMode\",\n \"disableDefaultActions\",\n \"enabledViews\",\n \"entityActions\",\n \"entityViews\",\n \"exportable\",\n \"filterPresets\",\n \"fixedFilter\",\n \"formAutoSave\",\n \"formView\",\n \"group\",\n \"hideFromNavigation\",\n \"hideIdFromCollection\",\n \"hideIdFromForm\",\n \"icon\",\n \"includeJsonView\",\n \"inlineEditing\",\n \"kanban\",\n \"listProperties\",\n \"localChangesBackup\",\n \"openEntityMode\",\n \"orderProperty\",\n \"pagination\",\n \"previewProperties\",\n \"propertiesOrder\",\n \"selectionController\",\n \"selectionEnabled\",\n \"sideDialogWidth\",\n \"sort\",\n \"titleProperty\"\n] as const;\n\n/** A key of a collection's `admin` block. @group Models */\nexport type AdminCollectionKey = typeof ADMIN_COLLECTION_KEYS[number];\n\n/**\n * Every key that belongs inside a *property's* `admin` block, as data.\n *\n * The union of `AdminPropertyOptions` and its per-type extensions\n * (`AdminStringOptions`, `AdminArrayOptions`, …) in `@rebasepro/admin-types`.\n * It lives here for the same reason {@link ADMIN_COLLECTION_KEYS} does: the\n * runtime consumers are core packages that the BaaS guard forbids from\n * importing `@rebasepro/admin-types`. Here it is the boot-time collection\n * validator in `@rebasepro/server`, which has to tell \"you left `readOnly` at\n * the top of the property, where nothing reads it\" apart from \"you invented a\n * key we have never heard of\".\n *\n * `@rebasepro/admin-types` re-exports this and asserts it names only real\n * option keys.\n *\n * @group Models\n */\nexport const ADMIN_PROPERTY_KEYS = [\n \"canAddElements\",\n \"clearable\",\n \"columnWidth\",\n \"customProps\",\n \"disabled\",\n \"expanded\",\n \"Field\",\n \"Filter\",\n \"filterOperators\",\n \"fixedFilter\",\n \"hideFromCollection\",\n \"includeEntityLink\",\n \"includeId\",\n \"markdown\",\n \"minimalistView\",\n \"multiline\",\n \"Preview\",\n \"previewAsTag\",\n \"previewProperties\",\n \"readOnly\",\n \"sortable\",\n \"spreadChildren\",\n \"urlPreview\",\n \"widget\",\n \"widthPercentage\"\n] as const;\n\n/** A key of a property's `admin` block. @group Models */\nexport type AdminPropertyKey = typeof ADMIN_PROPERTY_KEYS[number];\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,IAAa,wBAAwB;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACJ;;;;;;;;;;;;;;;;;;AAsBA,IAAa,sBAAsB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACJ"}