@rakun-kit/core 1.7.0 → 1.7.1

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
@@ -1153,7 +1153,15 @@ APIs:
1153
1153
  - `getMediaService()`: returns the singleton or creates it from config.
1154
1154
  - `handleMediaBinaryUpload`: processes manager binary uploads.
1155
1155
 
1156
- The service supports prepare/finalize upload, URL generation, folders, and media optimization depending on adapter/configuration. Manager uploads encode original file names for transport, so Unicode names (including accents, non-Latin scripts, and emoji) are preserved without placing invalid characters in HTTP headers.
1156
+ The service supports prepare/finalize upload, URL generation, folders, and media optimization depending on adapter/configuration. Manager uploads encode original file names for transport, so Unicode names (including accents, non-Latin scripts, and emoji) are preserved without placing invalid characters in HTTP headers.
1157
+
1158
+ Adapters can implement `getPublicObject` to let every Rakun server adapter proxy
1159
+ public media at its normal `/media/public/<key>` API route. This keeps browser
1160
+ URLs stable even when the object store is private or only supports expiring
1161
+ presigned URLs. The core handler validates the key under `public/`, forwards
1162
+ byte ranges, preserves object metadata, and applies long-lived caching by
1163
+ default. The storage adapter receives server-side credentials; never expose its
1164
+ presigned storage URL as the public media URL.
1157
1165
 
1158
1166
  Optimized video uploads use the `ffmpeg-static` peer dependency and produce an MP4 primary object plus MP4 and WebM entries in `sources`. Existing image-only optimize options remain compatible; use `video: { quality: 80 }` to configure video quality explicitly.
1159
1167
 
@@ -45,4 +45,5 @@ function getMediaService() {
45
45
  }
46
46
  __exportStar(require("./mediaService"), exports);
47
47
  __exportStar(require("./adapters"), exports);
