@01.software/sdk 0.5.4 → 0.5.5

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.
Files changed (45) hide show
  1. package/dist/auth.cjs +22 -46
  2. package/dist/auth.cjs.map +1 -1
  3. package/dist/auth.js +22 -47
  4. package/dist/auth.js.map +1 -1
  5. package/dist/index.cjs +922 -1069
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.js +922 -1072
  8. package/dist/index.js.map +1 -1
  9. package/dist/realtime.cjs +75 -101
  10. package/dist/realtime.cjs.map +1 -1
  11. package/dist/realtime.js +75 -102
  12. package/dist/realtime.js.map +1 -1
  13. package/dist/ui/code-block.cjs +13 -35
  14. package/dist/ui/code-block.cjs.map +1 -1
  15. package/dist/ui/code-block.js +13 -35
  16. package/dist/ui/code-block.js.map +1 -1
  17. package/dist/ui/flow/server.cjs +26 -68
  18. package/dist/ui/flow/server.cjs.map +1 -1
  19. package/dist/ui/flow/server.js +26 -71
  20. package/dist/ui/flow/server.js.map +1 -1
  21. package/dist/ui/flow.cjs +176 -232
  22. package/dist/ui/flow.cjs.map +1 -1
  23. package/dist/ui/flow.js +176 -234
  24. package/dist/ui/flow.js.map +1 -1
  25. package/dist/ui/form.cjs +40 -84
  26. package/dist/ui/form.cjs.map +1 -1
  27. package/dist/ui/form.js +40 -86
  28. package/dist/ui/form.js.map +1 -1
  29. package/dist/ui/image.cjs +27 -40
  30. package/dist/ui/image.cjs.map +1 -1
  31. package/dist/ui/image.js +27 -42
  32. package/dist/ui/image.js.map +1 -1
  33. package/dist/ui/rich-text.cjs +33 -67
  34. package/dist/ui/rich-text.cjs.map +1 -1
  35. package/dist/ui/rich-text.js +33 -69
  36. package/dist/ui/rich-text.js.map +1 -1
  37. package/dist/ui/video.cjs +32 -50
  38. package/dist/ui/video.cjs.map +1 -1
  39. package/dist/ui/video.js +32 -52
  40. package/dist/ui/video.js.map +1 -1
  41. package/dist/webhook.cjs +48 -73
  42. package/dist/webhook.cjs.map +1 -1
  43. package/dist/webhook.js +48 -74
  44. package/dist/webhook.js.map +1 -1
  45. package/package.json +3 -3
package/dist/ui/video.js CHANGED
@@ -1,20 +1,4 @@
1
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
2
 
19
3
  // src/ui/Video/index.tsx
20
4
  import React, { forwardRef } from "react";
@@ -24,24 +8,22 @@ import MuxPlayer from "@mux/mux-player-react";
24
8
  var MUX_IMAGE_BASE = "https://image.mux.com";
25
9
  var MUX_STREAM_BASE = "https://stream.mux.com";
26
10
  function getVideoThumbnail(playbackId, options) {
27
- var _a;
28
11
  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));
12
+ params.set("width", String(options?.width ?? 640));
13
+ if (options?.height) params.set("height", String(options.height));
14
+ if (options?.time != null) params.set("time", String(options.time));
15
+ if (options?.fitMode) params.set("fit_mode", options.fitMode);
16
+ if (options?.flipH) params.set("flip_h", "true");
17
+ if (options?.flipV) params.set("flip_v", "true");
18
+ if (options?.rotate) params.set("rotate", String(options.rotate));
36
19
  return `${MUX_IMAGE_BASE}/${playbackId}/thumbnail.jpg?${params}`;
37
20
  }
38
21
  function getVideoGif(playbackId, options) {
39
- var _a;
40
22
  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));
23
+ params.set("width", String(options?.width ?? 320));
24
+ if (options?.start != null) params.set("start", String(options.start));
25
+ if (options?.end != null) params.set("end", String(options.end));
26
+ if (options?.fps) params.set("fps", String(options.fps));
45
27
  return `${MUX_IMAGE_BASE}/${playbackId}/animated.gif?${params}`;
46
28
  }
