@stacksjs/storage 0.70.87 → 0.70.88
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/package.json +6 -6
- package/dist/adapters/bun.d.ts +0 -31
- package/dist/adapters/index.d.ts +0 -6
- package/dist/adapters/local.d.ts +0 -38
- package/dist/adapters/memory.d.ts +0 -38
- package/dist/adapters/s3.d.ts +0 -53
- package/dist/adapters/scoped.d.ts +0 -68
- package/dist/copy.d.ts +0 -3
- package/dist/delete.d.ts +0 -8
- package/dist/drivers/aws.d.ts +0 -4
- package/dist/drivers/bun.d.ts +0 -4
- package/dist/drivers/index.d.ts +0 -4
- package/dist/drivers/local.d.ts +0 -4
- package/dist/drivers/memory.d.ts +0 -4
- package/dist/facade.d.ts +0 -53
- package/dist/files.d.ts +0 -52
- package/dist/folders.d.ts +0 -18
- package/dist/fs.d.ts +0 -4
- package/dist/glob.d.ts +0 -13
- package/dist/hash.d.ts +0 -5
- package/dist/helpers.d.ts +0 -7
- package/dist/image.d.ts +0 -55
- package/dist/image.js +0 -43
- package/dist/index.d.ts +0 -60
- package/dist/index.js +0 -2810
- package/dist/mime-verify.d.ts +0 -65
- package/dist/move.d.ts +0 -6
- package/dist/path-sanitize.d.ts +0 -92
- package/dist/put-file.d.ts +0 -53
- package/dist/s3-presigned-post.d.ts +0 -52
- package/dist/signed-url.d.ts +0 -69
- package/dist/static-serve.d.ts +0 -37
- package/dist/storage.d.ts +0 -9
- package/dist/types/filesystem.d.ts +0 -131
- package/dist/types.d.ts +0 -229
- package/dist/uploaded-file.d.ts +0 -38
- package/dist/visibility.d.ts +0 -3
- package/dist/zip.d.ts +0 -16
package/dist/mime-verify.d.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Detect a MIME type from the first chunk of a file. Returns the
|
|
3
|
-
* detected MIME (e.g. `'image/png'`) or `null` if the bytes don't
|
|
4
|
-
* match any known signature.
|
|
5
|
-
*
|
|
6
|
-
* Intentionally narrow — only the well-known binary formats that
|
|
7
|
-
* appear in `presignedUploadUrl`'s extension map are detected. Text
|
|
8
|
-
* formats are not covered because their signatures are ambiguous.
|
|
9
|
-
*/
|
|
10
|
-
export declare function detectMimeFromMagicBytes(bytes: Uint8Array | ArrayBuffer): string | null;
|
|
11
|
-
/**
|
|
12
|
-
* Verify that a file's actual contents match the claimed content type.
|
|
13
|
-
* Returns `{ ok, expected, detected }` so callers can branch on the
|
|
14
|
-
* result and produce useful error messages.
|
|
15
|
-
*
|
|
16
|
-
* Reads up to 32 bytes from the file (enough for every signature we
|
|
17
|
-
* check), then matches against `detectMimeFromMagicBytes`.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```ts
|
|
21
|
-
* // After a presigned upload completes:
|
|
22
|
-
* const result = await verifyUploadedMime('uploads/avatar.jpg', 'image/jpeg')
|
|
23
|
-
* if (!result.ok) {
|
|
24
|
-
* await Storage.disk().deleteFile('uploads/avatar.jpg')
|
|
25
|
-
* return Response.json({ error: 'content type mismatch', ...result }, { status: 400 })
|
|
26
|
-
* }
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
export declare function verifyUploadedMime(path: string, expectedContentType: string, options?: { disk?: string }): Promise<MimeVerifyResult>;
|
|
30
|
-
/**
|
|
31
|
-
* MIME re-verification helpers (stacksjs/stacks#1873 S-3).
|
|
32
|
-
*
|
|
33
|
-
* Background: `presignedUploadUrl({ contentType })` lets the caller
|
|
34
|
-
* declare what they're going to upload, and AWS signs the URL against
|
|
35
|
-
* that exact `Content-Type` header. Nothing checks that the **bytes**
|
|
36
|
-
* actually match the claim. An attacker who can call your presigned
|
|
37
|
-
* endpoint can request `image/jpeg` (which derives a `.jpg`
|
|
38
|
-
* extension), then PUT a JavaScript file. The server only sees
|
|
39
|
-
* "object exists, contentType was image/jpeg" — but the bytes are
|
|
40
|
-
* executable.
|
|
41
|
-
*
|
|
42
|
-
* These helpers exist so server code can re-detect the MIME from
|
|
43
|
-
* magic bytes after the upload finishes, and either delete the
|
|
44
|
-
* mismatched object or surface it as a 400.
|
|
45
|
-
*
|
|
46
|
-
* **Limitations** — magic-byte sniffing only works for binary formats
|
|
47
|
-
* with a well-defined signature. Text-based types (JSON, CSV, plain
|
|
48
|
-
* text, SVG, HTML) can't be unambiguously detected from the first few
|
|
49
|
-
* bytes; for those, validate by parsing the content (e.g. try
|
|
50
|
-
* `JSON.parse` for `application/json`).
|
|
51
|
-
*/
|
|
52
|
-
/**
|
|
53
|
-
* Result of a magic-byte detection attempt.
|
|
54
|
-
*
|
|
55
|
-
* `ok: true` means the bytes match a known signature for the
|
|
56
|
-
* expected content type. `ok: false` with `detected: null` means the
|
|
57
|
-
* bytes didn't match any signature this helper knows; `ok: false`
|
|
58
|
-
* with `detected: string` means the bytes match a *different*
|
|
59
|
-
* signature than expected (e.g. PNG bytes uploaded as image/jpeg).
|
|
60
|
-
*/
|
|
61
|
-
export declare interface MimeVerifyResult {
|
|
62
|
-
ok: boolean
|
|
63
|
-
expected: string
|
|
64
|
-
detected: string | null
|
|
65
|
-
}
|
package/dist/move.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { Result } from '@stacksjs/error-handling';
|
|
2
|
-
export declare function move(src: string | string[], dest: string, options?: MoveOptions): Promise<Result<{ message: string }, Error>>;
|
|
3
|
-
export declare function rename(from: string, to: string, options?: MoveOptions): Promise<Result<{ message: string }, Error>>;
|
|
4
|
-
declare interface MoveOptions {
|
|
5
|
-
overwrite?: boolean
|
|
6
|
-
}
|
package/dist/path-sanitize.d.ts
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sanitize a `dir` parameter for `presignedUploadUrl`. Returns the
|
|
3
|
-
* cleaned dir on success (trailing slashes stripped, empty string
|
|
4
|
-
* preserved as-is) or throws `PathSanitizeError` on:
|
|
5
|
-
*
|
|
6
|
-
* - non-string input
|
|
7
|
-
* - absolute paths (`/foo`)
|
|
8
|
-
* - traversal segments (`..`, `foo/../bar`)
|
|
9
|
-
* - null bytes (`foo\0bar`) — these get stripped by some S3 SDKs
|
|
10
|
-
* silently
|
|
11
|
-
* - control characters (`\r`, `\n`, etc.) — log-injection risk
|
|
12
|
-
* - segments outside `[A-Za-z0-9._-]`
|
|
13
|
-
*
|
|
14
|
-
* Empty / undefined dir is allowed (it means "write at the root of
|
|
15
|
-
* the configured prefix").
|
|
16
|
-
*/
|
|
17
|
-
export declare function sanitizePresignedDir(dir: string | undefined): string;
|
|
18
|
-
/**
|
|
19
|
-
* Sanitize a `filename` parameter for `presignedUploadUrl`. Returns
|
|
20
|
-
* the cleaned filename on success or throws `PathSanitizeError`.
|
|
21
|
-
*
|
|
22
|
-
* Rejects path separators, traversal tokens, null bytes, control
|
|
23
|
-
* characters, and disallowed characters. Validates the extension
|
|
24
|
-
* against a strict alphanumeric pattern (no `.exe.jpg` smuggling —
|
|
25
|
-
* the caller is responsible for matching extension to expected
|
|
26
|
-
* content type via the contentType the URL was signed for).
|
|
27
|
-
*/
|
|
28
|
-
export declare function sanitizePresignedFilename(filename: string): string;
|
|
29
|
-
/**
|
|
30
|
-
* Parse a `disk:path` reference used by `Storage.copyAcross()` /
|
|
31
|
-
* `moveAcross()` (stacksjs/stacks#1888 S-7).
|
|
32
|
-
*
|
|
33
|
-
* Format: `<disk>:<path>` where:
|
|
34
|
-
* - `<disk>` is an alphanumeric + dash/underscore disk name
|
|
35
|
-
* - `<path>` is a storage-relative path (path-traversal /
|
|
36
|
-
* null-byte / control-char checks applied)
|
|
37
|
-
*
|
|
38
|
-
* Throws {@link PathSanitizeError} on a malformed input — the
|
|
39
|
-
* cross-disk helpers turn that into a clear "bad source" / "bad
|
|
40
|
-
* dest" error rather than crashing inside the adapter.
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```ts
|
|
44
|
-
* parseDiskPath('s3:user-uploads/foo.jpg')
|
|
45
|
-
* // → { disk: 's3', path: 'user-uploads/foo.jpg' }
|
|
46
|
-
* ```
|
|
47
|
-
*/
|
|
48
|
-
export declare function parseDiskPath(input: string): ParsedDiskPath;
|
|
49
|
-
/**
|
|
50
|
-
* Parsed `disk:path` reference returned by {@link parseDiskPath}.
|
|
51
|
-
*/
|
|
52
|
-
export declare interface ParsedDiskPath {
|
|
53
|
-
disk: string
|
|
54
|
-
path: string
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Path-sanitization helpers for storage adapters (stacksjs/stacks#1873).
|
|
58
|
-
*
|
|
59
|
-
* Callers of `presignedUploadUrl({ dir, filename })` pass in
|
|
60
|
-
* caller-controlled strings that get interpolated straight into the
|
|
61
|
-
* stored key. Without sanitization, `dir: '../../sensitive'` escapes
|
|
62
|
-
* the intended prefix and `filename: 'foo/bar.exe'` injects a
|
|
63
|
-
* directory separator — both let a hostile caller (or a confused
|
|
64
|
-
* authenticated caller) write to objects outside their intended
|
|
65
|
-
* scope. These helpers reject the dangerous shapes loudly before the
|
|
66
|
-
* adapter ever signs anything.
|
|
67
|
-
*
|
|
68
|
-
* Note: the local/bun adapters already have a defense-in-depth check
|
|
69
|
-
* via `path.relative()` in `resolvePath()`. The S3 adapter doesn't,
|
|
70
|
-
* because S3 keys are opaque strings — there's no filesystem `..`
|
|
71
|
-
* resolution to lean on. That's exactly why we need this layer.
|
|
72
|
-
*/
|
|
73
|
-
/**
|
|
74
|
-
* Thrown when `sanitizePresignedDir` or `sanitizePresignedFilename`
|
|
75
|
-
* detects a value that would escape the intended scope. The `reason`
|
|
76
|
-
* discriminant lets callers distinguish "you passed an absolute path"
|
|
77
|
-
* from "you passed a null byte" if they want to surface that in error
|
|
78
|
-
* messages — most callers can just `catch (e: PathSanitizeError)` and
|
|
79
|
-
* return a 400.
|
|
80
|
-
*/
|
|
81
|
-
export declare class PathSanitizeError extends Error {
|
|
82
|
-
readonly reason: | 'empty'
|
|
83
|
-
| 'not-string'
|
|
84
|
-
| 'absolute-path'
|
|
85
|
-
| 'traversal'
|
|
86
|
-
| 'null-byte'
|
|
87
|
-
| 'control-char'
|
|
88
|
-
| 'too-long'
|
|
89
|
-
| 'invalid-char'
|
|
90
|
-
| 'invalid-extension';
|
|
91
|
-
constructor(message: string, reason: PathSanitizeError['reason']);
|
|
92
|
-
}
|
package/dist/put-file.d.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import type { DiskName } from './types/filesystem';
|
|
2
|
-
import type { PutResult } from './types';
|
|
3
|
-
import type { StorageManager } from './facade';
|
|
4
|
-
export declare function putUploadedFile(manager: StorageManager, file: UploadedFileLike, opts: PutFileOptions): Promise<PutResult & { url: string }>;
|
|
5
|
-
/**
|
|
6
|
-
* Optional metadata fields shared by every uploaded-file shape we
|
|
7
|
-
* accept. The `name` / `mimeType` aliases are present so the router's
|
|
8
|
-
* `UploadedFile` class (which uses the class-style names) flows
|
|
9
|
-
* through alongside the direct-parse shape (which uses the
|
|
10
|
-
* snake-style `originalName` / `mimetype`).
|
|
11
|
-
*/
|
|
12
|
-
declare interface UploadedFileMetadata {
|
|
13
|
-
originalName?: string
|
|
14
|
-
name?: string
|
|
15
|
-
mimetype?: string
|
|
16
|
-
mimeType?: string
|
|
17
|
-
}
|
|
18
|
-
export declare interface PutFileOptions {
|
|
19
|
-
disk?: DiskName
|
|
20
|
-
dir?: string
|
|
21
|
-
filename?: FilenameStrategy
|
|
22
|
-
preserveExtension?: boolean
|
|
23
|
-
transform?: (input: Uint8Array | Buffer | ArrayBuffer) => Promise<Uint8Array | Buffer>
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Minimal structural shape for an uploaded file accepted by
|
|
27
|
-
* `Storage.put(file, opts)`. Modeled as a discriminated union so the
|
|
28
|
-
* type-checker rejects `Storage.put({})` and similar empty-object
|
|
29
|
-
* mistakes (stacksjs/stacks#1873 S-13). At least one of `buffer`,
|
|
30
|
-
* `bytes()`, or `arrayBuffer()` must be present — that's the runtime
|
|
31
|
-
* contract `readBytes()` enforces with a throw, and now the
|
|
32
|
-
* structural contract the type system enforces at compile time.
|
|
33
|
-
*
|
|
34
|
-
* Two callsites land here in practice (stacksjs/stacks#1856):
|
|
35
|
-
*
|
|
36
|
-
* 1. **Direct multipart parse** (the original router shape, before
|
|
37
|
-
* bun-router wrapped each entry in an `UploadedFile` class).
|
|
38
|
-
* `{ originalName, mimetype, buffer }` — synchronous.
|
|
39
|
-
* 2. **Router's `UploadedFile` class** (current shape from
|
|
40
|
-
* `req.file(key)` / `req.files`). Exposes `name`, `mimeType`, and
|
|
41
|
-
* an async `bytes()` / `arrayBuffer()` accessor instead of a
|
|
42
|
-
* `buffer` property — Bun's `File` is lazy by design.
|
|
43
|
-
*/
|
|
44
|
-
export type UploadedFileLike = UploadedFileMetadata & (
|
|
45
|
-
| { buffer: ArrayBuffer | Uint8Array | Buffer, bytes?: () => Promise<Uint8Array>, arrayBuffer?: () => Promise<ArrayBuffer> }
|
|
46
|
-
| { bytes: () => Promise<Uint8Array>, buffer?: ArrayBuffer | Uint8Array | Buffer, arrayBuffer?: () => Promise<ArrayBuffer> }
|
|
47
|
-
| { arrayBuffer: () => Promise<ArrayBuffer>, buffer?: ArrayBuffer | Uint8Array | Buffer, bytes?: () => Promise<Uint8Array> }
|
|
48
|
-
);
|
|
49
|
-
/** Built-in filename strategies for `Storage.put(file, { filename })`. */
|
|
50
|
-
export type FilenameStrategy = | 'uuid'
|
|
51
|
-
| 'hash'
|
|
52
|
-
| 'original'
|
|
53
|
-
| ((file: UploadedFileLike) => string);
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Build + sign an S3 presigned-POST policy.
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```ts
|
|
6
|
-
* const post = signS3PresignedPost({
|
|
7
|
-
* bucket: 'app-uploads',
|
|
8
|
-
* region: 'us-east-1',
|
|
9
|
-
* credentials: { accessKeyId, secretAccessKey },
|
|
10
|
-
* key: { startsWith: 'avatars/' },
|
|
11
|
-
* contentType: { startsWith: 'image/' },
|
|
12
|
-
* contentLengthRange: { min: 0, max: 5 * 1024 * 1024 },
|
|
13
|
-
* expiresIn: 3600,
|
|
14
|
-
* })
|
|
15
|
-
*
|
|
16
|
-
* // Browser side:
|
|
17
|
-
* // const fd = new FormData()
|
|
18
|
-
* // Object.entries(post.fields).forEach(([k, v]) => fd.append(k, v))
|
|
19
|
-
* // fd.append('file', file) // MUST be last
|
|
20
|
-
* // await fetch(post.url, { method: 'POST', body: fd })
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
export declare function signS3PresignedPost(input: S3PresignedPostInput): S3PresignedPostResult;
|
|
24
|
-
/**
|
|
25
|
-
* Inputs to {@link signS3PresignedPost}. Mirrors the
|
|
26
|
-
* `presignedUploadPolicy()` adapter call once it's wired up.
|
|
27
|
-
*/
|
|
28
|
-
export declare interface S3PresignedPostInput {
|
|
29
|
-
bucket: string
|
|
30
|
-
region: string
|
|
31
|
-
credentials: {
|
|
32
|
-
accessKeyId: string
|
|
33
|
-
secretAccessKey: string
|
|
34
|
-
sessionToken?: string
|
|
35
|
-
}
|
|
36
|
-
key: string | { startsWith: string }
|
|
37
|
-
contentType: string | { startsWith: string }
|
|
38
|
-
contentLengthRange?: { min: number, max: number }
|
|
39
|
-
acl?: 'private' | 'public-read' | 'public-read-write' | 'authenticated-read' | 'bucket-owner-read' | 'bucket-owner-full-control'
|
|
40
|
-
expiresIn: number
|
|
41
|
-
fields?: Record<string, string>
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* What the browser submits. The form is `multipart/form-data` POSTed
|
|
45
|
-
* to `url`; every key in `fields` becomes a form field with the same
|
|
46
|
-
* name. The actual file MUST be the LAST field, named `'file'`.
|
|
47
|
-
*/
|
|
48
|
-
export declare interface S3PresignedPostResult {
|
|
49
|
-
url: string
|
|
50
|
-
fields: Record<string, string>
|
|
51
|
-
key: string
|
|
52
|
-
}
|
package/dist/signed-url.d.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { SignedUrlOptions } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* Mint a signed token for the given storage path.
|
|
4
|
-
*
|
|
5
|
-
* @example
|
|
6
|
-
* ```ts
|
|
7
|
-
* const token = createSignedStorageToken('reports/q4.pdf', { expiresIn: 3600 })
|
|
8
|
-
* ```
|
|
9
|
-
*/
|
|
10
|
-
export declare function createSignedStorageToken(path: string, options: SignedUrlOptions): string;
|
|
11
|
-
/**
|
|
12
|
-
* Revoke a signed storage token so subsequent
|
|
13
|
-
* {@link verifySignedStorageToken} calls return
|
|
14
|
-
* `{ valid: false, reason: 'revoked' }`. Idempotent — calling
|
|
15
|
-
* twice is a no-op.
|
|
16
|
-
*
|
|
17
|
-
* Pass either the full JWS compact-form token or just the signature
|
|
18
|
-
* segment (the part after the second `.`); both work because
|
|
19
|
-
* verification keys off the signature segment.
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```ts
|
|
23
|
-
* const url = await Storage.disk('local').signedUrl('reports/q4.pdf', { expiresIn: 3600 })
|
|
24
|
-
* // ... url is shared, then later leaked
|
|
25
|
-
* revokeSignedStorageToken(extractTokenFromUrl(url))
|
|
26
|
-
* // Any further fetch with that URL → 403
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
export declare function revokeSignedStorageToken(token: string): void;
|
|
30
|
-
/**
|
|
31
|
-
* Check whether a signature has been revoked. Exposed for tests
|
|
32
|
-
* and for distributed-cache replicators that need to peek at the
|
|
33
|
-
* set; production callers should rely on {@link verifySignedStorageToken}
|
|
34
|
-
* to consult this automatically.
|
|
35
|
-
*/
|
|
36
|
-
export declare function isSignedStorageTokenRevoked(sigPart: string): boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Test-only: clear the revocation set. The set is process-local
|
|
39
|
-
* and unbounded across tests would let one test's revoke bleed
|
|
40
|
-
* into another's verification.
|
|
41
|
-
*/
|
|
42
|
-
export declare function clearRevokedSignedStorageTokens(): void;
|
|
43
|
-
/**
|
|
44
|
-
* Verify a signed storage token. The caller MUST pass the requested
|
|
45
|
-
* path so we can ensure the token's `path` claim matches what the
|
|
46
|
-
* client is trying to fetch — otherwise an attacker could substitute
|
|
47
|
-
* any path in the URL and still pass signature verification.
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```ts
|
|
51
|
-
* const v = verifySignedStorageToken(req.query.token, requestedPath)
|
|
52
|
-
* if (!v.valid) return new Response('Forbidden', { status: 403 })
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
|
55
|
-
export declare function verifySignedStorageToken(token: string, requestedPath: string): SignedTokenVerification;
|
|
56
|
-
declare interface SignedTokenClaims {
|
|
57
|
-
iss: string
|
|
58
|
-
iat: number
|
|
59
|
-
exp: number
|
|
60
|
-
path: string
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Result of verifying a signed token.
|
|
64
|
-
*/
|
|
65
|
-
export declare interface SignedTokenVerification {
|
|
66
|
-
valid: boolean
|
|
67
|
-
reason?: 'malformed' | 'bad_signature' | 'expired' | 'path_mismatch' | 'revoked'
|
|
68
|
-
claims?: SignedTokenClaims
|
|
69
|
-
}
|
package/dist/static-serve.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Serve a static file with production-grade cache headers:
|
|
3
|
-
* - Strong ETag (sha256, first 16 hex chars) computed once per
|
|
4
|
-
* `(path, mtime)` and cached in-process.
|
|
5
|
-
* - `Last-Modified` from the file's mtime.
|
|
6
|
-
* - 304 Not Modified when `If-None-Match` matches OR
|
|
7
|
-
* `If-Modified-Since` is at-or-after mtime (and ETag didn't mismatch).
|
|
8
|
-
* - `Cache-Control: public, max-age=31536000, immutable` for paths
|
|
9
|
-
* that look fingerprinted (e.g. `/_assets/foo.abc12345.js`).
|
|
10
|
-
* - `Cache-Control: public, max-age=300, must-revalidate` for
|
|
11
|
-
* everything else.
|
|
12
|
-
*
|
|
13
|
-
* Returns a `404` if the file doesn't exist. Other read errors propagate.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```ts
|
|
17
|
-
* import { serveFile } from '@stacksjs/storage'
|
|
18
|
-
* import { resolve } from 'node:path'
|
|
19
|
-
*
|
|
20
|
-
* route.get('/assets/:path', async (req) => {
|
|
21
|
-
* const url = new URL(req.url)
|
|
22
|
-
* // url.pathname is e.g. /assets/app.abc12345.js
|
|
23
|
-
* const filePath = resolve('./public', url.pathname.replace(/^\//, ''))
|
|
24
|
-
* return serveFile(req, filePath)
|
|
25
|
-
* })
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
export declare function serveFile(req: Request, filePath: string, options?: ServeFileOptions): Promise<Response>;
|
|
29
|
-
/**
|
|
30
|
-
* Optional knobs for {@link serveFile}.
|
|
31
|
-
*/
|
|
32
|
-
export declare interface ServeFileOptions {
|
|
33
|
-
contentType?: string
|
|
34
|
-
cacheControl?: string
|
|
35
|
-
defaultMaxAge?: number
|
|
36
|
-
etag?: boolean
|
|
37
|
-
}
|
package/dist/storage.d.ts
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Helper to create a local disk config
|
|
3
|
-
*/
|
|
4
|
-
export declare function localDisk(root: string, options?: Partial<Omit<LocalDiskConfig, 'driver' | 'root'>>): LocalDiskConfig;
|
|
5
|
-
/**
|
|
6
|
-
* Helper to create an S3 disk config
|
|
7
|
-
*/
|
|
8
|
-
export declare function s3Disk(bucket: string, options?: Partial<Omit<S3DiskConfig, 'driver' | 'bucket'>>): S3DiskConfig;
|
|
9
|
-
/**
|
|
10
|
-
* Create filesystem config from environment variables
|
|
11
|
-
*/
|
|
12
|
-
export declare function configFromEnv(base?: Partial<FilesystemConfig>): FilesystemConfig;
|
|
13
|
-
/**
|
|
14
|
-
* Base disk configuration shared by all drivers
|
|
15
|
-
*/
|
|
16
|
-
declare interface BaseDiskConfig {
|
|
17
|
-
name?: string
|
|
18
|
-
visibility?: Visibility
|
|
19
|
-
throw?: boolean
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Local filesystem disk configuration
|
|
23
|
-
*/
|
|
24
|
-
export declare interface LocalDiskConfig extends BaseDiskConfig {
|
|
25
|
-
driver: 'local'
|
|
26
|
-
root: string
|
|
27
|
-
url?: string
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* S3 disk configuration
|
|
31
|
-
*/
|
|
32
|
-
export declare interface S3DiskConfig extends BaseDiskConfig {
|
|
33
|
-
driver: 's3'
|
|
34
|
-
bucket: string
|
|
35
|
-
region?: string
|
|
36
|
-
prefix?: string
|
|
37
|
-
endpoint?: string
|
|
38
|
-
usePathStyleEndpoint?: boolean
|
|
39
|
-
url?: string
|
|
40
|
-
credentials?: {
|
|
41
|
-
key: string
|
|
42
|
-
secret: string
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Userland-augmentable disk-name registry (stacksjs/stacks#1924).
|
|
47
|
-
*
|
|
48
|
-
* Empty by default — the framework can't know an app's configured
|
|
49
|
-
* disks at its own build time. Apps declare their disks once and get
|
|
50
|
-
* autocomplete on `Storage.disk('…')` everywhere:
|
|
51
|
-
*
|
|
52
|
-
* ```ts
|
|
53
|
-
* // types/storage.d.ts
|
|
54
|
-
* declare module '@stacksjs/storage' {
|
|
55
|
-
* interface KnownDisks {
|
|
56
|
-
* local: true
|
|
57
|
-
* public: true
|
|
58
|
-
* s3: true
|
|
59
|
-
* }
|
|
60
|
-
* }
|
|
61
|
-
* ```
|
|
62
|
-
*
|
|
63
|
-
* Mirrors the `DatabaseSchema` pattern from stacksjs/stacks#1923.
|
|
64
|
-
*/
|
|
65
|
-
// eslint-disable-next-line ts/no-empty-object-type
|
|
66
|
-
export declare interface KnownDisks {}
|
|
67
|
-
/**
|
|
68
|
-
* Main filesystem configuration
|
|
69
|
-
*
|
|
70
|
-
* @example
|
|
71
|
-
* ```ts
|
|
72
|
-
* const config: FilesystemConfig = {
|
|
73
|
-
* default: 'local',
|
|
74
|
-
* disks: {
|
|
75
|
-
* local: {
|
|
76
|
-
* driver: 'local',
|
|
77
|
-
* root: '/storage/app',
|
|
78
|
-
* },
|
|
79
|
-
* public: {
|
|
80
|
-
* driver: 'local',
|
|
81
|
-
* root: '/public',
|
|
82
|
-
* url: '/storage',
|
|
83
|
-
* visibility: 'public',
|
|
84
|
-
* },
|
|
85
|
-
* s3: {
|
|
86
|
-
* driver: 's3',
|
|
87
|
-
* bucket: 'my-bucket',
|
|
88
|
-
* region: 'us-east-1',
|
|
89
|
-
* },
|
|
90
|
-
* },
|
|
91
|
-
* }
|
|
92
|
-
* ```
|
|
93
|
-
*/
|
|
94
|
-
export declare interface FilesystemConfig {
|
|
95
|
-
default: string
|
|
96
|
-
disks: Record<string, DiskConfig>
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Environment variable mappings for filesystem configuration
|
|
100
|
-
*/
|
|
101
|
-
export declare interface FilesystemEnv {
|
|
102
|
-
FILESYSTEM_DISK?: string
|
|
103
|
-
AWS_ACCESS_KEY_ID?: string
|
|
104
|
-
AWS_SECRET_ACCESS_KEY?: string
|
|
105
|
-
AWS_DEFAULT_REGION?: string
|
|
106
|
-
AWS_BUCKET?: string
|
|
107
|
-
AWS_ENDPOINT?: string
|
|
108
|
-
AWS_URL?: string
|
|
109
|
-
AWS_USE_PATH_STYLE_ENDPOINT?: string
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Filesystem Configuration Types
|
|
113
|
-
*
|
|
114
|
-
* Laravel-style filesystem configuration with clean, typed interfaces.
|
|
115
|
-
* Supports local, public, and S3 disk drivers.
|
|
116
|
-
*/
|
|
117
|
-
export type FilesystemDriver = 'local' | 's3';
|
|
118
|
-
export type Visibility = 'public' | 'private';
|
|
119
|
-
/**
|
|
120
|
-
* Union type for all disk configurations
|
|
121
|
-
*/
|
|
122
|
-
export type DiskConfig = LocalDiskConfig | S3DiskConfig;
|
|
123
|
-
/**
|
|
124
|
-
* A configured disk name (autocompletes to the keys of an augmented
|
|
125
|
-
* {@link KnownDisks}) or any other string. The `(string & {})` branch
|
|
126
|
-
* keeps the union from collapsing back to `string`, so known disks
|
|
127
|
-
* surface in autocomplete while arbitrary names still type-check —
|
|
128
|
-
* apps that haven't augmented `KnownDisks` keep compiling unchanged.
|
|
129
|
-
*/
|
|
130
|
-
// eslint-disable-next-line ts/no-empty-object-type
|
|
131
|
-
export type DiskName = (keyof KnownDisks & string) | (string & {});
|