@nomideusz/svelte-media 0.1.1 → 0.3.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/CHANGELOG.md +42 -0
- package/README.md +47 -12
- package/dist/core/media.d.ts +25 -0
- package/dist/core/media.js +43 -0
- package/dist/core/process.d.ts +2 -22
- package/dist/core/process.js +18 -41
- package/dist/core/types.d.ts +35 -2
- package/dist/index.d.ts +2 -5
- package/dist/index.js +4 -3
- package/dist/server/index.d.ts +6 -0
- package/dist/server/index.js +6 -0
- package/package.json +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-08-03
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **`derive` / `onDeriveError` on `MediaConfig`, and `derived` on `StoredMedia`.**
|
|
7
|
+
A hook over the decoded bytes during processing, so anything computed from the
|
|
8
|
+
image — placeholder, blurhash, dominant colour, EXIF — happens while the bytes
|
|
9
|
+
are in memory rather than fetching them back later. `TDerived` is inferred from
|
|
10
|
+
the callback, so the package takes no dependency on what you derive.
|
|
11
|
+
|
|
12
|
+
The hook runs after every size is stored, and failures deliberately do not
|
|
13
|
+
propagate: by then the upload has succeeded, and rejecting would make the
|
|
14
|
+
caller retry a completed upload and orphan the objects already written.
|
|
15
|
+
`derived` is left undefined and `onDeriveError` is called.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## 0.2.0 — 2026-08-03
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- **Breaking: the package is split into two entry points.** Storage adapters,
|
|
22
|
+
`processAndStore`, `deleteMedia` and `getMediaUrl` move to
|
|
23
|
+
`@nomideusz/svelte-media/server`; components, `validateImageFile`, the key
|
|
24
|
+
helpers, `IMAGE_SIZES` and the types stay on the root import.
|
|
25
|
+
|
|
26
|
+
Everything was previously behind one entry, and `core/process.ts` imported
|
|
27
|
+
`sharp` while `core/local-adapter.ts` imported `node:fs` and `node:path` at
|
|
28
|
+
module level. Any browser bundle that touched the package pulled those in and
|
|
29
|
+
failed to build — which means `ImageUpload` and `ImageGallery`, the two
|
|
30
|
+
exports that exist to be used from a component, could not be. The bug went
|
|
31
|
+
unnoticed because both apps in the source monorepo import only from server
|
|
32
|
+
files.
|
|
33
|
+
|
|
34
|
+
Migration: append `/server` to imports of the adapters or the pipeline. Key
|
|
35
|
+
helpers are re-exported from `/server` too, so a server file still needs one
|
|
36
|
+
import.
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
- A real demo at https://svelte-media-gamma.vercel.app/ — the components running
|
|
40
|
+
live, `validateImageFile` against files you choose, and the storage-key layout
|
|
41
|
+
for a prefix and entity you type. The server pipeline is shown as code, since
|
|
42
|
+
it cannot run in a browser.
|
|
43
|
+
|
|
44
|
+
|
|
3
45
|
Backfilled 2026-08-02 from git history. Entries before that date are
|
|
4
46
|
reconstructed from commits, so they record what changed rather than a release
|
|
5
47
|
that was tagged at the time. 0.1.0 was published manually — trusted publishing
|
package/README.md
CHANGED
|
@@ -10,9 +10,18 @@ pluggable storage adapter — S3-compatible or local disk.
|
|
|
10
10
|
pnpm add @nomideusz/svelte-media
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
> Requires Svelte 5 (`^5.0.0`).
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
> Requires Svelte 5 (`^5.0.0`).
|
|
14
|
+
|
|
15
|
+
The package has two entry points, because half of it cannot run in a browser:
|
|
16
|
+
|
|
17
|
+
| Import | Contains | Where |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `@nomideusz/svelte-media` | components, `validateImageFile`, key helpers, `IMAGE_SIZES`, types | anywhere |
|
|
20
|
+
| `@nomideusz/svelte-media/server` | storage adapters, `processAndStore`, `deleteMedia`, `getMediaUrl` | server only |
|
|
21
|
+
|
|
22
|
+
The pipeline needs `sharp`, `node:fs` and `Buffer`. Keeping it behind `/server`
|
|
23
|
+
is what lets a component import `ImageUpload` without a bundler dragging those
|
|
24
|
+
into the browser build.
|
|
16
25
|
|
|
17
26
|
## Why
|
|
18
27
|
|
|
@@ -24,7 +33,7 @@ the seam.
|
|
|
24
33
|
## Quick Start
|
|
25
34
|
|
|
26
35
|
```ts
|
|
27
|
-
import { createS3Adapter, processAndStore, getMediaUrl } from '@nomideusz/svelte-media';
|
|
36
|
+
import { createS3Adapter, processAndStore, getMediaUrl } from '@nomideusz/svelte-media/server';
|
|
28
37
|
|
|
29
38
|
const storage = createS3Adapter({
|
|
30
39
|
endpoint: process.env.S3_ENDPOINT!, // https://xxx.r2.cloudflarestorage.com
|
|
@@ -49,6 +58,32 @@ touches a database.
|
|
|
49
58
|
**Output is always WebP**, whatever was uploaded; `generateMediaKey` names every
|
|
50
59
|
file `<cuid2>.webp` and ignores the original extension.
|
|
51
60
|
|
|
61
|
+
## Deriving extras at upload time
|
|
62
|
+
|
|
63
|
+
`processAndStore` already has the decoded bytes in memory. A `derive` hook lets
|
|
64
|
+
you compute something from them in the same pass — a placeholder, a blurhash, a
|
|
65
|
+
dominant colour, EXIF — instead of fetching the image back later:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { generatePlaceholder } from '@nomideusz/svelte-geometrize/node';
|
|
69
|
+
|
|
70
|
+
const stored = await processAndStore(storage, file, 'tours', tourId, {
|
|
71
|
+
derive: ({ buffer }) => generatePlaceholder(buffer),
|
|
72
|
+
onDeriveError: (err) => log.warn('placeholder failed', err),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
stored.derived; // GeometrizePlaceholder | undefined — inferred from the hook
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The hook runs **after** every size is stored, and **failures do not propagate**:
|
|
79
|
+
by that point the upload has succeeded, and rejecting would make the caller
|
|
80
|
+
retry a completed upload — orphaning the objects already written. A failing
|
|
81
|
+
hook leaves `derived` undefined and calls `onDeriveError`. Wire that to your
|
|
82
|
+
logger, or the failure is silent.
|
|
83
|
+
|
|
84
|
+
The package takes no dependency on whatever you derive; `TDerived` is inferred
|
|
85
|
+
from the callback's return type.
|
|
86
|
+
|
|
52
87
|
## Sizes
|
|
53
88
|
|
|
54
89
|
`processAndStore` always writes four variants:
|
|
@@ -79,7 +114,7 @@ interface StorageAdapter {
|
|
|
79
114
|
Two ship with the package:
|
|
80
115
|
|
|
81
116
|
```ts
|
|
82
|
-
import { createS3Adapter, createLocalAdapter } from '@nomideusz/svelte-media';
|
|
117
|
+
import { createS3Adapter, createLocalAdapter } from '@nomideusz/svelte-media/server';
|
|
83
118
|
|
|
84
119
|
createS3Adapter({ /* S3Config, above */ }); // R2, MinIO, Tigris, AWS
|
|
85
120
|
createLocalAdapter({ root: '/data/images' }); // writes under root, mkdir -p
|
|
@@ -109,7 +144,7 @@ is only needed to reject early and report a friendlier message.
|
|
|
109
144
|
## Deleting
|
|
110
145
|
|
|
111
146
|
```ts
|
|
112
|
-
import { deleteMedia } from '@nomideusz/svelte-media';
|
|
147
|
+
import { deleteMedia } from '@nomideusz/svelte-media/server';
|
|
113
148
|
|
|
114
149
|
// Removes all four sizes; individual failures are swallowed
|
|
115
150
|
await deleteMedia(storage, stored.prefix, stored.entityId, stored.filename);
|
|
@@ -152,23 +187,23 @@ the same reason: it renders on the client, where the adapter cannot go.
|
|
|
152
187
|
## API
|
|
153
188
|
|
|
154
189
|
```ts
|
|
155
|
-
//
|
|
190
|
+
// ── @nomideusz/svelte-media/server ──
|
|
156
191
|
createS3Adapter(config: S3Config): StorageAdapter
|
|
157
192
|
createLocalAdapter(config: LocalConfig): StorageAdapter
|
|
158
|
-
|
|
159
|
-
// Pipeline
|
|
160
193
|
processAndStore(adapter, file, prefix, entityId, config?): Promise<StoredMedia>
|
|
161
194
|
deleteMedia(adapter, prefix, entityId, filename): Promise<void>
|
|
162
195
|
getMediaUrl(adapter, prefix, entityId, filename, size = 'medium'): string
|
|
163
|
-
|
|
196
|
+
|
|
197
|
+
// ── @nomideusz/svelte-media (client-safe) ──
|
|
164
198
|
validateImageFile(file, config?): ValidationResult
|
|
165
199
|
generateMediaKey(): string // `<cuid2>.webp`
|
|
200
|
+
getStorageKey(prefix, entityId, filename, size): string // `${prefix}/${entityId}/${sizePrefix}${filename}`
|
|
166
201
|
IMAGE_SIZES
|
|
167
|
-
|
|
168
|
-
// Components
|
|
169
202
|
ImageUpload, ImageGallery
|
|
170
203
|
```
|
|
171
204
|
|
|
205
|
+
Key helpers are exported from both entries, so server code needs only one import.
|
|
206
|
+
|
|
172
207
|
Types: `StorageAdapter`, `S3Config`, `LocalConfig`, `StoredMedia`, `ImageSize`,
|
|
173
208
|
`MediaConfig`, `ValidationResult`.
|
|
174
209
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ImageSize, ValidationConfig, ValidationResult } from './types.js';
|
|
2
|
+
export declare const DEFAULT_MAX_SIZE: number;
|
|
3
|
+
export declare const DEFAULT_ALLOWED_TYPES: string[];
|
|
4
|
+
export declare const IMAGE_SIZES: {
|
|
5
|
+
thumbnail: {
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
fit: "cover";
|
|
9
|
+
};
|
|
10
|
+
medium: {
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
fit: "inside";
|
|
14
|
+
};
|
|
15
|
+
large: {
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
fit: "inside";
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare const SIZE_PREFIXES: Record<ImageSize, string>;
|
|
22
|
+
export declare const SIZE_QUALITY: Record<ImageSize, number>;
|
|
23
|
+
export declare function validateImageFile(file: File, config?: ValidationConfig): ValidationResult;
|
|
24
|
+
export declare function generateMediaKey(_originalName?: string): string;
|
|
25
|
+
export declare function getStorageKey(prefix: string, entityId: string, filename: string, size: ImageSize): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Client-safe half of the package: validation, naming and key layout.
|
|
2
|
+
// Deliberately free of sharp, node:fs and Buffer so components and browser code
|
|
3
|
+
// can import it — see core/process.ts for the server pipeline.
|
|
4
|
+
import { createId } from '@paralleldrive/cuid2';
|
|
5
|
+
export const DEFAULT_MAX_SIZE = 5 * 1024 * 1024;
|
|
6
|
+
export const DEFAULT_ALLOWED_TYPES = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp'];
|
|
7
|
+
export const IMAGE_SIZES = {
|
|
8
|
+
thumbnail: { width: 300, height: 300, fit: 'cover' },
|
|
9
|
+
medium: { width: 800, height: 600, fit: 'inside' },
|
|
10
|
+
large: { width: 1200, height: 900, fit: 'inside' },
|
|
11
|
+
};
|
|
12
|
+
export const SIZE_PREFIXES = {
|
|
13
|
+
original: '',
|
|
14
|
+
thumbnail: 'thumb_',
|
|
15
|
+
medium: 'med_',
|
|
16
|
+
large: 'large_',
|
|
17
|
+
};
|
|
18
|
+
export const SIZE_QUALITY = {
|
|
19
|
+
original: 95,
|
|
20
|
+
thumbnail: 80,
|
|
21
|
+
medium: 85,
|
|
22
|
+
large: 90,
|
|
23
|
+
};
|
|
24
|
+
export function validateImageFile(file, config) {
|
|
25
|
+
const maxSize = config?.maxFileSize ?? DEFAULT_MAX_SIZE;
|
|
26
|
+
const allowed = config?.allowedTypes ?? DEFAULT_ALLOWED_TYPES;
|
|
27
|
+
if (file.size > maxSize) {
|
|
28
|
+
const mb = Math.round(maxSize / 1024 / 1024);
|
|
29
|
+
return { valid: false, error: `File too large (max ${mb}MB)` };
|
|
30
|
+
}
|
|
31
|
+
if (!allowed.includes(file.type)) {
|
|
32
|
+
return { valid: false, error: `Invalid file type. Allowed: JPEG, PNG, WebP` };
|
|
33
|
+
}
|
|
34
|
+
return { valid: true };
|
|
35
|
+
}
|
|
36
|
+
export function generateMediaKey(_originalName) {
|
|
37
|
+
// All processed output is WebP regardless of the uploaded format.
|
|
38
|
+
return `${createId()}.webp`;
|
|
39
|
+
}
|
|
40
|
+
export function getStorageKey(prefix, entityId, filename, size) {
|
|
41
|
+
const sizePrefix = SIZE_PREFIXES[size];
|
|
42
|
+
return `${prefix}/${entityId}/${sizePrefix}${filename}`;
|
|
43
|
+
}
|
package/dist/core/process.d.ts
CHANGED
|
@@ -1,24 +1,4 @@
|
|
|
1
|
-
import type { StorageAdapter, StoredMedia, ImageSize, MediaConfig
|
|
2
|
-
export declare
|
|
3
|
-
thumbnail: {
|
|
4
|
-
width: number;
|
|
5
|
-
height: number;
|
|
6
|
-
fit: "cover";
|
|
7
|
-
};
|
|
8
|
-
medium: {
|
|
9
|
-
width: number;
|
|
10
|
-
height: number;
|
|
11
|
-
fit: "inside";
|
|
12
|
-
};
|
|
13
|
-
large: {
|
|
14
|
-
width: number;
|
|
15
|
-
height: number;
|
|
16
|
-
fit: "inside";
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
export declare function validateImageFile(file: File, config?: MediaConfig): ValidationResult;
|
|
20
|
-
export declare function generateMediaKey(_originalName?: string): string;
|
|
21
|
-
export declare function getStorageKey(prefix: string, entityId: string, filename: string, size: ImageSize): string;
|
|
22
|
-
export declare function processAndStore(adapter: StorageAdapter, file: File, prefix: string, entityId: string, config?: MediaConfig): Promise<StoredMedia>;
|
|
1
|
+
import type { StorageAdapter, StoredMedia, ImageSize, MediaConfig } from './types.js';
|
|
2
|
+
export declare function processAndStore<TDerived = never>(adapter: StorageAdapter, file: File, prefix: string, entityId: string, config?: MediaConfig<TDerived>): Promise<StoredMedia<TDerived>>;
|
|
23
3
|
export declare function deleteMedia(adapter: StorageAdapter, prefix: string, entityId: string, filename: string): Promise<void>;
|
|
24
4
|
export declare function getMediaUrl(adapter: StorageAdapter, prefix: string, entityId: string, filename: string, size?: ImageSize): string;
|
package/dist/core/process.js
CHANGED
|
@@ -1,44 +1,8 @@
|
|
|
1
|
+
// Server-only pipeline: needs sharp and Node's Buffer. Importing this from a
|
|
2
|
+
// browser bundle will fail — the client-safe helpers live in core/media.ts and
|
|
3
|
+
// are re-exported from the package root.
|
|
1
4
|
import sharp from 'sharp';
|
|
2
|
-
import {
|
|
3
|
-
const DEFAULT_MAX_SIZE = 5 * 1024 * 1024;
|
|
4
|
-
const DEFAULT_ALLOWED_TYPES = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp'];
|
|
5
|
-
export const IMAGE_SIZES = {
|
|
6
|
-
thumbnail: { width: 300, height: 300, fit: 'cover' },
|
|
7
|
-
medium: { width: 800, height: 600, fit: 'inside' },
|
|
8
|
-
large: { width: 1200, height: 900, fit: 'inside' },
|
|
9
|
-
};
|
|
10
|
-
const SIZE_PREFIXES = {
|
|
11
|
-
original: '',
|
|
12
|
-
thumbnail: 'thumb_',
|
|
13
|
-
medium: 'med_',
|
|
14
|
-
large: 'large_',
|
|
15
|
-
};
|
|
16
|
-
const SIZE_QUALITY = {
|
|
17
|
-
original: 95,
|
|
18
|
-
thumbnail: 80,
|
|
19
|
-
medium: 85,
|
|
20
|
-
large: 90,
|
|
21
|
-
};
|
|
22
|
-
export function validateImageFile(file, config) {
|
|
23
|
-
const maxSize = config?.maxFileSize ?? DEFAULT_MAX_SIZE;
|
|
24
|
-
const allowed = config?.allowedTypes ?? DEFAULT_ALLOWED_TYPES;
|
|
25
|
-
if (file.size > maxSize) {
|
|
26
|
-
const mb = Math.round(maxSize / 1024 / 1024);
|
|
27
|
-
return { valid: false, error: `File too large (max ${mb}MB)` };
|
|
28
|
-
}
|
|
29
|
-
if (!allowed.includes(file.type)) {
|
|
30
|
-
return { valid: false, error: `Invalid file type. Allowed: JPEG, PNG, WebP` };
|
|
31
|
-
}
|
|
32
|
-
return { valid: true };
|
|
33
|
-
}
|
|
34
|
-
export function generateMediaKey(_originalName) {
|
|
35
|
-
// All processed output is WebP regardless of the uploaded format.
|
|
36
|
-
return `${createId()}.webp`;
|
|
37
|
-
}
|
|
38
|
-
export function getStorageKey(prefix, entityId, filename, size) {
|
|
39
|
-
const sizePrefix = SIZE_PREFIXES[size];
|
|
40
|
-
return `${prefix}/${entityId}/${sizePrefix}${filename}`;
|
|
41
|
-
}
|
|
5
|
+
import { IMAGE_SIZES, SIZE_QUALITY, generateMediaKey, getStorageKey, validateImageFile, } from './media.js';
|
|
42
6
|
export async function processAndStore(adapter, file, prefix, entityId, config) {
|
|
43
7
|
const validation = validateImageFile(file, config);
|
|
44
8
|
if (!validation.valid)
|
|
@@ -65,7 +29,20 @@ export async function processAndStore(adapter, file, prefix, entityId, config) {
|
|
|
65
29
|
}
|
|
66
30
|
// ponytail: existing objects stay JPEG under their old keys — URLs derive
|
|
67
31
|
// from the stored filename, so old rows keep working without migration.
|
|
68
|
-
|
|
32
|
+
// Runs last, so a throwing hook cannot orphan a half-written upload — and it
|
|
33
|
+
// is caught, because by this point the image is stored and rejecting would
|
|
34
|
+
// make the caller retry a completed upload.
|
|
35
|
+
let derived;
|
|
36
|
+
if (config?.derive) {
|
|
37
|
+
const source = { buffer, filename, mimeType: file.type };
|
|
38
|
+
try {
|
|
39
|
+
derived = await config.derive(source);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
config.onDeriveError?.(error, source);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { filename, originalName: file.name, prefix, entityId, sizes, derived };
|
|
69
46
|
}
|
|
70
47
|
export async function deleteMedia(adapter, prefix, entityId, filename) {
|
|
71
48
|
const keys = ['original', 'thumbnail', 'medium', 'large'].map((size) => getStorageKey(prefix, entityId, filename, size));
|
package/dist/core/types.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface S3Config {
|
|
|
17
17
|
/** Use path-style access (default: true for MinIO/R2, set false for Railway/AWS) */
|
|
18
18
|
forcePathStyle?: boolean;
|
|
19
19
|
}
|
|
20
|
-
export interface StoredMedia {
|
|
20
|
+
export interface StoredMedia<TDerived = never> {
|
|
21
21
|
filename: string;
|
|
22
22
|
originalName: string;
|
|
23
23
|
/** Storage prefix, e.g. 'tours' or 'avatars' */
|
|
@@ -26,6 +26,11 @@ export interface StoredMedia {
|
|
|
26
26
|
entityId: string;
|
|
27
27
|
/** Storage keys for each size */
|
|
28
28
|
sizes: Record<ImageSize, string>;
|
|
29
|
+
/**
|
|
30
|
+
* Result of `config.derive`, when supplied. Undefined if no hook was given,
|
|
31
|
+
* or if it threw — see `MediaConfig.onDeriveError`.
|
|
32
|
+
*/
|
|
33
|
+
derived?: TDerived;
|
|
29
34
|
}
|
|
30
35
|
export interface MediaValidationError {
|
|
31
36
|
isValid: false;
|
|
@@ -41,7 +46,35 @@ export interface ValidationResult {
|
|
|
41
46
|
valid: boolean;
|
|
42
47
|
error?: string;
|
|
43
48
|
}
|
|
44
|
-
|
|
49
|
+
/** What a `derive` hook receives — the image as uploaded, before any resizing. */
|
|
50
|
+
export interface DeriveSource {
|
|
51
|
+
/** Original bytes, pre-resize, EXIF intact. */
|
|
52
|
+
buffer: Buffer;
|
|
53
|
+
/** The generated storage filename, e.g. `k7x2m9.webp`. */
|
|
54
|
+
filename: string;
|
|
55
|
+
/** The uploaded file's MIME type. */
|
|
56
|
+
mimeType: string;
|
|
57
|
+
}
|
|
58
|
+
/** The validation half of MediaConfig — all `validateImageFile` needs. */
|
|
59
|
+
export interface ValidationConfig {
|
|
45
60
|
maxFileSize?: number;
|
|
46
61
|
allowedTypes?: string[];
|
|
47
62
|
}
|
|
63
|
+
export interface MediaConfig<TDerived = never> extends ValidationConfig {
|
|
64
|
+
/**
|
|
65
|
+
* Optional side-computation over the image, run once during processing while
|
|
66
|
+
* the bytes are already in hand — a placeholder, a blurhash, a dominant
|
|
67
|
+
* colour, EXIF. Whatever it returns is attached to the result as `derived`.
|
|
68
|
+
*
|
|
69
|
+
* Runs after every size has been stored, so a failure cannot orphan a
|
|
70
|
+
* half-written upload. Failures do not propagate: the upload has already
|
|
71
|
+
* succeeded and a derived extra must never invalidate it. `derived` is left
|
|
72
|
+
* undefined and `onDeriveError` is called.
|
|
73
|
+
*/
|
|
74
|
+
derive?(source: DeriveSource): Promise<TDerived>;
|
|
75
|
+
/**
|
|
76
|
+
* Called when `derive` throws. The upload still succeeds. Without this the
|
|
77
|
+
* failure is silent, so wire it to your logger.
|
|
78
|
+
*/
|
|
79
|
+
onDeriveError?(error: unknown, source: DeriveSource): void;
|
|
80
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
export type { StorageAdapter, S3Config, StoredMedia, ImageSize, MediaConfig, ValidationResult, } from './core/types.js';
|
|
2
|
-
export
|
|
3
|
-
export { createS3Adapter } from './core/adapter.js';
|
|
4
|
-
export { createLocalAdapter } from './core/local-adapter.js';
|
|
5
|
-
export { validateImageFile, generateMediaKey, getStorageKey, processAndStore, deleteMedia, getMediaUrl, IMAGE_SIZES, } from './core/process.js';
|
|
1
|
+
export type { StorageAdapter, S3Config, StoredMedia, ImageSize, MediaConfig, ValidationResult, ValidationConfig, DeriveSource, } from './core/types.js';
|
|
2
|
+
export { validateImageFile, generateMediaKey, getStorageKey, IMAGE_SIZES, DEFAULT_MAX_SIZE, DEFAULT_ALLOWED_TYPES, } from './core/media.js';
|
|
6
3
|
export { default as ImageUpload } from './components/ImageUpload.svelte';
|
|
7
4
|
export { default as ImageGallery } from './components/ImageGallery.svelte';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
// Client-safe entry. The image pipeline and storage adapters need sharp,
|
|
2
|
+
// node:fs and Buffer, so they live behind '@nomideusz/svelte-media/server' —
|
|
3
|
+
// importing them here would break any browser bundle that touches a component.
|
|
4
|
+
export { validateImageFile, generateMediaKey, getStorageKey, IMAGE_SIZES, DEFAULT_MAX_SIZE, DEFAULT_ALLOWED_TYPES, } from './core/media.js';
|
|
4
5
|
export { default as ImageUpload } from './components/ImageUpload.svelte';
|
|
5
6
|
export { default as ImageGallery } from './components/ImageGallery.svelte';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { LocalConfig } from '../core/local-adapter.js';
|
|
2
|
+
export { createS3Adapter } from '../core/adapter.js';
|
|
3
|
+
export { createLocalAdapter } from '../core/local-adapter.js';
|
|
4
|
+
export { processAndStore, deleteMedia, getMediaUrl } from '../core/process.js';
|
|
5
|
+
export { validateImageFile, generateMediaKey, getStorageKey, IMAGE_SIZES, } from '../core/media.js';
|
|
6
|
+
export type * from '../core/types.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Server-only entry: sharp, node:fs and Buffer live behind here.
|
|
2
|
+
export { createS3Adapter } from '../core/adapter.js';
|
|
3
|
+
export { createLocalAdapter } from '../core/local-adapter.js';
|
|
4
|
+
export { processAndStore, deleteMedia, getMediaUrl } from '../core/process.js';
|
|
5
|
+
// Re-exported so server code needs only one import.
|
|
6
|
+
export { validateImageFile, generateMediaKey, getStorageKey, IMAGE_SIZES, } from '../core/media.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nomideusz/svelte-media",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Image upload, processing, and S3-compatible storage for Svelte 5 apps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
13
13
|
"svelte": "./dist/index.js",
|
|
14
14
|
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./server": {
|
|
17
|
+
"types": "./dist/server/index.d.ts",
|
|
18
|
+
"default": "./dist/server/index.js"
|
|
15
19
|
}
|
|
16
20
|
},
|
|
17
21
|
"files": [
|