zerobucket 0.8.2 → 0.9.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/README.md CHANGED
@@ -123,11 +123,13 @@ await images.get(id, { context: { userId } }); // throws AccessDeniedError if th
123
123
  **A hook that throws fails closed**: the original exception propagates; it is never treated as
124
124
  "allow". Denied calls never reach the database. `exists()` is deliberately not gated.
125
125
 
126
- **Your hook receives the id exactly as the caller supplied it**, before ZeroBucket validates it, so it can be a
127
- malformed string such as one taken straight from a URL. Check the format before using it in SQL (for example against a
128
- UUID pattern, returning `true` for a malformed id so ZeroBucket answers "not found"); otherwise a request for
129
- `/images/garbage` becomes a database error and a `500`. The [example app](https://github.com/KedarGhadyalji/ZeroBucket/tree/main/examples/node-integration)
130
- shows a working hook, plus transactional uploads and serving.
126
+ **Your hook only ever sees a well-formed UUID.** A malformed id (such as one taken straight from a URL) can never
127
+ exist, so it is "not found" (`ImageNotFoundError`, or `error: "not found"` for that item in `getMany`) and your hook is
128
+ never called with it. You can use the id in SQL (`WHERE id = $1` on a `uuid` column) without validating it first. _(Before
129
+ 0.9.0 the hook received the raw string, so on 0.8.x guard against a malformed id yourself: a request for
130
+ `/images/garbage` otherwise became a database error and a `500`.)_ The
131
+ [example app](https://github.com/KedarGhadyalji/ZeroBucket/tree/main/examples/node-integration) shows a working hook, plus
132
+ transactional uploads and serving.
131
133
 
132
134
  ## Streaming and ranges
133
135
 
@@ -458,6 +460,7 @@ differ).
458
460
  | -------------------------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
459
461
  | API | sync + async clients | one async client |
460
462
  | Malformed id (`"abc"`) | `StorageError` from Postgres | treated as not found (`ImageNotFoundError`, no DB round trip), friendlier for `/images/:id` routes |
463
+ | Malformed id and the `beforeGet` hook | the hook **is** called with the raw string (validate it yourself) | never reaches the hook: not found, so the hook only sees well-formed UUIDs (0.9.0+) |
461
464
  | `optimize` | Pillow; EXIF stripped, not applied | sharp; EXIF **applied then stripped**; transparency → **white** for JPEG |
462
465
  | `putMany` inserts | pipelined | one transaction, statements run sequentially |
463
466
  | Formats | JPEG, PNG, WebP, HEIC (`[heic]` extra) | JPEG, PNG, WebP, HEIC (optional `libheif-js`) |
@@ -392,7 +392,9 @@ interface ZeroBucketOptions<C = unknown> {
392
392
  * Authorization hook for get / getMany (per id) / getStream / streamTo / metadata.
393
393
  * Return false to deny. A hook that THROWS fails closed: the exception
394
394
  * propagates (or is captured per item in getMany) and is never treated as allow.
395
- * NOT called for exists().
395
+ * NOT called for exists(). Only ever called with a well-formed UUID: a malformed id is
396
+ * "not found" (ImageNotFoundError, or `error: "not found"` per item in getMany) and never
397
+ * reaches the hook.
396
398
  */
397
399
  beforeGet?: BeforeGetHook<C>;
398
400
  /** Authorization hook for put / putMany (evaluated once per call). Same fail-closed rule. */
@@ -392,7 +392,9 @@ interface ZeroBucketOptions<C = unknown> {
392
392
  * Authorization hook for get / getMany (per id) / getStream / streamTo / metadata.
393
393
  * Return false to deny. A hook that THROWS fails closed: the exception
394
394
  * propagates (or is captured per item in getMany) and is never treated as allow.
395
- * NOT called for exists().
395
+ * NOT called for exists(). Only ever called with a well-formed UUID: a malformed id is
396
+ * "not found" (ImageNotFoundError, or `error: "not found"` per item in getMany) and never
397
+ * reaches the hook.
396
398
  */
397
399
  beforeGet?: BeforeGetHook<C>;
398
400
  /** Authorization hook for put / putMany (evaluated once per call). Same fail-closed rule. */
package/dist/http.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { IncomingMessage, ServerResponse } from 'node:http';
2
- import { Z as ZeroBucket } from './client-l4jPIFJI.cjs';
2
+ import { Z as ZeroBucket } from './client-7ZNu3xMJ.cjs';
3
3
  import 'pg';
4
4
 
5
5
  /**
package/dist/http.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { IncomingMessage, ServerResponse } from 'node:http';
2
- import { Z as ZeroBucket } from './client-l4jPIFJI.js';
2
+ import { Z as ZeroBucket } from './client-7ZNu3xMJ.js';
3
3
  import 'pg';
4
4
 
5
5
  /**
package/dist/index.cjs CHANGED
@@ -3407,6 +3407,7 @@ var ZeroBucket = class _ZeroBucket {
3407
3407
  }
3408
3408
  // ---- hooks -----------------------------------------------------------
3409
3409
  async checkBeforeGet(imageId, context) {
3410
+ if (!isValidId(imageId)) throw new ImageNotFoundError(imageId);
3410
3411
  if (!this.beforeGet) return;
3411
3412
  if (!await this.beforeGet(imageId, context))
3412
3413
  throw new AccessDeniedError("get", imageId);
@@ -3570,6 +3571,10 @@ var ZeroBucket = class _ZeroBucket {
3570
3571
  const allowedIdx = [];
3571
3572
  for (let i = 0; i < imageIds.length; i++) {
3572
3573
  const imageId = imageIds[i];
3574
+ if (!isValidId(imageId)) {
3575
+ results[i] = { imageId, image: null, error: "not found", success: false };
3576
+ continue;
3577
+ }
3573
3578
  if (this.beforeGet) {
3574
3579
  try {
3575
3580
  if (!await this.beforeGet(imageId, options.context)) {