47
29
  function getVideoStoryboard(playbackId) {
@@ -56,18 +38,15 @@ function getVideoMp4Url(playbackId, resolution = "high") {
56
38
 
57
39
  // src/ui/Video/index.tsx
58
40
  function resolvePlaybackId(video) {
59
- var _a;
60
41
  if (typeof video === "string") return video;
61
- return (_a = video.muxPlaybackId) != null ? _a : null;
42
+ return video.muxPlaybackId ?? null;
62
43
  }
63
44
  function resolveTitle(props) {
64
- var _a;
65
45
  if (props.title !== void 0) return props.title;
66
- if (typeof props.video !== "string") return (_a = props.video.title) != null ? _a : void 0;
46
+ if (typeof props.video !== "string") return props.video.title ?? void 0;
67
47
  return void 0;
68
48
  }
69
49
  function resolvePoster(props) {
70
- var _a;
71
50
  if (props.poster) return props.poster;
72
51
  if (typeof props.video !== "string" && props.video.thumbnail) {
73
52
  const thumb = props.video.thumbnail;
@@ -80,18 +59,16 @@ function resolvePoster(props) {
80
59
  if (!playbackId) return void 0;
81
60
  return getVideoThumbnail(playbackId, {
82
61
  width: 1280,
83
- time: (_a = props.thumbnailTime) != null ? _a : 0
62
+ time: props.thumbnailTime ?? 0
84
63
  });
85
64
  }
86
65
  function resolveAspectRatio(video) {
87
- var _a;
88
66
  if (typeof video === "string") return void 0;
89
- return (_a = video.aspectRatio) != null ? _a : void 0;
67
+ return video.aspectRatio ?? void 0;
90
68
  }
91
69
  function resolveStatus(video) {
92
- var _a;
93
70
  if (typeof video === "string") return "ready";
94
- return (_a = video.status) != null ? _a : "waiting";
71
+ return video.status ?? "waiting";
95
72
  }
96
73
  var VideoPlayer = forwardRef(
97
74
  function VideoPlayer2(props, ref) {
@@ -131,24 +108,25 @@ var VideoPlayer = forwardRef(
131
108
  return /* @__PURE__ */ React.createElement(
132
109
  "div",
133
110
  {
134
- className: placeholderClassName != null ? placeholderClassName : className,
135
- style: __spreadValues({
111
+ className: placeholderClassName ?? className,
112
+ style: {
136
113
  display: "flex",
137
114
  alignItems: "center",
138
115
  justifyContent: "center",
139
- aspectRatio: aspectRatio != null ? aspectRatio : "16/9",
116
+ aspectRatio: aspectRatio ?? "16/9",
140
117
  backgroundColor: "#000",
141
118
  color: "#888",
142
119
  fontSize: 14,
143
- width: "100%"
144
- }, placeholderStyle)
120
+ width: "100%",
121
+ ...placeholderStyle
122
+ }
145
123
  },
146
- placeholder != null ? placeholder : status === "preparing" ? "Video is processing..." : status === "errored" ? "Video processing failed" : "Video not available"
124
+ placeholder ?? (status === "preparing" ? "Video is processing..." : status === "errored" ? "Video processing failed" : "Video not available")
147
125
  );
148
126
  }
149
127
  return /* @__PURE__ */ React.createElement(
150
128
  MuxPlayer,
151
- __spreadValues({
129
+ {
152
130
  ref,
153
131
  playbackId,
154
132
  streamType,
@@ -166,17 +144,19 @@ var VideoPlayer = forwardRef(
166
144
  nohotkeys: noHotKeys,
167
145
  maxResolution,
168
146
  className,
169
- style: __spreadValues({
170
- aspectRatio: aspectRatio != null ? aspectRatio : "16/9",
171
- width: "100%"
172
- }, style),
147
+ style: {
148
+ aspectRatio: aspectRatio ?? "16/9",
149
+ width: "100%",
150
+ ...style
151
+ },
173
152
  onPlay,
174
153
  onPause,
175
154
  onEnded,
176
155
  onTimeUpdate,
177
156
  onLoadedData,
178
- onError
179
- }, playerProps)
157
+ onError,
158
+ ...playerProps
159
+ }
180
160
  );
181
161
  }
182
162
  );
@@ -1 +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"]}
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"]}
package/dist/webhook.cjs CHANGED
@@ -16,26 +16,6 @@ var __copyProps = (to, from, except, desc) => {
16
16
  return to;
17
17
  };
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var __async = (__this, __arguments, generator) => {
20
- return new Promise((resolve, reject) => {
21
- var fulfilled = (value) => {
22
- try {
23
- step(generator.next(value));
24
- } catch (e) {
25
- reject(e);
26
- }
27
- };
28
- var rejected = (value) => {
29
- try {
30
- step(generator.throw(value));
31
- } catch (e) {
32
- reject(e);
33
- }
34
- };
35
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
36
- step((generator = generator.apply(__this, __arguments)).next());
37
- });
38
- };
39
19
 
40
20
  // src/webhook.ts
41
21
  var webhook_exports = {};
@@ -52,73 +32,68 @@ function isValidWebhookEvent(data) {
52
32
  const obj = data;
53
33
  return typeof obj.collection === "string" && (obj.operation === "create" || obj.operation === "update") && typeof obj.data === "object" && obj.data !== null;
54
34
  }
55
- function verifySignature(payload, secret, signature) {
56
- return __async(this, null, function* () {
57
- var _a;
58
- const encoder = new TextEncoder();
59
- const key = yield crypto.subtle.importKey(
60
- "raw",
61
- encoder.encode(secret),
62
- { name: "HMAC", hash: "SHA-256" },
63
- false,
64
- ["verify"]
65
- );
66
- if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
67
- return false;
68
- }
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
- });
35
+ async function verifySignature(payload, secret, signature) {
36
+ const encoder = new TextEncoder();
37
+ const key = await crypto.subtle.importKey(
38
+ "raw",
39
+ encoder.encode(secret),
40
+ { name: "HMAC", hash: "SHA-256" },
41
+ false,
42
+ ["verify"]
43
+ );
44
+ if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
45
+ return false;
46
+ }
47
+ const sigBytes = new Uint8Array(
48
+ (signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16))
49
+ );
50
+ return crypto.subtle.verify("HMAC", key, sigBytes, encoder.encode(payload));
74
51
  }
75
- function handleWebhook(request, handler, options) {
76
- return __async(this, null, function* () {
77
- try {
78
- const rawBody = yield request.text();
79
- if (options == null ? void 0 : options.secret) {
80
- const signature = request.headers.get("x-webhook-signature") || "";
81
- const valid = yield verifySignature(rawBody, options.secret, signature);
82
- if (!valid) {
83
- return new Response(
84
- JSON.stringify({ error: "Invalid webhook signature" }),
85
- { status: 401, headers: { "Content-Type": "application/json" } }
86
- );
87
- }
88
- } else {
89
- console.warn(
90
- "[@01.software/sdk] Webhook signature verification is disabled. Set { secret } in handleWebhook() options to enable HMAC-SHA256 verification."
91
- );
92
- }
93
- const body = JSON.parse(rawBody);
94
- if (!isValidWebhookEvent(body)) {
52
+ async function handleWebhook(request, handler, options) {
53
+ try {
54
+ const rawBody = await request.text();
55
+ if (options?.secret) {
56
+ const signature = request.headers.get("x-webhook-signature") || "";
57
+ const valid = await verifySignature(rawBody, options.secret, signature);
58
+ if (!valid) {
95
59
  return new Response(
96
- JSON.stringify({ error: "Invalid webhook event format" }),
97
- { status: 400, headers: { "Content-Type": "application/json" } }
60
+ JSON.stringify({ error: "Invalid webhook signature" }),
61
+ { status: 401, headers: { "Content-Type": "application/json" } }
98
62
  );
99
63
  }
100
- yield handler(body);
64
+ } else {
65
+ console.warn(
66
+ "[@01.software/sdk] Webhook signature verification is disabled. Set { secret } in handleWebhook() options to enable HMAC-SHA256 verification."
67
+ );
68
+ }
69
+ const body = JSON.parse(rawBody);
70
+ if (!isValidWebhookEvent(body)) {
101
71
  return new Response(
102
- JSON.stringify({ success: true, message: "Webhook processed" }),
103
- { status: 200, headers: { "Content-Type": "application/json" } }
72
+ JSON.stringify({ error: "Invalid webhook event format" }),
73
+ { status: 400, headers: { "Content-Type": "application/json" } }
104
74
  );
105
- } catch (error) {
106
- console.error("Webhook processing error:", error);
107
- return new Response(JSON.stringify({ error: "Internal server error" }), {
108
- status: 500,
109
- headers: { "Content-Type": "application/json" }
110
- });
111
75
  }
112
- });
76
+ await handler(body);
77
+ return new Response(
78
+ JSON.stringify({ success: true, message: "Webhook processed" }),
79
+ { status: 200, headers: { "Content-Type": "application/json" } }
80
+ );
81
+ } catch (error) {
82
+ console.error("Webhook processing error:", error);
83
+ return new Response(JSON.stringify({ error: "Internal server error" }), {
84
+ status: 500,
85
+ headers: { "Content-Type": "application/json" }
86
+ });
87
+ }
113
88
  }
114
89
  function createTypedWebhookHandler(collection, handler) {
115
- return (event) => __async(null, null, function* () {
90
+ return async (event) => {
116
91
  if (event.collection !== collection) {
117
92
  throw new Error(
118
93
  `Expected collection "${collection}", got "${event.collection}"`
119
94
  );
120
95
  }
121
96
  return handler(event);
122
- });
97
+ };
123
98
  }
124
99
  //# sourceMappingURL=webhook.cjs.map
@@ -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 ['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":[]}
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,eAAe,gBACb,SACA,QACA,WACkB;AAClB,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,MAAM,MAAM,OAAO,OAAO;AAAA,IAC9B;AAAA,IACA,QAAQ,OAAO,MAAM;AAAA,IACrB,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IAChC;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,MAAI,UAAU,SAAS,MAAM,KAAK,CAAC,iBAAiB,KAAK,SAAS,GAAG;AACnE,WAAO;AAAA,EACT;AACA,QAAM,WAAW,IAAI;AAAA,KAClB,UAAU,MAAM,OAAO,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,SAAS,MAAM,EAAE,CAAC;AAAA,EACnE;AAEA,SAAO,OAAO,OAAO,OAAO,QAAQ,KAAK,UAAU,QAAQ,OAAO,OAAO,CAAC;AAC5E;AAEA,eAAsB,cACpB,SACA,SACA,SACmB;AACnB,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,KAAK;AAEnC,QAAI,SAAS,QAAQ;AACnB,YAAM,YAAY,QAAQ,QAAQ,IAAI,qBAAqB,KAAK;AAChE,YAAM,QAAQ,MAAM,gBAAgB,SAAS,QAAQ,QAAQ,SAAS;AACtE,UAAI,CAAC,OAAO;AACV,eAAO,IAAI;AAAA,UACT,KAAK,UAAU,EAAE,OAAO,4BAA4B,CAAC;AAAA,UACrD,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,mBAAmB,EAAE;AAAA,QACjE;AAAA,MACF;AAAA,IACF,OAAO;AACL,cAAQ;AAAA,QACN;AAAA,MAEF;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,MAAM,OAAO;AAE/B,QAAI,CAAC,oBAAoB,IAAI,GAAG;AAC9B,aAAO,IAAI;AAAA,QACT,KAAK,UAAU,EAAE,OAAO,+BAA+B,CAAC;AAAA,QACxD,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,mBAAmB,EAAE;AAAA,MACjE;AAAA,IACF;AAEA,UAAM,QAAQ,IAAuB;AAErC,WAAO,IAAI;AAAA,MACT,KAAK,UAAU,EAAE,SAAS,MAAM,SAAS,oBAAoB,CAAC;AAAA,MAC9D,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,mBAAmB,EAAE;AAAA,IACjE;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,6BAA6B,KAAK;AAEhD,WAAO,IAAI,SAAS,KAAK,UAAU,EAAE,OAAO,wBAAwB,CAAC,GAAG;AAAA,MACtE,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAChD,CAAC;AAAA,EACH;AACF;AAEO,SAAS,0BACd,YACA,SACmB;AACnB,SAAO,OAAO,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.js CHANGED
@@ -1,98 +1,72 @@
1
- var __async = (__this, __arguments, generator) => {
2
- return new Promise((resolve, reject) => {
3
- var fulfilled = (value) => {
4
- try {
5
- step(generator.next(value));
6
- } catch (e) {
7
- reject(e);
8
- }
9
- };
10
- var rejected = (value) => {
11
- try {
12
- step(generator.throw(value));
13
- } catch (e) {
14
- reject(e);
15
- }
16
- };
17
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
18
- step((generator = generator.apply(__this, __arguments)).next());
19
- });
20
- };
21
-
22
1
  // src/core/webhook/index.ts
23
2
  function isValidWebhookEvent(data) {
24
3
  if (typeof data !== "object" || data === null) return false;
25
4
  const obj = data;
26
5
  return typeof obj.collection === "string" && (obj.operation === "create" || obj.operation === "update") && typeof obj.data === "object" && obj.data !== null;
27
6
  }
28
- function verifySignature(payload, secret, signature) {
29
- return __async(this, null, function* () {
30
- var _a;
31
- const encoder = new TextEncoder();
32
- const key = yield crypto.subtle.importKey(
33
- "raw",
34
- encoder.encode(secret),
35
- { name: "HMAC", hash: "SHA-256" },
36
- false,
37
- ["verify"]
38
- );
39
- if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
40
- return false;
41
- }
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
- });
7
+ async function verifySignature(payload, secret, signature) {
8
+ const encoder = new TextEncoder();
9
+ const key = await crypto.subtle.importKey(
10
+ "raw",
11
+ encoder.encode(secret),
12
+ { name: "HMAC", hash: "SHA-256" },
13
+ false,
14
+ ["verify"]
15
+ );
16
+ if (signature.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(signature)) {
17
+ return false;
18
+ }
19
+ const sigBytes = new Uint8Array(
20
+ (signature.match(/.{2}/g) ?? []).map((byte) => parseInt(byte, 16))
21
+ );
22
+ return crypto.subtle.verify("HMAC", key, sigBytes, encoder.encode(payload));
47
23
  }
48
- function handleWebhook(request, handler, options) {
49
- return __async(this, null, function* () {
50
- try {
51
- const rawBody = yield request.text();
52
- if (options == null ? void 0 : options.secret) {
53
- const signature = request.headers.get("x-webhook-signature") || "";
54
- const valid = yield verifySignature(rawBody, options.secret, signature);
55
- if (!valid) {
56
- return new Response(
57
- JSON.stringify({ error: "Invalid webhook signature" }),
58
- { status: 401, headers: { "Content-Type": "application/json" } }
59
- );
60
- }
61
- } else {
62
- console.warn(
63
- "[@01.software/sdk] Webhook signature verification is disabled. Set { secret } in handleWebhook() options to enable HMAC-SHA256 verification."
64
- );
65
- }
66
- const body = JSON.parse(rawBody);
67
- if (!isValidWebhookEvent(body)) {
24
+ async function handleWebhook(request, handler, options) {
25
+ try {
26
+ const rawBody = await request.text();
27
+ if (options?.secret) {
28
+ const signature = request.headers.get("x-webhook-signature") || "";
29
+ const valid = await verifySignature(rawBody, options.secret, signature);
30
+ if (!valid) {
68
31
  return new Response(
69
- JSON.stringify({ error: "Invalid webhook event format" }),
70
- { status: 400, headers: { "Content-Type": "application/json" } }
32
+ JSON.stringify({ error: "Invalid webhook signature" }),
33
+ { status: 401, headers: { "Content-Type": "application/json" } }
71
34
  );
72
35
  }
73
- yield handler(body);
36
+ } else {
37
+ console.warn(
38
+ "[@01.software/sdk] Webhook signature verification is disabled. Set { secret } in handleWebhook() options to enable HMAC-SHA256 verification."
39
+ );
40
+ }
41
+ const body = JSON.parse(rawBody);
42
+ if (!isValidWebhookEvent(body)) {
74
43
  return new Response(
75
- JSON.stringify({ success: true, message: "Webhook processed" }),
76
- { status: 200, headers: { "Content-Type": "application/json" } }
44
+ JSON.stringify({ error: "Invalid webhook event format" }),
45
+ { status: 400, headers: { "Content-Type": "application/json" } }
77
46
  );
78
- } catch (error) {
79
- console.error("Webhook processing error:", error);
80
- return new Response(JSON.stringify({ error: "Internal server error" }), {
81
- status: 500,
82
- headers: { "Content-Type": "application/json" }
83
- });
84
47
  }
85
- });
48
+ await handler(body);
49
+ return new Response(
50
+ JSON.stringify({ success: true, message: "Webhook processed" }),
51
+ { status: 200, headers: { "Content-Type": "application/json" } }
52
+ );
53
+ } catch (error) {
54
+ console.error("Webhook processing error:", error);
55
+ return new Response(JSON.stringify({ error: "Internal server error" }), {
56
+ status: 500,
57
+ headers: { "Content-Type": "application/json" }
58
+ });
59
+ }
86
60
  }
87
61
  function createTypedWebhookHandler(collection, handler) {
88
- return (event) => __async(null, null, function* () {
62
+ return async (event) => {
89
63
  if (event.collection !== collection) {
90
64
  throw new Error(
91
65
  `Expected collection "${collection}", got "${event.collection}"`
92
66
  );
93
67
  }
94
68
  return handler(event);
95
- });
69
+ };
96
70
  }
97
71
  export {
98
72
  createTypedWebhookHandler,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/webhook/index.ts"],"sourcesContent":["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":";;;;;;;;;;;;;;;;;;;;;;AAmBO,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":[]}
1
+ {"version":3,"sources":["../src/core/webhook/index.ts"],"sourcesContent":["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":";AAmBO,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,eAAe,gBACb,SACA,QACA,WACkB;AAClB,QAAM,UAAU,IAAI,YAAY;AAChC,QAAM,MAAM,MAAM,OAAO,OAAO;AAAA,IAC9B;AAAA,IACA,QAAQ,OAAO,MAAM;AAAA,IACrB,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IAChC;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,MAAI,UAAU,SAAS,MAAM,KAAK,CAAC,iBAAiB,KAAK,SAAS,GAAG;AACnE,WAAO;AAAA,EACT;AACA,QAAM,WAAW,IAAI;AAAA,KAClB,UAAU,MAAM,OAAO,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,SAAS,MAAM,EAAE,CAAC;AAAA,EACnE;AAEA,SAAO,OAAO,OAAO,OAAO,QAAQ,KAAK,UAAU,QAAQ,OAAO,OAAO,CAAC;AAC5E;AAEA,eAAsB,cACpB,SACA,SACA,SACmB;AACnB,MAAI;AACF,UAAM,UAAU,MAAM,QAAQ,KAAK;AAEnC,QAAI,SAAS,QAAQ;AACnB,YAAM,YAAY,QAAQ,QAAQ,IAAI,qBAAqB,KAAK;AAChE,YAAM,QAAQ,MAAM,gBAAgB,SAAS,QAAQ,QAAQ,SAAS;AACtE,UAAI,CAAC,OAAO;AACV,eAAO,IAAI;AAAA,UACT,KAAK,UAAU,EAAE,OAAO,4BAA4B,CAAC;AAAA,UACrD,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,mBAAmB,EAAE;AAAA,QACjE;AAAA,MACF;AAAA,IACF,OAAO;AACL,cAAQ;AAAA,QACN;AAAA,MAEF;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,MAAM,OAAO;AAE/B,QAAI,CAAC,oBAAoB,IAAI,GAAG;AAC9B,aAAO,IAAI;AAAA,QACT,KAAK,UAAU,EAAE,OAAO,+BAA+B,CAAC;AAAA,QACxD,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,mBAAmB,EAAE;AAAA,MACjE;AAAA,IACF;AAEA,UAAM,QAAQ,IAAuB;AAErC,WAAO,IAAI;AAAA,MACT,KAAK,UAAU,EAAE,SAAS,MAAM,SAAS,oBAAoB,CAAC;AAAA,MAC9D,EAAE,QAAQ,KAAK,SAAS,EAAE,gBAAgB,mBAAmB,EAAE;AAAA,IACjE;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,6BAA6B,KAAK;AAEhD,WAAO,IAAI,SAAS,KAAK,UAAU,EAAE,OAAO,wBAAwB,CAAC,GAAG;AAAA,MACtE,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAChD,CAAC;AAAA,EACH;AACF;AAEO,SAAS,0BACd,YACA,SACmB;AACnB,SAAO,OAAO,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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@01.software/sdk",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "01.software SDK",
5
5
  "author": "<office@01.works>",
6
6
  "keywords": [],
@@ -148,8 +148,8 @@
148
148
  "shadcn": "^3.6.3",
149
149
  "tsup": "^8.3.7",
150
150
  "vitest": "^3.2.3",
151
- "@repo/eslint-config": "0.0.0",
152
- "@repo/typescript-config": "0.0.0"
151
+ "@repo/typescript-config": "0.0.0",
152
+ "@repo/eslint-config": "0.0.0"
153
153
  },
154
154
  "dependencies": {
155
155
  "@payloadcms/richtext-lexical": ">=3.78.0",