@freedam/picker 0.0.0-stage → 1.2.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/CHANGELOG.md ADDED
@@ -0,0 +1,82 @@
1
+ # Changelog
2
+
3
+ Changes to `@freedam/picker`, newest first. The package follows SemVer: a
4
+ major version changes the JavaScript API or the `postMessage` protocol
5
+ incompatibly, or removes a payload field; a minor version adds an option, an
6
+ event or a payload field; a patch fixes the rest. A deprecation is announced
7
+ here six months before the release that removes it.
8
+
9
+ Each version is also served by every Freedam host at
10
+ `https://{workspace}/sdk/picker/{version}/picker.js`. The integrity value of
11
+ an entry is the `integrity` attribute for that URL, used with
12
+ `crossorigin="anonymous"`.
13
+
14
+ ## 1.2.0 (2026-11-08)
15
+
16
+ First version published on npm. Versions 1.0.0 and 1.1.0 were served by
17
+ Freedam hosts only.
18
+
19
+ Integrity: `sha384-NngTI5clKCwu+PbhM6M3EDuOWhcywXV3y8qOJ1DrH7cAs8HfCoJgSdeMCuO8rgo/`
20
+
21
+ - New payload field `widths`: the widths, in pixels, that `url_template`
22
+ serves with `w=`, smallest first. They are the channel's widths up to the
23
+ width of the original, so a `srcset` built from them never asks for a
24
+ width the channel answers with 400.
25
+ - New option `types` (`'image'`, `'video'`, `'document'`), sent as the
26
+ `types` parameter and read from the `types` attribute of
27
+ `<freedam-picker>`: the picker offers only these types among the
28
+ integration's own. A type the integration does not offer is ignored.
29
+ - `mode: 'tab'` opens the picker in a new tab of the browser, with
30
+ `window.open()` and no window features. It works as the popup does: the
31
+ picker posts to `window.opener`, closes after an insertion, and a tab
32
+ closed without inserting resolves the promise with `null`.
33
+
34
+ ## 1.1.0 (not published on npm)
35
+
36
+ Integrity: `sha384-+YgSwNjdAmJuXKbGTClOVNARH6rbYHhliSwyWOB+ZhwjX59LSMuSwnQR7smcmt3I`
37
+
38
+ - `mode: 'modal'` shows the picker in an iframe over the page, full screen
39
+ below 640 pixels wide, closed by its close button (or the Escape key
40
+ while the focus is outside the picker's iframe), with the focus kept
41
+ inside it.
42
+ - `mode: 'inline'` shows the picker in an iframe inside the new `container`
43
+ option, at least 480 pixels high.
44
+ - In both modes, when the iframe cannot sign in (`auth_required`) or the
45
+ picker page sends nothing within 15 seconds, the iframe gives way to an
46
+ "Open Freedam" button that opens the picker in a window with the same
47
+ options; the promise settles with the outcome of that window.
48
+ - `<freedam-picker>` reads the `mode` and `container` attributes and has a
49
+ `container` property.
50
+ - `guest_access_unavailable` no longer rejects the promise: the picker still
51
+ offers to sign in, so the promise waits for the outcome, as after
52
+ `insert_failed`.
53
+ - Protocol version 1 gains the `sign_in` and `resize` messages from the
54
+ picker and the `close` message to the picker's iframe. Receivers ignore
55
+ message types they do not know, so version 1.0.0 is not affected.
56
+
57
+ ## 1.0.0 (not published on npm)
58
+
59
+ Integrity: `sha384-SYiykeNpX3DaSiYEV98NDoh7sCNYAAr4FhiOMzT+ySGecEkyxIHqFhTva4C5RAH4`
60
+
61
+ First release.
62
+
63
+ - `open(options)` opens the Freedam picker of a workspace integration in a
64
+ window on the workspace host and resolves with the inserted assets, or
65
+ `null` when the person cancels or closes the window. Callbacks `onReady`,
66
+ `onSelect`, `onCancel`, `onError` and `onClose`.
67
+ - Options: `workspace`, `integration`, `select` (`single` or `multiple`),
68
+ `max` (1 to 50), `q`, `filters` (rule tree of the Freedam API), `sort`,
69
+ `preselected` (GAIDs), `locale` (`en`, `fr`, `de`, `es`, `pt-BR`, `zh-CN`),
70
+ `theme` (`light`, `dark`, `auto`) and `mode` (`popup`).
71
+ - `FreedamPickerError` with a `code`: `origin_denied`, `feature_unavailable`,
72
+ `integration_suspended`, `integration_unavailable`, `insert_failed`,
73
+ `popup_blocked`, `invalid_options`.
74
+ - `<freedam-picker>` web component, defined by the script-tag build and by
75
+ `import '@freedam/picker/element'`, with the events `freedam-ready`,
76
+ `freedam-select`, `freedam-cancel`, `freedam-error` and `freedam-close`.
77
+ - Script-tag build that adds `window.Freedam.picker` and keeps an existing
78
+ `window.Freedam` object.
79
+ - Payload of image, video and document assets, described by the JSON Schema
80
+ in `schema/payload.schema.json` (`@freedam/picker/schema.json`), also served
81
+ at `https://{workspace}/sdk/picker/schema/v1/payload.schema.json`.
82
+ - `postMessage` protocol version 1.
package/README.md CHANGED
@@ -1,3 +1,123 @@
1
- # Temporary Holding Version
1
+ # @freedam/picker
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Let people choose assets from a [Freedam](https://freedam.io) workspace inside your own application. A click opens the Freedam picker in a window on the workspace host, over your page or inside it; the person searches, chooses and inserts, and your page receives each asset with ready-to-use URLs, its focus point and the metadata fields the integration exposes.
4
+
5
+ No runtime dependency, a few kilobytes, TypeScript types included.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @freedam/picker
11
+ ```
12
+
13
+ Or load the script from the workspace host, which adds `window.Freedam.picker`:
14
+
15
+ ```html
16
+ <script src="https://acme.freedam.io/sdk/picker/v1/picker.js"></script>
17
+ ```
18
+
19
+ `v1/` is the latest 1.x release. To pin an exact version and check its integrity, use the version's URL with the `integrity` value listed for that version in `CHANGELOG.md` (shipped in the package):
20
+
21
+ ```html
22
+ <script
23
+ src="https://acme.freedam.io/sdk/picker/1.1.0/picker.js"
24
+ integrity="sha384-…"
25
+ crossorigin="anonymous"
26
+ ></script>
27
+ ```
28
+
29
+ ## Use
30
+
31
+ A workspace administrator creates an integration and adds your page's origin to it. Then:
32
+
33
+ ```ts
34
+ import { open } from '@freedam/picker';
35
+
36
+ button.addEventListener('click', async () => {
37
+ // No await before open(): browsers allow the window only during the click.
38
+ const assets = await open({
39
+ workspace: 'acme.freedam.io',
40
+ integration: 'int_8f3k2',
41
+ select: 'multiple',
42
+ max: 5,
43
+ });
44
+
45
+ if (!assets) {
46
+ return; // The person cancelled or closed the window.
47
+ }
48
+
49
+ for (const asset of assets) {
50
+ console.log(asset.gaid, asset.url, asset.metadata.alt);
51
+ }
52
+ });
53
+ ```
54
+
55
+ `open()` resolves with the inserted assets, or `null` when the person cancels. Errors are `FreedamPickerError` instances with a `code`: `origin_denied`, `feature_unavailable`, `integration_suspended`, `integration_unavailable`, `insert_failed`, `guest_access_unavailable`, `popup_blocked`, `invalid_options`. Callbacks (`onReady`, `onSelect`, `onCancel`, `onError`, `onClose`) are available as well.
56
+
57
+ People who are not signed in to the workspace sign in from the picker, in a second window; the picker window itself never leaves the workspace host.
58
+
59
+ ## Tab mode
60
+
61
+ `mode: 'tab'` opens the picker in a new tab of the browser instead of a popup window. It works the same way: the person signs in from it, and it closes after the insertion.
62
+
63
+ ## Modal and inline modes
64
+
65
+ ```ts
66
+ open({ workspace: 'acme.freedam.io', integration: 'int_8f3k2', mode: 'modal' });
67
+
68
+ open({ workspace: 'acme.freedam.io', integration: 'int_8f3k2', mode: 'inline', container: document.getElementById('picker') });
69
+ ```
70
+
71
+ `modal` shows the picker in an iframe over the page (full screen below 640 pixels wide); `inline` shows it in an iframe that fills `container`, at least 480 pixels high. The picker in the iframe has a session of its own, opened from a small sign-in window. When the browser refuses that session, or the picker page does not answer within 15 seconds, the iframe gives way to an **Open Freedam** button that continues in a window with the same options; the promise settles the same way. Allow the workspace host in your Content-Security-Policy's `frame-src`.
72
+
73
+ ## Web component
74
+
75
+ The script-tag build defines `<freedam-picker>`; with npm, `import '@freedam/picker/element'` defines it. A click inside the element opens the picker with its attributes:
76
+
77
+ ```html
78
+ <freedam-picker workspace="acme.freedam.io" integration="int_8f3k2" select="multiple" max="5">
79
+ <button type="button">Insert from Freedam</button>
80
+ </freedam-picker>
81
+ ```
82
+
83
+ Attributes: `workspace`, `integration`, `public-key`, `select`, `max`, `q`, `sort-by`, `sort-direction`, `locale`, `theme`, `mode`, `container` (the `id` of the element that receives the picker with `mode="inline"`), `filters` (JSON), `preselected` (comma-separated GAIDs) and `types` (comma-separated asset types); `filters`, `preselected` and `container` are also properties that take an object, an array and an element. The element dispatches `freedam-ready`, `freedam-select` (`event.detail.assets`), `freedam-cancel`, `freedam-error` (`event.detail.error`) and `freedam-close`, which bubble out of shadow roots. `element.open()` opens the picker from your own click handler and returns the same promise as `open()`.
84
+
85
+ ## Payload
86
+
87
+ Each asset is an image, a video or a document. Its JSON Schema ships with the package:
88
+
89
+ ```ts
90
+ import schema from '@freedam/picker/schema.json';
91
+ ```
92
+
93
+ Every workspace host also serves it at `https://acme.freedam.io/sdk/picker/schema/v1/payload.schema.json`.
94
+
95
+ `url_template` contains `{options}` in place of the image options: replace it with `w=800`, `w=800,h=600` (cropped around the focus point), `fmt=hero` or `f=webp` to get any size of the asset's image without calling Freedam. `widths` lists the widths the channel serves for that asset, smallest first: build a `srcset` from it.
96
+
97
+ ## Documentation
98
+
99
+ - Quickstart: https://freedam.io/docs/api-picker-quickstart
100
+ - Reference (options, events, errors, payload, protocol): https://freedam.io/docs/api-picker-reference
101
+
102
+ ## Development
103
+
104
+ Commands run in the Freedam dev container, from the repository root:
105
+
106
+ ```bash
107
+ bin/dc npm --prefix sdk/picker ci
108
+ bin/dc npm --prefix sdk/picker run typecheck
109
+ bin/dc npm --prefix sdk/picker test
110
+ bin/dc npm --prefix sdk/picker run build
111
+ bin/dc npm --prefix sdk/picker run size
112
+ bin/dc npm --prefix sdk/picker run verify
113
+ ```
114
+
115
+ `schema/payload.schema.json` and `src/payload.ts` are both written by hand; the tests check typed examples of each asset type against the schema, so change them together.
116
+
117
+ `npm run verify` loads `dist/picker.global.js` in a minimal page stand-in and checks that it adds `window.Freedam.picker` with the package version and defines `<freedam-picker>`: the tests import the sources and do not cover what the bundler keeps in that file.
118
+
119
+ Releases (npm, and the files served under `public/sdk/picker/` by `npm run publish:cdn`): `docs/ops/picker-release.md`.
120
+
121
+ ## License
122
+
123
+ MIT
@@ -0,0 +1,2 @@
1
+ var ie=["origin_denied","feature_unavailable","integration_suspended","integration_unavailable","insert_failed","auth_required","guest_access_unavailable"],Se=["popup_blocked","invalid_options"],U={origin_denied:"This page is not allowed to open the picker: the integration does not exist or does not list this origin.",feature_unavailable:"The asset picker is not available on this workspace.",integration_suspended:"This integration is suspended.",integration_unavailable:"This integration cannot be used: its profile or publication channel is missing or disabled.",insert_failed:"The selected assets could not be inserted.",auth_required:"The picker cannot run in an iframe of this page: the person continues in a separate window.",guest_access_unavailable:"This integration does not allow access without an account.",popup_blocked:"The browser blocked the picker window. Call open() from a click handler.",invalid_options:"Invalid picker options."},z=["insert_failed","guest_access_unavailable"];function W(e){return ie.includes(e)}var h=class extends Error{constructor(t,r){super(r===void 0?U[t]:`${U[t]} ${r}`),this.name="FreedamPickerError",this.code=t}};var C=1,v="freedam-picker",B="/picker/",A=50;var G=["popup","modal","inline","tab"],O=480;var I=["image","video","document"],q=["single","multiple"],R=["en","fr","de","es","pt-BR","zh-CN"],j=["light","dark","auto"],H=["created_at","updated_at","title","original_filename","size","relevance"],V=["asc","desc"];var se=["onReady","onSelect","onCancel","onError","onClose"],ae=/^fdpk_[A-Za-z0-9]{32}$/,ce=/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*(?::\d{1,5})?$/i;function s(e){return new h("invalid_options",e)}function x(e,t){return e.includes(t)}function F(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function le(e){return typeof HTMLElement<"u"&&e instanceof HTMLElement}function J(e){if(!F(e))throw s("open() expects an options object.");if(typeof e.workspace!="string"||!ce.test(e.workspace)||!de(e.workspace))throw s('`workspace` must be the host of the workspace, without scheme or path, e.g. "acme.example.com".');if(typeof e.integration!="string"||!/^\S+$/.test(e.integration))throw s("`integration` must be the key of the integration, without spaces.");if(e.publicKey!==void 0&&(typeof e.publicKey!="string"||!ae.test(e.publicKey)))throw s('`publicKey` must be the key of the access without an account: "fdpk_" followed by 32 letters and digits.');if(e.select!==void 0&&!x(q,e.select))throw s('`select` must be "single" or "multiple".');if(e.max!==void 0){if(e.select!=="multiple")throw s('`max` requires `select: "multiple"`.');if(typeof e.max!="number"||!Number.isInteger(e.max)||e.max<1||e.max>50)throw s(`\`max\` must be an integer from 1 to ${50}.`)}if(e.q!==void 0&&(typeof e.q!="string"||e.q.length>500))throw s(`\`q\` must be a string of ${500} characters at most.`);if(e.filters!==void 0){if(!F(e.filters))throw s("`filters` must be a filter or group object.");try{JSON.stringify(e.filters)}catch{throw s("`filters` must be serializable to JSON.")}}if(e.sort!==void 0){if(!F(e.sort)||!x(H,e.sort.by))throw s(`\`sort.by\` must be one of ${H.join(", ")}.`);if(e.sort.direction!==void 0&&!x(V,e.sort.direction))throw s('`sort.direction` must be "asc" or "desc".')}if(e.preselected!==void 0){let t=e.preselected;if(!Array.isArray(t)||!t.every(r=>typeof r=="string"&&r!==""&&!r.includes(",")))throw s("`preselected` must be an array of GAIDs.")}if(e.types!==void 0){let t=e.types;if(!Array.isArray(t)||t.length===0||!t.every(r=>x(I,r)))throw s(`\`types\` must be a non-empty array of ${I.join(", ")}.`)}if(e.locale!==void 0&&!x(R,e.locale))throw s(`\`locale\` must be one of ${R.join(", ")}.`);if(e.theme!==void 0&&!x(j,e.theme))throw s('`theme` must be "light", "dark" or "auto".');if(e.mode!==void 0&&!x(G,e.mode))throw s('`mode` must be "popup", "tab", "modal" or "inline".');if(e.mode==="inline"){if(!le(e.container)||!e.container.isConnected)throw s('`mode: "inline"` requires `container`, an element of the page.')}else if(e.container!==void 0)throw s('`container` requires `mode: "inline"`.');for(let t of se)if(e[t]!==void 0&&typeof e[t]!="function")throw s(`\`${t}\` must be a function.`)}function de(e){try{return L(e),!0}catch{return!1}}function L(e){return new URL(`https://${e}`).origin}function Q(e){if(!/^https?:\/\//.test(e))throw s("The host page must be served over HTTP or HTTPS.");return e}function Z(){let e=new Uint8Array(16);crypto.getRandomValues(e);let t="";for(let r of e)t+=String.fromCharCode(r);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function D(e,t,r,f=e.mode??"popup"){let c=new URL(`${B}${encodeURIComponent(e.integration)}`,L(e.workspace)),n=c.searchParams;n.set("protocol",String(1)),n.set("origin",t),n.set("channel",r),n.set("mode",f),n.set("select",e.select??"single"),e.max!==void 0&&n.set("max",String(e.max)),e.publicKey!==void 0&&n.set("public_key",e.publicKey),e.q!==void 0&&e.q!==""&&n.set("q",e.q),e.filters!==void 0&&n.set("filters",JSON.stringify(e.filters)),e.sort!==void 0&&(n.set("sort_by",e.sort.by),e.sort.direction!==void 0&&n.set("sort_direction",e.sort.direction)),e.preselected!==void 0&&e.preselected.length>0&&n.set("preselected",e.preselected.join(",")),e.types!==void 0&&n.set("types",[...new Set(e.types)].join(",")),e.locale!==void 0&&n.set("locale",e.locale),e.theme!==void 0&&n.set("theme",e.theme);let o=c.toString();if(o.length>6e3)throw s(`The picker URL would exceed ${6e3} characters: shorten \`filters\`, \`q\` or \`preselected\`.`);return o}var fe=1100,pe=760,me=1e4,ge="2147483000",ye={en:{message:"Freedam cannot be shown in this page. Continue in a separate window.",open:"Open Freedam",cancel:"Cancel",close:"Close"},fr:{message:"Freedam ne peut pas s\u2019afficher dans cette page. Continuez dans une fen\xEAtre s\xE9par\xE9e.",open:"Ouvrir Freedam",cancel:"Annuler",close:"Fermer"},de:{message:"Freedam kann auf dieser Seite nicht angezeigt werden. Fahren Sie in einem separaten Fenster fort.",open:"Freedam \xF6ffnen",cancel:"Abbrechen",close:"Schlie\xDFen"},es:{message:"Freedam no se puede mostrar en esta p\xE1gina. Contin\xFAe en una ventana aparte.",open:"Abrir Freedam",cancel:"Cancelar",close:"Cerrar"},"pt-BR":{message:"O Freedam n\xE3o pode ser exibido nesta p\xE1gina. Continue em uma janela separada.",open:"Abrir o Freedam",cancel:"Cancelar",close:"Fechar"},"zh-CN":{message:"\u65E0\u6CD5\u5728\u6B64\u9875\u9762\u4E2D\u663E\u793A Freedam\u3002\u8BF7\u5728\u5355\u72EC\u7684\u7A97\u53E3\u4E2D\u7EE7\u7EED\u3002",open:"\u6253\u5F00 Freedam",cancel:"\u53D6\u6D88",close:"\u5173\u95ED"}};function ke(e){let t=[e,document.documentElement.lang,typeof navigator>"u"?void 0:navigator.language];for(let r of t){if(typeof r!="string"||r==="")continue;let f=R.find(o=>o.toLowerCase()===r.toLowerCase());if(f!==void 0)return f;let c=r.split("-")[0].toLowerCase(),n=R.find(o=>o.split("-")[0]===c);if(n!==void 0)return n}return"en"}function E(e,t={}){let r=document.createElement(e);return Object.assign(r.style,t),r}function ee(e,t){let r=E("button",{font:"inherit",fontWeight:"600",padding:"10px 18px",borderRadius:"8px",cursor:"pointer",border:t?"1px solid #111827":"1px solid #d1d5db",background:t?"#111827":"#ffffff",color:t?"#ffffff":"#111827"});return r.type="button",r.textContent=e,r}function te(e){let t=ye[ke(e.locale)],r=document.activeElement instanceof HTMLElement?document.activeElement:null,f=[],c=!1,n=E("iframe",{display:"block",width:"100%",height:"100%",border:"0",background:"#ffffff"});n.src=e.url,n.name=`freedam-picker-${e.channel}`,n.title="Freedam",n.setAttribute("data-freedam-picker",e.mode);let o,a;if(e.mode==="modal"){o=E("div",{position:"fixed",top:"0",right:"0",bottom:"0",left:"0",zIndex:ge,display:"flex",alignItems:"center",justifyContent:"center",boxSizing:"border-box",background:"rgba(17, 24, 39, 0.6)"}),o.setAttribute("role","dialog"),o.setAttribute("aria-modal","true"),o.setAttribute("aria-label","Freedam"),o.setAttribute("data-freedam-picker-overlay",""),a=E("div",{position:"relative",width:"100%",height:"100%",overflow:"hidden",background:"#ffffff",boxShadow:"0 24px 48px rgba(0, 0, 0, 0.3)"});let l=E("button",{position:"absolute",top:"6px",right:"8px",width:"32px",height:"32px",padding:"0",border:"0",borderRadius:"16px",background:"transparent",color:"#ffffff",fontSize:"24px",lineHeight:"32px",cursor:"pointer"});l.type="button",l.textContent="\xD7",l.setAttribute("aria-label",t.close),l.setAttribute("data-freedam-picker-close",""),l.addEventListener("click",()=>e.onDismiss()),o.append(a,l);let i=typeof window.matchMedia=="function"?window.matchMedia(`(max-width: ${640-.02}px)`):null,p=()=>{let u=i?.matches===!0;Object.assign(o.style,{padding:u?"44px 0 0":"48px 24px 24px"}),Object.assign(a.style,{maxWidth:u?"none":`${fe}px`,maxHeight:u?"none":`${pe}px`,borderRadius:u?"0":"12px"})};p(),i!==null&&(i.addEventListener("change",p),f.push(()=>i.removeEventListener("change",p)));let d=u=>{if(u.key==="Escape"){e.onDismiss();return}if(u.key!=="Tab")return;let w=Array.from(o.querySelectorAll("button, iframe")),y=w[0],_=w[w.length-1],T=document.activeElement;y===void 0||_===void 0||(!(T instanceof Node)||!o.contains(T)?(u.preventDefault(),y.focus()):u.shiftKey&&T===y?(u.preventDefault(),_.focus()):!u.shiftKey&&T===_&&(u.preventDefault(),y.focus()))};document.addEventListener("keydown",d),f.push(()=>document.removeEventListener("keydown",d));let g=document.documentElement,M=g.style.overflow;g.style.overflow="hidden",f.push(()=>{g.style.overflow=M}),a.append(n),document.body.append(o)}else o=E("div",{display:"block",width:"100%",height:"100%",minHeight:`${480}px`}),o.setAttribute("data-freedam-picker-inline",""),a=o,n.style.minHeight=`${480}px`,a.append(n),e.container.append(o);e.mode==="modal"&&n.focus();let b=()=>a.querySelector("[data-freedam-picker-open]");return{mode:e.mode,target:()=>n.isConnected?n.contentWindow:null,isClosed:()=>c||!o.isConnected,focus:()=>(b()??n).focus(),close:(l=!0)=>{if(c)return;c=!0;let i=n.isConnected?n.contentWindow:null;if(i!==null){let p={source:v,protocol:1,channel:e.channel,type:"close"};i.postMessage(p,e.origin)}o.remove();for(let p of f)p();l&&e.mode==="modal"&&r!==null&&r.isConnected&&r.focus()},showFallback:()=>{if(c||b()!==null)return;let l=E("div",{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"16px",boxSizing:"border-box",width:"100%",height:"100%",minHeight:e.mode==="inline"?`${480}px`:"0",padding:"24px",background:"#ffffff",color:"#111827",fontFamily:'system-ui, -apple-system, "Segoe UI", Roboto, sans-serif',fontSize:"15px",lineHeight:"1.5",textAlign:"center"});l.setAttribute("data-freedam-picker-fallback","");let i=E("p",{margin:"0",maxWidth:"420px"});i.textContent=t.message;let p=E("div",{display:"flex",flexWrap:"wrap",justifyContent:"center",gap:"8px"}),d=ee(t.open,!0);d.setAttribute("data-freedam-picker-open",""),d.addEventListener("click",()=>e.onOpenWindow());let g=ee(t.cancel,!1);g.setAttribute("data-freedam-picker-cancel",""),g.addEventListener("click",()=>e.onDismiss()),p.append(d,g),l.append(i,p),n.remove(),a.append(l),e.mode==="modal"&&d.focus()},resize:l=>{e.mode!=="inline"||!Number.isFinite(l)||(n.style.height=`${Math.round(Math.min(me,Math.max(480,l)))}px`,o.style.height="auto")}}}function N(e,t){let r=Math.min(1100,window.screen.availWidth||1100),f=Math.min(760,window.screen.availHeight||760),c=Math.round(window.screenX+(window.outerWidth-r)/2),n=Math.round(window.screenY+(window.outerHeight-f)/2);return ne(window.open(e,`freedam-picker-${t}`,`popup=yes,width=${r},height=${f},left=${c},top=${n}`))}function re(e,t){return ne(window.open(e,`freedam-picker-${t}`))}function ne(e){return e?{target:()=>e,isClosed:()=>e.closed,focus:()=>e.focus(),close:()=>e.close()}:null}var he=500,Ee=1e3,Pe=15e3,S=null;function be(){return navigator.userActivation?.isActive===!0}function P(e,...t){if(typeof e=="function")try{e(...t)}catch(r){setTimeout(()=>{throw r})}}function xe(e,t){if(typeof e!="object"||e===null)return!1;let r=e;return r.source===v&&r.protocol===1&&r.channel===t&&typeof r.type=="string"}function De(e){if(S!==null&&!S.surface().isClosed())return S.surface().focus(),S.promise;let t,r,f,c;try{J(e),f=L(e.workspace),c=Z();let i=Q(window.location.origin);t=D(e,i,c),r=D(e,i,c,"popup")}catch(i){if(!(i instanceof h))throw i;return P(e?.onError,i),Promise.reject(i)}let n=e.mode??"popup",o,a=null,b={dismiss:()=>{},openWindow:()=>{}};if(n==="popup"||n==="tab"){let i=n==="tab"?re(t,c):N(t,c);if(i===null){let p=new h("popup_blocked");return P(e.onError,p),Promise.reject(p)}o=i}else a=te({url:t,channel:c,origin:f,mode:n,container:e.container,locale:e.locale,onDismiss:()=>b.dismiss(),onOpenWindow:()=>b.openWindow()}),o=a;let l=new Promise((i,p)=>{let d=!1,g=!1,M,u,w=()=>{if(a!==null){a.close(),y();return}M=setTimeout(()=>{o.isClosed()||o.close()},Ee)},y=()=>{o.isClosed()&&(a?.close(),clearInterval(oe),clearTimeout(M),clearTimeout(u),window.removeEventListener("message",K),S?.promise===l&&(S=null),d||(d=!0,P(e.onCancel),i(null)),P(e.onClose))},_=()=>{if(a===null||d)return!1;let k=N(r,c);return k===null?!1:(clearTimeout(u),a.close(!1),a=null,o=k,!0)};b.dismiss=()=>{o.close(),y()},b.openWindow=()=>{if(!_()&&!d){d=!0;let k=new h("popup_blocked");P(e.onError,k),p(k),o.close(),y()}};let T=()=>{be()&&_()||a?.showFallback()},K=k=>{if(d||k.origin!==f||k.source!==o.target())return;let m=k.data;if(xe(m,c))switch(clearTimeout(u),m.type){case"ready":g||(g=!0,P(e.onReady));break;case"resize":typeof m.height=="number"&&a?.resize(m.height);break;case"select":if(!Array.isArray(m.assets))return;d=!0,P(e.onSelect,m.assets),i(m.assets),w();break;case"cancel":d=!0,P(e.onCancel),i(null),w();break;case"error":{if(!W(m.code))return;if(m.code==="auth_required"){T();return}let $=new h(m.code);P(e.onError,$),z.includes(m.code)||(d=!0,p($));break}}},oe=setInterval(y,he);a!==null&&(u=setTimeout(()=>{d||a?.showFallback()},Pe)),window.addEventListener("message",K)});return S={surface:()=>o,promise:l},l}export{ie as a,Se as b,U as c,h as d,C as e,A as f,G as g,O as h,I as i,R as j,j as k,H as l,V as m,De as n};
2
+ //# sourceMappingURL=chunk-SF2R2FAB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/protocol.ts","../src/options.ts","../src/frame.ts","../src/popup.ts","../src/open.ts"],"sourcesContent":["/**\n * Codes the picker page sends in an `error` message.\n *\n * Keep in sync with `App\\Enums\\PickerErrorCode`: `tests/Unit/Enums/PickerErrorCodeTest.php`\n * reads this list and fails when the two differ. `auth_required` belongs to\n * the iframe modes and `guest_access_unavailable` to the access without an\n * account (version 1.1); the picker never sends `auth_required` in a popup.\n */\nexport const SERVER_ERROR_CODES = [\n 'origin_denied',\n 'feature_unavailable',\n 'integration_suspended',\n 'integration_unavailable',\n 'insert_failed',\n 'auth_required',\n 'guest_access_unavailable',\n] as const;\n\n/** Codes the SDK raises itself, without the picker page. */\nexport const SDK_ERROR_CODES = ['popup_blocked', 'invalid_options'] as const;\n\nexport type PickerServerErrorCode = (typeof SERVER_ERROR_CODES)[number];\n\nexport type PickerSdkErrorCode = (typeof SDK_ERROR_CODES)[number];\n\nexport type PickerErrorCode = PickerServerErrorCode | PickerSdkErrorCode;\n\n/**\n * English messages for the developer console. The picker page shows its own\n * translated text to the person using it.\n */\nexport const ERROR_MESSAGES: Record<PickerErrorCode, string> = {\n origin_denied:\n 'This page is not allowed to open the picker: the integration does not exist or does not list this origin.',\n feature_unavailable: 'The asset picker is not available on this workspace.',\n integration_suspended: 'This integration is suspended.',\n integration_unavailable:\n 'This integration cannot be used: its profile or publication channel is missing or disabled.',\n insert_failed: 'The selected assets could not be inserted.',\n auth_required: 'The picker cannot run in an iframe of this page: the person continues in a separate window.',\n guest_access_unavailable: 'This integration does not allow access without an account.',\n popup_blocked: 'The browser blocked the picker window. Call open() from a click handler.',\n invalid_options: 'Invalid picker options.',\n};\n\n/**\n * Errors after which the person can go on in the open picker: `open()`\n * reports them through `onError` and keeps its promise pending. After\n * `insert_failed` the person can insert again; after\n * `guest_access_unavailable` the picker still offers to sign in.\n */\nexport const RECOVERABLE_ERROR_CODES: readonly PickerServerErrorCode[] = ['insert_failed', 'guest_access_unavailable'];\n\nexport function isServerErrorCode(value: unknown): value is PickerServerErrorCode {\n return (SERVER_ERROR_CODES as readonly unknown[]).includes(value);\n}\n\n/** Error passed to `onError` and used to reject the promise of `open()`. */\nexport class FreedamPickerError extends Error {\n readonly code: PickerErrorCode;\n\n constructor(code: PickerErrorCode, detail?: string) {\n super(detail === undefined ? ERROR_MESSAGES[code] : `${ERROR_MESSAGES[code]} ${detail}`);\n this.name = 'FreedamPickerError';\n this.code = code;\n }\n}\n","/**\n * Protocol between the picker window (served on the workspace host) and the\n * host page that opened it.\n *\n * This file is the only definition of the protocol: the SDK imports it, and\n * the Freedam application imports it through the `@freedam/picker-protocol`\n * alias (tsconfig.json and vite.config.ts) for the picker page's side.\n *\n * The protocol version is independent of the SDK version. A receiver ignores\n * any message `type` it does not know, so adding a message is compatible.\n */\nimport type { PickerServerErrorCode } from './errors';\nimport type { PickerAsset, PickerAssetType } from './payload';\n\nexport const PROTOCOL_VERSION = 1;\n\nexport type PickerProtocolVersion = typeof PROTOCOL_VERSION;\n\n/** Value of `source` in every message, to discard other scripts' messages quickly. */\nexport const MESSAGE_SOURCE = 'freedam-picker';\n\n/** Path of the picker page on the workspace host, followed by the integration key. */\nexport const PICKER_PATH = '/picker/';\n\n/** Most assets one insertion can return. */\nexport const MAX_SELECTION = 50;\n\n/** Longest search text, as for `q` in `GET /api/v1/assets`. */\nexport const QUERY_MAX_LENGTH = 500;\n\n/** Longest opening URL: nginx answers 414 past its header buffers. */\nexport const OPEN_URL_MAX_LENGTH = 6000;\n\nexport const PICKER_MODES = ['popup', 'modal', 'inline', 'tab'] as const;\n\n/**\n * How the picker opens: in a popup window on the workspace host (`popup`),\n * in an iframe over the host page (`modal`, version 1.1), in an iframe\n * inside an element of the host page (`inline`, version 1.1) or in a new\n * tab of the browser (`tab`, version 1.2).\n */\nexport type PickerMode = (typeof PICKER_MODES)[number];\n\n/** Modes that show the picker in a window of its own, which posts to `window.opener`. */\nexport type PickerWindowMode = Extract<PickerMode, 'popup' | 'tab'>;\n\n/** Modes that show the picker in an iframe of the host page. */\nexport type PickerFrameMode = Exclude<PickerMode, PickerWindowMode>;\n\n/** Smallest height of the inline iframe, in CSS pixels. */\nexport const INLINE_MIN_HEIGHT = 480;\n\n/** Below this viewport width, in CSS pixels, the modal fills the screen. */\nexport const MODAL_FULL_SCREEN_BELOW = 640;\n\n/** Values of the `types` option (version 1.2): the payload's asset types. */\nexport const PICKER_ASSET_TYPES = ['image', 'video', 'document'] as const satisfies readonly PickerAssetType[];\n\nexport const SELECT_MODES = ['single', 'multiple'] as const;\n\nexport type PickerSelectMode = (typeof SELECT_MODES)[number];\n\n/** Interface languages of Freedam. */\nexport const PICKER_LOCALES = ['en', 'fr', 'de', 'es', 'pt-BR', 'zh-CN'] as const;\n\nexport type PickerLocale = (typeof PICKER_LOCALES)[number];\n\nexport const PICKER_THEMES = ['light', 'dark', 'auto'] as const;\n\nexport type PickerTheme = (typeof PICKER_THEMES)[number];\n\n/** Sort fields, as for `sort_by` in `GET /api/v1/assets`. */\nexport const SORT_FIELDS = ['created_at', 'updated_at', 'title', 'original_filename', 'size', 'relevance'] as const;\n\nexport type SortField = (typeof SORT_FIELDS)[number];\n\nexport const SORT_DIRECTIONS = ['asc', 'desc'] as const;\n\nexport type SortDirection = (typeof SORT_DIRECTIONS)[number];\n\n/**\n * One condition of a filter tree, as for `filters` in `GET /api/v1/assets`,\n * e.g. `{ type: 'filter', field: 'asset.file_category', operator: 'equals', value: 'Image' }`.\n * The server validates fields, operators and values.\n */\nexport interface RuleFilter {\n type: 'filter';\n field: string;\n operator: string;\n value?: unknown;\n}\n\nexport interface RuleGroup {\n type: 'group';\n operator: 'and' | 'or';\n rules: RuleTree[];\n}\n\nexport type RuleTree = RuleFilter | RuleGroup;\n\n/**\n * Query parameters of the opening URL `https://{workspace}/picker/{integration}`.\n * None of them is a secret. The picker page keeps them for the whole session\n * of its window, including the reload after the person signs in.\n */\nexport interface PickerOpenQuery {\n protocol: `${PickerProtocolVersion}`;\n /** Origin of the host page, checked by the server against the integration's origins. */\n origin: string;\n /** Random nonce, 22 base64url characters, repeated in every message. */\n channel: string;\n /** The server also reads it to start the iframe's own session (`modal`, `inline`). */\n mode: PickerMode;\n select: PickerSelectMode;\n /** 1 to MAX_SELECTION, only with `select=multiple`. */\n max?: string;\n q?: string;\n /** RuleTree as JSON. */\n filters?: string;\n sort_by?: SortField;\n sort_direction?: SortDirection;\n /** Comma-separated GAIDs; the picker ignores those the person cannot see. */\n preselected?: string;\n /**\n * Comma-separated asset types, version 1.2. The picker offers only these\n * among the integration's own types; a type the integration does not\n * offer is ignored.\n */\n types?: string;\n /** Key of the integration's access without an account (`fdpk_…`), version 1.1. */\n public_key?: string;\n locale?: PickerLocale;\n theme?: PickerTheme;\n}\n\n/** Fields of every message. */\nexport interface PickerMessageBase {\n source: typeof MESSAGE_SOURCE;\n protocol: PickerProtocolVersion;\n channel: string;\n}\n\n/** The picker page is interactive. Sent on every page load, including after sign-in. */\nexport interface PickerReadyMessage extends PickerMessageBase {\n type: 'ready';\n integration: string;\n}\n\n/** The insertion succeeded; the picker window closes next. */\nexport interface PickerSelectMessage extends PickerMessageBase {\n type: 'select';\n assets: PickerAsset[];\n}\n\n/** The person pressed Cancel; the picker window closes next. */\nexport interface PickerCancelMessage extends PickerMessageBase {\n type: 'cancel';\n}\n\n/**\n * The picker in an iframe shows its sign-in screen (version 1.1): the page\n * loaded and waits for the person, and `ready` follows once they have\n * signed in or continued without an account.\n */\nexport interface PickerSignInMessage extends PickerMessageBase {\n type: 'sign_in';\n}\n\n/**\n * Height the picker's content needs, in CSS pixels (version 1.1). The SDK\n * applies it to the inline iframe, never below INLINE_MIN_HEIGHT, and\n * ignores it in the other modes.\n */\nexport interface PickerResizeMessage extends PickerMessageBase {\n type: 'resize';\n height: number;\n}\n\n/** An error the picker page also shows to the person; the window stays open. */\nexport interface PickerErrorMessage extends PickerMessageBase {\n type: 'error';\n code: PickerServerErrorCode;\n}\n\nexport type PickerToHostMessage =\n | PickerReadyMessage\n | PickerSelectMessage\n | PickerCancelMessage\n | PickerErrorMessage\n | PickerSignInMessage\n | PickerResizeMessage;\n\nexport type PickerToHostMessageType = PickerToHostMessage['type'];\n\n/**\n * The host page removes the picker's iframe (version 1.1): sent by the SDK\n * to the iframe, with the workspace origin as `targetOrigin`, just before it\n * removes it after an insertion or a cancellation, or when the person\n * closes the modal. The picker page does not answer it.\n */\nexport interface HostCloseMessage extends PickerMessageBase {\n type: 'close';\n}\n\n/** Messages of the host page to the picker; only the iframe modes send one. */\nexport type HostToPickerMessage = HostCloseMessage;\n\n/**\n * What the picker page needs to post to its host. Built by the server after\n * it has checked the origin, never read from the page URL in the browser.\n */\nexport interface PickerHostContext {\n /** Exact origin the host declared and the server accepted; always the `targetOrigin`. */\n origin: string;\n channel: string;\n protocol: PickerProtocolVersion;\n}\n","import { FreedamPickerError } from './errors';\nimport type { PickerAsset, PickerAssetType } from './payload';\nimport {\n MAX_SELECTION,\n OPEN_URL_MAX_LENGTH,\n PICKER_ASSET_TYPES,\n PICKER_LOCALES,\n PICKER_MODES,\n PICKER_PATH,\n PICKER_THEMES,\n PROTOCOL_VERSION,\n QUERY_MAX_LENGTH,\n SELECT_MODES,\n SORT_DIRECTIONS,\n SORT_FIELDS,\n type PickerLocale,\n type PickerMode,\n type PickerSelectMode,\n type PickerTheme,\n type RuleTree,\n type SortDirection,\n type SortField,\n} from './protocol';\n\nexport interface PickerOptions {\n /** Host of the Freedam workspace, without scheme or path: `acme.example.com`. HTTPS is always used. */\n workspace: string;\n /** Public key of the integration, shown in the workspace's integration settings. */\n integration: string;\n /**\n * Key of the integration's access without a Freedam account (`fdpk_…`),\n * shown in the integration's settings when the access is on. With it,\n * visitors without an account can browse and insert the integration's\n * assets. Not a secret.\n */\n publicKey?: string;\n /** Default `single`. */\n select?: PickerSelectMode;\n /** Most assets the person can choose, 1 to 50, with `select: 'multiple'`. */\n max?: number;\n /** Initial search text, 500 characters at most. */\n q?: string;\n /** Initial filters, applied on top of the integration's own rules. */\n filters?: RuleTree;\n sort?: { by: SortField; direction?: SortDirection };\n /** GAIDs selected when the picker opens; GAIDs the person cannot see are ignored. */\n preselected?: string[];\n /**\n * Asset types the picker offers, among the integration's own: `['image']`\n * for an image field. A type the integration does not offer is ignored.\n * Default: every type of the integration.\n */\n types?: PickerAssetType[];\n /** Interface language; default: the person's own setting. */\n locale?: PickerLocale;\n theme?: PickerTheme;\n /**\n * Default `popup`: a window on the workspace host. `tab` opens it in a\n * new tab of the browser instead. `modal` shows the picker in an iframe\n * over the page (full screen below 640 pixels wide); `inline` shows it\n * in an iframe inside `container`. When the browser does not let the\n * iframe sign in, the SDK offers to continue in a window.\n */\n mode?: PickerMode;\n /** Element that receives the picker's iframe, required with `mode: 'inline'` and only then. */\n container?: HTMLElement;\n onReady?: () => void;\n onSelect?: (assets: PickerAsset[]) => void;\n onCancel?: () => void;\n onError?: (error: FreedamPickerError) => void;\n onClose?: () => void;\n}\n\nconst CALLBACKS = ['onReady', 'onSelect', 'onCancel', 'onError', 'onClose'] as const;\n\n/** `fdpk_` and 32 base-62 characters. */\nconst PUBLIC_KEY_PATTERN = /^fdpk_[A-Za-z0-9]{32}$/;\n\n/** Labels of host names, then an optional port. No scheme, path, user or query. */\nconst WORKSPACE_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)*(?::\\d{1,5})?$/i;\n\nfunction invalid(detail: string): FreedamPickerError {\n return new FreedamPickerError('invalid_options', detail);\n}\n\nfunction isOneOf<T extends string>(values: readonly T[], value: unknown): value is T {\n return (values as readonly unknown[]).includes(value);\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isElement(value: unknown): value is HTMLElement {\n return typeof HTMLElement !== 'undefined' && value instanceof HTMLElement;\n}\n\n/** Throws FreedamPickerError `invalid_options` naming the first invalid option. */\nexport function validateOptions(options: unknown): asserts options is PickerOptions {\n if (!isPlainObject(options)) {\n throw invalid('open() expects an options object.');\n }\n\n if (typeof options.workspace !== 'string' || !WORKSPACE_PATTERN.test(options.workspace) || !isValidHost(options.workspace)) {\n throw invalid('`workspace` must be the host of the workspace, without scheme or path, e.g. \"acme.example.com\".');\n }\n\n if (typeof options.integration !== 'string' || !/^\\S+$/.test(options.integration)) {\n throw invalid('`integration` must be the key of the integration, without spaces.');\n }\n\n if (options.publicKey !== undefined && (typeof options.publicKey !== 'string' || !PUBLIC_KEY_PATTERN.test(options.publicKey))) {\n throw invalid('`publicKey` must be the key of the access without an account: \"fdpk_\" followed by 32 letters and digits.');\n }\n\n if (options.select !== undefined && !isOneOf(SELECT_MODES, options.select)) {\n throw invalid('`select` must be \"single\" or \"multiple\".');\n }\n\n if (options.max !== undefined) {\n if (options.select !== 'multiple') {\n throw invalid('`max` requires `select: \"multiple\"`.');\n }\n if (typeof options.max !== 'number' || !Number.isInteger(options.max) || options.max < 1 || options.max > MAX_SELECTION) {\n throw invalid(`\\`max\\` must be an integer from 1 to ${MAX_SELECTION}.`);\n }\n }\n\n if (options.q !== undefined && (typeof options.q !== 'string' || options.q.length > QUERY_MAX_LENGTH)) {\n throw invalid(`\\`q\\` must be a string of ${QUERY_MAX_LENGTH} characters at most.`);\n }\n\n if (options.filters !== undefined) {\n if (!isPlainObject(options.filters)) {\n throw invalid('`filters` must be a filter or group object.');\n }\n try {\n JSON.stringify(options.filters);\n } catch {\n throw invalid('`filters` must be serializable to JSON.');\n }\n }\n\n if (options.sort !== undefined) {\n if (!isPlainObject(options.sort) || !isOneOf(SORT_FIELDS, options.sort.by)) {\n throw invalid(`\\`sort.by\\` must be one of ${SORT_FIELDS.join(', ')}.`);\n }\n if (options.sort.direction !== undefined && !isOneOf(SORT_DIRECTIONS, options.sort.direction)) {\n throw invalid('`sort.direction` must be \"asc\" or \"desc\".');\n }\n }\n\n if (options.preselected !== undefined) {\n const preselected = options.preselected;\n if (!Array.isArray(preselected) || !preselected.every((gaid) => typeof gaid === 'string' && gaid !== '' && !gaid.includes(','))) {\n throw invalid('`preselected` must be an array of GAIDs.');\n }\n }\n\n if (options.types !== undefined) {\n const types = options.types;\n if (!Array.isArray(types) || types.length === 0 || !types.every((type) => isOneOf(PICKER_ASSET_TYPES, type))) {\n throw invalid(`\\`types\\` must be a non-empty array of ${PICKER_ASSET_TYPES.join(', ')}.`);\n }\n }\n\n if (options.locale !== undefined && !isOneOf(PICKER_LOCALES, options.locale)) {\n throw invalid(`\\`locale\\` must be one of ${PICKER_LOCALES.join(', ')}.`);\n }\n\n if (options.theme !== undefined && !isOneOf(PICKER_THEMES, options.theme)) {\n throw invalid('`theme` must be \"light\", \"dark\" or \"auto\".');\n }\n\n if (options.mode !== undefined && !isOneOf(PICKER_MODES, options.mode)) {\n throw invalid('`mode` must be \"popup\", \"tab\", \"modal\" or \"inline\".');\n }\n\n if (options.mode === 'inline') {\n if (!isElement(options.container) || !options.container.isConnected) {\n throw invalid('`mode: \"inline\"` requires `container`, an element of the page.');\n }\n } else if (options.container !== undefined) {\n throw invalid('`container` requires `mode: \"inline\"`.');\n }\n\n for (const name of CALLBACKS) {\n if (options[name] !== undefined && typeof options[name] !== 'function') {\n throw invalid(`\\`${name}\\` must be a function.`);\n }\n }\n}\n\n/** The URL parser also rejects what the pattern lets through, such as a port above 65535. */\nfunction isValidHost(workspace: string): boolean {\n try {\n workspaceOrigin(workspace);\n\n return true;\n } catch {\n return false;\n }\n}\n\n/** Origin of the workspace, the only origin whose messages the SDK accepts. */\nexport function workspaceOrigin(workspace: string): string {\n return new URL(`https://${workspace}`).origin;\n}\n\n/** Origin of the host page; throws `invalid_options` for a page without an HTTP(S) origin (file://, sandboxed). */\nexport function hostOrigin(origin: string): string {\n if (!/^https?:\\/\\//.test(origin)) {\n throw invalid('The host page must be served over HTTP or HTTPS.');\n }\n\n return origin;\n}\n\n/** 128 random bits as 22 base64url characters. */\nexport function createChannel(): string {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n\n let binary = '';\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * URL of the picker page, with the query parameters of the protocol. `mode`\n * replaces the option's mode: the SDK opens a window with the same options\n * when an iframe cannot be used.\n */\nexport function buildOpenUrl(options: PickerOptions, origin: string, channel: string, mode: PickerMode = options.mode ?? 'popup'): string {\n const url = new URL(`${PICKER_PATH}${encodeURIComponent(options.integration)}`, workspaceOrigin(options.workspace));\n const params = url.searchParams;\n\n params.set('protocol', String(PROTOCOL_VERSION));\n params.set('origin', origin);\n params.set('channel', channel);\n params.set('mode', mode);\n params.set('select', options.select ?? 'single');\n\n if (options.max !== undefined) {\n params.set('max', String(options.max));\n }\n if (options.publicKey !== undefined) {\n params.set('public_key', options.publicKey);\n }\n if (options.q !== undefined && options.q !== '') {\n params.set('q', options.q);\n }\n if (options.filters !== undefined) {\n params.set('filters', JSON.stringify(options.filters));\n }\n if (options.sort !== undefined) {\n params.set('sort_by', options.sort.by);\n if (options.sort.direction !== undefined) {\n params.set('sort_direction', options.sort.direction);\n }\n }\n if (options.preselected !== undefined && options.preselected.length > 0) {\n params.set('preselected', options.preselected.join(','));\n }\n if (options.types !== undefined) {\n params.set('types', [...new Set(options.types)].join(','));\n }\n if (options.locale !== undefined) {\n params.set('locale', options.locale);\n }\n if (options.theme !== undefined) {\n params.set('theme', options.theme);\n }\n\n const href = url.toString();\n if (href.length > OPEN_URL_MAX_LENGTH) {\n throw invalid(`The picker URL would exceed ${OPEN_URL_MAX_LENGTH} characters: shorten \\`filters\\`, \\`q\\` or \\`preselected\\`.`);\n }\n\n return href;\n}\n","/**\n * The picker in an iframe of the host page: over the page (`modal`) or\n * inside an element the host gives (`inline`). The iframe has no `sandbox`\n * attribute: its sign-in screen opens a popup on the workspace.\n *\n * When the iframe cannot be used (the browser refuses its session cookie,\n * or the picker page never answers), the SDK replaces it with a short text\n * and an \"Open Freedam\" button that opens the picker in a window. The\n * window needs the click: browsers block a window opened without one.\n *\n * Styles are set through the CSSOM, never with a `<style>` element or a\n * `style` attribute, so a Content-Security-Policy without `unsafe-inline`\n * in `style-src` does not block them.\n */\nimport { INLINE_MIN_HEIGHT, MESSAGE_SOURCE, MODAL_FULL_SCREEN_BELOW, PICKER_LOCALES, PROTOCOL_VERSION, type HostCloseMessage, type PickerFrameMode, type PickerLocale } from './protocol';\nimport type { PickerSurface } from './surface';\n\n/** Largest size of the modal on a wide screen, in CSS pixels. */\nexport const MODAL_MAX_WIDTH = 1100;\n\nexport const MODAL_MAX_HEIGHT = 760;\n\n/** Largest height the picker can ask for the inline iframe, in CSS pixels. */\nexport const INLINE_MAX_HEIGHT = 10000;\n\n/** Above the host page's own layers. */\nconst Z_INDEX = '2147483000';\n\ninterface FrameText {\n message: string;\n open: string;\n cancel: string;\n close: string;\n}\n\n/** The SDK's only text, shown by the modal and by the fallback that replaces an unusable iframe. */\nexport const FRAME_TEXT: Record<PickerLocale, FrameText> = {\n en: {\n message: 'Freedam cannot be shown in this page. Continue in a separate window.',\n open: 'Open Freedam',\n cancel: 'Cancel',\n close: 'Close',\n },\n fr: {\n message: 'Freedam ne peut pas s’afficher dans cette page. Continuez dans une fenêtre séparée.',\n open: 'Ouvrir Freedam',\n cancel: 'Annuler',\n close: 'Fermer',\n },\n de: {\n message: 'Freedam kann auf dieser Seite nicht angezeigt werden. Fahren Sie in einem separaten Fenster fort.',\n open: 'Freedam öffnen',\n cancel: 'Abbrechen',\n close: 'Schließen',\n },\n es: {\n message: 'Freedam no se puede mostrar en esta página. Continúe en una ventana aparte.',\n open: 'Abrir Freedam',\n cancel: 'Cancelar',\n close: 'Cerrar',\n },\n 'pt-BR': {\n message: 'O Freedam não pode ser exibido nesta página. Continue em uma janela separada.',\n open: 'Abrir o Freedam',\n cancel: 'Cancelar',\n close: 'Fechar',\n },\n 'zh-CN': {\n message: '无法在此页面中显示 Freedam。请在单独的窗口中继续。',\n open: '打开 Freedam',\n cancel: '取消',\n close: '关闭',\n },\n};\n\n/**\n * Language of the SDK's text: the `locale` option, else the host page's\n * `lang`, else the browser's language, matched on the language when the\n * region differs (`fr-CA` gives `fr`); English otherwise.\n */\nexport function frameLocale(locale?: PickerLocale): PickerLocale {\n const candidates = [locale, document.documentElement.lang, typeof navigator === 'undefined' ? undefined : navigator.language];\n\n for (const candidate of candidates) {\n if (typeof candidate !== 'string' || candidate === '') {\n continue;\n }\n const exact = PICKER_LOCALES.find((supported) => supported.toLowerCase() === candidate.toLowerCase());\n if (exact !== undefined) {\n return exact;\n }\n const language = candidate.split('-')[0].toLowerCase();\n const sameLanguage = PICKER_LOCALES.find((supported) => supported.split('-')[0] === language);\n if (sameLanguage !== undefined) {\n return sameLanguage;\n }\n }\n\n return 'en';\n}\n\nexport interface FrameOptions {\n url: string;\n channel: string;\n /** Origin of the workspace: the `targetOrigin` of the `close` message. */\n origin: string;\n mode: PickerFrameMode;\n /** Required with `inline`. */\n container?: HTMLElement;\n locale?: PickerLocale;\n /** The person closed the modal or pressed Cancel in the fallback. */\n onDismiss: () => void;\n /** The person pressed \"Open Freedam\" in the fallback; runs in the click. */\n onOpenWindow: () => void;\n}\n\nexport interface FrameSurface extends PickerSurface {\n readonly mode: PickerFrameMode;\n /**\n * Removes the iframe or its fallback. `restoreFocus: false` leaves the\n * focus alone, when the picker continues in a window that has it.\n */\n close(restoreFocus?: boolean): void;\n /** Replaces the iframe with the text and the \"Open Freedam\" button. */\n showFallback(): void;\n /** Height the picker asked for; applied to the inline iframe only. */\n resize(height: number): void;\n}\n\ntype Style = Partial<Record<keyof CSSStyleDeclaration, string>>;\n\nfunction element<K extends keyof HTMLElementTagNameMap>(tag: K, style: Style = {}): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n Object.assign(node.style, style);\n\n return node;\n}\n\nfunction button(label: string, primary: boolean): HTMLButtonElement {\n const node = element('button', {\n font: 'inherit',\n fontWeight: '600',\n padding: '10px 18px',\n borderRadius: '8px',\n cursor: 'pointer',\n border: primary ? '1px solid #111827' : '1px solid #d1d5db',\n background: primary ? '#111827' : '#ffffff',\n color: primary ? '#ffffff' : '#111827',\n });\n node.type = 'button';\n node.textContent = label;\n\n return node;\n}\n\n/**\n * Shows the picker in an iframe. Must run in the same task as the person's\n * click when `mode` is `modal`, so the focus moves to the picker.\n */\nexport function openFrame(options: FrameOptions): FrameSurface {\n const text = FRAME_TEXT[frameLocale(options.locale)];\n const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n const cleanups: Array<() => void> = [];\n let closed = false;\n\n const iframe = element('iframe', {\n display: 'block',\n width: '100%',\n height: '100%',\n border: '0',\n background: '#ffffff',\n });\n iframe.src = options.url;\n iframe.name = `freedam-picker-${options.channel}`;\n iframe.title = 'Freedam';\n iframe.setAttribute('data-freedam-picker', options.mode);\n\n // `slot` holds the iframe, then the fallback that replaces it.\n let root: HTMLElement;\n let slot: HTMLElement;\n\n if (options.mode === 'modal') {\n root = element('div', {\n position: 'fixed',\n top: '0',\n right: '0',\n bottom: '0',\n left: '0',\n zIndex: Z_INDEX,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxSizing: 'border-box',\n background: 'rgba(17, 24, 39, 0.6)',\n });\n root.setAttribute('role', 'dialog');\n root.setAttribute('aria-modal', 'true');\n root.setAttribute('aria-label', 'Freedam');\n root.setAttribute('data-freedam-picker-overlay', '');\n\n slot = element('div', {\n position: 'relative',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n background: '#ffffff',\n boxShadow: '0 24px 48px rgba(0, 0, 0, 0.3)',\n });\n\n const close = element('button', {\n position: 'absolute',\n top: '6px',\n right: '8px',\n width: '32px',\n height: '32px',\n padding: '0',\n border: '0',\n borderRadius: '16px',\n background: 'transparent',\n color: '#ffffff',\n fontSize: '24px',\n lineHeight: '32px',\n cursor: 'pointer',\n });\n close.type = 'button';\n close.textContent = '×';\n close.setAttribute('aria-label', text.close);\n close.setAttribute('data-freedam-picker-close', '');\n close.addEventListener('click', () => options.onDismiss());\n\n root.append(slot, close);\n\n // Full screen on a narrow viewport, with a bar for the close button.\n const fullScreen = typeof window.matchMedia === 'function' ? window.matchMedia(`(max-width: ${MODAL_FULL_SCREEN_BELOW - 0.02}px)`) : null;\n const layout = (): void => {\n const narrow = fullScreen?.matches === true;\n Object.assign(root.style, { padding: narrow ? '44px 0 0' : '48px 24px 24px' });\n Object.assign(slot.style, {\n maxWidth: narrow ? 'none' : `${MODAL_MAX_WIDTH}px`,\n maxHeight: narrow ? 'none' : `${MODAL_MAX_HEIGHT}px`,\n borderRadius: narrow ? '0' : '12px',\n });\n };\n layout();\n if (fullScreen !== null) {\n fullScreen.addEventListener('change', layout);\n cleanups.push(() => fullScreen.removeEventListener('change', layout));\n }\n\n // Escape reaches this page only while the focus is on it (the\n // close button, the fallback), not inside the picker's iframe.\n // Tab keeps the focus inside the modal.\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') {\n options.onDismiss();\n\n return;\n }\n if (event.key !== 'Tab') {\n return;\n }\n const focusable = Array.from(root.querySelectorAll<HTMLElement>('button, iframe'));\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const current = document.activeElement;\n if (first === undefined || last === undefined) {\n return;\n }\n if (!(current instanceof Node) || !root.contains(current)) {\n event.preventDefault();\n first.focus();\n } else if (event.shiftKey && current === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && current === last) {\n event.preventDefault();\n first.focus();\n }\n };\n document.addEventListener('keydown', onKeyDown);\n cleanups.push(() => document.removeEventListener('keydown', onKeyDown));\n\n const html = document.documentElement;\n const overflow = html.style.overflow;\n html.style.overflow = 'hidden';\n cleanups.push(() => {\n html.style.overflow = overflow;\n });\n\n slot.append(iframe);\n document.body.append(root);\n } else {\n root = element('div', {\n display: 'block',\n width: '100%',\n height: '100%',\n minHeight: `${INLINE_MIN_HEIGHT}px`,\n });\n root.setAttribute('data-freedam-picker-inline', '');\n slot = root;\n iframe.style.minHeight = `${INLINE_MIN_HEIGHT}px`;\n slot.append(iframe);\n (options.container as HTMLElement).append(root);\n }\n\n if (options.mode === 'modal') {\n iframe.focus();\n }\n\n const fallbackButton = (): HTMLButtonElement | null => slot.querySelector('[data-freedam-picker-open]');\n\n return {\n mode: options.mode,\n target: () => (iframe.isConnected ? iframe.contentWindow : null),\n isClosed: () => closed || !root.isConnected,\n focus: () => (fallbackButton() ?? iframe).focus(),\n close: (restoreFocus = true) => {\n if (closed) {\n return;\n }\n closed = true;\n const target = iframe.isConnected ? iframe.contentWindow : null;\n if (target !== null) {\n const message: HostCloseMessage = { source: MESSAGE_SOURCE, protocol: PROTOCOL_VERSION, channel: options.channel, type: 'close' };\n target.postMessage(message, options.origin);\n }\n root.remove();\n for (const cleanup of cleanups) {\n cleanup();\n }\n if (restoreFocus && options.mode === 'modal' && previousFocus !== null && previousFocus.isConnected) {\n previousFocus.focus();\n }\n },\n showFallback: () => {\n if (closed || fallbackButton() !== null) {\n return;\n }\n const panel = element('div', {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '16px',\n boxSizing: 'border-box',\n width: '100%',\n height: '100%',\n minHeight: options.mode === 'inline' ? `${INLINE_MIN_HEIGHT}px` : '0',\n padding: '24px',\n background: '#ffffff',\n color: '#111827',\n fontFamily: 'system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif',\n fontSize: '15px',\n lineHeight: '1.5',\n textAlign: 'center',\n });\n panel.setAttribute('data-freedam-picker-fallback', '');\n\n const message = element('p', { margin: '0', maxWidth: '420px' });\n message.textContent = text.message;\n\n const actions = element('div', { display: 'flex', flexWrap: 'wrap', justifyContent: 'center', gap: '8px' });\n const open = button(text.open, true);\n open.setAttribute('data-freedam-picker-open', '');\n open.addEventListener('click', () => options.onOpenWindow());\n const cancel = button(text.cancel, false);\n cancel.setAttribute('data-freedam-picker-cancel', '');\n cancel.addEventListener('click', () => options.onDismiss());\n actions.append(open, cancel);\n\n panel.append(message, actions);\n iframe.remove();\n slot.append(panel);\n if (options.mode === 'modal') {\n open.focus();\n }\n },\n resize: (height: number) => {\n if (options.mode !== 'inline' || !Number.isFinite(height)) {\n return;\n }\n iframe.style.height = `${Math.round(Math.min(INLINE_MAX_HEIGHT, Math.max(INLINE_MIN_HEIGHT, height)))}px`;\n root.style.height = 'auto';\n },\n };\n}\n","import type { PickerSurface } from './surface';\n\nexport const POPUP_WIDTH = 1100;\n\nexport const POPUP_HEIGHT = 760;\n\n/**\n * The picker's windows: a popup (`mode: 'popup'`) or a tab (`mode: 'tab'`,\n * version 1.2). Both must open in the same task as the person's click,\n * with no `await` before it, or browsers block them, and both keep\n * `window.opener` (no `noopener`): the picker page posts its messages to\n * it. Each returns null when the browser blocked the window.\n */\n\n/** Opens the picker in a popup centred on the host window. */\nexport function openPopup(url: string, channel: string): PickerSurface | null {\n const width = Math.min(POPUP_WIDTH, window.screen.availWidth || POPUP_WIDTH);\n const height = Math.min(POPUP_HEIGHT, window.screen.availHeight || POPUP_HEIGHT);\n const left = Math.round(window.screenX + (window.outerWidth - width) / 2);\n const top = Math.round(window.screenY + (window.outerHeight - height) / 2);\n\n return windowSurface(\n window.open(url, `freedam-picker-${channel}`, `popup=yes,width=${width},height=${height},left=${left},top=${top}`),\n );\n}\n\n/** Opens the picker in a new tab: without window features, desktop browsers open a tab. */\nexport function openTab(url: string, channel: string): PickerSurface | null {\n return windowSurface(window.open(url, `freedam-picker-${channel}`));\n}\n\nfunction windowSurface(opened: Window | null): PickerSurface | null {\n if (!opened) {\n return null;\n }\n\n return {\n target: () => opened,\n isClosed: () => opened.closed,\n focus: () => opened.focus(),\n close: () => opened.close(),\n };\n}\n","import { FreedamPickerError, RECOVERABLE_ERROR_CODES, isServerErrorCode } from './errors';\nimport { buildOpenUrl, createChannel, hostOrigin, validateOptions, workspaceOrigin, type PickerOptions } from './options';\nimport type { PickerAsset } from './payload';\nimport { openFrame, type FrameSurface } from './frame';\nimport { openPopup, openTab } from './popup';\nimport { MESSAGE_SOURCE, PROTOCOL_VERSION, type PickerToHostMessage } from './protocol';\nimport type { PickerSurface } from './surface';\n\n/** How often the SDK checks whether the person closed the picker window. */\nexport const CLOSE_POLL_INTERVAL_MS = 500;\n\n/** Delay after `select` or `cancel` before the SDK closes a window that did not close itself. */\nexport const CLOSE_GRACE_MS = 1000;\n\n/**\n * How long the SDK waits for the picker in an iframe to send its first\n * message (`ready`, `sign_in` or `error`) before it offers to continue in a\n * window: the page may be refused by the browser or never load.\n */\nexport const READY_TIMEOUT_MS = 15000;\n\ntype PickerResult = PickerAsset[] | null;\n\n/** The opening in progress; `surface()` is the iframe, or the window that replaced it. */\nlet active: { surface: () => PickerSurface; promise: Promise<PickerResult> } | null = null;\n\n/** Whether the page has the transient activation of a click, also given by a click inside the picker's iframe. */\nfunction hasUserActivation(): boolean {\n const activation = (navigator as Navigator & { userActivation?: { isActive: boolean } }).userActivation;\n\n return activation?.isActive === true;\n}\n\n/**\n * Calls a host callback. An exception thrown by the host is reported\n * asynchronously, so it reaches the console without breaking the SDK.\n */\nfunction notify<A extends unknown[]>(callback: ((...args: A) => void) | undefined, ...args: A): void {\n if (typeof callback !== 'function') {\n return;\n }\n try {\n callback(...args);\n } catch (error) {\n setTimeout(() => {\n throw error;\n });\n }\n}\n\nfunction isPickerMessage(data: unknown, channel: string): data is PickerToHostMessage {\n if (typeof data !== 'object' || data === null) {\n return false;\n }\n const message = data as Record<string, unknown>;\n\n return (\n message.source === MESSAGE_SOURCE &&\n message.protocol === PROTOCOL_VERSION &&\n message.channel === channel &&\n typeof message.type === 'string'\n );\n}\n\n/**\n * Opens the picker and resolves with the inserted assets, or with `null`\n * when the person cancels or closes it.\n *\n * Call it from a click handler, with no `await` before it: browsers block\n * windows opened outside a user gesture. Invalid options reject with\n * `invalid_options` before anything opens. While a picker of this page is\n * open, another call brings it to the front and returns the same promise.\n *\n * In the `popup` and `tab` modes the picker runs in a window of its own,\n * a popup or a new tab of the browser.\n *\n * In the `modal` and `inline` modes the picker runs in an iframe. When the\n * iframe cannot sign in (`auth_required`) or the picker page sends nothing\n * within READY_TIMEOUT_MS, the iframe gives way to an \"Open Freedam\"\n * button that opens the picker in a window with the same options; the\n * promise then settles with the outcome of that window.\n */\nexport function open(options: PickerOptions): Promise<PickerResult> {\n if (active !== null && !active.surface().isClosed()) {\n active.surface().focus();\n\n return active.promise;\n }\n\n let url: string;\n let windowUrl: string;\n let origin: string;\n let channel: string;\n try {\n validateOptions(options);\n origin = workspaceOrigin(options.workspace);\n channel = createChannel();\n const pageOrigin = hostOrigin(window.location.origin);\n url = buildOpenUrl(options, pageOrigin, channel);\n windowUrl = buildOpenUrl(options, pageOrigin, channel, 'popup');\n } catch (error) {\n if (!(error instanceof FreedamPickerError)) {\n throw error;\n }\n notify((options as Partial<PickerOptions> | null)?.onError, error);\n\n return Promise.reject(error);\n }\n\n const mode = options.mode ?? 'popup';\n let surface: PickerSurface;\n // The iframe while it shows the picker or its fallback; null in a window.\n let frame: FrameSurface | null = null;\n const controls = { dismiss: (): void => undefined, openWindow: (): void => undefined };\n\n if (mode === 'popup' || mode === 'tab') {\n const opened = mode === 'tab' ? openTab(url, channel) : openPopup(url, channel);\n if (opened === null) {\n const error = new FreedamPickerError('popup_blocked');\n notify(options.onError, error);\n\n return Promise.reject(error);\n }\n surface = opened;\n } else {\n frame = openFrame({\n url,\n channel,\n origin,\n mode,\n container: options.container,\n locale: options.locale,\n onDismiss: () => controls.dismiss(),\n onOpenWindow: () => controls.openWindow(),\n });\n surface = frame;\n }\n\n const promise = new Promise<PickerResult>((resolve, reject) => {\n let settled = false;\n let readyNotified = false;\n let closeTimer: ReturnType<typeof setTimeout> | undefined;\n let readyTimer: ReturnType<typeof setTimeout> | undefined;\n\n const closeSoon = (): void => {\n if (frame !== null) {\n // An iframe cannot close itself: remove it at once.\n frame.close();\n checkClosed();\n\n return;\n }\n closeTimer = setTimeout(() => {\n if (!surface.isClosed()) {\n surface.close();\n }\n }, CLOSE_GRACE_MS);\n };\n\n const checkClosed = (): void => {\n if (!surface.isClosed()) {\n return;\n }\n // Removes the listeners of an iframe the host page removed itself.\n frame?.close();\n clearInterval(closePoll);\n clearTimeout(closeTimer);\n clearTimeout(readyTimer);\n window.removeEventListener('message', onMessage);\n if (active?.promise === promise) {\n active = null;\n }\n if (!settled) {\n settled = true;\n notify(options.onCancel);\n resolve(null);\n }\n notify(options.onClose);\n };\n\n /** Opens the picker in a window in place of the iframe; false when the browser blocked it. */\n const openWindow = (): boolean => {\n if (frame === null || settled) {\n return false;\n }\n const popup = openPopup(windowUrl, channel);\n if (popup === null) {\n return false;\n }\n clearTimeout(readyTimer);\n // The new window has the focus: do not hand it back to this page.\n frame.close(false);\n frame = null;\n surface = popup;\n\n return true;\n };\n\n controls.dismiss = () => {\n surface.close();\n checkClosed();\n };\n\n controls.openWindow = () => {\n if (!openWindow() && !settled) {\n // Blocked even with the click: nothing more the SDK can do.\n settled = true;\n const error = new FreedamPickerError('popup_blocked');\n notify(options.onError, error);\n reject(error);\n surface.close();\n checkClosed();\n }\n };\n\n const fallBack = (): void => {\n // A click on \"Open in a window\" inside the iframe also activates\n // this page, so the window can open now; otherwise the person\n // clicks the fallback's button.\n if (!(hasUserActivation() && openWindow())) {\n frame?.showFallback();\n }\n };\n\n const onMessage = (event: MessageEvent): void => {\n if (settled || event.origin !== origin || event.source !== surface.target()) {\n return;\n }\n const message = event.data;\n if (!isPickerMessage(message, channel)) {\n return;\n }\n clearTimeout(readyTimer);\n\n switch (message.type) {\n case 'ready':\n if (!readyNotified) {\n readyNotified = true;\n notify(options.onReady);\n }\n break;\n case 'resize':\n if (typeof message.height === 'number') {\n frame?.resize(message.height);\n }\n break;\n case 'select':\n if (!Array.isArray(message.assets)) {\n return;\n }\n settled = true;\n notify(options.onSelect, message.assets);\n resolve(message.assets);\n closeSoon();\n break;\n case 'cancel':\n settled = true;\n notify(options.onCancel);\n resolve(null);\n closeSoon();\n break;\n case 'error': {\n if (!isServerErrorCode(message.code)) {\n return;\n }\n if (message.code === 'auth_required') {\n // Not an error for the host page: the person goes on\n // in a window. A window cannot be sent this code.\n fallBack();\n\n return;\n }\n const error = new FreedamPickerError(message.code);\n notify(options.onError, error);\n // After a recoverable error the person can go on in the\n // open picker: the promise waits for the outcome.\n if (!RECOVERABLE_ERROR_CODES.includes(message.code)) {\n settled = true;\n reject(error);\n }\n break;\n }\n }\n };\n\n const closePoll = setInterval(checkClosed, CLOSE_POLL_INTERVAL_MS);\n\n if (frame !== null) {\n readyTimer = setTimeout(() => {\n if (!settled) {\n frame?.showFallback();\n }\n }, READY_TIMEOUT_MS);\n }\n\n window.addEventListener('message', onMessage);\n });\n\n active = { surface: () => surface, promise };\n\n return promise;\n}\n"],"mappings":"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","names":["SERVER_ERROR_CODES","SDK_ERROR_CODES","ERROR_MESSAGES","RECOVERABLE_ERROR_CODES","isServerErrorCode","value","FreedamPickerError","code","detail","PROTOCOL_VERSION","MESSAGE_SOURCE","PICKER_PATH","MAX_SELECTION","PICKER_MODES","INLINE_MIN_HEIGHT","PICKER_ASSET_TYPES","SELECT_MODES","PICKER_LOCALES","PICKER_THEMES","SORT_FIELDS","SORT_DIRECTIONS","CALLBACKS","PUBLIC_KEY_PATTERN","WORKSPACE_PATTERN","invalid","detail","FreedamPickerError","isOneOf","values","value","isPlainObject","isElement","validateOptions","options","isValidHost","SELECT_MODES","SORT_FIELDS","SORT_DIRECTIONS","preselected","gaid","types","type","PICKER_ASSET_TYPES","PICKER_LOCALES","PICKER_THEMES","PICKER_MODES","name","workspace","workspaceOrigin","hostOrigin","origin","createChannel","bytes","binary","byte","buildOpenUrl","channel","mode","url","PICKER_PATH","params","href","MODAL_MAX_WIDTH","MODAL_MAX_HEIGHT","INLINE_MAX_HEIGHT","Z_INDEX","FRAME_TEXT","frameLocale","locale","candidates","candidate","exact","PICKER_LOCALES","supported","language","sameLanguage","element","tag","style","node","button","label","primary","openFrame","options","text","previousFocus","cleanups","closed","iframe","root","slot","close","fullScreen","layout","narrow","onKeyDown","event","focusable","first","last","current","html","overflow","fallbackButton","restoreFocus","target","message","MESSAGE_SOURCE","cleanup","panel","actions","open","cancel","height","openPopup","url","channel","width","height","left","top","windowSurface","openTab","opened","CLOSE_POLL_INTERVAL_MS","CLOSE_GRACE_MS","READY_TIMEOUT_MS","active","hasUserActivation","notify","callback","args","error","isPickerMessage","data","channel","message","MESSAGE_SOURCE","open","options","url","windowUrl","origin","validateOptions","workspaceOrigin","createChannel","pageOrigin","hostOrigin","buildOpenUrl","FreedamPickerError","mode","surface","frame","controls","opened","openTab","openPopup","openFrame","promise","resolve","reject","settled","readyNotified","closeTimer","readyTimer","closeSoon","checkClosed","closePoll","onMessage","openWindow","popup","fallBack","event","isServerErrorCode","RECOVERABLE_ERROR_CODES"]}