@01.software/sdk 0.2.9-dev.260314.f493447 → 0.4.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/README.md +5 -2
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/const-BpirbGBD.d.cts +19 -0
- package/dist/const-qZSQiSSC.d.ts +19 -0
- package/dist/index.cjs +229 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +114 -196
- package/dist/index.d.ts +114 -196
- package/dist/index.js +229 -79
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-ggU6BNuH.d.cts → payload-types-CZiaL4Wr.d.cts} +6 -5
- package/dist/{payload-types-ggU6BNuH.d.ts → payload-types-CZiaL4Wr.d.ts} +6 -5
- package/dist/realtime-DupPIYx-.d.cts +33 -0
- package/dist/realtime-DupPIYx-.d.ts +33 -0
- package/dist/realtime.cjs +261 -0
- package/dist/realtime.cjs.map +1 -0
- package/dist/realtime.d.cts +38 -0
- package/dist/realtime.d.ts +38 -0
- package/dist/realtime.js +239 -0
- package/dist/realtime.js.map +1 -0
- package/dist/ui/code-block.cjs +3 -1
- package/dist/ui/code-block.cjs.map +1 -1
- package/dist/ui/code-block.js +4 -2
- package/dist/ui/code-block.js.map +1 -1
- package/dist/ui/flow.cjs +18 -3
- package/dist/ui/flow.cjs.map +1 -1
- package/dist/ui/flow.js +18 -3
- package/dist/ui/flow.js.map +1 -1
- package/dist/ui/form.d.cts +1 -1
- package/dist/ui/form.d.ts +1 -1
- package/dist/ui/video.cjs +219 -0
- package/dist/ui/video.cjs.map +1 -0
- package/dist/ui/video.d.cts +96 -0
- package/dist/ui/video.d.ts +96 -0
- package/dist/ui/video.js +191 -0
- package/dist/ui/video.js.map +1 -0
- package/dist/video-DbLL8yuc.d.cts +85 -0
- package/dist/video-DbLL8yuc.d.ts +85 -0
- package/dist/webhook-3iL9OEyq.d.cts +20 -0
- package/dist/webhook-DuTqrH9x.d.ts +20 -0
- package/dist/webhook.cjs +8 -8
- package/dist/webhook.cjs.map +1 -1
- package/dist/webhook.d.cts +3 -2
- package/dist/webhook.d.ts +3 -2
- package/dist/webhook.js +8 -8
- package/dist/webhook.js.map +1 -1
- package/package.json +29 -4
- package/dist/webhook-B54a-HGd.d.ts +0 -35
- package/dist/webhook-DInps2xX.d.cts +0 -35
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React, { CSSProperties } from 'react';
|
|
2
|
+
import { MuxPlayerProps, MuxPlayerRefAttributes } from '@mux/mux-player-react';
|
|
3
|
+
export { MuxPlayerRefAttributes as VideoPlayerRef } from '@mux/mux-player-react';
|
|
4
|
+
import { V as Video } from '../payload-types-CZiaL4Wr.js';
|
|
5
|
+
export { e as VideoGifOptions, V as VideoThumbnailOptions, a as getVideoGif, c as getVideoMp4Url, d as getVideoStoryboard, b as getVideoStreamUrl, g as getVideoThumbnail } from '../video-DbLL8yuc.js';
|
|
6
|
+
|
|
7
|
+
interface VideoPlayerCSSProperties extends CSSProperties {
|
|
8
|
+
[key: `--${string}`]: string | undefined;
|
|
9
|
+
}
|
|
10
|
+
interface VideoPlayerProps {
|
|
11
|
+
/** Video document or playbackId string */
|
|
12
|
+
video: Video | string;
|
|
13
|
+
/** Theme accent color */
|
|
14
|
+
accentColor?: string;
|
|
15
|
+
/** Theme primary color (controls) */
|
|
16
|
+
primaryColor?: string;
|
|
17
|
+
/** Theme secondary color (time display, etc.) */
|
|
18
|
+
secondaryColor?: string;
|
|
19
|
+
/** Title overlay (auto-resolved from Video.title if omitted) */
|
|
20
|
+
title?: string;
|
|
21
|
+
/** Autoplay behavior */
|
|
22
|
+
autoPlay?: boolean | 'muted' | 'any';
|
|
23
|
+
/** Loop playback */
|
|
24
|
+
loop?: boolean;
|
|
25
|
+
/** Muted by default */
|
|
26
|
+
muted?: boolean;
|
|
27
|
+
/** Preload strategy (default: 'metadata') */
|
|
28
|
+
preload?: 'auto' | 'metadata' | 'none';
|
|
29
|
+
/** Start time in seconds */
|
|
30
|
+
startTime?: number;
|
|
31
|
+
/** Stream type (default: 'on-demand') */
|
|
32
|
+
streamType?: 'on-demand' | 'live' | 'll-live';
|
|
33
|
+
/** Audio-only mode */
|
|
34
|
+
audio?: boolean;
|
|
35
|
+
/** Disable keyboard shortcuts */
|
|
36
|
+
noHotKeys?: boolean;
|
|
37
|
+
/** Max resolution cap */
|
|
38
|
+
maxResolution?: '720p' | '1080p' | '1440p' | '2160p';
|
|
39
|
+
/** Thumbnail time for auto-generated poster (default: 0) */
|
|
40
|
+
thumbnailTime?: number;
|
|
41
|
+
/** Custom poster URL (overrides auto-generated thumbnail) */
|
|
42
|
+
poster?: string;
|
|
43
|
+
/** Placeholder text when video is not ready */
|
|
44
|
+
placeholder?: string;
|
|
45
|
+
/** CSS class for the placeholder */
|
|
46
|
+
placeholderClassName?: string;
|
|
47
|
+
/** Inline styles for the placeholder */
|
|
48
|
+
placeholderStyle?: CSSProperties;
|
|
49
|
+
/** CSS class */
|
|
50
|
+
className?: string;
|
|
51
|
+
/** Inline styles (supports --mux CSS custom properties) */
|
|
52
|
+
style?: VideoPlayerCSSProperties;
|
|
53
|
+
onPlay?: () => void;
|
|
54
|
+
onPause?: () => void;
|
|
55
|
+
onEnded?: () => void;
|
|
56
|
+
onTimeUpdate?: () => void;
|
|
57
|
+
onLoadedData?: () => void;
|
|
58
|
+
onError?: () => void;
|
|
59
|
+
/** Extra props forwarded directly to MuxPlayer */
|
|
60
|
+
playerProps?: Omit<MuxPlayerProps, 'playbackId' | 'streamType' | 'accentColor' | 'primaryColor' | 'secondaryColor' | 'title' | 'autoPlay' | 'loop' | 'muted' | 'preload' | 'startTime' | 'poster' | 'audio' | 'nohotkeys' | 'maxResolution' | 'className' | 'style'>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Mux video player component.
|
|
64
|
+
* Requires `@mux/mux-player-react` (optional peer dependency).
|
|
65
|
+
*
|
|
66
|
+
* @example Basic usage
|
|
67
|
+
* ```tsx
|
|
68
|
+
* import { VideoPlayer } from '@01.software/sdk/ui/video'
|
|
69
|
+
*
|
|
70
|
+
* <VideoPlayer video={videoDoc} />
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @example With playback ID string
|
|
74
|
+
* ```tsx
|
|
75
|
+
* <VideoPlayer video="abc123def" autoPlay="muted" loop />
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @example Custom theming with CSS custom properties
|
|
79
|
+
* ```tsx
|
|
80
|
+
* <VideoPlayer
|
|
81
|
+
* video={videoDoc}
|
|
82
|
+
* accentColor="#f43f5e"
|
|
83
|
+
* primaryColor="#fff"
|
|
84
|
+
* className="rounded-lg overflow-hidden"
|
|
85
|
+
* style={{ '--controls-backdrop-color': 'rgba(0,0,0,0.6)' }}
|
|
86
|
+
* />
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @example Audio-only mode
|
|
90
|
+
* ```tsx
|
|
91
|
+
* <VideoPlayer video={videoDoc} audio />
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
declare const VideoPlayer: React.ForwardRefExoticComponent<VideoPlayerProps & React.RefAttributes<MuxPlayerRefAttributes>>;
|
|
95
|
+
|
|
96
|
+
export { Video as VideoData, VideoPlayer, type VideoPlayerCSSProperties, type VideoPlayerProps };
|
package/dist/ui/video.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
6
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
|
+
var __spreadValues = (a, b) => {
|
|
8
|
+
for (var prop in b || (b = {}))
|
|
9
|
+
if (__hasOwnProp.call(b, prop))
|
|
10
|
+
__defNormalProp(a, prop, b[prop]);
|
|
11
|
+
if (__getOwnPropSymbols)
|
|
12
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
13
|
+
if (__propIsEnum.call(b, prop))
|
|
14
|
+
__defNormalProp(a, prop, b[prop]);
|
|
15
|
+
}
|
|
16
|
+
return a;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// src/ui/Video/index.tsx
|
|
20
|
+
import React, { forwardRef } from "react";
|
|
21
|
+
import MuxPlayer from "@mux/mux-player-react";
|
|
22
|
+
|
|
23
|
+
// src/utils/video.ts
|
|
24
|
+
var MUX_IMAGE_BASE = "https://image.mux.com";
|
|
25
|
+
var MUX_STREAM_BASE = "https://stream.mux.com";
|
|
26
|
+
function getVideoThumbnail(playbackId, options) {
|
|
27
|
+
var _a;
|
|
28
|
+
const params = new URLSearchParams();
|
|
29
|
+
params.set("width", String((_a = options == null ? void 0 : options.width) != null ? _a : 640));
|
|
30
|
+
if (options == null ? void 0 : options.height) params.set("height", String(options.height));
|
|
31
|
+
if ((options == null ? void 0 : options.time) != null) params.set("time", String(options.time));
|
|
32
|
+
if (options == null ? void 0 : options.fitMode) params.set("fit_mode", options.fitMode);
|
|
33
|
+
if (options == null ? void 0 : options.flipH) params.set("flip_h", "true");
|
|
34
|
+
if (options == null ? void 0 : options.flipV) params.set("flip_v", "true");
|
|
35
|
+
if (options == null ? void 0 : options.rotate) params.set("rotate", String(options.rotate));
|
|
36
|
+
return `${MUX_IMAGE_BASE}/${playbackId}/thumbnail.jpg?${params}`;
|
|
37
|
+
}
|
|
38
|
+
function getVideoGif(playbackId, options) {
|
|
39
|
+
var _a;
|
|
40
|
+
const params = new URLSearchParams();
|
|
41
|
+
params.set("width", String((_a = options == null ? void 0 : options.width) != null ? _a : 320));
|
|
42
|
+
if ((options == null ? void 0 : options.start) != null) params.set("start", String(options.start));
|
|
43
|
+
if ((options == null ? void 0 : options.end) != null) params.set("end", String(options.end));
|
|
44
|
+
if (options == null ? void 0 : options.fps) params.set("fps", String(options.fps));
|
|
45
|
+
return `${MUX_IMAGE_BASE}/${playbackId}/animated.gif?${params}`;
|
|
46
|
+
}
|
|
47
|
+
function getVideoStoryboard(playbackId) {
|
|
48
|
+
return `${MUX_IMAGE_BASE}/${playbackId}/storyboard.vtt`;
|
|
49
|
+
}
|
|
50
|
+
function getVideoStreamUrl(playbackId) {
|
|
51
|
+
return `${MUX_STREAM_BASE}/${playbackId}.m3u8`;
|
|
52
|
+
}
|
|
53
|
+
function getVideoMp4Url(playbackId, resolution = "high") {
|
|
54
|
+
return `${MUX_STREAM_BASE}/${playbackId}/${resolution}.mp4`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/ui/Video/index.tsx
|
|
58
|
+
function resolvePlaybackId(video) {
|
|
59
|
+
var _a;
|
|
60
|
+
if (typeof video === "string") return video;
|
|
61
|
+
return (_a = video.muxPlaybackId) != null ? _a : null;
|
|
62
|
+
}
|
|
63
|
+
function resolveTitle(props) {
|
|
64
|
+
var _a;
|
|
65
|
+
if (props.title !== void 0) return props.title;
|
|
66
|
+
if (typeof props.video !== "string") return (_a = props.video.title) != null ? _a : void 0;
|
|
67
|
+
return void 0;
|
|
68
|
+
}
|
|
69
|
+
function resolvePoster(props) {
|
|
70
|
+
var _a;
|
|
71
|
+
if (props.poster) return props.poster;
|
|
72
|
+
if (typeof props.video !== "string" && props.video.thumbnail) {
|
|
73
|
+
const thumb = props.video.thumbnail;
|
|
74
|
+
if (typeof thumb === "object" && thumb !== null && "url" in thumb) {
|
|
75
|
+
const url = thumb.url;
|
|
76
|
+
if (url) return url;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const playbackId = resolvePlaybackId(props.video);
|
|
80
|
+
if (!playbackId) return void 0;
|
|
81
|
+
return getVideoThumbnail(playbackId, {
|
|
82
|
+
width: 1280,
|
|
83
|
+
time: (_a = props.thumbnailTime) != null ? _a : 0
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function resolveAspectRatio(video) {
|
|
87
|
+
var _a;
|
|
88
|
+
if (typeof video === "string") return void 0;
|
|
89
|
+
return (_a = video.aspectRatio) != null ? _a : void 0;
|
|
90
|
+
}
|
|
91
|
+
function resolveStatus(video) {
|
|
92
|
+
var _a;
|
|
93
|
+
if (typeof video === "string") return "ready";
|
|
94
|
+
return (_a = video.status) != null ? _a : "waiting";
|
|
95
|
+
}
|
|
96
|
+
var VideoPlayer = forwardRef(
|
|
97
|
+
function VideoPlayer2(props, ref) {
|
|
98
|
+
const {
|
|
99
|
+
video,
|
|
100
|
+
accentColor,
|
|
101
|
+
primaryColor,
|
|
102
|
+
secondaryColor,
|
|
103
|
+
autoPlay,
|
|
104
|
+
loop,
|
|
105
|
+
muted,
|
|
106
|
+
preload = "metadata",
|
|
107
|
+
startTime,
|
|
108
|
+
streamType = "on-demand",
|
|
109
|
+
audio,
|
|
110
|
+
noHotKeys,
|
|
111
|
+
maxResolution,
|
|
112
|
+
placeholder,
|
|
113
|
+
placeholderClassName,
|
|
114
|
+
placeholderStyle,
|
|
115
|
+
className,
|
|
116
|
+
style,
|
|
117
|
+
onPlay,
|
|
118
|
+
onPause,
|
|
119
|
+
onEnded,
|
|
120
|
+
onTimeUpdate,
|
|
121
|
+
onLoadedData,
|
|
122
|
+
onError,
|
|
123
|
+
playerProps
|
|
124
|
+
} = props;
|
|
125
|
+
const playbackId = resolvePlaybackId(video);
|
|
126
|
+
const title = resolveTitle(props);
|
|
127
|
+
const poster = resolvePoster(props);
|
|
128
|
+
const aspectRatio = resolveAspectRatio(video);
|
|
129
|
+
const status = resolveStatus(video);
|
|
130
|
+
if (!playbackId || typeof video !== "string" && status !== "ready") {
|
|
131
|
+
return /* @__PURE__ */ React.createElement(
|
|
132
|
+
"div",
|
|
133
|
+
{
|
|
134
|
+
className: placeholderClassName != null ? placeholderClassName : className,
|
|
135
|
+
style: __spreadValues({
|
|
136
|
+
display: "flex",
|
|
137
|
+
alignItems: "center",
|
|
138
|
+
justifyContent: "center",
|
|
139
|
+
aspectRatio: aspectRatio != null ? aspectRatio : "16/9",
|
|
140
|
+
backgroundColor: "#000",
|
|
141
|
+
color: "#888",
|
|
142
|
+
fontSize: 14,
|
|
143
|
+
width: "100%"
|
|
144
|
+
}, placeholderStyle)
|
|
145
|
+
},
|
|
146
|
+
placeholder != null ? placeholder : status === "preparing" ? "Video is processing..." : status === "errored" ? "Video processing failed" : "Video not available"
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
return /* @__PURE__ */ React.createElement(
|
|
150
|
+
MuxPlayer,
|
|
151
|
+
__spreadValues({
|
|
152
|
+
ref,
|
|
153
|
+
playbackId,
|
|
154
|
+
streamType,
|
|
155
|
+
accentColor,
|
|
156
|
+
primaryColor,
|
|
157
|
+
secondaryColor,
|
|
158
|
+
title,
|
|
159
|
+
autoPlay,
|
|
160
|
+
loop,
|
|
161
|
+
muted,
|
|
162
|
+
preload,
|
|
163
|
+
startTime,
|
|
164
|
+
poster,
|
|
165
|
+
audio,
|
|
166
|
+
nohotkeys: noHotKeys,
|
|
167
|
+
maxResolution,
|
|
168
|
+
className,
|
|
169
|
+
style: __spreadValues({
|
|
170
|
+
aspectRatio: aspectRatio != null ? aspectRatio : "16/9",
|
|
171
|
+
width: "100%"
|
|
172
|
+
}, style),
|
|
173
|
+
onPlay,
|
|
174
|
+
onPause,
|
|
175
|
+
onEnded,
|
|
176
|
+
onTimeUpdate,
|
|
177
|
+
onLoadedData,
|
|
178
|
+
onError
|
|
179
|
+
}, playerProps)
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
);
|
|
183
|
+
export {
|
|
184
|
+
VideoPlayer,
|
|
185
|
+
getVideoGif,
|
|
186
|
+
getVideoMp4Url,
|
|
187
|
+
getVideoStoryboard,
|
|
188
|
+
getVideoStreamUrl,
|
|
189
|
+
getVideoThumbnail
|
|
190
|
+
};
|
|
191
|
+
//# sourceMappingURL=video.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/ui/Video/index.tsx","../../src/utils/video.ts"],"sourcesContent":["'use client'\n\nimport React, { forwardRef, type CSSProperties } from 'react'\nimport MuxPlayer from '@mux/mux-player-react'\nimport type {\n MuxPlayerRefAttributes,\n MuxPlayerProps,\n} from '@mux/mux-player-react'\nimport type { Video, Image } from '../../payload-types'\nimport { getVideoThumbnail } from '../../utils/video'\n\n// Re-export video utilities for convenience\nexport {\n getVideoThumbnail,\n getVideoGif,\n getVideoStreamUrl,\n getVideoMp4Url,\n getVideoStoryboard,\n type VideoThumbnailOptions,\n type VideoGifOptions,\n} from '../../utils/video'\n\n// ── CSS custom properties ──\n\nexport interface VideoPlayerCSSProperties extends CSSProperties {\n [key: `--${string}`]: string | undefined\n}\n\n// ── Props ──\n\nexport interface VideoPlayerProps {\n /** Video document or playbackId string */\n video: Video | string\n\n // ── Theming ──\n /** Theme accent color */\n accentColor?: string\n /** Theme primary color (controls) */\n primaryColor?: string\n /** Theme secondary color (time display, etc.) */\n secondaryColor?: string\n\n // ── Playback ──\n /** Title overlay (auto-resolved from Video.title if omitted) */\n title?: string\n /** Autoplay behavior */\n autoPlay?: boolean | 'muted' | 'any'\n /** Loop playback */\n loop?: boolean\n /** Muted by default */\n muted?: boolean\n /** Preload strategy (default: 'metadata') */\n preload?: 'auto' | 'metadata' | 'none'\n /** Start time in seconds */\n startTime?: number\n /** Stream type (default: 'on-demand') */\n streamType?: 'on-demand' | 'live' | 'll-live'\n /** Audio-only mode */\n audio?: boolean\n /** Disable keyboard shortcuts */\n noHotKeys?: boolean\n /** Max resolution cap */\n maxResolution?: '720p' | '1080p' | '1440p' | '2160p'\n\n // ── Poster ──\n /** Thumbnail time for auto-generated poster (default: 0) */\n thumbnailTime?: number\n /** Custom poster URL (overrides auto-generated thumbnail) */\n poster?: string\n\n // ── Placeholder (when video not ready) ──\n /** Placeholder text when video is not ready */\n placeholder?: string\n /** CSS class for the placeholder */\n placeholderClassName?: string\n /** Inline styles for the placeholder */\n placeholderStyle?: CSSProperties\n\n // ── Styling ──\n /** CSS class */\n className?: string\n /** Inline styles (supports --mux CSS custom properties) */\n style?: VideoPlayerCSSProperties\n\n // ── Events ──\n onPlay?: () => void\n onPause?: () => void\n onEnded?: () => void\n onTimeUpdate?: () => void\n onLoadedData?: () => void\n onError?: () => void\n\n // ── Escape hatch ──\n /** Extra props forwarded directly to MuxPlayer */\n playerProps?: Omit<\n MuxPlayerProps,\n | 'playbackId'\n | 'streamType'\n | 'accentColor'\n | 'primaryColor'\n | 'secondaryColor'\n | 'title'\n | 'autoPlay'\n | 'loop'\n | 'muted'\n | 'preload'\n | 'startTime'\n | 'poster'\n | 'audio'\n | 'nohotkeys'\n | 'maxResolution'\n | 'className'\n | 'style'\n >\n}\n\n// ── Helpers ──\n\nfunction resolvePlaybackId(video: Video | string): string | null {\n if (typeof video === 'string') return video\n return video.muxPlaybackId ?? null\n}\n\nfunction resolveTitle(props: VideoPlayerProps): string | undefined {\n if (props.title !== undefined) return props.title\n if (typeof props.video !== 'string') return props.video.title ?? undefined\n return undefined\n}\n\nfunction resolvePoster(props: VideoPlayerProps): string | undefined {\n // 1. Explicit poster URL (highest priority)\n if (props.poster) return props.poster\n\n // 2. Video.thumbnail uploaded image\n if (typeof props.video !== 'string' && props.video.thumbnail) {\n const thumb = props.video.thumbnail\n if (typeof thumb === 'object' && thumb !== null && 'url' in thumb) {\n const url = (thumb as Image).url\n if (url) return url\n }\n }\n\n // 3. Auto-generate from Mux image API\n const playbackId = resolvePlaybackId(props.video)\n if (!playbackId) return undefined\n return getVideoThumbnail(playbackId, {\n width: 1280,\n time: props.thumbnailTime ?? 0,\n })\n}\n\nfunction resolveAspectRatio(video: Video | string): string | undefined {\n if (typeof video === 'string') return undefined\n return video.aspectRatio ?? undefined\n}\n\nfunction resolveStatus(video: Video | string): string {\n if (typeof video === 'string') return 'ready'\n return video.status ?? 'waiting'\n}\n\n// ── Component ──\n\n/**\n * Mux video player component.\n * Requires `@mux/mux-player-react` (optional peer dependency).\n *\n * @example Basic usage\n * ```tsx\n * import { VideoPlayer } from '@01.software/sdk/ui/video'\n *\n * <VideoPlayer video={videoDoc} />\n * ```\n *\n * @example With playback ID string\n * ```tsx\n * <VideoPlayer video=\"abc123def\" autoPlay=\"muted\" loop />\n * ```\n *\n * @example Custom theming with CSS custom properties\n * ```tsx\n * <VideoPlayer\n * video={videoDoc}\n * accentColor=\"#f43f5e\"\n * primaryColor=\"#fff\"\n * className=\"rounded-lg overflow-hidden\"\n * style={{ '--controls-backdrop-color': 'rgba(0,0,0,0.6)' }}\n * />\n * ```\n *\n * @example Audio-only mode\n * ```tsx\n * <VideoPlayer video={videoDoc} audio />\n * ```\n */\nexport const VideoPlayer: React.ForwardRefExoticComponent<\n VideoPlayerProps & React.RefAttributes<MuxPlayerRefAttributes>\n> = forwardRef<MuxPlayerRefAttributes, VideoPlayerProps>(\n function VideoPlayer(props, ref) {\n const {\n video,\n accentColor,\n primaryColor,\n secondaryColor,\n autoPlay,\n loop,\n muted,\n preload = 'metadata',\n startTime,\n streamType = 'on-demand',\n audio,\n noHotKeys,\n maxResolution,\n placeholder,\n placeholderClassName,\n placeholderStyle,\n className,\n style,\n onPlay,\n onPause,\n onEnded,\n onTimeUpdate,\n onLoadedData,\n onError,\n playerProps,\n } = props\n\n const playbackId = resolvePlaybackId(video)\n const title = resolveTitle(props)\n const poster = resolvePoster(props)\n const aspectRatio = resolveAspectRatio(video)\n const status = resolveStatus(video)\n\n // Show placeholder when no playbackId or video not ready\n if (!playbackId || (typeof video !== 'string' && status !== 'ready')) {\n return (\n <div\n className={placeholderClassName ?? className}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n aspectRatio: aspectRatio ?? '16/9',\n backgroundColor: '#000',\n color: '#888',\n fontSize: 14,\n width: '100%',\n ...placeholderStyle,\n }}\n >\n {placeholder ??\n (status === 'preparing'\n ? 'Video is processing...'\n : status === 'errored'\n ? 'Video processing failed'\n : 'Video not available')}\n </div>\n )\n }\n\n return (\n <MuxPlayer\n ref={ref}\n playbackId={playbackId}\n streamType={streamType}\n accentColor={accentColor}\n primaryColor={primaryColor}\n secondaryColor={secondaryColor}\n title={title}\n autoPlay={autoPlay}\n loop={loop}\n muted={muted}\n preload={preload}\n startTime={startTime}\n poster={poster}\n audio={audio}\n nohotkeys={noHotKeys}\n maxResolution={maxResolution}\n className={className}\n style={{\n aspectRatio: aspectRatio ?? '16/9',\n width: '100%',\n ...style,\n }}\n onPlay={onPlay}\n onPause={onPause}\n onEnded={onEnded}\n onTimeUpdate={onTimeUpdate}\n onLoadedData={onLoadedData}\n onError={onError}\n {...playerProps}\n />\n )\n },\n)\n\n// ── Type Exports ──\n\nexport type { MuxPlayerRefAttributes as VideoPlayerRef } from '@mux/mux-player-react'\nexport type { Video as VideoData } from '../../payload-types'\n","const MUX_IMAGE_BASE = 'https://image.mux.com'\nconst MUX_STREAM_BASE = 'https://stream.mux.com'\n\n// ── Thumbnail ──\n\nexport interface VideoThumbnailOptions {\n /** Width in pixels (default: 640) */\n width?: number\n /** Height in pixels (auto if omitted) */\n height?: number\n /** Time offset in seconds (default: 0) */\n time?: number\n /** Fit mode (default: 'smartcrop') */\n fitMode?: 'preserve' | 'stretch' | 'crop' | 'smartcrop' | 'pad'\n /** Flip horizontally */\n flipH?: boolean\n /** Flip vertically */\n flipV?: boolean\n /** Rotation in degrees (90, 180, 270) */\n rotate?: 90 | 180 | 270\n}\n\n/**\n * Returns a Mux thumbnail URL for a video.\n *\n * @example\n * ```ts\n * getVideoThumbnail('abc123')\n * // => 'https://image.mux.com/abc123/thumbnail.jpg?width=640'\n *\n * getVideoThumbnail('abc123', { width: 320, time: 5 })\n * // => 'https://image.mux.com/abc123/thumbnail.jpg?width=320&time=5'\n * ```\n */\nexport function getVideoThumbnail(\n playbackId: string,\n options?: VideoThumbnailOptions,\n): string {\n const params = new URLSearchParams()\n params.set('width', String(options?.width ?? 640))\n if (options?.height) params.set('height', String(options.height))\n if (options?.time != null) params.set('time', String(options.time))\n if (options?.fitMode) params.set('fit_mode', options.fitMode)\n if (options?.flipH) params.set('flip_h', 'true')\n if (options?.flipV) params.set('flip_v', 'true')\n if (options?.rotate) params.set('rotate', String(options.rotate))\n return `${MUX_IMAGE_BASE}/${playbackId}/thumbnail.jpg?${params}`\n}\n\n// ── Animated GIF ──\n\nexport interface VideoGifOptions {\n /** Width in pixels (default: 320) */\n width?: number\n /** Start time in seconds (default: 0) */\n start?: number\n /** End time in seconds (default: start + 5) */\n end?: number\n /** Frames per second (default: 15) */\n fps?: number\n}\n\n/**\n * Returns a Mux animated GIF URL for a video.\n *\n * @example\n * ```ts\n * getVideoGif('abc123')\n * // => 'https://image.mux.com/abc123/animated.gif?width=320'\n *\n * getVideoGif('abc123', { width: 240, start: 2, end: 6 })\n * // => 'https://image.mux.com/abc123/animated.gif?width=240&start=2&end=6'\n * ```\n */\nexport function getVideoGif(\n playbackId: string,\n options?: VideoGifOptions,\n): string {\n const params = new URLSearchParams()\n params.set('width', String(options?.width ?? 320))\n if (options?.start != null) params.set('start', String(options.start))\n if (options?.end != null) params.set('end', String(options.end))\n if (options?.fps) params.set('fps', String(options.fps))\n return `${MUX_IMAGE_BASE}/${playbackId}/animated.gif?${params}`\n}\n\n// ── Storyboard ──\n\n/**\n * Returns a Mux storyboard VTT URL for timeline hover previews.\n *\n * @example\n * ```ts\n * getVideoStoryboard('abc123')\n * // => 'https://image.mux.com/abc123/storyboard.vtt'\n * ```\n */\nexport function getVideoStoryboard(playbackId: string): string {\n return `${MUX_IMAGE_BASE}/${playbackId}/storyboard.vtt`\n}\n\n// ── Stream / Playback URLs ──\n\n/**\n * Returns the HLS stream URL for a video.\n *\n * @example\n * ```ts\n * getVideoStreamUrl('abc123')\n * // => 'https://stream.mux.com/abc123.m3u8'\n * ```\n */\nexport function getVideoStreamUrl(playbackId: string): string {\n return `${MUX_STREAM_BASE}/${playbackId}.m3u8`\n}\n\n/**\n * Returns a Mux MP4 download URL for a video.\n * Only available if the asset was created with `mp4_support` enabled.\n *\n * @example\n * ```ts\n * getVideoMp4Url('abc123', 'high')\n * // => 'https://stream.mux.com/abc123/high.mp4'\n * ```\n */\nexport function getVideoMp4Url(\n playbackId: string,\n resolution: 'high' | 'medium' | 'low' = 'high',\n): string {\n return `${MUX_STREAM_BASE}/${playbackId}/${resolution}.mp4`\n}\n"],"mappings":"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","names":["VideoPlayer"]}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
interface VideoThumbnailOptions {
|
|
2
|
+
/** Width in pixels (default: 640) */
|
|
3
|
+
width?: number;
|
|
4
|
+
/** Height in pixels (auto if omitted) */
|
|
5
|
+
height?: number;
|
|
6
|
+
/** Time offset in seconds (default: 0) */
|
|
7
|
+
time?: number;
|
|
8
|
+
/** Fit mode (default: 'smartcrop') */
|
|
9
|
+
fitMode?: 'preserve' | 'stretch' | 'crop' | 'smartcrop' | 'pad';
|
|
10
|
+
/** Flip horizontally */
|
|
11
|
+
flipH?: boolean;
|
|
12
|
+
/** Flip vertically */
|
|
13
|
+
flipV?: boolean;
|
|
14
|
+
/** Rotation in degrees (90, 180, 270) */
|
|
15
|
+
rotate?: 90 | 180 | 270;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns a Mux thumbnail URL for a video.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* getVideoThumbnail('abc123')
|
|
23
|
+
* // => 'https://image.mux.com/abc123/thumbnail.jpg?width=640'
|
|
24
|
+
*
|
|
25
|
+
* getVideoThumbnail('abc123', { width: 320, time: 5 })
|
|
26
|
+
* // => 'https://image.mux.com/abc123/thumbnail.jpg?width=320&time=5'
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare function getVideoThumbnail(playbackId: string, options?: VideoThumbnailOptions): string;
|
|
30
|
+
interface VideoGifOptions {
|
|
31
|
+
/** Width in pixels (default: 320) */
|
|
32
|
+
width?: number;
|
|
33
|
+
/** Start time in seconds (default: 0) */
|
|
34
|
+
start?: number;
|
|
35
|
+
/** End time in seconds (default: start + 5) */
|
|
36
|
+
end?: number;
|
|
37
|
+
/** Frames per second (default: 15) */
|
|
38
|
+
fps?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns a Mux animated GIF URL for a video.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* getVideoGif('abc123')
|
|
46
|
+
* // => 'https://image.mux.com/abc123/animated.gif?width=320'
|
|
47
|
+
*
|
|
48
|
+
* getVideoGif('abc123', { width: 240, start: 2, end: 6 })
|
|
49
|
+
* // => 'https://image.mux.com/abc123/animated.gif?width=240&start=2&end=6'
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function getVideoGif(playbackId: string, options?: VideoGifOptions): string;
|
|
53
|
+
/**
|
|
54
|
+
* Returns a Mux storyboard VTT URL for timeline hover previews.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* getVideoStoryboard('abc123')
|
|
59
|
+
* // => 'https://image.mux.com/abc123/storyboard.vtt'
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare function getVideoStoryboard(playbackId: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Returns the HLS stream URL for a video.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* getVideoStreamUrl('abc123')
|
|
69
|
+
* // => 'https://stream.mux.com/abc123.m3u8'
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare function getVideoStreamUrl(playbackId: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Returns a Mux MP4 download URL for a video.
|
|
75
|
+
* Only available if the asset was created with `mp4_support` enabled.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* getVideoMp4Url('abc123', 'high')
|
|
80
|
+
* // => 'https://stream.mux.com/abc123/high.mp4'
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
declare function getVideoMp4Url(playbackId: string, resolution?: 'high' | 'medium' | 'low'): string;
|
|
84
|
+
|
|
85
|
+
export { type VideoThumbnailOptions as V, getVideoGif as a, getVideoStreamUrl as b, getVideoMp4Url as c, getVideoStoryboard as d, type VideoGifOptions as e, getVideoThumbnail as g };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
interface VideoThumbnailOptions {
|
|
2
|
+
/** Width in pixels (default: 640) */
|
|
3
|
+
width?: number;
|
|
4
|
+
/** Height in pixels (auto if omitted) */
|
|
5
|
+
height?: number;
|
|
6
|
+
/** Time offset in seconds (default: 0) */
|
|
7
|
+
time?: number;
|
|
8
|
+
/** Fit mode (default: 'smartcrop') */
|
|
9
|
+
fitMode?: 'preserve' | 'stretch' | 'crop' | 'smartcrop' | 'pad';
|
|
10
|
+
/** Flip horizontally */
|
|
11
|
+
flipH?: boolean;
|
|
12
|
+
/** Flip vertically */
|
|
13
|
+
flipV?: boolean;
|
|
14
|
+
/** Rotation in degrees (90, 180, 270) */
|
|
15
|
+
rotate?: 90 | 180 | 270;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns a Mux thumbnail URL for a video.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* getVideoThumbnail('abc123')
|
|
23
|
+
* // => 'https://image.mux.com/abc123/thumbnail.jpg?width=640'
|
|
24
|
+
*
|
|
25
|
+
* getVideoThumbnail('abc123', { width: 320, time: 5 })
|
|
26
|
+
* // => 'https://image.mux.com/abc123/thumbnail.jpg?width=320&time=5'
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare function getVideoThumbnail(playbackId: string, options?: VideoThumbnailOptions): string;
|
|
30
|
+
interface VideoGifOptions {
|
|
31
|
+
/** Width in pixels (default: 320) */
|
|
32
|
+
width?: number;
|
|
33
|
+
/** Start time in seconds (default: 0) */
|
|
34
|
+
start?: number;
|
|
35
|
+
/** End time in seconds (default: start + 5) */
|
|
36
|
+
end?: number;
|
|
37
|
+
/** Frames per second (default: 15) */
|
|
38
|
+
fps?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns a Mux animated GIF URL for a video.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* getVideoGif('abc123')
|
|
46
|
+
* // => 'https://image.mux.com/abc123/animated.gif?width=320'
|
|
47
|
+
*
|
|
48
|
+
* getVideoGif('abc123', { width: 240, start: 2, end: 6 })
|
|
49
|
+
* // => 'https://image.mux.com/abc123/animated.gif?width=240&start=2&end=6'
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function getVideoGif(playbackId: string, options?: VideoGifOptions): string;
|
|
53
|
+
/**
|
|
54
|
+
* Returns a Mux storyboard VTT URL for timeline hover previews.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* getVideoStoryboard('abc123')
|
|
59
|
+
* // => 'https://image.mux.com/abc123/storyboard.vtt'
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
declare function getVideoStoryboard(playbackId: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Returns the HLS stream URL for a video.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* getVideoStreamUrl('abc123')
|
|
69
|
+
* // => 'https://stream.mux.com/abc123.m3u8'
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
declare function getVideoStreamUrl(playbackId: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Returns a Mux MP4 download URL for a video.
|
|
75
|
+
* Only available if the asset was created with `mp4_support` enabled.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* getVideoMp4Url('abc123', 'high')
|
|
80
|
+
* // => 'https://stream.mux.com/abc123/high.mp4'
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
declare function getVideoMp4Url(playbackId: string, resolution?: 'high' | 'medium' | 'low'): string;
|
|
84
|
+
|
|
85
|
+
export { type VideoThumbnailOptions as V, getVideoGif as a, getVideoStreamUrl as b, getVideoMp4Url as c, getVideoStoryboard as d, type VideoGifOptions as e, getVideoThumbnail as g };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { C as Collection } from './const-BpirbGBD.cjs';
|
|
2
|
+
import { C as Config } from './payload-types-CZiaL4Wr.cjs';
|
|
3
|
+
|
|
4
|
+
type CollectionType<T extends Collection> = T extends keyof Config['collections'] ? Config['collections'][T] : never;
|
|
5
|
+
|
|
6
|
+
type WebhookOperation = 'create' | 'update';
|
|
7
|
+
interface WebhookEvent<T extends Collection = Collection> {
|
|
8
|
+
collection: T;
|
|
9
|
+
operation: WebhookOperation;
|
|
10
|
+
data: CollectionType<T>;
|
|
11
|
+
}
|
|
12
|
+
type WebhookHandler<T extends Collection = Collection> = (event: WebhookEvent<T>) => Promise<void> | void;
|
|
13
|
+
interface WebhookOptions {
|
|
14
|
+
secret?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function isValidWebhookEvent(data: unknown): data is WebhookEvent;
|
|
17
|
+
declare function handleWebhook<T extends Collection = Collection>(request: Request, handler: WebhookHandler<T>, options?: WebhookOptions): Promise<Response>;
|
|
18
|
+
declare function createTypedWebhookHandler<T extends Collection>(collection: T, handler: (event: WebhookEvent<T>) => Promise<void> | void): WebhookHandler<T>;
|
|
19
|
+
|
|
20
|
+
export { type CollectionType as C, type WebhookOperation as W, type WebhookEvent as a, type WebhookHandler as b, type WebhookOptions as c, createTypedWebhookHandler as d, handleWebhook as h, isValidWebhookEvent as i };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { C as Collection } from './const-qZSQiSSC.js';
|
|
2
|
+
import { C as Config } from './payload-types-CZiaL4Wr.js';
|
|
3
|
+
|
|
4
|
+
type CollectionType<T extends Collection> = T extends keyof Config['collections'] ? Config['collections'][T] : never;
|
|
5
|
+
|
|
6
|
+
type WebhookOperation = 'create' | 'update';
|
|
7
|
+
interface WebhookEvent<T extends Collection = Collection> {
|
|
8
|
+
collection: T;
|
|
9
|
+
operation: WebhookOperation;
|
|
10
|
+
data: CollectionType<T>;
|
|
11
|
+
}
|
|
12
|
+
type WebhookHandler<T extends Collection = Collection> = (event: WebhookEvent<T>) => Promise<void> | void;
|
|
13
|
+
interface WebhookOptions {
|
|
14
|
+
secret?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function isValidWebhookEvent(data: unknown): data is WebhookEvent;
|
|
17
|
+
declare function handleWebhook<T extends Collection = Collection>(request: Request, handler: WebhookHandler<T>, options?: WebhookOptions): Promise<Response>;
|
|
18
|
+
declare function createTypedWebhookHandler<T extends Collection>(collection: T, handler: (event: WebhookEvent<T>) => Promise<void> | void): WebhookHandler<T>;
|
|
19
|
+
|
|
20
|
+
export { type CollectionType as C, type WebhookOperation as W, type WebhookEvent as a, type WebhookHandler as b, type WebhookOptions as c, createTypedWebhookHandler as d, handleWebhook as h, isValidWebhookEvent as i };
|
package/dist/webhook.cjs
CHANGED
|
@@ -54,22 +54,22 @@ function isValidWebhookEvent(data) {
|
|
|
54
54
|
}
|
|
55
55
|
function verifySignature(payload, secret, signature) {
|
|
56
56
|
return __async(this, null, function* () {
|
|
57
|
+
var _a;
|
|
57
58
|
const encoder = new TextEncoder();
|
|
58
59
|
const key = yield crypto.subtle.importKey(
|
|
59
60
|
"raw",
|
|
60
61
|
encoder.encode(secret),
|
|
61
62
|
{ name: "HMAC", hash: "SHA-256" },
|
|
62
63
|
false,
|
|
63
|
-
["
|
|
64
|
+
["verify"]
|
|
64
65
|
);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
let result = expected.length !== signature.length ? 1 : 0;
|
|
68
|
-
const len = Math.max(expected.length, signature.length);
|
|
69
|
-
for (let i = 0; i < len; i++) {
|
|
70
|
-
result |= (expected.charCodeAt(i) || 0) ^ (signature.charCodeAt(i) || 0);
|
|
66
|
+
if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
|
|
67
|
+
return false;
|
|
71
68
|
}
|
|
72
|
-
|
|
69
|
+
const sigBytes = new Uint8Array(
|
|
70
|
+
((_a = signature.match(/.{2}/g)) != null ? _a : []).map((byte) => parseInt(byte, 16))
|
|
71
|
+
);
|
|
72
|
+
return crypto.subtle.verify("HMAC", key, sigBytes, encoder.encode(payload));
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
75
|
function handleWebhook(request, handler, options) {
|
package/dist/webhook.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/webhook.ts","../src/core/webhook/index.ts"],"sourcesContent":["export {\n handleWebhook,\n createTypedWebhookHandler,\n isValidWebhookEvent,\n} from './core/webhook'\nexport type {\n WebhookEvent,\n WebhookHandler,\n WebhookOperation,\n WebhookOptions,\n} from './core/webhook'\n","import type { Collection } from '../client/types'\nimport type { CollectionType } from '../collection/types'\n\nexport type WebhookOperation = 'create' | 'update'\n\nexport interface WebhookEvent<T extends Collection = Collection> {\n collection: T\n operation: WebhookOperation\n data: CollectionType<T>\n}\n\nexport type WebhookHandler<T extends Collection = Collection> = (\n event: WebhookEvent<T>,\n) => Promise<void> | void\n\nexport interface WebhookOptions {\n secret?: string\n}\n\nexport function isValidWebhookEvent(data: unknown): data is WebhookEvent {\n if (typeof data !== 'object' || data === null) return false\n const obj = data as Record<string, unknown>\n return (\n typeof obj.collection === 'string' &&\n (obj.operation === 'create' || obj.operation === 'update') &&\n typeof obj.data === 'object' &&\n obj.data !== null\n )\n}\n\nasync function verifySignature(\n payload: string,\n secret: string,\n signature: string,\n): Promise<boolean> {\n const encoder = new TextEncoder()\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['
|
|
1
|
+
{"version":3,"sources":["../src/webhook.ts","../src/core/webhook/index.ts"],"sourcesContent":["export {\n handleWebhook,\n createTypedWebhookHandler,\n isValidWebhookEvent,\n} from './core/webhook'\nexport type {\n WebhookEvent,\n WebhookHandler,\n WebhookOperation,\n WebhookOptions,\n} from './core/webhook'\n","import type { Collection } from '../client/types'\nimport type { CollectionType } from '../collection/types'\n\nexport type WebhookOperation = 'create' | 'update'\n\nexport interface WebhookEvent<T extends Collection = Collection> {\n collection: T\n operation: WebhookOperation\n data: CollectionType<T>\n}\n\nexport type WebhookHandler<T extends Collection = Collection> = (\n event: WebhookEvent<T>,\n) => Promise<void> | void\n\nexport interface WebhookOptions {\n secret?: string\n}\n\nexport function isValidWebhookEvent(data: unknown): data is WebhookEvent {\n if (typeof data !== 'object' || data === null) return false\n const obj = data as Record<string, unknown>\n return (\n typeof obj.collection === 'string' &&\n (obj.operation === 'create' || obj.operation === 'update') &&\n typeof obj.data === 'object' &&\n obj.data !== null\n )\n}\n\nasync function verifySignature(\n payload: string,\n secret: string,\n signature: string,\n): Promise<boolean> {\n const encoder = new TextEncoder()\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['verify'],\n )\n // Validate and convert hex signature to Uint8Array\n if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {\n return false\n }\n const sigBytes = new Uint8Array(\n (signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16)),\n )\n // crypto.subtle.verify performs constant-time comparison internally\n return crypto.subtle.verify('HMAC', key, sigBytes, encoder.encode(payload))\n}\n\nexport async function handleWebhook<T extends Collection = Collection>(\n request: Request,\n handler: WebhookHandler<T>,\n options?: WebhookOptions,\n): Promise<Response> {\n try {\n const rawBody = await request.text()\n\n if (options?.secret) {\n const signature = request.headers.get('x-webhook-signature') || ''\n const valid = await verifySignature(rawBody, options.secret, signature)\n if (!valid) {\n return new Response(\n JSON.stringify({ error: 'Invalid webhook signature' }),\n { status: 401, headers: { 'Content-Type': 'application/json' } },\n )\n }\n } else {\n console.warn(\n '[@01.software/sdk] Webhook signature verification is disabled. ' +\n 'Set { secret } in handleWebhook() options to enable HMAC-SHA256 verification.',\n )\n }\n\n const body = JSON.parse(rawBody)\n\n if (!isValidWebhookEvent(body)) {\n return new Response(\n JSON.stringify({ error: 'Invalid webhook event format' }),\n { status: 400, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n await handler(body as WebhookEvent<T>)\n\n return new Response(\n JSON.stringify({ success: true, message: 'Webhook processed' }),\n { status: 200, headers: { 'Content-Type': 'application/json' } },\n )\n } catch (error) {\n console.error('Webhook processing error:', error)\n\n return new Response(JSON.stringify({ error: 'Internal server error' }), {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n })\n }\n}\n\nexport function createTypedWebhookHandler<T extends Collection>(\n collection: T,\n handler: (event: WebhookEvent<T>) => Promise<void> | void,\n): WebhookHandler<T> {\n return async (event: WebhookEvent<T>) => {\n if (event.collection !== collection) {\n throw new Error(\n `Expected collection \"${collection}\", got \"${event.collection}\"`,\n )\n }\n return handler(event)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACmBO,SAAS,oBAAoB,MAAqC;AACvE,MAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO;AACtD,QAAM,MAAM;AACZ,SACE,OAAO,IAAI,eAAe,aACzB,IAAI,cAAc,YAAY,IAAI,cAAc,aACjD,OAAO,IAAI,SAAS,YACpB,IAAI,SAAS;AAEjB;AAEA,SAAe,gBACb,SACA,QACA,WACkB;AAAA;AAlCpB;AAmCE,UAAM,UAAU,IAAI,YAAY;AAChC,UAAM,MAAM,MAAM,OAAO,OAAO;AAAA,MAC9B;AAAA,MACA,QAAQ,OAAO,MAAM;AAAA,MACrB,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,MAChC;AAAA,MACA,CAAC,QAAQ;AAAA,IACX;AAEA,QAAI,UAAU,SAAS,MAAM,KAAK,CAAC,iBAAiB,KAAK,SAAS,GAAG;AACnE,aAAO;AAAA,IACT;AACA,UAAM,WAAW,IAAI;AAAA,QAClB,eAAU,MAAM,OAAO,MAAvB,YAA4B,CAAC,GAAG,IAAI,CAAC,SAAS,SAAS,MAAM,EAAE,CAAC;AAAA,IACnE;AAEA,WAAO,OAAO,OAAO,OAAO,QAAQ,KAAK,UAAU,QAAQ,OAAO,OAAO,CAAC;AAAA,EAC5E;AAAA;AAEA,SAAsB,cACpB,SACA,SACA,SACmB;AAAA;AACnB,QAAI;AACF,YAAM,UAAU,MAAM,QAAQ,KAAK;AAEnC,UAAI,mCAAS,QAAQ;AACnB,cAAM,YAAY,QAAQ,QAAQ,IAAI,qBAAqB,KAAK;AAChE,cAAM,QAAQ,MAAM,gBAAgB,SAAS,QAAQ,QAAQ,SAAS;AACtE,YAAI,CAAC,OAAO;AACV,iBAAO,IAAI;AAAA,YACT,KAAK,UAAU,EAAE,OAAO,4BAA4B,CAAC;AAAA,YACrD,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,mBAAmB,EAAE;AAAA,UACjE;AAAA,QACF;AAAA,MACF,OAAO;AACL,gBAAQ;AAAA,UACN;AAAA,QAEF;AAAA,MACF;AAEA,YAAM,OAAO,KAAK,MAAM,OAAO;AAE/B,UAAI,CAAC,oBAAoB,IAAI,GAAG;AAC9B,eAAO,IAAI;AAAA,UACT,KAAK,UAAU,EAAE,OAAO,+BAA+B,CAAC;AAAA,UACxD,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,mBAAmB,EAAE;AAAA,QACjE;AAAA,MACF;AAEA,YAAM,QAAQ,IAAuB;AAErC,aAAO,IAAI;AAAA,QACT,KAAK,UAAU,EAAE,SAAS,MAAM,SAAS,oBAAoB,CAAC;AAAA,QAC9D,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,mBAAmB,EAAE;AAAA,MACjE;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,6BAA6B,KAAK;AAEhD,aAAO,IAAI,SAAS,KAAK,UAAU,EAAE,OAAO,wBAAwB,CAAC,GAAG;AAAA,QACtE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAChD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAEO,SAAS,0BACd,YACA,SACmB;AACnB,SAAO,CAAO,UAA2B;AACvC,QAAI,MAAM,eAAe,YAAY;AACnC,YAAM,IAAI;AAAA,QACR,wBAAwB,UAAU,WAAW,MAAM,UAAU;AAAA,MAC/D;AAAA,IACF;AACA,WAAO,QAAQ,KAAK;AAAA,EACtB;AACF;","names":[]}
|
package/dist/webhook.d.cts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import './
|
|
1
|
+
export { a as WebhookEvent, b as WebhookHandler, W as WebhookOperation, c as WebhookOptions, d as createTypedWebhookHandler, h as handleWebhook, i as isValidWebhookEvent } from './webhook-3iL9OEyq.cjs';
|
|
2
|
+
import './const-BpirbGBD.cjs';
|
|
3
|
+
import './payload-types-CZiaL4Wr.cjs';
|
package/dist/webhook.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import './
|
|
1
|
+
export { a as WebhookEvent, b as WebhookHandler, W as WebhookOperation, c as WebhookOptions, d as createTypedWebhookHandler, h as handleWebhook, i as isValidWebhookEvent } from './webhook-DuTqrH9x.js';
|
|
2
|
+
import './const-qZSQiSSC.js';
|
|
3
|
+
import './payload-types-CZiaL4Wr.js';
|
package/dist/webhook.js
CHANGED
|
@@ -27,22 +27,22 @@ function isValidWebhookEvent(data) {
|
|
|
27
27
|
}
|
|
28
28
|
function verifySignature(payload, secret, signature) {
|
|
29
29
|
return __async(this, null, function* () {
|
|
30
|
+
var _a;
|
|
30
31
|
const encoder = new TextEncoder();
|
|
31
32
|
const key = yield crypto.subtle.importKey(
|
|
32
33
|
"raw",
|
|
33
34
|
encoder.encode(secret),
|
|
34
35
|
{ name: "HMAC", hash: "SHA-256" },
|
|
35
36
|
false,
|
|
36
|
-
["
|
|
37
|
+
["verify"]
|
|
37
38
|
);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
let result = expected.length !== signature.length ? 1 : 0;
|
|
41
|
-
const len = Math.max(expected.length, signature.length);
|
|
42
|
-
for (let i = 0; i < len; i++) {
|
|
43
|
-
result |= (expected.charCodeAt(i) || 0) ^ (signature.charCodeAt(i) || 0);
|
|
39
|
+
if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
|
|
40
|
+
return false;
|
|
44
41
|
}
|
|
45
|
-
|
|
42
|
+
const sigBytes = new Uint8Array(
|
|
43
|
+
((_a = signature.match(/.{2}/g)) != null ? _a : []).map((byte) => parseInt(byte, 16))
|
|
44
|
+
);
|
|
45
|
+
return crypto.subtle.verify("HMAC", key, sigBytes, encoder.encode(payload));
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
function handleWebhook(request, handler, options) {
|