@mindstudio-ai/interface 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +46 -6
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -337,7 +337,7 @@ Authentication is cookie-based (`HttpOnly`, `Secure`, `SameSite=Lax`). The SDK n
|
|
|
337
337
|
|
|
338
338
|
## Error reporting
|
|
339
339
|
|
|
340
|
-
Uncaught errors and unhandled promise rejections are automatically captured and shipped to the platform for bucketing + dashboards. No setup required — install happens on
|
|
340
|
+
Uncaught errors and unhandled promise rejections are automatically captured and shipped to the platform for bucketing + dashboards. No setup required — install happens automatically on page load (next tick after the SDK module loads). Reports include the error, a stack, and a breadcrumb trail of recent navigations + network calls for context.
|
|
341
341
|
|
|
342
342
|
Opt out per app via bootstrap config:
|
|
343
343
|
|
package/dist/index.d.ts
CHANGED
|
@@ -26,21 +26,30 @@
|
|
|
26
26
|
*
|
|
27
27
|
* ## Streaming
|
|
28
28
|
*
|
|
29
|
-
* Methods can optionally stream
|
|
30
|
-
*
|
|
31
|
-
* callback to receive incremental updates:
|
|
29
|
+
* Methods can optionally stream output via SSE. Pass `{ stream: true }` as
|
|
30
|
+
* the second argument along with callbacks for the events you care about:
|
|
32
31
|
*
|
|
33
32
|
* ```ts
|
|
33
|
+
* // LLM token text
|
|
34
34
|
* const result = await api.submitVendorRequest({ name: 'Acme' }, {
|
|
35
35
|
* stream: true,
|
|
36
36
|
* onToken: (text) => setResponseText(text),
|
|
37
37
|
* });
|
|
38
|
+
*
|
|
39
|
+
* // Structured progress events from `stream({...})` on the backend
|
|
40
|
+
* const order = await api.processOrder({ id: 'abc' }, {
|
|
41
|
+
* stream: true,
|
|
42
|
+
* onStreamData: (event) => setStatus(event),
|
|
43
|
+
* });
|
|
38
44
|
* ```
|
|
39
45
|
*
|
|
40
46
|
* **Important:** The `text` value passed to `onToken` is the accumulated
|
|
41
47
|
* response so far (not a delta). Replace your display content each time —
|
|
42
48
|
* do not append. See {@link InvokeOptions.onToken} for details.
|
|
43
49
|
*
|
|
50
|
+
* Each `onStreamData` payload is independent (no accumulation) — it's the
|
|
51
|
+
* raw object passed to `stream({...})` on the backend.
|
|
52
|
+
*
|
|
44
53
|
* ## Type safety
|
|
45
54
|
*
|
|
46
55
|
* Since the frontend and backend live in the same project, you can import
|
|
@@ -67,11 +76,12 @@
|
|
|
67
76
|
*
|
|
68
77
|
* When `stream` is `true`, the SDK sends `{ stream: true }` in the request
|
|
69
78
|
* body and parses the response as an SSE (Server-Sent Events) stream.
|
|
70
|
-
*
|
|
79
|
+
* Four event types are handled:
|
|
71
80
|
*
|
|
72
81
|
* | SSE `type` | Payload field | SDK action |
|
|
73
82
|
* |------------|---------------|------------|
|
|
74
83
|
* | `token` | `text` | Calls {@link onToken} with accumulated text |
|
|
84
|
+
* | `data` | `data` | Calls {@link onStreamData} with the raw payload |
|
|
75
85
|
* | `error` | `error` | Calls {@link onStreamError} with the message |
|
|
76
86
|
* | `done` | `output` | Captures as the method's return value |
|
|
77
87
|
*
|
|
@@ -113,6 +123,30 @@ interface InvokeOptions {
|
|
|
113
123
|
* ```
|
|
114
124
|
*/
|
|
115
125
|
onToken?: (text: string) => void;
|
|
126
|
+
/**
|
|
127
|
+
* Called when the backend method emits a structured event via
|
|
128
|
+
* `stream({...})` (object payload).
|
|
129
|
+
*
|
|
130
|
+
* Receives the raw object passed to `stream()` on the backend —
|
|
131
|
+
* not accumulated, not parsed, not wrapped. Use this for status
|
|
132
|
+
* updates, progress, intermediate results, or any structured
|
|
133
|
+
* streaming UI that isn't LLM token text.
|
|
134
|
+
*
|
|
135
|
+
* Different from {@link onToken}, which receives accumulated text from
|
|
136
|
+
* `stream('text')` calls.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* await api.processOrder({ id: 'abc' }, {
|
|
141
|
+
* stream: true,
|
|
142
|
+
* onStreamData: (event) => {
|
|
143
|
+
* // event is whatever the backend passed to stream({...})
|
|
144
|
+
* setStatus(event as { status: string; progress: number });
|
|
145
|
+
* },
|
|
146
|
+
* });
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
onStreamData?: (payload: unknown) => void;
|
|
116
150
|
/**
|
|
117
151
|
* Called if a stream-level error event arrives.
|
|
118
152
|
*
|
|
@@ -852,8 +886,14 @@ declare const auth: Auth;
|
|
|
852
886
|
*
|
|
853
887
|
* ## How it works
|
|
854
888
|
*
|
|
855
|
-
* Installed by `maybeInstallAnalytics()
|
|
856
|
-
* `getConfig()`
|
|
889
|
+
* Installed by `maybeInstallAnalytics()`, which is called by `getConfig()`
|
|
890
|
+
* in `config.ts`. `getConfig()` runs automatically on the next tick after
|
|
891
|
+
* SDK import when the platform bootstrap is present (see eager-init block
|
|
892
|
+
* in `src/index.ts`), so pageview tracking + presence are live at page
|
|
893
|
+
* load without app code needing to invoke anything. Falls back to lazy
|
|
894
|
+
* install on first SDK use if eager init was skipped.
|
|
895
|
+
*
|
|
896
|
+
* Once installed:
|
|
857
897
|
*
|
|
858
898
|
* 1. Subscribes to navigation events from `telemetry-breadcrumbs.ts`
|
|
859
899
|
* and emits a pageview on each change.
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
var l=class extends Error{code;status;constructor(t,n,
|
|
2
|
-
`)[1]??"";return`${e}|${n.trim()}`}function ue(e){if(ce)return;let t=$e(e.message,e.stack);for(let n of
|
|
3
|
-
`);
|
|
4
|
-
`);E=A.pop()??"";for(let R of A){if(!R.startsWith("data: "))continue;let h=R.slice(6);try{let B=JSON.parse(h);B.type==="done"&&(T={stopReason:B.stopReason,usage:B.usage}),Xe(B,r)}catch{}}}if(!T)throw new l("Stream ended without a done event","stream_incomplete");return T})();return c.abort=()=>a.abort(),c}}}var We={async uploadFile(e,t){let n=s(),{onProgress:o,signal:a}=t??{};a?.throwIfAborted();let i=await fetch("/_/generate-upload-request",{method:"POST",headers:{Authorization:`Bearer ${n.token}`,"Content-Type":"application/json"},body:JSON.stringify({filename:e.name,contentType:e.type||"application/octet-stream"}),signal:a});if(!i.ok)throw new l(`Upload presign failed: ${i.status} ${i.statusText}`,"upload_error",i.status);let{uploadUrl:c,uploadFields:d,publicUrl:g}=await i.json(),u=new FormData;for(let[v,E]of Object.entries(d))u.append(v,E);if(u.append("file",e),o)return await Qe(c,u,o,a),g;let f=await fetch(c,{method:"POST",body:u,signal:a});if(!f.ok)throw new l(`File upload failed: ${f.status} ${f.statusText}`,"upload_error",f.status);return g}};function Qe(e,t,n,o){return new Promise((a,r)=>{let i=new XMLHttpRequest;if(i.upload.addEventListener("progress",c=>{c.lengthComputable&&n(c.loaded/c.total)}),i.addEventListener("load",()=>{i.status>=200&&i.status<300?(n(1),a()):r(new l(`File upload failed: ${i.status} ${i.statusText}`,"upload_error",i.status))}),i.addEventListener("error",()=>{r(new l("File upload failed: network error","upload_error"))}),i.addEventListener("abort",()=>{r(new DOMException("Upload aborted","AbortError"))}),o){if(o.aborted){r(new DOMException("Upload aborted","AbortError"));return}o.addEventListener("abort",()=>i.abort(),{once:!0})}i.open("POST",e),i.send(t)})}var D=[{code:"AF",dialCode:"+93",name:"Afghanistan",flag:"\u{1F1E6}\u{1F1EB}"},{code:"AL",dialCode:"+355",name:"Albania",flag:"\u{1F1E6}\u{1F1F1}"},{code:"DZ",dialCode:"+213",name:"Algeria",flag:"\u{1F1E9}\u{1F1FF}"},{code:"AD",dialCode:"+376",name:"Andorra",flag:"\u{1F1E6}\u{1F1E9}"},{code:"AO",dialCode:"+244",name:"Angola",flag:"\u{1F1E6}\u{1F1F4}"},{code:"AG",dialCode:"+1",name:"Antigua and Barbuda",flag:"\u{1F1E6}\u{1F1EC}"},{code:"AR",dialCode:"+54",name:"Argentina",flag:"\u{1F1E6}\u{1F1F7}"},{code:"AM",dialCode:"+374",name:"Armenia",flag:"\u{1F1E6}\u{1F1F2}"},{code:"AU",dialCode:"+61",name:"Australia",flag:"\u{1F1E6}\u{1F1FA}"},{code:"AT",dialCode:"+43",name:"Austria",flag:"\u{1F1E6}\u{1F1F9}"},{code:"AZ",dialCode:"+994",name:"Azerbaijan",flag:"\u{1F1E6}\u{1F1FF}"},{code:"BS",dialCode:"+1",name:"Bahamas",flag:"\u{1F1E7}\u{1F1F8}"},{code:"BH",dialCode:"+973",name:"Bahrain",flag:"\u{1F1E7}\u{1F1ED}"},{code:"BD",dialCode:"+880",name:"Bangladesh",flag:"\u{1F1E7}\u{1F1E9}"},{code:"BB",dialCode:"+1",name:"Barbados",flag:"\u{1F1E7}\u{1F1E7}"},{code:"BY",dialCode:"+375",name:"Belarus",flag:"\u{1F1E7}\u{1F1FE}"},{code:"BE",dialCode:"+32",name:"Belgium",flag:"\u{1F1E7}\u{1F1EA}"},{code:"BZ",dialCode:"+501",name:"Belize",flag:"\u{1F1E7}\u{1F1FF}"},{code:"BJ",dialCode:"+229",name:"Benin",flag:"\u{1F1E7}\u{1F1EF}"},{code:"BT",dialCode:"+975",name:"Bhutan",flag:"\u{1F1E7}\u{1F1F9}"},{code:"BO",dialCode:"+591",name:"Bolivia",flag:"\u{1F1E7}\u{1F1F4}"},{code:"BA",dialCode:"+387",name:"Bosnia and Herzegovina",flag:"\u{1F1E7}\u{1F1E6}"},{code:"BW",dialCode:"+267",name:"Botswana",flag:"\u{1F1E7}\u{1F1FC}"},{code:"BR",dialCode:"+55",name:"Brazil",flag:"\u{1F1E7}\u{1F1F7}"},{code:"BN",dialCode:"+673",name:"Brunei",flag:"\u{1F1E7}\u{1F1F3}"},{code:"BG",dialCode:"+359",name:"Bulgaria",flag:"\u{1F1E7}\u{1F1EC}"},{code:"BF",dialCode:"+226",name:"Burkina Faso",flag:"\u{1F1E7}\u{1F1EB}"},{code:"BI",dialCode:"+257",name:"Burundi",flag:"\u{1F1E7}\u{1F1EE}"},{code:"CV",dialCode:"+238",name:"Cabo Verde",flag:"\u{1F1E8}\u{1F1FB}"},{code:"KH",dialCode:"+855",name:"Cambodia",flag:"\u{1F1F0}\u{1F1ED}"},{code:"CM",dialCode:"+237",name:"Cameroon",flag:"\u{1F1E8}\u{1F1F2}"},{code:"CA",dialCode:"+1",name:"Canada",flag:"\u{1F1E8}\u{1F1E6}"},{code:"CF",dialCode:"+236",name:"Central African Republic",flag:"\u{1F1E8}\u{1F1EB}"},{code:"TD",dialCode:"+235",name:"Chad",flag:"\u{1F1F9}\u{1F1E9}"},{code:"CL",dialCode:"+56",name:"Chile",flag:"\u{1F1E8}\u{1F1F1}"},{code:"CN",dialCode:"+86",name:"China",flag:"\u{1F1E8}\u{1F1F3}"},{code:"CO",dialCode:"+57",name:"Colombia",flag:"\u{1F1E8}\u{1F1F4}"},{code:"KM",dialCode:"+269",name:"Comoros",flag:"\u{1F1F0}\u{1F1F2}"},{code:"CG",dialCode:"+242",name:"Congo",flag:"\u{1F1E8}\u{1F1EC}"},{code:"CD",dialCode:"+243",name:"Congo (DRC)",flag:"\u{1F1E8}\u{1F1E9}"},{code:"CR",dialCode:"+506",name:"Costa Rica",flag:"\u{1F1E8}\u{1F1F7}"},{code:"HR",dialCode:"+385",name:"Croatia",flag:"\u{1F1ED}\u{1F1F7}"},{code:"CU",dialCode:"+53",name:"Cuba",flag:"\u{1F1E8}\u{1F1FA}"},{code:"CY",dialCode:"+357",name:"Cyprus",flag:"\u{1F1E8}\u{1F1FE}"},{code:"CZ",dialCode:"+420",name:"Czechia",flag:"\u{1F1E8}\u{1F1FF}"},{code:"CI",dialCode:"+225",name:"Cote d'Ivoire",flag:"\u{1F1E8}\u{1F1EE}"},{code:"DK",dialCode:"+45",name:"Denmark",flag:"\u{1F1E9}\u{1F1F0}"},{code:"DJ",dialCode:"+253",name:"Djibouti",flag:"\u{1F1E9}\u{1F1EF}"},{code:"DM",dialCode:"+1",name:"Dominica",flag:"\u{1F1E9}\u{1F1F2}"},{code:"DO",dialCode:"+1",name:"Dominican Republic",flag:"\u{1F1E9}\u{1F1F4}"},{code:"EC",dialCode:"+593",name:"Ecuador",flag:"\u{1F1EA}\u{1F1E8}"},{code:"EG",dialCode:"+20",name:"Egypt",flag:"\u{1F1EA}\u{1F1EC}"},{code:"SV",dialCode:"+503",name:"El Salvador",flag:"\u{1F1F8}\u{1F1FB}"},{code:"GQ",dialCode:"+240",name:"Equatorial Guinea",flag:"\u{1F1EC}\u{1F1F6}"},{code:"ER",dialCode:"+291",name:"Eritrea",flag:"\u{1F1EA}\u{1F1F7}"},{code:"EE",dialCode:"+372",name:"Estonia",flag:"\u{1F1EA}\u{1F1EA}"},{code:"SZ",dialCode:"+268",name:"Eswatini",flag:"\u{1F1F8}\u{1F1FF}"},{code:"ET",dialCode:"+251",name:"Ethiopia",flag:"\u{1F1EA}\u{1F1F9}"},{code:"FJ",dialCode:"+679",name:"Fiji",flag:"\u{1F1EB}\u{1F1EF}"},{code:"FI",dialCode:"+358",name:"Finland",flag:"\u{1F1EB}\u{1F1EE}"},{code:"FR",dialCode:"+33",name:"France",flag:"\u{1F1EB}\u{1F1F7}"},{code:"GA",dialCode:"+241",name:"Gabon",flag:"\u{1F1EC}\u{1F1E6}"},{code:"GM",dialCode:"+220",name:"Gambia",flag:"\u{1F1EC}\u{1F1F2}"},{code:"GE",dialCode:"+995",name:"Georgia",flag:"\u{1F1EC}\u{1F1EA}"},{code:"DE",dialCode:"+49",name:"Germany",flag:"\u{1F1E9}\u{1F1EA}"},{code:"GH",dialCode:"+233",name:"Ghana",flag:"\u{1F1EC}\u{1F1ED}"},{code:"GR",dialCode:"+30",name:"Greece",flag:"\u{1F1EC}\u{1F1F7}"},{code:"GD",dialCode:"+1",name:"Grenada",flag:"\u{1F1EC}\u{1F1E9}"},{code:"GT",dialCode:"+502",name:"Guatemala",flag:"\u{1F1EC}\u{1F1F9}"},{code:"GN",dialCode:"+224",name:"Guinea",flag:"\u{1F1EC}\u{1F1F3}"},{code:"GW",dialCode:"+245",name:"Guinea-Bissau",flag:"\u{1F1EC}\u{1F1FC}"},{code:"GY",dialCode:"+592",name:"Guyana",flag:"\u{1F1EC}\u{1F1FE}"},{code:"HT",dialCode:"+509",name:"Haiti",flag:"\u{1F1ED}\u{1F1F9}"},{code:"HN",dialCode:"+504",name:"Honduras",flag:"\u{1F1ED}\u{1F1F3}"},{code:"HK",dialCode:"+852",name:"Hong Kong",flag:"\u{1F1ED}\u{1F1F0}"},{code:"HU",dialCode:"+36",name:"Hungary",flag:"\u{1F1ED}\u{1F1FA}"},{code:"IS",dialCode:"+354",name:"Iceland",flag:"\u{1F1EE}\u{1F1F8}"},{code:"IN",dialCode:"+91",name:"India",flag:"\u{1F1EE}\u{1F1F3}"},{code:"ID",dialCode:"+62",name:"Indonesia",flag:"\u{1F1EE}\u{1F1E9}"},{code:"IR",dialCode:"+98",name:"Iran",flag:"\u{1F1EE}\u{1F1F7}"},{code:"IQ",dialCode:"+964",name:"Iraq",flag:"\u{1F1EE}\u{1F1F6}"},{code:"IE",dialCode:"+353",name:"Ireland",flag:"\u{1F1EE}\u{1F1EA}"},{code:"IL",dialCode:"+972",name:"Israel",flag:"\u{1F1EE}\u{1F1F1}"},{code:"IT",dialCode:"+39",name:"Italy",flag:"\u{1F1EE}\u{1F1F9}"},{code:"JM",dialCode:"+1",name:"Jamaica",flag:"\u{1F1EF}\u{1F1F2}"},{code:"JP",dialCode:"+81",name:"Japan",flag:"\u{1F1EF}\u{1F1F5}"},{code:"JO",dialCode:"+962",name:"Jordan",flag:"\u{1F1EF}\u{1F1F4}"},{code:"KZ",dialCode:"+7",name:"Kazakhstan",flag:"\u{1F1F0}\u{1F1FF}"},{code:"KE",dialCode:"+254",name:"Kenya",flag:"\u{1F1F0}\u{1F1EA}"},{code:"KI",dialCode:"+686",name:"Kiribati",flag:"\u{1F1F0}\u{1F1EE}"},{code:"KW",dialCode:"+965",name:"Kuwait",flag:"\u{1F1F0}\u{1F1FC}"},{code:"KG",dialCode:"+996",name:"Kyrgyzstan",flag:"\u{1F1F0}\u{1F1EC}"},{code:"LA",dialCode:"+856",name:"Laos",flag:"\u{1F1F1}\u{1F1E6}"},{code:"LV",dialCode:"+371",name:"Latvia",flag:"\u{1F1F1}\u{1F1FB}"},{code:"LB",dialCode:"+961",name:"Lebanon",flag:"\u{1F1F1}\u{1F1E7}"},{code:"LS",dialCode:"+266",name:"Lesotho",flag:"\u{1F1F1}\u{1F1F8}"},{code:"LR",dialCode:"+231",name:"Liberia",flag:"\u{1F1F1}\u{1F1F7}"},{code:"LY",dialCode:"+218",name:"Libya",flag:"\u{1F1F1}\u{1F1FE}"},{code:"LI",dialCode:"+423",name:"Liechtenstein",flag:"\u{1F1F1}\u{1F1EE}"},{code:"LT",dialCode:"+370",name:"Lithuania",flag:"\u{1F1F1}\u{1F1F9}"},{code:"LU",dialCode:"+352",name:"Luxembourg",flag:"\u{1F1F1}\u{1F1FA}"},{code:"MO",dialCode:"+853",name:"Macao",flag:"\u{1F1F2}\u{1F1F4}"},{code:"MG",dialCode:"+261",name:"Madagascar",flag:"\u{1F1F2}\u{1F1EC}"},{code:"MW",dialCode:"+265",name:"Malawi",flag:"\u{1F1F2}\u{1F1FC}"},{code:"MY",dialCode:"+60",name:"Malaysia",flag:"\u{1F1F2}\u{1F1FE}"},{code:"MV",dialCode:"+960",name:"Maldives",flag:"\u{1F1F2}\u{1F1FB}"},{code:"ML",dialCode:"+223",name:"Mali",flag:"\u{1F1F2}\u{1F1F1}"},{code:"MT",dialCode:"+356",name:"Malta",flag:"\u{1F1F2}\u{1F1F9}"},{code:"MH",dialCode:"+692",name:"Marshall Islands",flag:"\u{1F1F2}\u{1F1ED}"},{code:"MR",dialCode:"+222",name:"Mauritania",flag:"\u{1F1F2}\u{1F1F7}"},{code:"MU",dialCode:"+230",name:"Mauritius",flag:"\u{1F1F2}\u{1F1FA}"},{code:"MX",dialCode:"+52",name:"Mexico",flag:"\u{1F1F2}\u{1F1FD}"},{code:"FM",dialCode:"+691",name:"Micronesia",flag:"\u{1F1EB}\u{1F1F2}"},{code:"MD",dialCode:"+373",name:"Moldova",flag:"\u{1F1F2}\u{1F1E9}"},{code:"MC",dialCode:"+377",name:"Monaco",flag:"\u{1F1F2}\u{1F1E8}"},{code:"MN",dialCode:"+976",name:"Mongolia",flag:"\u{1F1F2}\u{1F1F3}"},{code:"ME",dialCode:"+382",name:"Montenegro",flag:"\u{1F1F2}\u{1F1EA}"},{code:"MA",dialCode:"+212",name:"Morocco",flag:"\u{1F1F2}\u{1F1E6}"},{code:"MZ",dialCode:"+258",name:"Mozambique",flag:"\u{1F1F2}\u{1F1FF}"},{code:"MM",dialCode:"+95",name:"Myanmar",flag:"\u{1F1F2}\u{1F1F2}"},{code:"NA",dialCode:"+264",name:"Namibia",flag:"\u{1F1F3}\u{1F1E6}"},{code:"NR",dialCode:"+674",name:"Nauru",flag:"\u{1F1F3}\u{1F1F7}"},{code:"NP",dialCode:"+977",name:"Nepal",flag:"\u{1F1F3}\u{1F1F5}"},{code:"NL",dialCode:"+31",name:"Netherlands",flag:"\u{1F1F3}\u{1F1F1}"},{code:"NZ",dialCode:"+64",name:"New Zealand",flag:"\u{1F1F3}\u{1F1FF}"},{code:"NI",dialCode:"+505",name:"Nicaragua",flag:"\u{1F1F3}\u{1F1EE}"},{code:"NE",dialCode:"+227",name:"Niger",flag:"\u{1F1F3}\u{1F1EA}"},{code:"NG",dialCode:"+234",name:"Nigeria",flag:"\u{1F1F3}\u{1F1EC}"},{code:"KP",dialCode:"+850",name:"North Korea",flag:"\u{1F1F0}\u{1F1F5}"},{code:"MK",dialCode:"+389",name:"North Macedonia",flag:"\u{1F1F2}\u{1F1F0}"},{code:"NO",dialCode:"+47",name:"Norway",flag:"\u{1F1F3}\u{1F1F4}"},{code:"OM",dialCode:"+968",name:"Oman",flag:"\u{1F1F4}\u{1F1F2}"},{code:"PK",dialCode:"+92",name:"Pakistan",flag:"\u{1F1F5}\u{1F1F0}"},{code:"PW",dialCode:"+680",name:"Palau",flag:"\u{1F1F5}\u{1F1FC}"},{code:"PS",dialCode:"+970",name:"Palestine",flag:"\u{1F1F5}\u{1F1F8}"},{code:"PA",dialCode:"+507",name:"Panama",flag:"\u{1F1F5}\u{1F1E6}"},{code:"PG",dialCode:"+675",name:"Papua New Guinea",flag:"\u{1F1F5}\u{1F1EC}"},{code:"PY",dialCode:"+595",name:"Paraguay",flag:"\u{1F1F5}\u{1F1FE}"},{code:"PE",dialCode:"+51",name:"Peru",flag:"\u{1F1F5}\u{1F1EA}"},{code:"PH",dialCode:"+63",name:"Philippines",flag:"\u{1F1F5}\u{1F1ED}"},{code:"PL",dialCode:"+48",name:"Poland",flag:"\u{1F1F5}\u{1F1F1}"},{code:"PT",dialCode:"+351",name:"Portugal",flag:"\u{1F1F5}\u{1F1F9}"},{code:"PR",dialCode:"+1",name:"Puerto Rico",flag:"\u{1F1F5}\u{1F1F7}"},{code:"QA",dialCode:"+974",name:"Qatar",flag:"\u{1F1F6}\u{1F1E6}"},{code:"RO",dialCode:"+40",name:"Romania",flag:"\u{1F1F7}\u{1F1F4}"},{code:"RU",dialCode:"+7",name:"Russia",flag:"\u{1F1F7}\u{1F1FA}"},{code:"RW",dialCode:"+250",name:"Rwanda",flag:"\u{1F1F7}\u{1F1FC}"},{code:"KN",dialCode:"+1",name:"Saint Kitts and Nevis",flag:"\u{1F1F0}\u{1F1F3}"},{code:"LC",dialCode:"+1",name:"Saint Lucia",flag:"\u{1F1F1}\u{1F1E8}"},{code:"VC",dialCode:"+1",name:"Saint Vincent and the Grenadines",flag:"\u{1F1FB}\u{1F1E8}"},{code:"WS",dialCode:"+685",name:"Samoa",flag:"\u{1F1FC}\u{1F1F8}"},{code:"SM",dialCode:"+378",name:"San Marino",flag:"\u{1F1F8}\u{1F1F2}"},{code:"ST",dialCode:"+239",name:"Sao Tome and Principe",flag:"\u{1F1F8}\u{1F1F9}"},{code:"SA",dialCode:"+966",name:"Saudi Arabia",flag:"\u{1F1F8}\u{1F1E6}"},{code:"SN",dialCode:"+221",name:"Senegal",flag:"\u{1F1F8}\u{1F1F3}"},{code:"RS",dialCode:"+381",name:"Serbia",flag:"\u{1F1F7}\u{1F1F8}"},{code:"SC",dialCode:"+248",name:"Seychelles",flag:"\u{1F1F8}\u{1F1E8}"},{code:"SL",dialCode:"+232",name:"Sierra Leone",flag:"\u{1F1F8}\u{1F1F1}"},{code:"SG",dialCode:"+65",name:"Singapore",flag:"\u{1F1F8}\u{1F1EC}"},{code:"SK",dialCode:"+421",name:"Slovakia",flag:"\u{1F1F8}\u{1F1F0}"},{code:"SI",dialCode:"+386",name:"Slovenia",flag:"\u{1F1F8}\u{1F1EE}"},{code:"SB",dialCode:"+677",name:"Solomon Islands",flag:"\u{1F1F8}\u{1F1E7}"},{code:"SO",dialCode:"+252",name:"Somalia",flag:"\u{1F1F8}\u{1F1F4}"},{code:"ZA",dialCode:"+27",name:"South Africa",flag:"\u{1F1FF}\u{1F1E6}"},{code:"KR",dialCode:"+82",name:"South Korea",flag:"\u{1F1F0}\u{1F1F7}"},{code:"SS",dialCode:"+211",name:"South Sudan",flag:"\u{1F1F8}\u{1F1F8}"},{code:"ES",dialCode:"+34",name:"Spain",flag:"\u{1F1EA}\u{1F1F8}"},{code:"LK",dialCode:"+94",name:"Sri Lanka",flag:"\u{1F1F1}\u{1F1F0}"},{code:"SD",dialCode:"+249",name:"Sudan",flag:"\u{1F1F8}\u{1F1E9}"},{code:"SR",dialCode:"+597",name:"Suriname",flag:"\u{1F1F8}\u{1F1F7}"},{code:"SE",dialCode:"+46",name:"Sweden",flag:"\u{1F1F8}\u{1F1EA}"},{code:"CH",dialCode:"+41",name:"Switzerland",flag:"\u{1F1E8}\u{1F1ED}"},{code:"SY",dialCode:"+963",name:"Syria",flag:"\u{1F1F8}\u{1F1FE}"},{code:"TW",dialCode:"+886",name:"Taiwan",flag:"\u{1F1F9}\u{1F1FC}"},{code:"TJ",dialCode:"+992",name:"Tajikistan",flag:"\u{1F1F9}\u{1F1EF}"},{code:"TZ",dialCode:"+255",name:"Tanzania",flag:"\u{1F1F9}\u{1F1FF}"},{code:"TH",dialCode:"+66",name:"Thailand",flag:"\u{1F1F9}\u{1F1ED}"},{code:"TL",dialCode:"+670",name:"Timor-Leste",flag:"\u{1F1F9}\u{1F1F1}"},{code:"TG",dialCode:"+228",name:"Togo",flag:"\u{1F1F9}\u{1F1EC}"},{code:"TO",dialCode:"+676",name:"Tonga",flag:"\u{1F1F9}\u{1F1F4}"},{code:"TT",dialCode:"+1",name:"Trinidad and Tobago",flag:"\u{1F1F9}\u{1F1F9}"},{code:"TN",dialCode:"+216",name:"Tunisia",flag:"\u{1F1F9}\u{1F1F3}"},{code:"TR",dialCode:"+90",name:"Turkey",flag:"\u{1F1F9}\u{1F1F7}"},{code:"TM",dialCode:"+993",name:"Turkmenistan",flag:"\u{1F1F9}\u{1F1F2}"},{code:"TV",dialCode:"+688",name:"Tuvalu",flag:"\u{1F1F9}\u{1F1FB}"},{code:"UG",dialCode:"+256",name:"Uganda",flag:"\u{1F1FA}\u{1F1EC}"},{code:"UA",dialCode:"+380",name:"Ukraine",flag:"\u{1F1FA}\u{1F1E6}"},{code:"AE",dialCode:"+971",name:"United Arab Emirates",flag:"\u{1F1E6}\u{1F1EA}"},{code:"GB",dialCode:"+44",name:"United Kingdom",flag:"\u{1F1EC}\u{1F1E7}"},{code:"US",dialCode:"+1",name:"United States",flag:"\u{1F1FA}\u{1F1F8}"},{code:"UY",dialCode:"+598",name:"Uruguay",flag:"\u{1F1FA}\u{1F1FE}"},{code:"UZ",dialCode:"+998",name:"Uzbekistan",flag:"\u{1F1FA}\u{1F1FF}"},{code:"VU",dialCode:"+678",name:"Vanuatu",flag:"\u{1F1FB}\u{1F1FA}"},{code:"VA",dialCode:"+39",name:"Vatican City",flag:"\u{1F1FB}\u{1F1E6}"},{code:"VE",dialCode:"+58",name:"Venezuela",flag:"\u{1F1FB}\u{1F1EA}"},{code:"VN",dialCode:"+84",name:"Vietnam",flag:"\u{1F1FB}\u{1F1F3}"},{code:"YE",dialCode:"+967",name:"Yemen",flag:"\u{1F1FE}\u{1F1EA}"},{code:"ZM",dialCode:"+260",name:"Zambia",flag:"\u{1F1FF}\u{1F1F2}"},{code:"ZW",dialCode:"+263",name:"Zimbabwe",flag:"\u{1F1FF}\u{1F1FC}"}],et=new Map(D.map(e=>[e.code,e])),tt={"America/New_York":"US","America/Chicago":"US","America/Denver":"US","America/Los_Angeles":"US","America/Anchorage":"US","Pacific/Honolulu":"US","America/Phoenix":"US","America/Indiana/Indianapolis":"US","America/Toronto":"CA","America/Vancouver":"CA","America/Edmonton":"CA","America/Winnipeg":"CA","America/Halifax":"CA","America/St_Johns":"CA","Europe/London":"GB","Europe/Dublin":"IE","Europe/Paris":"FR","Europe/Berlin":"DE","Europe/Madrid":"ES","Europe/Rome":"IT","Europe/Amsterdam":"NL","Europe/Brussels":"BE","Europe/Zurich":"CH","Europe/Vienna":"AT","Europe/Stockholm":"SE","Europe/Oslo":"NO","Europe/Copenhagen":"DK","Europe/Helsinki":"FI","Europe/Warsaw":"PL","Europe/Prague":"CZ","Europe/Bucharest":"RO","Europe/Budapest":"HU","Europe/Athens":"GR","Europe/Istanbul":"TR","Europe/Moscow":"RU","Europe/Kiev":"UA","Europe/Lisbon":"PT","Europe/Belgrade":"RS","Europe/Zagreb":"HR","Europe/Bratislava":"SK","Europe/Ljubljana":"SI","Europe/Tallinn":"EE","Europe/Riga":"LV","Europe/Vilnius":"LT","Asia/Tokyo":"JP","Asia/Seoul":"KR","Asia/Shanghai":"CN","Asia/Hong_Kong":"HK","Asia/Taipei":"TW","Asia/Singapore":"SG","Asia/Kolkata":"IN","Asia/Karachi":"PK","Asia/Dhaka":"BD","Asia/Bangkok":"TH","Asia/Jakarta":"ID","Asia/Manila":"PH","Asia/Kuala_Lumpur":"MY","Asia/Ho_Chi_Minh":"VN","Asia/Riyadh":"SA","Asia/Dubai":"AE","Asia/Tehran":"IR","Asia/Baghdad":"IQ","Asia/Beirut":"LB","Asia/Jerusalem":"IL","Asia/Amman":"JO","Asia/Almaty":"KZ","Asia/Tashkent":"UZ","Asia/Colombo":"LK","Asia/Kathmandu":"NP","Asia/Yangon":"MM","Australia/Sydney":"AU","Australia/Melbourne":"AU","Australia/Brisbane":"AU","Australia/Perth":"AU","Australia/Adelaide":"AU","Pacific/Auckland":"NZ","Pacific/Fiji":"FJ","Africa/Cairo":"EG","Africa/Lagos":"NG","Africa/Nairobi":"KE","Africa/Johannesburg":"ZA","Africa/Casablanca":"MA","Africa/Accra":"GH","Africa/Addis_Ababa":"ET","Africa/Dar_es_Salaam":"TZ","Africa/Kampala":"UG","America/Mexico_City":"MX","America/Bogota":"CO","America/Lima":"PE","America/Santiago":"CL","America/Buenos_Aires":"AR","America/Sao_Paulo":"BR","America/Caracas":"VE","America/Guatemala":"GT","America/Havana":"CU","America/Panama":"PA","America/Jamaica":"JM"};function he(){try{let e=Intl.DateTimeFormat().resolvedOptions().timeZone;return tt[e]??"US"}catch{return"US"}}function Ce(e){if(!e.startsWith("+"))return e;let t=e.slice(1);if(t.startsWith("1")&&t.length===11){let n=t.slice(1,4),o=t.slice(4,7),a=t.slice(7);return`+1 (${n}) ${o}-${a}`}for(let n=4;n>=1;n--){let o="+"+t.slice(0,n),a=D.find(r=>r.dialCode===o);if(a){let r=t.slice(n);return`${a.dialCode} ${r}`}}return e}function ye(e,t){let n=e.replace(/\D/g,""),o=et.get(t);if(!o)return"+"+n;let a=o.dialCode.slice(1);return n.startsWith(a)?"+"+n:o.dialCode+n}function Ae(e){return/^\+[1-9]\d{6,14}$/.test(e)}function Ee(e){return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)}async function y(e,t,n){let a={Authorization:`Bearer ${s().token}`};n!==void 0&&(a["Content-Type"]="application/json");let r=await fetch(e,{method:t,headers:a,...n!==void 0&&{body:JSON.stringify(n)}});if(!r.ok){let i=`Auth request failed: ${r.status} ${r.statusText}`,c="auth_error";try{let d=await r.json();d.error&&(i=d.error),d.code&&(c=d.code)}catch{}throw new l(i,c,r.status)}return await r.json()}var G=new Set;function P(e){me({token:e.token,user:e.user,methods:e.methods,visitorId:e.visitorId}),G.forEach(t=>t(e.user))}function H(e){if(!e.user)throw new l("Verification succeeded but no user was returned","auth_error");return e.user}function Te(e){let t=s();t.user&&(Object.assign(t.user,e),G.forEach(n=>n(t.user)))}var ot={get currentUser(){return s().user},getCurrentUser(){return s().user},isAuthenticated(){return s().user!==null},get currentVisitorId(){return s().visitorId??null},getCurrentVisitorId(){return s().visitorId??null},sendEmailCode(e){return y("/_/auth/email/send","POST",{email:e})},async verifyEmailCode(e,t){let n=await y("/_/auth/email/verify","POST",{verificationId:e,code:t});return P(n),H(n)},sendSmsCode(e){return y("/_/auth/sms/send","POST",{phone:e})},async verifySmsCode(e,t){let n=await y("/_/auth/sms/verify","POST",{verificationId:e,code:t});return P(n),H(n)},async requestEmailChange(e){await y("/_/auth/email/change","POST",{newEmail:e})},async confirmEmailChange(e,t){let n=await y("/_/auth/email/change/confirm","POST",{newEmail:e,code:t});return P(n),H(n)},async requestPhoneChange(e){await y("/_/auth/phone/change","POST",{newPhone:e})},async confirmPhoneChange(e,t){let n=await y("/_/auth/phone/change/confirm","POST",{newPhone:e,code:t});return P(n),H(n)},async logout(){let e=await y("/_/auth/logout","POST",{});P(e)},async createApiKey(){let e=await y("/_/auth/api-key/create","POST",{});return Te({apiKey:e.apiKey}),{key:e.key}},async revokeApiKey(){await y("/_/auth/api-key/revoke","POST",{}),Te({apiKey:null})},onAuthStateChanged(e){return G.add(e),e(s().user),()=>{G.delete(e)}},phone:{countries:D,detectCountry:he,format:Ce,toE164:ye,isValid:Ae},email:{isValid:Ee}};export{l as MindStudioInterfaceError,De as analytics,ot as auth,Ye as createAgentChatClient,ze as createClient,We as platform};
|
|
1
|
+
var l=class extends Error{code;status;constructor(t,n,a){super(t),this.name="MindStudioInterfaceError",this.code=n,this.status=a}};var Se="/_/telemetry/";var U=[];function w(e){U.push(e),U.length>20&&U.shift()}function F(){return U.slice()}function z(e){return e.includes(Se)}function be(e){return typeof e=="string"?e:e instanceof URL?e.href:e.url||String(e)}var x="",K=new Set;function X(e){return K.add(e),()=>{K.delete(e)}}function B(e){e!==x&&(w({type:"navigation",from:x,to:e,timestamp:Date.now()}),x=e,K.forEach(t=>{try{t(e)}catch{}}))}function ve(){let e=window;if(e.__ms_history_patched)return;e.__ms_history_patched=!0,x=location.href;let t=history.pushState.bind(history);history.pushState=function(a,o,r){t(a,o,r);try{B(location.href)}catch{}};let n=history.replaceState.bind(history);history.replaceState=function(a,o,r){n(a,o,r);try{B(location.href)}catch{}},window.addEventListener("popstate",()=>{try{B(location.href)}catch{}}),window.addEventListener("hashchange",()=>{try{B(location.href)}catch{}})}function we(e){if(!window.fetch||window.fetch.__ms_patched)return;let n=window.fetch.bind(window),a=function(o,r){let i=be(o);if(z(i))return n(o,r);let c=(r?.method||(typeof o!="string"&&!(o instanceof URL)?o.method:"")||"GET").toUpperCase(),d=Date.now();return n(o,r).then(g=>{let u={type:"fetch",method:c,url:i,status:g.status,ok:g.ok,duration:Date.now()-d,timestamp:d};if(!g.ok&&e)try{g.clone().text().then(m=>{u.body=m.slice(0,1024),w(u)}).catch(()=>w(u))}catch{w(u)}else w(u);return g},g=>{throw w({type:"fetch",method:c,url:i,ok:!1,duration:Date.now()-d,timestamp:d,error:g instanceof Error?g.message:String(g??"fetch failed")}),g})};a.__ms_patched=!0,window.fetch=a}function _e(){if(XMLHttpRequest.prototype.open.__ms_patched)return;let t=XMLHttpRequest.prototype.open,n=XMLHttpRequest.prototype.send;XMLHttpRequest.prototype.open=function(a,o,...r){return this.__ms_method=(a||"GET").toUpperCase(),this.__ms_url=String(o),t.apply(this,[a,o,...r])},XMLHttpRequest.prototype.send=function(a){let o=this.__ms_method||"GET",r=this.__ms_url||"";if(z(r))return n.apply(this,[a]);let i=Date.now();return this.addEventListener("loadend",function(){w({type:"xhr",method:o,url:r,status:this.status,ok:this.status>=200&&this.status<300,duration:Date.now()-i,timestamp:i})},{once:!0}),n.apply(this,[a])},XMLHttpRequest.prototype.open.__ms_patched=!0}var Z=!1;function Y(e){if(!Z){Z=!0;try{ve()}catch{}try{we(e.captureResponseBodies)}catch{}try{_e()}catch{}}}var te="/_/telemetry/events",ke=1e3,Me=100,Pe=6e4,C=[],$=null,V=0,ne=!1;function ae(e){ne||C.length>=Me||(C.push(e),Re())}function Re(){$||C.length===0||($=setTimeout(()=>{$=null,Ie()},ke))}function oe(){let e=C;return C=[],e}async function Ie(){if(C.length===0)return;if(Date.now()<V){C=[];return}let e;try{e=s()}catch{C=[];return}let t=oe();try{let n=await fetch(te,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.token}`},body:JSON.stringify({events:t})});if(n.status===429){let a=n.headers.get("Retry-After"),o=a?parseInt(a,10):NaN,r=Number.isFinite(o)&&o>0?o*1e3:Pe;V=Date.now()+r}}catch{}}function W(){if(C.length===0)return;if(Date.now()<V){C=[];return}let e;try{e=s()}catch{C=[];return}let t=oe();try{fetch(te,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.token}`},body:JSON.stringify({events:t}),keepalive:!0})}catch{}}function Be(e){if(!e)return;let t={};for(let[n,a]of Object.entries(e))(typeof a=="string"||typeof a=="number"||typeof a=="boolean")&&(t[n]=a);return Object.keys(t).length>0?t:void 0}function Q(e){try{let t=s();ae({type:"pageview",releaseId:t.releaseId,url:e,referrer:document.referrer,userAgent:navigator.userAgent,language:navigator.language,screen:{w:window.innerWidth,h:window.innerHeight},timestamp:Date.now()})}catch{}}function Ue(e,t){try{let n=s();ae({type:"event",releaseId:n.releaseId,name:e,url:location.href,timestamp:Date.now(),props:Be(t)})}catch{}}var xe="/_/telemetry/presence",Le=1e4,Ne=3e4,k=null,_=null,N=1e3,b=!1;function j(){let e=N;N=Math.min(N*2,Le);let t=Math.random()*250;return e+t}function L(e){_&&clearTimeout(_),_=setTimeout(()=>{_=null,b&&re()},e)}function Oe(){if(b=!1,_&&(clearTimeout(_),_=null),k){try{k.abort()}catch{}k=null}}async function re(){if(!b)return;let e;try{e=s()}catch{b=!1;return}k=new AbortController;let t=k.signal;try{let n=await fetch(xe,{method:"GET",headers:{Authorization:`Bearer ${e.token}`,Accept:"text/event-stream"},signal:t});if(n.status===503){let o=n.headers.get("Retry-After"),r=o?parseInt(o,10):NaN,i=Number.isFinite(r)&&r>0?r*1e3:Ne;L(i);return}if(n.status===401){b=!1;return}if(!n.ok||!n.body){L(j());return}N=1e3;let a=n.body.getReader();for(;b;){let{done:o}=await a.read();if(o)break}b&&L(j())}catch(n){let a=n?.name;b&&a!=="AbortError"&&L(j())}}var De={track:Ue},ee=!1;function He(){if(ee||typeof window>"u")return;let e;try{e=s()}catch{return}if(e.telemetry?.analytics===!1)return;ee=!0;let t=()=>{ne=!0,W(),Oe()};window.addEventListener("pagehide",t),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&W()}),X(n=>{Q(n)}),Q(location.href),b=!0,re()}function ie(){try{He()}catch{}}var le="/_/telemetry/errors",Ge=1e3,Ke=50,Fe=6e4,se=!1,h=[],q=null,J=0,ce=!1;function $e(e,t){let n=t.split(`
|
|
2
|
+
`)[1]??"";return`${e}|${n.trim()}`}function ue(e){if(ce)return;let t=$e(e.message,e.stack);for(let n of h)if(n._fp===t){n.count=(n.count??1)+1;return}h.length>=Ke||(e._fp=t,h.push(e),je())}function je(){q||h.length===0||(q=setTimeout(()=>{q=null,Ve()},Ge))}function ge(){let e=h;return h=[],e.map(({_fp:t,...n})=>n)}async function Ve(){if(h.length===0)return;if(Date.now()<J){h=[];return}let e=(()=>{try{return s()}catch{return null}})();if(!e){h=[];return}let t=ge();try{let n=await fetch(le,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.token}`},body:JSON.stringify({events:t})});if(n.status===429){let a=n.headers.get("Retry-After"),o=a?parseInt(a,10):NaN,r=Number.isFinite(o)&&o>0?o*1e3:Fe;J=Date.now()+r}}catch{}}function de(){if(h.length===0)return;if(Date.now()<J){h=[];return}let e=null;try{e=s()}catch{h=[];return}let t=ge();try{fetch(le,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e.token}`},body:JSON.stringify({events:t}),keepalive:!0})}catch{}}function qe(e){try{let t=s();ue({releaseId:t.releaseId,url:location.href,userAgent:navigator.userAgent,timestamp:Date.now(),type:"error",message:e.message||"Unknown error",stack:e.error?.stack??"",source:e.filename||void 0,line:typeof e.lineno=="number"?e.lineno:void 0,column:typeof e.colno=="number"?e.colno:void 0,breadcrumbs:F()})}catch{}}function Je(e){try{let t=s(),n=e.reason,a,o="";n&&typeof n=="object"?(a=n.message||String(n),o=n.stack??""):a=String(n??"Unhandled rejection"),ue({releaseId:t.releaseId,url:location.href,userAgent:navigator.userAgent,timestamp:Date.now(),type:"unhandledrejection",message:a,stack:o,breadcrumbs:F()})}catch{}}function Ze(){if(se||typeof window>"u")return;let e;try{e=s()}catch{return}if(e.telemetry?.errors===!1)return;se=!0,Y({captureResponseBodies:!!e.telemetryCaptureResponseBodies}),window.addEventListener("error",qe),window.addEventListener("unhandledrejection",Je);let t=()=>{ce=!0,de()};window.addEventListener("pagehide",t),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&de()})}function fe(){try{Ze()}catch{}}var O;function s(){if(O)return O;let e=globalThis.__MINDSTUDIO__;if(!e)throw new l("@mindstudio-ai/interface requires the MindStudio platform context. This page must be loaded inside MindStudio (window.__MINDSTUDIO__ is missing).","not_initialized");if(!e.token||!e.releaseId||!e.methods){let t=["token","releaseId","methods"].filter(n=>!e[n]).join(", ");throw new l(`MindStudio platform context is incomplete. Missing: ${t}`,"invalid_config")}return O=e,fe(),ie(),O}function me(e){let t=s();e.token!==void 0&&(t.token=e.token),e.user!==void 0&&(t.user=e.user),e.methods!==void 0&&(t.methods=e.methods),e.visitorId!==void 0&&(t.visitorId=e.visitorId)}function ze(){return new Proxy({},{get(e,t){return async(n,a)=>{let o=s(),r=o.methods[t];if(!r)throw new l(`Method "${t}" not found. Available methods: ${Object.keys(o.methods).join(", ")||"(none)"}`,"method_not_found");let i=`/_/methods/${r}/invoke`,c=a?.stream===!0,d=await fetch(i,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o.token}`},body:JSON.stringify({input:n??{},...c&&{stream:!0}})});if(!d.ok){let T=`Method "${t}" failed: ${d.status} ${d.statusText}`,S="method_error";try{let p=await d.json();p.error&&(T=p.error),p.code&&(S=p.code)}catch{}throw new l(T,S,d.status)}if(!c)return(await d.json()).output;let g=d.body.getReader(),u=new TextDecoder,m="",v,E;for(;;){let{done:T,value:S}=await g.read();if(T)break;m+=u.decode(S,{stream:!0});let p=m.split(`
|
|
3
|
+
`);m=p.pop()??"";for(let A of p){if(!A.startsWith("data: "))continue;let R=A.slice(6);try{let f=JSON.parse(R);f.type==="token"&&a?.onToken&&f.text?a.onToken(f.text):f.type==="data"&&a?.onStreamData?a.onStreamData(f.data):f.type==="error"&&f.error?(E=f.error,a?.onStreamError&&a.onStreamError(f.error)):f.type==="done"&&(v=f.output)}catch{}}}if(v===void 0&&E!==void 0)throw new l(E,"method_error");if(v===void 0)throw new l("Stream ended without a done event","stream_incomplete");return v}}})}var pe="/_/agent";async function M(e,t,n){let o={Authorization:`Bearer ${s().token}`};n!==void 0&&(o["Content-Type"]="application/json");let r=await fetch(`${pe}${e}`,{method:t,headers:o,...n!==void 0&&{body:JSON.stringify(n)}});if(!r.ok){let i=`Agent chat request failed: ${r.status} ${r.statusText}`,c="agent_chat_error";try{let d=await r.json();d.error&&(i=d.error),d.code&&(c=d.code)}catch{}throw new l(i,c,r.status)}return await r.json()}function Xe(e,t){switch(t.onEvent?.(e),e.type){case"text":t.onText?.(e.text);break;case"thinking":t.onThinking?.(e.text);break;case"thinking_complete":t.onThinkingComplete?.(e.thinking,e.signature);break;case"tool_call_start":t.onToolCallStart?.(e.id,e.name);break;case"tool_call_result":t.onToolCallResult?.(e.id,e.output);break;case"error":t.onError?.(e.error);break}}function Ye(){return{createThread(){return M("/threads","POST")},listThreads(e){let t=e?`?cursor=${encodeURIComponent(e)}`:"";return M(`/threads${t}`,"GET")},getThread(e){return M(`/threads/${e}`,"GET")},async updateThread(e,t){await M(`/threads/${e}`,"PATCH",{title:t})},async deleteThread(e){await M(`/threads/${e}`,"DELETE")},sendMessage(e,t,n,a){let o=new AbortController,r=n??{};r.signal&&(r.signal.aborted?o.abort():r.signal.addEventListener("abort",()=>o.abort(),{once:!0}));let c=(async()=>{let d=s(),g=`${pe}/threads/${e}/messages`,u=await fetch(g,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${d.token}`},body:JSON.stringify({content:t,...a?.attachments?.length&&{attachments:a.attachments}}),signal:o.signal});if(!u.ok){let S=`Send message failed: ${u.status} ${u.statusText}`,p="agent_chat_error";try{let A=await u.json();A.error&&(S=A.error),A.code&&(p=A.code)}catch{}throw new l(S,p,u.status)}let m=u.body.getReader(),v=new TextDecoder,E="",T;for(;;){let{done:S,value:p}=await m.read();if(S)break;E+=v.decode(p,{stream:!0});let A=E.split(`
|
|
4
|
+
`);E=A.pop()??"";for(let R of A){if(!R.startsWith("data: "))continue;let f=R.slice(6);try{let I=JSON.parse(f);I.type==="done"&&(T={stopReason:I.stopReason,usage:I.usage}),Xe(I,r)}catch{}}}if(!T)throw new l("Stream ended without a done event","stream_incomplete");return T})();return c.abort=()=>o.abort(),c}}}var We={async uploadFile(e,t){let n=s(),{onProgress:a,signal:o}=t??{};o?.throwIfAborted();let i=await fetch("/_/generate-upload-request",{method:"POST",headers:{Authorization:`Bearer ${n.token}`,"Content-Type":"application/json"},body:JSON.stringify({filename:e.name,contentType:e.type||"application/octet-stream"}),signal:o});if(!i.ok)throw new l(`Upload presign failed: ${i.status} ${i.statusText}`,"upload_error",i.status);let{uploadUrl:c,uploadFields:d,publicUrl:g}=await i.json(),u=new FormData;for(let[v,E]of Object.entries(d))u.append(v,E);if(u.append("file",e),a)return await Qe(c,u,a,o),g;let m=await fetch(c,{method:"POST",body:u,signal:o});if(!m.ok)throw new l(`File upload failed: ${m.status} ${m.statusText}`,"upload_error",m.status);return g}};function Qe(e,t,n,a){return new Promise((o,r)=>{let i=new XMLHttpRequest;if(i.upload.addEventListener("progress",c=>{c.lengthComputable&&n(c.loaded/c.total)}),i.addEventListener("load",()=>{i.status>=200&&i.status<300?(n(1),o()):r(new l(`File upload failed: ${i.status} ${i.statusText}`,"upload_error",i.status))}),i.addEventListener("error",()=>{r(new l("File upload failed: network error","upload_error"))}),i.addEventListener("abort",()=>{r(new DOMException("Upload aborted","AbortError"))}),a){if(a.aborted){r(new DOMException("Upload aborted","AbortError"));return}a.addEventListener("abort",()=>i.abort(),{once:!0})}i.open("POST",e),i.send(t)})}var D=[{code:"AF",dialCode:"+93",name:"Afghanistan",flag:"\u{1F1E6}\u{1F1EB}"},{code:"AL",dialCode:"+355",name:"Albania",flag:"\u{1F1E6}\u{1F1F1}"},{code:"DZ",dialCode:"+213",name:"Algeria",flag:"\u{1F1E9}\u{1F1FF}"},{code:"AD",dialCode:"+376",name:"Andorra",flag:"\u{1F1E6}\u{1F1E9}"},{code:"AO",dialCode:"+244",name:"Angola",flag:"\u{1F1E6}\u{1F1F4}"},{code:"AG",dialCode:"+1",name:"Antigua and Barbuda",flag:"\u{1F1E6}\u{1F1EC}"},{code:"AR",dialCode:"+54",name:"Argentina",flag:"\u{1F1E6}\u{1F1F7}"},{code:"AM",dialCode:"+374",name:"Armenia",flag:"\u{1F1E6}\u{1F1F2}"},{code:"AU",dialCode:"+61",name:"Australia",flag:"\u{1F1E6}\u{1F1FA}"},{code:"AT",dialCode:"+43",name:"Austria",flag:"\u{1F1E6}\u{1F1F9}"},{code:"AZ",dialCode:"+994",name:"Azerbaijan",flag:"\u{1F1E6}\u{1F1FF}"},{code:"BS",dialCode:"+1",name:"Bahamas",flag:"\u{1F1E7}\u{1F1F8}"},{code:"BH",dialCode:"+973",name:"Bahrain",flag:"\u{1F1E7}\u{1F1ED}"},{code:"BD",dialCode:"+880",name:"Bangladesh",flag:"\u{1F1E7}\u{1F1E9}"},{code:"BB",dialCode:"+1",name:"Barbados",flag:"\u{1F1E7}\u{1F1E7}"},{code:"BY",dialCode:"+375",name:"Belarus",flag:"\u{1F1E7}\u{1F1FE}"},{code:"BE",dialCode:"+32",name:"Belgium",flag:"\u{1F1E7}\u{1F1EA}"},{code:"BZ",dialCode:"+501",name:"Belize",flag:"\u{1F1E7}\u{1F1FF}"},{code:"BJ",dialCode:"+229",name:"Benin",flag:"\u{1F1E7}\u{1F1EF}"},{code:"BT",dialCode:"+975",name:"Bhutan",flag:"\u{1F1E7}\u{1F1F9}"},{code:"BO",dialCode:"+591",name:"Bolivia",flag:"\u{1F1E7}\u{1F1F4}"},{code:"BA",dialCode:"+387",name:"Bosnia and Herzegovina",flag:"\u{1F1E7}\u{1F1E6}"},{code:"BW",dialCode:"+267",name:"Botswana",flag:"\u{1F1E7}\u{1F1FC}"},{code:"BR",dialCode:"+55",name:"Brazil",flag:"\u{1F1E7}\u{1F1F7}"},{code:"BN",dialCode:"+673",name:"Brunei",flag:"\u{1F1E7}\u{1F1F3}"},{code:"BG",dialCode:"+359",name:"Bulgaria",flag:"\u{1F1E7}\u{1F1EC}"},{code:"BF",dialCode:"+226",name:"Burkina Faso",flag:"\u{1F1E7}\u{1F1EB}"},{code:"BI",dialCode:"+257",name:"Burundi",flag:"\u{1F1E7}\u{1F1EE}"},{code:"CV",dialCode:"+238",name:"Cabo Verde",flag:"\u{1F1E8}\u{1F1FB}"},{code:"KH",dialCode:"+855",name:"Cambodia",flag:"\u{1F1F0}\u{1F1ED}"},{code:"CM",dialCode:"+237",name:"Cameroon",flag:"\u{1F1E8}\u{1F1F2}"},{code:"CA",dialCode:"+1",name:"Canada",flag:"\u{1F1E8}\u{1F1E6}"},{code:"CF",dialCode:"+236",name:"Central African Republic",flag:"\u{1F1E8}\u{1F1EB}"},{code:"TD",dialCode:"+235",name:"Chad",flag:"\u{1F1F9}\u{1F1E9}"},{code:"CL",dialCode:"+56",name:"Chile",flag:"\u{1F1E8}\u{1F1F1}"},{code:"CN",dialCode:"+86",name:"China",flag:"\u{1F1E8}\u{1F1F3}"},{code:"CO",dialCode:"+57",name:"Colombia",flag:"\u{1F1E8}\u{1F1F4}"},{code:"KM",dialCode:"+269",name:"Comoros",flag:"\u{1F1F0}\u{1F1F2}"},{code:"CG",dialCode:"+242",name:"Congo",flag:"\u{1F1E8}\u{1F1EC}"},{code:"CD",dialCode:"+243",name:"Congo (DRC)",flag:"\u{1F1E8}\u{1F1E9}"},{code:"CR",dialCode:"+506",name:"Costa Rica",flag:"\u{1F1E8}\u{1F1F7}"},{code:"HR",dialCode:"+385",name:"Croatia",flag:"\u{1F1ED}\u{1F1F7}"},{code:"CU",dialCode:"+53",name:"Cuba",flag:"\u{1F1E8}\u{1F1FA}"},{code:"CY",dialCode:"+357",name:"Cyprus",flag:"\u{1F1E8}\u{1F1FE}"},{code:"CZ",dialCode:"+420",name:"Czechia",flag:"\u{1F1E8}\u{1F1FF}"},{code:"CI",dialCode:"+225",name:"Cote d'Ivoire",flag:"\u{1F1E8}\u{1F1EE}"},{code:"DK",dialCode:"+45",name:"Denmark",flag:"\u{1F1E9}\u{1F1F0}"},{code:"DJ",dialCode:"+253",name:"Djibouti",flag:"\u{1F1E9}\u{1F1EF}"},{code:"DM",dialCode:"+1",name:"Dominica",flag:"\u{1F1E9}\u{1F1F2}"},{code:"DO",dialCode:"+1",name:"Dominican Republic",flag:"\u{1F1E9}\u{1F1F4}"},{code:"EC",dialCode:"+593",name:"Ecuador",flag:"\u{1F1EA}\u{1F1E8}"},{code:"EG",dialCode:"+20",name:"Egypt",flag:"\u{1F1EA}\u{1F1EC}"},{code:"SV",dialCode:"+503",name:"El Salvador",flag:"\u{1F1F8}\u{1F1FB}"},{code:"GQ",dialCode:"+240",name:"Equatorial Guinea",flag:"\u{1F1EC}\u{1F1F6}"},{code:"ER",dialCode:"+291",name:"Eritrea",flag:"\u{1F1EA}\u{1F1F7}"},{code:"EE",dialCode:"+372",name:"Estonia",flag:"\u{1F1EA}\u{1F1EA}"},{code:"SZ",dialCode:"+268",name:"Eswatini",flag:"\u{1F1F8}\u{1F1FF}"},{code:"ET",dialCode:"+251",name:"Ethiopia",flag:"\u{1F1EA}\u{1F1F9}"},{code:"FJ",dialCode:"+679",name:"Fiji",flag:"\u{1F1EB}\u{1F1EF}"},{code:"FI",dialCode:"+358",name:"Finland",flag:"\u{1F1EB}\u{1F1EE}"},{code:"FR",dialCode:"+33",name:"France",flag:"\u{1F1EB}\u{1F1F7}"},{code:"GA",dialCode:"+241",name:"Gabon",flag:"\u{1F1EC}\u{1F1E6}"},{code:"GM",dialCode:"+220",name:"Gambia",flag:"\u{1F1EC}\u{1F1F2}"},{code:"GE",dialCode:"+995",name:"Georgia",flag:"\u{1F1EC}\u{1F1EA}"},{code:"DE",dialCode:"+49",name:"Germany",flag:"\u{1F1E9}\u{1F1EA}"},{code:"GH",dialCode:"+233",name:"Ghana",flag:"\u{1F1EC}\u{1F1ED}"},{code:"GR",dialCode:"+30",name:"Greece",flag:"\u{1F1EC}\u{1F1F7}"},{code:"GD",dialCode:"+1",name:"Grenada",flag:"\u{1F1EC}\u{1F1E9}"},{code:"GT",dialCode:"+502",name:"Guatemala",flag:"\u{1F1EC}\u{1F1F9}"},{code:"GN",dialCode:"+224",name:"Guinea",flag:"\u{1F1EC}\u{1F1F3}"},{code:"GW",dialCode:"+245",name:"Guinea-Bissau",flag:"\u{1F1EC}\u{1F1FC}"},{code:"GY",dialCode:"+592",name:"Guyana",flag:"\u{1F1EC}\u{1F1FE}"},{code:"HT",dialCode:"+509",name:"Haiti",flag:"\u{1F1ED}\u{1F1F9}"},{code:"HN",dialCode:"+504",name:"Honduras",flag:"\u{1F1ED}\u{1F1F3}"},{code:"HK",dialCode:"+852",name:"Hong Kong",flag:"\u{1F1ED}\u{1F1F0}"},{code:"HU",dialCode:"+36",name:"Hungary",flag:"\u{1F1ED}\u{1F1FA}"},{code:"IS",dialCode:"+354",name:"Iceland",flag:"\u{1F1EE}\u{1F1F8}"},{code:"IN",dialCode:"+91",name:"India",flag:"\u{1F1EE}\u{1F1F3}"},{code:"ID",dialCode:"+62",name:"Indonesia",flag:"\u{1F1EE}\u{1F1E9}"},{code:"IR",dialCode:"+98",name:"Iran",flag:"\u{1F1EE}\u{1F1F7}"},{code:"IQ",dialCode:"+964",name:"Iraq",flag:"\u{1F1EE}\u{1F1F6}"},{code:"IE",dialCode:"+353",name:"Ireland",flag:"\u{1F1EE}\u{1F1EA}"},{code:"IL",dialCode:"+972",name:"Israel",flag:"\u{1F1EE}\u{1F1F1}"},{code:"IT",dialCode:"+39",name:"Italy",flag:"\u{1F1EE}\u{1F1F9}"},{code:"JM",dialCode:"+1",name:"Jamaica",flag:"\u{1F1EF}\u{1F1F2}"},{code:"JP",dialCode:"+81",name:"Japan",flag:"\u{1F1EF}\u{1F1F5}"},{code:"JO",dialCode:"+962",name:"Jordan",flag:"\u{1F1EF}\u{1F1F4}"},{code:"KZ",dialCode:"+7",name:"Kazakhstan",flag:"\u{1F1F0}\u{1F1FF}"},{code:"KE",dialCode:"+254",name:"Kenya",flag:"\u{1F1F0}\u{1F1EA}"},{code:"KI",dialCode:"+686",name:"Kiribati",flag:"\u{1F1F0}\u{1F1EE}"},{code:"KW",dialCode:"+965",name:"Kuwait",flag:"\u{1F1F0}\u{1F1FC}"},{code:"KG",dialCode:"+996",name:"Kyrgyzstan",flag:"\u{1F1F0}\u{1F1EC}"},{code:"LA",dialCode:"+856",name:"Laos",flag:"\u{1F1F1}\u{1F1E6}"},{code:"LV",dialCode:"+371",name:"Latvia",flag:"\u{1F1F1}\u{1F1FB}"},{code:"LB",dialCode:"+961",name:"Lebanon",flag:"\u{1F1F1}\u{1F1E7}"},{code:"LS",dialCode:"+266",name:"Lesotho",flag:"\u{1F1F1}\u{1F1F8}"},{code:"LR",dialCode:"+231",name:"Liberia",flag:"\u{1F1F1}\u{1F1F7}"},{code:"LY",dialCode:"+218",name:"Libya",flag:"\u{1F1F1}\u{1F1FE}"},{code:"LI",dialCode:"+423",name:"Liechtenstein",flag:"\u{1F1F1}\u{1F1EE}"},{code:"LT",dialCode:"+370",name:"Lithuania",flag:"\u{1F1F1}\u{1F1F9}"},{code:"LU",dialCode:"+352",name:"Luxembourg",flag:"\u{1F1F1}\u{1F1FA}"},{code:"MO",dialCode:"+853",name:"Macao",flag:"\u{1F1F2}\u{1F1F4}"},{code:"MG",dialCode:"+261",name:"Madagascar",flag:"\u{1F1F2}\u{1F1EC}"},{code:"MW",dialCode:"+265",name:"Malawi",flag:"\u{1F1F2}\u{1F1FC}"},{code:"MY",dialCode:"+60",name:"Malaysia",flag:"\u{1F1F2}\u{1F1FE}"},{code:"MV",dialCode:"+960",name:"Maldives",flag:"\u{1F1F2}\u{1F1FB}"},{code:"ML",dialCode:"+223",name:"Mali",flag:"\u{1F1F2}\u{1F1F1}"},{code:"MT",dialCode:"+356",name:"Malta",flag:"\u{1F1F2}\u{1F1F9}"},{code:"MH",dialCode:"+692",name:"Marshall Islands",flag:"\u{1F1F2}\u{1F1ED}"},{code:"MR",dialCode:"+222",name:"Mauritania",flag:"\u{1F1F2}\u{1F1F7}"},{code:"MU",dialCode:"+230",name:"Mauritius",flag:"\u{1F1F2}\u{1F1FA}"},{code:"MX",dialCode:"+52",name:"Mexico",flag:"\u{1F1F2}\u{1F1FD}"},{code:"FM",dialCode:"+691",name:"Micronesia",flag:"\u{1F1EB}\u{1F1F2}"},{code:"MD",dialCode:"+373",name:"Moldova",flag:"\u{1F1F2}\u{1F1E9}"},{code:"MC",dialCode:"+377",name:"Monaco",flag:"\u{1F1F2}\u{1F1E8}"},{code:"MN",dialCode:"+976",name:"Mongolia",flag:"\u{1F1F2}\u{1F1F3}"},{code:"ME",dialCode:"+382",name:"Montenegro",flag:"\u{1F1F2}\u{1F1EA}"},{code:"MA",dialCode:"+212",name:"Morocco",flag:"\u{1F1F2}\u{1F1E6}"},{code:"MZ",dialCode:"+258",name:"Mozambique",flag:"\u{1F1F2}\u{1F1FF}"},{code:"MM",dialCode:"+95",name:"Myanmar",flag:"\u{1F1F2}\u{1F1F2}"},{code:"NA",dialCode:"+264",name:"Namibia",flag:"\u{1F1F3}\u{1F1E6}"},{code:"NR",dialCode:"+674",name:"Nauru",flag:"\u{1F1F3}\u{1F1F7}"},{code:"NP",dialCode:"+977",name:"Nepal",flag:"\u{1F1F3}\u{1F1F5}"},{code:"NL",dialCode:"+31",name:"Netherlands",flag:"\u{1F1F3}\u{1F1F1}"},{code:"NZ",dialCode:"+64",name:"New Zealand",flag:"\u{1F1F3}\u{1F1FF}"},{code:"NI",dialCode:"+505",name:"Nicaragua",flag:"\u{1F1F3}\u{1F1EE}"},{code:"NE",dialCode:"+227",name:"Niger",flag:"\u{1F1F3}\u{1F1EA}"},{code:"NG",dialCode:"+234",name:"Nigeria",flag:"\u{1F1F3}\u{1F1EC}"},{code:"KP",dialCode:"+850",name:"North Korea",flag:"\u{1F1F0}\u{1F1F5}"},{code:"MK",dialCode:"+389",name:"North Macedonia",flag:"\u{1F1F2}\u{1F1F0}"},{code:"NO",dialCode:"+47",name:"Norway",flag:"\u{1F1F3}\u{1F1F4}"},{code:"OM",dialCode:"+968",name:"Oman",flag:"\u{1F1F4}\u{1F1F2}"},{code:"PK",dialCode:"+92",name:"Pakistan",flag:"\u{1F1F5}\u{1F1F0}"},{code:"PW",dialCode:"+680",name:"Palau",flag:"\u{1F1F5}\u{1F1FC}"},{code:"PS",dialCode:"+970",name:"Palestine",flag:"\u{1F1F5}\u{1F1F8}"},{code:"PA",dialCode:"+507",name:"Panama",flag:"\u{1F1F5}\u{1F1E6}"},{code:"PG",dialCode:"+675",name:"Papua New Guinea",flag:"\u{1F1F5}\u{1F1EC}"},{code:"PY",dialCode:"+595",name:"Paraguay",flag:"\u{1F1F5}\u{1F1FE}"},{code:"PE",dialCode:"+51",name:"Peru",flag:"\u{1F1F5}\u{1F1EA}"},{code:"PH",dialCode:"+63",name:"Philippines",flag:"\u{1F1F5}\u{1F1ED}"},{code:"PL",dialCode:"+48",name:"Poland",flag:"\u{1F1F5}\u{1F1F1}"},{code:"PT",dialCode:"+351",name:"Portugal",flag:"\u{1F1F5}\u{1F1F9}"},{code:"PR",dialCode:"+1",name:"Puerto Rico",flag:"\u{1F1F5}\u{1F1F7}"},{code:"QA",dialCode:"+974",name:"Qatar",flag:"\u{1F1F6}\u{1F1E6}"},{code:"RO",dialCode:"+40",name:"Romania",flag:"\u{1F1F7}\u{1F1F4}"},{code:"RU",dialCode:"+7",name:"Russia",flag:"\u{1F1F7}\u{1F1FA}"},{code:"RW",dialCode:"+250",name:"Rwanda",flag:"\u{1F1F7}\u{1F1FC}"},{code:"KN",dialCode:"+1",name:"Saint Kitts and Nevis",flag:"\u{1F1F0}\u{1F1F3}"},{code:"LC",dialCode:"+1",name:"Saint Lucia",flag:"\u{1F1F1}\u{1F1E8}"},{code:"VC",dialCode:"+1",name:"Saint Vincent and the Grenadines",flag:"\u{1F1FB}\u{1F1E8}"},{code:"WS",dialCode:"+685",name:"Samoa",flag:"\u{1F1FC}\u{1F1F8}"},{code:"SM",dialCode:"+378",name:"San Marino",flag:"\u{1F1F8}\u{1F1F2}"},{code:"ST",dialCode:"+239",name:"Sao Tome and Principe",flag:"\u{1F1F8}\u{1F1F9}"},{code:"SA",dialCode:"+966",name:"Saudi Arabia",flag:"\u{1F1F8}\u{1F1E6}"},{code:"SN",dialCode:"+221",name:"Senegal",flag:"\u{1F1F8}\u{1F1F3}"},{code:"RS",dialCode:"+381",name:"Serbia",flag:"\u{1F1F7}\u{1F1F8}"},{code:"SC",dialCode:"+248",name:"Seychelles",flag:"\u{1F1F8}\u{1F1E8}"},{code:"SL",dialCode:"+232",name:"Sierra Leone",flag:"\u{1F1F8}\u{1F1F1}"},{code:"SG",dialCode:"+65",name:"Singapore",flag:"\u{1F1F8}\u{1F1EC}"},{code:"SK",dialCode:"+421",name:"Slovakia",flag:"\u{1F1F8}\u{1F1F0}"},{code:"SI",dialCode:"+386",name:"Slovenia",flag:"\u{1F1F8}\u{1F1EE}"},{code:"SB",dialCode:"+677",name:"Solomon Islands",flag:"\u{1F1F8}\u{1F1E7}"},{code:"SO",dialCode:"+252",name:"Somalia",flag:"\u{1F1F8}\u{1F1F4}"},{code:"ZA",dialCode:"+27",name:"South Africa",flag:"\u{1F1FF}\u{1F1E6}"},{code:"KR",dialCode:"+82",name:"South Korea",flag:"\u{1F1F0}\u{1F1F7}"},{code:"SS",dialCode:"+211",name:"South Sudan",flag:"\u{1F1F8}\u{1F1F8}"},{code:"ES",dialCode:"+34",name:"Spain",flag:"\u{1F1EA}\u{1F1F8}"},{code:"LK",dialCode:"+94",name:"Sri Lanka",flag:"\u{1F1F1}\u{1F1F0}"},{code:"SD",dialCode:"+249",name:"Sudan",flag:"\u{1F1F8}\u{1F1E9}"},{code:"SR",dialCode:"+597",name:"Suriname",flag:"\u{1F1F8}\u{1F1F7}"},{code:"SE",dialCode:"+46",name:"Sweden",flag:"\u{1F1F8}\u{1F1EA}"},{code:"CH",dialCode:"+41",name:"Switzerland",flag:"\u{1F1E8}\u{1F1ED}"},{code:"SY",dialCode:"+963",name:"Syria",flag:"\u{1F1F8}\u{1F1FE}"},{code:"TW",dialCode:"+886",name:"Taiwan",flag:"\u{1F1F9}\u{1F1FC}"},{code:"TJ",dialCode:"+992",name:"Tajikistan",flag:"\u{1F1F9}\u{1F1EF}"},{code:"TZ",dialCode:"+255",name:"Tanzania",flag:"\u{1F1F9}\u{1F1FF}"},{code:"TH",dialCode:"+66",name:"Thailand",flag:"\u{1F1F9}\u{1F1ED}"},{code:"TL",dialCode:"+670",name:"Timor-Leste",flag:"\u{1F1F9}\u{1F1F1}"},{code:"TG",dialCode:"+228",name:"Togo",flag:"\u{1F1F9}\u{1F1EC}"},{code:"TO",dialCode:"+676",name:"Tonga",flag:"\u{1F1F9}\u{1F1F4}"},{code:"TT",dialCode:"+1",name:"Trinidad and Tobago",flag:"\u{1F1F9}\u{1F1F9}"},{code:"TN",dialCode:"+216",name:"Tunisia",flag:"\u{1F1F9}\u{1F1F3}"},{code:"TR",dialCode:"+90",name:"Turkey",flag:"\u{1F1F9}\u{1F1F7}"},{code:"TM",dialCode:"+993",name:"Turkmenistan",flag:"\u{1F1F9}\u{1F1F2}"},{code:"TV",dialCode:"+688",name:"Tuvalu",flag:"\u{1F1F9}\u{1F1FB}"},{code:"UG",dialCode:"+256",name:"Uganda",flag:"\u{1F1FA}\u{1F1EC}"},{code:"UA",dialCode:"+380",name:"Ukraine",flag:"\u{1F1FA}\u{1F1E6}"},{code:"AE",dialCode:"+971",name:"United Arab Emirates",flag:"\u{1F1E6}\u{1F1EA}"},{code:"GB",dialCode:"+44",name:"United Kingdom",flag:"\u{1F1EC}\u{1F1E7}"},{code:"US",dialCode:"+1",name:"United States",flag:"\u{1F1FA}\u{1F1F8}"},{code:"UY",dialCode:"+598",name:"Uruguay",flag:"\u{1F1FA}\u{1F1FE}"},{code:"UZ",dialCode:"+998",name:"Uzbekistan",flag:"\u{1F1FA}\u{1F1FF}"},{code:"VU",dialCode:"+678",name:"Vanuatu",flag:"\u{1F1FB}\u{1F1FA}"},{code:"VA",dialCode:"+39",name:"Vatican City",flag:"\u{1F1FB}\u{1F1E6}"},{code:"VE",dialCode:"+58",name:"Venezuela",flag:"\u{1F1FB}\u{1F1EA}"},{code:"VN",dialCode:"+84",name:"Vietnam",flag:"\u{1F1FB}\u{1F1F3}"},{code:"YE",dialCode:"+967",name:"Yemen",flag:"\u{1F1FE}\u{1F1EA}"},{code:"ZM",dialCode:"+260",name:"Zambia",flag:"\u{1F1FF}\u{1F1F2}"},{code:"ZW",dialCode:"+263",name:"Zimbabwe",flag:"\u{1F1FF}\u{1F1FC}"}],et=new Map(D.map(e=>[e.code,e])),tt={"America/New_York":"US","America/Chicago":"US","America/Denver":"US","America/Los_Angeles":"US","America/Anchorage":"US","Pacific/Honolulu":"US","America/Phoenix":"US","America/Indiana/Indianapolis":"US","America/Toronto":"CA","America/Vancouver":"CA","America/Edmonton":"CA","America/Winnipeg":"CA","America/Halifax":"CA","America/St_Johns":"CA","Europe/London":"GB","Europe/Dublin":"IE","Europe/Paris":"FR","Europe/Berlin":"DE","Europe/Madrid":"ES","Europe/Rome":"IT","Europe/Amsterdam":"NL","Europe/Brussels":"BE","Europe/Zurich":"CH","Europe/Vienna":"AT","Europe/Stockholm":"SE","Europe/Oslo":"NO","Europe/Copenhagen":"DK","Europe/Helsinki":"FI","Europe/Warsaw":"PL","Europe/Prague":"CZ","Europe/Bucharest":"RO","Europe/Budapest":"HU","Europe/Athens":"GR","Europe/Istanbul":"TR","Europe/Moscow":"RU","Europe/Kiev":"UA","Europe/Lisbon":"PT","Europe/Belgrade":"RS","Europe/Zagreb":"HR","Europe/Bratislava":"SK","Europe/Ljubljana":"SI","Europe/Tallinn":"EE","Europe/Riga":"LV","Europe/Vilnius":"LT","Asia/Tokyo":"JP","Asia/Seoul":"KR","Asia/Shanghai":"CN","Asia/Hong_Kong":"HK","Asia/Taipei":"TW","Asia/Singapore":"SG","Asia/Kolkata":"IN","Asia/Karachi":"PK","Asia/Dhaka":"BD","Asia/Bangkok":"TH","Asia/Jakarta":"ID","Asia/Manila":"PH","Asia/Kuala_Lumpur":"MY","Asia/Ho_Chi_Minh":"VN","Asia/Riyadh":"SA","Asia/Dubai":"AE","Asia/Tehran":"IR","Asia/Baghdad":"IQ","Asia/Beirut":"LB","Asia/Jerusalem":"IL","Asia/Amman":"JO","Asia/Almaty":"KZ","Asia/Tashkent":"UZ","Asia/Colombo":"LK","Asia/Kathmandu":"NP","Asia/Yangon":"MM","Australia/Sydney":"AU","Australia/Melbourne":"AU","Australia/Brisbane":"AU","Australia/Perth":"AU","Australia/Adelaide":"AU","Pacific/Auckland":"NZ","Pacific/Fiji":"FJ","Africa/Cairo":"EG","Africa/Lagos":"NG","Africa/Nairobi":"KE","Africa/Johannesburg":"ZA","Africa/Casablanca":"MA","Africa/Accra":"GH","Africa/Addis_Ababa":"ET","Africa/Dar_es_Salaam":"TZ","Africa/Kampala":"UG","America/Mexico_City":"MX","America/Bogota":"CO","America/Lima":"PE","America/Santiago":"CL","America/Buenos_Aires":"AR","America/Sao_Paulo":"BR","America/Caracas":"VE","America/Guatemala":"GT","America/Havana":"CU","America/Panama":"PA","America/Jamaica":"JM"};function he(){try{let e=Intl.DateTimeFormat().resolvedOptions().timeZone;return tt[e]??"US"}catch{return"US"}}function Ce(e){if(!e.startsWith("+"))return e;let t=e.slice(1);if(t.startsWith("1")&&t.length===11){let n=t.slice(1,4),a=t.slice(4,7),o=t.slice(7);return`+1 (${n}) ${a}-${o}`}for(let n=4;n>=1;n--){let a="+"+t.slice(0,n),o=D.find(r=>r.dialCode===a);if(o){let r=t.slice(n);return`${o.dialCode} ${r}`}}return e}function ye(e,t){let n=e.replace(/\D/g,""),a=et.get(t);if(!a)return"+"+n;let o=a.dialCode.slice(1);return n.startsWith(o)?"+"+n:a.dialCode+n}function Ae(e){return/^\+[1-9]\d{6,14}$/.test(e)}function Ee(e){return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)}async function y(e,t,n){let o={Authorization:`Bearer ${s().token}`};n!==void 0&&(o["Content-Type"]="application/json");let r=await fetch(e,{method:t,headers:o,...n!==void 0&&{body:JSON.stringify(n)}});if(!r.ok){let i=`Auth request failed: ${r.status} ${r.statusText}`,c="auth_error";try{let d=await r.json();d.error&&(i=d.error),d.code&&(c=d.code)}catch{}throw new l(i,c,r.status)}return await r.json()}var G=new Set;function P(e){me({token:e.token,user:e.user,methods:e.methods,visitorId:e.visitorId}),G.forEach(t=>t(e.user))}function H(e){if(!e.user)throw new l("Verification succeeded but no user was returned","auth_error");return e.user}function Te(e){let t=s();t.user&&(Object.assign(t.user,e),G.forEach(n=>n(t.user)))}var ot={get currentUser(){return s().user},getCurrentUser(){return s().user},isAuthenticated(){return s().user!==null},get currentVisitorId(){return s().visitorId??null},getCurrentVisitorId(){return s().visitorId??null},sendEmailCode(e){return y("/_/auth/email/send","POST",{email:e})},async verifyEmailCode(e,t){let n=await y("/_/auth/email/verify","POST",{verificationId:e,code:t});return P(n),H(n)},sendSmsCode(e){return y("/_/auth/sms/send","POST",{phone:e})},async verifySmsCode(e,t){let n=await y("/_/auth/sms/verify","POST",{verificationId:e,code:t});return P(n),H(n)},async requestEmailChange(e){await y("/_/auth/email/change","POST",{newEmail:e})},async confirmEmailChange(e,t){let n=await y("/_/auth/email/change/confirm","POST",{newEmail:e,code:t});return P(n),H(n)},async requestPhoneChange(e){await y("/_/auth/phone/change","POST",{newPhone:e})},async confirmPhoneChange(e,t){let n=await y("/_/auth/phone/change/confirm","POST",{newPhone:e,code:t});return P(n),H(n)},async logout(){let e=await y("/_/auth/logout","POST",{});P(e)},async createApiKey(){let e=await y("/_/auth/api-key/create","POST",{});return Te({apiKey:e.apiKey}),{key:e.key}},async revokeApiKey(){await y("/_/auth/api-key/revoke","POST",{}),Te({apiKey:null})},onAuthStateChanged(e){return G.add(e),e(s().user),()=>{G.delete(e)}},phone:{countries:D,detectCountry:he,format:Ce,toE164:ye,isValid:Ae},email:{isValid:Ee}};typeof window<"u"&&globalThis.__MINDSTUDIO__&&setTimeout(()=>{try{s()}catch{}},0);export{l as MindStudioInterfaceError,De as analytics,ot as auth,Ye as createAgentChatClient,ze as createClient,We as platform};
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/telemetry-breadcrumbs.ts","../src/telemetry-analytics.ts","../src/telemetry-errors.ts","../src/config.ts","../src/client.ts","../src/agent-chat.ts","../src/platform.ts","../src/auth-phone.ts","../src/auth-email.ts","../src/auth.ts"],"sourcesContent":["/**\n * Error class for the @mindstudio-ai/interface SDK.\n *\n * Thrown by `createClient()` method calls on HTTP errors, by `platform`\n * actions on failures, and by the config reader when bootstrap globals\n * are missing.\n */\nexport class MindStudioInterfaceError extends Error {\n /** Machine-readable error code (e.g. 'method_not_found', 'not_initialized'). */\n readonly code: string;\n\n /** HTTP status code, when the error originated from an API response. */\n readonly status?: number;\n\n constructor(message: string, code: string, status?: number) {\n super(message);\n this.name = 'MindStudioInterfaceError';\n this.code = code;\n this.status = status;\n }\n}\n","/**\n * Breadcrumbs — a ring buffer of recent navigations + network calls\n * attached to outgoing error reports for debugging context.\n *\n * Installed by `installErrorMonitoring()` in `telemetry-errors.ts`.\n * Three monkeypatches feed the buffer:\n *\n * - `history.pushState`/`replaceState`/`popstate` → `navigation`\n * - `window.fetch` → `fetch`\n * - `XMLHttpRequest.prototype.open`/`send` → `xhr`\n *\n * Each patch is idempotent — guarded by a `__ms_*_patched` flag so\n * re-imports (HMR, double bundle inclusion, etc.) are no-ops.\n *\n * The SDK's own telemetry endpoint is excluded from capture so error\n * reports don't feed themselves through the breadcrumb pipeline.\n */\n\nconst TELEMETRY_ENDPOINT_FRAGMENT = '/_/telemetry/';\nconst MAX_BREADCRUMBS = 20;\nconst MAX_BODY_BYTES = 1024;\n\n/**\n * A single breadcrumb entry. Discriminated union — server validates the\n * `type` field; unknown types are dropped at ingest.\n */\nexport type Breadcrumb =\n | {\n type: 'navigation';\n from: string;\n to: string;\n timestamp: number;\n }\n | {\n type: 'fetch';\n method: string;\n url: string;\n status?: number;\n ok: boolean;\n duration: number;\n timestamp: number;\n error?: string;\n /** Truncated response body for failed requests, when capture is enabled. */\n body?: string;\n }\n | {\n type: 'xhr';\n method: string;\n url: string;\n status?: number;\n ok: boolean;\n duration: number;\n timestamp: number;\n };\n\nconst buffer: Breadcrumb[] = [];\n\nfunction push(entry: Breadcrumb): void {\n buffer.push(entry);\n if (buffer.length > MAX_BREADCRUMBS) {\n buffer.shift();\n }\n}\n\n/**\n * Return a shallow copy of the current breadcrumb buffer.\n * Called when an error is captured to snapshot context at that moment.\n */\nexport function getBreadcrumbs(): Breadcrumb[] {\n return buffer.slice();\n}\n\nfunction shouldSkipUrl(url: string): boolean {\n return url.includes(TELEMETRY_ENDPOINT_FRAGMENT);\n}\n\nfunction resolveUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') {\n return input;\n }\n if (input instanceof URL) {\n return input.href;\n }\n return input.url || String(input);\n}\n\nlet lastHref = '';\n\nconst navListeners = new Set<(url: string) => void>();\n\n/**\n * Subscribe to navigation events. Fires on every history change\n * (`pushState`, `replaceState`, `popstate`, `hashchange`) with the new URL.\n *\n * Used by the analytics module to emit pageview events without\n * installing a second set of history patches.\n *\n * @returns Unsubscribe function.\n */\nexport function onNavigation(cb: (url: string) => void): () => void {\n navListeners.add(cb);\n return () => {\n navListeners.delete(cb);\n };\n}\n\nfunction emitNavigation(to: string): void {\n if (to === lastHref) {\n return;\n }\n push({\n type: 'navigation',\n from: lastHref,\n to,\n timestamp: Date.now(),\n });\n lastHref = to;\n navListeners.forEach((cb) => {\n try {\n cb(to);\n } catch {\n // listener errors must not break navigation\n }\n });\n}\n\nfunction installHistory(): void {\n const w = window as unknown as Record<string, unknown>;\n if (w.__ms_history_patched) {\n return;\n }\n w.__ms_history_patched = true;\n\n lastHref = location.href;\n\n const originalPushState = history.pushState.bind(history);\n history.pushState = function (\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalPushState(data, unused, url);\n try {\n emitNavigation(location.href);\n } catch {\n // never crash navigation\n }\n };\n\n const originalReplaceState = history.replaceState.bind(history);\n history.replaceState = function (\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalReplaceState(data, unused, url);\n try {\n emitNavigation(location.href);\n } catch {\n // never crash navigation\n }\n };\n\n window.addEventListener('popstate', () => {\n try {\n emitNavigation(location.href);\n } catch {\n // swallow\n }\n });\n\n window.addEventListener('hashchange', () => {\n try {\n emitNavigation(location.href);\n } catch {\n // swallow\n }\n });\n}\n\nfunction installFetch(captureResponseBodies: boolean): void {\n if (!window.fetch) {\n return;\n }\n const fetchFn = window.fetch as typeof fetch & { __ms_patched?: boolean };\n if (fetchFn.__ms_patched) {\n return;\n }\n\n const originalFetch = window.fetch.bind(window);\n\n const patched: typeof fetch = function (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> {\n const url = resolveUrl(input);\n\n if (shouldSkipUrl(url)) {\n return originalFetch(input, init);\n }\n\n const method = (\n init?.method ||\n (typeof input !== 'string' && !(input instanceof URL)\n ? input.method\n : '') ||\n 'GET'\n ).toUpperCase();\n const startTime = Date.now();\n\n return originalFetch(input, init).then(\n (response) => {\n const entry: Breadcrumb = {\n type: 'fetch',\n method,\n url,\n status: response.status,\n ok: response.ok,\n duration: Date.now() - startTime,\n timestamp: startTime,\n };\n\n if (!response.ok && captureResponseBodies) {\n try {\n response\n .clone()\n .text()\n .then((body) => {\n entry.body = body.slice(0, MAX_BODY_BYTES);\n push(entry);\n })\n .catch(() => push(entry));\n } catch {\n push(entry);\n }\n } else {\n push(entry);\n }\n\n return response;\n },\n (err: unknown) => {\n push({\n type: 'fetch',\n method,\n url,\n ok: false,\n duration: Date.now() - startTime,\n timestamp: startTime,\n error:\n err instanceof Error ? err.message : String(err ?? 'fetch failed'),\n });\n throw err;\n },\n );\n };\n\n (patched as typeof fetch & { __ms_patched: boolean }).__ms_patched = true;\n window.fetch = patched;\n}\n\nfunction installXhr(): void {\n const openProto = XMLHttpRequest.prototype.open as ((\n ...args: unknown[]\n ) => void) & { __ms_patched?: boolean };\n if (openProto.__ms_patched) {\n return;\n }\n\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (\n this: XMLHttpRequest & {\n __ms_method?: string;\n __ms_url?: string;\n },\n method: string,\n url: string | URL,\n ...rest: unknown[]\n ): void {\n this.__ms_method = (method || 'GET').toUpperCase();\n this.__ms_url = String(url);\n return originalOpen.apply(this, [method, url, ...rest] as Parameters<\n typeof originalOpen\n >);\n } as typeof XMLHttpRequest.prototype.open;\n\n XMLHttpRequest.prototype.send = function (\n this: XMLHttpRequest & {\n __ms_method?: string;\n __ms_url?: string;\n },\n body?: Document | XMLHttpRequestBodyInit | null,\n ): void {\n const method = this.__ms_method || 'GET';\n const url = this.__ms_url || '';\n\n if (shouldSkipUrl(url)) {\n return originalSend.apply(this, [body] as Parameters<\n typeof originalSend\n >);\n }\n\n const startTime = Date.now();\n\n this.addEventListener(\n 'loadend',\n function (this: XMLHttpRequest) {\n push({\n type: 'xhr',\n method,\n url,\n status: this.status,\n ok: this.status >= 200 && this.status < 300,\n duration: Date.now() - startTime,\n timestamp: startTime,\n });\n },\n { once: true },\n );\n\n return originalSend.apply(this, [body] as Parameters<typeof originalSend>);\n } as typeof XMLHttpRequest.prototype.send;\n\n (\n XMLHttpRequest.prototype.open as typeof XMLHttpRequest.prototype.open & {\n __ms_patched: boolean;\n }\n ).__ms_patched = true;\n}\n\nlet _breadcrumbsInstalled = false;\n\n/**\n * Install all three breadcrumb sources. Idempotent.\n *\n * @param opts.captureResponseBodies — when `true`, failed `fetch`\n * responses have their bodies read and attached (truncated to ~1KB).\n * Backend strips this field unless the per-app setting is enabled.\n */\nexport function installBreadcrumbs(opts: {\n captureResponseBodies: boolean;\n}): void {\n if (_breadcrumbsInstalled) {\n return;\n }\n _breadcrumbsInstalled = true;\n\n try {\n installHistory();\n } catch {\n // history patches are best-effort\n }\n try {\n installFetch(opts.captureResponseBodies);\n } catch {\n // fetch patches are best-effort\n }\n try {\n installXhr();\n } catch {\n // xhr patches are best-effort\n }\n}\n","/**\n * Analytics — Plausible/Fathom-style visitor analytics.\n *\n * Auto-tracks pageviews via the existing history patches in\n * `telemetry-breadcrumbs.ts` and exposes a small public API:\n *\n * ```ts\n * import { analytics } from '@mindstudio-ai/interface';\n *\n * // Custom events (optional — pageviews track automatically)\n * analytics.track('vendor_submitted', { vendorType: 'restaurant' });\n * ```\n *\n * Server-side derivation handles geo (IP → country), device class\n * (UA → mobile/tablet/desktop), referrers, UTM parsing, and\n * sessionization. The SDK ships nothing for those — just raw\n * pageview events with enough context for backend enrichment.\n *\n * ## How it works\n *\n * Installed by `maybeInstallAnalytics()` in `config.ts` on the first\n * `getConfig()` call. Once installed:\n *\n * 1. Subscribes to navigation events from `telemetry-breadcrumbs.ts`\n * and emits a pageview on each change.\n * 2. Fires an initial pageview for the first-load URL.\n * 3. Batches events (~1s debounce, 100/batch cap) and POSTs to\n * `/_/telemetry/events`.\n * 4. On `pagehide` / `visibilitychange='hidden'`, drains via\n * `fetch` with `keepalive: true`.\n * 5. On `429`, pauses sends for the `Retry-After` window.\n *\n * ## Privacy posture\n *\n * Live visitor counts are intentionally **not** exposed to app code.\n * Aggregate visitor metrics (live count included) are surfaced only\n * through the platform dashboard to the app owner — visitors should\n * not be able to learn about other visitors' presence through the\n * SDK. If an app explicitly wants user-facing presence as a designed\n * feature (e.g. a multiplayer experience), it must build that on its\n * own application-level abstraction with its own consent semantics,\n * not on platform telemetry.\n *\n * Opt-out via `window.__MINDSTUDIO__.telemetry = { analytics: false }`.\n */\n\nimport { getConfig } from './config.js';\nimport { onNavigation } from './telemetry-breadcrumbs.js';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Flat-primitive prop values for custom events.\n *\n * Backend caps: max 10 keys, key length ~50 chars, value length ~500 chars.\n * Non-primitive values (objects, arrays, null) are stripped client-side\n * before send to save bandwidth — backend would silently drop them anyway.\n */\nexport type CustomEventProps = Record<string, string | number | boolean>;\n\n/**\n * The analytics namespace — pageview auto-tracking + custom events.\n *\n * Pageviews are auto-tracked from history changes; no public API for\n * them. Opt out entirely via `window.__MINDSTUDIO__.telemetry.analytics = false`.\n */\nexport interface AnalyticsClient {\n /**\n * Record a custom event with optional flat-primitive props.\n *\n * Non-primitive prop values (objects, arrays, null, undefined) are\n * stripped client-side before send. Server further caps name length\n * to 200 chars, props to 10 keys, key length to 50, value length to 500.\n *\n * Best-effort — never throws, never blocks. If the SDK isn't\n * initialized yet, the call is silently dropped.\n */\n track(event: string, props?: CustomEventProps): void;\n}\n\n// ---------------------------------------------------------------------------\n// Internal event types\n// ---------------------------------------------------------------------------\n\ntype PageviewEvent = {\n type: 'pageview';\n releaseId: string;\n url: string;\n referrer: string;\n userAgent: string;\n language: string;\n screen: { w: number; h: number };\n timestamp: number;\n};\n\ntype CustomEvent = {\n type: 'event';\n releaseId: string;\n name: string;\n url: string;\n timestamp: number;\n props?: CustomEventProps;\n};\n\ntype AnalyticsEvent = PageviewEvent | CustomEvent;\n\n// ---------------------------------------------------------------------------\n// Batched event transport\n// ---------------------------------------------------------------------------\n\nconst EVENTS_ENDPOINT = '/_/telemetry/events';\nconst FLUSH_INTERVAL_MS = 1000;\nconst MAX_BATCH_SIZE = 100;\nconst DEFAULT_RETRY_AFTER_MS = 60_000;\n\nlet pending: AnalyticsEvent[] = [];\nlet flushTimer: ReturnType<typeof setTimeout> | null = null;\nlet suppressUntil = 0;\nlet unloaded = false;\n\nfunction enqueue(event: AnalyticsEvent): void {\n if (unloaded) {\n return;\n }\n if (pending.length >= MAX_BATCH_SIZE) {\n return;\n }\n pending.push(event);\n scheduleFlush();\n}\n\nfunction scheduleFlush(): void {\n if (flushTimer || pending.length === 0) {\n return;\n }\n flushTimer = setTimeout(() => {\n flushTimer = null;\n void flush();\n }, FLUSH_INTERVAL_MS);\n}\n\nfunction takeBatch(): AnalyticsEvent[] {\n const batch = pending;\n pending = [];\n return batch;\n}\n\nasync function flush(): Promise<void> {\n if (pending.length === 0) {\n return;\n }\n\n if (Date.now() < suppressUntil) {\n pending = [];\n return;\n }\n\n let config;\n try {\n config = getConfig();\n } catch {\n pending = [];\n return;\n }\n\n const events = takeBatch();\n\n try {\n const res = await fetch(EVENTS_ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({ events }),\n });\n\n if (res.status === 429) {\n const retryAfterHeader = res.headers.get('Retry-After');\n const retryAfterSec = retryAfterHeader\n ? parseInt(retryAfterHeader, 10)\n : NaN;\n const waitMs =\n Number.isFinite(retryAfterSec) && retryAfterSec > 0\n ? retryAfterSec * 1000\n : DEFAULT_RETRY_AFTER_MS;\n suppressUntil = Date.now() + waitMs;\n }\n } catch {\n // network / serialization failure — drop silently\n }\n}\n\nfunction drainOnUnload(): void {\n if (pending.length === 0) {\n return;\n }\n if (Date.now() < suppressUntil) {\n pending = [];\n return;\n }\n\n let config;\n try {\n config = getConfig();\n } catch {\n pending = [];\n return;\n }\n\n const events = takeBatch();\n\n try {\n void fetch(EVENTS_ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({ events }),\n keepalive: true,\n });\n } catch {\n // best effort\n }\n}\n\n// ---------------------------------------------------------------------------\n// Custom event prop sanitization\n// ---------------------------------------------------------------------------\n\nfunction sanitizeProps(\n input?: Record<string, unknown>,\n): CustomEventProps | undefined {\n if (!input) {\n return undefined;\n }\n const out: CustomEventProps = {};\n for (const [k, v] of Object.entries(input)) {\n if (\n typeof v === 'string' ||\n typeof v === 'number' ||\n typeof v === 'boolean'\n ) {\n out[k] = v;\n }\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Pageview emit\n// ---------------------------------------------------------------------------\n\nfunction emitPageview(url: string): void {\n try {\n const config = getConfig();\n enqueue({\n type: 'pageview',\n releaseId: config.releaseId,\n url,\n referrer: document.referrer,\n userAgent: navigator.userAgent,\n language: navigator.language,\n screen: { w: window.innerWidth, h: window.innerHeight },\n timestamp: Date.now(),\n });\n } catch {\n // capture must never crash\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public `track`\n// ---------------------------------------------------------------------------\n\nfunction track(event: string, props?: CustomEventProps): void {\n try {\n const config = getConfig();\n enqueue({\n type: 'event',\n releaseId: config.releaseId,\n name: event,\n url: location.href,\n timestamp: Date.now(),\n props: sanitizeProps(props as Record<string, unknown> | undefined),\n });\n } catch {\n // never crash\n }\n}\n\n// ---------------------------------------------------------------------------\n// Silent presence connection\n//\n// The SDK opens a long-lived SSE connection to `/_/telemetry/presence`\n// while the tab is alive. The connection itself is the presence signal:\n// while it's open, the visitor is tracked as \"online\" in the server-side\n// Redis set; when the tab closes (or network drops), the connection\n// closes and the server immediately knows the visitor is gone.\n//\n// Any data the server pushes over this connection is silently discarded.\n// The visitor-facing live count is intentionally NOT exposed by the SDK.\n// The owner-facing dashboard reads counts via a separate authenticated\n// internal endpoint, never through the SDK.\n//\n// Reading-and-discarding the stream is required to keep the underlying\n// TCP buffer flowing — the open connection itself is what matters, not\n// the data flowing over it.\n// ---------------------------------------------------------------------------\n\nconst PRESENCE_ENDPOINT = '/_/telemetry/presence';\nconst PRESENCE_MAX_BACKOFF_MS = 10_000;\nconst PRESENCE_503_DEFAULT_MS = 30_000;\n\nlet presenceAbort: AbortController | null = null;\nlet presenceReconnectTimer: ReturnType<typeof setTimeout> | null = null;\nlet presenceBackoffMs = 1000;\nlet presenceActive = false;\n\nfunction presenceNextBackoff(): number {\n const base = presenceBackoffMs;\n presenceBackoffMs = Math.min(presenceBackoffMs * 2, PRESENCE_MAX_BACKOFF_MS);\n const jitter = Math.random() * 250;\n return base + jitter;\n}\n\nfunction schedulePresenceReconnect(ms: number): void {\n if (presenceReconnectTimer) {\n clearTimeout(presenceReconnectTimer);\n }\n presenceReconnectTimer = setTimeout(() => {\n presenceReconnectTimer = null;\n if (presenceActive) {\n void openPresenceConnection();\n }\n }, ms);\n}\n\nfunction closePresenceConnection(): void {\n presenceActive = false;\n if (presenceReconnectTimer) {\n clearTimeout(presenceReconnectTimer);\n presenceReconnectTimer = null;\n }\n if (presenceAbort) {\n try {\n presenceAbort.abort();\n } catch {\n // swallow\n }\n presenceAbort = null;\n }\n}\n\nasync function openPresenceConnection(): Promise<void> {\n if (!presenceActive) {\n return;\n }\n\n let config;\n try {\n config = getConfig();\n } catch {\n presenceActive = false;\n return;\n }\n\n presenceAbort = new AbortController();\n const signal = presenceAbort.signal;\n\n try {\n const res = await fetch(PRESENCE_ENDPOINT, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${config.token}`,\n Accept: 'text/event-stream',\n },\n signal,\n });\n\n if (res.status === 503) {\n const retryAfterHeader = res.headers.get('Retry-After');\n const retryAfterSec = retryAfterHeader\n ? parseInt(retryAfterHeader, 10)\n : NaN;\n const waitMs =\n Number.isFinite(retryAfterSec) && retryAfterSec > 0\n ? retryAfterSec * 1000\n : PRESENCE_503_DEFAULT_MS;\n schedulePresenceReconnect(waitMs);\n return;\n }\n\n if (res.status === 401) {\n // Session bad — stop trying until something refreshes config\n presenceActive = false;\n return;\n }\n\n if (!res.ok || !res.body) {\n schedulePresenceReconnect(presenceNextBackoff());\n return;\n }\n\n // Successful connect — reset backoff\n presenceBackoffMs = 1000;\n\n const reader = res.body.getReader();\n\n // Drain and discard. The open connection is the presence signal;\n // any count data the server pushes is intentionally ignored.\n while (presenceActive) {\n const { done } = await reader.read();\n if (done) {\n break;\n }\n }\n\n // Stream ended (server closed, deploy, etc.) — reconnect\n if (presenceActive) {\n schedulePresenceReconnect(presenceNextBackoff());\n }\n } catch (err) {\n const name = (err as { name?: string } | null)?.name;\n if (presenceActive && name !== 'AbortError') {\n schedulePresenceReconnect(presenceNextBackoff());\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public client\n// ---------------------------------------------------------------------------\n\nexport const analytics: AnalyticsClient = { track };\n\n// ---------------------------------------------------------------------------\n// Install + opt-out\n// ---------------------------------------------------------------------------\n\nlet _installed = false;\n\n/**\n * Install pageview auto-tracking + transport. Idempotent.\n *\n * Reads `window.__MINDSTUDIO__.telemetry?.analytics` — if explicitly\n * `false`, the SDK installs nothing and the function is a no-op.\n * `track()` calls also no-op in that case since enqueued events\n * have no flush path established.\n */\nexport function installAnalytics(): void {\n if (_installed) {\n return;\n }\n if (typeof window === 'undefined') {\n return;\n }\n\n let config;\n try {\n config = getConfig();\n } catch {\n return;\n }\n\n if (config.telemetry?.analytics === false) {\n return;\n }\n\n _installed = true;\n\n // Unload listeners (attached once)\n const handleUnload = (): void => {\n unloaded = true;\n drainOnUnload();\n closePresenceConnection();\n };\n window.addEventListener('pagehide', handleUnload);\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n drainOnUnload();\n }\n });\n\n // Auto-pageviews on every history change\n onNavigation((url) => {\n emitPageview(url);\n });\n\n // Initial pageview\n emitPageview(location.href);\n\n // Silent presence heartbeat — the open connection itself signals\n // \"this visitor is online\" to the server. No data is consumed.\n presenceActive = true;\n void openPresenceConnection();\n}\n\n/**\n * Wrapper that swallows any error from {@link installAnalytics} so a\n * misbehaving telemetry layer can never break `getConfig()`.\n *\n * @internal Called from config.ts on every `getConfig()` — idempotency\n * is enforced inside `installAnalytics`.\n */\nexport function maybeInstallAnalytics(): void {\n try {\n installAnalytics();\n } catch {\n // telemetry must never crash the host app\n }\n}\n","/**\n * Error reporting — auto-capture of uncaught errors and unhandled\n * promise rejections, batched and shipped to `/_/telemetry/errors`.\n *\n * ## How it works\n *\n * Installed by `maybeInstallTelemetry()` in `config.ts` on the first\n * `getConfig()` call. Once installed:\n *\n * 1. `window.error` and `unhandledrejection` listeners enqueue events\n * into a pending batch (max 50 per batch — the server cap).\n * 2. Events with the same fingerprint within a batch collapse into a\n * single entry with `count: N` (bandwidth optimization).\n * 3. The batch flushes ~1s after the first push via `POST` to\n * `/_/telemetry/errors`.\n * 4. On `pagehide` / `visibilitychange='hidden'`, the buffer drains\n * via `fetch` with `keepalive: true` so the Bearer header survives.\n * 5. On `429`, the SDK pauses sends for the `Retry-After` window.\n * 6. Any other transport failure is swallowed — telemetry must never\n * crash the host app.\n *\n * No public API — the only knob is opt-out via\n * `window.__MINDSTUDIO__.telemetry = { errors: false }`.\n */\n\nimport { getConfig } from './config.js';\nimport {\n installBreadcrumbs,\n getBreadcrumbs,\n type Breadcrumb,\n} from './telemetry-breadcrumbs.js';\n\nconst ENDPOINT = '/_/telemetry/errors';\nconst FLUSH_INTERVAL_MS = 1000;\nconst MAX_BATCH_SIZE = 50;\nconst DEFAULT_RETRY_AFTER_MS = 60_000;\n\ninterface ErrorEvent {\n releaseId: string;\n url: string;\n userAgent: string;\n timestamp: number;\n type: 'error' | 'unhandledrejection';\n message: string;\n stack: string;\n source?: string;\n line?: number;\n column?: number;\n breadcrumbs: Breadcrumb[];\n count?: number;\n /** Internal: fingerprint for within-batch dedupe. Stripped before send. */\n _fp?: string;\n}\n\nlet _installed = false;\nlet pending: ErrorEvent[] = [];\nlet flushTimer: ReturnType<typeof setTimeout> | null = null;\nlet suppressUntil = 0;\nlet unloaded = false;\n\nfunction fingerprint(message: string, stack: string): string {\n const firstStackLine = stack.split('\\n')[1] ?? '';\n return `${message}|${firstStackLine.trim()}`;\n}\n\nfunction enqueue(event: ErrorEvent): void {\n if (unloaded) {\n return;\n }\n\n const fp = fingerprint(event.message, event.stack);\n\n for (const existing of pending) {\n if (existing._fp === fp) {\n existing.count = (existing.count ?? 1) + 1;\n return;\n }\n }\n\n if (pending.length >= MAX_BATCH_SIZE) {\n return;\n }\n\n event._fp = fp;\n pending.push(event);\n scheduleFlush();\n}\n\nfunction scheduleFlush(): void {\n if (flushTimer || pending.length === 0) {\n return;\n }\n flushTimer = setTimeout(() => {\n flushTimer = null;\n void flush();\n }, FLUSH_INTERVAL_MS);\n}\n\nfunction takeBatch(): ErrorEvent[] {\n const batch = pending;\n pending = [];\n return batch.map(({ _fp, ...rest }) => {\n void _fp;\n return rest;\n });\n}\n\nasync function flush(): Promise<void> {\n if (pending.length === 0) {\n return;\n }\n\n if (Date.now() < suppressUntil) {\n pending = [];\n return;\n }\n\n const config = (() => {\n try {\n return getConfig();\n } catch {\n return null;\n }\n })();\n if (!config) {\n pending = [];\n return;\n }\n\n const events = takeBatch();\n\n try {\n const res = await fetch(ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({ events }),\n });\n\n if (res.status === 429) {\n const retryAfterHeader = res.headers.get('Retry-After');\n const retryAfterSec = retryAfterHeader\n ? parseInt(retryAfterHeader, 10)\n : NaN;\n const waitMs =\n Number.isFinite(retryAfterSec) && retryAfterSec > 0\n ? retryAfterSec * 1000\n : DEFAULT_RETRY_AFTER_MS;\n suppressUntil = Date.now() + waitMs;\n }\n } catch {\n // network / serialization failure — drop silently\n }\n}\n\nfunction drainOnUnload(): void {\n if (pending.length === 0) {\n return;\n }\n if (Date.now() < suppressUntil) {\n pending = [];\n return;\n }\n\n let config: ReturnType<typeof getConfig> | null = null;\n try {\n config = getConfig();\n } catch {\n pending = [];\n return;\n }\n\n const events = takeBatch();\n\n try {\n void fetch(ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({ events }),\n keepalive: true,\n });\n } catch {\n // best effort\n }\n}\n\nfunction captureError(e: globalThis.ErrorEvent): void {\n try {\n const config = getConfig();\n enqueue({\n releaseId: config.releaseId,\n url: location.href,\n userAgent: navigator.userAgent,\n timestamp: Date.now(),\n type: 'error',\n message: e.message || 'Unknown error',\n stack: e.error?.stack ?? '',\n source: e.filename || undefined,\n line: typeof e.lineno === 'number' ? e.lineno : undefined,\n column: typeof e.colno === 'number' ? e.colno : undefined,\n breadcrumbs: getBreadcrumbs(),\n });\n } catch {\n // never crash on capture\n }\n}\n\nfunction captureRejection(e: PromiseRejectionEvent): void {\n try {\n const config = getConfig();\n const reason = e.reason as\n | { message?: string; stack?: string }\n | string\n | undefined;\n\n let message: string;\n let stack = '';\n\n if (reason && typeof reason === 'object') {\n message = reason.message || String(reason);\n stack = reason.stack ?? '';\n } else {\n message = String(reason ?? 'Unhandled rejection');\n }\n\n enqueue({\n releaseId: config.releaseId,\n url: location.href,\n userAgent: navigator.userAgent,\n timestamp: Date.now(),\n type: 'unhandledrejection',\n message,\n stack,\n breadcrumbs: getBreadcrumbs(),\n });\n } catch {\n // never crash on capture\n }\n}\n\n/**\n * Install error capture + breadcrumb collection. Idempotent.\n *\n * Reads `window.__MINDSTUDIO__.telemetry?.errors` — if explicitly\n * `false`, no listeners are attached and the function is a no-op.\n *\n * Otherwise attaches:\n * - `window.error` + `unhandledrejection`\n * - `pagehide` + `visibilitychange === 'hidden'` (for buffer drain)\n * - Breadcrumb sources via {@link installBreadcrumbs}\n */\nexport function installErrorMonitoring(): void {\n if (_installed) {\n return;\n }\n if (typeof window === 'undefined') {\n return;\n }\n\n let config: ReturnType<typeof getConfig>;\n try {\n config = getConfig();\n } catch {\n return;\n }\n\n if (config.telemetry?.errors === false) {\n return;\n }\n\n _installed = true;\n\n installBreadcrumbs({\n captureResponseBodies: !!config.telemetryCaptureResponseBodies,\n });\n\n window.addEventListener('error', captureError);\n window.addEventListener('unhandledrejection', captureRejection);\n\n const handleUnload = (): void => {\n unloaded = true;\n drainOnUnload();\n };\n window.addEventListener('pagehide', handleUnload);\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n drainOnUnload();\n }\n });\n}\n\n/**\n * Wrapper that swallows any error from {@link installErrorMonitoring}\n * so a misbehaving telemetry layer can never break `getConfig()`.\n *\n * @internal Called from config.ts on every `getConfig()` — idempotency\n * is enforced inside `installErrorMonitoring`.\n */\nexport function maybeInstallTelemetry(): void {\n try {\n installErrorMonitoring();\n } catch {\n // telemetry must never crash the host app\n }\n}\n","/**\n * Bootstrap configuration reader.\n *\n * Reads and validates `window.__MINDSTUDIO__` — the globals injected by\n * the platform before the app's JavaScript runs. The result is cached\n * after first read.\n *\n * All other modules in the SDK call `getConfig()` internally. App code\n * should never need to call this directly — use `createClient()`, `auth`,\n * and `platform` instead.\n */\n\nimport { MindStudioInterfaceError } from './errors.js';\nimport { maybeInstallAnalytics } from './telemetry-analytics.js';\nimport { maybeInstallTelemetry } from './telemetry-errors.js';\nimport type { AppUser, BootstrapConfig } from './types.js';\n\nlet _config: BootstrapConfig | undefined;\n\n/**\n * Read and validate the bootstrap configuration from `window.__MINDSTUDIO__`.\n *\n * Caches the result after first successful read. Throws if the globals\n * are missing or incomplete — this means the page isn't running inside\n * the MindStudio platform.\n *\n * @returns The validated bootstrap config\n * @throws {MindStudioInterfaceError} if `window.__MINDSTUDIO__` is missing or invalid\n */\nexport function getConfig(): BootstrapConfig {\n if (_config) {\n return _config;\n }\n\n const raw = (globalThis as Record<string, unknown>).__MINDSTUDIO__ as\n | Partial<BootstrapConfig>\n | undefined;\n\n if (!raw) {\n throw new MindStudioInterfaceError(\n '@mindstudio-ai/interface requires the MindStudio platform context. ' +\n 'This page must be loaded inside MindStudio (window.__MINDSTUDIO__ is missing).',\n 'not_initialized',\n );\n }\n\n // Validate required fields (user can be null for unauthenticated sessions)\n if (!raw.token || !raw.releaseId || !raw.methods) {\n const missing = ['token', 'releaseId', 'methods']\n .filter((k) => !raw[k as keyof BootstrapConfig])\n .join(', ');\n\n throw new MindStudioInterfaceError(\n `MindStudio platform context is incomplete. Missing: ${missing}`,\n 'invalid_config',\n );\n }\n\n _config = raw as BootstrapConfig;\n\n // Auto-install telemetry surfaces on first successful config read.\n // Both are idempotent + try/caught — telemetry must never break getConfig().\n maybeInstallTelemetry();\n maybeInstallAnalytics();\n\n return _config;\n}\n\n/**\n * Update the cached config in-place after an auth state transition.\n *\n * The cached config is a mutable reference — all SDK modules read it\n * on-demand via `getConfig()`, so mutations propagate immediately to\n * method invocation, agent chat, uploads, etc.\n *\n * @internal Not exported from the package — used by the auth module only.\n */\nexport function updateConfig(updates: {\n token?: string;\n user?: AppUser | null;\n methods?: Record<string, string>;\n visitorId?: string;\n}): void {\n const config = getConfig();\n if (updates.token !== undefined) {\n config.token = updates.token;\n }\n if (updates.user !== undefined) {\n config.user = updates.user;\n }\n if (updates.methods !== undefined) {\n config.methods = updates.methods;\n }\n if (updates.visitorId !== undefined) {\n config.visitorId = updates.visitorId;\n }\n}\n","/**\n * Method RPC client — typed function calls to backend methods.\n *\n * `createClient()` returns a Proxy where every property access creates\n * an async function that invokes the corresponding backend method via HTTP.\n * The method name matches the method's `export` field in `app.json`.\n *\n * ## How it works\n *\n * ```\n * api.submitVendorRequest({ name: 'Acme' })\n * │\n * ├─ Look up method ID: config.methods[\"submitVendorRequest\"]\n * │ → \"submit-vendor-request\"\n * │\n * ├─ POST /_/methods/submit-vendor-request/invoke\n * │ Authorization: Bearer {session token}\n * │ Body: { input: { name: \"Acme\" } }\n * │\n * └─ Returns response.output (or throws on error)\n * ```\n *\n * The method registry (export name → method ID mapping) is embedded in\n * `window.__MINDSTUDIO__.methods` at page load time — no extra HTTP call\n * needed to discover methods.\n *\n * ## Streaming\n *\n * Methods can optionally stream LLM token output via SSE. Pass\n * `{ stream: true }` as the second argument along with an `onToken`\n * callback to receive incremental updates:\n *\n * ```ts\n * const result = await api.submitVendorRequest({ name: 'Acme' }, {\n * stream: true,\n * onToken: (text) => setResponseText(text),\n * });\n * ```\n *\n * **Important:** The `text` value passed to `onToken` is the accumulated\n * response so far (not a delta). Replace your display content each time —\n * do not append. See {@link InvokeOptions.onToken} for details.\n *\n * ## Type safety\n *\n * Since the frontend and backend live in the same project, you can import\n * types directly:\n *\n * ```ts\n * import type { SubmitVendorInput, SubmitVendorOutput }\n * from '../../backend/src/submitVendorRequest';\n *\n * interface AppMethods {\n * submitVendorRequest(input: SubmitVendorInput): Promise<SubmitVendorOutput>;\n * getDashboard(): Promise<GetDashboardOutput>;\n * }\n *\n * const api = createClient<AppMethods>();\n * const result = await api.submitVendorRequest({ name: 'Acme' }); // fully typed\n * ```\n *\n * If no type parameter is provided, methods accept `any` input and return `any`.\n */\n\nimport { getConfig } from './config.js';\nimport { MindStudioInterfaceError } from './errors.js';\n\n/**\n * Options for method invocation. Pass as the optional second argument to\n * any method on the client returned by {@link createClient}.\n *\n * When `stream` is `true`, the SDK sends `{ stream: true }` in the request\n * body and parses the response as an SSE (Server-Sent Events) stream.\n * Three event types are handled:\n *\n * | SSE `type` | Payload field | SDK action |\n * |------------|---------------|------------|\n * | `token` | `text` | Calls {@link onToken} with accumulated text |\n * | `error` | `error` | Calls {@link onStreamError} with the message |\n * | `done` | `output` | Captures as the method's return value |\n *\n * The method's `Promise` resolves with the final `output` from the `done`\n * event — the same shape you'd get without streaming.\n */\nexport interface InvokeOptions {\n /**\n * Enable SSE streaming for LLM token output.\n *\n * When `true`, the request body includes `{ stream: true }` and the\n * response is parsed as an SSE stream instead of a single JSON payload.\n * The method still returns a `Promise` that resolves with the final\n * output once the stream completes.\n *\n * @default false\n */\n stream?: boolean;\n\n /**\n * Called with the accumulated response text each time a new token arrives.\n *\n * **Important:** `text` is the full response so far, not a delta/chunk.\n * Your frontend should **replace** (not append to) its display content\n * with this value each time the callback fires.\n *\n * This design avoids edge cases where the platform sanitizes or\n * reformats JSON mid-stream, causing earlier portions of the text to\n * change between tokens.\n *\n * @example\n * ```ts\n * const result = await api.generate({ prompt: 'Hello' }, {\n * stream: true,\n * onToken: (text) => {\n * // Replace — do NOT append\n * responseElement.textContent = text;\n * },\n * });\n * ```\n */\n onToken?: (text: string) => void;\n\n /**\n * Called if a stream-level error event arrives.\n *\n * If the stream then closes without a `done` event, the method rejects\n * with a `MindStudioInterfaceError` containing the error message (code\n * `method_error`). If a `done` event does arrive after the error, the\n * method resolves with the final output — in that case this callback\n * is just for logging or showing a transient warning.\n *\n * If the stream ends without either a `done` or `error` event, the\n * method rejects with `stream_incomplete`.\n */\n onStreamError?: (error: string) => void;\n}\n\n/**\n * Default client type when no generic parameter is provided.\n * Every property returns an async function accepting optional input\n * and optional {@link InvokeOptions} for streaming.\n */\ntype DefaultMethodClient = Record<\n string,\n (input?: Record<string, unknown>, options?: InvokeOptions) => Promise<unknown>\n>;\n\n/**\n * Create a typed RPC client for calling backend methods.\n *\n * @typeParam T - Optional interface mapping method names to their signatures.\n * If omitted, all methods accept `any` and return `Promise<any>`.\n *\n * @returns A Proxy object where each property is an async function that\n * invokes the corresponding backend method.\n *\n * @example\n * ```ts\n * import { createClient } from '@mindstudio-ai/interface';\n *\n * const api = createClient();\n *\n * // Each method maps to a backend method export\n * const result = await api.submitVendorRequest({ name: 'Acme' });\n * const dashboard = await api.getDashboard();\n *\n * // Stream LLM output — onToken receives accumulated text (replace, don't append)\n * const streamed = await api.submitVendorRequest({ name: 'Acme' }, {\n * stream: true,\n * onToken: (text) => setResponseText(text),\n * });\n * // `streamed` is the same final output you'd get without streaming\n * ```\n */\nexport function createClient<T = DefaultMethodClient>(): T {\n return new Proxy({} as Record<string, unknown> as T & object, {\n get(_, methodName: string) {\n return async (input?: unknown, options?: InvokeOptions) => {\n const config = getConfig();\n\n const methodId = config.methods[methodName];\n if (!methodId) {\n throw new MindStudioInterfaceError(\n `Method \"${methodName}\" not found. Available methods: ${Object.keys(config.methods).join(', ') || '(none)'}`,\n 'method_not_found',\n );\n }\n\n const url = `/_/methods/${methodId}/invoke`;\n const wantsStream = options?.stream === true;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({\n input: input ?? {},\n ...(wantsStream && { stream: true }),\n }),\n });\n\n if (!res.ok) {\n let errorMessage = `Method \"${methodName}\" failed: ${res.status} ${res.statusText}`;\n let errorCode = 'method_error';\n try {\n const body = (await res.json()) as {\n error?: string;\n code?: string;\n };\n if (body.error) {\n errorMessage = body.error;\n }\n if (body.code) {\n errorCode = body.code;\n }\n } catch {\n // Response wasn't JSON — use the default message\n }\n throw new MindStudioInterfaceError(\n errorMessage,\n errorCode,\n res.status,\n );\n }\n\n // Non-streaming: unchanged behavior\n if (!wantsStream) {\n const body = (await res.json()) as { output?: unknown };\n return body.output;\n }\n\n // Streaming: parse SSE events from response body\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let finalOutput: unknown;\n let streamError: string | undefined;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) {\n continue;\n }\n const json = line.slice(6);\n try {\n const event = JSON.parse(json) as {\n type: string;\n text?: string;\n error?: string;\n output?: unknown;\n };\n\n if (event.type === 'token' && options?.onToken && event.text) {\n options.onToken(event.text);\n } else if (event.type === 'error' && event.error) {\n streamError = event.error;\n if (options?.onStreamError) {\n options.onStreamError(event.error);\n }\n } else if (event.type === 'done') {\n finalOutput = event.output;\n }\n } catch {\n // Skip malformed SSE lines\n }\n }\n }\n\n // If the stream errored and didn't produce a final output,\n // surface the error message from the error event.\n if (finalOutput === undefined && streamError !== undefined) {\n throw new MindStudioInterfaceError(streamError, 'method_error');\n }\n\n if (finalOutput === undefined) {\n throw new MindStudioInterfaceError(\n 'Stream ended without a done event',\n 'stream_incomplete',\n );\n }\n\n return finalOutput;\n };\n },\n });\n}\n","/**\n * Agent chat client — thread-based conversations with AI agents.\n *\n * `createAgentChatClient()` returns an object with methods for thread\n * lifecycle (create, list, get, rename, delete) and message streaming.\n * The agent runs server-side with access to the app's methods as tools.\n *\n * ## How it works\n *\n * ```\n * chat.sendMessage(threadId, 'Help me prep for my review', {\n * onText: (delta) => setAssistantMessage((prev) => prev + delta),\n * })\n * │\n * ├─ POST /_/agent/threads/{threadId}/messages\n * │ Authorization: Bearer {session token}\n * │ Body: { content: \"Help me prep for my review\" }\n * │\n * ├─ Response: SSE stream\n * │ data: {\"type\":\"text\",\"text\":\"I'll create...\",\"ts\":1711...}\n * │ data: {\"type\":\"tool_call_start\",\"id\":\"call_abc\",\"name\":\"create-todo\",\"ts\":1711...}\n * │ data: {\"type\":\"tool_call_result\",\"id\":\"call_abc\",\"output\":{...},\"ts\":1711...}\n * │ data: {\"type\":\"text\",\"text\":\"Done — added it.\",\"ts\":1711...}\n * │ data: {\"type\":\"done\",\"stopReason\":\"end_turn\",\"usage\":{...},\"ts\":1711...}\n * │\n * └─ Promise resolves with { stopReason, usage }\n * ```\n *\n * ## Stateless design\n *\n * This client is a thin wrapper over HTTP endpoints. It does not manage\n * local state — your React/framework layer owns the thread list, message\n * array, and UI state. Each method is an independent request.\n *\n * ## Streaming callbacks\n *\n * `sendMessage` accepts named callbacks for common events (onText,\n * onThinking, onToolCallStart, etc.) plus a catch-all `onEvent` that\n * receives every SSE event as a discriminated union. Both fire for the\n * same event — use named callbacks for convenience, `onEvent` for\n * logging or handling low-level events like `tool_use` and\n * `tool_input_delta`.\n *\n * @example\n * ```ts\n * import { createAgentChatClient } from '@mindstudio-ai/interface';\n *\n * const chat = createAgentChatClient();\n *\n * // Thread lifecycle\n * const thread = await chat.createThread();\n * const { threads } = await chat.listThreads();\n * const full = await chat.getThread(thread.id);\n *\n * // Send a message with streaming\n * const response = chat.sendMessage(thread.id, 'Hello!', {\n * onText: (delta) => setMessage((prev) => prev + delta),\n * onToolCallStart: (id, name) => showToolSpinner(name),\n * onToolCallResult: (id, output) => showToolResult(output),\n * });\n *\n * const { stopReason, usage } = await response;\n *\n * // Abort mid-stream\n * response.abort();\n * ```\n */\n\nimport { getConfig } from './config.js';\nimport { MindStudioInterfaceError } from './errors.js';\n\n// ---------------------------------------------------------------------------\n// Thread types\n// ---------------------------------------------------------------------------\n\n/** Thread summary returned from create and list endpoints. */\nexport interface ThreadSummary {\n /** Thread ID (UUID). */\n id: string;\n /** User-editable title, auto-generated on first message. */\n title: string | null;\n /** ISO 8601 creation timestamp. */\n dateCreated: string;\n /** ISO 8601 last-updated timestamp. */\n dateUpdated: string;\n}\n\n/** Full thread with message history, returned from get endpoint. */\nexport interface Thread {\n /** Thread ID (UUID). */\n id: string;\n /** User-editable title. */\n title: string | null;\n /** Full conversation history. */\n messages: Message[];\n /** ISO 8601 creation timestamp. */\n dateCreated: string;\n /** ISO 8601 last-updated timestamp. */\n dateUpdated: string;\n}\n\n/** A tool call requested by the assistant. */\nexport interface ToolCall {\n /** Tool call ID, used to match results. */\n id: string;\n /** Method name. */\n name: string;\n /** Input arguments. */\n input: Record<string, unknown>;\n}\n\n/** A single message in a thread's conversation history. */\nexport interface Message {\n /** `\"user\"` for human messages, `\"assistant\"` for agent responses. */\n role: 'user' | 'assistant';\n /** Message text content. For tool results, this is JSON-stringified output. */\n content: string;\n /**\n * MindStudio CDN URLs attached to this message (user messages only).\n *\n * Images (`i.mscdn.ai`) are sent to the model as vision input.\n * Documents (`f.mscdn.ai`, `files.mindstudio-cdn.com`) have their text\n * extracted server-side and included in the model context. The original\n * URLs are preserved in thread history for the frontend to render.\n */\n attachments?: string[];\n /** Tool calls the assistant requested (assistant messages only). */\n toolCalls?: ToolCall[];\n /** ID of the tool call this message is a result for (tool result messages only). */\n toolCallId?: string;\n /** Whether this tool result represents an error. */\n isToolError?: boolean;\n}\n\n/** Paginated thread list response. */\nexport interface ThreadListPage {\n /** Threads for this page. */\n threads: ThreadSummary[];\n /** Cursor for the next page, or `null` if this is the last page. */\n nextCursor: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// SSE event types\n// ---------------------------------------------------------------------------\n\n/** Assistant text delta — append to your display string, do not replace. */\nexport interface AgentTextEvent {\n type: 'text';\n text: string;\n ts: number;\n}\n\n/** Model thinking text (extended thinking). */\nexport interface AgentThinkingEvent {\n type: 'thinking';\n text: string;\n ts: number;\n}\n\n/** Thinking complete with full text and signature. */\nexport interface AgentThinkingCompleteEvent {\n type: 'thinking_complete';\n thinking: string;\n signature: string;\n ts: number;\n}\n\n/** Model requested a tool call (includes parsed input). */\nexport interface AgentToolUseEvent {\n type: 'tool_use';\n id: string;\n name: string;\n input: Record<string, unknown>;\n ts: number;\n}\n\n/** Streaming delta for tool call input JSON. */\nexport interface AgentToolInputDeltaEvent {\n type: 'tool_input_delta';\n id: string;\n name: string;\n delta: string;\n ts: number;\n}\n\n/** Agent began executing a tool call. */\nexport interface AgentToolCallStartEvent {\n type: 'tool_call_start';\n id: string;\n name: string;\n ts: number;\n}\n\n/** Tool call returned a result. */\nexport interface AgentToolCallResultEvent {\n type: 'tool_call_result';\n id: string;\n output: unknown;\n ts: number;\n}\n\n/** Stream complete. */\nexport interface AgentDoneEvent {\n type: 'done';\n stopReason: string;\n usage: { inputTokens: number; outputTokens: number };\n ts: number;\n}\n\n/** Stream-level error. */\nexport interface AgentErrorEvent {\n type: 'error';\n error: string;\n ts: number;\n}\n\n/** Discriminated union of all SSE events from the agent chat stream. */\nexport type AgentChatEvent =\n | AgentTextEvent\n | AgentThinkingEvent\n | AgentThinkingCompleteEvent\n | AgentToolUseEvent\n | AgentToolInputDeltaEvent\n | AgentToolCallStartEvent\n | AgentToolCallResultEvent\n | AgentDoneEvent\n | AgentErrorEvent;\n\n// ---------------------------------------------------------------------------\n// Callbacks and result types\n// ---------------------------------------------------------------------------\n\n/**\n * Callbacks for `sendMessage` streaming.\n *\n * Named callbacks fire for common events. The catch-all `onEvent` fires\n * for every event including those with named callbacks — use it for\n * logging or handling low-level events like `tool_use` and\n * `tool_input_delta`.\n */\nexport interface SendMessageCallbacks {\n /**\n * Called with each text delta as the assistant responds.\n *\n * **Important:** `text` is a delta (new chunk), not the accumulated\n * response. Append it to your display string — do not replace.\n *\n * @example\n * ```ts\n * onText: (delta) => setMessage((prev) => prev + delta)\n * ```\n */\n onText?: (text: string) => void;\n\n /** Called with model thinking text (extended thinking). */\n onThinking?: (text: string) => void;\n\n /** Called when thinking is complete. */\n onThinkingComplete?: (thinking: string, signature: string) => void;\n\n /** Called when a tool call begins executing. */\n onToolCallStart?: (id: string, name: string) => void;\n\n /** Called when a tool call produces a result. */\n onToolCallResult?: (id: string, output: unknown) => void;\n\n /** Called on a stream-level error event. */\n onError?: (error: string) => void;\n\n /** Called for every SSE event (including ones with named callbacks). */\n onEvent?: (event: AgentChatEvent) => void;\n\n /** AbortSignal to cancel the stream. */\n signal?: AbortSignal;\n}\n\n/** Options for `sendMessage`. */\nexport interface SendMessageOptions {\n /**\n * MindStudio CDN URLs to attach to the message.\n *\n * Images (`i.mscdn.ai`) are sent to the model as vision input (one per message).\n * Documents (`f.mscdn.ai`, `files.mindstudio-cdn.com`) have their text\n * extracted server-side and included in context.\n *\n * Upload files first via `platform.uploadFile()`.\n *\n * @example\n * ```ts\n * const url = await platform.uploadFile(file);\n * chat.sendMessage(threadId, 'What is this?', callbacks, {\n * attachments: [url],\n * });\n * ```\n */\n attachments?: string[];\n}\n\n/** Resolved value of `sendMessage` — extracted from the `done` event. */\nexport interface SendMessageResult {\n /** Why the agent stopped (`\"end_turn\"`, `\"max_tokens\"`, etc.). */\n stopReason: string;\n /** Token usage for the full agent loop. */\n usage: { inputTokens: number; outputTokens: number };\n}\n\n/** A Promise with an `abort()` method for cancelling the stream. */\nexport type AbortablePromise<T> = Promise<T> & {\n /** Cancel the in-flight stream. The promise rejects with `AbortError`. */\n abort: () => void;\n};\n\n// ---------------------------------------------------------------------------\n// Client interface\n// ---------------------------------------------------------------------------\n\n/** Agent chat client returned by {@link createAgentChatClient}. */\nexport interface AgentChatClient {\n /** Create a new conversation thread. */\n createThread(): Promise<ThreadSummary>;\n\n /** List threads with cursor-based pagination (50 per page). */\n listThreads(cursor?: string): Promise<ThreadListPage>;\n\n /** Get a thread with its full message history. */\n getThread(threadId: string): Promise<Thread>;\n\n /** Update a thread's title. */\n updateThread(threadId: string, title: string): Promise<void>;\n\n /** Delete a thread (soft delete). */\n deleteThread(threadId: string): Promise<void>;\n\n /**\n * Send a message and stream the agent's response.\n *\n * Returns an {@link AbortablePromise} that resolves with\n * `{ stopReason, usage }` when the stream completes. Call `.abort()`\n * on the returned promise to cancel mid-stream.\n *\n * @param options.attachments - MindStudio CDN URLs to attach.\n * Images (`i.mscdn.ai`) are sent as vision input.\n * Documents (`f.mscdn.ai`) have text extracted into context.\n * Upload files first via `platform.uploadFile()`.\n */\n sendMessage(\n threadId: string,\n content: string,\n callbacks?: SendMessageCallbacks,\n options?: SendMessageOptions,\n ): AbortablePromise<SendMessageResult>;\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\nconst AGENT_BASE = '/_/agent';\n\nasync function request<T>(\n path: string,\n method: string,\n body?: unknown,\n): Promise<T> {\n const config = getConfig();\n const headers: Record<string, string> = {\n Authorization: `Bearer ${config.token}`,\n };\n\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n const res = await fetch(`${AGENT_BASE}${path}`, {\n method,\n headers,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n });\n\n if (!res.ok) {\n let errorMessage = `Agent chat request failed: ${res.status} ${res.statusText}`;\n let errorCode = 'agent_chat_error';\n try {\n const err = (await res.json()) as { error?: string; code?: string };\n if (err.error) {\n errorMessage = err.error;\n }\n if (err.code) {\n errorCode = err.code;\n }\n } catch {\n // Response wasn't JSON — use the default message\n }\n throw new MindStudioInterfaceError(errorMessage, errorCode, res.status);\n }\n\n return (await res.json()) as T;\n}\n\nfunction dispatchEvent(\n event: AgentChatEvent,\n callbacks: SendMessageCallbacks,\n): void {\n // Catch-all fires for every event\n callbacks.onEvent?.(event);\n\n // Named callbacks\n switch (event.type) {\n case 'text':\n callbacks.onText?.(event.text);\n break;\n case 'thinking':\n callbacks.onThinking?.(event.text);\n break;\n case 'thinking_complete':\n callbacks.onThinkingComplete?.(event.thinking, event.signature);\n break;\n case 'tool_call_start':\n callbacks.onToolCallStart?.(event.id, event.name);\n break;\n case 'tool_call_result':\n callbacks.onToolCallResult?.(event.id, event.output);\n break;\n case 'error':\n callbacks.onError?.(event.error);\n break;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create an agent chat client for thread-based conversations.\n *\n * The client is stateless — each method is an independent HTTP request.\n * Your application layer owns thread state, message arrays, and UI updates.\n *\n * @returns An {@link AgentChatClient} with methods for thread CRUD and\n * message streaming.\n *\n * @example\n * ```ts\n * import { createAgentChatClient } from '@mindstudio-ai/interface';\n *\n * const chat = createAgentChatClient();\n *\n * const thread = await chat.createThread();\n *\n * const response = chat.sendMessage(thread.id, 'Hello!', {\n * onText: (delta) => setAssistantMessage((prev) => prev + delta),\n * onToolCallStart: (id, name) => showToolSpinner(name),\n * onToolCallResult: (id, output) => showToolResult(output),\n * });\n *\n * const { stopReason, usage } = await response;\n * ```\n */\nexport function createAgentChatClient(): AgentChatClient {\n return {\n createThread() {\n return request<ThreadSummary>('/threads', 'POST');\n },\n\n listThreads(cursor?: string) {\n const query = cursor ? `?cursor=${encodeURIComponent(cursor)}` : '';\n return request<ThreadListPage>(`/threads${query}`, 'GET');\n },\n\n getThread(threadId: string) {\n return request<Thread>(`/threads/${threadId}`, 'GET');\n },\n\n async updateThread(threadId: string, title: string) {\n await request(`/threads/${threadId}`, 'PATCH', { title });\n },\n\n async deleteThread(threadId: string) {\n await request(`/threads/${threadId}`, 'DELETE');\n },\n\n sendMessage(\n threadId: string,\n content: string,\n callbacks?: SendMessageCallbacks,\n options?: SendMessageOptions,\n ): AbortablePromise<SendMessageResult> {\n const controller = new AbortController();\n const cb = callbacks ?? {};\n\n // Wire caller's signal to our internal controller\n if (cb.signal) {\n if (cb.signal.aborted) {\n controller.abort();\n } else {\n cb.signal.addEventListener('abort', () => controller.abort(), {\n once: true,\n });\n }\n }\n\n const promise = (async (): Promise<SendMessageResult> => {\n const config = getConfig();\n const url = `${AGENT_BASE}/threads/${threadId}/messages`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({\n content,\n ...(options?.attachments?.length && {\n attachments: options.attachments,\n }),\n }),\n signal: controller.signal,\n });\n\n if (!res.ok) {\n let errorMessage = `Send message failed: ${res.status} ${res.statusText}`;\n let errorCode = 'agent_chat_error';\n try {\n const err = (await res.json()) as {\n error?: string;\n code?: string;\n };\n if (err.error) {\n errorMessage = err.error;\n }\n if (err.code) {\n errorCode = err.code;\n }\n } catch {\n // Response wasn't JSON — use the default message\n }\n throw new MindStudioInterfaceError(\n errorMessage,\n errorCode,\n res.status,\n );\n }\n\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let result: SendMessageResult | undefined;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) {\n continue;\n }\n const json = line.slice(6);\n try {\n const event = JSON.parse(json) as AgentChatEvent;\n\n if (event.type === 'done') {\n result = {\n stopReason: event.stopReason,\n usage: event.usage,\n };\n }\n\n dispatchEvent(event, cb);\n } catch {\n // Skip malformed SSE lines\n }\n }\n }\n\n if (!result) {\n throw new MindStudioInterfaceError(\n 'Stream ended without a done event',\n 'stream_incomplete',\n );\n }\n\n return result;\n })();\n\n const abortable = promise as AbortablePromise<SendMessageResult>;\n abortable.abort = () => controller.abort();\n return abortable;\n },\n };\n}\n","/**\n * Platform actions — file uploads via presigned S3 POST.\n *\n * Uses the session token from `window.__MINDSTUDIO__` to request a\n * presigned upload URL from the platform, then uploads directly to S3.\n * Returns the public CDN URL.\n *\n * @example\n * ```ts\n * import { platform } from '@mindstudio-ai/interface';\n *\n * const file = document.querySelector('input[type=file]').files[0];\n * const url = await platform.uploadFile(file);\n *\n * // With progress and abort\n * const controller = new AbortController();\n * const url = await platform.uploadFile(file, {\n * onProgress: (fraction) => console.log(`${Math.round(fraction * 100)}%`),\n * signal: controller.signal,\n * });\n * ```\n */\n\nimport { getConfig } from './config.js';\nimport { MindStudioInterfaceError } from './errors.js';\n\n/**\n * Options for `platform.uploadFile()`.\n */\nexport interface UploadFileOptions {\n /** Called with upload progress as a fraction from 0 to 1. */\n onProgress?: (fraction: number) => void;\n\n /** AbortSignal to cancel the upload. */\n signal?: AbortSignal;\n}\n\n/**\n * The platform namespace — file upload actions.\n */\nexport const platform = {\n /**\n * Upload a file to the MindStudio CDN.\n *\n * Requests a presigned upload URL from the platform, then uploads\n * the file directly to S3. Returns the public CDN URL.\n *\n * @param file - The File to upload\n * @param options - Optional progress callback and abort signal\n * @returns CDN URL of the uploaded file\n *\n * @example\n * ```ts\n * const url = await platform.uploadFile(file);\n *\n * // With progress\n * const url = await platform.uploadFile(file, {\n * onProgress: (f) => setProgress(f),\n * });\n *\n * // With abort\n * const controller = new AbortController();\n * const url = await platform.uploadFile(file, {\n * signal: controller.signal,\n * });\n * // controller.abort() to cancel\n * ```\n */\n async uploadFile(file: File, options?: UploadFileOptions): Promise<string> {\n const config = getConfig();\n const { onProgress, signal } = options ?? {};\n\n // Check if already aborted\n signal?.throwIfAborted();\n\n // Step 1: Get presigned upload URL\n const presignUrl = '/_/generate-upload-request';\n const presignRes = await fetch(presignUrl, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${config.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n filename: file.name,\n contentType: file.type || 'application/octet-stream',\n }),\n signal,\n });\n\n if (!presignRes.ok) {\n throw new MindStudioInterfaceError(\n `Upload presign failed: ${presignRes.status} ${presignRes.statusText}`,\n 'upload_error',\n presignRes.status,\n );\n }\n\n const { uploadUrl, uploadFields, publicUrl } =\n (await presignRes.json()) as {\n uploadUrl: string;\n uploadFields: Record<string, string>;\n publicUrl: string;\n };\n\n // Step 2: Upload directly to S3\n const formData = new FormData();\n for (const [key, value] of Object.entries(uploadFields)) {\n formData.append(key, value);\n }\n formData.append('file', file); // must be last\n\n // Use XHR for upload progress (fetch doesn't support it)\n if (onProgress) {\n await xhrUpload(uploadUrl, formData, onProgress, signal);\n return publicUrl;\n }\n\n const uploadRes = await fetch(uploadUrl, {\n method: 'POST',\n body: formData,\n signal,\n });\n\n if (!uploadRes.ok) {\n throw new MindStudioInterfaceError(\n `File upload failed: ${uploadRes.status} ${uploadRes.statusText}`,\n 'upload_error',\n uploadRes.status,\n );\n }\n\n return publicUrl;\n },\n};\n\n/**\n * Upload via XMLHttpRequest to get progress events.\n * Falls back from fetch because fetch upload streams don't support progress.\n */\nfunction xhrUpload(\n url: string,\n formData: FormData,\n onProgress: (fraction: number) => void,\n signal?: AbortSignal,\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.addEventListener('progress', (e) => {\n if (e.lengthComputable) {\n onProgress(e.loaded / e.total);\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n onProgress(1);\n resolve();\n } else {\n reject(\n new MindStudioInterfaceError(\n `File upload failed: ${xhr.status} ${xhr.statusText}`,\n 'upload_error',\n xhr.status,\n ),\n );\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(\n new MindStudioInterfaceError(\n 'File upload failed: network error',\n 'upload_error',\n ),\n );\n });\n\n xhr.addEventListener('abort', () => {\n reject(new DOMException('Upload aborted', 'AbortError'));\n });\n\n // Wire up abort signal\n if (signal) {\n if (signal.aborted) {\n reject(new DOMException('Upload aborted', 'AbortError'));\n return;\n }\n signal.addEventListener('abort', () => xhr.abort(), { once: true });\n }\n\n xhr.open('POST', url);\n xhr.send(formData);\n });\n}\n","/**\n * Phone number utilities for auth flows.\n *\n * Provides country data, E.164 conversion, formatting, and validation.\n * No external dependencies — designed for login/signup UIs that need\n * a country code picker and phone number formatting.\n */\n\n// ---------------------------------------------------------------------------\n// Country data\n// ---------------------------------------------------------------------------\n\n/** A country with its dial code and flag emoji. */\nexport interface Country {\n /** ISO 3166-1 alpha-2 code (e.g. \"US\"). */\n code: string;\n /** International dial code with + prefix (e.g. \"+1\"). */\n dialCode: string;\n /** Country name in English. */\n name: string;\n /** Flag emoji. */\n flag: string;\n}\n\n/** All countries with dial codes, sorted alphabetically by name. */\nexport const countries: readonly Country[] = [\n { code: 'AF', dialCode: '+93', name: 'Afghanistan', flag: '🇦🇫' },\n { code: 'AL', dialCode: '+355', name: 'Albania', flag: '🇦🇱' },\n { code: 'DZ', dialCode: '+213', name: 'Algeria', flag: '🇩🇿' },\n { code: 'AD', dialCode: '+376', name: 'Andorra', flag: '🇦🇩' },\n { code: 'AO', dialCode: '+244', name: 'Angola', flag: '🇦🇴' },\n { code: 'AG', dialCode: '+1', name: 'Antigua and Barbuda', flag: '🇦🇬' },\n { code: 'AR', dialCode: '+54', name: 'Argentina', flag: '🇦🇷' },\n { code: 'AM', dialCode: '+374', name: 'Armenia', flag: '🇦🇲' },\n { code: 'AU', dialCode: '+61', name: 'Australia', flag: '🇦🇺' },\n { code: 'AT', dialCode: '+43', name: 'Austria', flag: '🇦🇹' },\n { code: 'AZ', dialCode: '+994', name: 'Azerbaijan', flag: '🇦🇿' },\n { code: 'BS', dialCode: '+1', name: 'Bahamas', flag: '🇧🇸' },\n { code: 'BH', dialCode: '+973', name: 'Bahrain', flag: '🇧🇭' },\n { code: 'BD', dialCode: '+880', name: 'Bangladesh', flag: '🇧🇩' },\n { code: 'BB', dialCode: '+1', name: 'Barbados', flag: '🇧🇧' },\n { code: 'BY', dialCode: '+375', name: 'Belarus', flag: '🇧🇾' },\n { code: 'BE', dialCode: '+32', name: 'Belgium', flag: '🇧🇪' },\n { code: 'BZ', dialCode: '+501', name: 'Belize', flag: '🇧🇿' },\n { code: 'BJ', dialCode: '+229', name: 'Benin', flag: '🇧🇯' },\n { code: 'BT', dialCode: '+975', name: 'Bhutan', flag: '🇧🇹' },\n { code: 'BO', dialCode: '+591', name: 'Bolivia', flag: '🇧🇴' },\n { code: 'BA', dialCode: '+387', name: 'Bosnia and Herzegovina', flag: '🇧🇦' },\n { code: 'BW', dialCode: '+267', name: 'Botswana', flag: '🇧🇼' },\n { code: 'BR', dialCode: '+55', name: 'Brazil', flag: '🇧🇷' },\n { code: 'BN', dialCode: '+673', name: 'Brunei', flag: '🇧🇳' },\n { code: 'BG', dialCode: '+359', name: 'Bulgaria', flag: '🇧🇬' },\n { code: 'BF', dialCode: '+226', name: 'Burkina Faso', flag: '🇧🇫' },\n { code: 'BI', dialCode: '+257', name: 'Burundi', flag: '🇧🇮' },\n { code: 'CV', dialCode: '+238', name: 'Cabo Verde', flag: '🇨🇻' },\n { code: 'KH', dialCode: '+855', name: 'Cambodia', flag: '🇰🇭' },\n { code: 'CM', dialCode: '+237', name: 'Cameroon', flag: '🇨🇲' },\n { code: 'CA', dialCode: '+1', name: 'Canada', flag: '🇨🇦' },\n {\n code: 'CF',\n dialCode: '+236',\n name: 'Central African Republic',\n flag: '🇨🇫',\n },\n { code: 'TD', dialCode: '+235', name: 'Chad', flag: '🇹🇩' },\n { code: 'CL', dialCode: '+56', name: 'Chile', flag: '🇨🇱' },\n { code: 'CN', dialCode: '+86', name: 'China', flag: '🇨🇳' },\n { code: 'CO', dialCode: '+57', name: 'Colombia', flag: '🇨🇴' },\n { code: 'KM', dialCode: '+269', name: 'Comoros', flag: '🇰🇲' },\n { code: 'CG', dialCode: '+242', name: 'Congo', flag: '🇨🇬' },\n { code: 'CD', dialCode: '+243', name: 'Congo (DRC)', flag: '🇨🇩' },\n { code: 'CR', dialCode: '+506', name: 'Costa Rica', flag: '🇨🇷' },\n { code: 'HR', dialCode: '+385', name: 'Croatia', flag: '🇭🇷' },\n { code: 'CU', dialCode: '+53', name: 'Cuba', flag: '🇨🇺' },\n { code: 'CY', dialCode: '+357', name: 'Cyprus', flag: '🇨🇾' },\n { code: 'CZ', dialCode: '+420', name: 'Czechia', flag: '🇨🇿' },\n { code: 'CI', dialCode: '+225', name: \"Cote d'Ivoire\", flag: '🇨🇮' },\n { code: 'DK', dialCode: '+45', name: 'Denmark', flag: '🇩🇰' },\n { code: 'DJ', dialCode: '+253', name: 'Djibouti', flag: '🇩🇯' },\n { code: 'DM', dialCode: '+1', name: 'Dominica', flag: '🇩🇲' },\n { code: 'DO', dialCode: '+1', name: 'Dominican Republic', flag: '🇩🇴' },\n { code: 'EC', dialCode: '+593', name: 'Ecuador', flag: '🇪🇨' },\n { code: 'EG', dialCode: '+20', name: 'Egypt', flag: '🇪🇬' },\n { code: 'SV', dialCode: '+503', name: 'El Salvador', flag: '🇸🇻' },\n { code: 'GQ', dialCode: '+240', name: 'Equatorial Guinea', flag: '🇬🇶' },\n { code: 'ER', dialCode: '+291', name: 'Eritrea', flag: '🇪🇷' },\n { code: 'EE', dialCode: '+372', name: 'Estonia', flag: '🇪🇪' },\n { code: 'SZ', dialCode: '+268', name: 'Eswatini', flag: '🇸🇿' },\n { code: 'ET', dialCode: '+251', name: 'Ethiopia', flag: '🇪🇹' },\n { code: 'FJ', dialCode: '+679', name: 'Fiji', flag: '🇫🇯' },\n { code: 'FI', dialCode: '+358', name: 'Finland', flag: '🇫🇮' },\n { code: 'FR', dialCode: '+33', name: 'France', flag: '🇫🇷' },\n { code: 'GA', dialCode: '+241', name: 'Gabon', flag: '🇬🇦' },\n { code: 'GM', dialCode: '+220', name: 'Gambia', flag: '🇬🇲' },\n { code: 'GE', dialCode: '+995', name: 'Georgia', flag: '🇬🇪' },\n { code: 'DE', dialCode: '+49', name: 'Germany', flag: '🇩🇪' },\n { code: 'GH', dialCode: '+233', name: 'Ghana', flag: '🇬🇭' },\n { code: 'GR', dialCode: '+30', name: 'Greece', flag: '🇬🇷' },\n { code: 'GD', dialCode: '+1', name: 'Grenada', flag: '🇬🇩' },\n { code: 'GT', dialCode: '+502', name: 'Guatemala', flag: '🇬🇹' },\n { code: 'GN', dialCode: '+224', name: 'Guinea', flag: '🇬🇳' },\n { code: 'GW', dialCode: '+245', name: 'Guinea-Bissau', flag: '🇬🇼' },\n { code: 'GY', dialCode: '+592', name: 'Guyana', flag: '🇬🇾' },\n { code: 'HT', dialCode: '+509', name: 'Haiti', flag: '🇭🇹' },\n { code: 'HN', dialCode: '+504', name: 'Honduras', flag: '🇭🇳' },\n { code: 'HK', dialCode: '+852', name: 'Hong Kong', flag: '🇭🇰' },\n { code: 'HU', dialCode: '+36', name: 'Hungary', flag: '🇭🇺' },\n { code: 'IS', dialCode: '+354', name: 'Iceland', flag: '🇮🇸' },\n { code: 'IN', dialCode: '+91', name: 'India', flag: '🇮🇳' },\n { code: 'ID', dialCode: '+62', name: 'Indonesia', flag: '🇮🇩' },\n { code: 'IR', dialCode: '+98', name: 'Iran', flag: '🇮🇷' },\n { code: 'IQ', dialCode: '+964', name: 'Iraq', flag: '🇮🇶' },\n { code: 'IE', dialCode: '+353', name: 'Ireland', flag: '🇮🇪' },\n { code: 'IL', dialCode: '+972', name: 'Israel', flag: '🇮🇱' },\n { code: 'IT', dialCode: '+39', name: 'Italy', flag: '🇮🇹' },\n { code: 'JM', dialCode: '+1', name: 'Jamaica', flag: '🇯🇲' },\n { code: 'JP', dialCode: '+81', name: 'Japan', flag: '🇯🇵' },\n { code: 'JO', dialCode: '+962', name: 'Jordan', flag: '🇯🇴' },\n { code: 'KZ', dialCode: '+7', name: 'Kazakhstan', flag: '🇰🇿' },\n { code: 'KE', dialCode: '+254', name: 'Kenya', flag: '🇰🇪' },\n { code: 'KI', dialCode: '+686', name: 'Kiribati', flag: '🇰🇮' },\n { code: 'KW', dialCode: '+965', name: 'Kuwait', flag: '🇰🇼' },\n { code: 'KG', dialCode: '+996', name: 'Kyrgyzstan', flag: '🇰🇬' },\n { code: 'LA', dialCode: '+856', name: 'Laos', flag: '🇱🇦' },\n { code: 'LV', dialCode: '+371', name: 'Latvia', flag: '🇱🇻' },\n { code: 'LB', dialCode: '+961', name: 'Lebanon', flag: '🇱🇧' },\n { code: 'LS', dialCode: '+266', name: 'Lesotho', flag: '🇱🇸' },\n { code: 'LR', dialCode: '+231', name: 'Liberia', flag: '🇱🇷' },\n { code: 'LY', dialCode: '+218', name: 'Libya', flag: '🇱🇾' },\n { code: 'LI', dialCode: '+423', name: 'Liechtenstein', flag: '🇱🇮' },\n { code: 'LT', dialCode: '+370', name: 'Lithuania', flag: '🇱🇹' },\n { code: 'LU', dialCode: '+352', name: 'Luxembourg', flag: '🇱🇺' },\n { code: 'MO', dialCode: '+853', name: 'Macao', flag: '🇲🇴' },\n { code: 'MG', dialCode: '+261', name: 'Madagascar', flag: '🇲🇬' },\n { code: 'MW', dialCode: '+265', name: 'Malawi', flag: '🇲🇼' },\n { code: 'MY', dialCode: '+60', name: 'Malaysia', flag: '🇲🇾' },\n { code: 'MV', dialCode: '+960', name: 'Maldives', flag: '🇲🇻' },\n { code: 'ML', dialCode: '+223', name: 'Mali', flag: '🇲🇱' },\n { code: 'MT', dialCode: '+356', name: 'Malta', flag: '🇲🇹' },\n { code: 'MH', dialCode: '+692', name: 'Marshall Islands', flag: '🇲🇭' },\n { code: 'MR', dialCode: '+222', name: 'Mauritania', flag: '🇲🇷' },\n { code: 'MU', dialCode: '+230', name: 'Mauritius', flag: '🇲🇺' },\n { code: 'MX', dialCode: '+52', name: 'Mexico', flag: '🇲🇽' },\n { code: 'FM', dialCode: '+691', name: 'Micronesia', flag: '🇫🇲' },\n { code: 'MD', dialCode: '+373', name: 'Moldova', flag: '🇲🇩' },\n { code: 'MC', dialCode: '+377', name: 'Monaco', flag: '🇲🇨' },\n { code: 'MN', dialCode: '+976', name: 'Mongolia', flag: '🇲🇳' },\n { code: 'ME', dialCode: '+382', name: 'Montenegro', flag: '🇲🇪' },\n { code: 'MA', dialCode: '+212', name: 'Morocco', flag: '🇲🇦' },\n { code: 'MZ', dialCode: '+258', name: 'Mozambique', flag: '🇲🇿' },\n { code: 'MM', dialCode: '+95', name: 'Myanmar', flag: '🇲🇲' },\n { code: 'NA', dialCode: '+264', name: 'Namibia', flag: '🇳🇦' },\n { code: 'NR', dialCode: '+674', name: 'Nauru', flag: '🇳🇷' },\n { code: 'NP', dialCode: '+977', name: 'Nepal', flag: '🇳🇵' },\n { code: 'NL', dialCode: '+31', name: 'Netherlands', flag: '🇳🇱' },\n { code: 'NZ', dialCode: '+64', name: 'New Zealand', flag: '🇳🇿' },\n { code: 'NI', dialCode: '+505', name: 'Nicaragua', flag: '🇳🇮' },\n { code: 'NE', dialCode: '+227', name: 'Niger', flag: '🇳🇪' },\n { code: 'NG', dialCode: '+234', name: 'Nigeria', flag: '🇳🇬' },\n { code: 'KP', dialCode: '+850', name: 'North Korea', flag: '🇰🇵' },\n { code: 'MK', dialCode: '+389', name: 'North Macedonia', flag: '🇲🇰' },\n { code: 'NO', dialCode: '+47', name: 'Norway', flag: '🇳🇴' },\n { code: 'OM', dialCode: '+968', name: 'Oman', flag: '🇴🇲' },\n { code: 'PK', dialCode: '+92', name: 'Pakistan', flag: '🇵🇰' },\n { code: 'PW', dialCode: '+680', name: 'Palau', flag: '🇵🇼' },\n { code: 'PS', dialCode: '+970', name: 'Palestine', flag: '🇵🇸' },\n { code: 'PA', dialCode: '+507', name: 'Panama', flag: '🇵🇦' },\n { code: 'PG', dialCode: '+675', name: 'Papua New Guinea', flag: '🇵🇬' },\n { code: 'PY', dialCode: '+595', name: 'Paraguay', flag: '🇵🇾' },\n { code: 'PE', dialCode: '+51', name: 'Peru', flag: '🇵🇪' },\n { code: 'PH', dialCode: '+63', name: 'Philippines', flag: '🇵🇭' },\n { code: 'PL', dialCode: '+48', name: 'Poland', flag: '🇵🇱' },\n { code: 'PT', dialCode: '+351', name: 'Portugal', flag: '🇵🇹' },\n { code: 'PR', dialCode: '+1', name: 'Puerto Rico', flag: '🇵🇷' },\n { code: 'QA', dialCode: '+974', name: 'Qatar', flag: '🇶🇦' },\n { code: 'RO', dialCode: '+40', name: 'Romania', flag: '🇷🇴' },\n { code: 'RU', dialCode: '+7', name: 'Russia', flag: '🇷🇺' },\n { code: 'RW', dialCode: '+250', name: 'Rwanda', flag: '🇷🇼' },\n { code: 'KN', dialCode: '+1', name: 'Saint Kitts and Nevis', flag: '🇰🇳' },\n { code: 'LC', dialCode: '+1', name: 'Saint Lucia', flag: '🇱🇨' },\n {\n code: 'VC',\n dialCode: '+1',\n name: 'Saint Vincent and the Grenadines',\n flag: '🇻🇨',\n },\n { code: 'WS', dialCode: '+685', name: 'Samoa', flag: '🇼🇸' },\n { code: 'SM', dialCode: '+378', name: 'San Marino', flag: '🇸🇲' },\n { code: 'ST', dialCode: '+239', name: 'Sao Tome and Principe', flag: '🇸🇹' },\n { code: 'SA', dialCode: '+966', name: 'Saudi Arabia', flag: '🇸🇦' },\n { code: 'SN', dialCode: '+221', name: 'Senegal', flag: '🇸🇳' },\n { code: 'RS', dialCode: '+381', name: 'Serbia', flag: '🇷🇸' },\n { code: 'SC', dialCode: '+248', name: 'Seychelles', flag: '🇸🇨' },\n { code: 'SL', dialCode: '+232', name: 'Sierra Leone', flag: '🇸🇱' },\n { code: 'SG', dialCode: '+65', name: 'Singapore', flag: '🇸🇬' },\n { code: 'SK', dialCode: '+421', name: 'Slovakia', flag: '🇸🇰' },\n { code: 'SI', dialCode: '+386', name: 'Slovenia', flag: '🇸🇮' },\n { code: 'SB', dialCode: '+677', name: 'Solomon Islands', flag: '🇸🇧' },\n { code: 'SO', dialCode: '+252', name: 'Somalia', flag: '🇸🇴' },\n { code: 'ZA', dialCode: '+27', name: 'South Africa', flag: '🇿🇦' },\n { code: 'KR', dialCode: '+82', name: 'South Korea', flag: '🇰🇷' },\n { code: 'SS', dialCode: '+211', name: 'South Sudan', flag: '🇸🇸' },\n { code: 'ES', dialCode: '+34', name: 'Spain', flag: '🇪🇸' },\n { code: 'LK', dialCode: '+94', name: 'Sri Lanka', flag: '🇱🇰' },\n { code: 'SD', dialCode: '+249', name: 'Sudan', flag: '🇸🇩' },\n { code: 'SR', dialCode: '+597', name: 'Suriname', flag: '🇸🇷' },\n { code: 'SE', dialCode: '+46', name: 'Sweden', flag: '🇸🇪' },\n { code: 'CH', dialCode: '+41', name: 'Switzerland', flag: '🇨🇭' },\n { code: 'SY', dialCode: '+963', name: 'Syria', flag: '🇸🇾' },\n { code: 'TW', dialCode: '+886', name: 'Taiwan', flag: '🇹🇼' },\n { code: 'TJ', dialCode: '+992', name: 'Tajikistan', flag: '🇹🇯' },\n { code: 'TZ', dialCode: '+255', name: 'Tanzania', flag: '🇹🇿' },\n { code: 'TH', dialCode: '+66', name: 'Thailand', flag: '🇹🇭' },\n { code: 'TL', dialCode: '+670', name: 'Timor-Leste', flag: '🇹🇱' },\n { code: 'TG', dialCode: '+228', name: 'Togo', flag: '🇹🇬' },\n { code: 'TO', dialCode: '+676', name: 'Tonga', flag: '🇹🇴' },\n { code: 'TT', dialCode: '+1', name: 'Trinidad and Tobago', flag: '🇹🇹' },\n { code: 'TN', dialCode: '+216', name: 'Tunisia', flag: '🇹🇳' },\n { code: 'TR', dialCode: '+90', name: 'Turkey', flag: '🇹🇷' },\n { code: 'TM', dialCode: '+993', name: 'Turkmenistan', flag: '🇹🇲' },\n { code: 'TV', dialCode: '+688', name: 'Tuvalu', flag: '🇹🇻' },\n { code: 'UG', dialCode: '+256', name: 'Uganda', flag: '🇺🇬' },\n { code: 'UA', dialCode: '+380', name: 'Ukraine', flag: '🇺🇦' },\n { code: 'AE', dialCode: '+971', name: 'United Arab Emirates', flag: '🇦🇪' },\n { code: 'GB', dialCode: '+44', name: 'United Kingdom', flag: '🇬🇧' },\n { code: 'US', dialCode: '+1', name: 'United States', flag: '🇺🇸' },\n { code: 'UY', dialCode: '+598', name: 'Uruguay', flag: '🇺🇾' },\n { code: 'UZ', dialCode: '+998', name: 'Uzbekistan', flag: '🇺🇿' },\n { code: 'VU', dialCode: '+678', name: 'Vanuatu', flag: '🇻🇺' },\n { code: 'VA', dialCode: '+39', name: 'Vatican City', flag: '🇻🇦' },\n { code: 'VE', dialCode: '+58', name: 'Venezuela', flag: '🇻🇪' },\n { code: 'VN', dialCode: '+84', name: 'Vietnam', flag: '🇻🇳' },\n { code: 'YE', dialCode: '+967', name: 'Yemen', flag: '🇾🇪' },\n { code: 'ZM', dialCode: '+260', name: 'Zambia', flag: '🇿🇲' },\n { code: 'ZW', dialCode: '+263', name: 'Zimbabwe', flag: '🇿🇼' },\n];\n\n// ---------------------------------------------------------------------------\n// Country lookup helpers\n// ---------------------------------------------------------------------------\n\nconst byCode = new Map(countries.map((c) => [c.code, c]));\n\n/** Common IANA timezone → country code mapping. */\nconst timezoneToCountry: Record<string, string> = {\n 'America/New_York': 'US',\n 'America/Chicago': 'US',\n 'America/Denver': 'US',\n 'America/Los_Angeles': 'US',\n 'America/Anchorage': 'US',\n 'Pacific/Honolulu': 'US',\n 'America/Phoenix': 'US',\n 'America/Indiana/Indianapolis': 'US',\n 'America/Toronto': 'CA',\n 'America/Vancouver': 'CA',\n 'America/Edmonton': 'CA',\n 'America/Winnipeg': 'CA',\n 'America/Halifax': 'CA',\n 'America/St_Johns': 'CA',\n 'Europe/London': 'GB',\n 'Europe/Dublin': 'IE',\n 'Europe/Paris': 'FR',\n 'Europe/Berlin': 'DE',\n 'Europe/Madrid': 'ES',\n 'Europe/Rome': 'IT',\n 'Europe/Amsterdam': 'NL',\n 'Europe/Brussels': 'BE',\n 'Europe/Zurich': 'CH',\n 'Europe/Vienna': 'AT',\n 'Europe/Stockholm': 'SE',\n 'Europe/Oslo': 'NO',\n 'Europe/Copenhagen': 'DK',\n 'Europe/Helsinki': 'FI',\n 'Europe/Warsaw': 'PL',\n 'Europe/Prague': 'CZ',\n 'Europe/Bucharest': 'RO',\n 'Europe/Budapest': 'HU',\n 'Europe/Athens': 'GR',\n 'Europe/Istanbul': 'TR',\n 'Europe/Moscow': 'RU',\n 'Europe/Kiev': 'UA',\n 'Europe/Lisbon': 'PT',\n 'Europe/Belgrade': 'RS',\n 'Europe/Zagreb': 'HR',\n 'Europe/Bratislava': 'SK',\n 'Europe/Ljubljana': 'SI',\n 'Europe/Tallinn': 'EE',\n 'Europe/Riga': 'LV',\n 'Europe/Vilnius': 'LT',\n 'Asia/Tokyo': 'JP',\n 'Asia/Seoul': 'KR',\n 'Asia/Shanghai': 'CN',\n 'Asia/Hong_Kong': 'HK',\n 'Asia/Taipei': 'TW',\n 'Asia/Singapore': 'SG',\n 'Asia/Kolkata': 'IN',\n 'Asia/Karachi': 'PK',\n 'Asia/Dhaka': 'BD',\n 'Asia/Bangkok': 'TH',\n 'Asia/Jakarta': 'ID',\n 'Asia/Manila': 'PH',\n 'Asia/Kuala_Lumpur': 'MY',\n 'Asia/Ho_Chi_Minh': 'VN',\n 'Asia/Riyadh': 'SA',\n 'Asia/Dubai': 'AE',\n 'Asia/Tehran': 'IR',\n 'Asia/Baghdad': 'IQ',\n 'Asia/Beirut': 'LB',\n 'Asia/Jerusalem': 'IL',\n 'Asia/Amman': 'JO',\n 'Asia/Almaty': 'KZ',\n 'Asia/Tashkent': 'UZ',\n 'Asia/Colombo': 'LK',\n 'Asia/Kathmandu': 'NP',\n 'Asia/Yangon': 'MM',\n 'Australia/Sydney': 'AU',\n 'Australia/Melbourne': 'AU',\n 'Australia/Brisbane': 'AU',\n 'Australia/Perth': 'AU',\n 'Australia/Adelaide': 'AU',\n 'Pacific/Auckland': 'NZ',\n 'Pacific/Fiji': 'FJ',\n 'Africa/Cairo': 'EG',\n 'Africa/Lagos': 'NG',\n 'Africa/Nairobi': 'KE',\n 'Africa/Johannesburg': 'ZA',\n 'Africa/Casablanca': 'MA',\n 'Africa/Accra': 'GH',\n 'Africa/Addis_Ababa': 'ET',\n 'Africa/Dar_es_Salaam': 'TZ',\n 'Africa/Kampala': 'UG',\n 'America/Mexico_City': 'MX',\n 'America/Bogota': 'CO',\n 'America/Lima': 'PE',\n 'America/Santiago': 'CL',\n 'America/Buenos_Aires': 'AR',\n 'America/Sao_Paulo': 'BR',\n 'America/Caracas': 'VE',\n 'America/Guatemala': 'GT',\n 'America/Havana': 'CU',\n 'America/Panama': 'PA',\n 'America/Jamaica': 'JM',\n};\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Detect the user's country from their timezone.\n * Falls back to `'US'` if the timezone can't be mapped.\n */\nexport function detectCountry(): string {\n try {\n const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;\n return timezoneToCountry[tz] ?? 'US';\n } catch {\n return 'US';\n }\n}\n\n/**\n * Format an E.164 phone number for display.\n *\n * US/CA numbers: `+1 (555) 123-4567`\n * Others: `+{dialCode} {rest}`\n */\nexport function format(e164: string): string {\n if (!e164.startsWith('+')) {\n return e164;\n }\n\n const digits = e164.slice(1);\n\n // US/CA: +1 followed by 10 digits\n if (digits.startsWith('1') && digits.length === 11) {\n const area = digits.slice(1, 4);\n const prefix = digits.slice(4, 7);\n const line = digits.slice(7);\n return `+1 (${area}) ${prefix}-${line}`;\n }\n\n // Find matching dial code (try longest match first)\n for (let len = 4; len >= 1; len--) {\n const candidate = '+' + digits.slice(0, len);\n const match = countries.find((c) => c.dialCode === candidate);\n if (match) {\n const rest = digits.slice(len);\n return `${match.dialCode} ${rest}`;\n }\n }\n\n return e164;\n}\n\n/**\n * Convert a national phone number to E.164 format.\n *\n * @param national - Phone number with or without formatting (e.g. \"(555) 123-4567\")\n * @param countryCode - ISO 3166-1 alpha-2 code (e.g. \"US\")\n * @returns E.164 formatted number (e.g. \"+15551234567\")\n */\nexport function toE164(national: string, countryCode: string): string {\n const digits = national.replace(/\\D/g, '');\n const country = byCode.get(countryCode);\n if (!country) {\n return '+' + digits;\n }\n const dialDigits = country.dialCode.slice(1); // remove +\n // If the number already starts with the dial code, don't double-add\n if (digits.startsWith(dialDigits)) {\n return '+' + digits;\n }\n return country.dialCode + digits;\n}\n\n/**\n * Check if a string is a valid E.164 phone number.\n * Must start with + followed by 7-15 digits.\n */\nexport function isValid(phone: string): boolean {\n return /^\\+[1-9]\\d{6,14}$/.test(phone);\n}\n","/**\n * Email validation helper for auth flows.\n */\n\n/** Basic email format check. Not RFC 5322 exhaustive. */\nexport function isValid(email: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);\n}\n","/**\n * Auth — app-managed authentication for MindStudio v2 apps.\n *\n * Provides verification code flows (email + SMS), session state\n * management, and phone/email validation helpers. The platform\n * handles code delivery, cookie management, and user storage —\n * developers build their own login UI using these methods.\n *\n * ## How it works\n *\n * ```\n * // 1. Send a verification code\n * const { verificationId } = await auth.sendEmailCode('user@example.com');\n *\n * // 2. User enters the code in your UI\n * const user = await auth.verifyEmailCode(verificationId, '123456');\n *\n * // 3. Session is now active — all SDK calls use the authenticated token\n * const result = await api.getDashboard(); // uses authenticated session\n * auth.getCurrentUser(); // { id, email, phone, roles, createdAt }\n * ```\n *\n * Verify, confirm, and logout methods update `window.__MINDSTUDIO__`\n * in-place so all downstream calls (method invocation, agent chat,\n * uploads) immediately use the new session. No page refresh needed.\n *\n * @example\n * ```tsx\n * import { auth } from '@mindstudio-ai/interface';\n *\n * function LoginPage() {\n * const [email, setEmail] = useState('');\n * const [verificationId, setVerificationId] = useState('');\n * const [code, setCode] = useState('');\n *\n * const handleSend = async () => {\n * const { verificationId } = await auth.sendEmailCode(email);\n * setVerificationId(verificationId);\n * };\n *\n * const handleVerify = async () => {\n * await auth.verifyEmailCode(verificationId, code);\n * // Session updated in-place — navigate to your app\n * window.location.href = '/dashboard';\n * };\n * }\n * ```\n */\n\nimport { getConfig, updateConfig } from './config.js';\nimport { MindStudioInterfaceError } from './errors.js';\nimport type { AppUser, AuthSessionBundle } from './types.js';\nimport * as phoneHelpers from './auth-phone.js';\nimport * as emailHelpers from './auth-email.js';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nasync function authFetch<T>(\n path: string,\n method: 'GET' | 'POST',\n body?: Record<string, unknown>,\n): Promise<T> {\n const config = getConfig();\n const headers: Record<string, string> = {\n Authorization: `Bearer ${config.token}`,\n };\n\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n const res = await fetch(path, {\n method,\n headers,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n });\n\n if (!res.ok) {\n let message = `Auth request failed: ${res.status} ${res.statusText}`;\n let code = 'auth_error';\n try {\n const err = (await res.json()) as { error?: string; code?: string };\n if (err.error) {\n message = err.error;\n }\n if (err.code) {\n code = err.code;\n }\n } catch {\n // Response wasn't JSON\n }\n throw new MindStudioInterfaceError(message, code, res.status);\n }\n\n return (await res.json()) as T;\n}\n\nconst authListeners: Set<(user: AppUser | null) => void> = new Set();\n\nfunction applySession(bundle: AuthSessionBundle): void {\n updateConfig({\n token: bundle.token,\n user: bundle.user,\n methods: bundle.methods,\n visitorId: bundle.visitorId,\n });\n authListeners.forEach((cb) => cb(bundle.user));\n}\n\nfunction requireUser(bundle: AuthSessionBundle): AppUser {\n if (!bundle.user) {\n throw new MindStudioInterfaceError(\n 'Verification succeeded but no user was returned',\n 'auth_error',\n );\n }\n return bundle.user;\n}\n\nfunction updateUserAndNotify(update: Partial<AppUser>): void {\n const config = getConfig();\n if (config.user) {\n Object.assign(config.user, update);\n authListeners.forEach((cb) => cb(config.user));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Auth interface\n// ---------------------------------------------------------------------------\n\n/**\n * The auth namespace — authentication flows, state, and helpers.\n *\n * Auth methods throw {@link MindStudioInterfaceError} on failure.\n * Common error codes:\n *\n * | Code | Status | Meaning |\n * |------|--------|---------|\n * | `rate_limited` | 429 | Too many code requests (max 5 per 15 min per identifier) |\n * | `invalid_code` | 400 | Wrong verification code |\n * | `verification_expired` | 400 | Code expired (10 min TTL) — request a new one |\n * | `max_attempts_exceeded` | 400 | Too many incorrect attempts (max 3) — request a new code |\n * | `not_authenticated` | 401 | Auth cookie missing (change/logout endpoints) |\n * | `invalid_session` | 401 | Auth cookie expired or invalid |\n */\nexport interface Auth {\n // -- State --\n\n /** The current authenticated user, or `null` if not authenticated. */\n readonly currentUser: AppUser | null;\n\n /** Get the current authenticated user, or `null` if not authenticated. */\n getCurrentUser(): AppUser | null;\n\n /** Whether the current session is authenticated. */\n isAuthenticated(): boolean;\n\n /**\n * The stable per-browser, per-app visitor identifier, or `null` if\n * unavailable (e.g. cached bootstrap from before this field existed).\n *\n * Opaque string backed by a server-set HttpOnly cookie. For authed\n * sessions this is the user's platform user ID; for guests it's a\n * per-browser UUID. Persists ~1 year; refreshed on each page load.\n * Updates in-place on login/logout transitions.\n */\n readonly currentVisitorId: string | null;\n\n /** Get the current visitor ID, or `null` if unavailable. */\n getCurrentVisitorId(): string | null;\n\n // -- Email code flow --\n\n /** Send a 6-digit verification code to an email address. */\n sendEmailCode(email: string): Promise<{ verificationId: string }>;\n\n /**\n * Verify an email code. On success, updates the session in-place\n * and returns the authenticated user.\n */\n verifyEmailCode(verificationId: string, code: string): Promise<AppUser>;\n\n // -- SMS code flow --\n\n /** Send a 6-digit verification code via SMS. Phone must be E.164. */\n sendSmsCode(phone: string): Promise<{ verificationId: string }>;\n\n /**\n * Verify an SMS code. On success, updates the session in-place\n * and returns the authenticated user.\n */\n verifySmsCode(verificationId: string, code: string): Promise<AppUser>;\n\n // -- Email/phone change (requires authentication) --\n\n /** Request an email change. Sends a code to the new email. */\n requestEmailChange(newEmail: string): Promise<void>;\n\n /** Confirm an email change with the verification code. */\n confirmEmailChange(newEmail: string, code: string): Promise<AppUser>;\n\n /** Request a phone change. Sends a code to the new phone (E.164). */\n requestPhoneChange(newPhone: string): Promise<void>;\n\n /** Confirm a phone change with the verification code. */\n confirmPhoneChange(newPhone: string, code: string): Promise<AppUser>;\n\n // -- Session --\n\n /** Log out. Clears the cookie and updates the session to unauthenticated. */\n logout(): Promise<void>;\n\n // -- API keys --\n\n /**\n * Generate an API key for the current user. Returns the full key\n * (shown once). The user's `apiKey` field updates to the masked\n * value and `onAuthStateChanged` fires.\n *\n * @throws `not_authenticated` (401) if no session\n * @throws `not_supported` (400) if api-key auth is not enabled\n */\n createApiKey(): Promise<{ key: string }>;\n\n /**\n * Revoke the current user's API key. The user's `apiKey` field\n * becomes `null` and `onAuthStateChanged` fires.\n *\n * @throws `not_authenticated` (401) if no session\n */\n revokeApiKey(): Promise<void>;\n\n /**\n * Subscribe to auth state changes. Fires immediately with the\n * current state, then again whenever verify, confirm, or logout\n * updates the session.\n *\n * @returns An unsubscribe function.\n *\n * @example\n * ```ts\n * // React hook\n * function useAuth() {\n * const [user, setUser] = useState<AppUser | null>(null);\n * useEffect(() => auth.onAuthStateChanged(setUser), []);\n * return user;\n * }\n * ```\n */\n onAuthStateChanged(callback: (user: AppUser | null) => void): () => void;\n\n // -- Helpers --\n\n /** Phone number utilities — countries, formatting, validation. */\n phone: {\n /** All countries with dial codes, sorted alphabetically. */\n countries: readonly phoneHelpers.Country[];\n /** Detect the user's country from their timezone. Falls back to `'US'`. */\n detectCountry(): string;\n /** Format an E.164 number for display (e.g. `+1 (555) 123-4567`). */\n format(e164: string): string;\n /** Convert a national number to E.164 (e.g. `('5551234567', 'US') → '+15551234567'`). */\n toE164(national: string, countryCode: string): string;\n /** Check if a string is a valid E.164 phone number. */\n isValid(phone: string): boolean;\n };\n\n /** Email validation. */\n email: {\n /** Basic email format check. */\n isValid(email: string): boolean;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\nexport const auth: Auth = {\n // -- State --\n\n get currentUser() {\n return getConfig().user;\n },\n\n getCurrentUser() {\n return getConfig().user;\n },\n\n isAuthenticated() {\n return getConfig().user !== null;\n },\n\n get currentVisitorId() {\n return getConfig().visitorId ?? null;\n },\n\n getCurrentVisitorId() {\n return getConfig().visitorId ?? null;\n },\n\n // -- Email code flow --\n\n sendEmailCode(email: string) {\n return authFetch<{ verificationId: string }>('/_/auth/email/send', 'POST', {\n email,\n });\n },\n\n async verifyEmailCode(verificationId: string, code: string) {\n const bundle = await authFetch<AuthSessionBundle>(\n '/_/auth/email/verify',\n 'POST',\n { verificationId, code },\n );\n applySession(bundle);\n return requireUser(bundle);\n },\n\n // -- SMS code flow --\n\n sendSmsCode(phone: string) {\n return authFetch<{ verificationId: string }>('/_/auth/sms/send', 'POST', {\n phone,\n });\n },\n\n async verifySmsCode(verificationId: string, code: string) {\n const bundle = await authFetch<AuthSessionBundle>(\n '/_/auth/sms/verify',\n 'POST',\n { verificationId, code },\n );\n applySession(bundle);\n return requireUser(bundle);\n },\n\n // -- Email/phone change --\n\n async requestEmailChange(newEmail: string) {\n await authFetch('/_/auth/email/change', 'POST', { newEmail });\n },\n\n async confirmEmailChange(newEmail: string, code: string) {\n const bundle = await authFetch<AuthSessionBundle>(\n '/_/auth/email/change/confirm',\n 'POST',\n { newEmail, code },\n );\n applySession(bundle);\n return requireUser(bundle);\n },\n\n async requestPhoneChange(newPhone: string) {\n await authFetch('/_/auth/phone/change', 'POST', { newPhone });\n },\n\n async confirmPhoneChange(newPhone: string, code: string) {\n const bundle = await authFetch<AuthSessionBundle>(\n '/_/auth/phone/change/confirm',\n 'POST',\n { newPhone, code },\n );\n applySession(bundle);\n return requireUser(bundle);\n },\n\n // -- Session --\n\n async logout() {\n const bundle = await authFetch<AuthSessionBundle>(\n '/_/auth/logout',\n 'POST',\n {},\n );\n applySession(bundle);\n },\n\n async createApiKey() {\n const result = await authFetch<{ key: string; apiKey: string }>(\n '/_/auth/api-key/create',\n 'POST',\n {},\n );\n updateUserAndNotify({ apiKey: result.apiKey });\n return { key: result.key };\n },\n\n async revokeApiKey() {\n await authFetch('/_/auth/api-key/revoke', 'POST', {});\n updateUserAndNotify({ apiKey: null });\n },\n\n onAuthStateChanged(callback: (user: AppUser | null) => void) {\n authListeners.add(callback);\n callback(getConfig().user);\n return () => {\n authListeners.delete(callback);\n };\n },\n\n // -- Helpers --\n\n phone: {\n countries: phoneHelpers.countries,\n detectCountry: phoneHelpers.detectCountry,\n format: phoneHelpers.format,\n toE164: phoneHelpers.toE164,\n isValid: phoneHelpers.isValid,\n },\n\n email: {\n isValid: emailHelpers.isValid,\n },\n};\n"],"mappings":"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","names":["MindStudioInterfaceError","message","code","status","TELEMETRY_ENDPOINT_FRAGMENT","buffer","push","entry","getBreadcrumbs","shouldSkipUrl","url","TELEMETRY_ENDPOINT_FRAGMENT","resolveUrl","input","lastHref","navListeners","onNavigation","cb","emitNavigation","to","installHistory","w","originalPushState","data","unused","originalReplaceState","installFetch","captureResponseBodies","originalFetch","patched","init","method","startTime","response","body","err","installXhr","originalOpen","originalSend","rest","_breadcrumbsInstalled","installBreadcrumbs","opts","EVENTS_ENDPOINT","FLUSH_INTERVAL_MS","MAX_BATCH_SIZE","DEFAULT_RETRY_AFTER_MS","pending","flushTimer","suppressUntil","unloaded","enqueue","event","scheduleFlush","flush","takeBatch","batch","config","getConfig","events","res","retryAfterHeader","retryAfterSec","waitMs","drainOnUnload","sanitizeProps","input","out","k","v","emitPageview","url","track","props","PRESENCE_ENDPOINT","PRESENCE_MAX_BACKOFF_MS","PRESENCE_503_DEFAULT_MS","presenceAbort","presenceReconnectTimer","presenceBackoffMs","presenceActive","presenceNextBackoff","base","jitter","schedulePresenceReconnect","ms","openPresenceConnection","closePresenceConnection","signal","reader","done","err","name","analytics","_installed","installAnalytics","handleUnload","onNavigation","maybeInstallAnalytics","ENDPOINT","FLUSH_INTERVAL_MS","MAX_BATCH_SIZE","DEFAULT_RETRY_AFTER_MS","_installed","pending","flushTimer","suppressUntil","unloaded","fingerprint","message","stack","firstStackLine","enqueue","event","fp","existing","scheduleFlush","flush","takeBatch","batch","_fp","rest","config","getConfig","events","res","retryAfterHeader","retryAfterSec","waitMs","drainOnUnload","captureError","getBreadcrumbs","captureRejection","reason","installErrorMonitoring","installBreadcrumbs","handleUnload","maybeInstallTelemetry","_config","getConfig","raw","MindStudioInterfaceError","missing","k","maybeInstallTelemetry","maybeInstallAnalytics","updateConfig","updates","config","createClient","_","methodName","input","options","config","getConfig","methodId","MindStudioInterfaceError","url","wantsStream","res","errorMessage","errorCode","body","reader","decoder","buffer","finalOutput","streamError","done","value","lines","line","json","event","AGENT_BASE","request","path","method","body","headers","getConfig","res","errorMessage","errorCode","err","MindStudioInterfaceError","dispatchEvent","event","callbacks","createAgentChatClient","cursor","query","threadId","title","content","options","controller","cb","abortable","config","url","reader","decoder","buffer","result","done","value","lines","line","json","platform","file","options","config","getConfig","onProgress","signal","presignRes","MindStudioInterfaceError","uploadUrl","uploadFields","publicUrl","formData","key","value","xhrUpload","uploadRes","url","resolve","reject","xhr","e","countries","byCode","c","timezoneToCountry","detectCountry","tz","format","e164","digits","area","prefix","line","len","candidate","match","rest","toE164","national","countryCode","country","dialDigits","isValid","phone","isValid","email","authFetch","path","method","body","headers","getConfig","res","message","code","err","MindStudioInterfaceError","authListeners","applySession","bundle","updateConfig","cb","requireUser","updateUserAndNotify","update","config","auth","email","verificationId","phone","newEmail","newPhone","result","callback","countries","detectCountry","format","toE164","isValid"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/telemetry-breadcrumbs.ts","../src/telemetry-analytics.ts","../src/telemetry-errors.ts","../src/config.ts","../src/client.ts","../src/agent-chat.ts","../src/platform.ts","../src/auth-phone.ts","../src/auth-email.ts","../src/auth.ts","../src/index.ts"],"sourcesContent":["/**\n * Error class for the @mindstudio-ai/interface SDK.\n *\n * Thrown by `createClient()` method calls on HTTP errors, by `platform`\n * actions on failures, and by the config reader when bootstrap globals\n * are missing.\n */\nexport class MindStudioInterfaceError extends Error {\n /** Machine-readable error code (e.g. 'method_not_found', 'not_initialized'). */\n readonly code: string;\n\n /** HTTP status code, when the error originated from an API response. */\n readonly status?: number;\n\n constructor(message: string, code: string, status?: number) {\n super(message);\n this.name = 'MindStudioInterfaceError';\n this.code = code;\n this.status = status;\n }\n}\n","/**\n * Breadcrumbs — a ring buffer of recent navigations + network calls\n * attached to outgoing error reports for debugging context.\n *\n * Installed by `installErrorMonitoring()` in `telemetry-errors.ts`.\n * Three monkeypatches feed the buffer:\n *\n * - `history.pushState`/`replaceState`/`popstate` → `navigation`\n * - `window.fetch` → `fetch`\n * - `XMLHttpRequest.prototype.open`/`send` → `xhr`\n *\n * Each patch is idempotent — guarded by a `__ms_*_patched` flag so\n * re-imports (HMR, double bundle inclusion, etc.) are no-ops.\n *\n * The SDK's own telemetry endpoint is excluded from capture so error\n * reports don't feed themselves through the breadcrumb pipeline.\n */\n\nconst TELEMETRY_ENDPOINT_FRAGMENT = '/_/telemetry/';\nconst MAX_BREADCRUMBS = 20;\nconst MAX_BODY_BYTES = 1024;\n\n/**\n * A single breadcrumb entry. Discriminated union — server validates the\n * `type` field; unknown types are dropped at ingest.\n */\nexport type Breadcrumb =\n | {\n type: 'navigation';\n from: string;\n to: string;\n timestamp: number;\n }\n | {\n type: 'fetch';\n method: string;\n url: string;\n status?: number;\n ok: boolean;\n duration: number;\n timestamp: number;\n error?: string;\n /** Truncated response body for failed requests, when capture is enabled. */\n body?: string;\n }\n | {\n type: 'xhr';\n method: string;\n url: string;\n status?: number;\n ok: boolean;\n duration: number;\n timestamp: number;\n };\n\nconst buffer: Breadcrumb[] = [];\n\nfunction push(entry: Breadcrumb): void {\n buffer.push(entry);\n if (buffer.length > MAX_BREADCRUMBS) {\n buffer.shift();\n }\n}\n\n/**\n * Return a shallow copy of the current breadcrumb buffer.\n * Called when an error is captured to snapshot context at that moment.\n */\nexport function getBreadcrumbs(): Breadcrumb[] {\n return buffer.slice();\n}\n\nfunction shouldSkipUrl(url: string): boolean {\n return url.includes(TELEMETRY_ENDPOINT_FRAGMENT);\n}\n\nfunction resolveUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') {\n return input;\n }\n if (input instanceof URL) {\n return input.href;\n }\n return input.url || String(input);\n}\n\nlet lastHref = '';\n\nconst navListeners = new Set<(url: string) => void>();\n\n/**\n * Subscribe to navigation events. Fires on every history change\n * (`pushState`, `replaceState`, `popstate`, `hashchange`) with the new URL.\n *\n * Used by the analytics module to emit pageview events without\n * installing a second set of history patches.\n *\n * @returns Unsubscribe function.\n */\nexport function onNavigation(cb: (url: string) => void): () => void {\n navListeners.add(cb);\n return () => {\n navListeners.delete(cb);\n };\n}\n\nfunction emitNavigation(to: string): void {\n if (to === lastHref) {\n return;\n }\n push({\n type: 'navigation',\n from: lastHref,\n to,\n timestamp: Date.now(),\n });\n lastHref = to;\n navListeners.forEach((cb) => {\n try {\n cb(to);\n } catch {\n // listener errors must not break navigation\n }\n });\n}\n\nfunction installHistory(): void {\n const w = window as unknown as Record<string, unknown>;\n if (w.__ms_history_patched) {\n return;\n }\n w.__ms_history_patched = true;\n\n lastHref = location.href;\n\n const originalPushState = history.pushState.bind(history);\n history.pushState = function (\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalPushState(data, unused, url);\n try {\n emitNavigation(location.href);\n } catch {\n // never crash navigation\n }\n };\n\n const originalReplaceState = history.replaceState.bind(history);\n history.replaceState = function (\n data: unknown,\n unused: string,\n url?: string | URL | null,\n ): void {\n originalReplaceState(data, unused, url);\n try {\n emitNavigation(location.href);\n } catch {\n // never crash navigation\n }\n };\n\n window.addEventListener('popstate', () => {\n try {\n emitNavigation(location.href);\n } catch {\n // swallow\n }\n });\n\n window.addEventListener('hashchange', () => {\n try {\n emitNavigation(location.href);\n } catch {\n // swallow\n }\n });\n}\n\nfunction installFetch(captureResponseBodies: boolean): void {\n if (!window.fetch) {\n return;\n }\n const fetchFn = window.fetch as typeof fetch & { __ms_patched?: boolean };\n if (fetchFn.__ms_patched) {\n return;\n }\n\n const originalFetch = window.fetch.bind(window);\n\n const patched: typeof fetch = function (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> {\n const url = resolveUrl(input);\n\n if (shouldSkipUrl(url)) {\n return originalFetch(input, init);\n }\n\n const method = (\n init?.method ||\n (typeof input !== 'string' && !(input instanceof URL)\n ? input.method\n : '') ||\n 'GET'\n ).toUpperCase();\n const startTime = Date.now();\n\n return originalFetch(input, init).then(\n (response) => {\n const entry: Breadcrumb = {\n type: 'fetch',\n method,\n url,\n status: response.status,\n ok: response.ok,\n duration: Date.now() - startTime,\n timestamp: startTime,\n };\n\n if (!response.ok && captureResponseBodies) {\n try {\n response\n .clone()\n .text()\n .then((body) => {\n entry.body = body.slice(0, MAX_BODY_BYTES);\n push(entry);\n })\n .catch(() => push(entry));\n } catch {\n push(entry);\n }\n } else {\n push(entry);\n }\n\n return response;\n },\n (err: unknown) => {\n push({\n type: 'fetch',\n method,\n url,\n ok: false,\n duration: Date.now() - startTime,\n timestamp: startTime,\n error:\n err instanceof Error ? err.message : String(err ?? 'fetch failed'),\n });\n throw err;\n },\n );\n };\n\n (patched as typeof fetch & { __ms_patched: boolean }).__ms_patched = true;\n window.fetch = patched;\n}\n\nfunction installXhr(): void {\n const openProto = XMLHttpRequest.prototype.open as ((\n ...args: unknown[]\n ) => void) & { __ms_patched?: boolean };\n if (openProto.__ms_patched) {\n return;\n }\n\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n\n XMLHttpRequest.prototype.open = function (\n this: XMLHttpRequest & {\n __ms_method?: string;\n __ms_url?: string;\n },\n method: string,\n url: string | URL,\n ...rest: unknown[]\n ): void {\n this.__ms_method = (method || 'GET').toUpperCase();\n this.__ms_url = String(url);\n return originalOpen.apply(this, [method, url, ...rest] as Parameters<\n typeof originalOpen\n >);\n } as typeof XMLHttpRequest.prototype.open;\n\n XMLHttpRequest.prototype.send = function (\n this: XMLHttpRequest & {\n __ms_method?: string;\n __ms_url?: string;\n },\n body?: Document | XMLHttpRequestBodyInit | null,\n ): void {\n const method = this.__ms_method || 'GET';\n const url = this.__ms_url || '';\n\n if (shouldSkipUrl(url)) {\n return originalSend.apply(this, [body] as Parameters<\n typeof originalSend\n >);\n }\n\n const startTime = Date.now();\n\n this.addEventListener(\n 'loadend',\n function (this: XMLHttpRequest) {\n push({\n type: 'xhr',\n method,\n url,\n status: this.status,\n ok: this.status >= 200 && this.status < 300,\n duration: Date.now() - startTime,\n timestamp: startTime,\n });\n },\n { once: true },\n );\n\n return originalSend.apply(this, [body] as Parameters<typeof originalSend>);\n } as typeof XMLHttpRequest.prototype.send;\n\n (\n XMLHttpRequest.prototype.open as typeof XMLHttpRequest.prototype.open & {\n __ms_patched: boolean;\n }\n ).__ms_patched = true;\n}\n\nlet _breadcrumbsInstalled = false;\n\n/**\n * Install all three breadcrumb sources. Idempotent.\n *\n * @param opts.captureResponseBodies — when `true`, failed `fetch`\n * responses have their bodies read and attached (truncated to ~1KB).\n * Backend strips this field unless the per-app setting is enabled.\n */\nexport function installBreadcrumbs(opts: {\n captureResponseBodies: boolean;\n}): void {\n if (_breadcrumbsInstalled) {\n return;\n }\n _breadcrumbsInstalled = true;\n\n try {\n installHistory();\n } catch {\n // history patches are best-effort\n }\n try {\n installFetch(opts.captureResponseBodies);\n } catch {\n // fetch patches are best-effort\n }\n try {\n installXhr();\n } catch {\n // xhr patches are best-effort\n }\n}\n","/**\n * Analytics — Plausible/Fathom-style visitor analytics.\n *\n * Auto-tracks pageviews via the existing history patches in\n * `telemetry-breadcrumbs.ts` and exposes a small public API:\n *\n * ```ts\n * import { analytics } from '@mindstudio-ai/interface';\n *\n * // Custom events (optional — pageviews track automatically)\n * analytics.track('vendor_submitted', { vendorType: 'restaurant' });\n * ```\n *\n * Server-side derivation handles geo (IP → country), device class\n * (UA → mobile/tablet/desktop), referrers, UTM parsing, and\n * sessionization. The SDK ships nothing for those — just raw\n * pageview events with enough context for backend enrichment.\n *\n * ## How it works\n *\n * Installed by `maybeInstallAnalytics()`, which is called by `getConfig()`\n * in `config.ts`. `getConfig()` runs automatically on the next tick after\n * SDK import when the platform bootstrap is present (see eager-init block\n * in `src/index.ts`), so pageview tracking + presence are live at page\n * load without app code needing to invoke anything. Falls back to lazy\n * install on first SDK use if eager init was skipped.\n *\n * Once installed:\n *\n * 1. Subscribes to navigation events from `telemetry-breadcrumbs.ts`\n * and emits a pageview on each change.\n * 2. Fires an initial pageview for the first-load URL.\n * 3. Batches events (~1s debounce, 100/batch cap) and POSTs to\n * `/_/telemetry/events`.\n * 4. On `pagehide` / `visibilitychange='hidden'`, drains via\n * `fetch` with `keepalive: true`.\n * 5. On `429`, pauses sends for the `Retry-After` window.\n *\n * ## Privacy posture\n *\n * Live visitor counts are intentionally **not** exposed to app code.\n * Aggregate visitor metrics (live count included) are surfaced only\n * through the platform dashboard to the app owner — visitors should\n * not be able to learn about other visitors' presence through the\n * SDK. If an app explicitly wants user-facing presence as a designed\n * feature (e.g. a multiplayer experience), it must build that on its\n * own application-level abstraction with its own consent semantics,\n * not on platform telemetry.\n *\n * Opt-out via `window.__MINDSTUDIO__.telemetry = { analytics: false }`.\n */\n\nimport { getConfig } from './config.js';\nimport { onNavigation } from './telemetry-breadcrumbs.js';\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Flat-primitive prop values for custom events.\n *\n * Backend caps: max 10 keys, key length ~50 chars, value length ~500 chars.\n * Non-primitive values (objects, arrays, null) are stripped client-side\n * before send to save bandwidth — backend would silently drop them anyway.\n */\nexport type CustomEventProps = Record<string, string | number | boolean>;\n\n/**\n * The analytics namespace — pageview auto-tracking + custom events.\n *\n * Pageviews are auto-tracked from history changes; no public API for\n * them. Opt out entirely via `window.__MINDSTUDIO__.telemetry.analytics = false`.\n */\nexport interface AnalyticsClient {\n /**\n * Record a custom event with optional flat-primitive props.\n *\n * Non-primitive prop values (objects, arrays, null, undefined) are\n * stripped client-side before send. Server further caps name length\n * to 200 chars, props to 10 keys, key length to 50, value length to 500.\n *\n * Best-effort — never throws, never blocks. If the SDK isn't\n * initialized yet, the call is silently dropped.\n */\n track(event: string, props?: CustomEventProps): void;\n}\n\n// ---------------------------------------------------------------------------\n// Internal event types\n// ---------------------------------------------------------------------------\n\ntype PageviewEvent = {\n type: 'pageview';\n releaseId: string;\n url: string;\n referrer: string;\n userAgent: string;\n language: string;\n screen: { w: number; h: number };\n timestamp: number;\n};\n\ntype CustomEvent = {\n type: 'event';\n releaseId: string;\n name: string;\n url: string;\n timestamp: number;\n props?: CustomEventProps;\n};\n\ntype AnalyticsEvent = PageviewEvent | CustomEvent;\n\n// ---------------------------------------------------------------------------\n// Batched event transport\n// ---------------------------------------------------------------------------\n\nconst EVENTS_ENDPOINT = '/_/telemetry/events';\nconst FLUSH_INTERVAL_MS = 1000;\nconst MAX_BATCH_SIZE = 100;\nconst DEFAULT_RETRY_AFTER_MS = 60_000;\n\nlet pending: AnalyticsEvent[] = [];\nlet flushTimer: ReturnType<typeof setTimeout> | null = null;\nlet suppressUntil = 0;\nlet unloaded = false;\n\nfunction enqueue(event: AnalyticsEvent): void {\n if (unloaded) {\n return;\n }\n if (pending.length >= MAX_BATCH_SIZE) {\n return;\n }\n pending.push(event);\n scheduleFlush();\n}\n\nfunction scheduleFlush(): void {\n if (flushTimer || pending.length === 0) {\n return;\n }\n flushTimer = setTimeout(() => {\n flushTimer = null;\n void flush();\n }, FLUSH_INTERVAL_MS);\n}\n\nfunction takeBatch(): AnalyticsEvent[] {\n const batch = pending;\n pending = [];\n return batch;\n}\n\nasync function flush(): Promise<void> {\n if (pending.length === 0) {\n return;\n }\n\n if (Date.now() < suppressUntil) {\n pending = [];\n return;\n }\n\n let config;\n try {\n config = getConfig();\n } catch {\n pending = [];\n return;\n }\n\n const events = takeBatch();\n\n try {\n const res = await fetch(EVENTS_ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({ events }),\n });\n\n if (res.status === 429) {\n const retryAfterHeader = res.headers.get('Retry-After');\n const retryAfterSec = retryAfterHeader\n ? parseInt(retryAfterHeader, 10)\n : NaN;\n const waitMs =\n Number.isFinite(retryAfterSec) && retryAfterSec > 0\n ? retryAfterSec * 1000\n : DEFAULT_RETRY_AFTER_MS;\n suppressUntil = Date.now() + waitMs;\n }\n } catch {\n // network / serialization failure — drop silently\n }\n}\n\nfunction drainOnUnload(): void {\n if (pending.length === 0) {\n return;\n }\n if (Date.now() < suppressUntil) {\n pending = [];\n return;\n }\n\n let config;\n try {\n config = getConfig();\n } catch {\n pending = [];\n return;\n }\n\n const events = takeBatch();\n\n try {\n void fetch(EVENTS_ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({ events }),\n keepalive: true,\n });\n } catch {\n // best effort\n }\n}\n\n// ---------------------------------------------------------------------------\n// Custom event prop sanitization\n// ---------------------------------------------------------------------------\n\nfunction sanitizeProps(\n input?: Record<string, unknown>,\n): CustomEventProps | undefined {\n if (!input) {\n return undefined;\n }\n const out: CustomEventProps = {};\n for (const [k, v] of Object.entries(input)) {\n if (\n typeof v === 'string' ||\n typeof v === 'number' ||\n typeof v === 'boolean'\n ) {\n out[k] = v;\n }\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Pageview emit\n// ---------------------------------------------------------------------------\n\nfunction emitPageview(url: string): void {\n try {\n const config = getConfig();\n enqueue({\n type: 'pageview',\n releaseId: config.releaseId,\n url,\n referrer: document.referrer,\n userAgent: navigator.userAgent,\n language: navigator.language,\n screen: { w: window.innerWidth, h: window.innerHeight },\n timestamp: Date.now(),\n });\n } catch {\n // capture must never crash\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public `track`\n// ---------------------------------------------------------------------------\n\nfunction track(event: string, props?: CustomEventProps): void {\n try {\n const config = getConfig();\n enqueue({\n type: 'event',\n releaseId: config.releaseId,\n name: event,\n url: location.href,\n timestamp: Date.now(),\n props: sanitizeProps(props as Record<string, unknown> | undefined),\n });\n } catch {\n // never crash\n }\n}\n\n// ---------------------------------------------------------------------------\n// Silent presence connection\n//\n// The SDK opens a long-lived SSE connection to `/_/telemetry/presence`\n// while the tab is alive. The connection itself is the presence signal:\n// while it's open, the visitor is tracked as \"online\" in the server-side\n// Redis set; when the tab closes (or network drops), the connection\n// closes and the server immediately knows the visitor is gone.\n//\n// Any data the server pushes over this connection is silently discarded.\n// The visitor-facing live count is intentionally NOT exposed by the SDK.\n// The owner-facing dashboard reads counts via a separate authenticated\n// internal endpoint, never through the SDK.\n//\n// Reading-and-discarding the stream is required to keep the underlying\n// TCP buffer flowing — the open connection itself is what matters, not\n// the data flowing over it.\n// ---------------------------------------------------------------------------\n\nconst PRESENCE_ENDPOINT = '/_/telemetry/presence';\nconst PRESENCE_MAX_BACKOFF_MS = 10_000;\nconst PRESENCE_503_DEFAULT_MS = 30_000;\n\nlet presenceAbort: AbortController | null = null;\nlet presenceReconnectTimer: ReturnType<typeof setTimeout> | null = null;\nlet presenceBackoffMs = 1000;\nlet presenceActive = false;\n\nfunction presenceNextBackoff(): number {\n const base = presenceBackoffMs;\n presenceBackoffMs = Math.min(presenceBackoffMs * 2, PRESENCE_MAX_BACKOFF_MS);\n const jitter = Math.random() * 250;\n return base + jitter;\n}\n\nfunction schedulePresenceReconnect(ms: number): void {\n if (presenceReconnectTimer) {\n clearTimeout(presenceReconnectTimer);\n }\n presenceReconnectTimer = setTimeout(() => {\n presenceReconnectTimer = null;\n if (presenceActive) {\n void openPresenceConnection();\n }\n }, ms);\n}\n\nfunction closePresenceConnection(): void {\n presenceActive = false;\n if (presenceReconnectTimer) {\n clearTimeout(presenceReconnectTimer);\n presenceReconnectTimer = null;\n }\n if (presenceAbort) {\n try {\n presenceAbort.abort();\n } catch {\n // swallow\n }\n presenceAbort = null;\n }\n}\n\nasync function openPresenceConnection(): Promise<void> {\n if (!presenceActive) {\n return;\n }\n\n let config;\n try {\n config = getConfig();\n } catch {\n presenceActive = false;\n return;\n }\n\n presenceAbort = new AbortController();\n const signal = presenceAbort.signal;\n\n try {\n const res = await fetch(PRESENCE_ENDPOINT, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${config.token}`,\n Accept: 'text/event-stream',\n },\n signal,\n });\n\n if (res.status === 503) {\n const retryAfterHeader = res.headers.get('Retry-After');\n const retryAfterSec = retryAfterHeader\n ? parseInt(retryAfterHeader, 10)\n : NaN;\n const waitMs =\n Number.isFinite(retryAfterSec) && retryAfterSec > 0\n ? retryAfterSec * 1000\n : PRESENCE_503_DEFAULT_MS;\n schedulePresenceReconnect(waitMs);\n return;\n }\n\n if (res.status === 401) {\n // Session bad — stop trying until something refreshes config\n presenceActive = false;\n return;\n }\n\n if (!res.ok || !res.body) {\n schedulePresenceReconnect(presenceNextBackoff());\n return;\n }\n\n // Successful connect — reset backoff\n presenceBackoffMs = 1000;\n\n const reader = res.body.getReader();\n\n // Drain and discard. The open connection is the presence signal;\n // any count data the server pushes is intentionally ignored.\n while (presenceActive) {\n const { done } = await reader.read();\n if (done) {\n break;\n }\n }\n\n // Stream ended (server closed, deploy, etc.) — reconnect\n if (presenceActive) {\n schedulePresenceReconnect(presenceNextBackoff());\n }\n } catch (err) {\n const name = (err as { name?: string } | null)?.name;\n if (presenceActive && name !== 'AbortError') {\n schedulePresenceReconnect(presenceNextBackoff());\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public client\n// ---------------------------------------------------------------------------\n\nexport const analytics: AnalyticsClient = { track };\n\n// ---------------------------------------------------------------------------\n// Install + opt-out\n// ---------------------------------------------------------------------------\n\nlet _installed = false;\n\n/**\n * Install pageview auto-tracking + transport. Idempotent.\n *\n * Reads `window.__MINDSTUDIO__.telemetry?.analytics` — if explicitly\n * `false`, the SDK installs nothing and the function is a no-op.\n * `track()` calls also no-op in that case since enqueued events\n * have no flush path established.\n */\nexport function installAnalytics(): void {\n if (_installed) {\n return;\n }\n if (typeof window === 'undefined') {\n return;\n }\n\n let config;\n try {\n config = getConfig();\n } catch {\n return;\n }\n\n if (config.telemetry?.analytics === false) {\n return;\n }\n\n _installed = true;\n\n // Unload listeners (attached once)\n const handleUnload = (): void => {\n unloaded = true;\n drainOnUnload();\n closePresenceConnection();\n };\n window.addEventListener('pagehide', handleUnload);\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n drainOnUnload();\n }\n });\n\n // Auto-pageviews on every history change\n onNavigation((url) => {\n emitPageview(url);\n });\n\n // Initial pageview\n emitPageview(location.href);\n\n // Silent presence heartbeat — the open connection itself signals\n // \"this visitor is online\" to the server. No data is consumed.\n presenceActive = true;\n void openPresenceConnection();\n}\n\n/**\n * Wrapper that swallows any error from {@link installAnalytics} so a\n * misbehaving telemetry layer can never break `getConfig()`.\n *\n * @internal Called from config.ts on every `getConfig()` — idempotency\n * is enforced inside `installAnalytics`.\n */\nexport function maybeInstallAnalytics(): void {\n try {\n installAnalytics();\n } catch {\n // telemetry must never crash the host app\n }\n}\n","/**\n * Error reporting — auto-capture of uncaught errors and unhandled\n * promise rejections, batched and shipped to `/_/telemetry/errors`.\n *\n * ## How it works\n *\n * Installed by `maybeInstallTelemetry()`, which is called by `getConfig()`\n * in `config.ts`. `getConfig()` runs automatically on the next tick after\n * SDK import when the platform bootstrap is present (see eager-init block\n * in `src/index.ts`), so installation happens at page load without app\n * code needing to invoke anything. Falls back to lazy install on first\n * SDK use if eager init was skipped (SSR / tests / no bootstrap).\n *\n * Once installed:\n *\n * 1. `window.error` and `unhandledrejection` listeners enqueue events\n * into a pending batch (max 50 per batch — the server cap).\n * 2. Events with the same fingerprint within a batch collapse into a\n * single entry with `count: N` (bandwidth optimization).\n * 3. The batch flushes ~1s after the first push via `POST` to\n * `/_/telemetry/errors`.\n * 4. On `pagehide` / `visibilitychange='hidden'`, the buffer drains\n * via `fetch` with `keepalive: true` so the Bearer header survives.\n * 5. On `429`, the SDK pauses sends for the `Retry-After` window.\n * 6. Any other transport failure is swallowed — telemetry must never\n * crash the host app.\n *\n * No public API — the only knob is opt-out via\n * `window.__MINDSTUDIO__.telemetry = { errors: false }`.\n */\n\nimport { getConfig } from './config.js';\nimport {\n installBreadcrumbs,\n getBreadcrumbs,\n type Breadcrumb,\n} from './telemetry-breadcrumbs.js';\n\nconst ENDPOINT = '/_/telemetry/errors';\nconst FLUSH_INTERVAL_MS = 1000;\nconst MAX_BATCH_SIZE = 50;\nconst DEFAULT_RETRY_AFTER_MS = 60_000;\n\ninterface ErrorEvent {\n releaseId: string;\n url: string;\n userAgent: string;\n timestamp: number;\n type: 'error' | 'unhandledrejection';\n message: string;\n stack: string;\n source?: string;\n line?: number;\n column?: number;\n breadcrumbs: Breadcrumb[];\n count?: number;\n /** Internal: fingerprint for within-batch dedupe. Stripped before send. */\n _fp?: string;\n}\n\nlet _installed = false;\nlet pending: ErrorEvent[] = [];\nlet flushTimer: ReturnType<typeof setTimeout> | null = null;\nlet suppressUntil = 0;\nlet unloaded = false;\n\nfunction fingerprint(message: string, stack: string): string {\n const firstStackLine = stack.split('\\n')[1] ?? '';\n return `${message}|${firstStackLine.trim()}`;\n}\n\nfunction enqueue(event: ErrorEvent): void {\n if (unloaded) {\n return;\n }\n\n const fp = fingerprint(event.message, event.stack);\n\n for (const existing of pending) {\n if (existing._fp === fp) {\n existing.count = (existing.count ?? 1) + 1;\n return;\n }\n }\n\n if (pending.length >= MAX_BATCH_SIZE) {\n return;\n }\n\n event._fp = fp;\n pending.push(event);\n scheduleFlush();\n}\n\nfunction scheduleFlush(): void {\n if (flushTimer || pending.length === 0) {\n return;\n }\n flushTimer = setTimeout(() => {\n flushTimer = null;\n void flush();\n }, FLUSH_INTERVAL_MS);\n}\n\nfunction takeBatch(): ErrorEvent[] {\n const batch = pending;\n pending = [];\n return batch.map(({ _fp, ...rest }) => {\n void _fp;\n return rest;\n });\n}\n\nasync function flush(): Promise<void> {\n if (pending.length === 0) {\n return;\n }\n\n if (Date.now() < suppressUntil) {\n pending = [];\n return;\n }\n\n const config = (() => {\n try {\n return getConfig();\n } catch {\n return null;\n }\n })();\n if (!config) {\n pending = [];\n return;\n }\n\n const events = takeBatch();\n\n try {\n const res = await fetch(ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({ events }),\n });\n\n if (res.status === 429) {\n const retryAfterHeader = res.headers.get('Retry-After');\n const retryAfterSec = retryAfterHeader\n ? parseInt(retryAfterHeader, 10)\n : NaN;\n const waitMs =\n Number.isFinite(retryAfterSec) && retryAfterSec > 0\n ? retryAfterSec * 1000\n : DEFAULT_RETRY_AFTER_MS;\n suppressUntil = Date.now() + waitMs;\n }\n } catch {\n // network / serialization failure — drop silently\n }\n}\n\nfunction drainOnUnload(): void {\n if (pending.length === 0) {\n return;\n }\n if (Date.now() < suppressUntil) {\n pending = [];\n return;\n }\n\n let config: ReturnType<typeof getConfig> | null = null;\n try {\n config = getConfig();\n } catch {\n pending = [];\n return;\n }\n\n const events = takeBatch();\n\n try {\n void fetch(ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({ events }),\n keepalive: true,\n });\n } catch {\n // best effort\n }\n}\n\nfunction captureError(e: globalThis.ErrorEvent): void {\n try {\n const config = getConfig();\n enqueue({\n releaseId: config.releaseId,\n url: location.href,\n userAgent: navigator.userAgent,\n timestamp: Date.now(),\n type: 'error',\n message: e.message || 'Unknown error',\n stack: e.error?.stack ?? '',\n source: e.filename || undefined,\n line: typeof e.lineno === 'number' ? e.lineno : undefined,\n column: typeof e.colno === 'number' ? e.colno : undefined,\n breadcrumbs: getBreadcrumbs(),\n });\n } catch {\n // never crash on capture\n }\n}\n\nfunction captureRejection(e: PromiseRejectionEvent): void {\n try {\n const config = getConfig();\n const reason = e.reason as\n | { message?: string; stack?: string }\n | string\n | undefined;\n\n let message: string;\n let stack = '';\n\n if (reason && typeof reason === 'object') {\n message = reason.message || String(reason);\n stack = reason.stack ?? '';\n } else {\n message = String(reason ?? 'Unhandled rejection');\n }\n\n enqueue({\n releaseId: config.releaseId,\n url: location.href,\n userAgent: navigator.userAgent,\n timestamp: Date.now(),\n type: 'unhandledrejection',\n message,\n stack,\n breadcrumbs: getBreadcrumbs(),\n });\n } catch {\n // never crash on capture\n }\n}\n\n/**\n * Install error capture + breadcrumb collection. Idempotent.\n *\n * Reads `window.__MINDSTUDIO__.telemetry?.errors` — if explicitly\n * `false`, no listeners are attached and the function is a no-op.\n *\n * Otherwise attaches:\n * - `window.error` + `unhandledrejection`\n * - `pagehide` + `visibilitychange === 'hidden'` (for buffer drain)\n * - Breadcrumb sources via {@link installBreadcrumbs}\n */\nexport function installErrorMonitoring(): void {\n if (_installed) {\n return;\n }\n if (typeof window === 'undefined') {\n return;\n }\n\n let config: ReturnType<typeof getConfig>;\n try {\n config = getConfig();\n } catch {\n return;\n }\n\n if (config.telemetry?.errors === false) {\n return;\n }\n\n _installed = true;\n\n installBreadcrumbs({\n captureResponseBodies: !!config.telemetryCaptureResponseBodies,\n });\n\n window.addEventListener('error', captureError);\n window.addEventListener('unhandledrejection', captureRejection);\n\n const handleUnload = (): void => {\n unloaded = true;\n drainOnUnload();\n };\n window.addEventListener('pagehide', handleUnload);\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'hidden') {\n drainOnUnload();\n }\n });\n}\n\n/**\n * Wrapper that swallows any error from {@link installErrorMonitoring}\n * so a misbehaving telemetry layer can never break `getConfig()`.\n *\n * @internal Called from config.ts on every `getConfig()` — idempotency\n * is enforced inside `installErrorMonitoring`.\n */\nexport function maybeInstallTelemetry(): void {\n try {\n installErrorMonitoring();\n } catch {\n // telemetry must never crash the host app\n }\n}\n","/**\n * Bootstrap configuration reader.\n *\n * Reads and validates `window.__MINDSTUDIO__` — the globals injected by\n * the platform before the app's JavaScript runs. The result is cached\n * after first read.\n *\n * All other modules in the SDK call `getConfig()` internally. App code\n * should never need to call this directly — use `createClient()`, `auth`,\n * and `platform` instead.\n */\n\nimport { MindStudioInterfaceError } from './errors.js';\nimport { maybeInstallAnalytics } from './telemetry-analytics.js';\nimport { maybeInstallTelemetry } from './telemetry-errors.js';\nimport type { AppUser, BootstrapConfig } from './types.js';\n\nlet _config: BootstrapConfig | undefined;\n\n/**\n * Read and validate the bootstrap configuration from `window.__MINDSTUDIO__`.\n *\n * Caches the result after first successful read. Throws if the globals\n * are missing or incomplete — this means the page isn't running inside\n * the MindStudio platform.\n *\n * @returns The validated bootstrap config\n * @throws {MindStudioInterfaceError} if `window.__MINDSTUDIO__` is missing or invalid\n */\nexport function getConfig(): BootstrapConfig {\n if (_config) {\n return _config;\n }\n\n const raw = (globalThis as Record<string, unknown>).__MINDSTUDIO__ as\n | Partial<BootstrapConfig>\n | undefined;\n\n if (!raw) {\n throw new MindStudioInterfaceError(\n '@mindstudio-ai/interface requires the MindStudio platform context. ' +\n 'This page must be loaded inside MindStudio (window.__MINDSTUDIO__ is missing).',\n 'not_initialized',\n );\n }\n\n // Validate required fields (user can be null for unauthenticated sessions)\n if (!raw.token || !raw.releaseId || !raw.methods) {\n const missing = ['token', 'releaseId', 'methods']\n .filter((k) => !raw[k as keyof BootstrapConfig])\n .join(', ');\n\n throw new MindStudioInterfaceError(\n `MindStudio platform context is incomplete. Missing: ${missing}`,\n 'invalid_config',\n );\n }\n\n _config = raw as BootstrapConfig;\n\n // Auto-install telemetry surfaces on first successful config read.\n // Both are idempotent + try/caught — telemetry must never break getConfig().\n maybeInstallTelemetry();\n maybeInstallAnalytics();\n\n return _config;\n}\n\n/**\n * Update the cached config in-place after an auth state transition.\n *\n * The cached config is a mutable reference — all SDK modules read it\n * on-demand via `getConfig()`, so mutations propagate immediately to\n * method invocation, agent chat, uploads, etc.\n *\n * @internal Not exported from the package — used by the auth module only.\n */\nexport function updateConfig(updates: {\n token?: string;\n user?: AppUser | null;\n methods?: Record<string, string>;\n visitorId?: string;\n}): void {\n const config = getConfig();\n if (updates.token !== undefined) {\n config.token = updates.token;\n }\n if (updates.user !== undefined) {\n config.user = updates.user;\n }\n if (updates.methods !== undefined) {\n config.methods = updates.methods;\n }\n if (updates.visitorId !== undefined) {\n config.visitorId = updates.visitorId;\n }\n}\n","/**\n * Method RPC client — typed function calls to backend methods.\n *\n * `createClient()` returns a Proxy where every property access creates\n * an async function that invokes the corresponding backend method via HTTP.\n * The method name matches the method's `export` field in `app.json`.\n *\n * ## How it works\n *\n * ```\n * api.submitVendorRequest({ name: 'Acme' })\n * │\n * ├─ Look up method ID: config.methods[\"submitVendorRequest\"]\n * │ → \"submit-vendor-request\"\n * │\n * ├─ POST /_/methods/submit-vendor-request/invoke\n * │ Authorization: Bearer {session token}\n * │ Body: { input: { name: \"Acme\" } }\n * │\n * └─ Returns response.output (or throws on error)\n * ```\n *\n * The method registry (export name → method ID mapping) is embedded in\n * `window.__MINDSTUDIO__.methods` at page load time — no extra HTTP call\n * needed to discover methods.\n *\n * ## Streaming\n *\n * Methods can optionally stream output via SSE. Pass `{ stream: true }` as\n * the second argument along with callbacks for the events you care about:\n *\n * ```ts\n * // LLM token text\n * const result = await api.submitVendorRequest({ name: 'Acme' }, {\n * stream: true,\n * onToken: (text) => setResponseText(text),\n * });\n *\n * // Structured progress events from `stream({...})` on the backend\n * const order = await api.processOrder({ id: 'abc' }, {\n * stream: true,\n * onStreamData: (event) => setStatus(event),\n * });\n * ```\n *\n * **Important:** The `text` value passed to `onToken` is the accumulated\n * response so far (not a delta). Replace your display content each time —\n * do not append. See {@link InvokeOptions.onToken} for details.\n *\n * Each `onStreamData` payload is independent (no accumulation) — it's the\n * raw object passed to `stream({...})` on the backend.\n *\n * ## Type safety\n *\n * Since the frontend and backend live in the same project, you can import\n * types directly:\n *\n * ```ts\n * import type { SubmitVendorInput, SubmitVendorOutput }\n * from '../../backend/src/submitVendorRequest';\n *\n * interface AppMethods {\n * submitVendorRequest(input: SubmitVendorInput): Promise<SubmitVendorOutput>;\n * getDashboard(): Promise<GetDashboardOutput>;\n * }\n *\n * const api = createClient<AppMethods>();\n * const result = await api.submitVendorRequest({ name: 'Acme' }); // fully typed\n * ```\n *\n * If no type parameter is provided, methods accept `any` input and return `any`.\n */\n\nimport { getConfig } from './config.js';\nimport { MindStudioInterfaceError } from './errors.js';\n\n/**\n * Options for method invocation. Pass as the optional second argument to\n * any method on the client returned by {@link createClient}.\n *\n * When `stream` is `true`, the SDK sends `{ stream: true }` in the request\n * body and parses the response as an SSE (Server-Sent Events) stream.\n * Four event types are handled:\n *\n * | SSE `type` | Payload field | SDK action |\n * |------------|---------------|------------|\n * | `token` | `text` | Calls {@link onToken} with accumulated text |\n * | `data` | `data` | Calls {@link onStreamData} with the raw payload |\n * | `error` | `error` | Calls {@link onStreamError} with the message |\n * | `done` | `output` | Captures as the method's return value |\n *\n * The method's `Promise` resolves with the final `output` from the `done`\n * event — the same shape you'd get without streaming.\n */\nexport interface InvokeOptions {\n /**\n * Enable SSE streaming for LLM token output.\n *\n * When `true`, the request body includes `{ stream: true }` and the\n * response is parsed as an SSE stream instead of a single JSON payload.\n * The method still returns a `Promise` that resolves with the final\n * output once the stream completes.\n *\n * @default false\n */\n stream?: boolean;\n\n /**\n * Called with the accumulated response text each time a new token arrives.\n *\n * **Important:** `text` is the full response so far, not a delta/chunk.\n * Your frontend should **replace** (not append to) its display content\n * with this value each time the callback fires.\n *\n * This design avoids edge cases where the platform sanitizes or\n * reformats JSON mid-stream, causing earlier portions of the text to\n * change between tokens.\n *\n * @example\n * ```ts\n * const result = await api.generate({ prompt: 'Hello' }, {\n * stream: true,\n * onToken: (text) => {\n * // Replace — do NOT append\n * responseElement.textContent = text;\n * },\n * });\n * ```\n */\n onToken?: (text: string) => void;\n\n /**\n * Called when the backend method emits a structured event via\n * `stream({...})` (object payload).\n *\n * Receives the raw object passed to `stream()` on the backend —\n * not accumulated, not parsed, not wrapped. Use this for status\n * updates, progress, intermediate results, or any structured\n * streaming UI that isn't LLM token text.\n *\n * Different from {@link onToken}, which receives accumulated text from\n * `stream('text')` calls.\n *\n * @example\n * ```ts\n * await api.processOrder({ id: 'abc' }, {\n * stream: true,\n * onStreamData: (event) => {\n * // event is whatever the backend passed to stream({...})\n * setStatus(event as { status: string; progress: number });\n * },\n * });\n * ```\n */\n onStreamData?: (payload: unknown) => void;\n\n /**\n * Called if a stream-level error event arrives.\n *\n * If the stream then closes without a `done` event, the method rejects\n * with a `MindStudioInterfaceError` containing the error message (code\n * `method_error`). If a `done` event does arrive after the error, the\n * method resolves with the final output — in that case this callback\n * is just for logging or showing a transient warning.\n *\n * If the stream ends without either a `done` or `error` event, the\n * method rejects with `stream_incomplete`.\n */\n onStreamError?: (error: string) => void;\n}\n\n/**\n * Default client type when no generic parameter is provided.\n * Every property returns an async function accepting optional input\n * and optional {@link InvokeOptions} for streaming.\n */\ntype DefaultMethodClient = Record<\n string,\n (input?: Record<string, unknown>, options?: InvokeOptions) => Promise<unknown>\n>;\n\n/**\n * Create a typed RPC client for calling backend methods.\n *\n * @typeParam T - Optional interface mapping method names to their signatures.\n * If omitted, all methods accept `any` and return `Promise<any>`.\n *\n * @returns A Proxy object where each property is an async function that\n * invokes the corresponding backend method.\n *\n * @example\n * ```ts\n * import { createClient } from '@mindstudio-ai/interface';\n *\n * const api = createClient();\n *\n * // Each method maps to a backend method export\n * const result = await api.submitVendorRequest({ name: 'Acme' });\n * const dashboard = await api.getDashboard();\n *\n * // Stream LLM output — onToken receives accumulated text (replace, don't append)\n * const streamed = await api.submitVendorRequest({ name: 'Acme' }, {\n * stream: true,\n * onToken: (text) => setResponseText(text),\n * });\n * // `streamed` is the same final output you'd get without streaming\n * ```\n */\nexport function createClient<T = DefaultMethodClient>(): T {\n return new Proxy({} as Record<string, unknown> as T & object, {\n get(_, methodName: string) {\n return async (input?: unknown, options?: InvokeOptions) => {\n const config = getConfig();\n\n const methodId = config.methods[methodName];\n if (!methodId) {\n throw new MindStudioInterfaceError(\n `Method \"${methodName}\" not found. Available methods: ${Object.keys(config.methods).join(', ') || '(none)'}`,\n 'method_not_found',\n );\n }\n\n const url = `/_/methods/${methodId}/invoke`;\n const wantsStream = options?.stream === true;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({\n input: input ?? {},\n ...(wantsStream && { stream: true }),\n }),\n });\n\n if (!res.ok) {\n let errorMessage = `Method \"${methodName}\" failed: ${res.status} ${res.statusText}`;\n let errorCode = 'method_error';\n try {\n const body = (await res.json()) as {\n error?: string;\n code?: string;\n };\n if (body.error) {\n errorMessage = body.error;\n }\n if (body.code) {\n errorCode = body.code;\n }\n } catch {\n // Response wasn't JSON — use the default message\n }\n throw new MindStudioInterfaceError(\n errorMessage,\n errorCode,\n res.status,\n );\n }\n\n // Non-streaming: unchanged behavior\n if (!wantsStream) {\n const body = (await res.json()) as { output?: unknown };\n return body.output;\n }\n\n // Streaming: parse SSE events from response body\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let finalOutput: unknown;\n let streamError: string | undefined;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) {\n continue;\n }\n const json = line.slice(6);\n try {\n const event = JSON.parse(json) as {\n type: string;\n text?: string;\n error?: string;\n output?: unknown;\n data?: unknown;\n };\n\n if (event.type === 'token' && options?.onToken && event.text) {\n options.onToken(event.text);\n } else if (event.type === 'data' && options?.onStreamData) {\n options.onStreamData(event.data);\n } else if (event.type === 'error' && event.error) {\n streamError = event.error;\n if (options?.onStreamError) {\n options.onStreamError(event.error);\n }\n } else if (event.type === 'done') {\n finalOutput = event.output;\n }\n } catch {\n // Skip malformed SSE lines\n }\n }\n }\n\n // If the stream errored and didn't produce a final output,\n // surface the error message from the error event.\n if (finalOutput === undefined && streamError !== undefined) {\n throw new MindStudioInterfaceError(streamError, 'method_error');\n }\n\n if (finalOutput === undefined) {\n throw new MindStudioInterfaceError(\n 'Stream ended without a done event',\n 'stream_incomplete',\n );\n }\n\n return finalOutput;\n };\n },\n });\n}\n","/**\n * Agent chat client — thread-based conversations with AI agents.\n *\n * `createAgentChatClient()` returns an object with methods for thread\n * lifecycle (create, list, get, rename, delete) and message streaming.\n * The agent runs server-side with access to the app's methods as tools.\n *\n * ## How it works\n *\n * ```\n * chat.sendMessage(threadId, 'Help me prep for my review', {\n * onText: (delta) => setAssistantMessage((prev) => prev + delta),\n * })\n * │\n * ├─ POST /_/agent/threads/{threadId}/messages\n * │ Authorization: Bearer {session token}\n * │ Body: { content: \"Help me prep for my review\" }\n * │\n * ├─ Response: SSE stream\n * │ data: {\"type\":\"text\",\"text\":\"I'll create...\",\"ts\":1711...}\n * │ data: {\"type\":\"tool_call_start\",\"id\":\"call_abc\",\"name\":\"create-todo\",\"ts\":1711...}\n * │ data: {\"type\":\"tool_call_result\",\"id\":\"call_abc\",\"output\":{...},\"ts\":1711...}\n * │ data: {\"type\":\"text\",\"text\":\"Done — added it.\",\"ts\":1711...}\n * │ data: {\"type\":\"done\",\"stopReason\":\"end_turn\",\"usage\":{...},\"ts\":1711...}\n * │\n * └─ Promise resolves with { stopReason, usage }\n * ```\n *\n * ## Stateless design\n *\n * This client is a thin wrapper over HTTP endpoints. It does not manage\n * local state — your React/framework layer owns the thread list, message\n * array, and UI state. Each method is an independent request.\n *\n * ## Streaming callbacks\n *\n * `sendMessage` accepts named callbacks for common events (onText,\n * onThinking, onToolCallStart, etc.) plus a catch-all `onEvent` that\n * receives every SSE event as a discriminated union. Both fire for the\n * same event — use named callbacks for convenience, `onEvent` for\n * logging or handling low-level events like `tool_use` and\n * `tool_input_delta`.\n *\n * @example\n * ```ts\n * import { createAgentChatClient } from '@mindstudio-ai/interface';\n *\n * const chat = createAgentChatClient();\n *\n * // Thread lifecycle\n * const thread = await chat.createThread();\n * const { threads } = await chat.listThreads();\n * const full = await chat.getThread(thread.id);\n *\n * // Send a message with streaming\n * const response = chat.sendMessage(thread.id, 'Hello!', {\n * onText: (delta) => setMessage((prev) => prev + delta),\n * onToolCallStart: (id, name) => showToolSpinner(name),\n * onToolCallResult: (id, output) => showToolResult(output),\n * });\n *\n * const { stopReason, usage } = await response;\n *\n * // Abort mid-stream\n * response.abort();\n * ```\n */\n\nimport { getConfig } from './config.js';\nimport { MindStudioInterfaceError } from './errors.js';\n\n// ---------------------------------------------------------------------------\n// Thread types\n// ---------------------------------------------------------------------------\n\n/** Thread summary returned from create and list endpoints. */\nexport interface ThreadSummary {\n /** Thread ID (UUID). */\n id: string;\n /** User-editable title, auto-generated on first message. */\n title: string | null;\n /** ISO 8601 creation timestamp. */\n dateCreated: string;\n /** ISO 8601 last-updated timestamp. */\n dateUpdated: string;\n}\n\n/** Full thread with message history, returned from get endpoint. */\nexport interface Thread {\n /** Thread ID (UUID). */\n id: string;\n /** User-editable title. */\n title: string | null;\n /** Full conversation history. */\n messages: Message[];\n /** ISO 8601 creation timestamp. */\n dateCreated: string;\n /** ISO 8601 last-updated timestamp. */\n dateUpdated: string;\n}\n\n/** A tool call requested by the assistant. */\nexport interface ToolCall {\n /** Tool call ID, used to match results. */\n id: string;\n /** Method name. */\n name: string;\n /** Input arguments. */\n input: Record<string, unknown>;\n}\n\n/** A single message in a thread's conversation history. */\nexport interface Message {\n /** `\"user\"` for human messages, `\"assistant\"` for agent responses. */\n role: 'user' | 'assistant';\n /** Message text content. For tool results, this is JSON-stringified output. */\n content: string;\n /**\n * MindStudio CDN URLs attached to this message (user messages only).\n *\n * Images (`i.mscdn.ai`) are sent to the model as vision input.\n * Documents (`f.mscdn.ai`, `files.mindstudio-cdn.com`) have their text\n * extracted server-side and included in the model context. The original\n * URLs are preserved in thread history for the frontend to render.\n */\n attachments?: string[];\n /** Tool calls the assistant requested (assistant messages only). */\n toolCalls?: ToolCall[];\n /** ID of the tool call this message is a result for (tool result messages only). */\n toolCallId?: string;\n /** Whether this tool result represents an error. */\n isToolError?: boolean;\n}\n\n/** Paginated thread list response. */\nexport interface ThreadListPage {\n /** Threads for this page. */\n threads: ThreadSummary[];\n /** Cursor for the next page, or `null` if this is the last page. */\n nextCursor: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// SSE event types\n// ---------------------------------------------------------------------------\n\n/** Assistant text delta — append to your display string, do not replace. */\nexport interface AgentTextEvent {\n type: 'text';\n text: string;\n ts: number;\n}\n\n/** Model thinking text (extended thinking). */\nexport interface AgentThinkingEvent {\n type: 'thinking';\n text: string;\n ts: number;\n}\n\n/** Thinking complete with full text and signature. */\nexport interface AgentThinkingCompleteEvent {\n type: 'thinking_complete';\n thinking: string;\n signature: string;\n ts: number;\n}\n\n/** Model requested a tool call (includes parsed input). */\nexport interface AgentToolUseEvent {\n type: 'tool_use';\n id: string;\n name: string;\n input: Record<string, unknown>;\n ts: number;\n}\n\n/** Streaming delta for tool call input JSON. */\nexport interface AgentToolInputDeltaEvent {\n type: 'tool_input_delta';\n id: string;\n name: string;\n delta: string;\n ts: number;\n}\n\n/** Agent began executing a tool call. */\nexport interface AgentToolCallStartEvent {\n type: 'tool_call_start';\n id: string;\n name: string;\n ts: number;\n}\n\n/** Tool call returned a result. */\nexport interface AgentToolCallResultEvent {\n type: 'tool_call_result';\n id: string;\n output: unknown;\n ts: number;\n}\n\n/** Stream complete. */\nexport interface AgentDoneEvent {\n type: 'done';\n stopReason: string;\n usage: { inputTokens: number; outputTokens: number };\n ts: number;\n}\n\n/** Stream-level error. */\nexport interface AgentErrorEvent {\n type: 'error';\n error: string;\n ts: number;\n}\n\n/** Discriminated union of all SSE events from the agent chat stream. */\nexport type AgentChatEvent =\n | AgentTextEvent\n | AgentThinkingEvent\n | AgentThinkingCompleteEvent\n | AgentToolUseEvent\n | AgentToolInputDeltaEvent\n | AgentToolCallStartEvent\n | AgentToolCallResultEvent\n | AgentDoneEvent\n | AgentErrorEvent;\n\n// ---------------------------------------------------------------------------\n// Callbacks and result types\n// ---------------------------------------------------------------------------\n\n/**\n * Callbacks for `sendMessage` streaming.\n *\n * Named callbacks fire for common events. The catch-all `onEvent` fires\n * for every event including those with named callbacks — use it for\n * logging or handling low-level events like `tool_use` and\n * `tool_input_delta`.\n */\nexport interface SendMessageCallbacks {\n /**\n * Called with each text delta as the assistant responds.\n *\n * **Important:** `text` is a delta (new chunk), not the accumulated\n * response. Append it to your display string — do not replace.\n *\n * @example\n * ```ts\n * onText: (delta) => setMessage((prev) => prev + delta)\n * ```\n */\n onText?: (text: string) => void;\n\n /** Called with model thinking text (extended thinking). */\n onThinking?: (text: string) => void;\n\n /** Called when thinking is complete. */\n onThinkingComplete?: (thinking: string, signature: string) => void;\n\n /** Called when a tool call begins executing. */\n onToolCallStart?: (id: string, name: string) => void;\n\n /** Called when a tool call produces a result. */\n onToolCallResult?: (id: string, output: unknown) => void;\n\n /** Called on a stream-level error event. */\n onError?: (error: string) => void;\n\n /** Called for every SSE event (including ones with named callbacks). */\n onEvent?: (event: AgentChatEvent) => void;\n\n /** AbortSignal to cancel the stream. */\n signal?: AbortSignal;\n}\n\n/** Options for `sendMessage`. */\nexport interface SendMessageOptions {\n /**\n * MindStudio CDN URLs to attach to the message.\n *\n * Images (`i.mscdn.ai`) are sent to the model as vision input (one per message).\n * Documents (`f.mscdn.ai`, `files.mindstudio-cdn.com`) have their text\n * extracted server-side and included in context.\n *\n * Upload files first via `platform.uploadFile()`.\n *\n * @example\n * ```ts\n * const url = await platform.uploadFile(file);\n * chat.sendMessage(threadId, 'What is this?', callbacks, {\n * attachments: [url],\n * });\n * ```\n */\n attachments?: string[];\n}\n\n/** Resolved value of `sendMessage` — extracted from the `done` event. */\nexport interface SendMessageResult {\n /** Why the agent stopped (`\"end_turn\"`, `\"max_tokens\"`, etc.). */\n stopReason: string;\n /** Token usage for the full agent loop. */\n usage: { inputTokens: number; outputTokens: number };\n}\n\n/** A Promise with an `abort()` method for cancelling the stream. */\nexport type AbortablePromise<T> = Promise<T> & {\n /** Cancel the in-flight stream. The promise rejects with `AbortError`. */\n abort: () => void;\n};\n\n// ---------------------------------------------------------------------------\n// Client interface\n// ---------------------------------------------------------------------------\n\n/** Agent chat client returned by {@link createAgentChatClient}. */\nexport interface AgentChatClient {\n /** Create a new conversation thread. */\n createThread(): Promise<ThreadSummary>;\n\n /** List threads with cursor-based pagination (50 per page). */\n listThreads(cursor?: string): Promise<ThreadListPage>;\n\n /** Get a thread with its full message history. */\n getThread(threadId: string): Promise<Thread>;\n\n /** Update a thread's title. */\n updateThread(threadId: string, title: string): Promise<void>;\n\n /** Delete a thread (soft delete). */\n deleteThread(threadId: string): Promise<void>;\n\n /**\n * Send a message and stream the agent's response.\n *\n * Returns an {@link AbortablePromise} that resolves with\n * `{ stopReason, usage }` when the stream completes. Call `.abort()`\n * on the returned promise to cancel mid-stream.\n *\n * @param options.attachments - MindStudio CDN URLs to attach.\n * Images (`i.mscdn.ai`) are sent as vision input.\n * Documents (`f.mscdn.ai`) have text extracted into context.\n * Upload files first via `platform.uploadFile()`.\n */\n sendMessage(\n threadId: string,\n content: string,\n callbacks?: SendMessageCallbacks,\n options?: SendMessageOptions,\n ): AbortablePromise<SendMessageResult>;\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\nconst AGENT_BASE = '/_/agent';\n\nasync function request<T>(\n path: string,\n method: string,\n body?: unknown,\n): Promise<T> {\n const config = getConfig();\n const headers: Record<string, string> = {\n Authorization: `Bearer ${config.token}`,\n };\n\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n const res = await fetch(`${AGENT_BASE}${path}`, {\n method,\n headers,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n });\n\n if (!res.ok) {\n let errorMessage = `Agent chat request failed: ${res.status} ${res.statusText}`;\n let errorCode = 'agent_chat_error';\n try {\n const err = (await res.json()) as { error?: string; code?: string };\n if (err.error) {\n errorMessage = err.error;\n }\n if (err.code) {\n errorCode = err.code;\n }\n } catch {\n // Response wasn't JSON — use the default message\n }\n throw new MindStudioInterfaceError(errorMessage, errorCode, res.status);\n }\n\n return (await res.json()) as T;\n}\n\nfunction dispatchEvent(\n event: AgentChatEvent,\n callbacks: SendMessageCallbacks,\n): void {\n // Catch-all fires for every event\n callbacks.onEvent?.(event);\n\n // Named callbacks\n switch (event.type) {\n case 'text':\n callbacks.onText?.(event.text);\n break;\n case 'thinking':\n callbacks.onThinking?.(event.text);\n break;\n case 'thinking_complete':\n callbacks.onThinkingComplete?.(event.thinking, event.signature);\n break;\n case 'tool_call_start':\n callbacks.onToolCallStart?.(event.id, event.name);\n break;\n case 'tool_call_result':\n callbacks.onToolCallResult?.(event.id, event.output);\n break;\n case 'error':\n callbacks.onError?.(event.error);\n break;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create an agent chat client for thread-based conversations.\n *\n * The client is stateless — each method is an independent HTTP request.\n * Your application layer owns thread state, message arrays, and UI updates.\n *\n * @returns An {@link AgentChatClient} with methods for thread CRUD and\n * message streaming.\n *\n * @example\n * ```ts\n * import { createAgentChatClient } from '@mindstudio-ai/interface';\n *\n * const chat = createAgentChatClient();\n *\n * const thread = await chat.createThread();\n *\n * const response = chat.sendMessage(thread.id, 'Hello!', {\n * onText: (delta) => setAssistantMessage((prev) => prev + delta),\n * onToolCallStart: (id, name) => showToolSpinner(name),\n * onToolCallResult: (id, output) => showToolResult(output),\n * });\n *\n * const { stopReason, usage } = await response;\n * ```\n */\nexport function createAgentChatClient(): AgentChatClient {\n return {\n createThread() {\n return request<ThreadSummary>('/threads', 'POST');\n },\n\n listThreads(cursor?: string) {\n const query = cursor ? `?cursor=${encodeURIComponent(cursor)}` : '';\n return request<ThreadListPage>(`/threads${query}`, 'GET');\n },\n\n getThread(threadId: string) {\n return request<Thread>(`/threads/${threadId}`, 'GET');\n },\n\n async updateThread(threadId: string, title: string) {\n await request(`/threads/${threadId}`, 'PATCH', { title });\n },\n\n async deleteThread(threadId: string) {\n await request(`/threads/${threadId}`, 'DELETE');\n },\n\n sendMessage(\n threadId: string,\n content: string,\n callbacks?: SendMessageCallbacks,\n options?: SendMessageOptions,\n ): AbortablePromise<SendMessageResult> {\n const controller = new AbortController();\n const cb = callbacks ?? {};\n\n // Wire caller's signal to our internal controller\n if (cb.signal) {\n if (cb.signal.aborted) {\n controller.abort();\n } else {\n cb.signal.addEventListener('abort', () => controller.abort(), {\n once: true,\n });\n }\n }\n\n const promise = (async (): Promise<SendMessageResult> => {\n const config = getConfig();\n const url = `${AGENT_BASE}/threads/${threadId}/messages`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.token}`,\n },\n body: JSON.stringify({\n content,\n ...(options?.attachments?.length && {\n attachments: options.attachments,\n }),\n }),\n signal: controller.signal,\n });\n\n if (!res.ok) {\n let errorMessage = `Send message failed: ${res.status} ${res.statusText}`;\n let errorCode = 'agent_chat_error';\n try {\n const err = (await res.json()) as {\n error?: string;\n code?: string;\n };\n if (err.error) {\n errorMessage = err.error;\n }\n if (err.code) {\n errorCode = err.code;\n }\n } catch {\n // Response wasn't JSON — use the default message\n }\n throw new MindStudioInterfaceError(\n errorMessage,\n errorCode,\n res.status,\n );\n }\n\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let result: SendMessageResult | undefined;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (!line.startsWith('data: ')) {\n continue;\n }\n const json = line.slice(6);\n try {\n const event = JSON.parse(json) as AgentChatEvent;\n\n if (event.type === 'done') {\n result = {\n stopReason: event.stopReason,\n usage: event.usage,\n };\n }\n\n dispatchEvent(event, cb);\n } catch {\n // Skip malformed SSE lines\n }\n }\n }\n\n if (!result) {\n throw new MindStudioInterfaceError(\n 'Stream ended without a done event',\n 'stream_incomplete',\n );\n }\n\n return result;\n })();\n\n const abortable = promise as AbortablePromise<SendMessageResult>;\n abortable.abort = () => controller.abort();\n return abortable;\n },\n };\n}\n","/**\n * Platform actions — file uploads via presigned S3 POST.\n *\n * Uses the session token from `window.__MINDSTUDIO__` to request a\n * presigned upload URL from the platform, then uploads directly to S3.\n * Returns the public CDN URL.\n *\n * @example\n * ```ts\n * import { platform } from '@mindstudio-ai/interface';\n *\n * const file = document.querySelector('input[type=file]').files[0];\n * const url = await platform.uploadFile(file);\n *\n * // With progress and abort\n * const controller = new AbortController();\n * const url = await platform.uploadFile(file, {\n * onProgress: (fraction) => console.log(`${Math.round(fraction * 100)}%`),\n * signal: controller.signal,\n * });\n * ```\n */\n\nimport { getConfig } from './config.js';\nimport { MindStudioInterfaceError } from './errors.js';\n\n/**\n * Options for `platform.uploadFile()`.\n */\nexport interface UploadFileOptions {\n /** Called with upload progress as a fraction from 0 to 1. */\n onProgress?: (fraction: number) => void;\n\n /** AbortSignal to cancel the upload. */\n signal?: AbortSignal;\n}\n\n/**\n * The platform namespace — file upload actions.\n */\nexport const platform = {\n /**\n * Upload a file to the MindStudio CDN.\n *\n * Requests a presigned upload URL from the platform, then uploads\n * the file directly to S3. Returns the public CDN URL.\n *\n * @param file - The File to upload\n * @param options - Optional progress callback and abort signal\n * @returns CDN URL of the uploaded file\n *\n * @example\n * ```ts\n * const url = await platform.uploadFile(file);\n *\n * // With progress\n * const url = await platform.uploadFile(file, {\n * onProgress: (f) => setProgress(f),\n * });\n *\n * // With abort\n * const controller = new AbortController();\n * const url = await platform.uploadFile(file, {\n * signal: controller.signal,\n * });\n * // controller.abort() to cancel\n * ```\n */\n async uploadFile(file: File, options?: UploadFileOptions): Promise<string> {\n const config = getConfig();\n const { onProgress, signal } = options ?? {};\n\n // Check if already aborted\n signal?.throwIfAborted();\n\n // Step 1: Get presigned upload URL\n const presignUrl = '/_/generate-upload-request';\n const presignRes = await fetch(presignUrl, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${config.token}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n filename: file.name,\n contentType: file.type || 'application/octet-stream',\n }),\n signal,\n });\n\n if (!presignRes.ok) {\n throw new MindStudioInterfaceError(\n `Upload presign failed: ${presignRes.status} ${presignRes.statusText}`,\n 'upload_error',\n presignRes.status,\n );\n }\n\n const { uploadUrl, uploadFields, publicUrl } =\n (await presignRes.json()) as {\n uploadUrl: string;\n uploadFields: Record<string, string>;\n publicUrl: string;\n };\n\n // Step 2: Upload directly to S3\n const formData = new FormData();\n for (const [key, value] of Object.entries(uploadFields)) {\n formData.append(key, value);\n }\n formData.append('file', file); // must be last\n\n // Use XHR for upload progress (fetch doesn't support it)\n if (onProgress) {\n await xhrUpload(uploadUrl, formData, onProgress, signal);\n return publicUrl;\n }\n\n const uploadRes = await fetch(uploadUrl, {\n method: 'POST',\n body: formData,\n signal,\n });\n\n if (!uploadRes.ok) {\n throw new MindStudioInterfaceError(\n `File upload failed: ${uploadRes.status} ${uploadRes.statusText}`,\n 'upload_error',\n uploadRes.status,\n );\n }\n\n return publicUrl;\n },\n};\n\n/**\n * Upload via XMLHttpRequest to get progress events.\n * Falls back from fetch because fetch upload streams don't support progress.\n */\nfunction xhrUpload(\n url: string,\n formData: FormData,\n onProgress: (fraction: number) => void,\n signal?: AbortSignal,\n): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.upload.addEventListener('progress', (e) => {\n if (e.lengthComputable) {\n onProgress(e.loaded / e.total);\n }\n });\n\n xhr.addEventListener('load', () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n onProgress(1);\n resolve();\n } else {\n reject(\n new MindStudioInterfaceError(\n `File upload failed: ${xhr.status} ${xhr.statusText}`,\n 'upload_error',\n xhr.status,\n ),\n );\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(\n new MindStudioInterfaceError(\n 'File upload failed: network error',\n 'upload_error',\n ),\n );\n });\n\n xhr.addEventListener('abort', () => {\n reject(new DOMException('Upload aborted', 'AbortError'));\n });\n\n // Wire up abort signal\n if (signal) {\n if (signal.aborted) {\n reject(new DOMException('Upload aborted', 'AbortError'));\n return;\n }\n signal.addEventListener('abort', () => xhr.abort(), { once: true });\n }\n\n xhr.open('POST', url);\n xhr.send(formData);\n });\n}\n","/**\n * Phone number utilities for auth flows.\n *\n * Provides country data, E.164 conversion, formatting, and validation.\n * No external dependencies — designed for login/signup UIs that need\n * a country code picker and phone number formatting.\n */\n\n// ---------------------------------------------------------------------------\n// Country data\n// ---------------------------------------------------------------------------\n\n/** A country with its dial code and flag emoji. */\nexport interface Country {\n /** ISO 3166-1 alpha-2 code (e.g. \"US\"). */\n code: string;\n /** International dial code with + prefix (e.g. \"+1\"). */\n dialCode: string;\n /** Country name in English. */\n name: string;\n /** Flag emoji. */\n flag: string;\n}\n\n/** All countries with dial codes, sorted alphabetically by name. */\nexport const countries: readonly Country[] = [\n { code: 'AF', dialCode: '+93', name: 'Afghanistan', flag: '🇦🇫' },\n { code: 'AL', dialCode: '+355', name: 'Albania', flag: '🇦🇱' },\n { code: 'DZ', dialCode: '+213', name: 'Algeria', flag: '🇩🇿' },\n { code: 'AD', dialCode: '+376', name: 'Andorra', flag: '🇦🇩' },\n { code: 'AO', dialCode: '+244', name: 'Angola', flag: '🇦🇴' },\n { code: 'AG', dialCode: '+1', name: 'Antigua and Barbuda', flag: '🇦🇬' },\n { code: 'AR', dialCode: '+54', name: 'Argentina', flag: '🇦🇷' },\n { code: 'AM', dialCode: '+374', name: 'Armenia', flag: '🇦🇲' },\n { code: 'AU', dialCode: '+61', name: 'Australia', flag: '🇦🇺' },\n { code: 'AT', dialCode: '+43', name: 'Austria', flag: '🇦🇹' },\n { code: 'AZ', dialCode: '+994', name: 'Azerbaijan', flag: '🇦🇿' },\n { code: 'BS', dialCode: '+1', name: 'Bahamas', flag: '🇧🇸' },\n { code: 'BH', dialCode: '+973', name: 'Bahrain', flag: '🇧🇭' },\n { code: 'BD', dialCode: '+880', name: 'Bangladesh', flag: '🇧🇩' },\n { code: 'BB', dialCode: '+1', name: 'Barbados', flag: '🇧🇧' },\n { code: 'BY', dialCode: '+375', name: 'Belarus', flag: '🇧🇾' },\n { code: 'BE', dialCode: '+32', name: 'Belgium', flag: '🇧🇪' },\n { code: 'BZ', dialCode: '+501', name: 'Belize', flag: '🇧🇿' },\n { code: 'BJ', dialCode: '+229', name: 'Benin', flag: '🇧🇯' },\n { code: 'BT', dialCode: '+975', name: 'Bhutan', flag: '🇧🇹' },\n { code: 'BO', dialCode: '+591', name: 'Bolivia', flag: '🇧🇴' },\n { code: 'BA', dialCode: '+387', name: 'Bosnia and Herzegovina', flag: '🇧🇦' },\n { code: 'BW', dialCode: '+267', name: 'Botswana', flag: '🇧🇼' },\n { code: 'BR', dialCode: '+55', name: 'Brazil', flag: '🇧🇷' },\n { code: 'BN', dialCode: '+673', name: 'Brunei', flag: '🇧🇳' },\n { code: 'BG', dialCode: '+359', name: 'Bulgaria', flag: '🇧🇬' },\n { code: 'BF', dialCode: '+226', name: 'Burkina Faso', flag: '🇧🇫' },\n { code: 'BI', dialCode: '+257', name: 'Burundi', flag: '🇧🇮' },\n { code: 'CV', dialCode: '+238', name: 'Cabo Verde', flag: '🇨🇻' },\n { code: 'KH', dialCode: '+855', name: 'Cambodia', flag: '🇰🇭' },\n { code: 'CM', dialCode: '+237', name: 'Cameroon', flag: '🇨🇲' },\n { code: 'CA', dialCode: '+1', name: 'Canada', flag: '🇨🇦' },\n {\n code: 'CF',\n dialCode: '+236',\n name: 'Central African Republic',\n flag: '🇨🇫',\n },\n { code: 'TD', dialCode: '+235', name: 'Chad', flag: '🇹🇩' },\n { code: 'CL', dialCode: '+56', name: 'Chile', flag: '🇨🇱' },\n { code: 'CN', dialCode: '+86', name: 'China', flag: '🇨🇳' },\n { code: 'CO', dialCode: '+57', name: 'Colombia', flag: '🇨🇴' },\n { code: 'KM', dialCode: '+269', name: 'Comoros', flag: '🇰🇲' },\n { code: 'CG', dialCode: '+242', name: 'Congo', flag: '🇨🇬' },\n { code: 'CD', dialCode: '+243', name: 'Congo (DRC)', flag: '🇨🇩' },\n { code: 'CR', dialCode: '+506', name: 'Costa Rica', flag: '🇨🇷' },\n { code: 'HR', dialCode: '+385', name: 'Croatia', flag: '🇭🇷' },\n { code: 'CU', dialCode: '+53', name: 'Cuba', flag: '🇨🇺' },\n { code: 'CY', dialCode: '+357', name: 'Cyprus', flag: '🇨🇾' },\n { code: 'CZ', dialCode: '+420', name: 'Czechia', flag: '🇨🇿' },\n { code: 'CI', dialCode: '+225', name: \"Cote d'Ivoire\", flag: '🇨🇮' },\n { code: 'DK', dialCode: '+45', name: 'Denmark', flag: '🇩🇰' },\n { code: 'DJ', dialCode: '+253', name: 'Djibouti', flag: '🇩🇯' },\n { code: 'DM', dialCode: '+1', name: 'Dominica', flag: '🇩🇲' },\n { code: 'DO', dialCode: '+1', name: 'Dominican Republic', flag: '🇩🇴' },\n { code: 'EC', dialCode: '+593', name: 'Ecuador', flag: '🇪🇨' },\n { code: 'EG', dialCode: '+20', name: 'Egypt', flag: '🇪🇬' },\n { code: 'SV', dialCode: '+503', name: 'El Salvador', flag: '🇸🇻' },\n { code: 'GQ', dialCode: '+240', name: 'Equatorial Guinea', flag: '🇬🇶' },\n { code: 'ER', dialCode: '+291', name: 'Eritrea', flag: '🇪🇷' },\n { code: 'EE', dialCode: '+372', name: 'Estonia', flag: '🇪🇪' },\n { code: 'SZ', dialCode: '+268', name: 'Eswatini', flag: '🇸🇿' },\n { code: 'ET', dialCode: '+251', name: 'Ethiopia', flag: '🇪🇹' },\n { code: 'FJ', dialCode: '+679', name: 'Fiji', flag: '🇫🇯' },\n { code: 'FI', dialCode: '+358', name: 'Finland', flag: '🇫🇮' },\n { code: 'FR', dialCode: '+33', name: 'France', flag: '🇫🇷' },\n { code: 'GA', dialCode: '+241', name: 'Gabon', flag: '🇬🇦' },\n { code: 'GM', dialCode: '+220', name: 'Gambia', flag: '🇬🇲' },\n { code: 'GE', dialCode: '+995', name: 'Georgia', flag: '🇬🇪' },\n { code: 'DE', dialCode: '+49', name: 'Germany', flag: '🇩🇪' },\n { code: 'GH', dialCode: '+233', name: 'Ghana', flag: '🇬🇭' },\n { code: 'GR', dialCode: '+30', name: 'Greece', flag: '🇬🇷' },\n { code: 'GD', dialCode: '+1', name: 'Grenada', flag: '🇬🇩' },\n { code: 'GT', dialCode: '+502', name: 'Guatemala', flag: '🇬🇹' },\n { code: 'GN', dialCode: '+224', name: 'Guinea', flag: '🇬🇳' },\n { code: 'GW', dialCode: '+245', name: 'Guinea-Bissau', flag: '🇬🇼' },\n { code: 'GY', dialCode: '+592', name: 'Guyana', flag: '🇬🇾' },\n { code: 'HT', dialCode: '+509', name: 'Haiti', flag: '🇭🇹' },\n { code: 'HN', dialCode: '+504', name: 'Honduras', flag: '🇭🇳' },\n { code: 'HK', dialCode: '+852', name: 'Hong Kong', flag: '🇭🇰' },\n { code: 'HU', dialCode: '+36', name: 'Hungary', flag: '🇭🇺' },\n { code: 'IS', dialCode: '+354', name: 'Iceland', flag: '🇮🇸' },\n { code: 'IN', dialCode: '+91', name: 'India', flag: '🇮🇳' },\n { code: 'ID', dialCode: '+62', name: 'Indonesia', flag: '🇮🇩' },\n { code: 'IR', dialCode: '+98', name: 'Iran', flag: '🇮🇷' },\n { code: 'IQ', dialCode: '+964', name: 'Iraq', flag: '🇮🇶' },\n { code: 'IE', dialCode: '+353', name: 'Ireland', flag: '🇮🇪' },\n { code: 'IL', dialCode: '+972', name: 'Israel', flag: '🇮🇱' },\n { code: 'IT', dialCode: '+39', name: 'Italy', flag: '🇮🇹' },\n { code: 'JM', dialCode: '+1', name: 'Jamaica', flag: '🇯🇲' },\n { code: 'JP', dialCode: '+81', name: 'Japan', flag: '🇯🇵' },\n { code: 'JO', dialCode: '+962', name: 'Jordan', flag: '🇯🇴' },\n { code: 'KZ', dialCode: '+7', name: 'Kazakhstan', flag: '🇰🇿' },\n { code: 'KE', dialCode: '+254', name: 'Kenya', flag: '🇰🇪' },\n { code: 'KI', dialCode: '+686', name: 'Kiribati', flag: '🇰🇮' },\n { code: 'KW', dialCode: '+965', name: 'Kuwait', flag: '🇰🇼' },\n { code: 'KG', dialCode: '+996', name: 'Kyrgyzstan', flag: '🇰🇬' },\n { code: 'LA', dialCode: '+856', name: 'Laos', flag: '🇱🇦' },\n { code: 'LV', dialCode: '+371', name: 'Latvia', flag: '🇱🇻' },\n { code: 'LB', dialCode: '+961', name: 'Lebanon', flag: '🇱🇧' },\n { code: 'LS', dialCode: '+266', name: 'Lesotho', flag: '🇱🇸' },\n { code: 'LR', dialCode: '+231', name: 'Liberia', flag: '🇱🇷' },\n { code: 'LY', dialCode: '+218', name: 'Libya', flag: '🇱🇾' },\n { code: 'LI', dialCode: '+423', name: 'Liechtenstein', flag: '🇱🇮' },\n { code: 'LT', dialCode: '+370', name: 'Lithuania', flag: '🇱🇹' },\n { code: 'LU', dialCode: '+352', name: 'Luxembourg', flag: '🇱🇺' },\n { code: 'MO', dialCode: '+853', name: 'Macao', flag: '🇲🇴' },\n { code: 'MG', dialCode: '+261', name: 'Madagascar', flag: '🇲🇬' },\n { code: 'MW', dialCode: '+265', name: 'Malawi', flag: '🇲🇼' },\n { code: 'MY', dialCode: '+60', name: 'Malaysia', flag: '🇲🇾' },\n { code: 'MV', dialCode: '+960', name: 'Maldives', flag: '🇲🇻' },\n { code: 'ML', dialCode: '+223', name: 'Mali', flag: '🇲🇱' },\n { code: 'MT', dialCode: '+356', name: 'Malta', flag: '🇲🇹' },\n { code: 'MH', dialCode: '+692', name: 'Marshall Islands', flag: '🇲🇭' },\n { code: 'MR', dialCode: '+222', name: 'Mauritania', flag: '🇲🇷' },\n { code: 'MU', dialCode: '+230', name: 'Mauritius', flag: '🇲🇺' },\n { code: 'MX', dialCode: '+52', name: 'Mexico', flag: '🇲🇽' },\n { code: 'FM', dialCode: '+691', name: 'Micronesia', flag: '🇫🇲' },\n { code: 'MD', dialCode: '+373', name: 'Moldova', flag: '🇲🇩' },\n { code: 'MC', dialCode: '+377', name: 'Monaco', flag: '🇲🇨' },\n { code: 'MN', dialCode: '+976', name: 'Mongolia', flag: '🇲🇳' },\n { code: 'ME', dialCode: '+382', name: 'Montenegro', flag: '🇲🇪' },\n { code: 'MA', dialCode: '+212', name: 'Morocco', flag: '🇲🇦' },\n { code: 'MZ', dialCode: '+258', name: 'Mozambique', flag: '🇲🇿' },\n { code: 'MM', dialCode: '+95', name: 'Myanmar', flag: '🇲🇲' },\n { code: 'NA', dialCode: '+264', name: 'Namibia', flag: '🇳🇦' },\n { code: 'NR', dialCode: '+674', name: 'Nauru', flag: '🇳🇷' },\n { code: 'NP', dialCode: '+977', name: 'Nepal', flag: '🇳🇵' },\n { code: 'NL', dialCode: '+31', name: 'Netherlands', flag: '🇳🇱' },\n { code: 'NZ', dialCode: '+64', name: 'New Zealand', flag: '🇳🇿' },\n { code: 'NI', dialCode: '+505', name: 'Nicaragua', flag: '🇳🇮' },\n { code: 'NE', dialCode: '+227', name: 'Niger', flag: '🇳🇪' },\n { code: 'NG', dialCode: '+234', name: 'Nigeria', flag: '🇳🇬' },\n { code: 'KP', dialCode: '+850', name: 'North Korea', flag: '🇰🇵' },\n { code: 'MK', dialCode: '+389', name: 'North Macedonia', flag: '🇲🇰' },\n { code: 'NO', dialCode: '+47', name: 'Norway', flag: '🇳🇴' },\n { code: 'OM', dialCode: '+968', name: 'Oman', flag: '🇴🇲' },\n { code: 'PK', dialCode: '+92', name: 'Pakistan', flag: '🇵🇰' },\n { code: 'PW', dialCode: '+680', name: 'Palau', flag: '🇵🇼' },\n { code: 'PS', dialCode: '+970', name: 'Palestine', flag: '🇵🇸' },\n { code: 'PA', dialCode: '+507', name: 'Panama', flag: '🇵🇦' },\n { code: 'PG', dialCode: '+675', name: 'Papua New Guinea', flag: '🇵🇬' },\n { code: 'PY', dialCode: '+595', name: 'Paraguay', flag: '🇵🇾' },\n { code: 'PE', dialCode: '+51', name: 'Peru', flag: '🇵🇪' },\n { code: 'PH', dialCode: '+63', name: 'Philippines', flag: '🇵🇭' },\n { code: 'PL', dialCode: '+48', name: 'Poland', flag: '🇵🇱' },\n { code: 'PT', dialCode: '+351', name: 'Portugal', flag: '🇵🇹' },\n { code: 'PR', dialCode: '+1', name: 'Puerto Rico', flag: '🇵🇷' },\n { code: 'QA', dialCode: '+974', name: 'Qatar', flag: '🇶🇦' },\n { code: 'RO', dialCode: '+40', name: 'Romania', flag: '🇷🇴' },\n { code: 'RU', dialCode: '+7', name: 'Russia', flag: '🇷🇺' },\n { code: 'RW', dialCode: '+250', name: 'Rwanda', flag: '🇷🇼' },\n { code: 'KN', dialCode: '+1', name: 'Saint Kitts and Nevis', flag: '🇰🇳' },\n { code: 'LC', dialCode: '+1', name: 'Saint Lucia', flag: '🇱🇨' },\n {\n code: 'VC',\n dialCode: '+1',\n name: 'Saint Vincent and the Grenadines',\n flag: '🇻🇨',\n },\n { code: 'WS', dialCode: '+685', name: 'Samoa', flag: '🇼🇸' },\n { code: 'SM', dialCode: '+378', name: 'San Marino', flag: '🇸🇲' },\n { code: 'ST', dialCode: '+239', name: 'Sao Tome and Principe', flag: '🇸🇹' },\n { code: 'SA', dialCode: '+966', name: 'Saudi Arabia', flag: '🇸🇦' },\n { code: 'SN', dialCode: '+221', name: 'Senegal', flag: '🇸🇳' },\n { code: 'RS', dialCode: '+381', name: 'Serbia', flag: '🇷🇸' },\n { code: 'SC', dialCode: '+248', name: 'Seychelles', flag: '🇸🇨' },\n { code: 'SL', dialCode: '+232', name: 'Sierra Leone', flag: '🇸🇱' },\n { code: 'SG', dialCode: '+65', name: 'Singapore', flag: '🇸🇬' },\n { code: 'SK', dialCode: '+421', name: 'Slovakia', flag: '🇸🇰' },\n { code: 'SI', dialCode: '+386', name: 'Slovenia', flag: '🇸🇮' },\n { code: 'SB', dialCode: '+677', name: 'Solomon Islands', flag: '🇸🇧' },\n { code: 'SO', dialCode: '+252', name: 'Somalia', flag: '🇸🇴' },\n { code: 'ZA', dialCode: '+27', name: 'South Africa', flag: '🇿🇦' },\n { code: 'KR', dialCode: '+82', name: 'South Korea', flag: '🇰🇷' },\n { code: 'SS', dialCode: '+211', name: 'South Sudan', flag: '🇸🇸' },\n { code: 'ES', dialCode: '+34', name: 'Spain', flag: '🇪🇸' },\n { code: 'LK', dialCode: '+94', name: 'Sri Lanka', flag: '🇱🇰' },\n { code: 'SD', dialCode: '+249', name: 'Sudan', flag: '🇸🇩' },\n { code: 'SR', dialCode: '+597', name: 'Suriname', flag: '🇸🇷' },\n { code: 'SE', dialCode: '+46', name: 'Sweden', flag: '🇸🇪' },\n { code: 'CH', dialCode: '+41', name: 'Switzerland', flag: '🇨🇭' },\n { code: 'SY', dialCode: '+963', name: 'Syria', flag: '🇸🇾' },\n { code: 'TW', dialCode: '+886', name: 'Taiwan', flag: '🇹🇼' },\n { code: 'TJ', dialCode: '+992', name: 'Tajikistan', flag: '🇹🇯' },\n { code: 'TZ', dialCode: '+255', name: 'Tanzania', flag: '🇹🇿' },\n { code: 'TH', dialCode: '+66', name: 'Thailand', flag: '🇹🇭' },\n { code: 'TL', dialCode: '+670', name: 'Timor-Leste', flag: '🇹🇱' },\n { code: 'TG', dialCode: '+228', name: 'Togo', flag: '🇹🇬' },\n { code: 'TO', dialCode: '+676', name: 'Tonga', flag: '🇹🇴' },\n { code: 'TT', dialCode: '+1', name: 'Trinidad and Tobago', flag: '🇹🇹' },\n { code: 'TN', dialCode: '+216', name: 'Tunisia', flag: '🇹🇳' },\n { code: 'TR', dialCode: '+90', name: 'Turkey', flag: '🇹🇷' },\n { code: 'TM', dialCode: '+993', name: 'Turkmenistan', flag: '🇹🇲' },\n { code: 'TV', dialCode: '+688', name: 'Tuvalu', flag: '🇹🇻' },\n { code: 'UG', dialCode: '+256', name: 'Uganda', flag: '🇺🇬' },\n { code: 'UA', dialCode: '+380', name: 'Ukraine', flag: '🇺🇦' },\n { code: 'AE', dialCode: '+971', name: 'United Arab Emirates', flag: '🇦🇪' },\n { code: 'GB', dialCode: '+44', name: 'United Kingdom', flag: '🇬🇧' },\n { code: 'US', dialCode: '+1', name: 'United States', flag: '🇺🇸' },\n { code: 'UY', dialCode: '+598', name: 'Uruguay', flag: '🇺🇾' },\n { code: 'UZ', dialCode: '+998', name: 'Uzbekistan', flag: '🇺🇿' },\n { code: 'VU', dialCode: '+678', name: 'Vanuatu', flag: '🇻🇺' },\n { code: 'VA', dialCode: '+39', name: 'Vatican City', flag: '🇻🇦' },\n { code: 'VE', dialCode: '+58', name: 'Venezuela', flag: '🇻🇪' },\n { code: 'VN', dialCode: '+84', name: 'Vietnam', flag: '🇻🇳' },\n { code: 'YE', dialCode: '+967', name: 'Yemen', flag: '🇾🇪' },\n { code: 'ZM', dialCode: '+260', name: 'Zambia', flag: '🇿🇲' },\n { code: 'ZW', dialCode: '+263', name: 'Zimbabwe', flag: '🇿🇼' },\n];\n\n// ---------------------------------------------------------------------------\n// Country lookup helpers\n// ---------------------------------------------------------------------------\n\nconst byCode = new Map(countries.map((c) => [c.code, c]));\n\n/** Common IANA timezone → country code mapping. */\nconst timezoneToCountry: Record<string, string> = {\n 'America/New_York': 'US',\n 'America/Chicago': 'US',\n 'America/Denver': 'US',\n 'America/Los_Angeles': 'US',\n 'America/Anchorage': 'US',\n 'Pacific/Honolulu': 'US',\n 'America/Phoenix': 'US',\n 'America/Indiana/Indianapolis': 'US',\n 'America/Toronto': 'CA',\n 'America/Vancouver': 'CA',\n 'America/Edmonton': 'CA',\n 'America/Winnipeg': 'CA',\n 'America/Halifax': 'CA',\n 'America/St_Johns': 'CA',\n 'Europe/London': 'GB',\n 'Europe/Dublin': 'IE',\n 'Europe/Paris': 'FR',\n 'Europe/Berlin': 'DE',\n 'Europe/Madrid': 'ES',\n 'Europe/Rome': 'IT',\n 'Europe/Amsterdam': 'NL',\n 'Europe/Brussels': 'BE',\n 'Europe/Zurich': 'CH',\n 'Europe/Vienna': 'AT',\n 'Europe/Stockholm': 'SE',\n 'Europe/Oslo': 'NO',\n 'Europe/Copenhagen': 'DK',\n 'Europe/Helsinki': 'FI',\n 'Europe/Warsaw': 'PL',\n 'Europe/Prague': 'CZ',\n 'Europe/Bucharest': 'RO',\n 'Europe/Budapest': 'HU',\n 'Europe/Athens': 'GR',\n 'Europe/Istanbul': 'TR',\n 'Europe/Moscow': 'RU',\n 'Europe/Kiev': 'UA',\n 'Europe/Lisbon': 'PT',\n 'Europe/Belgrade': 'RS',\n 'Europe/Zagreb': 'HR',\n 'Europe/Bratislava': 'SK',\n 'Europe/Ljubljana': 'SI',\n 'Europe/Tallinn': 'EE',\n 'Europe/Riga': 'LV',\n 'Europe/Vilnius': 'LT',\n 'Asia/Tokyo': 'JP',\n 'Asia/Seoul': 'KR',\n 'Asia/Shanghai': 'CN',\n 'Asia/Hong_Kong': 'HK',\n 'Asia/Taipei': 'TW',\n 'Asia/Singapore': 'SG',\n 'Asia/Kolkata': 'IN',\n 'Asia/Karachi': 'PK',\n 'Asia/Dhaka': 'BD',\n 'Asia/Bangkok': 'TH',\n 'Asia/Jakarta': 'ID',\n 'Asia/Manila': 'PH',\n 'Asia/Kuala_Lumpur': 'MY',\n 'Asia/Ho_Chi_Minh': 'VN',\n 'Asia/Riyadh': 'SA',\n 'Asia/Dubai': 'AE',\n 'Asia/Tehran': 'IR',\n 'Asia/Baghdad': 'IQ',\n 'Asia/Beirut': 'LB',\n 'Asia/Jerusalem': 'IL',\n 'Asia/Amman': 'JO',\n 'Asia/Almaty': 'KZ',\n 'Asia/Tashkent': 'UZ',\n 'Asia/Colombo': 'LK',\n 'Asia/Kathmandu': 'NP',\n 'Asia/Yangon': 'MM',\n 'Australia/Sydney': 'AU',\n 'Australia/Melbourne': 'AU',\n 'Australia/Brisbane': 'AU',\n 'Australia/Perth': 'AU',\n 'Australia/Adelaide': 'AU',\n 'Pacific/Auckland': 'NZ',\n 'Pacific/Fiji': 'FJ',\n 'Africa/Cairo': 'EG',\n 'Africa/Lagos': 'NG',\n 'Africa/Nairobi': 'KE',\n 'Africa/Johannesburg': 'ZA',\n 'Africa/Casablanca': 'MA',\n 'Africa/Accra': 'GH',\n 'Africa/Addis_Ababa': 'ET',\n 'Africa/Dar_es_Salaam': 'TZ',\n 'Africa/Kampala': 'UG',\n 'America/Mexico_City': 'MX',\n 'America/Bogota': 'CO',\n 'America/Lima': 'PE',\n 'America/Santiago': 'CL',\n 'America/Buenos_Aires': 'AR',\n 'America/Sao_Paulo': 'BR',\n 'America/Caracas': 'VE',\n 'America/Guatemala': 'GT',\n 'America/Havana': 'CU',\n 'America/Panama': 'PA',\n 'America/Jamaica': 'JM',\n};\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Detect the user's country from their timezone.\n * Falls back to `'US'` if the timezone can't be mapped.\n */\nexport function detectCountry(): string {\n try {\n const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;\n return timezoneToCountry[tz] ?? 'US';\n } catch {\n return 'US';\n }\n}\n\n/**\n * Format an E.164 phone number for display.\n *\n * US/CA numbers: `+1 (555) 123-4567`\n * Others: `+{dialCode} {rest}`\n */\nexport function format(e164: string): string {\n if (!e164.startsWith('+')) {\n return e164;\n }\n\n const digits = e164.slice(1);\n\n // US/CA: +1 followed by 10 digits\n if (digits.startsWith('1') && digits.length === 11) {\n const area = digits.slice(1, 4);\n const prefix = digits.slice(4, 7);\n const line = digits.slice(7);\n return `+1 (${area}) ${prefix}-${line}`;\n }\n\n // Find matching dial code (try longest match first)\n for (let len = 4; len >= 1; len--) {\n const candidate = '+' + digits.slice(0, len);\n const match = countries.find((c) => c.dialCode === candidate);\n if (match) {\n const rest = digits.slice(len);\n return `${match.dialCode} ${rest}`;\n }\n }\n\n return e164;\n}\n\n/**\n * Convert a national phone number to E.164 format.\n *\n * @param national - Phone number with or without formatting (e.g. \"(555) 123-4567\")\n * @param countryCode - ISO 3166-1 alpha-2 code (e.g. \"US\")\n * @returns E.164 formatted number (e.g. \"+15551234567\")\n */\nexport function toE164(national: string, countryCode: string): string {\n const digits = national.replace(/\\D/g, '');\n const country = byCode.get(countryCode);\n if (!country) {\n return '+' + digits;\n }\n const dialDigits = country.dialCode.slice(1); // remove +\n // If the number already starts with the dial code, don't double-add\n if (digits.startsWith(dialDigits)) {\n return '+' + digits;\n }\n return country.dialCode + digits;\n}\n\n/**\n * Check if a string is a valid E.164 phone number.\n * Must start with + followed by 7-15 digits.\n */\nexport function isValid(phone: string): boolean {\n return /^\\+[1-9]\\d{6,14}$/.test(phone);\n}\n","/**\n * Email validation helper for auth flows.\n */\n\n/** Basic email format check. Not RFC 5322 exhaustive. */\nexport function isValid(email: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);\n}\n","/**\n * Auth — app-managed authentication for MindStudio v2 apps.\n *\n * Provides verification code flows (email + SMS), session state\n * management, and phone/email validation helpers. The platform\n * handles code delivery, cookie management, and user storage —\n * developers build their own login UI using these methods.\n *\n * ## How it works\n *\n * ```\n * // 1. Send a verification code\n * const { verificationId } = await auth.sendEmailCode('user@example.com');\n *\n * // 2. User enters the code in your UI\n * const user = await auth.verifyEmailCode(verificationId, '123456');\n *\n * // 3. Session is now active — all SDK calls use the authenticated token\n * const result = await api.getDashboard(); // uses authenticated session\n * auth.getCurrentUser(); // { id, email, phone, roles, createdAt }\n * ```\n *\n * Verify, confirm, and logout methods update `window.__MINDSTUDIO__`\n * in-place so all downstream calls (method invocation, agent chat,\n * uploads) immediately use the new session. No page refresh needed.\n *\n * @example\n * ```tsx\n * import { auth } from '@mindstudio-ai/interface';\n *\n * function LoginPage() {\n * const [email, setEmail] = useState('');\n * const [verificationId, setVerificationId] = useState('');\n * const [code, setCode] = useState('');\n *\n * const handleSend = async () => {\n * const { verificationId } = await auth.sendEmailCode(email);\n * setVerificationId(verificationId);\n * };\n *\n * const handleVerify = async () => {\n * await auth.verifyEmailCode(verificationId, code);\n * // Session updated in-place — navigate to your app\n * window.location.href = '/dashboard';\n * };\n * }\n * ```\n */\n\nimport { getConfig, updateConfig } from './config.js';\nimport { MindStudioInterfaceError } from './errors.js';\nimport type { AppUser, AuthSessionBundle } from './types.js';\nimport * as phoneHelpers from './auth-phone.js';\nimport * as emailHelpers from './auth-email.js';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nasync function authFetch<T>(\n path: string,\n method: 'GET' | 'POST',\n body?: Record<string, unknown>,\n): Promise<T> {\n const config = getConfig();\n const headers: Record<string, string> = {\n Authorization: `Bearer ${config.token}`,\n };\n\n if (body !== undefined) {\n headers['Content-Type'] = 'application/json';\n }\n\n const res = await fetch(path, {\n method,\n headers,\n ...(body !== undefined && { body: JSON.stringify(body) }),\n });\n\n if (!res.ok) {\n let message = `Auth request failed: ${res.status} ${res.statusText}`;\n let code = 'auth_error';\n try {\n const err = (await res.json()) as { error?: string; code?: string };\n if (err.error) {\n message = err.error;\n }\n if (err.code) {\n code = err.code;\n }\n } catch {\n // Response wasn't JSON\n }\n throw new MindStudioInterfaceError(message, code, res.status);\n }\n\n return (await res.json()) as T;\n}\n\nconst authListeners: Set<(user: AppUser | null) => void> = new Set();\n\nfunction applySession(bundle: AuthSessionBundle): void {\n updateConfig({\n token: bundle.token,\n user: bundle.user,\n methods: bundle.methods,\n visitorId: bundle.visitorId,\n });\n authListeners.forEach((cb) => cb(bundle.user));\n}\n\nfunction requireUser(bundle: AuthSessionBundle): AppUser {\n if (!bundle.user) {\n throw new MindStudioInterfaceError(\n 'Verification succeeded but no user was returned',\n 'auth_error',\n );\n }\n return bundle.user;\n}\n\nfunction updateUserAndNotify(update: Partial<AppUser>): void {\n const config = getConfig();\n if (config.user) {\n Object.assign(config.user, update);\n authListeners.forEach((cb) => cb(config.user));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Auth interface\n// ---------------------------------------------------------------------------\n\n/**\n * The auth namespace — authentication flows, state, and helpers.\n *\n * Auth methods throw {@link MindStudioInterfaceError} on failure.\n * Common error codes:\n *\n * | Code | Status | Meaning |\n * |------|--------|---------|\n * | `rate_limited` | 429 | Too many code requests (max 5 per 15 min per identifier) |\n * | `invalid_code` | 400 | Wrong verification code |\n * | `verification_expired` | 400 | Code expired (10 min TTL) — request a new one |\n * | `max_attempts_exceeded` | 400 | Too many incorrect attempts (max 3) — request a new code |\n * | `not_authenticated` | 401 | Auth cookie missing (change/logout endpoints) |\n * | `invalid_session` | 401 | Auth cookie expired or invalid |\n */\nexport interface Auth {\n // -- State --\n\n /** The current authenticated user, or `null` if not authenticated. */\n readonly currentUser: AppUser | null;\n\n /** Get the current authenticated user, or `null` if not authenticated. */\n getCurrentUser(): AppUser | null;\n\n /** Whether the current session is authenticated. */\n isAuthenticated(): boolean;\n\n /**\n * The stable per-browser, per-app visitor identifier, or `null` if\n * unavailable (e.g. cached bootstrap from before this field existed).\n *\n * Opaque string backed by a server-set HttpOnly cookie. For authed\n * sessions this is the user's platform user ID; for guests it's a\n * per-browser UUID. Persists ~1 year; refreshed on each page load.\n * Updates in-place on login/logout transitions.\n */\n readonly currentVisitorId: string | null;\n\n /** Get the current visitor ID, or `null` if unavailable. */\n getCurrentVisitorId(): string | null;\n\n // -- Email code flow --\n\n /** Send a 6-digit verification code to an email address. */\n sendEmailCode(email: string): Promise<{ verificationId: string }>;\n\n /**\n * Verify an email code. On success, updates the session in-place\n * and returns the authenticated user.\n */\n verifyEmailCode(verificationId: string, code: string): Promise<AppUser>;\n\n // -- SMS code flow --\n\n /** Send a 6-digit verification code via SMS. Phone must be E.164. */\n sendSmsCode(phone: string): Promise<{ verificationId: string }>;\n\n /**\n * Verify an SMS code. On success, updates the session in-place\n * and returns the authenticated user.\n */\n verifySmsCode(verificationId: string, code: string): Promise<AppUser>;\n\n // -- Email/phone change (requires authentication) --\n\n /** Request an email change. Sends a code to the new email. */\n requestEmailChange(newEmail: string): Promise<void>;\n\n /** Confirm an email change with the verification code. */\n confirmEmailChange(newEmail: string, code: string): Promise<AppUser>;\n\n /** Request a phone change. Sends a code to the new phone (E.164). */\n requestPhoneChange(newPhone: string): Promise<void>;\n\n /** Confirm a phone change with the verification code. */\n confirmPhoneChange(newPhone: string, code: string): Promise<AppUser>;\n\n // -- Session --\n\n /** Log out. Clears the cookie and updates the session to unauthenticated. */\n logout(): Promise<void>;\n\n // -- API keys --\n\n /**\n * Generate an API key for the current user. Returns the full key\n * (shown once). The user's `apiKey` field updates to the masked\n * value and `onAuthStateChanged` fires.\n *\n * @throws `not_authenticated` (401) if no session\n * @throws `not_supported` (400) if api-key auth is not enabled\n */\n createApiKey(): Promise<{ key: string }>;\n\n /**\n * Revoke the current user's API key. The user's `apiKey` field\n * becomes `null` and `onAuthStateChanged` fires.\n *\n * @throws `not_authenticated` (401) if no session\n */\n revokeApiKey(): Promise<void>;\n\n /**\n * Subscribe to auth state changes. Fires immediately with the\n * current state, then again whenever verify, confirm, or logout\n * updates the session.\n *\n * @returns An unsubscribe function.\n *\n * @example\n * ```ts\n * // React hook\n * function useAuth() {\n * const [user, setUser] = useState<AppUser | null>(null);\n * useEffect(() => auth.onAuthStateChanged(setUser), []);\n * return user;\n * }\n * ```\n */\n onAuthStateChanged(callback: (user: AppUser | null) => void): () => void;\n\n // -- Helpers --\n\n /** Phone number utilities — countries, formatting, validation. */\n phone: {\n /** All countries with dial codes, sorted alphabetically. */\n countries: readonly phoneHelpers.Country[];\n /** Detect the user's country from their timezone. Falls back to `'US'`. */\n detectCountry(): string;\n /** Format an E.164 number for display (e.g. `+1 (555) 123-4567`). */\n format(e164: string): string;\n /** Convert a national number to E.164 (e.g. `('5551234567', 'US') → '+15551234567'`). */\n toE164(national: string, countryCode: string): string;\n /** Check if a string is a valid E.164 phone number. */\n isValid(phone: string): boolean;\n };\n\n /** Email validation. */\n email: {\n /** Basic email format check. */\n isValid(email: string): boolean;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Implementation\n// ---------------------------------------------------------------------------\n\nexport const auth: Auth = {\n // -- State --\n\n get currentUser() {\n return getConfig().user;\n },\n\n getCurrentUser() {\n return getConfig().user;\n },\n\n isAuthenticated() {\n return getConfig().user !== null;\n },\n\n get currentVisitorId() {\n return getConfig().visitorId ?? null;\n },\n\n getCurrentVisitorId() {\n return getConfig().visitorId ?? null;\n },\n\n // -- Email code flow --\n\n sendEmailCode(email: string) {\n return authFetch<{ verificationId: string }>('/_/auth/email/send', 'POST', {\n email,\n });\n },\n\n async verifyEmailCode(verificationId: string, code: string) {\n const bundle = await authFetch<AuthSessionBundle>(\n '/_/auth/email/verify',\n 'POST',\n { verificationId, code },\n );\n applySession(bundle);\n return requireUser(bundle);\n },\n\n // -- SMS code flow --\n\n sendSmsCode(phone: string) {\n return authFetch<{ verificationId: string }>('/_/auth/sms/send', 'POST', {\n phone,\n });\n },\n\n async verifySmsCode(verificationId: string, code: string) {\n const bundle = await authFetch<AuthSessionBundle>(\n '/_/auth/sms/verify',\n 'POST',\n { verificationId, code },\n );\n applySession(bundle);\n return requireUser(bundle);\n },\n\n // -- Email/phone change --\n\n async requestEmailChange(newEmail: string) {\n await authFetch('/_/auth/email/change', 'POST', { newEmail });\n },\n\n async confirmEmailChange(newEmail: string, code: string) {\n const bundle = await authFetch<AuthSessionBundle>(\n '/_/auth/email/change/confirm',\n 'POST',\n { newEmail, code },\n );\n applySession(bundle);\n return requireUser(bundle);\n },\n\n async requestPhoneChange(newPhone: string) {\n await authFetch('/_/auth/phone/change', 'POST', { newPhone });\n },\n\n async confirmPhoneChange(newPhone: string, code: string) {\n const bundle = await authFetch<AuthSessionBundle>(\n '/_/auth/phone/change/confirm',\n 'POST',\n { newPhone, code },\n );\n applySession(bundle);\n return requireUser(bundle);\n },\n\n // -- Session --\n\n async logout() {\n const bundle = await authFetch<AuthSessionBundle>(\n '/_/auth/logout',\n 'POST',\n {},\n );\n applySession(bundle);\n },\n\n async createApiKey() {\n const result = await authFetch<{ key: string; apiKey: string }>(\n '/_/auth/api-key/create',\n 'POST',\n {},\n );\n updateUserAndNotify({ apiKey: result.apiKey });\n return { key: result.key };\n },\n\n async revokeApiKey() {\n await authFetch('/_/auth/api-key/revoke', 'POST', {});\n updateUserAndNotify({ apiKey: null });\n },\n\n onAuthStateChanged(callback: (user: AppUser | null) => void) {\n authListeners.add(callback);\n callback(getConfig().user);\n return () => {\n authListeners.delete(callback);\n };\n },\n\n // -- Helpers --\n\n phone: {\n countries: phoneHelpers.countries,\n detectCountry: phoneHelpers.detectCountry,\n format: phoneHelpers.format,\n toE164: phoneHelpers.toE164,\n isValid: phoneHelpers.isValid,\n },\n\n email: {\n isValid: emailHelpers.isValid,\n },\n};\n","/**\n * @mindstudio-ai/interface — Frontend SDK for MindStudio v2 app interfaces.\n *\n * Provides typed RPC to backend methods, file uploads, authentication,\n * and agent chat conversations. Runs inside web interfaces with\n * credentials injected by the platform via `window.__MINDSTUDIO__`.\n *\n * ## Four exports\n *\n * - `createClient()` — typed method RPC client\n * - `createAgentChatClient()` — thread-based agent conversations\n * - `platform` — file upload actions\n * - `auth` — authentication flows, user state, and validation helpers\n *\n * @example\n * ```ts\n * import {\n * createClient,\n * createAgentChatClient,\n * platform,\n * auth,\n * } from '@mindstudio-ai/interface';\n *\n * const api = createClient();\n * const chat = createAgentChatClient();\n *\n * // Check auth state\n * if (!auth.isAuthenticated()) {\n * const { verificationId } = await auth.sendEmailCode('user@example.com');\n * await auth.verifyEmailCode(verificationId, code);\n * }\n *\n * // Call backend methods (uses authenticated session)\n * const dashboard = await api.getDashboard();\n *\n * // Upload a file\n * const url = await platform.uploadFile(file);\n *\n * // Current user\n * const user = auth.getCurrentUser();\n * ```\n */\n\nexport { createClient, type InvokeOptions } from './client.js';\nexport {\n createAgentChatClient,\n type AgentChatClient,\n type AgentChatEvent,\n type SendMessageCallbacks,\n type SendMessageOptions,\n type SendMessageResult,\n type AbortablePromise,\n type Thread,\n type ThreadSummary,\n type ThreadListPage,\n type Message,\n} from './agent-chat.js';\nexport { platform, type UploadFileOptions } from './platform.js';\nexport { auth, type Auth } from './auth.js';\nexport {\n analytics,\n type AnalyticsClient,\n type CustomEventProps,\n} from './telemetry-analytics.js';\nexport { MindStudioInterfaceError } from './errors.js';\nexport type { BootstrapConfig, AppUser } from './types.js';\nexport type { Country } from './auth-phone.js';\nexport type { Breadcrumb } from './telemetry-breadcrumbs.js';\n\n// ---------------------------------------------------------------------------\n// Eager telemetry init\n//\n// When `window.__MINDSTUDIO__` is present at import time, trigger `getConfig()`\n// on the next tick so telemetry surfaces (errors, analytics, presence) install\n// at page load rather than on first SDK use. Without this, an app that creates\n// an `api` proxy at the module top but only invokes it from user interactions\n// would have no telemetry until the user clicks something.\n//\n// In environments without the bootstrap (SSR/Node, tests, dev without platform\n// context), the guard skips this and the SDK falls back to lazy init — first\n// SDK method call triggers `getConfig()` exactly as before.\n// ---------------------------------------------------------------------------\n\nimport { getConfig } from './config.js';\n\nif (\n typeof window !== 'undefined' &&\n (globalThis as Record<string, unknown>).__MINDSTUDIO__\n) {\n setTimeout(() => {\n try {\n getConfig();\n } catch {\n // bootstrap reads can still happen lazily on first SDK call\n }\n }, 0);\n}\n"],"mappings":"AAOO,IAAMA,EAAN,cAAuC,KAAM,CAEzC,KAGA,OAET,YAAYC,EAAiBC,EAAcC,EAAiB,CAC1D,MAAMF,CAAO,EACb,KAAK,KAAO,2BACZ,KAAK,KAAOC,EACZ,KAAK,OAASC,CAChB,CACF,ECFA,IAAMC,GAA8B,gBAqCpC,IAAMC,EAAuB,CAAC,EAE9B,SAASC,EAAKC,EAAyB,CACrCF,EAAO,KAAKE,CAAK,EACbF,EAAO,OAAS,IAClBA,EAAO,MAAM,CAEjB,CAMO,SAASG,GAA+B,CAC7C,OAAOH,EAAO,MAAM,CACtB,CAEA,SAASI,EAAcC,EAAsB,CAC3C,OAAOA,EAAI,SAASC,EAA2B,CACjD,CAEA,SAASC,GAAWC,EAAkC,CACpD,OAAI,OAAOA,GAAU,SACZA,EAELA,aAAiB,IACZA,EAAM,KAERA,EAAM,KAAO,OAAOA,CAAK,CAClC,CAEA,IAAIC,EAAW,GAETC,EAAe,IAAI,IAWlB,SAASC,EAAaC,EAAuC,CAClE,OAAAF,EAAa,IAAIE,CAAE,EACZ,IAAM,CACXF,EAAa,OAAOE,CAAE,CACxB,CACF,CAEA,SAASC,EAAeC,EAAkB,CACpCA,IAAOL,IAGXR,EAAK,CACH,KAAM,aACN,KAAMQ,EACN,GAAAK,EACA,UAAW,KAAK,IAAI,CACtB,CAAC,EACDL,EAAWK,EACXJ,EAAa,QAASE,GAAO,CAC3B,GAAI,CACFA,EAAGE,CAAE,CACP,MAAQ,CAER,CACF,CAAC,EACH,CAEA,SAASC,IAAuB,CAC9B,IAAMC,EAAI,OACV,GAAIA,EAAE,qBACJ,OAEFA,EAAE,qBAAuB,GAEzBP,EAAW,SAAS,KAEpB,IAAMQ,EAAoB,QAAQ,UAAU,KAAK,OAAO,EACxD,QAAQ,UAAY,SAClBC,EACAC,EACAd,EACM,CACNY,EAAkBC,EAAMC,EAAQd,CAAG,EACnC,GAAI,CACFQ,EAAe,SAAS,IAAI,CAC9B,MAAQ,CAER,CACF,EAEA,IAAMO,EAAuB,QAAQ,aAAa,KAAK,OAAO,EAC9D,QAAQ,aAAe,SACrBF,EACAC,EACAd,EACM,CACNe,EAAqBF,EAAMC,EAAQd,CAAG,EACtC,GAAI,CACFQ,EAAe,SAAS,IAAI,CAC9B,MAAQ,CAER,CACF,EAEA,OAAO,iBAAiB,WAAY,IAAM,CACxC,GAAI,CACFA,EAAe,SAAS,IAAI,CAC9B,MAAQ,CAER,CACF,CAAC,EAED,OAAO,iBAAiB,aAAc,IAAM,CAC1C,GAAI,CACFA,EAAe,SAAS,IAAI,CAC9B,MAAQ,CAER,CACF,CAAC,CACH,CAEA,SAASQ,GAAaC,EAAsC,CAK1D,GAJI,CAAC,OAAO,OAGI,OAAO,MACX,aACV,OAGF,IAAMC,EAAgB,OAAO,MAAM,KAAK,MAAM,EAExCC,EAAwB,SAC5BhB,EACAiB,EACmB,CACnB,IAAMpB,EAAME,GAAWC,CAAK,EAE5B,GAAIJ,EAAcC,CAAG,EACnB,OAAOkB,EAAcf,EAAOiB,CAAI,EAGlC,IAAMC,GACJD,GAAM,SACL,OAAOjB,GAAU,UAAY,EAAEA,aAAiB,KAC7CA,EAAM,OACN,KACJ,OACA,YAAY,EACRmB,EAAY,KAAK,IAAI,EAE3B,OAAOJ,EAAcf,EAAOiB,CAAI,EAAE,KAC/BG,GAAa,CACZ,IAAM1B,EAAoB,CACxB,KAAM,QACN,OAAAwB,EACA,IAAArB,EACA,OAAQuB,EAAS,OACjB,GAAIA,EAAS,GACb,SAAU,KAAK,IAAI,EAAID,EACvB,UAAWA,CACb,EAEA,GAAI,CAACC,EAAS,IAAMN,EAClB,GAAI,CACFM,EACG,MAAM,EACN,KAAK,EACL,KAAMC,GAAS,CACd3B,EAAM,KAAO2B,EAAK,MAAM,EAAG,IAAc,EACzC5B,EAAKC,CAAK,CACZ,CAAC,EACA,MAAM,IAAMD,EAAKC,CAAK,CAAC,CAC5B,MAAQ,CACND,EAAKC,CAAK,CACZ,MAEAD,EAAKC,CAAK,EAGZ,OAAO0B,CACT,EACCE,GAAiB,CAChB,MAAA7B,EAAK,CACH,KAAM,QACN,OAAAyB,EACA,IAAArB,EACA,GAAI,GACJ,SAAU,KAAK,IAAI,EAAIsB,EACvB,UAAWA,EACX,MACEG,aAAe,MAAQA,EAAI,QAAU,OAAOA,GAAO,cAAc,CACrE,CAAC,EACKA,CACR,CACF,CACF,EAECN,EAAqD,aAAe,GACrE,OAAO,MAAQA,CACjB,CAEA,SAASO,IAAmB,CAI1B,GAHkB,eAAe,UAAU,KAG7B,aACZ,OAGF,IAAMC,EAAe,eAAe,UAAU,KACxCC,EAAe,eAAe,UAAU,KAE9C,eAAe,UAAU,KAAO,SAK9BP,EACArB,KACG6B,EACG,CACN,YAAK,aAAeR,GAAU,OAAO,YAAY,EACjD,KAAK,SAAW,OAAOrB,CAAG,EACnB2B,EAAa,MAAM,KAAM,CAACN,EAAQrB,EAAK,GAAG6B,CAAI,CAEpD,CACH,EAEA,eAAe,UAAU,KAAO,SAK9BL,EACM,CACN,IAAMH,EAAS,KAAK,aAAe,MAC7BrB,EAAM,KAAK,UAAY,GAE7B,GAAID,EAAcC,CAAG,EACnB,OAAO4B,EAAa,MAAM,KAAM,CAACJ,CAAI,CAEpC,EAGH,IAAMF,EAAY,KAAK,IAAI,EAE3B,YAAK,iBACH,UACA,UAAgC,CAC9B1B,EAAK,CACH,KAAM,MACN,OAAAyB,EACA,IAAArB,EACA,OAAQ,KAAK,OACb,GAAI,KAAK,QAAU,KAAO,KAAK,OAAS,IACxC,SAAU,KAAK,IAAI,EAAIsB,EACvB,UAAWA,CACb,CAAC,CACH,EACA,CAAE,KAAM,EAAK,CACf,EAEOM,EAAa,MAAM,KAAM,CAACJ,CAAI,CAAoC,CAC3E,EAGE,eAAe,UAAU,KAGzB,aAAe,EACnB,CAEA,IAAIM,EAAwB,GASrB,SAASC,EAAmBC,EAE1B,CACP,GAAI,CAAAF,EAGJ,CAAAA,EAAwB,GAExB,GAAI,CACFpB,GAAe,CACjB,MAAQ,CAER,CACA,GAAI,CACFM,GAAagB,EAAK,qBAAqB,CACzC,MAAQ,CAER,CACA,GAAI,CACFN,GAAW,CACb,MAAQ,CAER,EACF,CCtPA,IAAMO,GAAkB,sBAClBC,GAAoB,IACpBC,GAAiB,IACjBC,GAAyB,IAE3BC,EAA4B,CAAC,EAC7BC,EAAmD,KACnDC,EAAgB,EAChBC,GAAW,GAEf,SAASC,GAAQC,EAA6B,CACxCF,IAGAH,EAAQ,QAAUF,KAGtBE,EAAQ,KAAKK,CAAK,EAClBC,GAAc,EAChB,CAEA,SAASA,IAAsB,CACzBL,GAAcD,EAAQ,SAAW,IAGrCC,EAAa,WAAW,IAAM,CAC5BA,EAAa,KACRM,GAAM,CACb,EAAGV,EAAiB,EACtB,CAEA,SAASW,IAA8B,CACrC,IAAMC,EAAQT,EACd,OAAAA,EAAU,CAAC,EACJS,CACT,CAEA,eAAeF,IAAuB,CACpC,GAAIP,EAAQ,SAAW,EACrB,OAGF,GAAI,KAAK,IAAI,EAAIE,EAAe,CAC9BF,EAAU,CAAC,EACX,MACF,CAEA,IAAIU,EACJ,GAAI,CACFA,EAASC,EAAU,CACrB,MAAQ,CACNX,EAAU,CAAC,EACX,MACF,CAEA,IAAMY,EAASJ,GAAU,EAEzB,GAAI,CACF,IAAMK,EAAM,MAAM,MAAMjB,GAAiB,CACvC,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,cAAe,UAAUc,EAAO,KAAK,EACvC,EACA,KAAM,KAAK,UAAU,CAAE,OAAAE,CAAO,CAAC,CACjC,CAAC,EAED,GAAIC,EAAI,SAAW,IAAK,CACtB,IAAMC,EAAmBD,EAAI,QAAQ,IAAI,aAAa,EAChDE,EAAgBD,EAClB,SAASA,EAAkB,EAAE,EAC7B,IACEE,EACJ,OAAO,SAASD,CAAa,GAAKA,EAAgB,EAC9CA,EAAgB,IAChBhB,GACNG,EAAgB,KAAK,IAAI,EAAIc,CAC/B,CACF,MAAQ,CAER,CACF,CAEA,SAASC,GAAsB,CAC7B,GAAIjB,EAAQ,SAAW,EACrB,OAEF,GAAI,KAAK,IAAI,EAAIE,EAAe,CAC9BF,EAAU,CAAC,EACX,MACF,CAEA,IAAIU,EACJ,GAAI,CACFA,EAASC,EAAU,CACrB,MAAQ,CACNX,EAAU,CAAC,EACX,MACF,CAEA,IAAMY,EAASJ,GAAU,EAEzB,GAAI,CACG,MAAMZ,GAAiB,CAC1B,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,cAAe,UAAUc,EAAO,KAAK,EACvC,EACA,KAAM,KAAK,UAAU,CAAE,OAAAE,CAAO,CAAC,EAC/B,UAAW,EACb,CAAC,CACH,MAAQ,CAER,CACF,CAMA,SAASM,GACPC,EAC8B,CAC9B,GAAI,CAACA,EACH,OAEF,IAAMC,EAAwB,CAAC,EAC/B,OAAW,CAACC,EAAGC,CAAC,IAAK,OAAO,QAAQH,CAAK,GAErC,OAAOG,GAAM,UACb,OAAOA,GAAM,UACb,OAAOA,GAAM,aAEbF,EAAIC,CAAC,EAAIC,GAGb,OAAO,OAAO,KAAKF,CAAG,EAAE,OAAS,EAAIA,EAAM,MAC7C,CAMA,SAASG,EAAaC,EAAmB,CACvC,GAAI,CACF,IAAMd,EAASC,EAAU,EACzBP,GAAQ,CACN,KAAM,WACN,UAAWM,EAAO,UAClB,IAAAc,EACA,SAAU,SAAS,SACnB,UAAW,UAAU,UACrB,SAAU,UAAU,SACpB,OAAQ,CAAE,EAAG,OAAO,WAAY,EAAG,OAAO,WAAY,EACtD,UAAW,KAAK,IAAI,CACtB,CAAC,CACH,MAAQ,CAER,CACF,CAMA,SAASC,GAAMpB,EAAeqB,EAAgC,CAC5D,GAAI,CACF,IAAMhB,EAASC,EAAU,EACzBP,GAAQ,CACN,KAAM,QACN,UAAWM,EAAO,UAClB,KAAML,EACN,IAAK,SAAS,KACd,UAAW,KAAK,IAAI,EACpB,MAAOa,GAAcQ,CAA4C,CACnE,CAAC,CACH,MAAQ,CAER,CACF,CAqBA,IAAMC,GAAoB,wBACpBC,GAA0B,IAC1BC,GAA0B,IAE5BC,EAAwC,KACxCC,EAA+D,KAC/DC,EAAoB,IACpBC,EAAiB,GAErB,SAASC,GAA8B,CACrC,IAAMC,EAAOH,EACbA,EAAoB,KAAK,IAAIA,EAAoB,EAAGJ,EAAuB,EAC3E,IAAMQ,EAAS,KAAK,OAAO,EAAI,IAC/B,OAAOD,EAAOC,CAChB,CAEA,SAASC,EAA0BC,EAAkB,CAC/CP,GACF,aAAaA,CAAsB,EAErCA,EAAyB,WAAW,IAAM,CACxCA,EAAyB,KACrBE,GACGM,GAAuB,CAEhC,EAAGD,CAAE,CACP,CAEA,SAASE,IAAgC,CAMvC,GALAP,EAAiB,GACbF,IACF,aAAaA,CAAsB,EACnCA,EAAyB,MAEvBD,EAAe,CACjB,GAAI,CACFA,EAAc,MAAM,CACtB,MAAQ,CAER,CACAA,EAAgB,IAClB,CACF,CAEA,eAAeS,IAAwC,CACrD,GAAI,CAACN,EACH,OAGF,IAAIvB,EACJ,GAAI,CACFA,EAASC,EAAU,CACrB,MAAQ,CACNsB,EAAiB,GACjB,MACF,CAEAH,EAAgB,IAAI,gBACpB,IAAMW,EAASX,EAAc,OAE7B,GAAI,CACF,IAAMjB,EAAM,MAAM,MAAMc,GAAmB,CACzC,OAAQ,MACR,QAAS,CACP,cAAe,UAAUjB,EAAO,KAAK,GACrC,OAAQ,mBACV,EACA,OAAA+B,CACF,CAAC,EAED,GAAI5B,EAAI,SAAW,IAAK,CACtB,IAAMC,EAAmBD,EAAI,QAAQ,IAAI,aAAa,EAChDE,EAAgBD,EAClB,SAASA,EAAkB,EAAE,EAC7B,IACEE,EACJ,OAAO,SAASD,CAAa,GAAKA,EAAgB,EAC9CA,EAAgB,IAChBc,GACNQ,EAA0BrB,CAAM,EAChC,MACF,CAEA,GAAIH,EAAI,SAAW,IAAK,CAEtBoB,EAAiB,GACjB,MACF,CAEA,GAAI,CAACpB,EAAI,IAAM,CAACA,EAAI,KAAM,CACxBwB,EAA0BH,EAAoB,CAAC,EAC/C,MACF,CAGAF,EAAoB,IAEpB,IAAMU,EAAS7B,EAAI,KAAK,UAAU,EAIlC,KAAOoB,GAAgB,CACrB,GAAM,CAAE,KAAAU,CAAK,EAAI,MAAMD,EAAO,KAAK,EACnC,GAAIC,EACF,KAEJ,CAGIV,GACFI,EAA0BH,EAAoB,CAAC,CAEnD,OAASU,EAAK,CACZ,IAAMC,EAAQD,GAAkC,KAC5CX,GAAkBY,IAAS,cAC7BR,EAA0BH,EAAoB,CAAC,CAEnD,CACF,CAMO,IAAMY,GAA6B,CAAE,MAAArB,EAAM,EAM9CsB,GAAa,GAUV,SAASC,IAAyB,CAIvC,GAHID,IAGA,OAAO,OAAW,IACpB,OAGF,IAAIrC,EACJ,GAAI,CACFA,EAASC,EAAU,CACrB,MAAQ,CACN,MACF,CAEA,GAAID,EAAO,WAAW,YAAc,GAClC,OAGFqC,GAAa,GAGb,IAAME,EAAe,IAAY,CAC/B9C,GAAW,GACXc,EAAc,EACduB,GAAwB,CAC1B,EACA,OAAO,iBAAiB,WAAYS,CAAY,EAChD,SAAS,iBAAiB,mBAAoB,IAAM,CAC9C,SAAS,kBAAoB,UAC/BhC,EAAc,CAElB,CAAC,EAGDiC,EAAc1B,GAAQ,CACpBD,EAAaC,CAAG,CAClB,CAAC,EAGDD,EAAa,SAAS,IAAI,EAI1BU,EAAiB,GACZM,GAAuB,CAC9B,CASO,SAASY,IAA8B,CAC5C,GAAI,CACFH,GAAiB,CACnB,MAAQ,CAER,CACF,CCleA,IAAMI,GAAW,sBACXC,GAAoB,IACpBC,GAAiB,GACjBC,GAAyB,IAmB3BC,GAAa,GACbC,EAAwB,CAAC,EACzBC,EAAmD,KACnDC,EAAgB,EAChBC,GAAW,GAEf,SAASC,GAAYC,EAAiBC,EAAuB,CAC3D,IAAMC,EAAiBD,EAAM,MAAM;AAAA,CAAI,EAAE,CAAC,GAAK,GAC/C,MAAO,GAAGD,CAAO,IAAIE,EAAe,KAAK,CAAC,EAC5C,CAEA,SAASC,GAAQC,EAAyB,CACxC,GAAIN,GACF,OAGF,IAAMO,EAAKN,GAAYK,EAAM,QAASA,EAAM,KAAK,EAEjD,QAAWE,KAAYX,EACrB,GAAIW,EAAS,MAAQD,EAAI,CACvBC,EAAS,OAASA,EAAS,OAAS,GAAK,EACzC,MACF,CAGEX,EAAQ,QAAUH,KAItBY,EAAM,IAAMC,EACZV,EAAQ,KAAKS,CAAK,EAClBG,GAAc,EAChB,CAEA,SAASA,IAAsB,CACzBX,GAAcD,EAAQ,SAAW,IAGrCC,EAAa,WAAW,IAAM,CAC5BA,EAAa,KACRY,GAAM,CACb,EAAGjB,EAAiB,EACtB,CAEA,SAASkB,IAA0B,CACjC,IAAMC,EAAQf,EACd,OAAAA,EAAU,CAAC,EACJe,EAAM,IAAI,CAAC,CAAE,IAAAC,EAAK,GAAGC,CAAK,IAExBA,CACR,CACH,CAEA,eAAeJ,IAAuB,CACpC,GAAIb,EAAQ,SAAW,EACrB,OAGF,GAAI,KAAK,IAAI,EAAIE,EAAe,CAC9BF,EAAU,CAAC,EACX,MACF,CAEA,IAAMkB,GAAU,IAAM,CACpB,GAAI,CACF,OAAOC,EAAU,CACnB,MAAQ,CACN,OAAO,IACT,CACF,GAAG,EACH,GAAI,CAACD,EAAQ,CACXlB,EAAU,CAAC,EACX,MACF,CAEA,IAAMoB,EAASN,GAAU,EAEzB,GAAI,CACF,IAAMO,EAAM,MAAM,MAAM1B,GAAU,CAChC,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,cAAe,UAAUuB,EAAO,KAAK,EACvC,EACA,KAAM,KAAK,UAAU,CAAE,OAAAE,CAAO,CAAC,CACjC,CAAC,EAED,GAAIC,EAAI,SAAW,IAAK,CACtB,IAAMC,EAAmBD,EAAI,QAAQ,IAAI,aAAa,EAChDE,EAAgBD,EAClB,SAASA,EAAkB,EAAE,EAC7B,IACEE,EACJ,OAAO,SAASD,CAAa,GAAKA,EAAgB,EAC9CA,EAAgB,IAChBzB,GACNI,EAAgB,KAAK,IAAI,EAAIsB,CAC/B,CACF,MAAQ,CAER,CACF,CAEA,SAASC,IAAsB,CAC7B,GAAIzB,EAAQ,SAAW,EACrB,OAEF,GAAI,KAAK,IAAI,EAAIE,EAAe,CAC9BF,EAAU,CAAC,EACX,MACF,CAEA,IAAIkB,EAA8C,KAClD,GAAI,CACFA,EAASC,EAAU,CACrB,MAAQ,CACNnB,EAAU,CAAC,EACX,MACF,CAEA,IAAMoB,EAASN,GAAU,EAEzB,GAAI,CACG,MAAMnB,GAAU,CACnB,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,cAAe,UAAUuB,EAAO,KAAK,EACvC,EACA,KAAM,KAAK,UAAU,CAAE,OAAAE,CAAO,CAAC,EAC/B,UAAW,EACb,CAAC,CACH,MAAQ,CAER,CACF,CAEA,SAASM,GAAa,EAAgC,CACpD,GAAI,CACF,IAAMR,EAASC,EAAU,EACzBX,GAAQ,CACN,UAAWU,EAAO,UAClB,IAAK,SAAS,KACd,UAAW,UAAU,UACrB,UAAW,KAAK,IAAI,EACpB,KAAM,QACN,QAAS,EAAE,SAAW,gBACtB,MAAO,EAAE,OAAO,OAAS,GACzB,OAAQ,EAAE,UAAY,OACtB,KAAM,OAAO,EAAE,QAAW,SAAW,EAAE,OAAS,OAChD,OAAQ,OAAO,EAAE,OAAU,SAAW,EAAE,MAAQ,OAChD,YAAaS,EAAe,CAC9B,CAAC,CACH,MAAQ,CAER,CACF,CAEA,SAASC,GAAiB,EAAgC,CACxD,GAAI,CACF,IAAMV,EAASC,EAAU,EACnBU,EAAS,EAAE,OAKbxB,EACAC,EAAQ,GAERuB,GAAU,OAAOA,GAAW,UAC9BxB,EAAUwB,EAAO,SAAW,OAAOA,CAAM,EACzCvB,EAAQuB,EAAO,OAAS,IAExBxB,EAAU,OAAOwB,GAAU,qBAAqB,EAGlDrB,GAAQ,CACN,UAAWU,EAAO,UAClB,IAAK,SAAS,KACd,UAAW,UAAU,UACrB,UAAW,KAAK,IAAI,EACpB,KAAM,qBACN,QAAAb,EACA,MAAAC,EACA,YAAaqB,EAAe,CAC9B,CAAC,CACH,MAAQ,CAER,CACF,CAaO,SAASG,IAA+B,CAI7C,GAHI/B,IAGA,OAAO,OAAW,IACpB,OAGF,IAAImB,EACJ,GAAI,CACFA,EAASC,EAAU,CACrB,MAAQ,CACN,MACF,CAEA,GAAID,EAAO,WAAW,SAAW,GAC/B,OAGFnB,GAAa,GAEbgC,EAAmB,CACjB,sBAAuB,CAAC,CAACb,EAAO,8BAClC,CAAC,EAED,OAAO,iBAAiB,QAASQ,EAAY,EAC7C,OAAO,iBAAiB,qBAAsBE,EAAgB,EAE9D,IAAMI,EAAe,IAAY,CAC/B7B,GAAW,GACXsB,GAAc,CAChB,EACA,OAAO,iBAAiB,WAAYO,CAAY,EAChD,SAAS,iBAAiB,mBAAoB,IAAM,CAC9C,SAAS,kBAAoB,UAC/BP,GAAc,CAElB,CAAC,CACH,CASO,SAASQ,IAA8B,CAC5C,GAAI,CACFH,GAAuB,CACzB,MAAQ,CAER,CACF,CC1SA,IAAII,EAYG,SAASC,GAA6B,CAC3C,GAAID,EACF,OAAOA,EAGT,IAAME,EAAO,WAAuC,eAIpD,GAAI,CAACA,EACH,MAAM,IAAIC,EACR,oJAEA,iBACF,EAIF,GAAI,CAACD,EAAI,OAAS,CAACA,EAAI,WAAa,CAACA,EAAI,QAAS,CAChD,IAAME,EAAU,CAAC,QAAS,YAAa,SAAS,EAC7C,OAAQC,GAAM,CAACH,EAAIG,CAA0B,CAAC,EAC9C,KAAK,IAAI,EAEZ,MAAM,IAAIF,EACR,uDAAuDC,CAAO,GAC9D,gBACF,CACF,CAEA,OAAAJ,EAAUE,EAIVI,GAAsB,EACtBC,GAAsB,EAEfP,CACT,CAWO,SAASQ,GAAaC,EAKpB,CACP,IAAMC,EAAST,EAAU,EACrBQ,EAAQ,QAAU,SACpBC,EAAO,MAAQD,EAAQ,OAErBA,EAAQ,OAAS,SACnBC,EAAO,KAAOD,EAAQ,MAEpBA,EAAQ,UAAY,SACtBC,EAAO,QAAUD,EAAQ,SAEvBA,EAAQ,YAAc,SACxBC,EAAO,UAAYD,EAAQ,UAE/B,CCgHO,SAASE,IAA2C,CACzD,OAAO,IAAI,MAAM,CAAC,EAA4C,CAC5D,IAAIC,EAAGC,EAAoB,CACzB,MAAO,OAAOC,EAAiBC,IAA4B,CACzD,IAAMC,EAASC,EAAU,EAEnBC,EAAWF,EAAO,QAAQH,CAAU,EAC1C,GAAI,CAACK,EACH,MAAM,IAAIC,EACR,WAAWN,CAAU,mCAAmC,OAAO,KAAKG,EAAO,OAAO,EAAE,KAAK,IAAI,GAAK,QAAQ,GAC1G,kBACF,EAGF,IAAMI,EAAM,cAAcF,CAAQ,UAC5BG,EAAcN,GAAS,SAAW,GAElCO,EAAM,MAAM,MAAMF,EAAK,CAC3B,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,cAAe,UAAUJ,EAAO,KAAK,EACvC,EACA,KAAM,KAAK,UAAU,CACnB,MAAOF,GAAS,CAAC,EACjB,GAAIO,GAAe,CAAE,OAAQ,EAAK,CACpC,CAAC,CACH,CAAC,EAED,GAAI,CAACC,EAAI,GAAI,CACX,IAAIC,EAAe,WAAWV,CAAU,aAAaS,EAAI,MAAM,IAAIA,EAAI,UAAU,GAC7EE,EAAY,eAChB,GAAI,CACF,IAAMC,EAAQ,MAAMH,EAAI,KAAK,EAIzBG,EAAK,QACPF,EAAeE,EAAK,OAElBA,EAAK,OACPD,EAAYC,EAAK,KAErB,MAAQ,CAER,CACA,MAAM,IAAIN,EACRI,EACAC,EACAF,EAAI,MACN,CACF,CAGA,GAAI,CAACD,EAEH,OADc,MAAMC,EAAI,KAAK,GACjB,OAId,IAAMI,EAASJ,EAAI,KAAM,UAAU,EAC7BK,EAAU,IAAI,YAChBC,EAAS,GACTC,EACAC,EAEJ,OAAa,CACX,GAAM,CAAE,KAAAC,EAAM,MAAAC,CAAM,EAAI,MAAMN,EAAO,KAAK,EAC1C,GAAIK,EACF,MAGFH,GAAUD,EAAQ,OAAOK,EAAO,CAAE,OAAQ,EAAK,CAAC,EAChD,IAAMC,EAAQL,EAAO,MAAM;AAAA,CAAI,EAC/BA,EAASK,EAAM,IAAI,GAAK,GAExB,QAAWC,KAAQD,EAAO,CACxB,GAAI,CAACC,EAAK,WAAW,QAAQ,EAC3B,SAEF,IAAMC,EAAOD,EAAK,MAAM,CAAC,EACzB,GAAI,CACF,IAAME,EAAQ,KAAK,MAAMD,CAAI,EAQzBC,EAAM,OAAS,SAAWrB,GAAS,SAAWqB,EAAM,KACtDrB,EAAQ,QAAQqB,EAAM,IAAI,EACjBA,EAAM,OAAS,QAAUrB,GAAS,aAC3CA,EAAQ,aAAaqB,EAAM,IAAI,EACtBA,EAAM,OAAS,SAAWA,EAAM,OACzCN,EAAcM,EAAM,MAChBrB,GAAS,eACXA,EAAQ,cAAcqB,EAAM,KAAK,GAE1BA,EAAM,OAAS,SACxBP,EAAcO,EAAM,OAExB,MAAQ,CAER,CACF,CACF,CAIA,GAAIP,IAAgB,QAAaC,IAAgB,OAC/C,MAAM,IAAIX,EAAyBW,EAAa,cAAc,EAGhE,GAAID,IAAgB,OAClB,MAAM,IAAIV,EACR,oCACA,mBACF,EAGF,OAAOU,CACT,CACF,CACF,CAAC,CACH,CCyBA,IAAMQ,GAAa,WAEnB,eAAeC,EACbC,EACAC,EACAC,EACY,CAEZ,IAAMC,EAAkC,CACtC,cAAe,UAFFC,EAAU,EAES,KAAK,EACvC,EAEIF,IAAS,SACXC,EAAQ,cAAc,EAAI,oBAG5B,IAAME,EAAM,MAAM,MAAM,GAAGP,EAAU,GAAGE,CAAI,GAAI,CAC9C,OAAAC,EACA,QAAAE,EACA,GAAID,IAAS,QAAa,CAAE,KAAM,KAAK,UAAUA,CAAI,CAAE,CACzD,CAAC,EAED,GAAI,CAACG,EAAI,GAAI,CACX,IAAIC,EAAe,8BAA8BD,EAAI,MAAM,IAAIA,EAAI,UAAU,GACzEE,EAAY,mBAChB,GAAI,CACF,IAAMC,EAAO,MAAMH,EAAI,KAAK,EACxBG,EAAI,QACNF,EAAeE,EAAI,OAEjBA,EAAI,OACND,EAAYC,EAAI,KAEpB,MAAQ,CAER,CACA,MAAM,IAAIC,EAAyBH,EAAcC,EAAWF,EAAI,MAAM,CACxE,CAEA,OAAQ,MAAMA,EAAI,KAAK,CACzB,CAEA,SAASK,GACPC,EACAC,EACM,CAKN,OAHAA,EAAU,UAAUD,CAAK,EAGjBA,EAAM,KAAM,CAClB,IAAK,OACHC,EAAU,SAASD,EAAM,IAAI,EAC7B,MACF,IAAK,WACHC,EAAU,aAAaD,EAAM,IAAI,EACjC,MACF,IAAK,oBACHC,EAAU,qBAAqBD,EAAM,SAAUA,EAAM,SAAS,EAC9D,MACF,IAAK,kBACHC,EAAU,kBAAkBD,EAAM,GAAIA,EAAM,IAAI,EAChD,MACF,IAAK,mBACHC,EAAU,mBAAmBD,EAAM,GAAIA,EAAM,MAAM,EACnD,MACF,IAAK,QACHC,EAAU,UAAUD,EAAM,KAAK,EAC/B,KACJ,CACF,CAgCO,SAASE,IAAyC,CACvD,MAAO,CACL,cAAe,CACb,OAAOd,EAAuB,WAAY,MAAM,CAClD,EAEA,YAAYe,EAAiB,CAC3B,IAAMC,EAAQD,EAAS,WAAW,mBAAmBA,CAAM,CAAC,GAAK,GACjE,OAAOf,EAAwB,WAAWgB,CAAK,GAAI,KAAK,CAC1D,EAEA,UAAUC,EAAkB,CAC1B,OAAOjB,EAAgB,YAAYiB,CAAQ,GAAI,KAAK,CACtD,EAEA,MAAM,aAAaA,EAAkBC,EAAe,CAClD,MAAMlB,EAAQ,YAAYiB,CAAQ,GAAI,QAAS,CAAE,MAAAC,CAAM,CAAC,CAC1D,EAEA,MAAM,aAAaD,EAAkB,CACnC,MAAMjB,EAAQ,YAAYiB,CAAQ,GAAI,QAAQ,CAChD,EAEA,YACEA,EACAE,EACAN,EACAO,EACqC,CACrC,IAAMC,EAAa,IAAI,gBACjBC,EAAKT,GAAa,CAAC,EAGrBS,EAAG,SACDA,EAAG,OAAO,QACZD,EAAW,MAAM,EAEjBC,EAAG,OAAO,iBAAiB,QAAS,IAAMD,EAAW,MAAM,EAAG,CAC5D,KAAM,EACR,CAAC,GA8FL,IAAME,GA1FW,SAAwC,CACvD,IAAMC,EAASnB,EAAU,EACnBoB,EAAM,GAAG1B,EAAU,YAAYkB,CAAQ,YAEvCX,EAAM,MAAM,MAAMmB,EAAK,CAC3B,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,cAAe,UAAUD,EAAO,KAAK,EACvC,EACA,KAAM,KAAK,UAAU,CACnB,QAAAL,EACA,GAAIC,GAAS,aAAa,QAAU,CAClC,YAAaA,EAAQ,WACvB,CACF,CAAC,EACD,OAAQC,EAAW,MACrB,CAAC,EAED,GAAI,CAACf,EAAI,GAAI,CACX,IAAIC,EAAe,wBAAwBD,EAAI,MAAM,IAAIA,EAAI,UAAU,GACnEE,EAAY,mBAChB,GAAI,CACF,IAAMC,EAAO,MAAMH,EAAI,KAAK,EAIxBG,EAAI,QACNF,EAAeE,EAAI,OAEjBA,EAAI,OACND,EAAYC,EAAI,KAEpB,MAAQ,CAER,CACA,MAAM,IAAIC,EACRH,EACAC,EACAF,EAAI,MACN,CACF,CAEA,IAAMoB,EAASpB,EAAI,KAAM,UAAU,EAC7BqB,EAAU,IAAI,YAChBC,EAAS,GACTC,EAEJ,OAAa,CACX,GAAM,CAAE,KAAAC,EAAM,MAAAC,CAAM,EAAI,MAAML,EAAO,KAAK,EAC1C,GAAII,EACF,MAGFF,GAAUD,EAAQ,OAAOI,EAAO,CAAE,OAAQ,EAAK,CAAC,EAChD,IAAMC,EAAQJ,EAAO,MAAM;AAAA,CAAI,EAC/BA,EAASI,EAAM,IAAI,GAAK,GAExB,QAAWC,KAAQD,EAAO,CACxB,GAAI,CAACC,EAAK,WAAW,QAAQ,EAC3B,SAEF,IAAMC,EAAOD,EAAK,MAAM,CAAC,EACzB,GAAI,CACF,IAAMrB,EAAQ,KAAK,MAAMsB,CAAI,EAEzBtB,EAAM,OAAS,SACjBiB,EAAS,CACP,WAAYjB,EAAM,WAClB,MAAOA,EAAM,KACf,GAGFD,GAAcC,EAAOU,CAAE,CACzB,MAAQ,CAER,CACF,CACF,CAEA,GAAI,CAACO,EACH,MAAM,IAAInB,EACR,oCACA,mBACF,EAGF,OAAOmB,CACT,GAAG,EAGH,OAAAN,EAAU,MAAQ,IAAMF,EAAW,MAAM,EAClCE,CACT,CACF,CACF,CC9iBO,IAAMY,GAAW,CA4BtB,MAAM,WAAWC,EAAYC,EAA8C,CACzE,IAAMC,EAASC,EAAU,EACnB,CAAE,WAAAC,EAAY,OAAAC,CAAO,EAAIJ,GAAW,CAAC,EAG3CI,GAAQ,eAAe,EAIvB,IAAMC,EAAa,MAAM,MADN,6BACwB,CACzC,OAAQ,OACR,QAAS,CACP,cAAe,UAAUJ,EAAO,KAAK,GACrC,eAAgB,kBAClB,EACA,KAAM,KAAK,UAAU,CACnB,SAAUF,EAAK,KACf,YAAaA,EAAK,MAAQ,0BAC5B,CAAC,EACD,OAAAK,CACF,CAAC,EAED,GAAI,CAACC,EAAW,GACd,MAAM,IAAIC,EACR,0BAA0BD,EAAW,MAAM,IAAIA,EAAW,UAAU,GACpE,eACAA,EAAW,MACb,EAGF,GAAM,CAAE,UAAAE,EAAW,aAAAC,EAAc,UAAAC,CAAU,EACxC,MAAMJ,EAAW,KAAK,EAOnBK,EAAW,IAAI,SACrB,OAAW,CAACC,EAAKC,CAAK,IAAK,OAAO,QAAQJ,CAAY,EACpDE,EAAS,OAAOC,EAAKC,CAAK,EAK5B,GAHAF,EAAS,OAAO,OAAQX,CAAI,EAGxBI,EACF,aAAMU,GAAUN,EAAWG,EAAUP,EAAYC,CAAM,EAChDK,EAGT,IAAMK,EAAY,MAAM,MAAMP,EAAW,CACvC,OAAQ,OACR,KAAMG,EACN,OAAAN,CACF,CAAC,EAED,GAAI,CAACU,EAAU,GACb,MAAM,IAAIR,EACR,uBAAuBQ,EAAU,MAAM,IAAIA,EAAU,UAAU,GAC/D,eACAA,EAAU,MACZ,EAGF,OAAOL,CACT,CACF,EAMA,SAASI,GACPE,EACAL,EACAP,EACAC,EACe,CACf,OAAO,IAAI,QAAc,CAACY,EAASC,IAAW,CAC5C,IAAMC,EAAM,IAAI,eAqChB,GAnCAA,EAAI,OAAO,iBAAiB,WAAaC,GAAM,CACzCA,EAAE,kBACJhB,EAAWgB,EAAE,OAASA,EAAE,KAAK,CAEjC,CAAC,EAEDD,EAAI,iBAAiB,OAAQ,IAAM,CAC7BA,EAAI,QAAU,KAAOA,EAAI,OAAS,KACpCf,EAAW,CAAC,EACZa,EAAQ,GAERC,EACE,IAAIX,EACF,uBAAuBY,EAAI,MAAM,IAAIA,EAAI,UAAU,GACnD,eACAA,EAAI,MACN,CACF,CAEJ,CAAC,EAEDA,EAAI,iBAAiB,QAAS,IAAM,CAClCD,EACE,IAAIX,EACF,oCACA,cACF,CACF,CACF,CAAC,EAEDY,EAAI,iBAAiB,QAAS,IAAM,CAClCD,EAAO,IAAI,aAAa,iBAAkB,YAAY,CAAC,CACzD,CAAC,EAGGb,EAAQ,CACV,GAAIA,EAAO,QAAS,CAClBa,EAAO,IAAI,aAAa,iBAAkB,YAAY,CAAC,EACvD,MACF,CACAb,EAAO,iBAAiB,QAAS,IAAMc,EAAI,MAAM,EAAG,CAAE,KAAM,EAAK,CAAC,CACpE,CAEAA,EAAI,KAAK,OAAQH,CAAG,EACpBG,EAAI,KAAKR,CAAQ,CACnB,CAAC,CACH,CC1KO,IAAMU,EAAgC,CAC3C,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,cAAe,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,sBAAuB,KAAM,oBAAO,EACxE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,YAAa,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,YAAa,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,UAAW,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,UAAW,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,WAAY,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,UAAW,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,yBAA0B,KAAM,oBAAO,EAC7E,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,SAAU,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,eAAgB,KAAM,oBAAO,EACnE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,SAAU,KAAM,oBAAO,EAC3D,CACE,KAAM,KACN,SAAU,OACV,KAAM,2BACN,KAAM,oBACR,EACA,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,OAAQ,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,QAAS,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,QAAS,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,WAAY,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,cAAe,KAAM,oBAAO,EAClE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,OAAQ,KAAM,oBAAO,EAC1D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,gBAAiB,KAAM,oBAAO,EACpE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,UAAW,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,WAAY,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,qBAAsB,KAAM,oBAAO,EACvE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,QAAS,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,cAAe,KAAM,oBAAO,EAClE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,oBAAqB,KAAM,oBAAO,EACxE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,OAAQ,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,SAAU,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,UAAW,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,SAAU,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,UAAW,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,YAAa,KAAM,oBAAO,EAChE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,gBAAiB,KAAM,oBAAO,EACpE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,YAAa,KAAM,oBAAO,EAChE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,UAAW,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,QAAS,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,YAAa,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,OAAQ,KAAM,oBAAO,EAC1D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,OAAQ,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,QAAS,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,UAAW,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,QAAS,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,aAAc,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,OAAQ,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,gBAAiB,KAAM,oBAAO,EACpE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,YAAa,KAAM,oBAAO,EAChE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,WAAY,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,OAAQ,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,mBAAoB,KAAM,oBAAO,EACvE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,YAAa,KAAM,oBAAO,EAChE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,SAAU,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,UAAW,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,cAAe,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,cAAe,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,YAAa,KAAM,oBAAO,EAChE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,cAAe,KAAM,oBAAO,EAClE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,kBAAmB,KAAM,oBAAO,EACtE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,SAAU,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,OAAQ,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,WAAY,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,YAAa,KAAM,oBAAO,EAChE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,mBAAoB,KAAM,oBAAO,EACvE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,OAAQ,KAAM,oBAAO,EAC1D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,cAAe,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,SAAU,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,cAAe,KAAM,oBAAO,EAChE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,UAAW,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,SAAU,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,wBAAyB,KAAM,oBAAO,EAC1E,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,cAAe,KAAM,oBAAO,EAChE,CACE,KAAM,KACN,SAAU,KACV,KAAM,mCACN,KAAM,oBACR,EACA,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,wBAAyB,KAAM,oBAAO,EAC5E,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,eAAgB,KAAM,oBAAO,EACnE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,eAAgB,KAAM,oBAAO,EACnE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,YAAa,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,kBAAmB,KAAM,oBAAO,EACtE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,eAAgB,KAAM,oBAAO,EAClE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,cAAe,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,cAAe,KAAM,oBAAO,EAClE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,QAAS,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,YAAa,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,SAAU,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,cAAe,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,WAAY,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,cAAe,KAAM,oBAAO,EAClE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,OAAQ,KAAM,oBAAO,EAC3D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,sBAAuB,KAAM,oBAAO,EACxE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,SAAU,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,eAAgB,KAAM,oBAAO,EACnE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,uBAAwB,KAAM,oBAAO,EAC3E,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,iBAAkB,KAAM,oBAAO,EACpE,CAAE,KAAM,KAAM,SAAU,KAAM,KAAM,gBAAiB,KAAM,oBAAO,EAClE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,aAAc,KAAM,oBAAO,EACjE,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,UAAW,KAAM,oBAAO,EAC9D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,eAAgB,KAAM,oBAAO,EAClE,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,YAAa,KAAM,oBAAO,EAC/D,CAAE,KAAM,KAAM,SAAU,MAAO,KAAM,UAAW,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,QAAS,KAAM,oBAAO,EAC5D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,SAAU,KAAM,oBAAO,EAC7D,CAAE,KAAM,KAAM,SAAU,OAAQ,KAAM,WAAY,KAAM,oBAAO,CACjE,EAMMC,GAAS,IAAI,IAAID,EAAU,IAAKE,GAAM,CAACA,EAAE,KAAMA,CAAC,CAAC,CAAC,EAGlDC,GAA4C,CAChD,mBAAoB,KACpB,kBAAmB,KACnB,iBAAkB,KAClB,sBAAuB,KACvB,oBAAqB,KACrB,mBAAoB,KACpB,kBAAmB,KACnB,+BAAgC,KAChC,kBAAmB,KACnB,oBAAqB,KACrB,mBAAoB,KACpB,mBAAoB,KACpB,kBAAmB,KACnB,mBAAoB,KACpB,gBAAiB,KACjB,gBAAiB,KACjB,eAAgB,KAChB,gBAAiB,KACjB,gBAAiB,KACjB,cAAe,KACf,mBAAoB,KACpB,kBAAmB,KACnB,gBAAiB,KACjB,gBAAiB,KACjB,mBAAoB,KACpB,cAAe,KACf,oBAAqB,KACrB,kBAAmB,KACnB,gBAAiB,KACjB,gBAAiB,KACjB,mBAAoB,KACpB,kBAAmB,KACnB,gBAAiB,KACjB,kBAAmB,KACnB,gBAAiB,KACjB,cAAe,KACf,gBAAiB,KACjB,kBAAmB,KACnB,gBAAiB,KACjB,oBAAqB,KACrB,mBAAoB,KACpB,iBAAkB,KAClB,cAAe,KACf,iBAAkB,KAClB,aAAc,KACd,aAAc,KACd,gBAAiB,KACjB,iBAAkB,KAClB,cAAe,KACf,iBAAkB,KAClB,eAAgB,KAChB,eAAgB,KAChB,aAAc,KACd,eAAgB,KAChB,eAAgB,KAChB,cAAe,KACf,oBAAqB,KACrB,mBAAoB,KACpB,cAAe,KACf,aAAc,KACd,cAAe,KACf,eAAgB,KAChB,cAAe,KACf,iBAAkB,KAClB,aAAc,KACd,cAAe,KACf,gBAAiB,KACjB,eAAgB,KAChB,iBAAkB,KAClB,cAAe,KACf,mBAAoB,KACpB,sBAAuB,KACvB,qBAAsB,KACtB,kBAAmB,KACnB,qBAAsB,KACtB,mBAAoB,KACpB,eAAgB,KAChB,eAAgB,KAChB,eAAgB,KAChB,iBAAkB,KAClB,sBAAuB,KACvB,oBAAqB,KACrB,eAAgB,KAChB,qBAAsB,KACtB,uBAAwB,KACxB,iBAAkB,KAClB,sBAAuB,KACvB,iBAAkB,KAClB,eAAgB,KAChB,mBAAoB,KACpB,uBAAwB,KACxB,oBAAqB,KACrB,kBAAmB,KACnB,oBAAqB,KACrB,iBAAkB,KAClB,iBAAkB,KAClB,kBAAmB,IACrB,EAUO,SAASC,IAAwB,CACtC,GAAI,CACF,IAAMC,EAAK,KAAK,eAAe,EAAE,gBAAgB,EAAE,SACnD,OAAOF,GAAkBE,CAAE,GAAK,IAClC,MAAQ,CACN,MAAO,IACT,CACF,CAQO,SAASC,GAAOC,EAAsB,CAC3C,GAAI,CAACA,EAAK,WAAW,GAAG,EACtB,OAAOA,EAGT,IAAMC,EAASD,EAAK,MAAM,CAAC,EAG3B,GAAIC,EAAO,WAAW,GAAG,GAAKA,EAAO,SAAW,GAAI,CAClD,IAAMC,EAAOD,EAAO,MAAM,EAAG,CAAC,EACxBE,EAASF,EAAO,MAAM,EAAG,CAAC,EAC1BG,EAAOH,EAAO,MAAM,CAAC,EAC3B,MAAO,OAAOC,CAAI,KAAKC,CAAM,IAAIC,CAAI,EACvC,CAGA,QAASC,EAAM,EAAGA,GAAO,EAAGA,IAAO,CACjC,IAAMC,EAAY,IAAML,EAAO,MAAM,EAAGI,CAAG,EACrCE,EAAQd,EAAU,KAAME,GAAMA,EAAE,WAAaW,CAAS,EAC5D,GAAIC,EAAO,CACT,IAAMC,EAAOP,EAAO,MAAMI,CAAG,EAC7B,MAAO,GAAGE,EAAM,QAAQ,IAAIC,CAAI,EAClC,CACF,CAEA,OAAOR,CACT,CASO,SAASS,GAAOC,EAAkBC,EAA6B,CACpE,IAAMV,EAASS,EAAS,QAAQ,MAAO,EAAE,EACnCE,EAAUlB,GAAO,IAAIiB,CAAW,EACtC,GAAI,CAACC,EACH,MAAO,IAAMX,EAEf,IAAMY,EAAaD,EAAQ,SAAS,MAAM,CAAC,EAE3C,OAAIX,EAAO,WAAWY,CAAU,EACvB,IAAMZ,EAERW,EAAQ,SAAWX,CAC5B,CAMO,SAASa,GAAQC,EAAwB,CAC9C,MAAO,oBAAoB,KAAKA,CAAK,CACvC,CCjaO,SAASC,GAAQC,EAAwB,CAC9C,MAAO,6BAA6B,KAAKA,CAAK,CAChD,CCoDA,eAAeC,EACbC,EACAC,EACAC,EACY,CAEZ,IAAMC,EAAkC,CACtC,cAAe,UAFFC,EAAU,EAES,KAAK,EACvC,EAEIF,IAAS,SACXC,EAAQ,cAAc,EAAI,oBAG5B,IAAME,EAAM,MAAM,MAAML,EAAM,CAC5B,OAAAC,EACA,QAAAE,EACA,GAAID,IAAS,QAAa,CAAE,KAAM,KAAK,UAAUA,CAAI,CAAE,CACzD,CAAC,EAED,GAAI,CAACG,EAAI,GAAI,CACX,IAAIC,EAAU,wBAAwBD,EAAI,MAAM,IAAIA,EAAI,UAAU,GAC9DE,EAAO,aACX,GAAI,CACF,IAAMC,EAAO,MAAMH,EAAI,KAAK,EACxBG,EAAI,QACNF,EAAUE,EAAI,OAEZA,EAAI,OACND,EAAOC,EAAI,KAEf,MAAQ,CAER,CACA,MAAM,IAAIC,EAAyBH,EAASC,EAAMF,EAAI,MAAM,CAC9D,CAEA,OAAQ,MAAMA,EAAI,KAAK,CACzB,CAEA,IAAMK,EAAqD,IAAI,IAE/D,SAASC,EAAaC,EAAiC,CACrDC,GAAa,CACX,MAAOD,EAAO,MACd,KAAMA,EAAO,KACb,QAASA,EAAO,QAChB,UAAWA,EAAO,SACpB,CAAC,EACDF,EAAc,QAASI,GAAOA,EAAGF,EAAO,IAAI,CAAC,CAC/C,CAEA,SAASG,EAAYH,EAAoC,CACvD,GAAI,CAACA,EAAO,KACV,MAAM,IAAIH,EACR,kDACA,YACF,EAEF,OAAOG,EAAO,IAChB,CAEA,SAASI,GAAoBC,EAAgC,CAC3D,IAAMC,EAASd,EAAU,EACrBc,EAAO,OACT,OAAO,OAAOA,EAAO,KAAMD,CAAM,EACjCP,EAAc,QAASI,GAAOA,EAAGI,EAAO,IAAI,CAAC,EAEjD,CA0JO,IAAMC,GAAa,CAGxB,IAAI,aAAc,CAChB,OAAOf,EAAU,EAAE,IACrB,EAEA,gBAAiB,CACf,OAAOA,EAAU,EAAE,IACrB,EAEA,iBAAkB,CAChB,OAAOA,EAAU,EAAE,OAAS,IAC9B,EAEA,IAAI,kBAAmB,CACrB,OAAOA,EAAU,EAAE,WAAa,IAClC,EAEA,qBAAsB,CACpB,OAAOA,EAAU,EAAE,WAAa,IAClC,EAIA,cAAcgB,EAAe,CAC3B,OAAOrB,EAAsC,qBAAsB,OAAQ,CACzE,MAAAqB,CACF,CAAC,CACH,EAEA,MAAM,gBAAgBC,EAAwBd,EAAc,CAC1D,IAAMK,EAAS,MAAMb,EACnB,uBACA,OACA,CAAE,eAAAsB,EAAgB,KAAAd,CAAK,CACzB,EACA,OAAAI,EAAaC,CAAM,EACZG,EAAYH,CAAM,CAC3B,EAIA,YAAYU,EAAe,CACzB,OAAOvB,EAAsC,mBAAoB,OAAQ,CACvE,MAAAuB,CACF,CAAC,CACH,EAEA,MAAM,cAAcD,EAAwBd,EAAc,CACxD,IAAMK,EAAS,MAAMb,EACnB,qBACA,OACA,CAAE,eAAAsB,EAAgB,KAAAd,CAAK,CACzB,EACA,OAAAI,EAAaC,CAAM,EACZG,EAAYH,CAAM,CAC3B,EAIA,MAAM,mBAAmBW,EAAkB,CACzC,MAAMxB,EAAU,uBAAwB,OAAQ,CAAE,SAAAwB,CAAS,CAAC,CAC9D,EAEA,MAAM,mBAAmBA,EAAkBhB,EAAc,CACvD,IAAMK,EAAS,MAAMb,EACnB,+BACA,OACA,CAAE,SAAAwB,EAAU,KAAAhB,CAAK,CACnB,EACA,OAAAI,EAAaC,CAAM,EACZG,EAAYH,CAAM,CAC3B,EAEA,MAAM,mBAAmBY,EAAkB,CACzC,MAAMzB,EAAU,uBAAwB,OAAQ,CAAE,SAAAyB,CAAS,CAAC,CAC9D,EAEA,MAAM,mBAAmBA,EAAkBjB,EAAc,CACvD,IAAMK,EAAS,MAAMb,EACnB,+BACA,OACA,CAAE,SAAAyB,EAAU,KAAAjB,CAAK,CACnB,EACA,OAAAI,EAAaC,CAAM,EACZG,EAAYH,CAAM,CAC3B,EAIA,MAAM,QAAS,CACb,IAAMA,EAAS,MAAMb,EACnB,iBACA,OACA,CAAC,CACH,EACAY,EAAaC,CAAM,CACrB,EAEA,MAAM,cAAe,CACnB,IAAMa,EAAS,MAAM1B,EACnB,yBACA,OACA,CAAC,CACH,EACA,OAAAiB,GAAoB,CAAE,OAAQS,EAAO,MAAO,CAAC,EACtC,CAAE,IAAKA,EAAO,GAAI,CAC3B,EAEA,MAAM,cAAe,CACnB,MAAM1B,EAAU,yBAA0B,OAAQ,CAAC,CAAC,EACpDiB,GAAoB,CAAE,OAAQ,IAAK,CAAC,CACtC,EAEA,mBAAmBU,EAA0C,CAC3D,OAAAhB,EAAc,IAAIgB,CAAQ,EAC1BA,EAAStB,EAAU,EAAE,IAAI,EAClB,IAAM,CACXM,EAAc,OAAOgB,CAAQ,CAC/B,CACF,EAIA,MAAO,CACL,UAAwBC,EACxB,cAA4BC,GAC5B,OAAqBC,GACrB,OAAqBC,GACrB,QAAsBC,EACxB,EAEA,MAAO,CACL,QAAsBA,EACxB,CACF,EC3UE,OAAO,OAAW,KACjB,WAAuC,gBAExC,WAAW,IAAM,CACf,GAAI,CACFC,EAAU,CACZ,MAAQ,CAER,CACF,EAAG,CAAC","names":["MindStudioInterfaceError","message","code","status","TELEMETRY_ENDPOINT_FRAGMENT","buffer","push","entry","getBreadcrumbs","shouldSkipUrl","url","TELEMETRY_ENDPOINT_FRAGMENT","resolveUrl","input","lastHref","navListeners","onNavigation","cb","emitNavigation","to","installHistory","w","originalPushState","data","unused","originalReplaceState","installFetch","captureResponseBodies","originalFetch","patched","init","method","startTime","response","body","err","installXhr","originalOpen","originalSend","rest","_breadcrumbsInstalled","installBreadcrumbs","opts","EVENTS_ENDPOINT","FLUSH_INTERVAL_MS","MAX_BATCH_SIZE","DEFAULT_RETRY_AFTER_MS","pending","flushTimer","suppressUntil","unloaded","enqueue","event","scheduleFlush","flush","takeBatch","batch","config","getConfig","events","res","retryAfterHeader","retryAfterSec","waitMs","drainOnUnload","sanitizeProps","input","out","k","v","emitPageview","url","track","props","PRESENCE_ENDPOINT","PRESENCE_MAX_BACKOFF_MS","PRESENCE_503_DEFAULT_MS","presenceAbort","presenceReconnectTimer","presenceBackoffMs","presenceActive","presenceNextBackoff","base","jitter","schedulePresenceReconnect","ms","openPresenceConnection","closePresenceConnection","signal","reader","done","err","name","analytics","_installed","installAnalytics","handleUnload","onNavigation","maybeInstallAnalytics","ENDPOINT","FLUSH_INTERVAL_MS","MAX_BATCH_SIZE","DEFAULT_RETRY_AFTER_MS","_installed","pending","flushTimer","suppressUntil","unloaded","fingerprint","message","stack","firstStackLine","enqueue","event","fp","existing","scheduleFlush","flush","takeBatch","batch","_fp","rest","config","getConfig","events","res","retryAfterHeader","retryAfterSec","waitMs","drainOnUnload","captureError","getBreadcrumbs","captureRejection","reason","installErrorMonitoring","installBreadcrumbs","handleUnload","maybeInstallTelemetry","_config","getConfig","raw","MindStudioInterfaceError","missing","k","maybeInstallTelemetry","maybeInstallAnalytics","updateConfig","updates","config","createClient","_","methodName","input","options","config","getConfig","methodId","MindStudioInterfaceError","url","wantsStream","res","errorMessage","errorCode","body","reader","decoder","buffer","finalOutput","streamError","done","value","lines","line","json","event","AGENT_BASE","request","path","method","body","headers","getConfig","res","errorMessage","errorCode","err","MindStudioInterfaceError","dispatchEvent","event","callbacks","createAgentChatClient","cursor","query","threadId","title","content","options","controller","cb","abortable","config","url","reader","decoder","buffer","result","done","value","lines","line","json","platform","file","options","config","getConfig","onProgress","signal","presignRes","MindStudioInterfaceError","uploadUrl","uploadFields","publicUrl","formData","key","value","xhrUpload","uploadRes","url","resolve","reject","xhr","e","countries","byCode","c","timezoneToCountry","detectCountry","tz","format","e164","digits","area","prefix","line","len","candidate","match","rest","toE164","national","countryCode","country","dialDigits","isValid","phone","isValid","email","authFetch","path","method","body","headers","getConfig","res","message","code","err","MindStudioInterfaceError","authListeners","applySession","bundle","updateConfig","cb","requireUser","updateUserAndNotify","update","config","auth","email","verificationId","phone","newEmail","newPhone","result","callback","countries","detectCountry","format","toE164","isValid","getConfig"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindstudio-ai/interface",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Frontend SDK for MindStudio v2 app interfaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
},
|
|
43
43
|
"author": "MindStudio <support@mindstudio.ai> (https://mindstudio.ai)",
|
|
44
44
|
"license": "MIT",
|
|
45
|
-
"sideEffects":
|
|
45
|
+
"sideEffects": [
|
|
46
|
+
"./dist/index.js"
|
|
47
|
+
],
|
|
46
48
|
"devDependencies": {
|
|
47
49
|
"husky": "^9.1.7",
|
|
48
50
|
"lint-staged": "^16.3.2",
|