first commit
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
# sign-url
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Owns the boundary validation for `CdnAdapter.signUrl` callers. Wraps the Zod
|
||||
`SignUrlOptionsSchema` parse and converts schema failures into the canonical
|
||||
`StorageCdnError` codes — `STORAGE_CDN.INVALID_TTL` when `ttlSeconds <= 0`
|
||||
or non-integer, `STORAGE_CDN.INVALID_OPTIONS` for any other schema failure.
|
||||
Provider adapters invoke `parseSignUrlOptions` at the top of their `signUrl`
|
||||
implementations so every provider returns the same diagnostic surface on
|
||||
invalid input.
|
||||
|
||||
Without this module, every provider would either replicate the Zod parse
|
||||
boilerplate or invent its own error mapping — neither outcome is good for
|
||||
operators trying to write provider-agnostic alerting rules.
|
||||
|
||||
## Features
|
||||
|
||||
- One exported function (`parseSignUrlOptions`) — keeps the public surface
|
||||
trivial.
|
||||
- Distinct error codes for `ttlSeconds` failures vs. everything else, so
|
||||
monitoring rules can alert separately on "TTL out of range" vs. "caller
|
||||
is misconfigured".
|
||||
- Returns a clean `SignUrlOptions` value with optional fields strictly
|
||||
omitted (not `undefined`) to satisfy `exactOptionalPropertyTypes`.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { parseSignUrlOptions } from "@suaveplan/storage-cdn";
|
||||
|
||||
const parsed = parseSignUrlOptions({ ttlSeconds: 60, method: "GET" });
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import {
|
||||
CdnAdapter,
|
||||
parseSignUrlOptions,
|
||||
STORAGE_CDN_CODES,
|
||||
StorageCdnError,
|
||||
} from "@suaveplan/storage-cdn";
|
||||
|
||||
class MyCdn extends CdnAdapter {
|
||||
public override async signUrl(key: string, options: SignUrlOptions): Promise<string> {
|
||||
const opts = parseSignUrlOptions(options); // throws on bad input
|
||||
const url = await this.client.presign(key, opts.method ?? "GET", opts.ttlSeconds);
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await myCdn.signUrl("a/b.bin", { ttlSeconds: 0 });
|
||||
} catch (err) {
|
||||
if (err instanceof StorageCdnError && err.code === STORAGE_CDN_CODES.INVALID_TTL) {
|
||||
// distinct from INVALID_OPTIONS — alert pipeline can fire a specific rule.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `parseSignUrlOptions(options: SignUrlOptions): SignUrlOptions`
|
||||
|
||||
Validates `options` against `SignUrlOptionsSchema`. On success, returns a
|
||||
fresh `SignUrlOptions` value with optional fields strictly omitted (not
|
||||
set to `undefined`). On failure, throws:
|
||||
|
||||
- `StorageCdnError(STORAGE_CDN.INVALID_TTL)` when the `ttlSeconds` issue
|
||||
is present.
|
||||
- `StorageCdnError(STORAGE_CDN.INVALID_OPTIONS)` otherwise (e.g. method
|
||||
outside whitelist, empty `responseContentType`).
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The Zod parse runs once per call — the schema is module-level so there
|
||||
is no per-call construction overhead.
|
||||
- The `ttlSeconds` detection scans the issues array for any issue whose
|
||||
path begins with `ttlSeconds`. This catches both "out of range" and
|
||||
"not an integer" — both surface as `INVALID_TTL` because they are
|
||||
the same caller mistake (passing a bad TTL).
|
||||
- Optional-field reconstruction explicitly skips fields the caller
|
||||
omitted; this preserves the `exactOptionalPropertyTypes` invariant
|
||||
downstream (some providers' API clients hard-fail on `method: undefined`).
|
||||
- The function is intentionally narrow — it does not sign anything. Real
|
||||
signing is provider-specific and lives in the provider package.
|
||||
Reference in New Issue
Block a user