@tempoxyz/id 0.0.0-pr-349.sha-fd1d6ff → 0.0.0-pr-416.sha-e4bee27

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.
@@ -1 +1 @@
1
- {"version":3,"file":"Grant-TXwmc9xo.js","names":["REASONS.closePress","BaseUi.Popover.Close","BaseUi.Popover.Root","BaseUi.Popover.Trigger","_jsx","BaseUi.Popover.Arrow","styles","BaseUi.Popover.Description","BaseUi.Popover.Portal","BaseUi.Popover.Positioner","BaseUi.Popover.Popup","BaseUi.Popover.Title","_jsxs","_jsx","__import_glob__0_0_","__import_glob__0_1_","__import_glob__0_2_","__import_glob__0_3_","__import_glob__0_4_","__import_glob__0_5_","__import_glob__0_6_","__import_glob__0_7_","__import_glob__0_8_","__import_glob__0_9_","__import_glob__0_10_","__import_glob__0_11_","__import_glob__0_12_","__import_glob__0_13_","__import_glob__0_14_","__import_glob__0_15_","__import_glob__0_16_","__import_glob__0_17_","__import_glob__0_18_","__import_glob__0_19_","__import_glob__0_20_","__import_glob__0_21_","__import_glob__0_22_","__import_glob__0_23_","__import_glob__0_24_","__import_glob__0_25_","__import_glob__0_26_","__import_glob__0_27_","__import_glob__0_28_","__import_glob__0_29_","__import_glob__0_30_","__import_glob__0_31_","__import_glob__0_32_","__import_glob__0_33_","__import_glob__0_34_","__import_glob__0_35_","__import_glob__0_36_","__import_glob__1_0_","__import_glob__1_1_","useId","useState","_Fragment","__toESM","require_react","require_jsx_runtime","Stack","useRenderElement","useButton","create","closePress","createChangeEventDetails","popupStateMapping","useBaseUiId","Tooltip","PopoverPortal","PopoverRoot","usePopoverRootContext","PopoverPositioner","PopoverTrigger","useClosePartRegistration","usePopoverPositionerContext","PopoverPopup","Alert","Inline","StatusChip","CheckCircle","InfoCircle","import_react","PopoverArrow","elementProps","componentProps","open","arrowUncentered","forwardedRef","arrowRef","arrowStyles","PopoverTitle","store","id","PopoverDescription","PopoverClose","nativeButton","buttonRef","event","getButtonProps","import_jsx_runtime","Popover","Arrow","attributes","props","styles$1","Description","Popup","Title","XCircle","BRLA_default","BRZ_default","CHFAU_default","DLUSD_default","EURAU_default","EURC_e_default","GBPA_default","GUSD_default","MACH_default","OUSD_default","PRIME_default","SBC_default","SEKAU_default","USD1_default","USDB_default","USDC_e_default","USDT0_default","USDY_default","USDe_default","YLDS_default","alphaUSD_default","betaUSD_default","cUSD_default","cbBTC_default","frxUSD_default","goUSD_default","iUSD_default","pathUSD_default","rUSD_default","reUSD_default","sUSDe_default","siUSD_default","stcUSD_default","syrupUSDC_default","thetaUSD_default","wYLDS_default","wsrUSD_default","OUSD_dark_default","OUSD_light_default","icons","file","url","logos","symbol","scheme","result","Abilities","channels","calls","call","topUp","styles","limits","limit","format","every","label","token","logo","icon","Grant","deniedId","detailsId","details","setDetails","Heading","until","expiry","unrecognized","decimal","relative","spans","units","unit","seconds","period","entry","count","amount","remaining"],"sources":["../../../../../node_modules/.pnpm/@base-ui+react@1.9.0_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react@19.3.0/node_modules/@base-ui/react/popover/arrow/PopoverArrow.mjs","../../../../../node_modules/.pnpm/@base-ui+react@1.9.0_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react@19.3.0/node_modules/@base-ui/react/popover/title/PopoverTitle.mjs","../../../../../node_modules/.pnpm/@base-ui+react@1.9.0_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react@19.3.0/node_modules/@base-ui/react/popover/description/PopoverDescription.mjs","../../../../../node_modules/.pnpm/@base-ui+react@1.9.0_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react@19.3.0/node_modules/@base-ui/react/popover/close/PopoverClose.mjs","../../../../../node_modules/.pnpm/@tempoxyz+ds@0.3.5_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react-native@0.86_b327597bc920a5831d2a012c973d2470/node_modules/@tempoxyz/ds/dist/web/components/Popover.css","../../../../../node_modules/.pnpm/@tempoxyz+ds@0.3.5_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react-native@0.86_b327597bc920a5831d2a012c973d2470/node_modules/@tempoxyz/ds/dist/web/components/Popover.js","../../../../../node_modules/.pnpm/@tempoxyz+ds@0.3.5_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react-native@0.86_b327597bc920a5831d2a012c973d2470/node_modules/@tempoxyz/ds/dist/web/icons/XCircle.js","../../../components/icons/BRLA.png?no-inline","../../../components/icons/BRZ.svg?no-inline","../../../components/icons/CHFAU.png?no-inline","../../../components/icons/DLUSD.png?no-inline","../../../components/icons/EURAU.svg?no-inline","../../../components/icons/EURC.e.svg?no-inline","../../../components/icons/GBPA.svg?no-inline","../../../components/icons/GUSD.svg?no-inline","../../../components/icons/MACH.svg?no-inline","../../../components/icons/OUSD.svg?no-inline","../../../components/icons/PRIME.svg?no-inline","../../../components/icons/SBC.svg?no-inline","../../../components/icons/SEKAU.svg?no-inline","../../../components/icons/USD1.svg?no-inline","../../../components/icons/USDB.svg?no-inline","../../../components/icons/USDC.e.svg?no-inline","../../../components/icons/USDT0.svg?no-inline","../../../components/icons/USDY.svg?no-inline","../../../components/icons/USDe.svg?no-inline","../../../components/icons/YLDS.svg?no-inline","../../../components/icons/alphaUSD.svg?no-inline","../../../components/icons/betaUSD.svg?no-inline","../../../components/icons/cUSD.svg?no-inline","../../../components/icons/cbBTC.svg?no-inline","../../../components/icons/frxUSD.svg?no-inline","../../../components/icons/goUSD.svg?no-inline","../../../components/icons/iUSD.svg?no-inline","../../../components/icons/pathUSD.svg?no-inline","../../../components/icons/rUSD.svg?no-inline","../../../components/icons/reUSD.svg?no-inline","../../../components/icons/sUSDe.svg?no-inline","../../../components/icons/siUSD.svg?no-inline","../../../components/icons/stcUSD.svg?no-inline","../../../components/icons/syrupUSDC.svg?no-inline","../../../components/icons/thetaUSD.svg?no-inline","../../../components/icons/wYLDS.svg?no-inline","../../../components/icons/wsrUSD.svg?no-inline","../../../components/logos/OUSD.dark.svg?no-inline","../../../components/logos/OUSD.light.svg?no-inline","../../../components/Grant.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { usePopoverPositionerContext } from \"../positioner/PopoverPositionerContext.mjs\";\nimport { usePopoverRootContext } from \"../root/PopoverRootContext.mjs\";\nimport { popupStateMapping } from \"../../utils/popupStateMapping.mjs\";\nimport { useRenderElement } from \"../../internals/useRenderElement.mjs\";\n\n/**\n * Displays an element positioned against the popover anchor.\n * Renders a `<div>` element.\n *\n * Documentation: [Base UI Popover](https://base-ui.com/react/components/popover)\n */\nexport const PopoverArrow = /*#__PURE__*/React.forwardRef(function PopoverArrow(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n ...elementProps\n } = componentProps;\n const store = usePopoverRootContext();\n const open = store.useState('open');\n const {\n arrowRef,\n side,\n align,\n arrowUncentered,\n arrowStyles\n } = usePopoverPositionerContext();\n const state = {\n open,\n side,\n align,\n uncentered: arrowUncentered\n };\n const element = useRenderElement('div', componentProps, {\n state,\n ref: [forwardedRef, arrowRef],\n props: [{\n style: arrowStyles,\n 'aria-hidden': true\n }, elementProps],\n stateAttributesMapping: popupStateMapping\n });\n return element;\n});\nif (process.env.NODE_ENV !== \"production\") PopoverArrow.displayName = \"PopoverArrow\";","'use client';\n\nimport * as React from 'react';\nimport { usePopoverRootContext } from \"../root/PopoverRootContext.mjs\";\nimport { useRenderElement } from \"../../internals/useRenderElement.mjs\";\nimport { useBaseUiId } from \"../../internals/useBaseUiId.mjs\";\n\n/**\n * A heading that labels the popover.\n * Renders an `<h2>` element.\n *\n * Documentation: [Base UI Popover](https://base-ui.com/react/components/popover)\n */\nexport const PopoverTitle = /*#__PURE__*/React.forwardRef(function PopoverTitle(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n ...elementProps\n } = componentProps;\n const store = usePopoverRootContext();\n const id = useBaseUiId(elementProps.id);\n store.useSyncedValueWithCleanup('titleElementId', id);\n const element = useRenderElement('h2', componentProps, {\n ref: forwardedRef,\n props: [{\n id\n }, elementProps]\n });\n return element;\n});\nif (process.env.NODE_ENV !== \"production\") PopoverTitle.displayName = \"PopoverTitle\";","'use client';\n\nimport * as React from 'react';\nimport { usePopoverRootContext } from \"../root/PopoverRootContext.mjs\";\nimport { useBaseUiId } from \"../../internals/useBaseUiId.mjs\";\nimport { useRenderElement } from \"../../internals/useRenderElement.mjs\";\n\n/**\n * A paragraph with additional information about the popover.\n * Renders a `<p>` element.\n *\n * Documentation: [Base UI Popover](https://base-ui.com/react/components/popover)\n */\nexport const PopoverDescription = /*#__PURE__*/React.forwardRef(function PopoverDescription(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n ...elementProps\n } = componentProps;\n const store = usePopoverRootContext();\n const id = useBaseUiId(elementProps.id);\n store.useSyncedValueWithCleanup('descriptionElementId', id);\n const element = useRenderElement('p', componentProps, {\n ref: forwardedRef,\n props: [{\n id\n }, elementProps]\n });\n return element;\n});\nif (process.env.NODE_ENV !== \"production\") PopoverDescription.displayName = \"PopoverDescription\";","'use client';\n\nimport * as React from 'react';\nimport { usePopoverRootContext } from \"../root/PopoverRootContext.mjs\";\nimport { useRenderElement } from \"../../internals/useRenderElement.mjs\";\nimport { useButton } from \"../../internals/use-button/index.mjs\";\nimport { createChangeEventDetails } from \"../../internals/createBaseUIEventDetails.mjs\";\nimport { REASONS } from \"../../internals/reasons.mjs\";\nimport { useClosePartRegistration } from \"../../utils/closePart.mjs\";\n\n/**\n * A button that closes the popover.\n * Renders a `<button>` element.\n *\n * Documentation: [Base UI Popover](https://base-ui.com/react/components/popover)\n */\nexport const PopoverClose = /*#__PURE__*/React.forwardRef(function PopoverClose(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n disabled = false,\n nativeButton = true,\n ...elementProps\n } = componentProps;\n const {\n buttonRef,\n getButtonProps\n } = useButton({\n disabled,\n focusableWhenDisabled: false,\n native: nativeButton\n });\n const store = usePopoverRootContext();\n useClosePartRegistration();\n const element = useRenderElement('button', componentProps, {\n ref: [forwardedRef, buttonRef],\n props: [{\n onClick(event) {\n store.setOpen(false, createChangeEventDetails(REASONS.closePress, event.nativeEvent));\n }\n }, elementProps, getButtonProps]\n });\n return element;\n});\nif (process.env.NODE_ENV !== \"production\") PopoverClose.displayName = \"PopoverClose\";",".z_tds_2f_web-WYxykg0{color:var(--z-tds_2f_web-color-background-elevated,light-dark(var(--z-tds_2f_web-color-neutral-000,#fff),var(--z-tds_2f_web-color-neutral-092,#141414)))}.z_tds_2f_web-WYxykg1{display:flex}.z_tds_2f_web-WYxykg2{&[data-side=bottom]{top:-10px}}.z_tds_2f_web-WYxykg3{&[data-side=left]{right:-14px}}.z_tds_2f_web-WYxykg4{&[data-side=left]{rotate:90deg}}.z_tds_2f_web-WYxykg5{&[data-side=right]{left:-14px}}.z_tds_2f_web-WYxykg6{&[data-side=right]{rotate:-90deg}}.z_tds_2f_web-WYxykg7{&[data-side=top]{bottom:-10px}}.z_tds_2f_web-WYxykg8{&[data-side=top]{rotate:180deg}}.z_tds_2f_web-WYxykg9{color:var(--z-tds_2f_web-color-content-secondary,light-dark(var(--z-tds_2f_web-color-neutral-shade-056,#0000008f),var(--z-tds_2f_web-color-neutral-tint-064,#ffffffa3)))}.z_tds_2f_web-WYxykga{margin:var(--z-tds_2f_web-spacing-0,0rem)}.z_tds_2f_web-WYxykgb{font-family:var(--z-tds_2f_web-typography-body-b2-fontFamily,var(--z-tds_2f_web-fontFamily-body,Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"))}.z_tds_2f_web-WYxykgc{font-size:var(--z-tds_2f_web-typography-body-b2-fontSize,14px)}.z_tds_2f_web-WYxykgd{font-weight:var(--z-tds_2f_web-typography-body-b2-fontWeight,400)}.z_tds_2f_web-WYxykge{letter-spacing:var(--z-tds_2f_web-typography-body-b2-letterSpacing,-.09px)}.z_tds_2f_web-WYxykgf{line-height:var(--z-tds_2f_web-typography-body-b2-lineHeight,20px)}.z_tds_2f_web-WYxykgg{background-color:var(--z-tds_2f_web-color-background-elevated,light-dark(var(--z-tds_2f_web-color-neutral-000,#fff),var(--z-tds_2f_web-color-neutral-092,#141414)))}.z_tds_2f_web-WYxykgh{border-radius:var(--z-tds_2f_web-radius-sm,calc(1rem * var(--tds-corner-scale,1)))}.z_tds_2f_web-WYxykgi{box-shadow:var(--z-tds_2f_web-shadow-regular,0 8px 48px #0000000a, 0 4px 16px #0000000a, 0 2px 8px #0000000a)}.z_tds_2f_web-WYxykgj{box-sizing:border-box}.z_tds_2f_web-WYxykgk{color:var(--z-tds_2f_web-color-content-primary,light-dark(var(--z-tds_2f_web-color-neutral-100,#000),var(--z-tds_2f_web-color-neutral-000,#fff)))}.z_tds_2f_web-WYxykgl{max-width:var(--available-width)}.z_tds_2f_web-WYxykgm{outline:none}.z_tds_2f_web-WYxykgn{padding:var(--z-tds_2f_web-spacing-24,1.5rem)}.z_tds_2f_web-WYxykgo{transform-origin:var(--transform-origin)}.z_tds_2f_web-WYxykgp{transition-duration:var(--z-tds_2f_web-transitionDuration-200,.2s)}.z_tds_2f_web-WYxykgq{transition-property:opacity,scale}.z_tds_2f_web-WYxykgr{transition-timing-function:var(--z-tds_2f_web-ease-snappy,cubic-bezier(.23, 1, .32, 1))}.z_tds_2f_web-WYxykgs{width:max-content}.z_tds_2f_web-WYxykgt{&[data-ending-style]{opacity:0}}.z_tds_2f_web-WYxykgu{&[data-ending-style]{scale:var(--z-tds_2f_web-scale-enter,.96)}}.z_tds_2f_web-WYxykgv{&[data-ending-style]{transition-duration:var(--z-tds_2f_web-transitionDuration-140,.14s)}}.z_tds_2f_web-WYxykgw{&[data-starting-style]{opacity:0}}.z_tds_2f_web-WYxykgx{&[data-starting-style]{scale:var(--z-tds_2f_web-scale-enter,.96)}}@media (prefers-reduced-motion:reduce){.z_tds_2f_web-WYxykgy{transition-property:opacity}.z_tds_2f_web-WYxykgz{&[data-ending-style],&[data-starting-style]{scale:none}}}.z_tds_2f_web-WYxykg10{z-index:var(--z-tds_2f_web-zIndex-popover,50)}.z_tds_2f_web-WYxykg11{font-family:var(--z-tds_2f_web-typography-heading-h3-fontFamily,var(--z-tds_2f_web-fontFamily-heading,Pilat, Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif))}.z_tds_2f_web-WYxykg12{font-size:var(--z-tds_2f_web-typography-heading-h3-fontSize,20px)}.z_tds_2f_web-WYxykg13{font-weight:var(--z-tds_2f_web-typography-heading-h3-fontWeight,500)}.z_tds_2f_web-WYxykg14{letter-spacing:var(--z-tds_2f_web-typography-heading-h3-letterSpacing,-.3px)}.z_tds_2f_web-WYxykg15{line-height:var(--z-tds_2f_web-typography-heading-h3-lineHeight,23px)}.z_tds_2f_web-WYxykg16{margin:var(--z-tds_2f_web-spacing-0,0rem)}.z_tds_2f_web-WYxykg17{margin-bottom:var(--z-tds_2f_web-spacing-4,.25rem)}","\nimport { Props as __zyzzProps } from 'zyzz/runtime';\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nimport * as BaseUi from '@base-ui/react/popover';\nimport { style } from '../zyzz.config.js';\n/**\n * A non-modal `dialog` anchored to a trigger and opened on click. Opening moves focus to the first\n * tabbable element inside, or to the popup on touch. Escape and outside presses close it and\n * return focus to the trigger.\n *\n * - Use it for interactive or longer content. Use `Tooltip` for a short hint on hover.\n * - Include `Title` so the dialog has an accessible name, and `Description` for supporting text.\n * - Offer `Close` when the popup holds a form or other controls.\n *\n * @example\n * <Popover.Root>\n * <Popover.Trigger render={<Button variant=\"secondary\" />}>Network fee</Popover.Trigger>\n * <Popover.Popup>\n * <Popover.Title>Network fee</Popover.Title>\n * <Popover.Description>Paid in the token you send.</Popover.Description>\n * </Popover.Popup>\n * </Popover.Root>\n *\n * @see {@link https://base-ui.com/react/components/popover | Base UI Popover}\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Popover_API | MDN Popover API}\n * @see {@link https://www.w3.org/WAI/WCAG22/Understanding/content-on-hover-or-focus.html | WCAG 2.2 Content on Hover or Focus}\n * @see {@link https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html | WCAG 2.2 Focus Order}\n * @see {@link https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html | WCAG 2.2 Keyboard}\n */\nexport var Popover;\n(function (Popover) {\n /** Renders a `button` that closes the popover. Pass `render` to use a `Button`. */\n Popover.Close = BaseUi.Popover.Close;\n /**\n * Owns the open state. Pass `open` and `onOpenChange` to control it. Unless `modal` is set, the\n * page stays interactive while the popover is open.\n */\n Popover.Root = BaseUi.Popover.Root;\n /**\n * Toggles the popover on click and anchors the popup. Set `openOnHover` to also open it on hover.\n *\n * @example\n * <Popover.Trigger render={<Button variant=\"secondary\" />}>Network fee</Popover.Trigger>\n */\n Popover.Trigger = BaseUi.Popover.Trigger;\n /** Draws a pointer toward the trigger on the popup's anchored side. Place it inside `Popup`. */\n function Arrow(props) {\n const { className, vars, ...attributes } = props;\n return (_jsx(BaseUi.Popover.Arrow, { ...attributes, ...styles.arrow({ className, style: props.style, vars }), children: _jsx(\"svg\", { \"aria-hidden\": \"true\", fill: \"currentColor\", height: \"10\", viewBox: \"0 0 20 10\", width: \"20\", children: _jsx(\"path\", { d: \"M0 10C4 10 7 7 8.6 4.6a2 2 0 0 1 2.8 0C13 7 16 10 20 10Z\" }) }) }));\n }\n Popover.Arrow = Arrow;\n /** Renders a `p` that describes the popup through `aria-describedby`. */\n function Description(props) {\n const { className, vars, ...attributes } = props;\n return (_jsx(BaseUi.Popover.Description, { ...attributes, ...styles.description({ className, style: props.style, vars }) }));\n }\n Popover.Description = Description;\n /**\n * Renders the portal, positioner and popup. Placement props go to the positioner, which sits 8px\n * from the trigger unless `sideOffset` is set. Other props, `ref`, `className` and `style` reach\n * the popup. `initialFocus` and `finalFocus` override where focus moves on open and close.\n */\n function Popup(props) {\n const { align, alignOffset, anchor, className, collisionPadding, side, sideOffset = 8, vars, ...attributes } = props;\n return (_jsx(BaseUi.Popover.Portal, { children: _jsx(BaseUi.Popover.Positioner, { ...styles.positioner(), align: align, alignOffset: alignOffset, anchor: anchor, collisionPadding: collisionPadding, side: side, sideOffset: sideOffset, children: _jsx(BaseUi.Popover.Popup, { ...attributes, ...styles.popup({ className, style: props.style, vars }) }) }) }));\n }\n Popover.Popup = Popup;\n /** Renders an `h2` that names the popup through `aria-labelledby`. */\n function Title(props) {\n const { className, vars, ...attributes } = props;\n return (_jsx(BaseUi.Popover.Title, { ...attributes, ...styles.title({ className, style: props.style, vars }) }));\n }\n Popover.Title = Title;\n})(Popover || (Popover = {}));\nvar styles;\n(function (styles) {\n styles.arrow = /*#__PURE__*/__zyzzProps.create({className:\"z_tds_2f_web-WYxykg0 z_tds_2f_web-WYxykg1 z_tds_2f_web-WYxykg2 z_tds_2f_web-WYxykg3 z_tds_2f_web-WYxykg4 z_tds_2f_web-WYxykg5 z_tds_2f_web-WYxykg6 z_tds_2f_web-WYxykg7 z_tds_2f_web-WYxykg8\"});\n styles.description = /*#__PURE__*/__zyzzProps.create({className:\"z_tds_2f_web-WYxykg9 z_tds_2f_web-WYxykga z_tds_2f_web-WYxykgb z_tds_2f_web-WYxykgc z_tds_2f_web-WYxykgd z_tds_2f_web-WYxykge z_tds_2f_web-WYxykgf\"});\n styles.popup = /*#__PURE__*/__zyzzProps.create({className:\"z_tds_2f_web-WYxykgg z_tds_2f_web-WYxykgh z_tds_2f_web-WYxykgi z_tds_2f_web-WYxykgj z_tds_2f_web-WYxykgk z_tds_2f_web-WYxykgl z_tds_2f_web-WYxykgm z_tds_2f_web-WYxykgn z_tds_2f_web-WYxykgo z_tds_2f_web-WYxykgp z_tds_2f_web-WYxykgq z_tds_2f_web-WYxykgr z_tds_2f_web-WYxykgb z_tds_2f_web-WYxykgc z_tds_2f_web-WYxykgd z_tds_2f_web-WYxykge z_tds_2f_web-WYxykgf z_tds_2f_web-WYxykgs z_tds_2f_web-WYxykgt z_tds_2f_web-WYxykgu z_tds_2f_web-WYxykgv z_tds_2f_web-WYxykgw z_tds_2f_web-WYxykgx z_tds_2f_web-WYxykgy z_tds_2f_web-WYxykgz\"});\n styles.positioner = /*#__PURE__*/__zyzzProps.create({className:\"z_tds_2f_web-WYxykg10\"});\n styles.title = /*#__PURE__*/__zyzzProps.create({className:\"z_tds_2f_web-WYxykg11 z_tds_2f_web-WYxykg12 z_tds_2f_web-WYxykg13 z_tds_2f_web-WYxykg14 z_tds_2f_web-WYxykg15 z_tds_2f_web-WYxykg16 z_tds_2f_web-WYxykg17\"});\n})(styles || (styles = {}));\n//# sourceMappingURL=Popover.js.map\nimport './Popover.css';\n","import { jsx as _jsx, jsxs as _jsxs } from \"react/jsx-runtime\";\nexport function XCircle(props) {\n return (_jsxs(\"svg\", { width: \"1em\", height: \"1em\", viewBox: \"0 0 16 16\", fill: \"none\", xmlns: \"http://www.w3.org/2000/svg\", \"aria-hidden\": props['aria-label'] || props['aria-labelledby'] ? undefined : true, role: props['aria-label'] || props['aria-labelledby'] ? 'img' : undefined, ...props, children: [_jsx(\"path\", { d: \"M9.64648 5.64648C9.84175 5.45122 10.1583 5.45122 10.3535 5.64648C10.5487 5.84175 10.5488 6.15827 10.3535 6.35352L8.70703 8L10.3535 9.64648C10.5487 9.84175 10.5488 10.1583 10.3535 10.3535C10.1583 10.5488 9.84175 10.5487 9.64648 10.3535L8 8.70703L6.35352 10.3535C6.15827 10.5488 5.84175 10.5487 5.64648 10.3535C5.45122 10.1583 5.45122 9.84175 5.64648 9.64648L7.29297 8L5.64648 6.35352C5.45122 6.15825 5.45122 5.84175 5.64648 5.64648C5.84175 5.45122 6.15825 5.45122 6.35352 5.64648L8 7.29297L9.64648 5.64648Z\", fill: \"currentColor\" }), _jsx(\"path\", { fillRule: \"evenodd\", clipRule: \"evenodd\", d: \"M8 1.33301C11.6817 1.33318 14.666 4.31919 14.666 8.00098C14.6656 11.6824 11.6815 14.6668 8 14.667C4.31837 14.667 1.33345 11.6825 1.33301 8.00098C1.33301 4.31908 4.3181 1.33301 8 1.33301ZM8 2.33398C4.87039 2.33398 2.33301 4.87137 2.33301 8.00098C2.33345 11.1302 4.87066 13.667 8 13.667C11.1292 13.6668 13.6656 11.1301 13.666 8.00098C13.666 4.87147 11.1294 2.33416 8 2.33398Z\", fill: \"currentColor\" })] }));\n}\n//# sourceMappingURL=XCircle.js.map","export default import.meta.ROLLDOWN_FILE_URL_q6tfGKm3Qmt5DJmATeHQdA","export default import.meta.ROLLDOWN_FILE_URL_OestAvA2SyLT4CG6L76dAw","export default import.meta.ROLLDOWN_FILE_URL_nJkgIVJgL11RgZiGUBj6wA","export default import.meta.ROLLDOWN_FILE_URL_tgFyw$X211zXSctfMU9_LA","export default import.meta.ROLLDOWN_FILE_URL_LphhLScmzwPqWwTyAbd7ig","export default import.meta.ROLLDOWN_FILE_URL_U6muqRGa8aHtq8t0c9wAzg","export default import.meta.ROLLDOWN_FILE_URL_i2ywl_YzKp2MjtOEr7ngzA","export default import.meta.ROLLDOWN_FILE_URL_tgItkVM6JTrfm2CiQnzY5g","export default import.meta.ROLLDOWN_FILE_URL_zOyQqdNGsn0lL_XEFrarVA","export default import.meta.ROLLDOWN_FILE_URL_TX5a1iViCylaCWPFSCQG2w","export default import.meta.ROLLDOWN_FILE_URL_y3WuTrdTs_Si7uYpRddj9w","export default import.meta.ROLLDOWN_FILE_URL_0PgJxXqjw$KAl6PgZjQb5g","export default import.meta.ROLLDOWN_FILE_URL_kSHvwCjLFxLpY3FM1MyAsA","export default import.meta.ROLLDOWN_FILE_URL_EsSyonNWXFChOyjfj2S3nw","export default import.meta.ROLLDOWN_FILE_URL_e3FJByPCCgv8fip_DM$mWQ","export default import.meta.ROLLDOWN_FILE_URL_yW_eMvu1QqHghXJHMLbBbg","export default import.meta.ROLLDOWN_FILE_URL_07gvO1IvTzTCTyYqp_a5mw","export default import.meta.ROLLDOWN_FILE_URL_qZZZ7EOcQU0bnm2SE9d1Ig","export default import.meta.ROLLDOWN_FILE_URL_RCaHVq_jCUoWDQWiWLxE3w","export default import.meta.ROLLDOWN_FILE_URL_8Jdj9qQ4eJq3labUJOvRYQ","export default import.meta.ROLLDOWN_FILE_URL_gTxdgYqT1FnWrjfbk9DrbA","export default import.meta.ROLLDOWN_FILE_URL_rUkiH63qcJGEQEedyX41xw","export default import.meta.ROLLDOWN_FILE_URL_PWd8aapBt1YfLvgRaedarQ","export default import.meta.ROLLDOWN_FILE_URL_V1ZYpwZc9C51fJhgOTS5xQ","export default import.meta.ROLLDOWN_FILE_URL_HAwZnQ40A17rYC3Q$lxt9A","export default import.meta.ROLLDOWN_FILE_URL_DzYsnjr1LtW1tBWqsYm2RQ","export default import.meta.ROLLDOWN_FILE_URL_3Lrf7vA$GngskD3e2_Wsaw","export default import.meta.ROLLDOWN_FILE_URL_2ZEzIIM_atdpHcr$6kvj$Q","export default import.meta.ROLLDOWN_FILE_URL_6bp_5It$EfTQ8f$omStdjw","export default import.meta.ROLLDOWN_FILE_URL_xUfAOc8vsLn5godiQWqFgA","export default import.meta.ROLLDOWN_FILE_URL_8KByd7W0oH8zGe1MvrBFUw","export default import.meta.ROLLDOWN_FILE_URL_aKo4wVjMjV9S8rY28E5Mvg","export default import.meta.ROLLDOWN_FILE_URL_OxgPY7jd89vmgHQlmb5h_Q","export default import.meta.ROLLDOWN_FILE_URL_Ngmgj7KrmSrUoXH_NFNtFA","export default import.meta.ROLLDOWN_FILE_URL_eBB5uVE_t2Bb1etqpZE3Ig","export default import.meta.ROLLDOWN_FILE_URL_cLLFq7OX38PQjR0WE41fig","export default import.meta.ROLLDOWN_FILE_URL_bLNX6U6f8qE7L2W0pHPLmA","export default import.meta.ROLLDOWN_FILE_URL_UF4iDpNJhIbRdkaNqmNRqw","export default import.meta.ROLLDOWN_FILE_URL_2h$eqWdLjjj$zuUvyPi$HQ","/**\n * Shows a requested key's limits and expiry, and warns about unrecognized calls. {@link Abilities},\n * the list of what a key allows, also serves the permissions page.\n * @module\n */\nimport {\n Alert,\n Inline,\n Popover,\n Stack,\n StatusChip,\n Tooltip,\n} from '@tempoxyz/ds'\nimport { CheckCircle, InfoCircle, XCircle } from '@tempoxyz/ds/icons'\nimport { type ReactNode, useId, useState } from 'react'\nimport type * as KeyAuthorization from '../../internal/KeyAuthorization.js'\nimport { style } from '../zyzz.config.js'\n\n/**\n * Each token's icon URL, by symbol. Each icon stays its own file, since an inlined icon would put\n * every token's icon in the script of each page that shows a key.\n */\nconst icons = Object.fromEntries(\n Object.entries(\n import.meta.glob<string>('./icons/*.{png,svg,webp}', {\n eager: true,\n import: 'default',\n query: '?no-inline',\n }),\n ).map(([file, url]) => [\n file.slice('./icons/'.length, file.lastIndexOf('.')),\n url,\n ]),\n)\n\n/** Logos from `logos/`, by symbol and color scheme, each its own file. A logo replaces the icon. */\nconst logos = Object.entries(\n import.meta.glob<string>('./logos/*.{light,dark}.{png,svg,webp}', {\n eager: true,\n import: 'default',\n query: '?no-inline',\n }),\n).reduce<Record<string, { dark?: string; light?: string }>>(\n (result, [file, url]) => {\n const [, symbol, scheme] = file.match(\n /^\\.\\/logos\\/(.+)\\.(light|dark)\\.\\w+$/,\n )!\n result[symbol!] = { ...result[symbol!], [scheme!]: url }\n return result\n },\n {},\n)\n\n/**\n * What a key lets its app do: view the balance, spend within each limit, with each token's icon, and\n * hold funds for services. The approval screens and the permissions page show the same list.\n */\nexport function Abilities(props: Abilities.Props): ReactNode {\n const { calls, limits } = props.keyAuthorization\n // MPP sessions pay through payment channels, which `open` starts and `topUp` funds. Both read as\n // funds the app holds, since a channel is an escrow that the service draws from.\n const channels = (() => {\n const open = calls.some((call) => call.call === 'open')\n const topUp = calls.some((call) => call.call === 'topUp')\n if (open) return 'Hold funds for services'\n if (topUp) return 'Add to funds it holds for services'\n return undefined\n })()\n return (\n <Stack\n {...styles.list()}\n aria-labelledby={props['aria-labelledby']}\n gap=\"8\"\n render={<ul />}\n >\n <Inline gap=\"8\" render={<li />}>\n <CheckCircle {...styles.allowed()} />\n <span>View your balance and activity</span>\n </Inline>\n {limits.map((limit) => (\n <Inline\n gap=\"8\"\n key={`${limit.currency}:${limit.period ?? 0}`}\n render={<li />}\n >\n <CheckCircle {...styles.allowed()} />\n <span>\n Spend{' '}\n {limit.period\n ? `${format(limit)} ${every(limit.period)}`\n : format(limit)}\n </span>\n <span {...styles.icons()}>\n {limit.tokens.map((token) => {\n // Each token's own limit shows on its icon, since the total spans several.\n const label = `${token.symbol}: ${format({ amount: token.amount, currency: limit.currency })}`\n const logo = logos[token.symbol]\n const icon = logo?.light ?? icons[token.symbol]\n return (\n <Tooltip.Root key={token.symbol}>\n <Tooltip.Trigger\n delay={150}\n render={\n <span {...styles.token()} tabIndex={0}>\n {icon ? (\n // The page follows the system color scheme, so the image does too.\n <picture>\n {logo?.dark ? (\n <source\n media=\"(prefers-color-scheme: dark)\"\n srcSet={logo.dark}\n />\n ) : null}\n <img\n {...styles.icon()}\n alt={label}\n height={20}\n src={icon}\n width={20}\n />\n </picture>\n ) : (\n // A token without a logo shows its initial.\n <span\n {...styles.placeholder()}\n aria-label={label}\n role=\"img\"\n >\n {token.symbol[0]}\n </span>\n )}\n </span>\n }\n />\n <Tooltip.Popup>{label}</Tooltip.Popup>\n </Tooltip.Root>\n )\n })}\n </span>\n </Inline>\n ))}\n {channels ? (\n <Inline gap=\"8\" render={<li />}>\n <CheckCircle {...styles.allowed()} />\n <span>\n {channels.slice(0, channels.lastIndexOf(' ') + 1)}\n {/* The last word and the icon wrap together. */}\n <span {...styles.nowrap()}>\n {channels.slice(channels.lastIndexOf(' ') + 1)}{' '}\n <Popover.Root>\n <Popover.Trigger\n aria-label=\"About funds for services\"\n nativeButton={false}\n openOnHover\n render={<InfoCircle {...styles.info()} tabIndex={0} />}\n />\n <Popover.Popup\n {...styles.popup()}\n aria-label=\"Funds for services\"\n >\n <Popover.Description>\n Set aside for pay-as-you-go services that use{' '}\n <a\n {...styles.popupLink()}\n href=\"https://mpp.dev\"\n rel=\"noreferrer\"\n target=\"_blank\"\n >\n MPP\n </a>\n . They take only what you use, and you get the rest back.\n </Popover.Description>\n </Popover.Popup>\n </Popover.Root>\n </span>\n </span>\n </Inline>\n ) : null}\n {props.children}\n </Stack>\n )\n}\n\nexport declare namespace Abilities {\n type Props = {\n /** The ID of the heading that names the list, if any. */\n 'aria-labelledby'?: string | undefined\n /** Further `<li>` rows after the abilities, such as a page's own warning. Absent, none. */\n children?: ReactNode | undefined\n /** The key whose abilities the list shows. */\n keyAuthorization: KeyAuthorization.Description\n }\n}\n\n/** What the requested key may and may not do, with its limits and expiry. */\nexport function Grant(props: Grant.Props): ReactNode {\n // Several grants can share a document, so each derives its own IDs.\n const id = useId()\n const deniedId = useId()\n const detailsId = useId()\n // The unrecognized calls stay collapsed under their one-line warning until the user opens them.\n const [details, setDetails] = useState(false)\n const { expiry, unrecognized } = props.keyAuthorization\n const Heading = props.heading ?? 'h2'\n return (\n <>\n <Stack\n {...styles.section()}\n aria-labelledby={id}\n gap=\"24\"\n render={<section />}\n >\n {props.chain ? (\n <StatusChip\n {...styles.chain()}\n aria-label={`Chain: ${props.chain}`}\n network\n size=\"small\"\n >\n {props.chain}\n </StatusChip>\n ) : null}\n <Stack gap=\"12\">\n <Heading {...styles.heading()} id={id}>\n This app will be able to:\n </Heading>\n <Abilities\n aria-labelledby={id}\n keyAuthorization={props.keyAuthorization}\n />\n </Stack>\n <Stack gap=\"12\">\n <Heading {...styles.heading()} id={deniedId}>\n This app won’t be able to:\n </Heading>\n <Stack\n {...styles.list()}\n aria-labelledby={deniedId}\n gap=\"8\"\n render={<ul />}\n >\n <Inline gap=\"8\" render={<li />}>\n <XCircle {...styles.denied()} />\n <span>Spend more than you approve</span>\n </Inline>\n </Stack>\n </Stack>\n <Stack {...styles.details()} gap=\"8\" render={<dl />}>\n <div>\n <dt {...styles.term()}>Expires</dt>{' '}\n <dd {...styles.value()}>\n {until(expiry)}{' '}\n {/* The tooltip's text never reaches the server render, so it shows the visitor's own time zone. */}\n <Tooltip.Root>\n <Tooltip.Trigger\n delay={150}\n render={\n <InfoCircle\n {...styles.info()}\n aria-label=\"Expiry date\"\n role=\"img\"\n tabIndex={0}\n />\n }\n />\n <Tooltip.Popup>\n {new Date(expiry * 1000).toLocaleString(undefined, {\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n month: 'short',\n timeZoneName: 'short',\n year: 'numeric',\n })}\n </Tooltip.Popup>\n </Tooltip.Root>\n </dd>\n </div>\n </Stack>\n </Stack>\n {unrecognized.length ? (\n // A note, not an alert, since the calls are part of the request and interrupt nothing.\n <Alert intent=\"warning\" role=\"note\">\n <Alert.Icon />\n <Alert.Content>\n <Stack gap=\"8\">\n <p {...styles.warningTitle()}>This app can take other actions</p>\n {details ? (\n <Stack gap=\"8\" id={detailsId}>\n <p {...styles.warningText()}>\n Tempo ID can’t tell you what these actions do. Approve only\n if you trust this app.\n </p>\n </Stack>\n ) : null}\n </Stack>\n </Alert.Content>\n <Alert.Action\n aria-controls={detailsId}\n aria-expanded={details}\n onClick={() => setDetails((open) => !open)}\n >\n {details ? 'Hide' : 'Show'}\n </Alert.Action>\n </Alert>\n ) : null}\n </>\n )\n}\n\nexport declare namespace Grant {\n type Props = {\n /** The key's chain, shown in the corner. Absent, none shows. */\n chain?: string | undefined\n /** `h2` by default, or `h5` on the flows canvas. */\n heading?: 'h2' | 'h5' | undefined\n /** The key that the app requests. */\n keyAuthorization: KeyAuthorization.Description\n }\n}\n\n/**\n * Groups thousands and keeps every decimal. Each formatter is built at its first use, since a page's\n * first one loads the locale's data, which a page that shows no key never needs.\n */\nlet decimal: Intl.NumberFormat | undefined\n\n/** Formats an expiry's distance, such as `in 7 days`, from its first use. */\nlet relative: Intl.RelativeTimeFormat | undefined\n\n/** The spans of an expiry, largest first. Months and years are approximate. */\nconst spans = [\n ['year', 31_536_000],\n ['month', 2_592_000],\n ['week', 604_800],\n ['day', 86_400],\n ['hour', 3_600],\n ['minute', 60],\n] as const\n\n/** The units of a period, largest first. */\nconst units = [\n ['week', 604_800],\n ['day', 86_400],\n ['hour', 3_600],\n ['minute', 60],\n ['second', 1],\n] as const\n\n/** Returns how often a limit resets, such as `per day` or `every 2 weeks`. */\nfunction every(period: number) {\n const [unit, seconds] = units.find((entry) => period % entry[1] === 0)!\n const count = period / seconds\n return count === 1 ? `per ${unit}` : `every ${count} ${unit}s`\n}\n\n/** Formats a limit in its currency, such as `$1,000`, or as the amount and its code. */\nfunction format(\n limit: Pick<\n KeyAuthorization.Description['limits'][number],\n 'amount' | 'currency'\n >,\n) {\n const amount = limit.amount as Intl.StringNumericLiteral\n try {\n return new Intl.NumberFormat('en-US', {\n currency: limit.currency,\n maximumFractionDigits: 6,\n style: 'currency',\n trailingZeroDisplay: 'stripIfInteger',\n }).format(amount)\n } catch {\n // A yield-bearing token's own symbol is not a currency code.\n decimal ??= new Intl.NumberFormat('en-US', { maximumFractionDigits: 20 })\n return `${decimal.format(amount)} ${limit.currency}`\n }\n}\n\n/**\n * Returns the time until `expiry`, in Unix seconds, in its largest whole span, such as\n * `in 3 months`.\n */\nfunction until(expiry: number) {\n const remaining = expiry - Date.now() / 1000\n const [unit, seconds] =\n spans.find((entry) => remaining + 60 >= entry[1]) ?? spans.at(-1)!\n relative ??= new Intl.RelativeTimeFormat('en-US', { numeric: 'always' })\n return relative.format(Math.max(1, Math.round(remaining / seconds)), unit)\n}\n\nnamespace styles {\n export const allowed = style({\n color: 'content.positive',\n flexShrink: 0,\n height: '20',\n width: '20',\n })\n\n export const chain = style({\n insetBlockStart: '16',\n insetInlineEnd: '16',\n position: 'absolute',\n })\n\n export const denied = style({\n color: 'content.negative',\n flexShrink: 0,\n height: '20',\n width: '20',\n })\n\n // Each term and its value read as one line of text.\n export const details = style({ margin: '0', typography: 'body.b2' })\n\n export const heading = style({\n color: 'content.secondary',\n margin: '0',\n typography: 'body.b2',\n })\n\n export const icon = style({\n borderRadius: 'full',\n display: 'block',\n height: '20',\n width: '20',\n })\n\n // Several tokens overlap, and spread apart while hovered so each symbol can show.\n export const icons = style({\n display: 'flex',\n flexShrink: 0,\n // Each token but the last cuts a 2px gap around the next one, which overlaps it by 6px. A\n // cutout, unlike a ring in the fill color, matches a translucent fill.\n '& > span:not(:last-child)': {\n mask: 'radial-gradient(circle at 1.5rem 50%, transparent 0.75rem, #000 calc(0.75rem + 0.5px)) !custom',\n },\n '&:is(:hover, :focus-within) > span': { mask: 'none !custom' },\n '& > span + span': { marginInlineStart: '-0.375rem !custom' },\n '&:is(:hover, :focus-within) > span + span': { marginInlineStart: '4' },\n })\n\n export const info = style({\n color: 'content.secondary',\n display: 'inline',\n height: '16',\n outline: 'none',\n verticalAlign: 'middle',\n width: '16',\n ':focus-visible': {\n outline: '2px solid',\n outlineColor: 'border.focus',\n outlineOffset: '2',\n },\n })\n\n export const list = style({\n listStyle: 'none',\n margin: '0',\n padding: '0',\n typography: 'body.b2Strong',\n })\n\n export const nowrap = style({ whiteSpace: 'nowrap' })\n\n export const placeholder = style({\n alignItems: 'center',\n backgroundColor: 'background.elevated',\n borderRadius: 'full',\n color: 'content.secondary',\n display: 'flex',\n height: '20',\n justifyContent: 'center',\n typography: 'body.b3',\n width: '20',\n })\n\n export const popup = style({ maxWidth: '256' })\n\n export const popupLink = style({ color: 'accent.blue.foreground' })\n\n export const section = style({\n backgroundColor: 'container.regular',\n borderRadius: 'sm',\n margin: '0',\n padding: '20',\n // The chain's chip sits in the section's top-right corner.\n position: 'relative',\n })\n\n export const term = style({ color: 'content.secondary', display: 'inline' })\n\n export const token = style({\n borderRadius: 'full',\n outline: '2px solid',\n outlineColor: 'transparent !custom',\n outlineOffset: '2',\n ':focus-visible': { outlineColor: 'border.focus' },\n // Under reduced motion, the tokens spread apart without a transition.\n '@media (prefers-reduced-motion: no-preference)': {\n transitionDuration: '150',\n transitionProperty: 'margin',\n transitionTimingFunction: 'in-out',\n },\n })\n\n // The expiry reads in the weight of the permissions above it.\n export const value = style({\n display: 'inline',\n margin: '0',\n overflowWrap: 'anywhere',\n typography: 'body.b2Strong',\n })\n\n export const warningText = style({ color: 'content.primary' })\n\n // The title takes the alert's strong type, so the action at the end of the row lines up with it.\n export const warningTitle = style({ typography: 'body.b3Strong' })\n}\n"],"ignoreList":[0,1,2,3,4,5,6],"mappings":"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"}
1
+ {"version":3,"file":"Grant-TXwmc9xo.js","names":["REASONS.closePress","BaseUi.Popover.Close","BaseUi.Popover.Root","BaseUi.Popover.Trigger","_jsx","BaseUi.Popover.Arrow","styles","BaseUi.Popover.Description","BaseUi.Popover.Portal","BaseUi.Popover.Positioner","BaseUi.Popover.Popup","BaseUi.Popover.Title","_jsxs","_jsx","__import_glob__0_0_","__import_glob__0_1_","__import_glob__0_2_","__import_glob__0_3_","__import_glob__0_4_","__import_glob__0_5_","__import_glob__0_6_","__import_glob__0_7_","__import_glob__0_8_","__import_glob__0_9_","__import_glob__0_10_","__import_glob__0_11_","__import_glob__0_12_","__import_glob__0_13_","__import_glob__0_14_","__import_glob__0_15_","__import_glob__0_16_","__import_glob__0_17_","__import_glob__0_18_","__import_glob__0_19_","__import_glob__0_20_","__import_glob__0_21_","__import_glob__0_22_","__import_glob__0_23_","__import_glob__0_24_","__import_glob__0_25_","__import_glob__0_26_","__import_glob__0_27_","__import_glob__0_28_","__import_glob__0_29_","__import_glob__0_30_","__import_glob__0_31_","__import_glob__0_32_","__import_glob__0_33_","__import_glob__0_34_","__import_glob__0_35_","__import_glob__0_36_","__import_glob__1_0_","__import_glob__1_1_","useId","useState","_Fragment","__toESM","require_react","require_jsx_runtime","Stack","useRenderElement","useButton","create","closePress","createChangeEventDetails","popupStateMapping","useBaseUiId","Tooltip","PopoverPortal","PopoverRoot","usePopoverRootContext","PopoverPositioner","PopoverTrigger","useClosePartRegistration","usePopoverPositionerContext","PopoverPopup","Alert","Inline","StatusChip","CheckCircle","InfoCircle","import_react","PopoverArrow","elementProps","componentProps","open","arrowUncentered","forwardedRef","arrowRef","arrowStyles","PopoverTitle","store","id","PopoverDescription","PopoverClose","nativeButton","buttonRef","event","getButtonProps","import_jsx_runtime","Popover","Arrow","attributes","props","styles$1","Description","Popup","Title","XCircle","BRLA_default","BRZ_default","CHFAU_default","DLUSD_default","EURAU_default","EURC_e_default","GBPA_default","GUSD_default","MACH_default","OUSD_default","PRIME_default","SBC_default","SEKAU_default","USD1_default","USDB_default","USDC_e_default","USDT0_default","USDY_default","USDe_default","YLDS_default","alphaUSD_default","betaUSD_default","cUSD_default","cbBTC_default","frxUSD_default","goUSD_default","iUSD_default","pathUSD_default","rUSD_default","reUSD_default","sUSDe_default","siUSD_default","stcUSD_default","syrupUSDC_default","thetaUSD_default","wYLDS_default","wsrUSD_default","OUSD_dark_default","OUSD_light_default","icons","file","url","logos","symbol","scheme","result","Abilities","channels","calls","call","topUp","styles","limits","limit","format","every","label","token","logo","icon","Grant","deniedId","detailsId","details","setDetails","Heading","until","expiry","unrecognized","decimal","relative","spans","units","unit","seconds","period","entry","count","amount","remaining"],"sources":["../../../../../node_modules/.pnpm/@base-ui+react@1.9.0_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react@19.3.0/node_modules/@base-ui/react/popover/arrow/PopoverArrow.mjs","../../../../../node_modules/.pnpm/@base-ui+react@1.9.0_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react@19.3.0/node_modules/@base-ui/react/popover/title/PopoverTitle.mjs","../../../../../node_modules/.pnpm/@base-ui+react@1.9.0_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react@19.3.0/node_modules/@base-ui/react/popover/description/PopoverDescription.mjs","../../../../../node_modules/.pnpm/@base-ui+react@1.9.0_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react@19.3.0/node_modules/@base-ui/react/popover/close/PopoverClose.mjs","../../../../../node_modules/.pnpm/@tempoxyz+ds@0.3.5_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react-native@0.86_b327597bc920a5831d2a012c973d2470/node_modules/@tempoxyz/ds/dist/web/components/Popover.css","../../../../../node_modules/.pnpm/@tempoxyz+ds@0.3.5_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react-native@0.86_b327597bc920a5831d2a012c973d2470/node_modules/@tempoxyz/ds/dist/web/components/Popover.js","../../../../../node_modules/.pnpm/@tempoxyz+ds@0.3.5_@types+react@19.3.0_react-dom@19.3.0_react@19.3.0__react-native@0.86_b327597bc920a5831d2a012c973d2470/node_modules/@tempoxyz/ds/dist/web/icons/XCircle.js","../../../components/icons/BRLA.png?no-inline","../../../components/icons/BRZ.svg?no-inline","../../../components/icons/CHFAU.png?no-inline","../../../components/icons/DLUSD.png?no-inline","../../../components/icons/EURAU.svg?no-inline","../../../components/icons/EURC.e.svg?no-inline","../../../components/icons/GBPA.svg?no-inline","../../../components/icons/GUSD.svg?no-inline","../../../components/icons/MACH.svg?no-inline","../../../components/icons/OUSD.svg?no-inline","../../../components/icons/PRIME.svg?no-inline","../../../components/icons/SBC.svg?no-inline","../../../components/icons/SEKAU.svg?no-inline","../../../components/icons/USD1.svg?no-inline","../../../components/icons/USDB.svg?no-inline","../../../components/icons/USDC.e.svg?no-inline","../../../components/icons/USDT0.svg?no-inline","../../../components/icons/USDY.svg?no-inline","../../../components/icons/USDe.svg?no-inline","../../../components/icons/YLDS.svg?no-inline","../../../components/icons/alphaUSD.svg?no-inline","../../../components/icons/betaUSD.svg?no-inline","../../../components/icons/cUSD.svg?no-inline","../../../components/icons/cbBTC.svg?no-inline","../../../components/icons/frxUSD.svg?no-inline","../../../components/icons/goUSD.svg?no-inline","../../../components/icons/iUSD.svg?no-inline","../../../components/icons/pathUSD.svg?no-inline","../../../components/icons/rUSD.svg?no-inline","../../../components/icons/reUSD.svg?no-inline","../../../components/icons/sUSDe.svg?no-inline","../../../components/icons/siUSD.svg?no-inline","../../../components/icons/stcUSD.svg?no-inline","../../../components/icons/syrupUSDC.svg?no-inline","../../../components/icons/thetaUSD.svg?no-inline","../../../components/icons/wYLDS.svg?no-inline","../../../components/icons/wsrUSD.svg?no-inline","../../../components/logos/OUSD.dark.svg?no-inline","../../../components/logos/OUSD.light.svg?no-inline","../../../components/Grant.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { usePopoverPositionerContext } from \"../positioner/PopoverPositionerContext.mjs\";\nimport { usePopoverRootContext } from \"../root/PopoverRootContext.mjs\";\nimport { popupStateMapping } from \"../../utils/popupStateMapping.mjs\";\nimport { useRenderElement } from \"../../internals/useRenderElement.mjs\";\n\n/**\n * Displays an element positioned against the popover anchor.\n * Renders a `<div>` element.\n *\n * Documentation: [Base UI Popover](https://base-ui.com/react/components/popover)\n */\nexport const PopoverArrow = /*#__PURE__*/React.forwardRef(function PopoverArrow(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n ...elementProps\n } = componentProps;\n const store = usePopoverRootContext();\n const open = store.useState('open');\n const {\n arrowRef,\n side,\n align,\n arrowUncentered,\n arrowStyles\n } = usePopoverPositionerContext();\n const state = {\n open,\n side,\n align,\n uncentered: arrowUncentered\n };\n const element = useRenderElement('div', componentProps, {\n state,\n ref: [forwardedRef, arrowRef],\n props: [{\n style: arrowStyles,\n 'aria-hidden': true\n }, elementProps],\n stateAttributesMapping: popupStateMapping\n });\n return element;\n});\nif (process.env.NODE_ENV !== \"production\") PopoverArrow.displayName = \"PopoverArrow\";","'use client';\n\nimport * as React from 'react';\nimport { usePopoverRootContext } from \"../root/PopoverRootContext.mjs\";\nimport { useRenderElement } from \"../../internals/useRenderElement.mjs\";\nimport { useBaseUiId } from \"../../internals/useBaseUiId.mjs\";\n\n/**\n * A heading that labels the popover.\n * Renders an `<h2>` element.\n *\n * Documentation: [Base UI Popover](https://base-ui.com/react/components/popover)\n */\nexport const PopoverTitle = /*#__PURE__*/React.forwardRef(function PopoverTitle(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n ...elementProps\n } = componentProps;\n const store = usePopoverRootContext();\n const id = useBaseUiId(elementProps.id);\n store.useSyncedValueWithCleanup('titleElementId', id);\n const element = useRenderElement('h2', componentProps, {\n ref: forwardedRef,\n props: [{\n id\n }, elementProps]\n });\n return element;\n});\nif (process.env.NODE_ENV !== \"production\") PopoverTitle.displayName = \"PopoverTitle\";","'use client';\n\nimport * as React from 'react';\nimport { usePopoverRootContext } from \"../root/PopoverRootContext.mjs\";\nimport { useBaseUiId } from \"../../internals/useBaseUiId.mjs\";\nimport { useRenderElement } from \"../../internals/useRenderElement.mjs\";\n\n/**\n * A paragraph with additional information about the popover.\n * Renders a `<p>` element.\n *\n * Documentation: [Base UI Popover](https://base-ui.com/react/components/popover)\n */\nexport const PopoverDescription = /*#__PURE__*/React.forwardRef(function PopoverDescription(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n ...elementProps\n } = componentProps;\n const store = usePopoverRootContext();\n const id = useBaseUiId(elementProps.id);\n store.useSyncedValueWithCleanup('descriptionElementId', id);\n const element = useRenderElement('p', componentProps, {\n ref: forwardedRef,\n props: [{\n id\n }, elementProps]\n });\n return element;\n});\nif (process.env.NODE_ENV !== \"production\") PopoverDescription.displayName = \"PopoverDescription\";","'use client';\n\nimport * as React from 'react';\nimport { usePopoverRootContext } from \"../root/PopoverRootContext.mjs\";\nimport { useRenderElement } from \"../../internals/useRenderElement.mjs\";\nimport { useButton } from \"../../internals/use-button/index.mjs\";\nimport { createChangeEventDetails } from \"../../internals/createBaseUIEventDetails.mjs\";\nimport { REASONS } from \"../../internals/reasons.mjs\";\nimport { useClosePartRegistration } from \"../../utils/closePart.mjs\";\n\n/**\n * A button that closes the popover.\n * Renders a `<button>` element.\n *\n * Documentation: [Base UI Popover](https://base-ui.com/react/components/popover)\n */\nexport const PopoverClose = /*#__PURE__*/React.forwardRef(function PopoverClose(componentProps, forwardedRef) {\n const {\n render,\n className,\n style,\n disabled = false,\n nativeButton = true,\n ...elementProps\n } = componentProps;\n const {\n buttonRef,\n getButtonProps\n } = useButton({\n disabled,\n focusableWhenDisabled: false,\n native: nativeButton\n });\n const store = usePopoverRootContext();\n useClosePartRegistration();\n const element = useRenderElement('button', componentProps, {\n ref: [forwardedRef, buttonRef],\n props: [{\n onClick(event) {\n store.setOpen(false, createChangeEventDetails(REASONS.closePress, event.nativeEvent));\n }\n }, elementProps, getButtonProps]\n });\n return element;\n});\nif (process.env.NODE_ENV !== \"production\") PopoverClose.displayName = \"PopoverClose\";",".z_tds_2f_web-WYxykg0{color:var(--z-tds_2f_web-color-background-elevated,light-dark(var(--z-tds_2f_web-color-neutral-000,#fff),var(--z-tds_2f_web-color-neutral-092,#141414)))}.z_tds_2f_web-WYxykg1{display:flex}.z_tds_2f_web-WYxykg2{&[data-side=bottom]{top:-10px}}.z_tds_2f_web-WYxykg3{&[data-side=left]{right:-14px}}.z_tds_2f_web-WYxykg4{&[data-side=left]{rotate:90deg}}.z_tds_2f_web-WYxykg5{&[data-side=right]{left:-14px}}.z_tds_2f_web-WYxykg6{&[data-side=right]{rotate:-90deg}}.z_tds_2f_web-WYxykg7{&[data-side=top]{bottom:-10px}}.z_tds_2f_web-WYxykg8{&[data-side=top]{rotate:180deg}}.z_tds_2f_web-WYxykg9{color:var(--z-tds_2f_web-color-content-secondary,light-dark(var(--z-tds_2f_web-color-neutral-shade-056,#0000008f),var(--z-tds_2f_web-color-neutral-tint-064,#ffffffa3)))}.z_tds_2f_web-WYxykga{margin:var(--z-tds_2f_web-spacing-0,0rem)}.z_tds_2f_web-WYxykgb{font-family:var(--z-tds_2f_web-typography-body-b2-fontFamily,var(--z-tds_2f_web-fontFamily-body,Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"))}.z_tds_2f_web-WYxykgc{font-size:var(--z-tds_2f_web-typography-body-b2-fontSize,14px)}.z_tds_2f_web-WYxykgd{font-weight:var(--z-tds_2f_web-typography-body-b2-fontWeight,400)}.z_tds_2f_web-WYxykge{letter-spacing:var(--z-tds_2f_web-typography-body-b2-letterSpacing,-.09px)}.z_tds_2f_web-WYxykgf{line-height:var(--z-tds_2f_web-typography-body-b2-lineHeight,20px)}.z_tds_2f_web-WYxykgg{background-color:var(--z-tds_2f_web-color-background-elevated,light-dark(var(--z-tds_2f_web-color-neutral-000,#fff),var(--z-tds_2f_web-color-neutral-092,#141414)))}.z_tds_2f_web-WYxykgh{border-radius:var(--z-tds_2f_web-radius-sm,calc(1rem * var(--tds-corner-scale,1)))}.z_tds_2f_web-WYxykgi{box-shadow:var(--z-tds_2f_web-shadow-regular,0 8px 48px #0000000a, 0 4px 16px #0000000a, 0 2px 8px #0000000a)}.z_tds_2f_web-WYxykgj{box-sizing:border-box}.z_tds_2f_web-WYxykgk{color:var(--z-tds_2f_web-color-content-primary,light-dark(var(--z-tds_2f_web-color-neutral-100,#000),var(--z-tds_2f_web-color-neutral-000,#fff)))}.z_tds_2f_web-WYxykgl{max-width:var(--available-width)}.z_tds_2f_web-WYxykgm{outline:none}.z_tds_2f_web-WYxykgn{padding:var(--z-tds_2f_web-spacing-24,1.5rem)}.z_tds_2f_web-WYxykgo{transform-origin:var(--transform-origin)}.z_tds_2f_web-WYxykgp{transition-duration:var(--z-tds_2f_web-transitionDuration-200,.2s)}.z_tds_2f_web-WYxykgq{transition-property:opacity,scale}.z_tds_2f_web-WYxykgr{transition-timing-function:var(--z-tds_2f_web-ease-snappy,cubic-bezier(.23, 1, .32, 1))}.z_tds_2f_web-WYxykgs{width:max-content}.z_tds_2f_web-WYxykgt{&[data-ending-style]{opacity:0}}.z_tds_2f_web-WYxykgu{&[data-ending-style]{scale:var(--z-tds_2f_web-scale-enter,.96)}}.z_tds_2f_web-WYxykgv{&[data-ending-style]{transition-duration:var(--z-tds_2f_web-transitionDuration-140,.14s)}}.z_tds_2f_web-WYxykgw{&[data-starting-style]{opacity:0}}.z_tds_2f_web-WYxykgx{&[data-starting-style]{scale:var(--z-tds_2f_web-scale-enter,.96)}}@media (prefers-reduced-motion:reduce){.z_tds_2f_web-WYxykgy{transition-property:opacity}.z_tds_2f_web-WYxykgz{&[data-ending-style],&[data-starting-style]{scale:none}}}.z_tds_2f_web-WYxykg10{z-index:var(--z-tds_2f_web-zIndex-popover,50)}.z_tds_2f_web-WYxykg11{font-family:var(--z-tds_2f_web-typography-heading-h3-fontFamily,var(--z-tds_2f_web-fontFamily-heading,Pilat, Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif))}.z_tds_2f_web-WYxykg12{font-size:var(--z-tds_2f_web-typography-heading-h3-fontSize,20px)}.z_tds_2f_web-WYxykg13{font-weight:var(--z-tds_2f_web-typography-heading-h3-fontWeight,500)}.z_tds_2f_web-WYxykg14{letter-spacing:var(--z-tds_2f_web-typography-heading-h3-letterSpacing,-.3px)}.z_tds_2f_web-WYxykg15{line-height:var(--z-tds_2f_web-typography-heading-h3-lineHeight,23px)}.z_tds_2f_web-WYxykg16{margin:var(--z-tds_2f_web-spacing-0,0rem)}.z_tds_2f_web-WYxykg17{margin-bottom:var(--z-tds_2f_web-spacing-4,.25rem)}","\nimport { Props as __zyzzProps } from 'zyzz/runtime';\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nimport * as BaseUi from '@base-ui/react/popover';\nimport { style } from '../zyzz.config.js';\n/**\n * A non-modal `dialog` anchored to a trigger and opened on click. Opening moves focus to the first\n * tabbable element inside, or to the popup on touch. Escape and outside presses close it and\n * return focus to the trigger.\n *\n * - Use it for interactive or longer content. Use `Tooltip` for a short hint on hover.\n * - Include `Title` so the dialog has an accessible name, and `Description` for supporting text.\n * - Offer `Close` when the popup holds a form or other controls.\n *\n * @example\n * <Popover.Root>\n * <Popover.Trigger render={<Button variant=\"secondary\" />}>Network fee</Popover.Trigger>\n * <Popover.Popup>\n * <Popover.Title>Network fee</Popover.Title>\n * <Popover.Description>Paid in the token you send.</Popover.Description>\n * </Popover.Popup>\n * </Popover.Root>\n *\n * @see {@link https://base-ui.com/react/components/popover | Base UI Popover}\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Popover_API | MDN Popover API}\n * @see {@link https://www.w3.org/WAI/WCAG22/Understanding/content-on-hover-or-focus.html | WCAG 2.2 Content on Hover or Focus}\n * @see {@link https://www.w3.org/WAI/WCAG22/Understanding/focus-order.html | WCAG 2.2 Focus Order}\n * @see {@link https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html | WCAG 2.2 Keyboard}\n */\nexport var Popover;\n(function (Popover) {\n /** Renders a `button` that closes the popover. Pass `render` to use a `Button`. */\n Popover.Close = BaseUi.Popover.Close;\n /**\n * Owns the open state. Pass `open` and `onOpenChange` to control it. Unless `modal` is set, the\n * page stays interactive while the popover is open.\n */\n Popover.Root = BaseUi.Popover.Root;\n /**\n * Toggles the popover on click and anchors the popup. Set `openOnHover` to also open it on hover.\n *\n * @example\n * <Popover.Trigger render={<Button variant=\"secondary\" />}>Network fee</Popover.Trigger>\n */\n Popover.Trigger = BaseUi.Popover.Trigger;\n /** Draws a pointer toward the trigger on the popup's anchored side. Place it inside `Popup`. */\n function Arrow(props) {\n const { className, vars, ...attributes } = props;\n return (_jsx(BaseUi.Popover.Arrow, { ...attributes, ...styles.arrow({ className, style: props.style, vars }), children: _jsx(\"svg\", { \"aria-hidden\": \"true\", fill: \"currentColor\", height: \"10\", viewBox: \"0 0 20 10\", width: \"20\", children: _jsx(\"path\", { d: \"M0 10C4 10 7 7 8.6 4.6a2 2 0 0 1 2.8 0C13 7 16 10 20 10Z\" }) }) }));\n }\n Popover.Arrow = Arrow;\n /** Renders a `p` that describes the popup through `aria-describedby`. */\n function Description(props) {\n const { className, vars, ...attributes } = props;\n return (_jsx(BaseUi.Popover.Description, { ...attributes, ...styles.description({ className, style: props.style, vars }) }));\n }\n Popover.Description = Description;\n /**\n * Renders the portal, positioner and popup. Placement props go to the positioner, which sits 8px\n * from the trigger unless `sideOffset` is set. Other props, `ref`, `className` and `style` reach\n * the popup. `initialFocus` and `finalFocus` override where focus moves on open and close.\n */\n function Popup(props) {\n const { align, alignOffset, anchor, className, collisionPadding, side, sideOffset = 8, vars, ...attributes } = props;\n return (_jsx(BaseUi.Popover.Portal, { children: _jsx(BaseUi.Popover.Positioner, { ...styles.positioner(), align: align, alignOffset: alignOffset, anchor: anchor, collisionPadding: collisionPadding, side: side, sideOffset: sideOffset, children: _jsx(BaseUi.Popover.Popup, { ...attributes, ...styles.popup({ className, style: props.style, vars }) }) }) }));\n }\n Popover.Popup = Popup;\n /** Renders an `h2` that names the popup through `aria-labelledby`. */\n function Title(props) {\n const { className, vars, ...attributes } = props;\n return (_jsx(BaseUi.Popover.Title, { ...attributes, ...styles.title({ className, style: props.style, vars }) }));\n }\n Popover.Title = Title;\n})(Popover || (Popover = {}));\nvar styles;\n(function (styles) {\n styles.arrow = /*#__PURE__*/__zyzzProps.create({className:\"z_tds_2f_web-WYxykg0 z_tds_2f_web-WYxykg1 z_tds_2f_web-WYxykg2 z_tds_2f_web-WYxykg3 z_tds_2f_web-WYxykg4 z_tds_2f_web-WYxykg5 z_tds_2f_web-WYxykg6 z_tds_2f_web-WYxykg7 z_tds_2f_web-WYxykg8\"});\n styles.description = /*#__PURE__*/__zyzzProps.create({className:\"z_tds_2f_web-WYxykg9 z_tds_2f_web-WYxykga z_tds_2f_web-WYxykgb z_tds_2f_web-WYxykgc z_tds_2f_web-WYxykgd z_tds_2f_web-WYxykge z_tds_2f_web-WYxykgf\"});\n styles.popup = /*#__PURE__*/__zyzzProps.create({className:\"z_tds_2f_web-WYxykgg z_tds_2f_web-WYxykgh z_tds_2f_web-WYxykgi z_tds_2f_web-WYxykgj z_tds_2f_web-WYxykgk z_tds_2f_web-WYxykgl z_tds_2f_web-WYxykgm z_tds_2f_web-WYxykgn z_tds_2f_web-WYxykgo z_tds_2f_web-WYxykgp z_tds_2f_web-WYxykgq z_tds_2f_web-WYxykgr z_tds_2f_web-WYxykgb z_tds_2f_web-WYxykgc z_tds_2f_web-WYxykgd z_tds_2f_web-WYxykge z_tds_2f_web-WYxykgf z_tds_2f_web-WYxykgs z_tds_2f_web-WYxykgt z_tds_2f_web-WYxykgu z_tds_2f_web-WYxykgv z_tds_2f_web-WYxykgw z_tds_2f_web-WYxykgx z_tds_2f_web-WYxykgy z_tds_2f_web-WYxykgz\"});\n styles.positioner = /*#__PURE__*/__zyzzProps.create({className:\"z_tds_2f_web-WYxykg10\"});\n styles.title = /*#__PURE__*/__zyzzProps.create({className:\"z_tds_2f_web-WYxykg11 z_tds_2f_web-WYxykg12 z_tds_2f_web-WYxykg13 z_tds_2f_web-WYxykg14 z_tds_2f_web-WYxykg15 z_tds_2f_web-WYxykg16 z_tds_2f_web-WYxykg17\"});\n})(styles || (styles = {}));\n//# sourceMappingURL=Popover.js.map\nimport './Popover.css';\n","import { jsx as _jsx, jsxs as _jsxs } from \"react/jsx-runtime\";\nexport function XCircle(props) {\n return (_jsxs(\"svg\", { width: \"1em\", height: \"1em\", viewBox: \"0 0 16 16\", fill: \"none\", xmlns: \"http://www.w3.org/2000/svg\", \"aria-hidden\": props['aria-label'] || props['aria-labelledby'] ? undefined : true, role: props['aria-label'] || props['aria-labelledby'] ? 'img' : undefined, ...props, children: [_jsx(\"path\", { d: \"M9.64648 5.64648C9.84175 5.45122 10.1583 5.45122 10.3535 5.64648C10.5487 5.84175 10.5488 6.15827 10.3535 6.35352L8.70703 8L10.3535 9.64648C10.5487 9.84175 10.5488 10.1583 10.3535 10.3535C10.1583 10.5488 9.84175 10.5487 9.64648 10.3535L8 8.70703L6.35352 10.3535C6.15827 10.5488 5.84175 10.5487 5.64648 10.3535C5.45122 10.1583 5.45122 9.84175 5.64648 9.64648L7.29297 8L5.64648 6.35352C5.45122 6.15825 5.45122 5.84175 5.64648 5.64648C5.84175 5.45122 6.15825 5.45122 6.35352 5.64648L8 7.29297L9.64648 5.64648Z\", fill: \"currentColor\" }), _jsx(\"path\", { fillRule: \"evenodd\", clipRule: \"evenodd\", d: \"M8 1.33301C11.6817 1.33318 14.666 4.31919 14.666 8.00098C14.6656 11.6824 11.6815 14.6668 8 14.667C4.31837 14.667 1.33345 11.6825 1.33301 8.00098C1.33301 4.31908 4.3181 1.33301 8 1.33301ZM8 2.33398C4.87039 2.33398 2.33301 4.87137 2.33301 8.00098C2.33345 11.1302 4.87066 13.667 8 13.667C11.1292 13.6668 13.6656 11.1301 13.666 8.00098C13.666 4.87147 11.1294 2.33416 8 2.33398Z\", fill: \"currentColor\" })] }));\n}\n//# sourceMappingURL=XCircle.js.map","export default import.meta.ROLLDOWN_FILE_URL_OestAvA2SyLT4CG6L76dAw","export default import.meta.ROLLDOWN_FILE_URL_q6tfGKm3Qmt5DJmATeHQdA","export default import.meta.ROLLDOWN_FILE_URL_nJkgIVJgL11RgZiGUBj6wA","export default import.meta.ROLLDOWN_FILE_URL_tgFyw$X211zXSctfMU9_LA","export default import.meta.ROLLDOWN_FILE_URL_LphhLScmzwPqWwTyAbd7ig","export default import.meta.ROLLDOWN_FILE_URL_U6muqRGa8aHtq8t0c9wAzg","export default import.meta.ROLLDOWN_FILE_URL_i2ywl_YzKp2MjtOEr7ngzA","export default import.meta.ROLLDOWN_FILE_URL_TX5a1iViCylaCWPFSCQG2w","export default import.meta.ROLLDOWN_FILE_URL_y3WuTrdTs_Si7uYpRddj9w","export default import.meta.ROLLDOWN_FILE_URL_kSHvwCjLFxLpY3FM1MyAsA","export default import.meta.ROLLDOWN_FILE_URL_0PgJxXqjw$KAl6PgZjQb5g","export default import.meta.ROLLDOWN_FILE_URL_EsSyonNWXFChOyjfj2S3nw","export default import.meta.ROLLDOWN_FILE_URL_zOyQqdNGsn0lL_XEFrarVA","export default import.meta.ROLLDOWN_FILE_URL_yW_eMvu1QqHghXJHMLbBbg","export default import.meta.ROLLDOWN_FILE_URL_07gvO1IvTzTCTyYqp_a5mw","export default import.meta.ROLLDOWN_FILE_URL_qZZZ7EOcQU0bnm2SE9d1Ig","export default import.meta.ROLLDOWN_FILE_URL_tgItkVM6JTrfm2CiQnzY5g","export default import.meta.ROLLDOWN_FILE_URL_RCaHVq_jCUoWDQWiWLxE3w","export default import.meta.ROLLDOWN_FILE_URL_8Jdj9qQ4eJq3labUJOvRYQ","export default import.meta.ROLLDOWN_FILE_URL_gTxdgYqT1FnWrjfbk9DrbA","export default import.meta.ROLLDOWN_FILE_URL_e3FJByPCCgv8fip_DM$mWQ","export default import.meta.ROLLDOWN_FILE_URL_rUkiH63qcJGEQEedyX41xw","export default import.meta.ROLLDOWN_FILE_URL_PWd8aapBt1YfLvgRaedarQ","export default import.meta.ROLLDOWN_FILE_URL_V1ZYpwZc9C51fJhgOTS5xQ","export default import.meta.ROLLDOWN_FILE_URL_HAwZnQ40A17rYC3Q$lxt9A","export default import.meta.ROLLDOWN_FILE_URL_DzYsnjr1LtW1tBWqsYm2RQ","export default import.meta.ROLLDOWN_FILE_URL_6bp_5It$EfTQ8f$omStdjw","export default import.meta.ROLLDOWN_FILE_URL_2ZEzIIM_atdpHcr$6kvj$Q","export default import.meta.ROLLDOWN_FILE_URL_xUfAOc8vsLn5godiQWqFgA","export default import.meta.ROLLDOWN_FILE_URL_8KByd7W0oH8zGe1MvrBFUw","export default import.meta.ROLLDOWN_FILE_URL_aKo4wVjMjV9S8rY28E5Mvg","export default import.meta.ROLLDOWN_FILE_URL_3Lrf7vA$GngskD3e2_Wsaw","export default import.meta.ROLLDOWN_FILE_URL_OxgPY7jd89vmgHQlmb5h_Q","export default import.meta.ROLLDOWN_FILE_URL_Ngmgj7KrmSrUoXH_NFNtFA","export default import.meta.ROLLDOWN_FILE_URL_eBB5uVE_t2Bb1etqpZE3Ig","export default import.meta.ROLLDOWN_FILE_URL_cLLFq7OX38PQjR0WE41fig","export default import.meta.ROLLDOWN_FILE_URL_2h$eqWdLjjj$zuUvyPi$HQ","export default import.meta.ROLLDOWN_FILE_URL_UF4iDpNJhIbRdkaNqmNRqw","export default import.meta.ROLLDOWN_FILE_URL_bLNX6U6f8qE7L2W0pHPLmA","/**\n * Shows a requested key's limits and expiry, and warns about unrecognized calls. {@link Abilities},\n * the list of what a key allows, also serves the permissions page.\n * @module\n */\nimport {\n Alert,\n Inline,\n Popover,\n Stack,\n StatusChip,\n Tooltip,\n} from '@tempoxyz/ds'\nimport { CheckCircle, InfoCircle, XCircle } from '@tempoxyz/ds/icons'\nimport { type ReactNode, useId, useState } from 'react'\nimport type * as KeyAuthorization from '../../internal/KeyAuthorization.js'\nimport { style } from '../zyzz.config.js'\n\n/**\n * Each token's icon URL, by symbol. Each icon stays its own file, since an inlined icon would put\n * every token's icon in the script of each page that shows a key.\n */\nconst icons = Object.fromEntries(\n Object.entries(\n import.meta.glob<string>('./icons/*.{png,svg,webp}', {\n eager: true,\n import: 'default',\n query: '?no-inline',\n }),\n ).map(([file, url]) => [\n file.slice('./icons/'.length, file.lastIndexOf('.')),\n url,\n ]),\n)\n\n/** Logos from `logos/`, by symbol and color scheme, each its own file. A logo replaces the icon. */\nconst logos = Object.entries(\n import.meta.glob<string>('./logos/*.{light,dark}.{png,svg,webp}', {\n eager: true,\n import: 'default',\n query: '?no-inline',\n }),\n).reduce<Record<string, { dark?: string; light?: string }>>(\n (result, [file, url]) => {\n const [, symbol, scheme] = file.match(\n /^\\.\\/logos\\/(.+)\\.(light|dark)\\.\\w+$/,\n )!\n result[symbol!] = { ...result[symbol!], [scheme!]: url }\n return result\n },\n {},\n)\n\n/**\n * What a key lets its app do: view the balance, spend within each limit, with each token's icon, and\n * hold funds for services. The approval screens and the permissions page show the same list.\n */\nexport function Abilities(props: Abilities.Props): ReactNode {\n const { calls, limits } = props.keyAuthorization\n // MPP sessions pay through payment channels, which `open` starts and `topUp` funds. Both read as\n // funds the app holds, since a channel is an escrow that the service draws from.\n const channels = (() => {\n const open = calls.some((call) => call.call === 'open')\n const topUp = calls.some((call) => call.call === 'topUp')\n if (open) return 'Hold funds for services'\n if (topUp) return 'Add to funds it holds for services'\n return undefined\n })()\n return (\n <Stack\n {...styles.list()}\n aria-labelledby={props['aria-labelledby']}\n gap=\"8\"\n render={<ul />}\n >\n <Inline gap=\"8\" render={<li />}>\n <CheckCircle {...styles.allowed()} />\n <span>View your balance and activity</span>\n </Inline>\n {limits.map((limit) => (\n <Inline\n gap=\"8\"\n key={`${limit.currency}:${limit.period ?? 0}`}\n render={<li />}\n >\n <CheckCircle {...styles.allowed()} />\n <span>\n Spend{' '}\n {limit.period\n ? `${format(limit)} ${every(limit.period)}`\n : format(limit)}\n </span>\n <span {...styles.icons()}>\n {limit.tokens.map((token) => {\n // Each token's own limit shows on its icon, since the total spans several.\n const label = `${token.symbol}: ${format({ amount: token.amount, currency: limit.currency })}`\n const logo = logos[token.symbol]\n const icon = logo?.light ?? icons[token.symbol]\n return (\n <Tooltip.Root key={token.symbol}>\n <Tooltip.Trigger\n delay={150}\n render={\n <span {...styles.token()} tabIndex={0}>\n {icon ? (\n // The page follows the system color scheme, so the image does too.\n <picture>\n {logo?.dark ? (\n <source\n media=\"(prefers-color-scheme: dark)\"\n srcSet={logo.dark}\n />\n ) : null}\n <img\n {...styles.icon()}\n alt={label}\n height={20}\n src={icon}\n width={20}\n />\n </picture>\n ) : (\n // A token without a logo shows its initial.\n <span\n {...styles.placeholder()}\n aria-label={label}\n role=\"img\"\n >\n {token.symbol[0]}\n </span>\n )}\n </span>\n }\n />\n <Tooltip.Popup>{label}</Tooltip.Popup>\n </Tooltip.Root>\n )\n })}\n </span>\n </Inline>\n ))}\n {channels ? (\n <Inline gap=\"8\" render={<li />}>\n <CheckCircle {...styles.allowed()} />\n <span>\n {channels.slice(0, channels.lastIndexOf(' ') + 1)}\n {/* The last word and the icon wrap together. */}\n <span {...styles.nowrap()}>\n {channels.slice(channels.lastIndexOf(' ') + 1)}{' '}\n <Popover.Root>\n <Popover.Trigger\n aria-label=\"About funds for services\"\n nativeButton={false}\n openOnHover\n render={<InfoCircle {...styles.info()} tabIndex={0} />}\n />\n <Popover.Popup\n {...styles.popup()}\n aria-label=\"Funds for services\"\n >\n <Popover.Description>\n Set aside for pay-as-you-go services that use{' '}\n <a\n {...styles.popupLink()}\n href=\"https://mpp.dev\"\n rel=\"noreferrer\"\n target=\"_blank\"\n >\n MPP\n </a>\n . They take only what you use, and you get the rest back.\n </Popover.Description>\n </Popover.Popup>\n </Popover.Root>\n </span>\n </span>\n </Inline>\n ) : null}\n {props.children}\n </Stack>\n )\n}\n\nexport declare namespace Abilities {\n type Props = {\n /** The ID of the heading that names the list, if any. */\n 'aria-labelledby'?: string | undefined\n /** Further `<li>` rows after the abilities, such as a page's own warning. Absent, none. */\n children?: ReactNode | undefined\n /** The key whose abilities the list shows. */\n keyAuthorization: KeyAuthorization.Description\n }\n}\n\n/** What the requested key may and may not do, with its limits and expiry. */\nexport function Grant(props: Grant.Props): ReactNode {\n // Several grants can share a document, so each derives its own IDs.\n const id = useId()\n const deniedId = useId()\n const detailsId = useId()\n // The unrecognized calls stay collapsed under their one-line warning until the user opens them.\n const [details, setDetails] = useState(false)\n const { expiry, unrecognized } = props.keyAuthorization\n const Heading = props.heading ?? 'h2'\n return (\n <>\n <Stack\n {...styles.section()}\n aria-labelledby={id}\n gap=\"24\"\n render={<section />}\n >\n {props.chain ? (\n <StatusChip\n {...styles.chain()}\n aria-label={`Chain: ${props.chain}`}\n network\n size=\"small\"\n >\n {props.chain}\n </StatusChip>\n ) : null}\n <Stack gap=\"12\">\n <Heading {...styles.heading()} id={id}>\n This app will be able to:\n </Heading>\n <Abilities\n aria-labelledby={id}\n keyAuthorization={props.keyAuthorization}\n />\n </Stack>\n <Stack gap=\"12\">\n <Heading {...styles.heading()} id={deniedId}>\n This app won’t be able to:\n </Heading>\n <Stack\n {...styles.list()}\n aria-labelledby={deniedId}\n gap=\"8\"\n render={<ul />}\n >\n <Inline gap=\"8\" render={<li />}>\n <XCircle {...styles.denied()} />\n <span>Spend more than you approve</span>\n </Inline>\n </Stack>\n </Stack>\n <Stack {...styles.details()} gap=\"8\" render={<dl />}>\n <div>\n <dt {...styles.term()}>Expires</dt>{' '}\n <dd {...styles.value()}>\n {until(expiry)}{' '}\n {/* The tooltip's text never reaches the server render, so it shows the visitor's own time zone. */}\n <Tooltip.Root>\n <Tooltip.Trigger\n delay={150}\n render={\n <InfoCircle\n {...styles.info()}\n aria-label=\"Expiry date\"\n role=\"img\"\n tabIndex={0}\n />\n }\n />\n <Tooltip.Popup>\n {new Date(expiry * 1000).toLocaleString(undefined, {\n day: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n month: 'short',\n timeZoneName: 'short',\n year: 'numeric',\n })}\n </Tooltip.Popup>\n </Tooltip.Root>\n </dd>\n </div>\n </Stack>\n </Stack>\n {unrecognized.length ? (\n // A note, not an alert, since the calls are part of the request and interrupt nothing.\n <Alert intent=\"warning\" role=\"note\">\n <Alert.Icon />\n <Alert.Content>\n <Stack gap=\"8\">\n <p {...styles.warningTitle()}>This app can take other actions</p>\n {details ? (\n <Stack gap=\"8\" id={detailsId}>\n <p {...styles.warningText()}>\n Tempo ID can’t tell you what these actions do. Approve only\n if you trust this app.\n </p>\n </Stack>\n ) : null}\n </Stack>\n </Alert.Content>\n <Alert.Action\n aria-controls={detailsId}\n aria-expanded={details}\n onClick={() => setDetails((open) => !open)}\n >\n {details ? 'Hide' : 'Show'}\n </Alert.Action>\n </Alert>\n ) : null}\n </>\n )\n}\n\nexport declare namespace Grant {\n type Props = {\n /** The key's chain, shown in the corner. Absent, none shows. */\n chain?: string | undefined\n /** `h2` by default, or `h5` on the flows canvas. */\n heading?: 'h2' | 'h5' | undefined\n /** The key that the app requests. */\n keyAuthorization: KeyAuthorization.Description\n }\n}\n\n/**\n * Groups thousands and keeps every decimal. Each formatter is built at its first use, since a page's\n * first one loads the locale's data, which a page that shows no key never needs.\n */\nlet decimal: Intl.NumberFormat | undefined\n\n/** Formats an expiry's distance, such as `in 7 days`, from its first use. */\nlet relative: Intl.RelativeTimeFormat | undefined\n\n/** The spans of an expiry, largest first. Months and years are approximate. */\nconst spans = [\n ['year', 31_536_000],\n ['month', 2_592_000],\n ['week', 604_800],\n ['day', 86_400],\n ['hour', 3_600],\n ['minute', 60],\n] as const\n\n/** The units of a period, largest first. */\nconst units = [\n ['week', 604_800],\n ['day', 86_400],\n ['hour', 3_600],\n ['minute', 60],\n ['second', 1],\n] as const\n\n/** Returns how often a limit resets, such as `per day` or `every 2 weeks`. */\nfunction every(period: number) {\n const [unit, seconds] = units.find((entry) => period % entry[1] === 0)!\n const count = period / seconds\n return count === 1 ? `per ${unit}` : `every ${count} ${unit}s`\n}\n\n/** Formats a limit in its currency, such as `$1,000`, or as the amount and its code. */\nfunction format(\n limit: Pick<\n KeyAuthorization.Description['limits'][number],\n 'amount' | 'currency'\n >,\n) {\n const amount = limit.amount as Intl.StringNumericLiteral\n try {\n return new Intl.NumberFormat('en-US', {\n currency: limit.currency,\n maximumFractionDigits: 6,\n style: 'currency',\n trailingZeroDisplay: 'stripIfInteger',\n }).format(amount)\n } catch {\n // A yield-bearing token's own symbol is not a currency code.\n decimal ??= new Intl.NumberFormat('en-US', { maximumFractionDigits: 20 })\n return `${decimal.format(amount)} ${limit.currency}`\n }\n}\n\n/**\n * Returns the time until `expiry`, in Unix seconds, in its largest whole span, such as\n * `in 3 months`.\n */\nfunction until(expiry: number) {\n const remaining = expiry - Date.now() / 1000\n const [unit, seconds] =\n spans.find((entry) => remaining + 60 >= entry[1]) ?? spans.at(-1)!\n relative ??= new Intl.RelativeTimeFormat('en-US', { numeric: 'always' })\n return relative.format(Math.max(1, Math.round(remaining / seconds)), unit)\n}\n\nnamespace styles {\n export const allowed = style({\n color: 'content.positive',\n flexShrink: 0,\n height: '20',\n width: '20',\n })\n\n export const chain = style({\n insetBlockStart: '16',\n insetInlineEnd: '16',\n position: 'absolute',\n })\n\n export const denied = style({\n color: 'content.negative',\n flexShrink: 0,\n height: '20',\n width: '20',\n })\n\n // Each term and its value read as one line of text.\n export const details = style({ margin: '0', typography: 'body.b2' })\n\n export const heading = style({\n color: 'content.secondary',\n margin: '0',\n typography: 'body.b2',\n })\n\n export const icon = style({\n borderRadius: 'full',\n display: 'block',\n height: '20',\n width: '20',\n })\n\n // Several tokens overlap, and spread apart while hovered so each symbol can show.\n export const icons = style({\n display: 'flex',\n flexShrink: 0,\n // Each token but the last cuts a 2px gap around the next one, which overlaps it by 6px. A\n // cutout, unlike a ring in the fill color, matches a translucent fill.\n '& > span:not(:last-child)': {\n mask: 'radial-gradient(circle at 1.5rem 50%, transparent 0.75rem, #000 calc(0.75rem + 0.5px)) !custom',\n },\n '&:is(:hover, :focus-within) > span': { mask: 'none !custom' },\n '& > span + span': { marginInlineStart: '-0.375rem !custom' },\n '&:is(:hover, :focus-within) > span + span': { marginInlineStart: '4' },\n })\n\n export const info = style({\n color: 'content.secondary',\n display: 'inline',\n height: '16',\n outline: 'none',\n verticalAlign: 'middle',\n width: '16',\n ':focus-visible': {\n outline: '2px solid',\n outlineColor: 'border.focus',\n outlineOffset: '2',\n },\n })\n\n export const list = style({\n listStyle: 'none',\n margin: '0',\n padding: '0',\n typography: 'body.b2Strong',\n })\n\n export const nowrap = style({ whiteSpace: 'nowrap' })\n\n export const placeholder = style({\n alignItems: 'center',\n backgroundColor: 'background.elevated',\n borderRadius: 'full',\n color: 'content.secondary',\n display: 'flex',\n height: '20',\n justifyContent: 'center',\n typography: 'body.b3',\n width: '20',\n })\n\n export const popup = style({ maxWidth: '256' })\n\n export const popupLink = style({ color: 'accent.blue.foreground' })\n\n export const section = style({\n backgroundColor: 'container.regular',\n borderRadius: 'sm',\n margin: '0',\n padding: '20',\n // The chain's chip sits in the section's top-right corner.\n position: 'relative',\n })\n\n export const term = style({ color: 'content.secondary', display: 'inline' })\n\n export const token = style({\n borderRadius: 'full',\n outline: '2px solid',\n outlineColor: 'transparent !custom',\n outlineOffset: '2',\n ':focus-visible': { outlineColor: 'border.focus' },\n // Under reduced motion, the tokens spread apart without a transition.\n '@media (prefers-reduced-motion: no-preference)': {\n transitionDuration: '150',\n transitionProperty: 'margin',\n transitionTimingFunction: 'in-out',\n },\n })\n\n // The expiry reads in the weight of the permissions above it.\n export const value = style({\n display: 'inline',\n margin: '0',\n overflowWrap: 'anywhere',\n typography: 'body.b2Strong',\n })\n\n export const warningText = style({ color: 'content.primary' })\n\n // The title takes the alert's strong type, so the action at the end of the row lines up with it.\n export const warningTitle = style({ typography: 'body.b3Strong' })\n}\n"],"ignoreList":[0,1,2,3,4,5,6],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+ import { type Auth } from './Auth.js';
2
+ import type * as Key from './Key.js';
3
+ import type { Permissions } from './Permissions.js';
4
+ import type { Storage } from './Storage.js';
5
+ import type { User } from './User.js';
6
+ /**
7
+ * `complete` received a session ID without a redirect in progress, such as a callback that arrived
8
+ * twice, or after 10 minutes.
9
+ */
10
+ export declare class PendingNotFoundError extends Error {
11
+ readonly name = "BackendSession.PendingNotFoundError";
12
+ constructor();
13
+ }
14
+ /** A signed-in session, as `get` returns it. The refresh token stays in `storage`. */
15
+ export type BackendSession = {
16
+ /** The access token for Tempo APIs: a Bearer token, or a DPoP token from an instance with `dpop`. */
17
+ accessToken: string;
18
+ /** When the access token expires, in milliseconds. */
19
+ expiresAt: number;
20
+ /** The app's access key, with its private key. Absent after a sign-in without `permissions`. */
21
+ key?: Key.Key | undefined;
22
+ /** The signed-in user. */
23
+ user: User;
24
+ };
25
+ /**
26
+ * Creates the sessions of one backend. Concurrent `get` calls of one session share one refresh. The
27
+ * instance holds the refreshes in progress, so one instance serves every request of a session: one
28
+ * per process, or one per Durable Object on Cloudflare Workers, which spreads requests across
29
+ * isolates.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const sessions = BackendSession.create(
34
+ * Auth.create({ clientId: env.CLIENT_ID, clientSecret: env.CLIENT_SECRET }),
35
+ * { storage },
36
+ * )
37
+ * ```
38
+ */
39
+ export declare function create(auth: Auth, options: create.Options): create.ReturnType;
40
+ export declare namespace create {
41
+ type Options = {
42
+ /**
43
+ * Where the sessions and the redirects in progress live, unserialized, such as a Durable
44
+ * Object's storage. Each value holds an access key's private key and a refresh token.
45
+ */
46
+ storage: Storage;
47
+ };
48
+ type ReturnType = {
49
+ /**
50
+ * Redeems the callback of `start` for the session `id`, and stores its tokens and key. Throws
51
+ * {@link PendingNotFoundError} without a redirect in progress, and `Auth.RequestError` for a
52
+ * forged `state` or a refused code.
53
+ */
54
+ complete: (options: complete.Options) => Promise<BackendSession>;
55
+ /**
56
+ * Revokes the session's refresh token at Tempo ID, then deletes the session. Throws
57
+ * `Auth.RequestError` and keeps the session if the revocation fails.
58
+ */
59
+ end: (options: {
60
+ id: string;
61
+ }) => Promise<void>;
62
+ /**
63
+ * Sends a request with the session's access token, as `Actions.fetch` does, after a refresh if
64
+ * necessary. Returns `undefined` without a session.
65
+ */
66
+ fetch: (options: fetch.Options) => Promise<Response | undefined>;
67
+ /** Returns the session, after a refresh if its access token expires within 30 seconds. */
68
+ get: (options: get.Options) => Promise<get.ReturnType>;
69
+ /**
70
+ * Starts a redirect sign-in, and stores its pending state for 10 minutes. Returns the session
71
+ * ID to set in the browser's cookie, and the URL to redirect to.
72
+ */
73
+ start: (options?: start.Options) => Promise<start.ReturnType>;
74
+ };
75
+ }
76
+ export declare namespace complete {
77
+ type Options = {
78
+ /** The session ID that `start` returned. */
79
+ id: string;
80
+ /** The callback URL that Tempo ID redirected to. */
81
+ url: string | URL;
82
+ };
83
+ }
84
+ export declare namespace fetch {
85
+ type Options = {
86
+ /** The session ID. */
87
+ id: string;
88
+ /** The request's other options, such as `method` and `body`. Its `Authorization` and `DPoP` headers are replaced. */
89
+ init?: RequestInit | undefined;
90
+ /** The request's URL. */
91
+ url: string | URL;
92
+ };
93
+ }
94
+ export declare namespace get {
95
+ type Options = {
96
+ /** The session ID. */
97
+ id: string;
98
+ };
99
+ /** The session, or `undefined` if it never existed, ended, or its refresh token was refused. */
100
+ type ReturnType = BackendSession | undefined;
101
+ }
102
+ export declare namespace start {
103
+ type Options = {
104
+ /** The session ID. Defaults to 32 random bytes in URL-safe Base64. */
105
+ id?: string | undefined;
106
+ /** What the access key may do, which requests the key. Without it, the sign-in authorizes no key. */
107
+ permissions?: Permissions | undefined;
108
+ /** Defaults to the instance's `redirectUri`. */
109
+ redirectUri?: string | undefined;
110
+ };
111
+ type ReturnType = {
112
+ /** The session ID, for an `HttpOnly` cookie. */
113
+ id: string;
114
+ /** Where to send the browser. */
115
+ url: string;
116
+ };
117
+ }
118
+ //# sourceMappingURL=BackendSession.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BackendSession.d.ts","sourceRoot":"","sources":["../../src/client/BackendSession.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Keeps a backend's sign-ins on the server, so the browser holds only an opaque session ID. The
3
+ * session's tokens and access key stay in `storage`, and concurrent requests of one session share
4
+ * one refresh, since a reused refresh token revokes every refresh token of the app for the user.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * const sessions = BackendSession.create(auth, { storage })
9
+ *
10
+ * const { id, url } = await sessions.start({ redirectUri })
11
+ * // After the redirect back:
12
+ * const { user } = await sessions.complete({ id, url: c.req.url })
13
+ * // On each later request:
14
+ * const response = await sessions.fetch({ id, url: 'https://api.tempo.xyz/v1/me' })
15
+ * ```
16
+ * @module
17
+ */
18
+ import { Base64, Bytes } from 'ox';
19
+ import * as Actions from './Actions.js';
20
+ import { RequestError } from './Auth.js';
21
+ import * as Api from './internal/api.js';
22
+ /**
23
+ * `complete` received a session ID without a redirect in progress, such as a callback that arrived
24
+ * twice, or after 10 minutes.
25
+ */
26
+ export class PendingNotFoundError extends Error {
27
+ name = 'BackendSession.PendingNotFoundError';
28
+ constructor() {
29
+ super('No sign-in in progress for this session ID, or it started more than 10 minutes ago. Start the sign-in again.');
30
+ }
31
+ }
32
+ /**
33
+ * Creates the sessions of one backend. Concurrent `get` calls of one session share one refresh. The
34
+ * instance holds the refreshes in progress, so one instance serves every request of a session: one
35
+ * per process, or one per Durable Object on Cloudflare Workers, which spreads requests across
36
+ * isolates.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * const sessions = BackendSession.create(
41
+ * Auth.create({ clientId: env.CLIENT_ID, clientSecret: env.CLIENT_SECRET }),
42
+ * { storage },
43
+ * )
44
+ * ```
45
+ */
46
+ export function create(auth, options) {
47
+ const { storage } = options;
48
+ // One refresh for each session ID, which concurrent reads of that session await.
49
+ const refreshes = new Map();
50
+ /**
51
+ * Refreshes the session's access token unless it is still valid. It reads the session again, since
52
+ * a read before this refresh started can hold a refresh token that an earlier refresh rotated.
53
+ */
54
+ async function refresh(id) {
55
+ const stored = (await storage.getItem(sessionKey(id)));
56
+ if (!stored || fresh(stored))
57
+ return stored;
58
+ const { refreshToken } = stored;
59
+ if (!refreshToken) {
60
+ await storage.removeItem(sessionKey(id));
61
+ return undefined;
62
+ }
63
+ const tokens = await (async () => {
64
+ try {
65
+ return await Actions.refresh(auth, { refreshToken });
66
+ }
67
+ catch (error) {
68
+ // A refused refresh token is revoked or expired, so the session ends. Any other failure,
69
+ // such as an outage, keeps the session for the next request.
70
+ if (error instanceof RequestError && error.code === 'invalid_grant')
71
+ return undefined;
72
+ throw error;
73
+ }
74
+ })();
75
+ if (!tokens) {
76
+ await storage.removeItem(sessionKey(id));
77
+ return undefined;
78
+ }
79
+ const { idToken: _, ...rest } = tokens;
80
+ const next = { ...stored, ...rest };
81
+ await storage.setItem(sessionKey(id), next);
82
+ return next;
83
+ }
84
+ async function get(options) {
85
+ const { id } = options;
86
+ const inProgress = refreshes.get(id);
87
+ const stored = inProgress
88
+ ? await inProgress
89
+ : (await storage.getItem(sessionKey(id)));
90
+ if (!stored)
91
+ return undefined;
92
+ if (fresh(stored))
93
+ return view(stored);
94
+ // The map entry is set before the refresh's first await, so every later read shares it.
95
+ const refreshing = refreshes.get(id) ?? refresh(id).finally(() => refreshes.delete(id));
96
+ refreshes.set(id, refreshing);
97
+ const next = await refreshing;
98
+ return next && view(next);
99
+ }
100
+ return {
101
+ async complete(options) {
102
+ const { id, url } = options;
103
+ const pending = (await storage.getItem(pendingKey(id)));
104
+ // The pending state redeems one code, so a second callback finds none.
105
+ await storage.removeItem(pendingKey(id));
106
+ if (!pending || pending.createdAt + pendingLifetime <= Date.now())
107
+ throw new PendingNotFoundError();
108
+ const authorization = await Actions.redirect.handleCallback(auth, {
109
+ pending: pending.pending,
110
+ url,
111
+ });
112
+ // The ID token holds the user's personal data, and the access key rebuilds from `key`.
113
+ const stored = (() => {
114
+ const { idToken: _, ...rest } = authorization;
115
+ if (!('accessKey' in rest))
116
+ return rest;
117
+ const { accessKey: __, ...withKey } = rest;
118
+ return withKey;
119
+ })();
120
+ await storage.setItem(sessionKey(id), stored);
121
+ return view(stored);
122
+ },
123
+ async end(options) {
124
+ const { id } = options;
125
+ // A refresh in progress would store its tokens after the deletion, so it finishes first.
126
+ await refreshes.get(id)?.catch(() => undefined);
127
+ const stored = (await storage.getItem(sessionKey(id)));
128
+ if (stored?.refreshToken)
129
+ await revoke(auth, { refreshToken: stored.refreshToken });
130
+ await storage.removeItem(sessionKey(id));
131
+ },
132
+ async fetch(options) {
133
+ const session = await get({ id: options.id });
134
+ if (!session)
135
+ return undefined;
136
+ return Actions.fetch(auth, {
137
+ accessToken: session.accessToken,
138
+ init: options.init,
139
+ url: options.url,
140
+ });
141
+ },
142
+ get,
143
+ async start(options = {}) {
144
+ const id = options.id ?? Base64.fromBytes(Bytes.random(32), base64url);
145
+ const { pending, url } = await Actions.redirect.createUrl(auth, {
146
+ permissions: options.permissions,
147
+ redirectUri: options.redirectUri,
148
+ });
149
+ const stored = { createdAt: Date.now(), pending };
150
+ await storage.setItem(pendingKey(id), stored);
151
+ return { id, url };
152
+ },
153
+ };
154
+ }
155
+ /** Unpadded URL-safe Base64 for session IDs. */
156
+ const base64url = { pad: false, url: true };
157
+ /** How long before its expiry an access token refreshes, in milliseconds. */
158
+ const margin = 30_000;
159
+ /** How long a redirect in progress waits for its callback, in milliseconds. */
160
+ const pendingLifetime = 10 * 60 * 1000;
161
+ /** Returns whether the session's access token stays valid for more than the margin. */
162
+ function fresh(stored) {
163
+ return stored.expiresAt - margin > Date.now();
164
+ }
165
+ /** Returns the session without its refresh token. */
166
+ function view(stored) {
167
+ const { refreshToken: _, ...session } = stored;
168
+ return session;
169
+ }
170
+ /** The storage key of a session. */
171
+ function sessionKey(id) {
172
+ return `tempo-id:session:${id}`;
173
+ }
174
+ /** The storage key of a redirect in progress. */
175
+ function pendingKey(id) {
176
+ return `tempo-id:pending:${id}`;
177
+ }
178
+ /** Revokes a refresh token at `/oauth2/revoke` (RFC 7009), with the app's client authentication. */
179
+ async function revoke(auth, options) {
180
+ const response = await (auth.fetch ?? globalThis.fetch)(new URL('/oauth2/revoke', auth.url), {
181
+ body: new URLSearchParams({
182
+ client_id: auth.clientId,
183
+ token: options.refreshToken,
184
+ token_type_hint: 'refresh_token',
185
+ ...(await Api.clientAuthentication(auth)),
186
+ }),
187
+ method: 'POST',
188
+ });
189
+ if (response.ok) {
190
+ await response.body?.cancel();
191
+ return;
192
+ }
193
+ await Api.json(response);
194
+ }
195
+ //# sourceMappingURL=BackendSession.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BackendSession.js","sourceRoot":"","sources":["../../src/client/BackendSession.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,12 @@
1
1
  /**
2
- * Where a redirect keeps its state until Tempo ID redirects back.
2
+ * Where a redirect keeps its state until Tempo ID redirects back, and where a backend keeps its
3
+ * sessions.
3
4
  * @module
4
5
  */
5
- /** Keeps a redirect's state, as structured-clone storage such as IndexedDB does. */
6
+ /**
7
+ * Keeps a redirect's state, or a backend's sessions, as structured-clone storage such as IndexedDB or
8
+ * a Durable Object's storage does.
9
+ */
6
10
  export type Storage = {
7
11
  /** Reads the value at `key`, or `undefined`. */
8
12
  getItem: (key: string) => Promise<unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../../src/client/Storage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,oFAAoF;AACpF,MAAM,MAAM,OAAO,GAAG;IACpB,gDAAgD;IAChD,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1C,kCAAkC;IAClC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,uDAAuD;IACvD,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACxD,CAAA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE5C"}
1
+ {"version":3,"file":"Storage.d.ts","sourceRoot":"","sources":["../../src/client/Storage.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;;;GAGG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,gDAAgD;IAChD,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1C,kCAAkC;IAClC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,uDAAuD;IACvD,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACxD,CAAA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE5C"}
@@ -1 +1 @@
1
- {"version":3,"file":"Storage.js","sourceRoot":"","sources":["../../src/client/Storage.ts"],"names":[],"mappings":"AAcA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,IAAI,CAAC,KAAc;IACjC,OAAO,KAAK,CAAA;AACd,CAAC"}
1
+ {"version":3,"file":"Storage.js","sourceRoot":"","sources":["../../src/client/Storage.ts"],"names":[],"mappings":"AAkBA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,IAAI,CAAC,KAAc;IACjC,OAAO,KAAK,CAAA;AACd,CAAC"}
package/dist/client.d.ts CHANGED
@@ -8,6 +8,7 @@ export * as Actions from './client/Actions.js';
8
8
  export * as Admin from './client/Admin.js';
9
9
  export * as Auth from './client/Auth.js';
10
10
  export * as Authorization from './client/Authorization.js';
11
+ export * as BackendSession from './client/BackendSession.js';
11
12
  export * as ClientAssertion from './client/ClientAssertion.js';
12
13
  export * as Decorator from './client/viem/Decorator.js';
13
14
  export { tempoId } from './client/viem/Decorator.js';
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAC1C,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,aAAa,MAAM,2BAA2B,CAAA;AAC1D,OAAO,KAAK,eAAe,MAAM,6BAA6B,CAAA;AAC9D,OAAO,KAAK,SAAS,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACpD,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,GAAG,MAAM,iBAAiB,CAAA;AACtC,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAA;AAC5C,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAC1C,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,aAAa,MAAM,2BAA2B,CAAA;AAC1D,OAAO,KAAK,cAAc,MAAM,4BAA4B,CAAA;AAC5D,OAAO,KAAK,eAAe,MAAM,6BAA6B,CAAA;AAC9D,OAAO,KAAK,SAAS,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACpD,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,GAAG,MAAM,iBAAiB,CAAA;AACtC,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAA;AAC5C,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA"}
package/dist/client.js CHANGED
@@ -8,6 +8,7 @@ export * as Actions from './client/Actions.js';
8
8
  export * as Admin from './client/Admin.js';
9
9
  export * as Auth from './client/Auth.js';
10
10
  export * as Authorization from './client/Authorization.js';
11
+ export * as BackendSession from './client/BackendSession.js';
11
12
  export * as ClientAssertion from './client/ClientAssertion.js';
12
13
  export * as Decorator from './client/viem/Decorator.js';
13
14
  export { tempoId } from './client/viem/Decorator.js';
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAC1C,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,aAAa,MAAM,2BAA2B,CAAA;AAC1D,OAAO,KAAK,eAAe,MAAM,6BAA6B,CAAA;AAC9D,OAAO,KAAK,SAAS,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACpD,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,GAAG,MAAM,iBAAiB,CAAA;AACtC,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAA;AAC5C,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAC1C,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,aAAa,MAAM,2BAA2B,CAAA;AAC1D,OAAO,KAAK,cAAc,MAAM,4BAA4B,CAAA;AAC5D,OAAO,KAAK,eAAe,MAAM,6BAA6B,CAAA;AAC9D,OAAO,KAAK,SAAS,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AACpD,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA;AACxC,OAAO,KAAK,GAAG,MAAM,iBAAiB,CAAA;AACtC,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAA;AAC9C,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAA;AAC5C,OAAO,KAAK,IAAI,MAAM,kBAAkB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tempoxyz/id",
3
- "version": "0.0.0-pr-349.sha-fd1d6ff",
3
+ "version": "0.0.0-pr-416.sha-e4bee27",
4
4
  "description": "Tempo ID: sign-in, tokens, and access keys for Tempo, on Better Auth and Void.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -0,0 +1,332 @@
1
+ /**
2
+ * Keeps a backend's sign-ins on the server, so the browser holds only an opaque session ID. The
3
+ * session's tokens and access key stay in `storage`, and concurrent requests of one session share
4
+ * one refresh, since a reused refresh token revokes every refresh token of the app for the user.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * const sessions = BackendSession.create(auth, { storage })
9
+ *
10
+ * const { id, url } = await sessions.start({ redirectUri })
11
+ * // After the redirect back:
12
+ * const { user } = await sessions.complete({ id, url: c.req.url })
13
+ * // On each later request:
14
+ * const response = await sessions.fetch({ id, url: 'https://api.tempo.xyz/v1/me' })
15
+ * ```
16
+ * @module
17
+ */
18
+ import { Base64, Bytes } from 'ox'
19
+ import * as Actions from './Actions.js'
20
+ import { type Auth, RequestError } from './Auth.js'
21
+ import * as Api from './internal/api.js'
22
+ import type * as Key from './Key.js'
23
+ import type * as Pending from './Pending.js'
24
+ import type { Permissions } from './Permissions.js'
25
+ import type { Storage } from './Storage.js'
26
+ import type { User } from './User.js'
27
+
28
+ /**
29
+ * `complete` received a session ID without a redirect in progress, such as a callback that arrived
30
+ * twice, or after 10 minutes.
31
+ */
32
+ export class PendingNotFoundError extends Error {
33
+ override readonly name = 'BackendSession.PendingNotFoundError'
34
+
35
+ constructor() {
36
+ super(
37
+ 'No sign-in in progress for this session ID, or it started more than 10 minutes ago. Start the sign-in again.',
38
+ )
39
+ }
40
+ }
41
+
42
+ /** A signed-in session, as `get` returns it. The refresh token stays in `storage`. */
43
+ export type BackendSession = {
44
+ /** The access token for Tempo APIs: a Bearer token, or a DPoP token from an instance with `dpop`. */
45
+ accessToken: string
46
+ /** When the access token expires, in milliseconds. */
47
+ expiresAt: number
48
+ /** The app's access key, with its private key. Absent after a sign-in without `permissions`. */
49
+ key?: Key.Key | undefined
50
+ /** The signed-in user. */
51
+ user: User
52
+ }
53
+
54
+ /**
55
+ * Creates the sessions of one backend. Concurrent `get` calls of one session share one refresh. The
56
+ * instance holds the refreshes in progress, so one instance serves every request of a session: one
57
+ * per process, or one per Durable Object on Cloudflare Workers, which spreads requests across
58
+ * isolates.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * const sessions = BackendSession.create(
63
+ * Auth.create({ clientId: env.CLIENT_ID, clientSecret: env.CLIENT_SECRET }),
64
+ * { storage },
65
+ * )
66
+ * ```
67
+ */
68
+ export function create(auth: Auth, options: create.Options): create.ReturnType {
69
+ const { storage } = options
70
+
71
+ // One refresh for each session ID, which concurrent reads of that session await.
72
+ const refreshes = new Map<string, Promise<Stored | undefined>>()
73
+
74
+ /**
75
+ * Refreshes the session's access token unless it is still valid. It reads the session again, since
76
+ * a read before this refresh started can hold a refresh token that an earlier refresh rotated.
77
+ */
78
+ async function refresh(id: string) {
79
+ const stored = (await storage.getItem(sessionKey(id))) as Stored | undefined
80
+ if (!stored || fresh(stored)) return stored
81
+ const { refreshToken } = stored
82
+ if (!refreshToken) {
83
+ await storage.removeItem(sessionKey(id))
84
+ return undefined
85
+ }
86
+
87
+ const tokens = await (async () => {
88
+ try {
89
+ return await Actions.refresh(auth, { refreshToken })
90
+ } catch (error) {
91
+ // A refused refresh token is revoked or expired, so the session ends. Any other failure,
92
+ // such as an outage, keeps the session for the next request.
93
+ if (error instanceof RequestError && error.code === 'invalid_grant')
94
+ return undefined
95
+ throw error
96
+ }
97
+ })()
98
+ if (!tokens) {
99
+ await storage.removeItem(sessionKey(id))
100
+ return undefined
101
+ }
102
+
103
+ const { idToken: _, ...rest } = tokens
104
+ const next: Stored = { ...stored, ...rest }
105
+ await storage.setItem(sessionKey(id), next)
106
+ return next
107
+ }
108
+
109
+ async function get(options: get.Options): Promise<get.ReturnType> {
110
+ const { id } = options
111
+ const inProgress = refreshes.get(id)
112
+ const stored = inProgress
113
+ ? await inProgress
114
+ : ((await storage.getItem(sessionKey(id))) as Stored | undefined)
115
+ if (!stored) return undefined
116
+ if (fresh(stored)) return view(stored)
117
+
118
+ // The map entry is set before the refresh's first await, so every later read shares it.
119
+ const refreshing =
120
+ refreshes.get(id) ?? refresh(id).finally(() => refreshes.delete(id))
121
+ refreshes.set(id, refreshing)
122
+ const next = await refreshing
123
+ return next && view(next)
124
+ }
125
+
126
+ return {
127
+ async complete(options) {
128
+ const { id, url } = options
129
+ const pending = (await storage.getItem(pendingKey(id))) as
130
+ | StoredPending
131
+ | undefined
132
+ // The pending state redeems one code, so a second callback finds none.
133
+ await storage.removeItem(pendingKey(id))
134
+ if (!pending || pending.createdAt + pendingLifetime <= Date.now())
135
+ throw new PendingNotFoundError()
136
+
137
+ const authorization = await Actions.redirect.handleCallback(auth, {
138
+ pending: pending.pending,
139
+ url,
140
+ })
141
+ // The ID token holds the user's personal data, and the access key rebuilds from `key`.
142
+ const stored: Stored = (() => {
143
+ const { idToken: _, ...rest } = authorization
144
+ if (!('accessKey' in rest)) return rest
145
+ const { accessKey: __, ...withKey } = rest
146
+ return withKey
147
+ })()
148
+ await storage.setItem(sessionKey(id), stored)
149
+ return view(stored)
150
+ },
151
+ async end(options) {
152
+ const { id } = options
153
+ // A refresh in progress would store its tokens after the deletion, so it finishes first.
154
+ await refreshes.get(id)?.catch(() => undefined)
155
+ const stored = (await storage.getItem(sessionKey(id))) as
156
+ | Stored
157
+ | undefined
158
+ if (stored?.refreshToken)
159
+ await revoke(auth, { refreshToken: stored.refreshToken })
160
+ await storage.removeItem(sessionKey(id))
161
+ },
162
+ async fetch(options) {
163
+ const session = await get({ id: options.id })
164
+ if (!session) return undefined
165
+ return Actions.fetch(auth, {
166
+ accessToken: session.accessToken,
167
+ init: options.init,
168
+ url: options.url,
169
+ })
170
+ },
171
+ get,
172
+ async start(options = {}) {
173
+ const id = options.id ?? Base64.fromBytes(Bytes.random(32), base64url)
174
+ const { pending, url } = await Actions.redirect.createUrl(auth, {
175
+ permissions: options.permissions,
176
+ redirectUri: options.redirectUri,
177
+ })
178
+ const stored: StoredPending = { createdAt: Date.now(), pending }
179
+ await storage.setItem(pendingKey(id), stored)
180
+ return { id, url }
181
+ },
182
+ }
183
+ }
184
+
185
+ export declare namespace create {
186
+ type Options = {
187
+ /**
188
+ * Where the sessions and the redirects in progress live, unserialized, such as a Durable
189
+ * Object's storage. Each value holds an access key's private key and a refresh token.
190
+ */
191
+ storage: Storage
192
+ }
193
+
194
+ type ReturnType = {
195
+ /**
196
+ * Redeems the callback of `start` for the session `id`, and stores its tokens and key. Throws
197
+ * {@link PendingNotFoundError} without a redirect in progress, and `Auth.RequestError` for a
198
+ * forged `state` or a refused code.
199
+ */
200
+ complete: (options: complete.Options) => Promise<BackendSession>
201
+ /**
202
+ * Revokes the session's refresh token at Tempo ID, then deletes the session. Throws
203
+ * `Auth.RequestError` and keeps the session if the revocation fails.
204
+ */
205
+ end: (options: { id: string }) => Promise<void>
206
+ /**
207
+ * Sends a request with the session's access token, as `Actions.fetch` does, after a refresh if
208
+ * necessary. Returns `undefined` without a session.
209
+ */
210
+ fetch: (options: fetch.Options) => Promise<Response | undefined>
211
+ /** Returns the session, after a refresh if its access token expires within 30 seconds. */
212
+ get: (options: get.Options) => Promise<get.ReturnType>
213
+ /**
214
+ * Starts a redirect sign-in, and stores its pending state for 10 minutes. Returns the session
215
+ * ID to set in the browser's cookie, and the URL to redirect to.
216
+ */
217
+ start: (options?: start.Options) => Promise<start.ReturnType>
218
+ }
219
+ }
220
+
221
+ export declare namespace complete {
222
+ type Options = {
223
+ /** The session ID that `start` returned. */
224
+ id: string
225
+ /** The callback URL that Tempo ID redirected to. */
226
+ url: string | URL
227
+ }
228
+ }
229
+
230
+ export declare namespace fetch {
231
+ type Options = {
232
+ /** The session ID. */
233
+ id: string
234
+ /** The request's other options, such as `method` and `body`. Its `Authorization` and `DPoP` headers are replaced. */
235
+ init?: RequestInit | undefined
236
+ /** The request's URL. */
237
+ url: string | URL
238
+ }
239
+ }
240
+
241
+ export declare namespace get {
242
+ type Options = {
243
+ /** The session ID. */
244
+ id: string
245
+ }
246
+
247
+ /** The session, or `undefined` if it never existed, ended, or its refresh token was refused. */
248
+ type ReturnType = BackendSession | undefined
249
+ }
250
+
251
+ export declare namespace start {
252
+ type Options = {
253
+ /** The session ID. Defaults to 32 random bytes in URL-safe Base64. */
254
+ id?: string | undefined
255
+ /** What the access key may do, which requests the key. Without it, the sign-in authorizes no key. */
256
+ permissions?: Permissions | undefined
257
+ /** Defaults to the instance's `redirectUri`. */
258
+ redirectUri?: string | undefined
259
+ }
260
+
261
+ type ReturnType = {
262
+ /** The session ID, for an `HttpOnly` cookie. */
263
+ id: string
264
+ /** Where to send the browser. */
265
+ url: string
266
+ }
267
+ }
268
+
269
+ /** Unpadded URL-safe Base64 for session IDs. */
270
+ const base64url = { pad: false, url: true } as const
271
+
272
+ /** How long before its expiry an access token refreshes, in milliseconds. */
273
+ const margin = 30_000
274
+
275
+ /** How long a redirect in progress waits for its callback, in milliseconds. */
276
+ const pendingLifetime = 10 * 60 * 1000
277
+
278
+ /** A session as `storage` holds it, with its refresh token. */
279
+ type Stored = BackendSession & {
280
+ /** Exchanges for new tokens, and rotates on each refresh. Absent without `offline_access`. */
281
+ refreshToken?: string | undefined
282
+ }
283
+
284
+ /** A redirect in progress, as `storage` holds it. */
285
+ type StoredPending = {
286
+ /** When `start` stored it, in milliseconds. */
287
+ createdAt: number
288
+ /** The state, the PKCE verifier, and any key's material. */
289
+ pending: Pending.Pending | Pending.WithoutKey
290
+ }
291
+
292
+ /** Returns whether the session's access token stays valid for more than the margin. */
293
+ function fresh(stored: Stored) {
294
+ return stored.expiresAt - margin > Date.now()
295
+ }
296
+
297
+ /** Returns the session without its refresh token. */
298
+ function view(stored: Stored): BackendSession {
299
+ const { refreshToken: _, ...session } = stored
300
+ return session
301
+ }
302
+
303
+ /** The storage key of a session. */
304
+ function sessionKey(id: string) {
305
+ return `tempo-id:session:${id}`
306
+ }
307
+
308
+ /** The storage key of a redirect in progress. */
309
+ function pendingKey(id: string) {
310
+ return `tempo-id:pending:${id}`
311
+ }
312
+
313
+ /** Revokes a refresh token at `/oauth2/revoke` (RFC 7009), with the app's client authentication. */
314
+ async function revoke(auth: Auth, options: { refreshToken: string }) {
315
+ const response = await (auth.fetch ?? globalThis.fetch)(
316
+ new URL('/oauth2/revoke', auth.url),
317
+ {
318
+ body: new URLSearchParams({
319
+ client_id: auth.clientId,
320
+ token: options.refreshToken,
321
+ token_type_hint: 'refresh_token',
322
+ ...(await Api.clientAuthentication(auth)),
323
+ }),
324
+ method: 'POST',
325
+ },
326
+ )
327
+ if (response.ok) {
328
+ await response.body?.cancel()
329
+ return
330
+ }
331
+ await Api.json(response)
332
+ }
@@ -1,8 +1,12 @@
1
1
  /**
2
- * Where a redirect keeps its state until Tempo ID redirects back.
2
+ * Where a redirect keeps its state until Tempo ID redirects back, and where a backend keeps its
3
+ * sessions.
3
4
  * @module
4
5
  */
5
- /** Keeps a redirect's state, as structured-clone storage such as IndexedDB does. */
6
+ /**
7
+ * Keeps a redirect's state, or a backend's sessions, as structured-clone storage such as IndexedDB or
8
+ * a Durable Object's storage does.
9
+ */
6
10
  export type Storage = {
7
11
  /** Reads the value at `key`, or `undefined`. */
8
12
  getItem: (key: string) => Promise<unknown>
package/src/client.ts CHANGED
@@ -8,6 +8,7 @@ export * as Actions from './client/Actions.js'
8
8
  export * as Admin from './client/Admin.js'
9
9
  export * as Auth from './client/Auth.js'
10
10
  export * as Authorization from './client/Authorization.js'
11
+ export * as BackendSession from './client/BackendSession.js'
11
12
  export * as ClientAssertion from './client/ClientAssertion.js'
12
13
  export * as Decorator from './client/viem/Decorator.js'
13
14
  export { tempoId } from './client/viem/Decorator.js'