@rakun-kit/core 1.7.0 → 1.7.2

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
@@ -90,16 +90,16 @@ rakunBootstrap({
90
90
  })
91
91
  ```
92
92
 
93
- The default image processor is native `Bun.Image` when available and `sharp`
94
- otherwise. Node.js image optimization therefore requires the optional `sharp`
95
- peer. Bun also falls back to it when an OS-dependent codec cannot handle the
96
- requested format. Custom `ImageProcessor` implementations provide
97
- `metadata`, `transform`, and `placeholder`; the latter returns an inline
98
- `{ dataUrl, mime }` LQIP. Bun uses native `Bun.Image.placeholder()`, while
99
- Sharp produces the placeholder through its normal reduced transform and serves
100
- as the fallback when the Bun method is unavailable. The
101
- platform resolves crypto, filesystem, compression,
102
- workers, and realtime capabilities. Polling is the safe realtime default when
93
+ The default image processor is native `Bun.Image` when available and `sharp`
94
+ otherwise. Node.js image optimization therefore requires the optional `sharp`
95
+ peer. Bun also falls back to it when an OS-dependent codec cannot handle the
96
+ requested format. Custom `ImageProcessor` implementations provide
97
+ `metadata`, `transform`, and `placeholder`; the latter returns an inline
98
+ `{ dataUrl, mime }` LQIP. Bun uses native `Bun.Image.placeholder()`, while
99
+ Sharp produces the placeholder through its normal reduced transform and serves
100
+ as the fallback when the Bun method is unavailable. The
101
+ platform resolves crypto, filesystem, compression,
102
+ workers, and realtime capabilities. Polling is the safe realtime default when
103
103
  the host cannot keep persistent connections open. The Next and Express
104
104
  adapters automatically serve configured SSE streams.
105
105
  Calling `sseRealtime()` uses the API-relative `/realtime` endpoint; pass an
@@ -127,12 +127,12 @@ keyed by its content type and `_id`. Editor updates synchronize through the
127
127
  authenticated `manager.contentCollaboration.sync` operation without changing
128
128
  the MongoDB content snapshot or triggering revalidation. Save calls
129
129
  `manager.contentCollaboration.save`, which materializes and validates the
130
- server-side CRDT state before using the normal update and revalidation flow.
131
- Draft promotion remains separate and promotes only a saved draft snapshot.
132
- `manager.contentCollaboration.discard` restores the room from that persisted
133
- snapshot, publishes the reset to connected editors, and marks the restored Yjs
134
- state as saved without creating a new content revision. Shared templates expose
135
- the equivalent `manager.templateCollaboration.discard` operation.
130
+ server-side CRDT state before using the normal update and revalidation flow.
131
+ Draft promotion remains separate and promotes only a saved draft snapshot.
132
+ `manager.contentCollaboration.discard` restores the room from that persisted
133
+ snapshot, publishes the reset to connected editors, and marks the restored Yjs
134
+ state as saved without creating a new content revision. Shared templates expose
135
+ the equivalent `manager.templateCollaboration.discard` operation.
136
136
 
137
137
  The default adapter keeps working documents in process memory. Configure a
138
138
  shared, durable implementation for replicated or restart-durable deployments:
@@ -142,33 +142,33 @@ rakunBootstrap({
142
142
  // ...
143
143
  collaboration: {
144
144
  adapter: {
145
- load: async (roomId) => loadRoom(roomId),
146
- save: async (roomId, state) => saveRoom(roomId, state),
147
- loadPresence: async (roomId) => loadRoomPresence(roomId),
148
- savePresence: async (roomId, presence) => saveRoomPresence(roomId, presence),
149
- delete: async (roomId) => deleteRoom(roomId),
145
+ load: async (roomId) => loadRoom(roomId),
146
+ save: async (roomId, state) => saveRoom(roomId, state),
147
+ loadPresence: async (roomId) => loadRoomPresence(roomId),
148
+ savePresence: async (roomId, presence) => saveRoomPresence(roomId, presence),
149
+ delete: async (roomId) => deleteRoom(roomId),
150
150
  },
151
151
  },
152
152
  })
153
153
  ```
154
154
 
155
155
  `state.update` and `state.savedStateVector` are opaque `Uint8Array` values.
156
- Store them outside the public content record. The built-in manager applies this
156
+ Store them outside the public content record. The built-in manager applies this
157
157
  to saved content edit screens and to each content type's shared Template.
158
158
  Templates use their own `template:<contentType>` room rather than an individual
159
159
  document room. Settings, route-layout overrides, and other administrative forms
160
160
  remain local. Translation changes join the working document and are persisted
161
- only by Save.
162
-
163
- The sync response also includes ephemeral viewers keyed by browser-tab client
164
- id, including the focused field. Presence expires automatically and is not
165
- part of `state.update`, `state.savedStateVector`, or the persistent event log.
166
- With SSE, the authenticated subscription owns the tab presence: server
167
- heartbeats renew it and closing the last stream for that tab removes it, so the
168
- manager does not send a periodic collaboration sync request just to stay
169
- visible. Polling refreshes presence through its normal sync cycle.
170
- `loadPresence` and `savePresence` are optional; implement both in replicated
171
- deployments that need presence shared across processes.
161
+ only by Save.
162
+
163
+ The sync response also includes ephemeral viewers keyed by browser-tab client
164
+ id, including the focused field. Presence expires automatically and is not
165
+ part of `state.update`, `state.savedStateVector`, or the persistent event log.
166
+ With SSE, the authenticated subscription owns the tab presence: server
167
+ heartbeats renew it and closing the last stream for that tab removes it, so the
168
+ manager does not send a periodic collaboration sync request just to stay
169
+ visible. Polling refreshes presence through its normal sync cycle.
170
+ `loadPresence` and `savePresence` are optional; implement both in replicated
171
+ deployments that need presence shared across processes.
172
172
 
173
173
  `@rakun-kit/manager-react` additionally stores these Yjs rooms per user in
174
174
  IndexedDB, allowing cached content and Template fields to remain editable during
@@ -1155,6 +1155,14 @@ APIs:
1155
1155
 
1156
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
1157
 
1158
+ Adapters can implement `getPublicObject` to let every Rakun server adapter proxy
1159
+ public media at its normal `/media/<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.
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
 
1160
1168
  Existing images and videos can be reimported from the media manager with the selected optimization settings. The replacement uses new storage keys and updates the existing `Media` record only after every requested variant has been written, preserving its ID and content references. Preview generation stores a compact `data:image/...` string on `previewUrl` for LQIP use in `@rakun-kit/react` `Image`, instead of writing a separate preview object to storage.
@@ -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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"}
@@ -477,6 +477,10 @@ Core defines service contracts; concrete integrations are separate:
477
477
 
478
478
  - Media: use `@rakun-kit/s3`, or local media from the selected framework
479
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/<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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"}