@ai-matrx/media 0.1.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 +61 -0
- package/LICENSE +21 -0
- package/README.md +106 -0
- package/dist/core.cjs +577 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +214 -0
- package/dist/core.d.ts +214 -0
- package/dist/core.js +559 -0
- package/dist/core.js.map +1 -0
- package/dist/index.cjs +31 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +227 -0
- package/dist/index.d.ts +227 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +2127 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +310 -0
- package/dist/react.d.ts +310 -0
- package/dist/react.js +2120 -0
- package/dist/react.js.map +1 -0
- package/dist/use-media-upload-VjUhqbyY.d.cts +270 -0
- package/dist/use-media-upload-VjUhqbyY.d.ts +270 -0
- package/package.json +114 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ai-matrx/media — the root types: the MediaClient port and the host ports.
|
|
3
|
+
*
|
|
4
|
+
* The package renders Matrx durable media; it NEVER talks to a network.
|
|
5
|
+
* Everything data-shaped arrives through the injected {@link MediaClient}
|
|
6
|
+
* (canonically implemented by `@ai-matrx/data/files`; any structural
|
|
7
|
+
* implementation works — the strangler step wires it over an app's existing
|
|
8
|
+
* file handler). The five file-handling laws are enforced here at the type
|
|
9
|
+
* level:
|
|
10
|
+
*
|
|
11
|
+
* 1. Never fetch a media URL yourself — the package contains zero network
|
|
12
|
+
* primitives; bytes exist only via {@link MediaClient.getBlob}.
|
|
13
|
+
* 2. Off-boundary code resolves media itself — every component takes a
|
|
14
|
+
* {@link MediaRefLike} and calls `resolve()` unconditionally. There is
|
|
15
|
+
* NO `src` prop on any component in this package.
|
|
16
|
+
* 3. A signed URL is a handoff, never an identity — the only string that
|
|
17
|
+
* reaches a media element is the branded {@link DurableSrc}, which only
|
|
18
|
+
* a MediaClient implementation can mint (via {@link mintDurableSrc}).
|
|
19
|
+
* 4. Public-facing media is persisted public, never signed —
|
|
20
|
+
* {@link MediaClient.shareableUrl} fails closed (`null` → the action
|
|
21
|
+
* renders disabled).
|
|
22
|
+
* 5. One URL contract; the engine builds URLs — zero URL construction in
|
|
23
|
+
* this package; `resolve()` is the only door.
|
|
24
|
+
*/
|
|
25
|
+
/** The canonical durable media reference. `file_id` is the identity. */
|
|
26
|
+
interface MediaRef {
|
|
27
|
+
file_id?: string | null;
|
|
28
|
+
url?: string | null;
|
|
29
|
+
mime_type?: string | null;
|
|
30
|
+
metadata?: Record<string, unknown> | null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Identity in. A raw string is a fileId or an EXTERNAL public URL — never a
|
|
34
|
+
* signed URL (the client's `resolve()` classifies and screams on one).
|
|
35
|
+
*/
|
|
36
|
+
type MediaRefLike = MediaRef | string;
|
|
37
|
+
declare const durable: unique symbol;
|
|
38
|
+
/**
|
|
39
|
+
* A URL that has passed through `MediaClient.resolve()` — the only string
|
|
40
|
+
* type any media element in this package will bind. A caller cannot pass an
|
|
41
|
+
* expiring URL through the package's types without an explicit unsafe cast.
|
|
42
|
+
*/
|
|
43
|
+
type DurableSrc = string & {
|
|
44
|
+
readonly [durable]: true;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Brand a URL as durable. FOR MediaClient IMPLEMENTATIONS ONLY — the
|
|
48
|
+
* implementation must classify the URL first (the ONE signed-URL classifier
|
|
49
|
+
* lives with the platform's files layer; never re-implement it here or in a
|
|
50
|
+
* host). Calling this on an unclassified string defeats law 3.
|
|
51
|
+
*/
|
|
52
|
+
declare function mintDurableSrc(url: string): DurableSrc;
|
|
53
|
+
type MediaKind = "image" | "video" | "audio" | "file";
|
|
54
|
+
interface MediaResolution {
|
|
55
|
+
src: DurableSrc;
|
|
56
|
+
/** RN auth lane (`<Image source={{uri, headers}}>`); absent on web (cookie session). */
|
|
57
|
+
headers?: Record<string, string> | undefined;
|
|
58
|
+
mimeType?: string | undefined;
|
|
59
|
+
kind: MediaKind;
|
|
60
|
+
/**
|
|
61
|
+
* How pixels must travel. `"element"` (default): bind `src` directly to the
|
|
62
|
+
* media element. `"blob"`: the bytes require bearer auth the element cannot
|
|
63
|
+
* attach — consumers go through {@link MediaClient.getBlob} and render the
|
|
64
|
+
* returned object URL (the private-image lane).
|
|
65
|
+
*/
|
|
66
|
+
transport?: "element" | "blob" | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* A server-rendered thumbnail for this file, when the client knows one
|
|
69
|
+
* (Matrx: `FileRecord.thumbnail_url` / asset variants). Consumed by the
|
|
70
|
+
* thumbnail tier machine.
|
|
71
|
+
*/
|
|
72
|
+
thumbnailSrc?: DurableSrc | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* True when this is a permanent public CDN URL — lets a host-supplied
|
|
75
|
+
* `ImageComponent` (e.g. a next/image adapter) take the render, and marks
|
|
76
|
+
* the URL CORS-safe for element-level `crossOrigin`.
|
|
77
|
+
*/
|
|
78
|
+
isCdn?: boolean | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Whether a load error can be recovered by the client's ONE retry policy
|
|
81
|
+
* (session-refresh → same-URL retry). False for foreign/external URLs —
|
|
82
|
+
* a session refresh can't resurrect someone else's link rot. Default true.
|
|
83
|
+
*/
|
|
84
|
+
recoverable?: boolean | undefined;
|
|
85
|
+
}
|
|
86
|
+
/** Typed unavailable states — render-as-state, never thrown as incidents. */
|
|
87
|
+
type MediaUnavailableReason = "access_denied" | "not_found" | "deleted" | "unknown";
|
|
88
|
+
interface MediaBlobHandle {
|
|
89
|
+
/** `blob:` object URL safe for any browser API. */
|
|
90
|
+
url: string;
|
|
91
|
+
blob: Blob;
|
|
92
|
+
/** Release the handle. Implementations backed by a shared cache may no-op. */
|
|
93
|
+
release(): void;
|
|
94
|
+
}
|
|
95
|
+
interface MediaUploadOptions {
|
|
96
|
+
onProgress?: ((loaded: number, total: number) => void) | undefined;
|
|
97
|
+
fileName?: string | undefined;
|
|
98
|
+
mimeType?: string | undefined;
|
|
99
|
+
/** Host visibility vocabulary passes through structurally. */
|
|
100
|
+
visibility?: string | undefined;
|
|
101
|
+
parentFolderId?: string | null | undefined;
|
|
102
|
+
metadata?: Record<string, unknown> | undefined;
|
|
103
|
+
}
|
|
104
|
+
/** Upload → durable identity. `fileId` is required at compile time and runtime. */
|
|
105
|
+
interface MediaUploadResult {
|
|
106
|
+
fileId: string;
|
|
107
|
+
ref: MediaRef;
|
|
108
|
+
}
|
|
109
|
+
interface MediaMultiUploadResult {
|
|
110
|
+
/** File ids for every successful upload. */
|
|
111
|
+
uploaded: string[];
|
|
112
|
+
/** Per-file failure with the real backend error message. */
|
|
113
|
+
failed: Array<{
|
|
114
|
+
name: string;
|
|
115
|
+
error: string;
|
|
116
|
+
}>;
|
|
117
|
+
/** True when the host's pre-flight (e.g. a duplicate dialog) cancelled the batch. */
|
|
118
|
+
cancelled: boolean;
|
|
119
|
+
}
|
|
120
|
+
interface MediaClient {
|
|
121
|
+
/**
|
|
122
|
+
* Synchronous durable-URL build + classification. Returns `null` when the
|
|
123
|
+
* ref carries no usable identity (components render their fallback).
|
|
124
|
+
* THROWS (and screams via its own diagnostics sink) on a signed/expiring
|
|
125
|
+
* URL — the D108 guard lives behind this door.
|
|
126
|
+
*/
|
|
127
|
+
resolve(ref: MediaRefLike): MediaResolution | null;
|
|
128
|
+
/** Bytes for canvas/crossOrigin/private-pixel consumers. */
|
|
129
|
+
getBlob(ref: MediaRefLike): Promise<MediaBlobHandle>;
|
|
130
|
+
/**
|
|
131
|
+
* Session bootstrap + the ONE retry policy: refresh-then-same-URL-retry,
|
|
132
|
+
* second failure terminal. Called by the package's onError path, never
|
|
133
|
+
* re-implemented.
|
|
134
|
+
*/
|
|
135
|
+
recoverLoadError(src: DurableSrc, attempt: number): Promise<"retry" | "terminal">;
|
|
136
|
+
/** Upload → durable identity. */
|
|
137
|
+
upload(file: File | Blob, opts?: MediaUploadOptions): Promise<MediaUploadResult>;
|
|
138
|
+
/**
|
|
139
|
+
* Optional batch upload with host pre-flight (dedup dialogs etc.). When
|
|
140
|
+
* absent, `useMediaUpload().uploadMany` falls back to sequential `upload`.
|
|
141
|
+
*/
|
|
142
|
+
uploadMany?(files: File[], opts?: MediaUploadOptions): Promise<MediaMultiUploadResult>;
|
|
143
|
+
/** Share affordances — fails closed (null), never emits a signed URL. */
|
|
144
|
+
shareableUrl(ref: MediaRefLike): Promise<string | null>;
|
|
145
|
+
/** Typed unavailable states — render-as-state, never thrown as incidents. */
|
|
146
|
+
classifyError(err: unknown): MediaUnavailableReason;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Structural component slot. `(props) => unknown` keeps the root entry free
|
|
150
|
+
* of React type imports; any React function component satisfies it.
|
|
151
|
+
*/
|
|
152
|
+
type MediaSlotComponent<P> = (props: P) => unknown;
|
|
153
|
+
interface MediaImageComponentProps {
|
|
154
|
+
src: string;
|
|
155
|
+
alt: string;
|
|
156
|
+
width: number;
|
|
157
|
+
height: number;
|
|
158
|
+
className?: string | undefined;
|
|
159
|
+
onError?: ((event: unknown) => void) | undefined;
|
|
160
|
+
onClick?: ((event: unknown) => void) | undefined;
|
|
161
|
+
onKeyDown?: ((event: unknown) => void) | undefined;
|
|
162
|
+
role?: string | undefined;
|
|
163
|
+
tabIndex?: number | undefined;
|
|
164
|
+
}
|
|
165
|
+
interface PlaybackSessionRegistration {
|
|
166
|
+
isPlaying: boolean;
|
|
167
|
+
source: string;
|
|
168
|
+
label: string;
|
|
169
|
+
trackKey?: string | undefined;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* The host's audio system (exclusive-playback lock, output-sink routing).
|
|
173
|
+
* Both members are HOOKS — the package calls them unconditionally on every
|
|
174
|
+
* render of a media element, so implementations must obey the Rules of Hooks
|
|
175
|
+
* and the port object must be referentially stable.
|
|
176
|
+
*/
|
|
177
|
+
interface PlaybackSessionPort {
|
|
178
|
+
/**
|
|
179
|
+
* Returns a ref callback for the underlying media element (routes audio
|
|
180
|
+
* output / setSinkId on hosts that support it) and forwards to the caller's
|
|
181
|
+
* own element ref.
|
|
182
|
+
*/
|
|
183
|
+
useMediaElementSink(forward: ((node: unknown) => void) | {
|
|
184
|
+
current: unknown;
|
|
185
|
+
} | null | undefined): (node: unknown) => void;
|
|
186
|
+
/** Joins the host's unified playback session for the element. */
|
|
187
|
+
usePlaybackSession(registration: PlaybackSessionRegistration, elementRef: {
|
|
188
|
+
current: unknown;
|
|
189
|
+
}): void;
|
|
190
|
+
}
|
|
191
|
+
type MediaActionKind = "share" | "download" | "copy" | "open";
|
|
192
|
+
interface MediaActionContext {
|
|
193
|
+
ref: MediaRefLike;
|
|
194
|
+
resolution: MediaResolution | null;
|
|
195
|
+
fileName?: string | undefined;
|
|
196
|
+
alt?: string | undefined;
|
|
197
|
+
}
|
|
198
|
+
interface MediaSharePopoverProps {
|
|
199
|
+
context: MediaActionContext;
|
|
200
|
+
onClose: () => void;
|
|
201
|
+
}
|
|
202
|
+
type MediaActionHandler = (ctx: MediaActionContext) => Promise<void>;
|
|
203
|
+
interface MediaActionsPort {
|
|
204
|
+
/**
|
|
205
|
+
* Quick-share handler (copy a share link, open the native share sheet…).
|
|
206
|
+
* Implementations obtain URLs ONLY via `MediaClient.shareableUrl` /
|
|
207
|
+
* durable identities — never a signed URL (law 4).
|
|
208
|
+
*/
|
|
209
|
+
share?: MediaActionHandler | undefined;
|
|
210
|
+
download?: MediaActionHandler | undefined;
|
|
211
|
+
copy?: MediaActionHandler | undefined;
|
|
212
|
+
open?: MediaActionHandler | undefined;
|
|
213
|
+
/**
|
|
214
|
+
* Rich share UI body — the slot the associations package fills. When
|
|
215
|
+
* present, the shells open it instead of (or on top of) the `share`
|
|
216
|
+
* handler. Receives {@link MediaSharePopoverProps}.
|
|
217
|
+
*/
|
|
218
|
+
SharePopover?: MediaSlotComponent<MediaSharePopoverProps> | undefined;
|
|
219
|
+
}
|
|
220
|
+
interface MediaHostPorts {
|
|
221
|
+
playbackSession?: PlaybackSessionPort | undefined;
|
|
222
|
+
actions?: MediaActionsPort | undefined;
|
|
223
|
+
/** Web host may pass a next/image adapter; default is a plain `<img>`. */
|
|
224
|
+
ImageComponent?: MediaSlotComponent<MediaImageComponentProps> | undefined;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export { type DurableSrc, type MediaActionContext, type MediaActionHandler, type MediaActionKind, type MediaActionsPort, type MediaBlobHandle, type MediaClient, type MediaHostPorts, type MediaImageComponentProps, type MediaKind, type MediaMultiUploadResult, type MediaRef, type MediaRefLike, type MediaResolution, type MediaSharePopoverProps, type MediaSlotComponent, type MediaUnavailableReason, type MediaUploadOptions, type MediaUploadResult, type PlaybackSessionPort, type PlaybackSessionRegistration, mintDurableSrc };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * @ai-matrx/media — the root types: the MediaClient port and the host ports.\n *\n * The package renders Matrx durable media; it NEVER talks to a network.\n * Everything data-shaped arrives through the injected {@link MediaClient}\n * (canonically implemented by `@ai-matrx/data/files`; any structural\n * implementation works — the strangler step wires it over an app's existing\n * file handler). The five file-handling laws are enforced here at the type\n * level:\n *\n * 1. Never fetch a media URL yourself — the package contains zero network\n * primitives; bytes exist only via {@link MediaClient.getBlob}.\n * 2. Off-boundary code resolves media itself — every component takes a\n * {@link MediaRefLike} and calls `resolve()` unconditionally. There is\n * NO `src` prop on any component in this package.\n * 3. A signed URL is a handoff, never an identity — the only string that\n * reaches a media element is the branded {@link DurableSrc}, which only\n * a MediaClient implementation can mint (via {@link mintDurableSrc}).\n * 4. Public-facing media is persisted public, never signed —\n * {@link MediaClient.shareableUrl} fails closed (`null` → the action\n * renders disabled).\n * 5. One URL contract; the engine builds URLs — zero URL construction in\n * this package; `resolve()` is the only door.\n */\n\n// ---------------------------------------------------------------------------\n// Identity\n// ---------------------------------------------------------------------------\n\n/** The canonical durable media reference. `file_id` is the identity. */\nexport interface MediaRef {\n file_id?: string | null;\n url?: string | null;\n mime_type?: string | null;\n metadata?: Record<string, unknown> | null;\n}\n\n/**\n * Identity in. A raw string is a fileId or an EXTERNAL public URL — never a\n * signed URL (the client's `resolve()` classifies and screams on one).\n */\nexport type MediaRefLike = MediaRef | string;\n\ndeclare const durable: unique symbol;\n\n/**\n * A URL that has passed through `MediaClient.resolve()` — the only string\n * type any media element in this package will bind. A caller cannot pass an\n * expiring URL through the package's types without an explicit unsafe cast.\n */\nexport type DurableSrc = string & { readonly [durable]: true };\n\n/**\n * Brand a URL as durable. FOR MediaClient IMPLEMENTATIONS ONLY — the\n * implementation must classify the URL first (the ONE signed-URL classifier\n * lives with the platform's files layer; never re-implement it here or in a\n * host). Calling this on an unclassified string defeats law 3.\n */\nexport function mintDurableSrc(url: string): DurableSrc {\n return url as DurableSrc;\n}\n\n// ---------------------------------------------------------------------------\n// Resolution\n// ---------------------------------------------------------------------------\n\nexport type MediaKind = \"image\" | \"video\" | \"audio\" | \"file\";\n\nexport interface MediaResolution {\n src: DurableSrc;\n /** RN auth lane (`<Image source={{uri, headers}}>`); absent on web (cookie session). */\n headers?: Record<string, string> | undefined;\n mimeType?: string | undefined;\n kind: MediaKind;\n /**\n * How pixels must travel. `\"element\"` (default): bind `src` directly to the\n * media element. `\"blob\"`: the bytes require bearer auth the element cannot\n * attach — consumers go through {@link MediaClient.getBlob} and render the\n * returned object URL (the private-image lane).\n */\n transport?: \"element\" | \"blob\" | undefined;\n /**\n * A server-rendered thumbnail for this file, when the client knows one\n * (Matrx: `FileRecord.thumbnail_url` / asset variants). Consumed by the\n * thumbnail tier machine.\n */\n thumbnailSrc?: DurableSrc | undefined;\n /**\n * True when this is a permanent public CDN URL — lets a host-supplied\n * `ImageComponent` (e.g. a next/image adapter) take the render, and marks\n * the URL CORS-safe for element-level `crossOrigin`.\n */\n isCdn?: boolean | undefined;\n /**\n * Whether a load error can be recovered by the client's ONE retry policy\n * (session-refresh → same-URL retry). False for foreign/external URLs —\n * a session refresh can't resurrect someone else's link rot. Default true.\n */\n recoverable?: boolean | undefined;\n}\n\n/** Typed unavailable states — render-as-state, never thrown as incidents. */\nexport type MediaUnavailableReason =\n | \"access_denied\"\n | \"not_found\"\n | \"deleted\"\n | \"unknown\";\n\n// ---------------------------------------------------------------------------\n// Bytes / upload\n// ---------------------------------------------------------------------------\n\nexport interface MediaBlobHandle {\n /** `blob:` object URL safe for any browser API. */\n url: string;\n blob: Blob;\n /** Release the handle. Implementations backed by a shared cache may no-op. */\n release(): void;\n}\n\nexport interface MediaUploadOptions {\n onProgress?: ((loaded: number, total: number) => void) | undefined;\n fileName?: string | undefined;\n mimeType?: string | undefined;\n /** Host visibility vocabulary passes through structurally. */\n visibility?: string | undefined;\n parentFolderId?: string | null | undefined;\n metadata?: Record<string, unknown> | undefined;\n}\n\n/** Upload → durable identity. `fileId` is required at compile time and runtime. */\nexport interface MediaUploadResult {\n fileId: string;\n ref: MediaRef;\n}\n\nexport interface MediaMultiUploadResult {\n /** File ids for every successful upload. */\n uploaded: string[];\n /** Per-file failure with the real backend error message. */\n failed: Array<{ name: string; error: string }>;\n /** True when the host's pre-flight (e.g. a duplicate dialog) cancelled the batch. */\n cancelled: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// THE port — one structural interface, owned by this package, implemented by\n// the data layer (canonically `@ai-matrx/data/files`).\n// ---------------------------------------------------------------------------\n\nexport interface MediaClient {\n /**\n * Synchronous durable-URL build + classification. Returns `null` when the\n * ref carries no usable identity (components render their fallback).\n * THROWS (and screams via its own diagnostics sink) on a signed/expiring\n * URL — the D108 guard lives behind this door.\n */\n resolve(ref: MediaRefLike): MediaResolution | null;\n /** Bytes for canvas/crossOrigin/private-pixel consumers. */\n getBlob(ref: MediaRefLike): Promise<MediaBlobHandle>;\n /**\n * Session bootstrap + the ONE retry policy: refresh-then-same-URL-retry,\n * second failure terminal. Called by the package's onError path, never\n * re-implemented.\n */\n recoverLoadError(src: DurableSrc, attempt: number): Promise<\"retry\" | \"terminal\">;\n /** Upload → durable identity. */\n upload(file: File | Blob, opts?: MediaUploadOptions): Promise<MediaUploadResult>;\n /**\n * Optional batch upload with host pre-flight (dedup dialogs etc.). When\n * absent, `useMediaUpload().uploadMany` falls back to sequential `upload`.\n */\n uploadMany?(files: File[], opts?: MediaUploadOptions): Promise<MediaMultiUploadResult>;\n /** Share affordances — fails closed (null), never emits a signed URL. */\n shareableUrl(ref: MediaRefLike): Promise<string | null>;\n /** Typed unavailable states — render-as-state, never thrown as incidents. */\n classifyError(err: unknown): MediaUnavailableReason;\n}\n\n// ---------------------------------------------------------------------------\n// Host ports — all optional, all defaulting to inert.\n// ---------------------------------------------------------------------------\n\n/**\n * Structural component slot. `(props) => unknown` keeps the root entry free\n * of React type imports; any React function component satisfies it.\n */\nexport type MediaSlotComponent<P> = (props: P) => unknown;\n\nexport interface MediaImageComponentProps {\n src: string;\n alt: string;\n width: number;\n height: number;\n className?: string | undefined;\n onError?: ((event: unknown) => void) | undefined;\n onClick?: ((event: unknown) => void) | undefined;\n onKeyDown?: ((event: unknown) => void) | undefined;\n role?: string | undefined;\n tabIndex?: number | undefined;\n}\n\nexport interface PlaybackSessionRegistration {\n isPlaying: boolean;\n source: string;\n label: string;\n trackKey?: string | undefined;\n}\n\n/**\n * The host's audio system (exclusive-playback lock, output-sink routing).\n * Both members are HOOKS — the package calls them unconditionally on every\n * render of a media element, so implementations must obey the Rules of Hooks\n * and the port object must be referentially stable.\n */\nexport interface PlaybackSessionPort {\n /**\n * Returns a ref callback for the underlying media element (routes audio\n * output / setSinkId on hosts that support it) and forwards to the caller's\n * own element ref.\n */\n useMediaElementSink(\n forward:\n | ((node: unknown) => void)\n | { current: unknown }\n | null\n | undefined,\n ): (node: unknown) => void;\n /** Joins the host's unified playback session for the element. */\n usePlaybackSession(\n registration: PlaybackSessionRegistration,\n elementRef: { current: unknown },\n ): void;\n}\n\n// ---------------------------------------------------------------------------\n// THE SHARE MANDATE (C19) — the complete headless media-actions contract.\n//\n// v0.1 ships this contract plus toolbar/lightbox shells wired to it, typed so\n// the associations/sharing package can plug in WITHOUT a media release: it\n// implements MediaActionsPort (handlers and/or the SharePopover body) and the\n// host injects it through MediaHostPorts. Nothing here may change shape in a\n// breaking way for that wave.\n// ---------------------------------------------------------------------------\n\nexport type MediaActionKind = \"share\" | \"download\" | \"copy\" | \"open\";\n\nexport interface MediaActionContext {\n ref: MediaRefLike;\n resolution: MediaResolution | null;\n fileName?: string | undefined;\n alt?: string | undefined;\n}\n\nexport interface MediaSharePopoverProps {\n context: MediaActionContext;\n onClose: () => void;\n}\n\nexport type MediaActionHandler = (ctx: MediaActionContext) => Promise<void>;\n\nexport interface MediaActionsPort {\n /**\n * Quick-share handler (copy a share link, open the native share sheet…).\n * Implementations obtain URLs ONLY via `MediaClient.shareableUrl` /\n * durable identities — never a signed URL (law 4).\n */\n share?: MediaActionHandler | undefined;\n download?: MediaActionHandler | undefined;\n copy?: MediaActionHandler | undefined;\n open?: MediaActionHandler | undefined;\n /**\n * Rich share UI body — the slot the associations package fills. When\n * present, the shells open it instead of (or on top of) the `share`\n * handler. Receives {@link MediaSharePopoverProps}.\n */\n SharePopover?: MediaSlotComponent<MediaSharePopoverProps> | undefined;\n}\n\nexport interface MediaHostPorts {\n playbackSession?: PlaybackSessionPort | undefined;\n actions?: MediaActionsPort | undefined;\n /** Web host may pass a next/image adapter; default is a plain `<img>`. */\n ImageComponent?: MediaSlotComponent<MediaImageComponentProps> | undefined;\n}\n"],"mappings":";AA0DO,SAAS,eAAe,KAAyB;AACtD,SAAO;AACT;","names":[]}
|