@withone/connect 0.8.3 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +158 -370
- package/dist/button.d.ts +9 -10
- package/dist/constants.d.ts +8 -4
- package/dist/index.cjs.js +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.esm.js +1 -1
- package/dist/next.cjs.js +104 -0
- package/dist/next.d.ts +36 -0
- package/dist/next.esm.js +98 -0
- package/dist/node.cjs.js +69 -0
- package/dist/node.d.ts +33 -0
- package/dist/node.esm.js +67 -0
- package/dist/platforms.d.ts +21 -0
- package/dist/react.cjs.js +1 -1
- package/dist/react.d.ts +2 -19
- package/dist/react.esm.js +1 -1
- package/dist/return.d.ts +11 -0
- package/dist/server/index.cjs.js +349 -0
- package/dist/server/index.d.ts +32 -0
- package/dist/server/index.esm.js +344 -0
- package/dist/server/oauth.d.ts +24 -0
- package/dist/server/types.d.ts +136 -0
- package/dist/svelte.cjs.js +1 -1
- package/dist/svelte.d.ts +14 -4
- package/dist/svelte.esm.js +1 -1
- package/dist/types.d.ts +80 -0
- package/dist/useOneConnect.d.ts +13 -2
- package/dist/vue.cjs.js +1 -1
- package/dist/vue.d.ts +20 -18
- package/dist/vue.esm.js +1 -1
- package/dist/wrapper-options.d.ts +20 -15
- package/package.json +37 -15
- package/skills/one-connect/SKILL.md +194 -0
- package/src/button.ts +106 -157
- package/src/constants.ts +10 -4
- package/src/index.ts +17 -2
- package/src/next.ts +133 -0
- package/src/node.ts +107 -0
- package/src/platforms.ts +89 -0
- package/src/react.ts +23 -66
- package/src/return.ts +30 -0
- package/src/server/index.ts +382 -0
- package/src/server/oauth.ts +98 -0
- package/src/server/types.ts +155 -0
- package/src/svelte.ts +15 -15
- package/src/types.ts +87 -0
- package/src/useOneConnect.ts +36 -69
- package/src/vue.ts +23 -29
- package/src/wrapper-options.ts +46 -23
- package/dist/index.umd.js +0 -1
- package/dist/types/index.d.ts +0 -92
- package/src/react-types.d.ts +0 -23
- package/src/svelte-types.d.ts +0 -27
- package/src/types/index.d.ts +0 -92
- package/src/vue-types.d.ts +0 -16
package/dist/button.d.ts
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import type { ConnectButtonHandle, ConnectButtonOptions } from "./types";
|
|
2
2
|
export declare const mountConnectButton: (container: HTMLElement, options: ConnectButtonOptions) => ConnectButtonHandle;
|
|
3
3
|
/**
|
|
4
|
-
* <one-connect-button
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* (Next.js SSR) never touches HTMLElement.
|
|
4
|
+
* <one-connect-button>: one tag for any framework. The element wires the
|
|
5
|
+
* whole flow from its attributes and manages Connect, Connecting and
|
|
6
|
+
* Connected. Registered automatically in the browser on import; defined
|
|
7
|
+
* inside a function so importing this module on a server never touches
|
|
8
|
+
* HTMLElement.
|
|
10
9
|
*
|
|
11
10
|
* Attributes: authorize-url (required), app-theme, label, variant,
|
|
12
|
-
* theme, platforms (
|
|
11
|
+
* theme, platforms ("stripe, notion" or a JSON array), more-count,
|
|
13
12
|
* description, accent-color, connected-label.
|
|
14
|
-
* Events: "success"
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* Events: "success" and "error" (detail: message), plus the matching
|
|
14
|
+
* onSuccess and onError function properties that React 19, Vue and
|
|
15
|
+
* Svelte set naturally as props.
|
|
17
16
|
*/
|
|
18
17
|
export declare function registerConnectButton(): void;
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
/** Query params the
|
|
2
|
-
*
|
|
3
|
-
*
|
|
1
|
+
/** Query params the app's callback route puts on its final redirect.
|
|
2
|
+
* The SDK reads them off the page URL when the tab comes home, so
|
|
3
|
+
* there is no completion page to build. */
|
|
4
4
|
export declare const RETURN_STATUS_PARAM = "one_connect";
|
|
5
5
|
export declare const RETURN_MESSAGE_PARAM = "one_connect_message";
|
|
6
6
|
/** Fragment key on the authorize URL carrying the app-chosen theme.
|
|
7
7
|
* A fragment never reaches any server and survives the whole redirect
|
|
8
|
-
* chain, so the
|
|
8
|
+
* chain, so the app's backend forwards nothing. */
|
|
9
9
|
export declare const THEME_PARAM = "one_theme";
|
|
10
|
+
/** One's connector logos, by slug. */
|
|
11
|
+
export declare const CONNECTOR_ASSETS_URL = "https://assets.withone.ai/connectors";
|
|
12
|
+
/** One's production API. Point `oneApiUrl` elsewhere for development. */
|
|
13
|
+
export declare const DEFAULT_ONE_API_URL = "https://api.withone.ai";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const e="one_connect",t="one_connect_message";let n=!1;const o=o=>{if("undefined"!=typeof window&&!n){const r=function(n){var o;const r=new URLSearchParams(n),i=r.get(e);if("success"!==i&&"error"!==i)return null;const c=null!==(o=r.get(t))&&void 0!==o?o:void 0;return c?{status:i,message:c}:{status:i}}(window.location.search);if(r){n=!0;const i=()=>{(function(n){const o=new URLSearchParams(n);return o.has(e)||o.has(t)})(window.location.search)&&window.history.replaceState(null,"",function(n){const o=new URLSearchParams(n.search);o.delete(e),o.delete(t);const r=o.toString();return`${n.pathname}${r?`?${r}`:""}${n.hash}`}(window.location))};i();for(const e of[50,500,2e3])window.setTimeout(i,e);window.setTimeout(()=>{try{var e,t,n;"success"===r.status?null===(e=o.onSuccess)||void 0===e||e.call(o):null===(t=o.onError)||void 0===t||t.call(o,null!==(n=r.message)&&void 0!==n?n:"The connection was not completed.")}catch{}},0)}}return{open:()=>{"undefined"!=typeof window&&window.location.assign((()=>{try{const e=new URL(o.authorizeUrl,"undefined"==typeof window?void 0:window.location.origin);return o.appTheme&&(e.hash=`one_theme=${o.appTheme}`),e.toString()}catch{return o.authorizeUrl}})())}}};function r(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var o=n.call(e,t);if("object"!=typeof o)return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e){return e.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}function c(e){return e.split(/[-_]+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function l(e){return e?`https://assets.withone.ai/connectors/${e}.svg`:""}function a(e){var t,n,o,r;const a="string"==typeof e?{slug:e}:e,s=null!==(t=a.slug)&&void 0!==t&&t.trim()?i(a.slug):null!==(n=a.name)&&void 0!==n&&n.trim()?i(a.name):"";return s?{slug:s,name:(null===(o=a.name)||void 0===o?void 0:o.trim())||c(s),imageUrl:(null===(r=a.imageUrl)||void 0===r?void 0:r.trim())||l(s)}:null}function s(e){return(null!=e?e:[]).map(a).filter(e=>null!==e)}function d(e){const t=null==e?void 0:e.trim();if(!t)return[];if(t.startsWith("["))try{const e=JSON.parse(t);return Array.isArray(e)?e.filter(e=>"string"==typeof e||"object"==typeof e&&null!==e):[]}catch{return[]}return t.split(",").map(e=>e.trim()).filter(Boolean)}const p="one-connect-button-styles",u="cubic-bezier(.2,.9,.25,1)",m="#CCFF00",h="#3FE3A5",b="#0A0C0B",f={buttonBackground:b,buttonForeground:"#FFFFFF",surface:"#FFFFFF",foreground:b,muted:"#6B7280",line:"#D1D5DB",shadow:"0 1px 2px rgba(10,12,11,.08), 0 4px 14px rgba(10,12,11,.06)"},w={buttonBackground:"#F2F5F3",buttonForeground:b,surface:"#101312",foreground:"#F2F5F3",muted:"#8A938E",line:"#2A302D",shadow:"0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.35)"};const g=(e,t)=>{var n,r,i;!function(){if("undefined"==typeof document||document.getElementById(p))return;const e=document.createElement("style");e.id=p,e.textContent=[`.owcb{font:500 14.5px/1.2 inherit;font-family:inherit;letter-spacing:-.01em;cursor:pointer;border:0;display:inline-flex;align-items:center;gap:12px;padding:12px 16px 12px 14px;border-radius:12px;transition:transform .2s ${u},box-shadow .2s ${u},opacity .2s ${u}}`,".owcb:hover{transform:translateY(-1px)}",".owcb:active{transform:translateY(0)}",`.owcb:focus-visible{outline:2px solid ${h};outline-offset:3px}`,".owcb[disabled]{cursor:default;opacity:.75;transform:none}",".owcb-stack{display:inline-flex;align-items:center;flex-shrink:0}",`.owcb-chip{width:22px;height:22px;border-radius:6px;display:grid;place-items:center;overflow:hidden;margin-left:-7px;transition:margin-left .28s ${u};position:relative;background:#FFFFFF}`,".owcb-chip:first-child{margin-left:0}",".owcb-chip img{width:14px;height:14px;display:block;object-fit:contain}",`.owcb-chip.owcb-more{font-family:ui-monospace,monospace;font-size:9px;font-weight:500;letter-spacing:-.02em;color:${b}}`,`.owcb-chip.owcb-letter{font:600 10px ui-monospace,monospace;color:${b}}`,".owcb:hover .owcb-chip{margin-left:-2px}",".owcb:hover .owcb-chip:first-child{margin-left:0}",".owcb-label{white-space:nowrap}",`.owcb-arrow{opacity:.5;transition:transform .2s ${u},opacity .2s ${u}}`,".owcb:hover .owcb-arrow{transform:translateX(2px);opacity:.8}",".owcb-spinner{width:16px;height:16px;border-radius:50%;border:2px solid currentColor;border-top-color:transparent;opacity:.7;animation:owcb-spin .7s linear infinite}","@keyframes owcb-spin{to{transform:rotate(360deg)}}",".owcb.owcb-block{display:flex;flex-direction:column;align-items:stretch;width:100%;max-width:420px;text-align:left;padding:16px;border-radius:14px;gap:0}",".owcb-block-top{display:flex;align-items:center;justify-content:space-between;gap:12px}",".owcb-block-title{font-size:15px;font-weight:600;letter-spacing:-.01em}",".owcb-block-sub{font-size:13px;line-height:1.5;margin-top:6px;font-weight:400}",".owcb-block-foot{margin-top:14px;padding-top:12px;display:flex;align-items:center;gap:6px;font-size:11.5px;font-weight:400}","@media (prefers-reduced-motion:reduce){.owcb,.owcb-chip,.owcb-arrow{transition:none}.owcb-spinner{animation-duration:1.4s}}"].join("\n"),document.head.appendChild(e)}();const c="dark"===t.theme?w:f,l=null!==(n=t.variant)&&void 0!==n?n:"default",a=null!==(r=t.label)&&void 0!==r?r:"Connect your apps",d=null!==(i=t.connectedLabel)&&void 0!==i?i:"Connected";let g="idle",v=!1;const x=o({...t.connect,onSuccess:()=>{var e,n;E("connected"),null===(e=(n=t.connect).onSuccess)||void 0===e||e.call(n)},onError:e=>{var n,o;E("idle"),null===(n=(o=t.connect).onError)||void 0===n||n.call(o,e)}}),y=document.createElement("button");y.type="button",y.className="block"===l?"owcb owcb-block":"owcb",y.addEventListener("click",()=>{"connecting"!==g&&(E("connecting"),x.open())});const C=()=>"connecting"===g?"Connecting…":"connected"===g?d:a,k=()=>{var e,n;const o="accent"===l,r="block"===l,i=r?c.surface:o?null!==(e=t.accentColor)&&void 0!==e?e:m:c.buttonBackground,a=r?c.foreground:o?b:c.buttonForeground,d=r?c.surface:i;y.style.background="connected"!==g||r?i:h,y.style.color="connected"!==g||r?a:b,y.style.boxShadow=r?`inset 0 0 0 1px ${c.line}`:"connected"===g?"none":o?`0 1px 2px rgba(10,12,11,.1), 0 6px 20px ${null!==(n=t.accentColor)&&void 0!==n?n:m}38`:c.shadow,y.disabled="connecting"===g,y.innerHTML="";const p=function(e,t){var n;const o=s(e.platforms);if(0===o.length&&!e.moreCount)return null;const r=document.createElement("span");r.className="owcb-stack",r.setAttribute("aria-hidden","true");for(const e of o.slice(0,3)){const n=document.createElement("span");n.className="owcb-chip",n.title=e.name,n.style.boxShadow=`0 0 0 1.5px ${t}`;const o=document.createElement("img");o.alt="",o.src=e.imageUrl,o.addEventListener("error",()=>{o.remove(),n.classList.add("owcb-letter"),n.textContent=e.name.charAt(0).toUpperCase()}),n.appendChild(o),r.appendChild(n)}const i=(null!==(n=e.moreCount)&&void 0!==n?n:0)+Math.max(0,o.length-3);if(i>0){const e=document.createElement("span");e.className="owcb-chip owcb-more",e.style.boxShadow=`0 0 0 1.5px ${t}`,e.textContent=`+${i}`,r.appendChild(e)}return r}(t,d);if(r){const e=document.createElement("span");e.className="owcb-block-top";const n=document.createElement("span");if(n.className="owcb-block-title",n.textContent=C(),e.appendChild(n),"connecting"===g){const t=document.createElement("span");t.className="owcb-spinner",e.appendChild(t)}else p&&e.appendChild(p);if(y.appendChild(e),t.description&&"idle"===g){const e=document.createElement("span");e.className="owcb-block-sub",e.style.color=c.muted,e.textContent=t.description,y.appendChild(e)}const o=document.createElement("span");return o.className="owcb-block-foot",o.style.color=c.muted,o.style.borderTop=`1px solid ${c.line}`,o.innerHTML=`<span style="font-size:11px;color:${c.muted}">Secured by</span><span style="display:inline-flex;color:${c.foreground}"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.4" style="flex-shrink:0"><circle cx="12" cy="12" r="8.5"/></svg></span><span style="font-size:12px;font-weight:600;letter-spacing:-0.02em;color:${c.foreground}">one</span>`,void y.appendChild(o)}if("connecting"===g){const e=document.createElement("span");e.className="owcb-spinner",y.appendChild(e)}else if("connected"===g){const e=document.createElement("span");e.innerHTML='<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px"><path d="M3 8.5l3.5 3.5L13 5"/></svg>',e.style.display="inline-flex",y.appendChild(e)}else p&&y.appendChild(p);const u=document.createElement("span");if(u.className="owcb-label",u.textContent=C(),y.appendChild(u),"idle"===g){const e=document.createElement("span");e.innerHTML='<svg class="owcb-arrow" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3l5 5-5 5"/></svg>',e.style.display="inline-flex",y.appendChild(e)}},E=e=>{v||(g=e,k())};return k(),e.appendChild(y),{setState:E,destroy:()=>{v=!0,y.remove()}}};function v(){if("undefined"!=typeof window&&"undefined"!=typeof customElements&&!customElements.get("one-connect-button")){class e extends HTMLElement{constructor(...e){super(...e),r(this,"onSuccess",null),r(this,"onError",null),r(this,"handle",null)}connectedCallback(){this.mount()}disconnectedCallback(){var e;null===(e=this.handle)||void 0===e||e.destroy(),this.handle=null}attributeChangedCallback(){this.isConnected&&this.handle&&this.mount()}mount(){var e,t,n,o,r;null===(e=this.handle)||void 0===e||e.destroy(),this.handle=null;const i=this.getAttribute("authorize-url");if(!i)return;const c=this.getAttribute("more-count"),l=c?parseInt(c,10):NaN;this.handle=g(this,{connect:{authorizeUrl:i,appTheme:x(this,"app-theme",["light","dark"]),onSuccess:()=>{var e;null===(e=this.onSuccess)||void 0===e||e.call(this),this.dispatchEvent(new CustomEvent("success"))},onError:e=>{var t;null===(t=this.onError)||void 0===t||t.call(this,e),this.dispatchEvent(new CustomEvent("error",{detail:e}))}},label:null!==(t=this.getAttribute("label"))&&void 0!==t?t:void 0,variant:x(this,"variant",["default","accent","block"]),theme:x(this,"theme",["light","dark"]),platforms:d(this.getAttribute("platforms")),moreCount:Number.isFinite(l)?l:void 0,description:null!==(n=this.getAttribute("description"))&&void 0!==n?n:void 0,accentColor:null!==(o=this.getAttribute("accent-color"))&&void 0!==o?o:void 0,connectedLabel:null!==(r=this.getAttribute("connected-label"))&&void 0!==r?r:void 0})}}r(e,"observedAttributes",["authorize-url","app-theme","label","variant","theme","platforms","more-count","description","accent-color","connected-label"]),customElements.define("one-connect-button",e)}}function x(e,t,n){const o=e.getAttribute(t);return o&&n.includes(o)?o:void 0}v(),exports.mountConnectButton=g,exports.normalizePlatform=a,exports.normalizePlatforms=s,exports.optionsFromProps=function(e,t=e){return{connect:{authorizeUrl:e.authorizeUrl,appTheme:e.appTheme,onSuccess:()=>{var e;return null===(e=t.onSuccess)||void 0===e?void 0:e.call(t)},onError:e=>{var n;return null===(n=t.onError)||void 0===n?void 0:n.call(t,e)}},label:e.label,variant:e.variant,theme:e.theme,platforms:e.platforms,moreCount:e.moreCount,description:e.description,accentColor:e.accentColor,connectedLabel:e.connectedLabel}},exports.parsePlatformsAttribute=d,exports.propsIdentity=function(e){var t;return JSON.stringify([e.authorizeUrl,e.appTheme,e.label,e.variant,e.theme,null!==(t=e.platforms)&&void 0!==t?t:[],e.moreCount,e.description,e.accentColor,e.connectedLabel])},exports.registerConnectButton=v,exports.useOneConnect=o;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { useOneConnect } from "./useOneConnect";
|
|
2
2
|
export { mountConnectButton, registerConnectButton } from "./button";
|
|
3
|
-
export
|
|
3
|
+
export { optionsFromProps, propsIdentity, type ConnectButtonProps, type ConnectButtonCallbacks, } from "./wrapper-options";
|
|
4
|
+
export { normalizePlatform, normalizePlatforms, parsePlatformsAttribute, } from "./platforms";
|
|
5
|
+
export type { OneConnectOptions, OneConnectHandle, OneConnectReturn, OneConnectTheme, ConnectButtonOptions, ConnectButtonPlatform, ConnectButtonPlatformInput, ConnectButtonVariant, ConnectButtonState, ConnectButtonHandle, } from "./types";
|
package/dist/index.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e="one_connect",t="one_connect_message";let n=!1;const o=o=>{let i=!1;if("undefined"!=typeof window&&!n){const l=new URLSearchParams(window.location.search),r=l.get(e);if("success"===r||"error"===r){var c;n=!0;const s=null!==(c=l.get(t))&&void 0!==c?c:void 0,a=()=>{const n=new URLSearchParams(window.location.search);(n.has(e)||n.has(t))&&(n.delete(e),n.delete(t),window.history.replaceState(null,"",window.location.pathname+(n.toString()?`?${n.toString()}`:"")+window.location.hash))};a();for(const e of[50,500,2e3])window.setTimeout(a,e);window.setTimeout(()=>{if(!i){i=!0;try{var e,t;"success"===r?null===(e=o.onSuccess)||void 0===e||e.call(o):null===(t=o.onError)||void 0===t||t.call(o,null!=s?s:"The connection was not completed.")}catch{}}},0)}}return{open:()=>{"undefined"!=typeof window&&window.location.assign((()=>{try{const e=new URL(o.authorize.url,"undefined"==typeof window?void 0:window.location.origin);return o.appTheme&&(e.hash=`one_theme=${o.appTheme}`),e.toString()}catch{return o.authorize.url}})())},close:e=>{}}};function i(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var o=n.call(e,t);if("object"!=typeof o)return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}const c="one-connect-button-styles",l="cubic-bezier(.2,.9,.25,1)",r={btnBg:"#0A0C0B",btnFg:"#ffffff",surface:"#ffffff",fg:"#0A0C0B",muted:"#6B7280",line:"#D1D5DB",shadow:"0 1px 2px rgba(10,12,11,.08), 0 4px 14px rgba(10,12,11,.06)"},s={btnBg:"#F2F5F3",btnFg:"#0A0C0B",surface:"#101312",fg:"#F2F5F3",muted:"#8A938E",line:"#2A302D",shadow:"0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.35)"},a="#CCFF00",d="#3FE3A5",p="#0A0C0B";function u(e){const t=e.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");return t?`https://assets.withone.ai/connectors/${t}.svg`:""}const h=(e,t)=>{var n,i;!function(){if("undefined"==typeof document||document.getElementById(c))return;const e=document.createElement("style");e.id=c,e.textContent=[`.owcb{font:500 14.5px/1.2 inherit;font-family:inherit;letter-spacing:-.01em;cursor:pointer;border:0;display:inline-flex;align-items:center;gap:12px;padding:12px 16px 12px 14px;border-radius:12px;transition:transform .2s ${l},box-shadow .2s ${l},opacity .2s ${l}}`,".owcb:hover{transform:translateY(-1px)}",".owcb:active{transform:translateY(0)}",`.owcb:focus-visible{outline:2px solid ${d};outline-offset:3px}`,".owcb[disabled]{cursor:default;opacity:.75;transform:none}",".owcb-stack{display:inline-flex;align-items:center;flex-shrink:0}",`.owcb-chip{width:22px;height:22px;border-radius:6px;display:grid;place-items:center;overflow:hidden;margin-left:-7px;transition:margin-left .28s ${l};position:relative}`,".owcb-chip:first-child{margin-left:0}",".owcb-chip img{width:14px;height:14px;display:block;object-fit:contain}",".owcb-chip.owcb-more{font-family:ui-monospace,monospace;font-size:9px;font-weight:500;letter-spacing:-.02em}",".owcb:hover .owcb-chip{margin-left:-2px}",".owcb:hover .owcb-chip:first-child{margin-left:0}",".owcb-label{white-space:nowrap}",`.owcb-arrow{opacity:.5;transition:transform .2s ${l},opacity .2s ${l}}`,".owcb:hover .owcb-arrow{transform:translateX(2px);opacity:.8}",".owcb-spinner{width:16px;height:16px;border-radius:50%;border:2px solid currentColor;border-top-color:transparent;opacity:.7;animation:owcb-spin .7s linear infinite}","@keyframes owcb-spin{to{transform:rotate(360deg)}}",".owcb.owcb-block{display:flex;flex-direction:column;align-items:stretch;width:100%;max-width:420px;text-align:left;padding:16px;border-radius:14px;gap:0}",".owcb-block-top{display:flex;align-items:center;justify-content:space-between;gap:12px}",".owcb-block-title{font-size:15px;font-weight:600;letter-spacing:-.01em}",".owcb-block-sub{font-size:13px;line-height:1.5;margin-top:6px;font-weight:400}",".owcb-block-foot{margin-top:14px;padding-top:12px;display:flex;align-items:center;gap:6px;font-size:11.5px;font-weight:400}","@media (prefers-reduced-motion:reduce){.owcb,.owcb-chip,.owcb-arrow{transition:none}.owcb-spinner{animation-duration:1.4s}}"].join("\n"),document.head.appendChild(e)}();const h="dark"===t.theme?s:r,m=null!==(n=t.variant)&&void 0!==n?n:"default",f=null!==(i=t.label)&&void 0!==i?i:"Connect your apps";let b="idle",w=!1;const g=o({...t.connect,onSuccess:()=>{var e,n;y("connected"),null===(e=(n=t.connect).onSuccess)||void 0===e||e.call(n)},onError:e=>{var n,o;y("idle"),null===(n=(o=t.connect).onError)||void 0===n||n.call(o,e)},onClose:()=>{var e,n;y("idle"),null===(e=(n=t.connect).onClose)||void 0===e||e.call(n)}}),v=document.createElement("button");v.type="button",v.className="block"===m?"owcb owcb-block":"owcb",v.addEventListener("click",()=>{"idle"!==b&&"connected"!==b||(y("connecting"),g.open())});const x=()=>{var e,n,o;const i="accent"===m,c="block"===m,l=c?h.surface:i?null!==(e=t.accentColor)&&void 0!==e?e:a:h.btnBg,r=c?h.fg:i?p:h.btnFg,s=c?h.surface:l,w=p;v.style.background="connected"!==b||c?l:d,v.style.color="connected"!==b||c?r:p,v.style.boxShadow=c?`inset 0 0 0 1px ${h.line}`:"connected"===b?"none":i?`0 1px 2px rgba(10,12,11,.1), 0 6px 20px ${null!==(n=t.accentColor)&&void 0!==n?n:a}38`:h.shadow,v.disabled="connecting"===b,v.innerHTML="";const g=function(e,t,n){var o,i;const c=null!==(o=e.platforms)&&void 0!==o?o:[];if(0===c.length&&!e.moreCount)return null;const l=document.createElement("span");l.className="owcb-stack",l.setAttribute("aria-hidden","true");for(const e of c.slice(0,3)){var r;const n=document.createElement("span");n.className="owcb-chip",n.style.background="#ffffff",n.style.boxShadow=`0 0 0 1.5px ${t}`;const o=()=>{n.textContent=e.name.charAt(0).toUpperCase(),n.style.font="600 10px ui-monospace,monospace",n.style.color=p},i=null!==(r=e.imageUrl)&&void 0!==r?r:u(e.name);if(i){const e=document.createElement("img");e.alt="",e.src=i,e.addEventListener("error",()=>{e.remove(),o()}),n.appendChild(e)}else o();l.appendChild(n)}const s=(null!==(i=e.moreCount)&&void 0!==i?i:0)+Math.max(0,c.length-3);if(s>0){const e=document.createElement("span");e.className="owcb-chip owcb-more",e.style.background="#ffffff",e.style.boxShadow=`0 0 0 1.5px ${t}`,e.style.color=n,e.textContent=`+${s}`,l.appendChild(e)}return l}(t,s,w);if(c){var x;const e=document.createElement("span");e.className="owcb-block-top";const n=document.createElement("span");if(n.className="owcb-block-title",n.textContent="connecting"===b?"Connecting…":"connected"===b?null!==(x=t.connectedLabel)&&void 0!==x?x:"Connected":f,e.appendChild(n),"connecting"===b){const t=document.createElement("span");t.className="owcb-spinner",e.appendChild(t)}else g&&e.appendChild(g);if(v.appendChild(e),t.description&&"idle"===b){const e=document.createElement("span");e.className="owcb-block-sub",e.style.color=h.muted,e.textContent=t.description,v.appendChild(e)}const o=document.createElement("span");return o.className="owcb-block-foot",o.style.color=h.muted,o.style.borderTop=`1px solid ${h.line}`,o.innerHTML=`<span style="font-size:11px;color:${h.muted}">Secured by</span><span style="display:inline-flex;color:${h.fg}"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.4" style="flex-shrink:0"><circle cx="12" cy="12" r="8.5"/></svg></span><span style="font-size:12px;font-weight:600;letter-spacing:-0.02em;color:${h.fg}">one</span>`,void v.appendChild(o)}if("connecting"===b){const e=document.createElement("span");e.className="owcb-spinner",v.appendChild(e)}else if("connected"===b){const e=document.createElement("span");e.innerHTML='<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px"><path d="M3 8.5l3.5 3.5L13 5"/></svg>',e.style.display="inline-flex",v.appendChild(e)}else g&&v.appendChild(g);const y=document.createElement("span");if(y.className="owcb-label",y.textContent="connecting"===b?"Connecting…":"connected"===b?null!==(o=t.connectedLabel)&&void 0!==o?o:"Connected":f,v.appendChild(y),"idle"===b){const e=document.createElement("span");e.innerHTML='<svg class="owcb-arrow" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3l5 5-5 5"/></svg>',e.style.display="inline-flex",v.appendChild(e)}},y=e=>{w||(b=e,x())};return x(),e.appendChild(v),{setState:y,destroy:()=>{w=!0,g.close({keepResult:!0}),v.remove()}}};function m(){if("undefined"!=typeof window&&"undefined"!=typeof customElements&&!customElements.get("one-connect-button")){class e extends HTMLElement{constructor(...e){super(...e),i(this,"onSuccess",null),i(this,"onError",null),i(this,"onClose",null),i(this,"handle",null)}connectedCallback(){this.mount()}disconnectedCallback(){var e;null===(e=this.handle)||void 0===e||e.destroy(),this.handle=null}attributeChangedCallback(){this.isConnected&&this.handle&&this.mount()}mount(){var e,t,n,o,i,c,l,r;null===(e=this.handle)||void 0===e||e.destroy(),this.handle=null;const s=this.getAttribute("authorize-url");if(!s)return;let a;const d=this.getAttribute("platforms");if(d)try{const e=JSON.parse(d);Array.isArray(e)&&(a=e)}catch{}const p=this.getAttribute("more-count"),u=p?parseInt(p,10):void 0;this.handle=h(this,{connect:{authorize:{url:s},appTheme:null!==(t=this.getAttribute("app-theme"))&&void 0!==t?t:void 0,onSuccess:()=>{var e;null===(e=this.onSuccess)||void 0===e||e.call(this),this.dispatchEvent(new CustomEvent("success"))},onError:e=>{var t;null===(t=this.onError)||void 0===t||t.call(this,e),this.dispatchEvent(new CustomEvent("error",{detail:e}))},onClose:()=>{var e;null===(e=this.onClose)||void 0===e||e.call(this),this.dispatchEvent(new CustomEvent("close"))}},label:null!==(n=this.getAttribute("label"))&&void 0!==n?n:void 0,variant:null!==(o=this.getAttribute("variant"))&&void 0!==o?o:void 0,theme:null!==(i=this.getAttribute("theme"))&&void 0!==i?i:void 0,platforms:a,moreCount:Number.isFinite(u)?u:void 0,description:null!==(c=this.getAttribute("description"))&&void 0!==c?c:void 0,accentColor:null!==(l=this.getAttribute("accent-color"))&&void 0!==l?l:void 0,connectedLabel:null!==(r=this.getAttribute("connected-label"))&&void 0!==r?r:void 0})}}i(e,"observedAttributes",["authorize-url","app-theme","label","variant","theme","platforms","more-count","description","accent-color","connected-label"]),customElements.define("one-connect-button",e)}}m();export{h as mountConnectButton,m as registerConnectButton,o as useOneConnect};
|
|
1
|
+
const e="one_connect",t="one_connect_message";let n=!1;const o=o=>{if("undefined"!=typeof window&&!n){const r=function(n){var o;const r=new URLSearchParams(n),i=r.get(e);if("success"!==i&&"error"!==i)return null;const c=null!==(o=r.get(t))&&void 0!==o?o:void 0;return c?{status:i,message:c}:{status:i}}(window.location.search);if(r){n=!0;const i=()=>{(function(n){const o=new URLSearchParams(n);return o.has(e)||o.has(t)})(window.location.search)&&window.history.replaceState(null,"",function(n){const o=new URLSearchParams(n.search);o.delete(e),o.delete(t);const r=o.toString();return`${n.pathname}${r?`?${r}`:""}${n.hash}`}(window.location))};i();for(const e of[50,500,2e3])window.setTimeout(i,e);window.setTimeout(()=>{try{var e,t,n;"success"===r.status?null===(e=o.onSuccess)||void 0===e||e.call(o):null===(t=o.onError)||void 0===t||t.call(o,null!==(n=r.message)&&void 0!==n?n:"The connection was not completed.")}catch{}},0)}}return{open:()=>{"undefined"!=typeof window&&window.location.assign((()=>{try{const e=new URL(o.authorizeUrl,"undefined"==typeof window?void 0:window.location.origin);return o.appTheme&&(e.hash=`one_theme=${o.appTheme}`),e.toString()}catch{return o.authorizeUrl}})())}}};function r(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var o=n.call(e,t);if("object"!=typeof o)return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e){return e.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}function c(e){return e.split(/[-_]+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function l(e){return e?`https://assets.withone.ai/connectors/${e}.svg`:""}function a(e){var t,n,o,r;const a="string"==typeof e?{slug:e}:e,s=null!==(t=a.slug)&&void 0!==t&&t.trim()?i(a.slug):null!==(n=a.name)&&void 0!==n&&n.trim()?i(a.name):"";return s?{slug:s,name:(null===(o=a.name)||void 0===o?void 0:o.trim())||c(s),imageUrl:(null===(r=a.imageUrl)||void 0===r?void 0:r.trim())||l(s)}:null}function s(e){return(null!=e?e:[]).map(a).filter(e=>null!==e)}function d(e){const t=null==e?void 0:e.trim();if(!t)return[];if(t.startsWith("["))try{const e=JSON.parse(t);return Array.isArray(e)?e.filter(e=>"string"==typeof e||"object"==typeof e&&null!==e):[]}catch{return[]}return t.split(",").map(e=>e.trim()).filter(Boolean)}const u="one-connect-button-styles",p="cubic-bezier(.2,.9,.25,1)",m="#CCFF00",h="#3FE3A5",b="#0A0C0B",f={buttonBackground:b,buttonForeground:"#FFFFFF",surface:"#FFFFFF",foreground:b,muted:"#6B7280",line:"#D1D5DB",shadow:"0 1px 2px rgba(10,12,11,.08), 0 4px 14px rgba(10,12,11,.06)"},w={buttonBackground:"#F2F5F3",buttonForeground:b,surface:"#101312",foreground:"#F2F5F3",muted:"#8A938E",line:"#2A302D",shadow:"0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.35)"};const g=(e,t)=>{var n,r,i;!function(){if("undefined"==typeof document||document.getElementById(u))return;const e=document.createElement("style");e.id=u,e.textContent=[`.owcb{font:500 14.5px/1.2 inherit;font-family:inherit;letter-spacing:-.01em;cursor:pointer;border:0;display:inline-flex;align-items:center;gap:12px;padding:12px 16px 12px 14px;border-radius:12px;transition:transform .2s ${p},box-shadow .2s ${p},opacity .2s ${p}}`,".owcb:hover{transform:translateY(-1px)}",".owcb:active{transform:translateY(0)}",`.owcb:focus-visible{outline:2px solid ${h};outline-offset:3px}`,".owcb[disabled]{cursor:default;opacity:.75;transform:none}",".owcb-stack{display:inline-flex;align-items:center;flex-shrink:0}",`.owcb-chip{width:22px;height:22px;border-radius:6px;display:grid;place-items:center;overflow:hidden;margin-left:-7px;transition:margin-left .28s ${p};position:relative;background:#FFFFFF}`,".owcb-chip:first-child{margin-left:0}",".owcb-chip img{width:14px;height:14px;display:block;object-fit:contain}",`.owcb-chip.owcb-more{font-family:ui-monospace,monospace;font-size:9px;font-weight:500;letter-spacing:-.02em;color:${b}}`,`.owcb-chip.owcb-letter{font:600 10px ui-monospace,monospace;color:${b}}`,".owcb:hover .owcb-chip{margin-left:-2px}",".owcb:hover .owcb-chip:first-child{margin-left:0}",".owcb-label{white-space:nowrap}",`.owcb-arrow{opacity:.5;transition:transform .2s ${p},opacity .2s ${p}}`,".owcb:hover .owcb-arrow{transform:translateX(2px);opacity:.8}",".owcb-spinner{width:16px;height:16px;border-radius:50%;border:2px solid currentColor;border-top-color:transparent;opacity:.7;animation:owcb-spin .7s linear infinite}","@keyframes owcb-spin{to{transform:rotate(360deg)}}",".owcb.owcb-block{display:flex;flex-direction:column;align-items:stretch;width:100%;max-width:420px;text-align:left;padding:16px;border-radius:14px;gap:0}",".owcb-block-top{display:flex;align-items:center;justify-content:space-between;gap:12px}",".owcb-block-title{font-size:15px;font-weight:600;letter-spacing:-.01em}",".owcb-block-sub{font-size:13px;line-height:1.5;margin-top:6px;font-weight:400}",".owcb-block-foot{margin-top:14px;padding-top:12px;display:flex;align-items:center;gap:6px;font-size:11.5px;font-weight:400}","@media (prefers-reduced-motion:reduce){.owcb,.owcb-chip,.owcb-arrow{transition:none}.owcb-spinner{animation-duration:1.4s}}"].join("\n"),document.head.appendChild(e)}();const c="dark"===t.theme?w:f,l=null!==(n=t.variant)&&void 0!==n?n:"default",a=null!==(r=t.label)&&void 0!==r?r:"Connect your apps",d=null!==(i=t.connectedLabel)&&void 0!==i?i:"Connected";let g="idle",v=!1;const x=o({...t.connect,onSuccess:()=>{var e,n;E("connected"),null===(e=(n=t.connect).onSuccess)||void 0===e||e.call(n)},onError:e=>{var n,o;E("idle"),null===(n=(o=t.connect).onError)||void 0===n||n.call(o,e)}}),y=document.createElement("button");y.type="button",y.className="block"===l?"owcb owcb-block":"owcb",y.addEventListener("click",()=>{"connecting"!==g&&(E("connecting"),x.open())});const C=()=>"connecting"===g?"Connecting…":"connected"===g?d:a,k=()=>{var e,n;const o="accent"===l,r="block"===l,i=r?c.surface:o?null!==(e=t.accentColor)&&void 0!==e?e:m:c.buttonBackground,a=r?c.foreground:o?b:c.buttonForeground,d=r?c.surface:i;y.style.background="connected"!==g||r?i:h,y.style.color="connected"!==g||r?a:b,y.style.boxShadow=r?`inset 0 0 0 1px ${c.line}`:"connected"===g?"none":o?`0 1px 2px rgba(10,12,11,.1), 0 6px 20px ${null!==(n=t.accentColor)&&void 0!==n?n:m}38`:c.shadow,y.disabled="connecting"===g,y.innerHTML="";const u=function(e,t){var n;const o=s(e.platforms);if(0===o.length&&!e.moreCount)return null;const r=document.createElement("span");r.className="owcb-stack",r.setAttribute("aria-hidden","true");for(const e of o.slice(0,3)){const n=document.createElement("span");n.className="owcb-chip",n.title=e.name,n.style.boxShadow=`0 0 0 1.5px ${t}`;const o=document.createElement("img");o.alt="",o.src=e.imageUrl,o.addEventListener("error",()=>{o.remove(),n.classList.add("owcb-letter"),n.textContent=e.name.charAt(0).toUpperCase()}),n.appendChild(o),r.appendChild(n)}const i=(null!==(n=e.moreCount)&&void 0!==n?n:0)+Math.max(0,o.length-3);if(i>0){const e=document.createElement("span");e.className="owcb-chip owcb-more",e.style.boxShadow=`0 0 0 1.5px ${t}`,e.textContent=`+${i}`,r.appendChild(e)}return r}(t,d);if(r){const e=document.createElement("span");e.className="owcb-block-top";const n=document.createElement("span");if(n.className="owcb-block-title",n.textContent=C(),e.appendChild(n),"connecting"===g){const t=document.createElement("span");t.className="owcb-spinner",e.appendChild(t)}else u&&e.appendChild(u);if(y.appendChild(e),t.description&&"idle"===g){const e=document.createElement("span");e.className="owcb-block-sub",e.style.color=c.muted,e.textContent=t.description,y.appendChild(e)}const o=document.createElement("span");return o.className="owcb-block-foot",o.style.color=c.muted,o.style.borderTop=`1px solid ${c.line}`,o.innerHTML=`<span style="font-size:11px;color:${c.muted}">Secured by</span><span style="display:inline-flex;color:${c.foreground}"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.4" style="flex-shrink:0"><circle cx="12" cy="12" r="8.5"/></svg></span><span style="font-size:12px;font-weight:600;letter-spacing:-0.02em;color:${c.foreground}">one</span>`,void y.appendChild(o)}if("connecting"===g){const e=document.createElement("span");e.className="owcb-spinner",y.appendChild(e)}else if("connected"===g){const e=document.createElement("span");e.innerHTML='<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px"><path d="M3 8.5l3.5 3.5L13 5"/></svg>',e.style.display="inline-flex",y.appendChild(e)}else u&&y.appendChild(u);const p=document.createElement("span");if(p.className="owcb-label",p.textContent=C(),y.appendChild(p),"idle"===g){const e=document.createElement("span");e.innerHTML='<svg class="owcb-arrow" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3l5 5-5 5"/></svg>',e.style.display="inline-flex",y.appendChild(e)}},E=e=>{v||(g=e,k())};return k(),e.appendChild(y),{setState:E,destroy:()=>{v=!0,y.remove()}}};function v(){if("undefined"!=typeof window&&"undefined"!=typeof customElements&&!customElements.get("one-connect-button")){class e extends HTMLElement{constructor(...e){super(...e),r(this,"onSuccess",null),r(this,"onError",null),r(this,"handle",null)}connectedCallback(){this.mount()}disconnectedCallback(){var e;null===(e=this.handle)||void 0===e||e.destroy(),this.handle=null}attributeChangedCallback(){this.isConnected&&this.handle&&this.mount()}mount(){var e,t,n,o,r;null===(e=this.handle)||void 0===e||e.destroy(),this.handle=null;const i=this.getAttribute("authorize-url");if(!i)return;const c=this.getAttribute("more-count"),l=c?parseInt(c,10):NaN;this.handle=g(this,{connect:{authorizeUrl:i,appTheme:x(this,"app-theme",["light","dark"]),onSuccess:()=>{var e;null===(e=this.onSuccess)||void 0===e||e.call(this),this.dispatchEvent(new CustomEvent("success"))},onError:e=>{var t;null===(t=this.onError)||void 0===t||t.call(this,e),this.dispatchEvent(new CustomEvent("error",{detail:e}))}},label:null!==(t=this.getAttribute("label"))&&void 0!==t?t:void 0,variant:x(this,"variant",["default","accent","block"]),theme:x(this,"theme",["light","dark"]),platforms:d(this.getAttribute("platforms")),moreCount:Number.isFinite(l)?l:void 0,description:null!==(n=this.getAttribute("description"))&&void 0!==n?n:void 0,accentColor:null!==(o=this.getAttribute("accent-color"))&&void 0!==o?o:void 0,connectedLabel:null!==(r=this.getAttribute("connected-label"))&&void 0!==r?r:void 0})}}r(e,"observedAttributes",["authorize-url","app-theme","label","variant","theme","platforms","more-count","description","accent-color","connected-label"]),customElements.define("one-connect-button",e)}}function x(e,t,n){const o=e.getAttribute(t);return o&&n.includes(o)?o:void 0}function y(e,t=e){return{connect:{authorizeUrl:e.authorizeUrl,appTheme:e.appTheme,onSuccess:()=>{var e;return null===(e=t.onSuccess)||void 0===e?void 0:e.call(t)},onError:e=>{var n;return null===(n=t.onError)||void 0===n?void 0:n.call(t,e)}},label:e.label,variant:e.variant,theme:e.theme,platforms:e.platforms,moreCount:e.moreCount,description:e.description,accentColor:e.accentColor,connectedLabel:e.connectedLabel}}function C(e){var t;return JSON.stringify([e.authorizeUrl,e.appTheme,e.label,e.variant,e.theme,null!==(t=e.platforms)&&void 0!==t?t:[],e.moreCount,e.description,e.accentColor,e.connectedLabel])}v();export{g as mountConnectButton,a as normalizePlatform,s as normalizePlatforms,y as optionsFromProps,d as parsePlatformsAttribute,C as propsIdentity,v as registerConnectButton,o as useOneConnect};
|
package/dist/next.cjs.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `@withone/connect/next`: the two routes as one file, for any server
|
|
5
|
+
* that speaks the web `Request` and `Response` (Next.js App Router,
|
|
6
|
+
* Remix, SvelteKit, Nuxt/h3 via its adapters, Hono, Bun).
|
|
7
|
+
*
|
|
8
|
+
* // app/api/one/[action]/route.ts
|
|
9
|
+
* import { createOneConnectRoutes } from "@withone/connect/next";
|
|
10
|
+
* import { oneConnect } from "@/lib/one";
|
|
11
|
+
*
|
|
12
|
+
* export const { GET } = createOneConnectRoutes(oneConnect, {
|
|
13
|
+
* identifyUser: async (request) => getSessionUserId(request),
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* That serves /api/one/authorize and /api/one/callback. Register
|
|
17
|
+
* `https://yourapp.com/api/one/callback` as the app's redirect URI.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const AUTHORIZE_ROUTE = "authorize";
|
|
21
|
+
const CALLBACK_ROUTE = "callback";
|
|
22
|
+
function redirectWithCookies(location, setCookies) {
|
|
23
|
+
const headers = new Headers({
|
|
24
|
+
Location: location
|
|
25
|
+
});
|
|
26
|
+
for (const cookie of setCookies) headers.append("Set-Cookie", cookie);
|
|
27
|
+
return new Response(null, {
|
|
28
|
+
status: 302,
|
|
29
|
+
headers
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function serializeCookie(name, value, options) {
|
|
33
|
+
const parts = [`${name}=${encodeURIComponent(value)}`, `Path=${options.path}`, `Max-Age=${options.maxAge}`, `SameSite=Lax`];
|
|
34
|
+
if (options.httpOnly) parts.push("HttpOnly");
|
|
35
|
+
if (options.secure) parts.push("Secure");
|
|
36
|
+
return parts.join("; ");
|
|
37
|
+
}
|
|
38
|
+
function expireCookie(name, path) {
|
|
39
|
+
return `${name}=; Path=${path}; Max-Age=0; SameSite=Lax; HttpOnly`;
|
|
40
|
+
}
|
|
41
|
+
function readCookie(request, name) {
|
|
42
|
+
const header = request.headers.get("cookie");
|
|
43
|
+
if (!header) return undefined;
|
|
44
|
+
for (const part of header.split(";")) {
|
|
45
|
+
const [rawName, ...rest] = part.trim().split("=");
|
|
46
|
+
if (rawName === name) return decodeURIComponent(rest.join("="));
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The last path segment names the leg: ".../authorize" or ".../callback". */
|
|
52
|
+
function routeFor(url) {
|
|
53
|
+
const pathname = new URL(url).pathname.replace(/\/+$/, "");
|
|
54
|
+
return pathname.slice(pathname.lastIndexOf("/") + 1);
|
|
55
|
+
}
|
|
56
|
+
function createOneConnectRoutes(oneConnect, options) {
|
|
57
|
+
const cookiePath = () => oneConnect.startAuthorization().cookie.options.path;
|
|
58
|
+
const requireUser = async request => {
|
|
59
|
+
const userId = await options.identifyUser(request);
|
|
60
|
+
if (userId) return userId;
|
|
61
|
+
if (options.signInUrl) return redirectWithCookies(new URL(options.signInUrl, request.url).toString(), []);
|
|
62
|
+
return new Response("Sign in to your account before connecting One.", {
|
|
63
|
+
status: 401
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
const authorize = async request => {
|
|
67
|
+
const user = await requireUser(request);
|
|
68
|
+
if (user instanceof Response) return user;
|
|
69
|
+
const loginHint = (await options.loginHintFor?.(request)) ?? undefined;
|
|
70
|
+
const {
|
|
71
|
+
redirectUrl,
|
|
72
|
+
cookie
|
|
73
|
+
} = oneConnect.startAuthorization({
|
|
74
|
+
loginHint
|
|
75
|
+
});
|
|
76
|
+
return redirectWithCookies(redirectUrl, [serializeCookie(cookie.name, cookie.value, cookie.options)]);
|
|
77
|
+
};
|
|
78
|
+
const callback = async request => {
|
|
79
|
+
const user = await requireUser(request);
|
|
80
|
+
if (user instanceof Response) return user;
|
|
81
|
+
const result = await oneConnect.completeAuthorization({
|
|
82
|
+
userId: user,
|
|
83
|
+
url: request.url,
|
|
84
|
+
getCookie: name => readCookie(request, name)
|
|
85
|
+
});
|
|
86
|
+
return redirectWithCookies(result.redirectUrl, result.clearCookieName ? [expireCookie(result.clearCookieName, cookiePath())] : []);
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
89
|
+
GET: async request => {
|
|
90
|
+
const route = routeFor(request.url);
|
|
91
|
+
if (route === AUTHORIZE_ROUTE) return authorize(request);
|
|
92
|
+
if (route === CALLBACK_ROUTE) return callback(request);
|
|
93
|
+
return new Response("Not found", {
|
|
94
|
+
status: 404
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
exports.AUTHORIZE_ROUTE = AUTHORIZE_ROUTE;
|
|
101
|
+
exports.CALLBACK_ROUTE = CALLBACK_ROUTE;
|
|
102
|
+
exports.createOneConnectRoutes = createOneConnectRoutes;
|
|
103
|
+
exports.readCookie = readCookie;
|
|
104
|
+
exports.routeFor = routeFor;
|
package/dist/next.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@withone/connect/next`: the two routes as one file, for any server
|
|
3
|
+
* that speaks the web `Request` and `Response` (Next.js App Router,
|
|
4
|
+
* Remix, SvelteKit, Nuxt/h3 via its adapters, Hono, Bun).
|
|
5
|
+
*
|
|
6
|
+
* // app/api/one/[action]/route.ts
|
|
7
|
+
* import { createOneConnectRoutes } from "@withone/connect/next";
|
|
8
|
+
* import { oneConnect } from "@/lib/one";
|
|
9
|
+
*
|
|
10
|
+
* export const { GET } = createOneConnectRoutes(oneConnect, {
|
|
11
|
+
* identifyUser: async (request) => getSessionUserId(request),
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* That serves /api/one/authorize and /api/one/callback. Register
|
|
15
|
+
* `https://yourapp.com/api/one/callback` as the app's redirect URI.
|
|
16
|
+
*/
|
|
17
|
+
import type { OneConnect } from "./server";
|
|
18
|
+
export interface OneConnectRoutesOptions {
|
|
19
|
+
/** The app's own id for the signed-in user, or null when nobody is
|
|
20
|
+
* signed in. The grant is stored under this id. */
|
|
21
|
+
identifyUser: (request: Request) => Promise<string | null> | string | null;
|
|
22
|
+
/** Pre-fills the sign-in email on One's page for this user. */
|
|
23
|
+
loginHintFor?: (request: Request) => Promise<string | null> | string | null;
|
|
24
|
+
/** Where to send the browser when nobody is signed in. Answers 401
|
|
25
|
+
* when omitted. */
|
|
26
|
+
signInUrl?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface OneConnectRoutes {
|
|
29
|
+
GET: (request: Request) => Promise<Response>;
|
|
30
|
+
}
|
|
31
|
+
export declare const AUTHORIZE_ROUTE = "authorize";
|
|
32
|
+
export declare const CALLBACK_ROUTE = "callback";
|
|
33
|
+
export declare function readCookie(request: Request, name: string): string | undefined;
|
|
34
|
+
/** The last path segment names the leg: ".../authorize" or ".../callback". */
|
|
35
|
+
export declare function routeFor(url: string): string;
|
|
36
|
+
export declare function createOneConnectRoutes(oneConnect: OneConnect, options: OneConnectRoutesOptions): OneConnectRoutes;
|
package/dist/next.esm.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@withone/connect/next`: the two routes as one file, for any server
|
|
3
|
+
* that speaks the web `Request` and `Response` (Next.js App Router,
|
|
4
|
+
* Remix, SvelteKit, Nuxt/h3 via its adapters, Hono, Bun).
|
|
5
|
+
*
|
|
6
|
+
* // app/api/one/[action]/route.ts
|
|
7
|
+
* import { createOneConnectRoutes } from "@withone/connect/next";
|
|
8
|
+
* import { oneConnect } from "@/lib/one";
|
|
9
|
+
*
|
|
10
|
+
* export const { GET } = createOneConnectRoutes(oneConnect, {
|
|
11
|
+
* identifyUser: async (request) => getSessionUserId(request),
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* That serves /api/one/authorize and /api/one/callback. Register
|
|
15
|
+
* `https://yourapp.com/api/one/callback` as the app's redirect URI.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const AUTHORIZE_ROUTE = "authorize";
|
|
19
|
+
const CALLBACK_ROUTE = "callback";
|
|
20
|
+
function redirectWithCookies(location, setCookies) {
|
|
21
|
+
const headers = new Headers({
|
|
22
|
+
Location: location
|
|
23
|
+
});
|
|
24
|
+
for (const cookie of setCookies) headers.append("Set-Cookie", cookie);
|
|
25
|
+
return new Response(null, {
|
|
26
|
+
status: 302,
|
|
27
|
+
headers
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function serializeCookie(name, value, options) {
|
|
31
|
+
const parts = [`${name}=${encodeURIComponent(value)}`, `Path=${options.path}`, `Max-Age=${options.maxAge}`, `SameSite=Lax`];
|
|
32
|
+
if (options.httpOnly) parts.push("HttpOnly");
|
|
33
|
+
if (options.secure) parts.push("Secure");
|
|
34
|
+
return parts.join("; ");
|
|
35
|
+
}
|
|
36
|
+
function expireCookie(name, path) {
|
|
37
|
+
return `${name}=; Path=${path}; Max-Age=0; SameSite=Lax; HttpOnly`;
|
|
38
|
+
}
|
|
39
|
+
function readCookie(request, name) {
|
|
40
|
+
const header = request.headers.get("cookie");
|
|
41
|
+
if (!header) return undefined;
|
|
42
|
+
for (const part of header.split(";")) {
|
|
43
|
+
const [rawName, ...rest] = part.trim().split("=");
|
|
44
|
+
if (rawName === name) return decodeURIComponent(rest.join("="));
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The last path segment names the leg: ".../authorize" or ".../callback". */
|
|
50
|
+
function routeFor(url) {
|
|
51
|
+
const pathname = new URL(url).pathname.replace(/\/+$/, "");
|
|
52
|
+
return pathname.slice(pathname.lastIndexOf("/") + 1);
|
|
53
|
+
}
|
|
54
|
+
function createOneConnectRoutes(oneConnect, options) {
|
|
55
|
+
const cookiePath = () => oneConnect.startAuthorization().cookie.options.path;
|
|
56
|
+
const requireUser = async request => {
|
|
57
|
+
const userId = await options.identifyUser(request);
|
|
58
|
+
if (userId) return userId;
|
|
59
|
+
if (options.signInUrl) return redirectWithCookies(new URL(options.signInUrl, request.url).toString(), []);
|
|
60
|
+
return new Response("Sign in to your account before connecting One.", {
|
|
61
|
+
status: 401
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
const authorize = async request => {
|
|
65
|
+
const user = await requireUser(request);
|
|
66
|
+
if (user instanceof Response) return user;
|
|
67
|
+
const loginHint = (await options.loginHintFor?.(request)) ?? undefined;
|
|
68
|
+
const {
|
|
69
|
+
redirectUrl,
|
|
70
|
+
cookie
|
|
71
|
+
} = oneConnect.startAuthorization({
|
|
72
|
+
loginHint
|
|
73
|
+
});
|
|
74
|
+
return redirectWithCookies(redirectUrl, [serializeCookie(cookie.name, cookie.value, cookie.options)]);
|
|
75
|
+
};
|
|
76
|
+
const callback = async request => {
|
|
77
|
+
const user = await requireUser(request);
|
|
78
|
+
if (user instanceof Response) return user;
|
|
79
|
+
const result = await oneConnect.completeAuthorization({
|
|
80
|
+
userId: user,
|
|
81
|
+
url: request.url,
|
|
82
|
+
getCookie: name => readCookie(request, name)
|
|
83
|
+
});
|
|
84
|
+
return redirectWithCookies(result.redirectUrl, result.clearCookieName ? [expireCookie(result.clearCookieName, cookiePath())] : []);
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
GET: async request => {
|
|
88
|
+
const route = routeFor(request.url);
|
|
89
|
+
if (route === AUTHORIZE_ROUTE) return authorize(request);
|
|
90
|
+
if (route === CALLBACK_ROUTE) return callback(request);
|
|
91
|
+
return new Response("Not found", {
|
|
92
|
+
status: 404
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export { AUTHORIZE_ROUTE, CALLBACK_ROUTE, createOneConnectRoutes, readCookie, routeFor };
|
package/dist/node.cjs.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var next = require('@withone/connect/next');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `@withone/connect/node`: the two routes as handlers for Node's
|
|
7
|
+
* `http` request and response objects, which is what Express, Fastify
|
|
8
|
+
* (via `reply.raw`), Koa (via `ctx.req`/`ctx.res`) and plain
|
|
9
|
+
* `http.createServer` hand you.
|
|
10
|
+
*
|
|
11
|
+
* import express from "express";
|
|
12
|
+
* import { createOneConnectHandlers } from "@withone/connect/node";
|
|
13
|
+
* import { oneConnect } from "./one";
|
|
14
|
+
*
|
|
15
|
+
* const { authorize, callback } = createOneConnectHandlers(oneConnect, {
|
|
16
|
+
* identifyUser: (request) => request.session?.userId ?? null,
|
|
17
|
+
* });
|
|
18
|
+
* app.get("/api/one/authorize", authorize);
|
|
19
|
+
* app.get("/api/one/callback", callback);
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** The incoming request as a web Request, so both adapters share one
|
|
23
|
+
* implementation. */
|
|
24
|
+
function toWebRequest(request) {
|
|
25
|
+
const protocol = request.headers["x-forwarded-proto"]?.toString().split(",")[0] ?? (request.socket.encrypted ? "https" : "http");
|
|
26
|
+
const host = request.headers["x-forwarded-host"] ?? request.headers.host ?? "localhost";
|
|
27
|
+
const headers = new Headers();
|
|
28
|
+
for (const [name, value] of Object.entries(request.headers)) {
|
|
29
|
+
if (typeof value === "string") headers.set(name, value);else if (Array.isArray(value)) headers.set(name, value.join(", "));
|
|
30
|
+
}
|
|
31
|
+
return new Request(`${protocol}://${host}${request.url ?? "/"}`, {
|
|
32
|
+
method: request.method ?? "GET",
|
|
33
|
+
headers
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async function send(response, web) {
|
|
37
|
+
const setCookies = typeof web.headers.getSetCookie === "function" ? web.headers.getSetCookie() : [];
|
|
38
|
+
web.headers.forEach((value, name) => {
|
|
39
|
+
if (name.toLowerCase() !== "set-cookie") response.setHeader(name, value);
|
|
40
|
+
});
|
|
41
|
+
if (setCookies.length > 0) response.setHeader("Set-Cookie", setCookies);
|
|
42
|
+
response.statusCode = web.status;
|
|
43
|
+
response.end(await web.text());
|
|
44
|
+
}
|
|
45
|
+
function createOneConnectHandlers(oneConnect, options) {
|
|
46
|
+
// The web adapter receives a Request; the Node callbacks want the
|
|
47
|
+
// original IncomingMessage, so it is carried alongside by closure.
|
|
48
|
+
let current = null;
|
|
49
|
+
const routeOptions = {
|
|
50
|
+
identifyUser: () => options.identifyUser(current),
|
|
51
|
+
loginHintFor: options.loginHintFor ? () => options.loginHintFor(current) : undefined,
|
|
52
|
+
signInUrl: options.signInUrl
|
|
53
|
+
};
|
|
54
|
+
const routes = next.createOneConnectRoutes(oneConnect, routeOptions);
|
|
55
|
+
const handle = async (request, response) => {
|
|
56
|
+
current = request;
|
|
57
|
+
try {
|
|
58
|
+
await send(response, await routes.GET(toWebRequest(request)));
|
|
59
|
+
} finally {
|
|
60
|
+
current = null;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
authorize: handle,
|
|
65
|
+
callback: handle
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
exports.createOneConnectHandlers = createOneConnectHandlers;
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@withone/connect/node`: the two routes as handlers for Node's
|
|
3
|
+
* `http` request and response objects, which is what Express, Fastify
|
|
4
|
+
* (via `reply.raw`), Koa (via `ctx.req`/`ctx.res`) and plain
|
|
5
|
+
* `http.createServer` hand you.
|
|
6
|
+
*
|
|
7
|
+
* import express from "express";
|
|
8
|
+
* import { createOneConnectHandlers } from "@withone/connect/node";
|
|
9
|
+
* import { oneConnect } from "./one";
|
|
10
|
+
*
|
|
11
|
+
* const { authorize, callback } = createOneConnectHandlers(oneConnect, {
|
|
12
|
+
* identifyUser: (request) => request.session?.userId ?? null,
|
|
13
|
+
* });
|
|
14
|
+
* app.get("/api/one/authorize", authorize);
|
|
15
|
+
* app.get("/api/one/callback", callback);
|
|
16
|
+
*/
|
|
17
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
18
|
+
import type { OneConnect } from "./server";
|
|
19
|
+
export interface OneConnectNodeOptions {
|
|
20
|
+
/** The app's own id for the signed-in user, or null when nobody is
|
|
21
|
+
* signed in. */
|
|
22
|
+
identifyUser: (request: IncomingMessage) => Promise<string | null> | string | null;
|
|
23
|
+
/** Pre-fills the sign-in email on One's page for this user. */
|
|
24
|
+
loginHintFor?: (request: IncomingMessage) => Promise<string | null> | string | null;
|
|
25
|
+
/** Where to send the browser when nobody is signed in. */
|
|
26
|
+
signInUrl?: string;
|
|
27
|
+
}
|
|
28
|
+
export type NodeHandler = (request: IncomingMessage, response: ServerResponse) => Promise<void>;
|
|
29
|
+
export interface OneConnectHandlers {
|
|
30
|
+
authorize: NodeHandler;
|
|
31
|
+
callback: NodeHandler;
|
|
32
|
+
}
|
|
33
|
+
export declare function createOneConnectHandlers(oneConnect: OneConnect, options: OneConnectNodeOptions): OneConnectHandlers;
|
package/dist/node.esm.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { createOneConnectRoutes } from '@withone/connect/next';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `@withone/connect/node`: the two routes as handlers for Node's
|
|
5
|
+
* `http` request and response objects, which is what Express, Fastify
|
|
6
|
+
* (via `reply.raw`), Koa (via `ctx.req`/`ctx.res`) and plain
|
|
7
|
+
* `http.createServer` hand you.
|
|
8
|
+
*
|
|
9
|
+
* import express from "express";
|
|
10
|
+
* import { createOneConnectHandlers } from "@withone/connect/node";
|
|
11
|
+
* import { oneConnect } from "./one";
|
|
12
|
+
*
|
|
13
|
+
* const { authorize, callback } = createOneConnectHandlers(oneConnect, {
|
|
14
|
+
* identifyUser: (request) => request.session?.userId ?? null,
|
|
15
|
+
* });
|
|
16
|
+
* app.get("/api/one/authorize", authorize);
|
|
17
|
+
* app.get("/api/one/callback", callback);
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** The incoming request as a web Request, so both adapters share one
|
|
21
|
+
* implementation. */
|
|
22
|
+
function toWebRequest(request) {
|
|
23
|
+
const protocol = request.headers["x-forwarded-proto"]?.toString().split(",")[0] ?? (request.socket.encrypted ? "https" : "http");
|
|
24
|
+
const host = request.headers["x-forwarded-host"] ?? request.headers.host ?? "localhost";
|
|
25
|
+
const headers = new Headers();
|
|
26
|
+
for (const [name, value] of Object.entries(request.headers)) {
|
|
27
|
+
if (typeof value === "string") headers.set(name, value);else if (Array.isArray(value)) headers.set(name, value.join(", "));
|
|
28
|
+
}
|
|
29
|
+
return new Request(`${protocol}://${host}${request.url ?? "/"}`, {
|
|
30
|
+
method: request.method ?? "GET",
|
|
31
|
+
headers
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async function send(response, web) {
|
|
35
|
+
const setCookies = typeof web.headers.getSetCookie === "function" ? web.headers.getSetCookie() : [];
|
|
36
|
+
web.headers.forEach((value, name) => {
|
|
37
|
+
if (name.toLowerCase() !== "set-cookie") response.setHeader(name, value);
|
|
38
|
+
});
|
|
39
|
+
if (setCookies.length > 0) response.setHeader("Set-Cookie", setCookies);
|
|
40
|
+
response.statusCode = web.status;
|
|
41
|
+
response.end(await web.text());
|
|
42
|
+
}
|
|
43
|
+
function createOneConnectHandlers(oneConnect, options) {
|
|
44
|
+
// The web adapter receives a Request; the Node callbacks want the
|
|
45
|
+
// original IncomingMessage, so it is carried alongside by closure.
|
|
46
|
+
let current = null;
|
|
47
|
+
const routeOptions = {
|
|
48
|
+
identifyUser: () => options.identifyUser(current),
|
|
49
|
+
loginHintFor: options.loginHintFor ? () => options.loginHintFor(current) : undefined,
|
|
50
|
+
signInUrl: options.signInUrl
|
|
51
|
+
};
|
|
52
|
+
const routes = createOneConnectRoutes(oneConnect, routeOptions);
|
|
53
|
+
const handle = async (request, response) => {
|
|
54
|
+
current = request;
|
|
55
|
+
try {
|
|
56
|
+
await send(response, await routes.GET(toWebRequest(request)));
|
|
57
|
+
} finally {
|
|
58
|
+
current = null;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
authorize: handle,
|
|
63
|
+
callback: handle
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { createOneConnectHandlers };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ConnectButtonPlatform, ConnectButtonPlatformInput } from "./types";
|
|
2
|
+
/** "Google Calendar" -> "google-calendar". */
|
|
3
|
+
export declare function slugFromName(name: string): string;
|
|
4
|
+
/** "google-calendar" -> "Google Calendar". */
|
|
5
|
+
export declare function nameFromSlug(slug: string): string;
|
|
6
|
+
/** One's logo for a connector slug. */
|
|
7
|
+
export declare function logoUrlForSlug(slug: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Turns whatever the developer passed into what the button draws. A bare
|
|
10
|
+
* string is a slug; an object may carry any of slug, name and imageUrl.
|
|
11
|
+
* Entries with neither a slug nor a name are dropped rather than drawn
|
|
12
|
+
* as an empty chip.
|
|
13
|
+
*/
|
|
14
|
+
export declare function normalizePlatform(input: ConnectButtonPlatformInput): ConnectButtonPlatform | null;
|
|
15
|
+
export declare function normalizePlatforms(inputs: ConnectButtonPlatformInput[] | undefined): ConnectButtonPlatform[];
|
|
16
|
+
/**
|
|
17
|
+
* The `platforms` attribute on <one-connect-button>: a comma list of
|
|
18
|
+
* slugs ("stripe, notion") or, for overrides, a JSON array of
|
|
19
|
+
* {slug, name, imageUrl} objects.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parsePlatformsAttribute(raw: string | null): ConnectButtonPlatformInput[];
|
package/dist/react.cjs.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("react");function t(e,t,n){return(t=function(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var o=n.call(e,t);if("object"!=typeof o)return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(e,"string");return"symbol"==typeof t?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}const n="one_connect",o="one_connect_message";let i=!1;const r=e=>{let t=!1;if("undefined"!=typeof window&&!i){const c=new URLSearchParams(window.location.search),l=c.get(n);if("success"===l||"error"===l){var r;i=!0;const s=null!==(r=c.get(o))&&void 0!==r?r:void 0,a=()=>{const e=new URLSearchParams(window.location.search);(e.has(n)||e.has(o))&&(e.delete(n),e.delete(o),window.history.replaceState(null,"",window.location.pathname+(e.toString()?`?${e.toString()}`:"")+window.location.hash))};a();for(const e of[50,500,2e3])window.setTimeout(a,e);window.setTimeout(()=>{if(!t){t=!0;try{var n,o;"success"===l?null===(n=e.onSuccess)||void 0===n||n.call(e):null===(o=e.onError)||void 0===o||o.call(e,null!=s?s:"The connection was not completed.")}catch{}}},0)}}return{open:()=>{"undefined"!=typeof window&&window.location.assign((()=>{try{const t=new URL(e.authorize.url,"undefined"==typeof window?void 0:window.location.origin);return e.appTheme&&(t.hash=`one_theme=${e.appTheme}`),t.toString()}catch{return e.authorize.url}})())},close:e=>{}}},c="one-connect-button-styles",l="cubic-bezier(.2,.9,.25,1)",s={btnBg:"#0A0C0B",btnFg:"#ffffff",surface:"#ffffff",fg:"#0A0C0B",muted:"#6B7280",line:"#D1D5DB",shadow:"0 1px 2px rgba(10,12,11,.08), 0 4px 14px rgba(10,12,11,.06)"},a={btnBg:"#F2F5F3",btnFg:"#0A0C0B",surface:"#101312",fg:"#F2F5F3",muted:"#8A938E",line:"#2A302D",shadow:"0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.35)"},d="#CCFF00",u="#3FE3A5",p="#0A0C0B";function h(e){const t=e.trim().toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"");return t?`https://assets.withone.ai/connectors/${t}.svg`:""}const m=(e,t)=>{var n,o;!function(){if("undefined"==typeof document||document.getElementById(c))return;const e=document.createElement("style");e.id=c,e.textContent=[`.owcb{font:500 14.5px/1.2 inherit;font-family:inherit;letter-spacing:-.01em;cursor:pointer;border:0;display:inline-flex;align-items:center;gap:12px;padding:12px 16px 12px 14px;border-radius:12px;transition:transform .2s ${l},box-shadow .2s ${l},opacity .2s ${l}}`,".owcb:hover{transform:translateY(-1px)}",".owcb:active{transform:translateY(0)}",`.owcb:focus-visible{outline:2px solid ${u};outline-offset:3px}`,".owcb[disabled]{cursor:default;opacity:.75;transform:none}",".owcb-stack{display:inline-flex;align-items:center;flex-shrink:0}",`.owcb-chip{width:22px;height:22px;border-radius:6px;display:grid;place-items:center;overflow:hidden;margin-left:-7px;transition:margin-left .28s ${l};position:relative}`,".owcb-chip:first-child{margin-left:0}",".owcb-chip img{width:14px;height:14px;display:block;object-fit:contain}",".owcb-chip.owcb-more{font-family:ui-monospace,monospace;font-size:9px;font-weight:500;letter-spacing:-.02em}",".owcb:hover .owcb-chip{margin-left:-2px}",".owcb:hover .owcb-chip:first-child{margin-left:0}",".owcb-label{white-space:nowrap}",`.owcb-arrow{opacity:.5;transition:transform .2s ${l},opacity .2s ${l}}`,".owcb:hover .owcb-arrow{transform:translateX(2px);opacity:.8}",".owcb-spinner{width:16px;height:16px;border-radius:50%;border:2px solid currentColor;border-top-color:transparent;opacity:.7;animation:owcb-spin .7s linear infinite}","@keyframes owcb-spin{to{transform:rotate(360deg)}}",".owcb.owcb-block{display:flex;flex-direction:column;align-items:stretch;width:100%;max-width:420px;text-align:left;padding:16px;border-radius:14px;gap:0}",".owcb-block-top{display:flex;align-items:center;justify-content:space-between;gap:12px}",".owcb-block-title{font-size:15px;font-weight:600;letter-spacing:-.01em}",".owcb-block-sub{font-size:13px;line-height:1.5;margin-top:6px;font-weight:400}",".owcb-block-foot{margin-top:14px;padding-top:12px;display:flex;align-items:center;gap:6px;font-size:11.5px;font-weight:400}","@media (prefers-reduced-motion:reduce){.owcb,.owcb-chip,.owcb-arrow{transition:none}.owcb-spinner{animation-duration:1.4s}}"].join("\n"),document.head.appendChild(e)}();const i="dark"===t.theme?a:s,m=null!==(n=t.variant)&&void 0!==n?n:"default",f=null!==(o=t.label)&&void 0!==o?o:"Connect your apps";let b="idle",w=!1;const v=r({...t.connect,onSuccess:()=>{var e,n;y("connected"),null===(e=(n=t.connect).onSuccess)||void 0===e||e.call(n)},onError:e=>{var n,o;y("idle"),null===(n=(o=t.connect).onError)||void 0===n||n.call(o,e)},onClose:()=>{var e,n;y("idle"),null===(e=(n=t.connect).onClose)||void 0===e||e.call(n)}}),g=document.createElement("button");g.type="button",g.className="block"===m?"owcb owcb-block":"owcb",g.addEventListener("click",()=>{"idle"!==b&&"connected"!==b||(y("connecting"),v.open())});const x=()=>{var e,n,o;const r="accent"===m,c="block"===m,l=c?i.surface:r?null!==(e=t.accentColor)&&void 0!==e?e:d:i.btnBg,s=c?i.fg:r?p:i.btnFg,a=c?i.surface:l,w=p;g.style.background="connected"!==b||c?l:u,g.style.color="connected"!==b||c?s:p,g.style.boxShadow=c?`inset 0 0 0 1px ${i.line}`:"connected"===b?"none":r?`0 1px 2px rgba(10,12,11,.1), 0 6px 20px ${null!==(n=t.accentColor)&&void 0!==n?n:d}38`:i.shadow,g.disabled="connecting"===b,g.innerHTML="";const v=function(e,t,n){var o,i;const r=null!==(o=e.platforms)&&void 0!==o?o:[];if(0===r.length&&!e.moreCount)return null;const c=document.createElement("span");c.className="owcb-stack",c.setAttribute("aria-hidden","true");for(const e of r.slice(0,3)){var l;const n=document.createElement("span");n.className="owcb-chip",n.style.background="#ffffff",n.style.boxShadow=`0 0 0 1.5px ${t}`;const o=()=>{n.textContent=e.name.charAt(0).toUpperCase(),n.style.font="600 10px ui-monospace,monospace",n.style.color=p},i=null!==(l=e.imageUrl)&&void 0!==l?l:h(e.name);if(i){const e=document.createElement("img");e.alt="",e.src=i,e.addEventListener("error",()=>{e.remove(),o()}),n.appendChild(e)}else o();c.appendChild(n)}const s=(null!==(i=e.moreCount)&&void 0!==i?i:0)+Math.max(0,r.length-3);if(s>0){const e=document.createElement("span");e.className="owcb-chip owcb-more",e.style.background="#ffffff",e.style.boxShadow=`0 0 0 1.5px ${t}`,e.style.color=n,e.textContent=`+${s}`,c.appendChild(e)}return c}(t,a,w);if(c){var x;const e=document.createElement("span");e.className="owcb-block-top";const n=document.createElement("span");if(n.className="owcb-block-title",n.textContent="connecting"===b?"Connecting…":"connected"===b?null!==(x=t.connectedLabel)&&void 0!==x?x:"Connected":f,e.appendChild(n),"connecting"===b){const t=document.createElement("span");t.className="owcb-spinner",e.appendChild(t)}else v&&e.appendChild(v);if(g.appendChild(e),t.description&&"idle"===b){const e=document.createElement("span");e.className="owcb-block-sub",e.style.color=i.muted,e.textContent=t.description,g.appendChild(e)}const o=document.createElement("span");return o.className="owcb-block-foot",o.style.color=i.muted,o.style.borderTop=`1px solid ${i.line}`,o.innerHTML=`<span style="font-size:11px;color:${i.muted}">Secured by</span><span style="display:inline-flex;color:${i.fg}"><svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2.4" style="flex-shrink:0"><circle cx="12" cy="12" r="8.5"/></svg></span><span style="font-size:12px;font-weight:600;letter-spacing:-0.02em;color:${i.fg}">one</span>`,void g.appendChild(o)}if("connecting"===b){const e=document.createElement("span");e.className="owcb-spinner",g.appendChild(e)}else if("connected"===b){const e=document.createElement("span");e.innerHTML='<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width:16px;height:16px"><path d="M3 8.5l3.5 3.5L13 5"/></svg>',e.style.display="inline-flex",g.appendChild(e)}else v&&g.appendChild(v);const y=document.createElement("span");if(y.className="owcb-label",y.textContent="connecting"===b?"Connecting…":"connected"===b?null!==(o=t.connectedLabel)&&void 0!==o?o:"Connected":f,g.appendChild(y),"idle"===b){const e=document.createElement("span");e.innerHTML='<svg class="owcb-arrow" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3l5 5-5 5"/></svg>',e.style.display="inline-flex",g.appendChild(e)}},y=e=>{w||(b=e,x())};return x(),e.appendChild(g),{setState:y,destroy:()=>{w=!0,v.close({keepResult:!0}),g.remove()}}};!function(){if("undefined"!=typeof window&&"undefined"!=typeof customElements&&!customElements.get("one-connect-button")){class e extends HTMLElement{constructor(...e){super(...e),t(this,"onSuccess",null),t(this,"onError",null),t(this,"onClose",null),t(this,"handle",null)}connectedCallback(){this.mount()}disconnectedCallback(){var e;null===(e=this.handle)||void 0===e||e.destroy(),this.handle=null}attributeChangedCallback(){this.isConnected&&this.handle&&this.mount()}mount(){var e,t,n,o,i,r,c,l;null===(e=this.handle)||void 0===e||e.destroy(),this.handle=null;const s=this.getAttribute("authorize-url");if(!s)return;let a;const d=this.getAttribute("platforms");if(d)try{const e=JSON.parse(d);Array.isArray(e)&&(a=e)}catch{}const u=this.getAttribute("more-count"),p=u?parseInt(u,10):void 0;this.handle=m(this,{connect:{authorize:{url:s},appTheme:null!==(t=this.getAttribute("app-theme"))&&void 0!==t?t:void 0,onSuccess:()=>{var e;null===(e=this.onSuccess)||void 0===e||e.call(this),this.dispatchEvent(new CustomEvent("success"))},onError:e=>{var t;null===(t=this.onError)||void 0===t||t.call(this,e),this.dispatchEvent(new CustomEvent("error",{detail:e}))},onClose:()=>{var e;null===(e=this.onClose)||void 0===e||e.call(this),this.dispatchEvent(new CustomEvent("close"))}},label:null!==(n=this.getAttribute("label"))&&void 0!==n?n:void 0,variant:null!==(o=this.getAttribute("variant"))&&void 0!==o?o:void 0,theme:null!==(i=this.getAttribute("theme"))&&void 0!==i?i:void 0,platforms:a,moreCount:Number.isFinite(p)?p:void 0,description:null!==(r=this.getAttribute("description"))&&void 0!==r?r:void 0,accentColor:null!==(c=this.getAttribute("accent-color"))&&void 0!==c?c:void 0,connectedLabel:null!==(l=this.getAttribute("connected-label"))&&void 0!==l?l:void 0})}}t(e,"observedAttributes",["authorize-url","app-theme","label","variant","theme","platforms","more-count","description","accent-color","connected-label"]),customElements.define("one-connect-button",e)}}(),exports.ConnectButton=function(t){var n;const o=e.useRef(null),i=e.useRef(null),r=e.useRef({onSuccess:t.onSuccess,onError:t.onError,onClose:t.onClose});r.current={onSuccess:t.onSuccess,onError:t.onError,onClose:t.onClose};const c=JSON.stringify(null!==(n=t.platforms)&&void 0!==n?n:[]);return e.useEffect(()=>{if(!o.current)return;const e={connect:{authorize:{url:t.authorizeUrl},appTheme:t.appTheme,onSuccess:()=>{var e,t;return null===(e=(t=r.current).onSuccess)||void 0===e?void 0:e.call(t)},onError:e=>{var t,n;return null===(t=(n=r.current).onError)||void 0===t?void 0:t.call(n,e)},onClose:()=>{var e,t;return null===(e=(t=r.current).onClose)||void 0===e?void 0:e.call(t)}},label:t.label,variant:t.variant,theme:t.theme,platforms:t.platforms,moreCount:t.moreCount,description:t.description,accentColor:t.accentColor,connectedLabel:t.connectedLabel};return i.current=m(o.current,e),()=>{var e;null===(e=i.current)||void 0===e||e.destroy(),i.current=null}},[t.authorizeUrl,t.appTheme,t.label,t.variant,t.theme,c,t.moreCount,t.description,t.accentColor,t.connectedLabel]),e.createElement("div",{ref:o,className:t.className,style:t.style})};
|
|
1
|
+
"use strict";var r=require("react"),e=require("@withone/connect");exports.ConnectButton=function(n){const o=r.useRef(null),t=r.useRef(null),c=r.useRef({onSuccess:n.onSuccess,onError:n.onError});c.current={onSuccess:n.onSuccess,onError:n.onError};const u=e.propsIdentity(n);return r.useEffect(()=>{if(o.current)return t.current=e.mountConnectButton(o.current,e.optionsFromProps(n,{onSuccess:()=>{var r,e;return null===(r=(e=c.current).onSuccess)||void 0===r?void 0:r.call(e)},onError:r=>{var e,n;return null===(e=(n=c.current).onError)||void 0===e?void 0:e.call(n,r)}})),()=>{var r;null===(r=t.current)||void 0===r||r.destroy(),t.current=null}},[u]),r.createElement("div",{ref:o,className:n.className,style:n.style})};
|