48
+ __exportStar(require("./publicMedia"), exports);
48
49
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/media/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAoBA,gDAWC;AAED,0CAYC;AA5CD,iDAGwB;AASxB,IAAI,aAA2B,CAAC;AAChC,IAAI,OAA2B,CAAC;AAEzB,MAAM,qBAAqB,GAAG,CAAC,MAA0B,EAAE,EAAE;IAClE,OAAO,GAAG,MAAM,CAAC;AACnB,CAAC,CAAC;AAFW,QAAA,qBAAqB,yBAEhC;AAEF,SAAgB,kBAAkB,CAAC,MAA0B;IAC3D,OAAO,GAAG,MAAM,CAAC;IAEjB,aAAa,GAAG,IAAA,4CAA6B,EAAC;QAC5C,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,0BAA0B,EAAE,MAAM,CAAC,0BAA0B;QAC7D,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC,CAAC;IAEH,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAgB,eAAe;IAC7B,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAC;QACJ,CAAC;QAED,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,iDAA+B;AAC/B,6CAA2B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/media/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAoBA,gDAWC;AAED,0CAYC;AA5CD,iDAGwB;AASxB,IAAI,aAA2B,CAAC;AAChC,IAAI,OAA2B,CAAC;AAEzB,MAAM,qBAAqB,GAAG,CAAC,MAA0B,EAAE,EAAE;IAClE,OAAO,GAAG,MAAM,CAAC;AACnB,CAAC,CAAC;AAFW,QAAA,qBAAqB,yBAEhC;AAEF,SAAgB,kBAAkB,CAAC,MAA0B;IAC3D,OAAO,GAAG,MAAM,CAAC;IAEjB,aAAa,GAAG,IAAA,4CAA6B,EAAC;QAC5C,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,0BAA0B,EAAE,MAAM,CAAC,0BAA0B;QAC7D,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC,CAAC;IAEH,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAgB,eAAe;IAC7B,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAC;QACJ,CAAC;QAED,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,iDAA+B;AAC/B,6CAA2B;AAC3B,gDAA6B"}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handlePublicMediaRequest = exports.getPublicMediaKey = void 0;
4
+ const index_1 = require("./index");
5
+ const DEFAULT_CACHE_CONTROL = 'public, max-age=31536000, immutable';
6
+ const decodePathSegment = (segment) => {
7
+ try {
8
+ const value = decodeURIComponent(segment);
9
+ if (!value || value === '.' || value === '..' || value.includes('/'))
10
+ return null;
11
+ return value;
12
+ }
13
+ catch {
14
+ return null;
15
+ }
16
+ };
17
+ const getPublicMediaKey = (pathSegments) => {
18
+ if (pathSegments.length === 0)
19
+ return null;
20
+ const segments = pathSegments.map(decodePathSegment);
21
+ if (segments.some((segment) => segment === null))
22
+ return null;
23
+ return `public/${segments.join('/')}`;
24
+ };
25
+ exports.getPublicMediaKey = getPublicMediaKey;
26
+ const errorResponse = (status) => new Response(null, { status });
27
+ const isNotFoundError = (error) => {
28
+ if (!error || typeof error !== 'object')
29
+ return false;
30
+ const value = error;
31
+ return (value.name === 'NotFound' ||
32
+ value.name === 'NoSuchKey' ||
33
+ value.code === 'NotFound' ||
34
+ value.code === 'NoSuchKey' ||
35
+ value.$metadata?.httpStatusCode === 404);
36
+ };
37
+ const getErrorStatus = (error) => {
38
+ if (isNotFoundError(error))
39
+ return 404;
40
+ const status = error && typeof error === 'object'
41
+ ? error.$metadata?.httpStatusCode
42
+ : undefined;
43
+ if (status === 416) {
44
+ return 416;
45
+ }
46
+ return 502;
47
+ };
48
+ const setDateHeader = (headers, name, value) => {
49
+ if (!value)
50
+ return;
51
+ headers.set(name, value instanceof Date ? value.toUTCString() : value);
52
+ };
53
+ const buildHeaders = (object) => {
54
+ const headers = new Headers({
55
+ 'Cache-Control': object.cacheControl ?? DEFAULT_CACHE_CONTROL,
56
+ 'X-Content-Type-Options': 'nosniff',
57
+ });
58
+ if (object.acceptRanges)
59
+ headers.set('Accept-Ranges', object.acceptRanges);
60
+ if (object.contentDisposition)
61
+ headers.set('Content-Disposition', object.contentDisposition);
62
+ if (object.contentEncoding)
63
+ headers.set('Content-Encoding', object.contentEncoding);
64
+ if (object.contentLanguage)
65
+ headers.set('Content-Language', object.contentLanguage);
66
+ if (object.contentLength !== undefined)
67
+ headers.set('Content-Length', String(object.contentLength));
68
+ if (object.contentRange)
69
+ headers.set('Content-Range', object.contentRange);
70
+ if (object.contentType)
71
+ headers.set('Content-Type', object.contentType);
72
+ if (object.etag)
73
+ headers.set('ETag', object.etag);
74
+ setDateHeader(headers, 'Expires', object.expires);
75
+ setDateHeader(headers, 'Last-Modified', object.lastModified);
76
+ return headers;
77
+ };
78
+ const handlePublicMediaRequest = async ({ request, pathSegments, }) => {
79
+ if (request.method !== 'GET' && request.method !== 'HEAD')
80
+ return null;
81
+ let adapter;
82
+ try {
83
+ adapter = (0, index_1.getMediaService)().rawAdapter;
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ if (!adapter.getPublicObject)
89
+ return null;
90
+ const key = (0, exports.getPublicMediaKey)(pathSegments);
91
+ if (!key)
92
+ return errorResponse(404);
93
+ try {
94
+ const object = await adapter.getPublicObject({
95
+ key,
96
+ method: request.method,
97
+ range: request.headers.get('Range') ?? undefined,
98
+ });
99
+ const headers = buildHeaders(object);
100
+ const status = object.status ?? (object.contentRange ? 206 : 200);
101
+ if (request.headers.get('If-None-Match') === object.etag) {
102
+ return new Response(null, { status: 304, headers });
103
+ }
104
+ return new Response(request.method === 'HEAD' ? null : object.body ?? null, {
105
+ status,
106
+ headers,
107
+ });
108
+ }
109
+ catch (error) {
110
+ return errorResponse(getErrorStatus(error));
111
+ }
112
+ };
113
+ exports.handlePublicMediaRequest = handlePublicMediaRequest;
114
+ //# sourceMappingURL=publicMedia.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicMedia.js","sourceRoot":"","sources":["../../../src/media/publicMedia.ts"],"names":[],"mappings":"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"}
@@ -475,8 +475,12 @@ blocking. Account recovery requires both a mail service and
475
475
 
476
476
  Core defines service contracts; concrete integrations are separate:
477
477
 
478
- - Media: use `@rakun-kit/s3`, or local media from the selected framework
479
- adapter. Configure the result as `media` in bootstrap.
478
+ - Media: use `@rakun-kit/s3`, or local media from the selected framework
479
+ adapter. Configure the result as `media` in bootstrap.
480
+ - Storage adapters may expose `getPublicObject`; Next.js, Express and Bun then
481
+ serve public media through their normal `/media/public/<key>` API route. This
482
+ gives public Rakun media a stable application URL while the backing object
483
+ store remains private or uses expiring storage URLs.
480
484
  - Mail: use `@rakun-kit/smtp` or `@rakun-kit/resend`; optionally render typed
481
485
  templates with `@rakun-kit/jsx-email`. Configure delivery as `mail`.
482
486
  - Translation: use `@rakun-kit/openai` or implement the core translation
@@ -4,6 +4,21 @@ export type PresignedPut = {
4
4
  headers?: Record<string, string>;
5
5
  key: string;
6
6
  };
7
+ export type PublicMediaObject = {
8
+ body?: ReadableStream<Uint8Array>;
9
+ status?: number;
10
+ acceptRanges?: string;
11
+ cacheControl?: string;
12
+ contentDisposition?: string;
13
+ contentEncoding?: string;
14
+ contentLanguage?: string;
15
+ contentLength?: number;
16
+ contentRange?: string;
17
+ contentType?: string;
18
+ etag?: string;
19
+ expires?: Date | string;
20
+ lastModified?: Date | string;
21
+ };
7
22
  export interface StorageAdapter {
8
23
  createPresignedPut(input: {
9
24
  key: string;
@@ -41,5 +56,10 @@ export interface StorageAdapter {
41
56
  key: string;
42
57
  access: MediaAccess;
43
58
  }): string | null;
59
+ getPublicObject?(input: {
60
+ key: string;
61
+ method: 'GET' | 'HEAD';
62
+ range?: string;
63
+ }): Promise<PublicMediaObject>;
44
64
  }
45
65
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/media/adapters/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE9C,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,WAAW,cAAc;IAC7B,kBAAkB,CAAC,KAAK,EAAE;QACxB,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,EAAE,WAAW,CAAA;KACpB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAEzB,SAAS,CAAC,KAAK,EAAE;QACf,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,UAAU,CAAA;QACnB,MAAM,EAAE,WAAW,CAAA;KACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjB,UAAU,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC;QAC/D,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAC,CAAA;IAEF,kBAAkB,CAAC,KAAK,EAAE;QACxB,GAAG,EAAE,MAAM,CAAA;QACX,MAAM,EAAE,WAAW,CAAA;QACnB,gBAAgB,EAAE,MAAM,CAAA;KACzB,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC,CAAA;IAE7C,YAAY,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAExE,SAAS,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,GAAG,MAAM,GAAG,IAAI,CAAA;CACtE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/media/adapters/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE9C,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAA;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;CAC7B,CAAA;AAED,MAAM,WAAW,cAAc;IAC7B,kBAAkB,CAAC,KAAK,EAAE;QACxB,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,EAAE,WAAW,CAAA;KACpB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAEzB,SAAS,CAAC,KAAK,EAAE;QACf,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,UAAU,CAAA;QACnB,MAAM,EAAE,WAAW,CAAA;KACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjB,UAAU,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC;QAC/D,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAC,CAAA;IAEF,kBAAkB,CAAC,KAAK,EAAE;QACxB,GAAG,EAAE,MAAM,CAAA;QACX,MAAM,EAAE,WAAW,CAAA;QACnB,gBAAgB,EAAE,MAAM,CAAA;KACzB,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,CAAC,CAAA;IAE7C,YAAY,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAExE,SAAS,CAAC,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,GAAG,MAAM,GAAG,IAAI,CAAA;IAErE,eAAe,CAAC,CAAC,KAAK,EAAE;QACtB,GAAG,EAAE,MAAM,CAAA;QACX,MAAM,EAAE,KAAK,GAAG,MAAM,CAAA;QACtB,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;CAC/B"}
@@ -11,4 +11,5 @@ export declare function createMediaService(config: MediaServiceConfig): MediaSer
11
11
  export declare function getMediaService(): MediaService;
12
12
  export * from "./mediaService.js";
13
13
  export * from "./adapters/index.js";
14
+ export * from './publicMedia.js';
14
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/media/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,cAAc,CAAC;IACxB,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAKF,eAAO,MAAM,qBAAqB,GAAI,QAAQ,kBAAkB,SAE/D,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAW3E;AAED,wBAAgB,eAAe,IAAI,YAAY,CAY9C;AAED,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/media/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,cAAc,CAAC;IACxB,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAKF,eAAO,MAAM,qBAAqB,GAAI,QAAQ,kBAAkB,SAE/D,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAW3E;AAED,wBAAgB,eAAe,IAAI,YAAY,CAY9C;AAED,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAA"}
@@ -25,4 +25,5 @@ export function getMediaService() {
25
25
  }
26
26
  export * from "./mediaService.js";
27
27
  export * from "./adapters/index.js";
28
+ export * from './publicMedia.js';
28
29
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/media/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,6BAA6B,GAE9B,MAAM,gBAAgB,CAAC;AASxB,IAAI,aAA2B,CAAC;AAChC,IAAI,OAA2B,CAAC;AAEhC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,MAA0B,EAAE,EAAE;IAClE,OAAO,GAAG,MAAM,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,MAA0B;IAC3D,OAAO,GAAG,MAAM,CAAC;IAEjB,aAAa,GAAG,6BAA6B,CAAC;QAC5C,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,0BAA0B,EAAE,MAAM,CAAC,0BAA0B;QAC7D,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC,CAAC;IAEH,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAC;QACJ,CAAC;QAED,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/media/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,6BAA6B,GAE9B,MAAM,gBAAgB,CAAC;AASxB,IAAI,aAA2B,CAAC;AAChC,IAAI,OAA2B,CAAC;AAEhC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,MAA0B,EAAE,EAAE;IAClE,OAAO,GAAG,MAAM,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,MAA0B;IAC3D,OAAO,GAAG,MAAM,CAAC;IAEjB,aAAa,GAAG,6BAA6B,CAAC;QAC5C,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,0BAA0B,EAAE,MAAM,CAAC,0BAA0B;QAC7D,SAAS,EAAE,MAAM,CAAC,SAAS;KAC5B,CAAC,CAAC;IAEH,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAC;QACJ,CAAC;QAED,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAA"}
@@ -0,0 +1,7 @@
1
+ export type HandlePublicMediaRequestInput = {
2
+ request: Request;
3
+ pathSegments: string[];
4
+ };
5
+ export declare const getPublicMediaKey: (pathSegments: string[]) => string | null;
6
+ export declare const handlePublicMediaRequest: ({ request, pathSegments, }: HandlePublicMediaRequestInput) => Promise<Response | null>;
7
+ //# sourceMappingURL=publicMedia.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicMedia.d.ts","sourceRoot":"","sources":["../../../src/media/publicMedia.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB,CAAA;AAYD,eAAO,MAAM,iBAAiB,GAAI,cAAc,MAAM,EAAE,KAAG,MAAM,GAAG,IAOnE,CAAA;AAoED,eAAO,MAAM,wBAAwB,GAAU,4BAG5C,6BAA6B,KAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAkCzD,CAAA"}
@@ -0,0 +1,109 @@
1
+ import { getMediaService } from './index.js';
2
+ const DEFAULT_CACHE_CONTROL = 'public, max-age=31536000, immutable';
3
+ const decodePathSegment = (segment) => {
4
+ try {
5
+ const value = decodeURIComponent(segment);
6
+ if (!value || value === '.' || value === '..' || value.includes('/'))
7
+ return null;
8
+ return value;
9
+ }
10
+ catch {
11
+ return null;
12
+ }
13
+ };
14
+ export const getPublicMediaKey = (pathSegments) => {
15
+ if (pathSegments.length === 0)
16
+ return null;
17
+ const segments = pathSegments.map(decodePathSegment);
18
+ if (segments.some((segment) => segment === null))
19
+ return null;
20
+ return `public/${segments.join('/')}`;
21
+ };
22
+ const errorResponse = (status) => new Response(null, { status });
23
+ const isNotFoundError = (error) => {
24
+ if (!error || typeof error !== 'object')
25
+ return false;
26
+ const value = error;
27
+ return (value.name === 'NotFound' ||
28
+ value.name === 'NoSuchKey' ||
29
+ value.code === 'NotFound' ||
30
+ value.code === 'NoSuchKey' ||
31
+ value.$metadata?.httpStatusCode === 404);
32
+ };
33
+ const getErrorStatus = (error) => {
34
+ if (isNotFoundError(error))
35
+ return 404;
36
+ const status = error && typeof error === 'object'
37
+ ? error.$metadata?.httpStatusCode
38
+ : undefined;
39
+ if (status === 416) {
40
+ return 416;
41
+ }
42
+ return 502;
43
+ };
44
+ const setDateHeader = (headers, name, value) => {
45
+ if (!value)
46
+ return;
47
+ headers.set(name, value instanceof Date ? value.toUTCString() : value);
48
+ };
49
+ const buildHeaders = (object) => {
50
+ const headers = new Headers({
51
+ 'Cache-Control': object.cacheControl ?? DEFAULT_CACHE_CONTROL,
52
+ 'X-Content-Type-Options': 'nosniff',
53
+ });
54
+ if (object.acceptRanges)
55
+ headers.set('Accept-Ranges', object.acceptRanges);
56
+ if (object.contentDisposition)
57
+ headers.set('Content-Disposition', object.contentDisposition);
58
+ if (object.contentEncoding)
59
+ headers.set('Content-Encoding', object.contentEncoding);
60
+ if (object.contentLanguage)
61
+ headers.set('Content-Language', object.contentLanguage);
62
+ if (object.contentLength !== undefined)
63
+ headers.set('Content-Length', String(object.contentLength));
64
+ if (object.contentRange)
65
+ headers.set('Content-Range', object.contentRange);
66
+ if (object.contentType)
67
+ headers.set('Content-Type', object.contentType);
68
+ if (object.etag)
69
+ headers.set('ETag', object.etag);
70
+ setDateHeader(headers, 'Expires', object.expires);
71
+ setDateHeader(headers, 'Last-Modified', object.lastModified);
72
+ return headers;
73
+ };
74
+ export const handlePublicMediaRequest = async ({ request, pathSegments, }) => {
75
+ if (request.method !== 'GET' && request.method !== 'HEAD')
76
+ return null;
77
+ let adapter;
78
+ try {
79
+ adapter = getMediaService().rawAdapter;
80
+ }
81
+ catch {
82
+ return null;
83
+ }
84
+ if (!adapter.getPublicObject)
85
+ return null;
86
+ const key = getPublicMediaKey(pathSegments);
87
+ if (!key)
88
+ return errorResponse(404);
89
+ try {
90
+ const object = await adapter.getPublicObject({
91
+ key,
92
+ method: request.method,
93
+ range: request.headers.get('Range') ?? undefined,
94
+ });
95
+ const headers = buildHeaders(object);
96
+ const status = object.status ?? (object.contentRange ? 206 : 200);
97
+ if (request.headers.get('If-None-Match') === object.etag) {
98
+ return new Response(null, { status: 304, headers });
99
+ }
100
+ return new Response(request.method === 'HEAD' ? null : object.body ?? null, {
101
+ status,
102
+ headers,
103
+ });
104
+ }
105
+ catch (error) {
106
+ return errorResponse(getErrorStatus(error));
107
+ }
108
+ };
109
+ //# sourceMappingURL=publicMedia.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicMedia.js","sourceRoot":"","sources":["../../../src/media/publicMedia.ts"],"names":[],"mappings":"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"}