@palbase/backend 8.1.0 → 8.2.0

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.cts CHANGED
@@ -714,20 +714,18 @@ type ParameterDecorator$1 = (target: object, propertyKey: string | symbol, param
714
714
  * — the client cannot exceed what it declared.
715
715
  */
716
716
  interface UploadConfig {
717
- /** Target bucket NAME. MUST exist in `config/storage.ts` `defineStorage(...)`. */
718
- bucket: string;
719
- /**
720
- * Max object size in BYTES. Enforced twice: the authorize pre-flight rejects a
721
- * larger declared size, and the signed URL pins it so storage rejects a larger
722
- * PUT. When omitted, the bucket's own `fileSizeLimit` applies.
723
- */
724
- maxSize?: number;
725
717
  /**
726
- * MIME allowlist for the object. The authorize pre-flight rejects a
727
- * non-matching declared content-type, and the signed URL pins the exact type.
728
- * When omitted, the bucket's own `allowedMimeTypes` applies (or any type).
718
+ * Target bucket NAME. MUST exist in `config/storage.ts` `defineStorage(...)`.
719
+ *
720
+ * The bucket is the SINGLE SOURCE OF TRUTH for the size limit + MIME allowlist:
721
+ * `bucket({ fileSizeLimit, allowedMimeTypes })`. Storage enforces those at the
722
+ * actual PUT (the only guard a client cannot skip), so `@Upload` deliberately
723
+ * does NOT take its own `maxSize`/`allowedTypes` — duplicating them here would
724
+ * let a route declare a tighter limit than its bucket that storage would not
725
+ * enforce (a real bypass: declare 10 bytes at authorize, then PUT up to the
726
+ * bucket ceiling straight at the signed URL). One bucket, one limit, enforced.
729
727
  */
730
- allowedTypes?: string[];
728
+ bucket: string;
731
729
  /**
732
730
  * SERVER-side object key template. The client NEVER chooses the path. Tokens:
733
731
  * `{userId}` (authenticated user id), `{uploadId}` (server-minted), and
@@ -742,9 +740,10 @@ interface UploadConfig {
742
740
  * guard + signed-URL pinning.
743
741
  *
744
742
  * @example
745
- * @Upload("/", { bucket: "docs", maxSize: 25 * 1024 * 1024,
746
- * allowedTypes: ["application/pdf"], pathTemplate: "{userId}/{uploadId}-{filename}" })
743
+ * @Upload("/", { bucket: "docs", pathTemplate: "{userId}/{uploadId}-{filename}" })
747
744
  * async upload(@UploadedObject() obj: UploadedObject, @User() user): Promise<DocResult> { ... }
745
+ * // The size limit + MIME allowlist come from the "docs" bucket in
746
+ * // config/storage.ts — storage enforces them at the PUT.
748
747
  */
749
748
  declare function Upload(subpath: string, config: UploadConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator$1;
750
749
  /**
@@ -777,10 +776,13 @@ interface UploadedObject {
777
776
  declare function UploadedObject(): ParameterDecorator$1;
778
777
  /**
779
778
  * Cross-check one `@Upload` route's uploadConfig against the project's
780
- * {@link StorageConfig}: the bucket must exist, the upload's `maxSize` must not
781
- * exceed the bucket's `fileSizeLimit`, and the upload's `allowedTypes` must be a
782
- * subset of the bucket's `allowedMimeTypes`. Throws a precise error so a
783
- * mismatch fails at deploy, not at the first user upload.
779
+ * {@link StorageConfig}: the named bucket MUST exist in `defineStorage(...)`.
780
+ * Throws a precise error so a typo fails at deploy, not at the first user upload.
781
+ *
782
+ * That is the ONLY cross-check: the size limit + MIME allowlist live on the
783
+ * bucket (`bucket({ fileSizeLimit, allowedMimeTypes })`) and are enforced by
784
+ * storage at the PUT. `@Upload` carries no `maxSize`/`allowedTypes` of its own,
785
+ * so there is nothing to compare — one bucket, one limit, no drift.
784
786
  *
785
787
  * `routeLabel` is used only for error messages (e.g. `docs.upload`).
786
788
  */
package/dist/index.d.ts CHANGED
@@ -714,20 +714,18 @@ type ParameterDecorator$1 = (target: object, propertyKey: string | symbol, param
714
714
  * — the client cannot exceed what it declared.
715
715
  */
716
716
  interface UploadConfig {
717
- /** Target bucket NAME. MUST exist in `config/storage.ts` `defineStorage(...)`. */
718
- bucket: string;
719
- /**
720
- * Max object size in BYTES. Enforced twice: the authorize pre-flight rejects a
721
- * larger declared size, and the signed URL pins it so storage rejects a larger
722
- * PUT. When omitted, the bucket's own `fileSizeLimit` applies.
723
- */
724
- maxSize?: number;
725
717
  /**
726
- * MIME allowlist for the object. The authorize pre-flight rejects a
727
- * non-matching declared content-type, and the signed URL pins the exact type.
728
- * When omitted, the bucket's own `allowedMimeTypes` applies (or any type).
718
+ * Target bucket NAME. MUST exist in `config/storage.ts` `defineStorage(...)`.
719
+ *
720
+ * The bucket is the SINGLE SOURCE OF TRUTH for the size limit + MIME allowlist:
721
+ * `bucket({ fileSizeLimit, allowedMimeTypes })`. Storage enforces those at the
722
+ * actual PUT (the only guard a client cannot skip), so `@Upload` deliberately
723
+ * does NOT take its own `maxSize`/`allowedTypes` — duplicating them here would
724
+ * let a route declare a tighter limit than its bucket that storage would not
725
+ * enforce (a real bypass: declare 10 bytes at authorize, then PUT up to the
726
+ * bucket ceiling straight at the signed URL). One bucket, one limit, enforced.
729
727
  */
730
- allowedTypes?: string[];
728
+ bucket: string;
731
729
  /**
732
730
  * SERVER-side object key template. The client NEVER chooses the path. Tokens:
733
731
  * `{userId}` (authenticated user id), `{uploadId}` (server-minted), and
@@ -742,9 +740,10 @@ interface UploadConfig {
742
740
  * guard + signed-URL pinning.
743
741
  *
744
742
  * @example
745
- * @Upload("/", { bucket: "docs", maxSize: 25 * 1024 * 1024,
746
- * allowedTypes: ["application/pdf"], pathTemplate: "{userId}/{uploadId}-{filename}" })
743
+ * @Upload("/", { bucket: "docs", pathTemplate: "{userId}/{uploadId}-{filename}" })
747
744
  * async upload(@UploadedObject() obj: UploadedObject, @User() user): Promise<DocResult> { ... }
745
+ * // The size limit + MIME allowlist come from the "docs" bucket in
746
+ * // config/storage.ts — storage enforces them at the PUT.
748
747
  */
749
748
  declare function Upload(subpath: string, config: UploadConfig & Pick<RouteOptions, "auth" | "rateLimit">): MethodDecorator$1;
750
749
  /**
@@ -777,10 +776,13 @@ interface UploadedObject {
777
776
  declare function UploadedObject(): ParameterDecorator$1;
778
777
  /**
779
778
  * Cross-check one `@Upload` route's uploadConfig against the project's
780
- * {@link StorageConfig}: the bucket must exist, the upload's `maxSize` must not
781
- * exceed the bucket's `fileSizeLimit`, and the upload's `allowedTypes` must be a
782
- * subset of the bucket's `allowedMimeTypes`. Throws a precise error so a
783
- * mismatch fails at deploy, not at the first user upload.
779
+ * {@link StorageConfig}: the named bucket MUST exist in `defineStorage(...)`.
780
+ * Throws a precise error so a typo fails at deploy, not at the first user upload.
781
+ *
782
+ * That is the ONLY cross-check: the size limit + MIME allowlist live on the
783
+ * bucket (`bucket({ fileSizeLimit, allowedMimeTypes })`) and are enforced by
784
+ * storage at the PUT. `@Upload` carries no `maxSize`/`allowedTypes` of its own,
785
+ * so there is nothing to compare — one bucket, one limit, no drift.
784
786
  *
785
787
  * `routeLabel` is used only for error messages (e.g. `docs.upload`).
786
788
  */
package/dist/index.js CHANGED
@@ -476,7 +476,6 @@ var Patch = makeMethodDecorator("PATCH");
476
476
  var Delete = makeMethodDecorator("DELETE");
477
477
 
478
478
  // src/decorators/upload.ts
479
- var MIME_RE2 = /^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*\/[A-Za-z0-9*][A-Za-z0-9!#$&^_.+-]*$/;
480
479
  function Upload(subpath, config) {
481
480
  const { auth: auth2, rateLimit, ...uploadConfig } = config;
482
481
  validateUploadConfigShape(uploadConfig);
@@ -507,21 +506,6 @@ function validateUploadConfigShape(c) {
507
506
  if (typeof c.pathTemplate !== "string" || c.pathTemplate.length === 0) {
508
507
  throw new Error("@Upload config.pathTemplate must be a non-empty key template");
509
508
  }
510
- if (c.maxSize !== void 0) {
511
- if (!Number.isInteger(c.maxSize) || c.maxSize <= 0) {
512
- throw new Error(`@Upload config.maxSize must be a positive integer byte count, got ${c.maxSize}`);
513
- }
514
- }
515
- if (c.allowedTypes !== void 0) {
516
- if (!Array.isArray(c.allowedTypes) || c.allowedTypes.length === 0) {
517
- throw new Error("@Upload config.allowedTypes must be a non-empty array of MIME types when present");
518
- }
519
- for (const t of c.allowedTypes) {
520
- if (typeof t !== "string" || !MIME_RE2.test(t.trim())) {
521
- throw new Error(`@Upload config.allowedTypes entry "${t}" is not a valid MIME type (e.g. "image/png")`);
522
- }
523
- }
524
- }
525
509
  }
526
510
  function validateUploadAgainstStorage(uploadConfig, storage2, routeLabel) {
527
511
  const def = storage2.buckets[uploadConfig.bucket];
@@ -531,28 +515,6 @@ function validateUploadAgainstStorage(uploadConfig, storage2, routeLabel) {
531
515
  `@Upload route ${routeLabel} targets bucket "${uploadConfig.bucket}" which is not declared in defineStorage(...). ` + (known.length ? `Known buckets: ${known.join(", ")}.` : "No buckets are declared.")
532
516
  );
533
517
  }
534
- if (uploadConfig.maxSize !== void 0 && def.fileSizeLimit !== null && uploadConfig.maxSize > def.fileSizeLimit) {
535
- throw new Error(
536
- `@Upload route ${routeLabel} maxSize (${uploadConfig.maxSize} bytes) exceeds bucket "${uploadConfig.bucket}" fileSizeLimit (${def.fileSizeLimit} bytes)`
537
- );
538
- }
539
- if (uploadConfig.allowedTypes !== void 0 && def.allowedMimeTypes !== null) {
540
- const bucketAllows = (mime) => def.allowedMimeTypes.some((b) => {
541
- if (b === mime) return true;
542
- const slash = b.indexOf("/");
543
- if (slash > 0 && b.slice(slash + 1) === "*") {
544
- return mime.startsWith(b.slice(0, slash + 1));
545
- }
546
- return false;
547
- });
548
- for (const t of uploadConfig.allowedTypes) {
549
- if (!bucketAllows(t)) {
550
- throw new Error(
551
- `@Upload route ${routeLabel} allows MIME "${t}" which bucket "${uploadConfig.bucket}" does not (bucket allows: ${def.allowedMimeTypes.join(", ")})`
552
- );
553
- }
554
- }
555
- }
556
518
  }
557
519
 
558
520
  // src/decorators/params.ts