@braintwopoint0/playback-commons 0.2.5 → 0.2.7
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/dist/api/index.d.ts +34 -0
- package/dist/api/index.js +26 -0
- package/dist/api/index.js.map +1 -0
- package/dist/ui/index.d.ts +40 -1
- package/dist/ui/index.js +367 -226
- package/dist/ui/index.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
type CorsOptions = {
|
|
2
|
+
/** Comma-separated method list. Default: 'POST, OPTIONS'. */
|
|
3
|
+
methods?: string;
|
|
4
|
+
/** Comma-separated header allowlist. Default: 'Content-Type'. */
|
|
5
|
+
headers?: string;
|
|
6
|
+
/** Preflight cache duration in seconds. Default: 86400 (24h). */
|
|
7
|
+
maxAge?: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Build CORS response headers.
|
|
11
|
+
*
|
|
12
|
+
* Always returns `Vary: Origin` so caches don't serve a CORS-allowed response
|
|
13
|
+
* to a different origin. Only emits `Access-Control-*` headers when the request
|
|
14
|
+
* Origin is in the allowlist — exact-match, no wildcards, so a typo'd subdomain
|
|
15
|
+
* or rogue preview URL can't post into a production endpoint.
|
|
16
|
+
*
|
|
17
|
+
* Same-origin requests have no Origin header on POST in some browsers and never
|
|
18
|
+
* preflight, so an absent or unknown origin returning the empty CORS set is the
|
|
19
|
+
* correct behavior.
|
|
20
|
+
*/
|
|
21
|
+
declare function corsHeaders(origin: string | null, allowed: ReadonlySet<string>, opts?: CorsOptions): Record<string, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Build a preflight (OPTIONS) Response. Use directly as the route's OPTIONS export:
|
|
24
|
+
*
|
|
25
|
+
* export const OPTIONS = (req: NextRequest) => corsPreflight(req, ALLOWED_ORIGINS)
|
|
26
|
+
*
|
|
27
|
+
* Returns 204 No Content with the CORS headers built from the request's Origin
|
|
28
|
+
* against the allowlist. If the origin isn't allowed, the response still returns
|
|
29
|
+
* 204 but without the `Access-Control-Allow-*` headers — which is what the browser
|
|
30
|
+
* needs to see in order to block the subsequent real request.
|
|
31
|
+
*/
|
|
32
|
+
declare function corsPreflight(req: Request, allowed: ReadonlySet<string>, opts?: CorsOptions): Response;
|
|
33
|
+
|
|
34
|
+
export { type CorsOptions, corsHeaders, corsPreflight };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/api/index.ts
|
|
2
|
+
var DEFAULT_METHODS = "POST, OPTIONS";
|
|
3
|
+
var DEFAULT_HEADERS = "Content-Type";
|
|
4
|
+
var DEFAULT_MAX_AGE = 86400;
|
|
5
|
+
function corsHeaders(origin, allowed, opts = {}) {
|
|
6
|
+
const headers = { Vary: "Origin" };
|
|
7
|
+
if (origin && allowed.has(origin)) {
|
|
8
|
+
headers["Access-Control-Allow-Origin"] = origin;
|
|
9
|
+
headers["Access-Control-Allow-Methods"] = opts.methods ?? DEFAULT_METHODS;
|
|
10
|
+
headers["Access-Control-Allow-Headers"] = opts.headers ?? DEFAULT_HEADERS;
|
|
11
|
+
headers["Access-Control-Max-Age"] = String(opts.maxAge ?? DEFAULT_MAX_AGE);
|
|
12
|
+
}
|
|
13
|
+
return headers;
|
|
14
|
+
}
|
|
15
|
+
function corsPreflight(req, allowed, opts) {
|
|
16
|
+
const origin = req.headers.get("origin");
|
|
17
|
+
return new Response(null, {
|
|
18
|
+
status: 204,
|
|
19
|
+
headers: corsHeaders(origin, allowed, opts)
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
corsHeaders,
|
|
24
|
+
corsPreflight
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/api/index.ts"],"sourcesContent":["// CORS primitives for cross-origin API routes between PLAYBACK / PLAYHUB / future\n// PLAYBACK-suite apps.\n//\n// The mechanism (header construction, preflight response) lives here. The policy\n// — i.e. which origins are allowed to call a given endpoint — is intentionally\n// per-route, since \"who can hit my newsletter endpoint\" is a different decision\n// from \"who can hit my admin endpoint\".\n\nexport type CorsOptions = {\n /** Comma-separated method list. Default: 'POST, OPTIONS'. */\n methods?: string\n /** Comma-separated header allowlist. Default: 'Content-Type'. */\n headers?: string\n /** Preflight cache duration in seconds. Default: 86400 (24h). */\n maxAge?: number\n}\n\nconst DEFAULT_METHODS = 'POST, OPTIONS'\nconst DEFAULT_HEADERS = 'Content-Type'\nconst DEFAULT_MAX_AGE = 86400\n\n/**\n * Build CORS response headers.\n *\n * Always returns `Vary: Origin` so caches don't serve a CORS-allowed response\n * to a different origin. Only emits `Access-Control-*` headers when the request\n * Origin is in the allowlist — exact-match, no wildcards, so a typo'd subdomain\n * or rogue preview URL can't post into a production endpoint.\n *\n * Same-origin requests have no Origin header on POST in some browsers and never\n * preflight, so an absent or unknown origin returning the empty CORS set is the\n * correct behavior.\n */\nexport function corsHeaders(\n origin: string | null,\n allowed: ReadonlySet<string>,\n opts: CorsOptions = {}\n): Record<string, string> {\n const headers: Record<string, string> = { Vary: 'Origin' }\n if (origin && allowed.has(origin)) {\n headers['Access-Control-Allow-Origin'] = origin\n headers['Access-Control-Allow-Methods'] = opts.methods ?? DEFAULT_METHODS\n headers['Access-Control-Allow-Headers'] = opts.headers ?? DEFAULT_HEADERS\n headers['Access-Control-Max-Age'] = String(opts.maxAge ?? DEFAULT_MAX_AGE)\n }\n return headers\n}\n\n/**\n * Build a preflight (OPTIONS) Response. Use directly as the route's OPTIONS export:\n *\n * export const OPTIONS = (req: NextRequest) => corsPreflight(req, ALLOWED_ORIGINS)\n *\n * Returns 204 No Content with the CORS headers built from the request's Origin\n * against the allowlist. If the origin isn't allowed, the response still returns\n * 204 but without the `Access-Control-Allow-*` headers — which is what the browser\n * needs to see in order to block the subsequent real request.\n */\nexport function corsPreflight(\n req: Request,\n allowed: ReadonlySet<string>,\n opts?: CorsOptions\n): Response {\n const origin = req.headers.get('origin')\n return new Response(null, {\n status: 204,\n headers: corsHeaders(origin, allowed, opts),\n })\n}\n"],"mappings":";AAiBA,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AAcjB,SAAS,YACd,QACA,SACA,OAAoB,CAAC,GACG;AACxB,QAAM,UAAkC,EAAE,MAAM,SAAS;AACzD,MAAI,UAAU,QAAQ,IAAI,MAAM,GAAG;AACjC,YAAQ,6BAA6B,IAAI;AACzC,YAAQ,8BAA8B,IAAI,KAAK,WAAW;AAC1D,YAAQ,8BAA8B,IAAI,KAAK,WAAW;AAC1D,YAAQ,wBAAwB,IAAI,OAAO,KAAK,UAAU,eAAe;AAAA,EAC3E;AACA,SAAO;AACT;AAYO,SAAS,cACd,KACA,SACA,MACU;AACV,QAAM,SAAS,IAAI,QAAQ,IAAI,QAAQ;AACvC,SAAO,IAAI,SAAS,MAAM;AAAA,IACxB,QAAQ;AAAA,IACR,SAAS,YAAY,QAAQ,SAAS,IAAI;AAAA,EAC5C,CAAC;AACH;","names":[]}
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -295,6 +295,45 @@ interface SearchBarProps extends Omit<React$1.InputHTMLAttributes<HTMLInputEleme
|
|
|
295
295
|
}
|
|
296
296
|
declare function SearchBar({ value, onChange, onClear, className, placeholder, ...props }: SearchBarProps): react_jsx_runtime.JSX.Element;
|
|
297
297
|
|
|
298
|
+
interface MultiSelectOption {
|
|
299
|
+
value: string;
|
|
300
|
+
label: string;
|
|
301
|
+
/** Optional badge shown after the label (e.g. row count). */
|
|
302
|
+
count?: number;
|
|
303
|
+
}
|
|
304
|
+
interface MultiSelectProps {
|
|
305
|
+
options: MultiSelectOption[];
|
|
306
|
+
selected: string[];
|
|
307
|
+
onChange: (selected: string[]) => void;
|
|
308
|
+
placeholder?: string;
|
|
309
|
+
searchPlaceholder?: string;
|
|
310
|
+
emptyLabel?: string;
|
|
311
|
+
/** Hide the search input when there are fewer than this many options. */
|
|
312
|
+
searchThreshold?: number;
|
|
313
|
+
/** Show a "Clear all" affordance inside the popover when something is selected. */
|
|
314
|
+
clearable?: boolean;
|
|
315
|
+
/** Tailwind classes applied to the trigger button. */
|
|
316
|
+
className?: string;
|
|
317
|
+
/** Popover content width. Defaults to w-72. */
|
|
318
|
+
contentClassName?: string;
|
|
319
|
+
/** Aria-label for the trigger. */
|
|
320
|
+
'aria-label'?: string;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Multi-select dropdown — a search-and-pick alternative to chip lists when
|
|
324
|
+
* the option count gets unwieldy. Composes the existing Popover + Checkbox
|
|
325
|
+
* + Input primitives so styling stays consistent with the rest of commons.
|
|
326
|
+
*
|
|
327
|
+
* Trigger renders:
|
|
328
|
+
* - placeholder when nothing is selected
|
|
329
|
+
* - the single option's label when exactly one is selected
|
|
330
|
+
* - "N selected" when multiple are selected
|
|
331
|
+
*
|
|
332
|
+
* Designed for short-to-medium option lists (~5-100). For very long lists
|
|
333
|
+
* consider a virtualised picker.
|
|
334
|
+
*/
|
|
335
|
+
declare function MultiSelect({ options, selected, onChange, placeholder, searchPlaceholder, emptyLabel, searchThreshold, clearable, className, contentClassName, 'aria-label': ariaLabel, }: MultiSelectProps): react_jsx_runtime.JSX.Element;
|
|
336
|
+
|
|
298
337
|
interface DataRowProps extends React$1.HTMLAttributes<HTMLDivElement> {
|
|
299
338
|
status?: 'green' | 'yellow' | 'red' | 'gray';
|
|
300
339
|
primary: string;
|
|
@@ -577,4 +616,4 @@ type ResetPasswordFormProps = {
|
|
|
577
616
|
};
|
|
578
617
|
declare function ResetPasswordForm({ loginHref, initialError, redirectDelayMs, title, subtitle, }: ResetPasswordFormProps): react_jsx_runtime.JSX.Element;
|
|
579
618
|
|
|
580
|
-
export { AnimatedTooltip, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Button, type ButtonProps, Calendar, CalendarDayButton, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, DataRow, type DataRowProps, DatePicker, DateTimePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, EmptyState, type EmptyStateProps, FadeIn, type FadeInProps, FlipWords, Footer, type FooterColumnDef, FooterCreditsBar, type FooterCreditsBarProps, type FooterLinkDef, type FooterProps, type FooterSocialDef, type FooterSocialLink, ForgotPasswordForm, type ForgotPasswordFormProps, HeroHighlight, Highlight, HoverCard, HoverCardDescription, HoverCardTitle, HoverEffect, Input, type InputProps, Label, LumaSpin, NewsletterForm, type NewsletterFormProps, PageShell, type PageShellProps, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ResetPasswordForm, type ResetPasswordFormProps, SearchBar, type SearchBarProps, SectionCard, type SectionCardProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SignInForm, type SignInFormProps, SiteFooter, type SiteFooterProps, Skeleton, type StatItem, StatsGrid, type StatsGridProps, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, TimePicker, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, easeSmooth, fadeInDown, fadeInUp, hoverLift, hoverScale, pageTransition, springBounce, staggerContainer, staggerItem };
|
|
619
|
+
export { AnimatedTooltip, Avatar, AvatarFallback, AvatarImage, Badge, type BadgeProps, Button, type ButtonProps, Calendar, CalendarDayButton, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, DataRow, type DataRowProps, DatePicker, DateTimePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, EmptyState, type EmptyStateProps, FadeIn, type FadeInProps, FlipWords, Footer, type FooterColumnDef, FooterCreditsBar, type FooterCreditsBarProps, type FooterLinkDef, type FooterProps, type FooterSocialDef, type FooterSocialLink, ForgotPasswordForm, type ForgotPasswordFormProps, HeroHighlight, Highlight, HoverCard, HoverCardDescription, HoverCardTitle, HoverEffect, Input, type InputProps, Label, LumaSpin, MultiSelect, type MultiSelectOption, type MultiSelectProps, NewsletterForm, type NewsletterFormProps, PageShell, type PageShellProps, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ResetPasswordForm, type ResetPasswordFormProps, SearchBar, type SearchBarProps, SectionCard, type SectionCardProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SignInForm, type SignInFormProps, SiteFooter, type SiteFooterProps, Skeleton, type StatItem, StatsGrid, type StatsGridProps, Switch, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, TimePicker, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, easeSmooth, fadeInDown, fadeInUp, hoverLift, hoverScale, pageTransition, springBounce, staggerContainer, staggerItem };
|