@promte/app-library 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 CHANGED
@@ -105,6 +105,29 @@ const response = await client.embeddings.create({
105
105
  const vectors = response.data.map((item) => item.embedding);
106
106
  ```
107
107
 
108
+ ## Knowledge search
109
+
110
+ Apps can search an assistant/workspace knowledge base directly:
111
+
112
+ ```ts
113
+ const client = usePromteClient();
114
+
115
+ const response = await client.knowledge.search({
116
+ workspaceId: "assistant-workspace-id",
117
+ query: "Hvad gælder for carporte i BR18?",
118
+ maxResults: 8,
119
+ generateSearchQuery: true,
120
+ });
121
+
122
+ for (const result of response.results) {
123
+ console.log(result.title, result.text, result.sourceUrl);
124
+ }
125
+ ```
126
+
127
+ If `workspaceId` is omitted, the search uses the current app workspace. Searching
128
+ another workspace requires that the current user has access to that workspace.
129
+ Public app tokens can only search their own workspace.
130
+
108
131
  ## Return behavior
109
132
 
110
133
  - `get()` returns the value at the current path, or `null` if missing.
package/dist/index.d.ts CHANGED
@@ -18,11 +18,13 @@ export declare type AudioSttRequest = {
18
18
  file: File | Blob;
19
19
  language?: string;
20
20
  prompt?: string;
21
+ responseFormat?: "json" | "verbose_json";
21
22
  ext?: string;
22
23
  };
23
24
 
24
25
  export declare type AudioSttResponse = {
25
26
  text: string;
27
+ language?: string;
26
28
  raw: any;
27
29
  };
28
30
 
@@ -68,9 +70,20 @@ export declare type ChatCompletionsRequest = {
68
70
 
69
71
  export declare type ChatCompletionsResponse = any;
70
72
 
73
+ export declare type ChatContentPart = {
74
+ type: "text";
75
+ text: string;
76
+ } | {
77
+ type: "image_url";
78
+ image_url: {
79
+ url: string;
80
+ detail?: "auto" | "low" | "high" | "original";
81
+ };
82
+ };
83
+
71
84
  export declare type ChatMessage = {
72
85
  role: "system" | "user" | "assistant" | "tool";
73
- content: string;
86
+ content: string | ChatContentPart[];
74
87
  };
75
88
 
76
89
  export declare type EmbeddingItem = {
@@ -99,6 +112,41 @@ export declare type EmbeddingsResponse = {
99
112
  [key: string]: any;
100
113
  };
101
114
 
115
+ export declare type KnowledgeSearchRequest = {
116
+ workspaceId?: string;
117
+ query: string;
118
+ maxResults?: number;
119
+ generateSearchQuery?: boolean;
120
+ sourceId?: string;
121
+ includeSourceUrls?: boolean;
122
+ queries?: string[];
123
+ };
124
+
125
+ export declare type KnowledgeSearchResponse = {
126
+ workspaceId: string;
127
+ workspaceName?: string;
128
+ query: string;
129
+ searchQueries: string[];
130
+ maxResults: number;
131
+ results: KnowledgeSearchResult[];
132
+ sourceIds: string[];
133
+ chunkIds: string[];
134
+ };
135
+
136
+ export declare type KnowledgeSearchResult = {
137
+ index: number;
138
+ id: string;
139
+ chunkId: string;
140
+ sourceWorkspaceId: string;
141
+ sourceId: string;
142
+ sourceName?: string;
143
+ title: string;
144
+ text: string;
145
+ relevance?: number;
146
+ link?: string;
147
+ sourceUrl?: string;
148
+ };
149
+
102
150
  export declare function PromteAppProvider({ children, expectedParentOrigin, initTargetOrigin, retryInit, }: PromteAppProviderProps): JSX_2.Element;
103
151
 
104
152
  export declare type PromteAppProviderProps = {
@@ -122,6 +170,16 @@ export declare type PromteClient = {
122
170
  create(req: EmbeddingsRequest): Promise<EmbeddingsResponse>;
123
171
  };
124
172
  audio: {
173
+ speechToken(): Promise<{
174
+ token: string;
175
+ region: string;
176
+ }>;
177
+ voiceLiveSession(): Promise<{
178
+ sessionToken: string;
179
+ websocketUrl: string;
180
+ model: string;
181
+ transcriptionModel: string;
182
+ }>;
125
183
  tts(req: AudioTtsRequest): Promise<AudioTtsResponse>;
126
184
  stt(req: AudioSttRequest): Promise<AudioSttResponse>;
127
185
  voices(req?: AudioVoicesRequest): Promise<AudioVoiceInfo[]>;
@@ -129,6 +187,18 @@ export declare type PromteClient = {
129
187
  web: {
130
188
  scrapeUrl(req: ScrapeUrlRequest): Promise<ScrapeUrlResponse>;
131
189
  };
190
+ knowledge: {
191
+ search(req: KnowledgeSearchRequest): Promise<KnowledgeSearchResponse>;
192
+ };
193
+ translatorLiveShare: {
194
+ create(displayLanguage: string): Promise<{
195
+ shareId: string;
196
+ token: string;
197
+ expiresAt: string;
198
+ }>;
199
+ update(shareId: string, snapshot: TranslatorLiveShareSnapshot): Promise<void>;
200
+ revoke(shareId: string): Promise<void>;
201
+ };
132
202
  data(scope?: AppDataScope): AppDataRef;
133
203
  };
134
204
 
@@ -160,6 +230,20 @@ export declare type PromteModelsRequest = {
160
230
 
161
231
  export declare type PromteModelType = "llm" | "embedding" | "image" | "stt" | "tts";
162
232
 
233
+ /**
234
+ * Provides the same Promte runtime to first-party, in-process features without
235
+ * duplicating the app client or emulating the iframe postMessage handshake.
236
+ */
237
+ export declare function PromteNativeProvider({ children, settings, token, isDarkMode, user, }: PromteNativeProviderProps): JSX_2.Element;
238
+
239
+ export declare type PromteNativeProviderProps = {
240
+ children: default_2.ReactNode;
241
+ settings: PromteSettings;
242
+ token: string | null;
243
+ isDarkMode: boolean;
244
+ user: PromteUser | null;
245
+ };
246
+
163
247
  export declare type PromteSettings = {
164
248
  workspaceId: string;
165
249
  version: number;
@@ -200,6 +284,23 @@ export declare type ScrapeUrlResponse = {
200
284
  };
201
285
  };
202
286
 
287
+ export declare type TranslatorLiveShareLine = {
288
+ id: string;
289
+ speaker: string;
290
+ language?: string;
291
+ text: string;
292
+ pending?: boolean;
293
+ edited?: boolean;
294
+ createdAt: string;
295
+ };
296
+
297
+ export declare type TranslatorLiveShareSnapshot = {
298
+ displayLanguage: string;
299
+ status: "active" | "ended";
300
+ lines: TranslatorLiveShareLine[];
301
+ revision: number;
302
+ };
303
+
203
304
  export declare function usePromte(): PromteCtxValue;
204
305
 
205
306
  export declare function usePromteClient(): PromteClient;
package/dist/index.mjs CHANGED
@@ -1,133 +1,160 @@
1
1
  import { jsx as B } from "react/jsx-runtime";
2
- import { createContext as L, useState as k, useMemo as x, useCallback as U, useEffect as T, useContext as D } from "react";
3
- const O = L(null);
4
- function N({
5
- children: p,
6
- expectedParentOrigin: d,
7
- initTargetOrigin: v,
8
- retryInit: l = { enabled: !0, intervalMs: 500, maxAttempts: 20 }
2
+ import { createContext as J, useState as T, useMemo as P, useCallback as _, useEffect as $, useContext as D } from "react";
3
+ const x = J(null);
4
+ function W({
5
+ children: f,
6
+ expectedParentOrigin: l,
7
+ initTargetOrigin: g,
8
+ retryInit: c = { enabled: !0, intervalMs: 500, maxAttempts: 20 }
9
9
  }) {
10
- const [m, $] = k(null), [y, j] = k(null), [h, b] = k(null), [E, t] = k(null), [r, e] = k(null), n = x(() => r ? "booting" : m ? y ? "ready" : "waiting_for_token" : "waiting_for_settings", [m, y, r]), s = n === "ready", c = x(() => v || d || "*", [v, d]), a = U(() => {
11
- var o;
10
+ const [p, k] = T(null), [y, v] = T(null), [b, E] = T(null), [S, t] = T(null), [r, e] = T(null), n = P(() => r ? "booting" : p ? y ? "ready" : "waiting_for_token" : "waiting_for_settings", [p, y, r]), o = n === "ready", a = P(() => g || l || "*", [g, l]), u = _(() => {
11
+ var d;
12
12
  try {
13
- const w = { type: "init" };
14
- (o = window.parent) == null || o.postMessage(w, c);
15
- } catch (w) {
16
- e((w == null ? void 0 : w.message) || "Failed to post init");
13
+ const h = { type: "init" };
14
+ (d = window.parent) == null || d.postMessage(h, a);
15
+ } catch (h) {
16
+ e((h == null ? void 0 : h.message) || "Failed to post init");
17
17
  }
18
- }, [c]);
19
- T(() => {
20
- a();
21
- }, [a]), T(() => {
22
- if (!(l != null && l.enabled) || m) return;
23
- const o = l.intervalMs ?? 500, w = l.maxAttempts ?? 20;
24
- let i = 0;
25
- const f = window.setInterval(() => {
26
- if (m) {
27
- window.clearInterval(f);
18
+ }, [a]);
19
+ $(() => {
20
+ u();
21
+ }, [u]), $(() => {
22
+ if (!(c != null && c.enabled) || p) return;
23
+ const d = c.intervalMs ?? 500, h = c.maxAttempts ?? 20;
24
+ let s = 0;
25
+ const m = window.setInterval(() => {
26
+ if (p) {
27
+ window.clearInterval(m);
28
28
  return;
29
29
  }
30
- if (i += 1, i > w) {
31
- window.clearInterval(f);
30
+ if (s += 1, s > h) {
31
+ window.clearInterval(m);
32
32
  return;
33
33
  }
34
- a();
35
- }, o);
36
- return () => window.clearInterval(f);
37
- }, [l, m, a]), T(() => {
38
- const o = (w) => {
39
- if (d && w.origin !== d) return;
40
- const i = w.data;
41
- if (!(!i || typeof i != "object")) {
42
- if (i.type === "set-settings") {
43
- const f = i.value;
44
- if (!(f != null && f.backendUrl) || f.parentOrigin && d && f.parentOrigin !== d)
34
+ u();
35
+ }, d);
36
+ return () => window.clearInterval(m);
37
+ }, [c, p, u]), $(() => {
38
+ const d = (h) => {
39
+ if (l && h.origin !== l) return;
40
+ const s = h.data;
41
+ if (!(!s || typeof s != "object")) {
42
+ if (s.type === "set-settings") {
43
+ const m = s.value;
44
+ if (!(m != null && m.backendUrl) || m.parentOrigin && l && m.parentOrigin !== l)
45
45
  return;
46
- $(f), f != null && f.user && t(f.user), e(null);
46
+ k(m), m != null && m.user && t(m.user), e(null);
47
47
  return;
48
48
  }
49
- if (i.type === "set-token" && typeof i.value == "string") {
50
- j(i.value), e(null);
49
+ if (s.type === "set-token" && typeof s.value == "string") {
50
+ v(s.value), e(null);
51
51
  return;
52
52
  }
53
- if (i.type === "set-dark-mode" && typeof i.value == "boolean") {
54
- b(i.value);
53
+ if (s.type === "set-dark-mode" && typeof s.value == "boolean") {
54
+ E(s.value);
55
55
  return;
56
56
  }
57
- if (i.type === "set-user" && typeof i.value == "object") {
58
- t(i.value);
57
+ if (s.type === "set-user" && typeof s.value == "object") {
58
+ t(s.value);
59
59
  return;
60
60
  }
61
61
  }
62
62
  };
63
- return window.addEventListener("message", o), () => window.removeEventListener("message", o);
64
- }, [d]);
65
- const u = x(() => _(
66
- () => m,
63
+ return window.addEventListener("message", d), () => window.removeEventListener("message", d);
64
+ }, [l]);
65
+ const i = P(() => F(
66
+ () => p,
67
67
  () => y
68
- ), [m, y]), g = x(
68
+ ), [p, y]), w = P(
69
69
  () => ({
70
- settings: m,
70
+ settings: p,
71
71
  token: y,
72
- isDarkMode: h,
73
- user: E,
74
- ready: s,
72
+ isDarkMode: b,
73
+ user: S,
74
+ ready: o,
75
75
  state: n,
76
76
  error: r,
77
- client: u
77
+ client: i
78
78
  }),
79
- [m, y, h, E, s, n, r, u]
79
+ [p, y, b, S, o, n, r, i]
80
80
  );
81
- return /* @__PURE__ */ B(O.Provider, { value: g, children: p });
81
+ return /* @__PURE__ */ B(x.Provider, { value: w, children: f });
82
82
  }
83
- function S() {
84
- const p = D(O);
85
- if (!p)
86
- throw new Error("usePromte must be used inside <PromteAppProvider>");
87
- return p;
83
+ function K({
84
+ children: f,
85
+ settings: l,
86
+ token: g,
87
+ isDarkMode: c,
88
+ user: p
89
+ }) {
90
+ const k = P(
91
+ () => F(() => l, () => g),
92
+ [l, g]
93
+ ), y = !!g, v = P(
94
+ () => ({
95
+ settings: l,
96
+ token: g,
97
+ isDarkMode: c,
98
+ user: p,
99
+ ready: y,
100
+ state: y ? "ready" : "waiting_for_token",
101
+ error: null,
102
+ client: k
103
+ }),
104
+ [k, c, y, l, g, p]
105
+ );
106
+ return /* @__PURE__ */ B(x.Provider, { value: v, children: f });
88
107
  }
89
- function z() {
90
- return S().settings;
108
+ function j() {
109
+ const f = D(x);
110
+ if (!f)
111
+ throw new Error(
112
+ "usePromte must be used inside <PromteAppProvider> or <PromteNativeProvider>"
113
+ );
114
+ return f;
115
+ }
116
+ function Q() {
117
+ return j().settings;
91
118
  }
92
- function I() {
93
- return S().token;
119
+ function H() {
120
+ return j().token;
94
121
  }
95
- function V() {
96
- return S().isDarkMode;
122
+ function X() {
123
+ return j().isDarkMode;
97
124
  }
98
- function W() {
99
- return S().user;
125
+ function Y() {
126
+ return j().user;
100
127
  }
101
- function F() {
102
- return S().client;
128
+ function G() {
129
+ return j().client;
103
130
  }
104
- function K(p = {}) {
105
- const { ready: d } = S(), v = F(), [l, m] = k([]), [$, y] = k(!1), [j, h] = k(null), b = x(() => (Array.isArray(p.type) ? p.type : p.type ? [p.type] : []).filter(Boolean).map((n) => String(n)).join(","), [p.type]), E = p.configuredOnly === !0, t = p.auto !== !1, r = U(async () => {
106
- if (!d) return [];
107
- y(!0), h(null);
131
+ function Z(f = {}) {
132
+ const { ready: l } = j(), g = G(), [c, p] = T([]), [k, y] = T(!1), [v, b] = T(null), E = P(() => (Array.isArray(f.type) ? f.type : f.type ? [f.type] : []).filter(Boolean).map((n) => String(n)).join(","), [f.type]), S = f.configuredOnly === !0, t = f.auto !== !1, r = _(async () => {
133
+ if (!l) return [];
134
+ y(!0), b(null);
108
135
  try {
109
- const e = b ? b.split(",").filter(Boolean) : void 0, n = await v.models({ type: e, configuredOnly: E });
110
- return m(n), n;
136
+ const e = E ? E.split(",").filter(Boolean) : void 0, n = await g.models({ type: e, configuredOnly: S });
137
+ return p(n), n;
111
138
  } catch (e) {
112
139
  const n = e instanceof Error ? e.message : String(e);
113
- throw h(n), e;
140
+ throw b(n), e;
114
141
  } finally {
115
142
  y(!1);
116
143
  }
117
- }, [v, E, d, b]);
118
- return T(() => {
119
- !t || !d || r().catch(() => {
144
+ }, [g, S, l, E]);
145
+ return $(() => {
146
+ !t || !l || r().catch(() => {
120
147
  });
121
- }, [t, d, r]), { models: l, loading: $, error: j, reload: r };
148
+ }, [t, l, r]), { models: c, loading: k, error: v, reload: r };
122
149
  }
123
- function _(p, d) {
124
- const v = (t) => typeof t == "string" && t.startsWith("gpt-5");
125
- async function l(t, r) {
126
- const e = p(), n = d();
150
+ function F(f, l) {
151
+ const g = (t) => typeof t == "string" && (t.startsWith("gpt-5") || t.startsWith("gpt-6"));
152
+ async function c(t, r) {
153
+ const e = f(), n = l();
127
154
  if (!e) throw new Error("Promte settings not received yet");
128
155
  if (!n) throw new Error("Promte token not received yet");
129
- const s = e.backendUrl.replace(/\/+$/, ""), c = String(t || "").replace(/^\/+/, ""), a = `${s}/${c}`;
130
- return await fetch(a, {
156
+ const o = e.backendUrl.replace(/\/+$/, ""), a = String(t || "").replace(/^\/+/, ""), u = `${o}/${a}`;
157
+ return await fetch(u, {
131
158
  ...r,
132
159
  headers: {
133
160
  ...r.headers || {},
@@ -135,8 +162,8 @@ function _(p, d) {
135
162
  }
136
163
  });
137
164
  }
138
- async function m(t, r) {
139
- const e = await l(`/app-api/data/${t}`, {
165
+ async function p(t, r) {
166
+ const e = await c(`/app-api/data/${t}`, {
140
167
  method: "POST",
141
168
  headers: { "Content-Type": "application/json" },
142
169
  body: JSON.stringify(r)
@@ -147,10 +174,10 @@ function _(p, d) {
147
174
  );
148
175
  return n == null ? void 0 : n.value;
149
176
  }
150
- async function $(t) {
177
+ async function k(t) {
151
178
  const r = new URLSearchParams();
152
179
  t.scope && r.set("scope", t.scope), t.path && r.set("path", t.path);
153
- const e = await l(`/app-api/data?${r.toString()}`, {
180
+ const e = await c(`/app-api/data?${r.toString()}`, {
154
181
  method: "GET"
155
182
  }), n = await e.json().catch(() => ({}));
156
183
  if (!e.ok)
@@ -158,131 +185,131 @@ function _(p, d) {
158
185
  return n == null ? void 0 : n.value;
159
186
  }
160
187
  async function y(t) {
161
- const r = new URLSearchParams(), e = Array.isArray(t == null ? void 0 : t.type) ? t == null ? void 0 : t.type : t != null && t.type ? [t.type] : [];
162
- e.length > 0 && r.set("type", e.join(",")), t != null && t.configuredOnly && r.set("configuredOnly", "true");
163
- const n = await l(
188
+ const r = new URLSearchParams(), e = t == null ? void 0 : t.type, n = Array.isArray(e) ? e : e ? [e] : [];
189
+ n.length > 0 && r.set("type", n.join(",")), t != null && t.configuredOnly && r.set("configuredOnly", "true");
190
+ const o = await c(
164
191
  `/app-api/models${r.toString() ? `?${r.toString()}` : ""}`,
165
192
  { method: "GET" }
166
- ), s = await n.json().catch(() => ({}));
167
- if (!n.ok)
168
- throw new Error((s == null ? void 0 : s.error) || `Request failed (${n.status})`);
169
- return (Array.isArray(s == null ? void 0 : s.models) ? s.models : []).map((a) => {
170
- if (!a || typeof a != "object") return null;
171
- const u = typeof a.id == "string" ? a.id.trim() : "", g = typeof a.label == "string" ? a.label.trim() : u, o = a.type, w = a.configured === !0, i = typeof a.source == "string" && a.source.trim() ? a.source.trim() : void 0;
172
- return !u || o !== "llm" && o !== "embedding" && o !== "image" && o !== "stt" && o !== "tts" ? null : {
173
- id: u,
174
- label: g || u,
175
- type: o,
176
- configured: w,
177
- source: i
193
+ ), a = await o.json().catch(() => ({}));
194
+ if (!o.ok)
195
+ throw new Error((a == null ? void 0 : a.error) || `Request failed (${o.status})`);
196
+ return (Array.isArray(a == null ? void 0 : a.models) ? a.models : []).map((i) => {
197
+ if (!i || typeof i != "object") return null;
198
+ const w = typeof i.id == "string" ? i.id.trim() : "", d = typeof i.label == "string" ? i.label.trim() : w, h = i.type, s = i.configured === !0, m = typeof i.source == "string" && i.source.trim() ? i.source.trim() : void 0;
199
+ return !w || h !== "llm" && h !== "embedding" && h !== "image" && h !== "stt" && h !== "tts" ? null : {
200
+ id: w,
201
+ label: d || w,
202
+ type: h,
203
+ configured: s,
204
+ source: m
178
205
  };
179
206
  }).filter(
180
- (a) => !!a
207
+ (i) => !!i
181
208
  );
182
209
  }
183
- async function j(t, r) {
184
- const e = await l(t, r), s = (e.headers.get("content-type") || "").includes("application/json") ? await e.json().catch(() => ({})) : await e.text();
210
+ async function v(t, r) {
211
+ const e = await c(t, r), o = (e.headers.get("content-type") || "").includes("application/json") ? await e.json().catch(() => ({})) : await e.text();
185
212
  if (!e.ok)
186
213
  throw new Error(
187
- typeof s == "string" ? s || `Request failed (${e.status})` : (s == null ? void 0 : s.error) || (s == null ? void 0 : s.message) || `Request failed (${e.status})`
214
+ typeof o == "string" ? o || `Request failed (${e.status})` : (o == null ? void 0 : o.error) || (o == null ? void 0 : o.message) || `Request failed (${e.status})`
188
215
  );
189
- return s;
216
+ return o;
190
217
  }
191
- const h = (t) => t ? t.split("/").map((r) => r.trim()).filter(Boolean).join("/") : "", b = (t, r) => {
192
- const e = h(t), n = h(r);
218
+ const b = (t) => t ? t.split("/").map((r) => r.trim()).filter(Boolean).join("/") : "", E = (t, r) => {
219
+ const e = b(t), n = b(r);
193
220
  return e ? n ? `${e}/${n}` : e : n;
194
- }, E = (t, r) => {
221
+ }, S = (t, r) => {
195
222
  const e = { scope: t };
196
223
  return {
197
224
  async get() {
198
- const n = h(r);
199
- return $({ ...e, path: n || void 0 });
225
+ const n = b(r);
226
+ return k({ ...e, path: n || void 0 });
200
227
  },
201
228
  async set(n) {
202
- const s = h(r);
203
- return m("set", {
229
+ const o = b(r);
230
+ return p("set", {
204
231
  ...e,
205
- path: s || void 0,
232
+ path: o || void 0,
206
233
  value: n
207
234
  });
208
235
  },
209
236
  async update(n) {
210
237
  if (!n || typeof n != "object")
211
238
  throw new Error("update requires an object");
212
- const s = {};
213
- for (const [c, a] of Object.entries(n)) {
214
- const u = b(r, c);
215
- if (!u)
239
+ const o = {};
240
+ for (const [a, u] of Object.entries(n)) {
241
+ const i = E(r, a);
242
+ if (!i)
216
243
  throw new Error("update paths must be non-empty");
217
- s[u] = a;
244
+ o[i] = u;
218
245
  }
219
- return m("update", { ...e, updates: s });
246
+ return p("update", { ...e, updates: o });
220
247
  },
221
248
  async remove() {
222
- const n = h(r);
223
- return m("remove", { ...e, path: n || void 0 });
249
+ const n = b(r);
250
+ return p("remove", { ...e, path: n || void 0 });
224
251
  },
225
252
  async push(n) {
226
- const s = h(r);
227
- if (!s) throw new Error("push requires a path");
228
- return m("array-push", { ...e, path: s, value: n });
253
+ const o = b(r);
254
+ if (!o) throw new Error("push requires a path");
255
+ return p("array-push", { ...e, path: o, value: n });
229
256
  },
230
257
  ref(n) {
231
- const s = b(r, n);
232
- if (!s) throw new Error("ref requires a path");
233
- return E(t, s);
258
+ const o = E(r, n);
259
+ if (!o) throw new Error("ref requires a path");
260
+ return S(t, o);
234
261
  }
235
262
  };
236
263
  };
237
264
  return {
238
265
  isReady() {
239
- return !!p() && !!d();
266
+ return !!f() && !!l();
240
267
  },
241
268
  getBackendUrl() {
242
269
  var t;
243
- return ((t = p()) == null ? void 0 : t.backendUrl) ?? null;
270
+ return ((t = f()) == null ? void 0 : t.backendUrl) ?? null;
244
271
  },
245
272
  async models(t) {
246
273
  return y(t);
247
274
  },
248
275
  async chatCompletions(t) {
249
- var o;
276
+ var d;
250
277
  const {
251
278
  reasoningEffort: r,
252
279
  reasoning_effort: e,
253
280
  ...n
254
- } = t, s = r ?? e, c = {
281
+ } = t, o = r ?? e, a = {
255
282
  ...n,
256
283
  stream: !1
257
284
  };
258
- s && v(t.model) && (c.reasoning_effort = s);
259
- const a = await l("/openai/chat/completions", {
285
+ o && g(t.model) && (a.reasoning_effort = o);
286
+ const u = await c("/openai/chat/completions", {
260
287
  method: "POST",
261
288
  headers: { "Content-Type": "application/json" },
262
- body: JSON.stringify(c)
263
- }), g = (a.headers.get("content-type") || "").includes("application/json") ? await a.json() : await a.text();
264
- if (!a.ok)
289
+ body: JSON.stringify(a)
290
+ }), w = (u.headers.get("content-type") || "").includes("application/json") ? await u.json() : await u.text();
291
+ if (!u.ok)
265
292
  throw new Error(
266
- typeof g == "string" ? g : ((o = g == null ? void 0 : g.error) == null ? void 0 : o.message) || `Request failed (${a.status})`
293
+ typeof w == "string" ? w : ((d = w == null ? void 0 : w.error) == null ? void 0 : d.message) || `Request failed (${u.status})`
267
294
  );
268
- return g;
295
+ return w;
269
296
  },
270
297
  async chatText(t) {
271
- var e, n, s;
298
+ var e, n, o;
272
299
  const r = await this.chatCompletions(t);
273
- return ((s = (n = (e = r == null ? void 0 : r.choices) == null ? void 0 : e[0]) == null ? void 0 : n.message) == null ? void 0 : s.content) ?? "";
300
+ return ((o = (n = (e = r == null ? void 0 : r.choices) == null ? void 0 : e[0]) == null ? void 0 : n.message) == null ? void 0 : o.content) ?? "";
274
301
  },
275
302
  embeddings: {
276
303
  async create(t) {
277
- var s;
278
- const r = (s = t == null ? void 0 : t.model) == null ? void 0 : s.trim();
304
+ var o;
305
+ const r = (o = t == null ? void 0 : t.model) == null ? void 0 : o.trim();
279
306
  if (!r) throw new Error("embeddings.create requires a model");
280
307
  const e = t == null ? void 0 : t.input;
281
- if (!(typeof e == "string" ? e.length > 0 : Array.isArray(e) && e.length > 0 && e.every((c) => typeof c == "string")))
308
+ if (!(typeof e == "string" ? e.length > 0 : Array.isArray(e) && e.length > 0 && e.every((a) => typeof a == "string")))
282
309
  throw new Error(
283
310
  "embeddings.create requires input as a string or string[]"
284
311
  );
285
- return j("/openai/embeddings", {
312
+ return v("/openai/embeddings", {
286
313
  method: "POST",
287
314
  headers: { "Content-Type": "application/json" },
288
315
  body: JSON.stringify({
@@ -294,11 +321,26 @@ function _(p, d) {
294
321
  }
295
322
  },
296
323
  audio: {
324
+ async speechToken() {
325
+ const t = await c("/app-api/audio/speech-token", { method: "POST" });
326
+ if (!t.ok) throw new Error("Live talegenkendelse er ikke tilgængelig. Kontakt administratoren.");
327
+ return t.json();
328
+ },
329
+ async voiceLiveSession() {
330
+ const t = await c("/app-api/audio/voice-live-session", {
331
+ method: "POST"
332
+ });
333
+ if (!t.ok) {
334
+ const r = await t.text();
335
+ throw new Error(r || "Voice Live er ikke tilgængelig.");
336
+ }
337
+ return t.json();
338
+ },
297
339
  async tts(t) {
298
- var s;
299
- const r = (s = t == null ? void 0 : t.text) == null ? void 0 : s.trim();
340
+ var o;
341
+ const r = (o = t == null ? void 0 : t.text) == null ? void 0 : o.trim();
300
342
  if (!r) throw new Error("audio.tts requires non-empty text");
301
- const e = await l("/app-api/audio/tts", {
343
+ const e = await c("/app-api/audio/tts", {
302
344
  method: "POST",
303
345
  headers: { "Content-Type": "application/json" },
304
346
  body: JSON.stringify({
@@ -308,8 +350,8 @@ function _(p, d) {
308
350
  })
309
351
  });
310
352
  if (!e.ok) {
311
- const c = await e.text();
312
- throw new Error(c || `Request failed (${e.status})`);
353
+ const a = await e.text();
354
+ throw new Error(a || `Request failed (${e.status})`);
313
355
  }
314
356
  return {
315
357
  audio: await e.arrayBuffer(),
@@ -317,35 +359,38 @@ function _(p, d) {
317
359
  };
318
360
  },
319
361
  async stt(t) {
320
- var i, f, P;
362
+ var R, C, U, O;
321
363
  if (!(t != null && t.file)) throw new Error("audio.stt requires a file");
322
- const r = (R) => {
323
- if (!R) return;
324
- const C = R.trim();
325
- if (!C) return;
326
- const A = C.toLowerCase(), M = A.split("-")[0];
327
- return M.length === 2 ? M : A;
328
- }, e = typeof File < "u" && t.file instanceof File, n = e && t.file.name.split(".").pop() || "webm", s = t.ext || n, c = new FormData();
329
- e ? c.set("file", t.file) : c.set("file", t.file, `audio.${s}`);
330
- const a = r(t.language);
331
- a && c.set("language", a), t.prompt && c.set("prompt", t.prompt);
332
- const u = await l(
333
- `/app-api/audio/stt?ext=${encodeURIComponent(s)}`,
364
+ const r = (R = t.language) == null ? void 0 : R.trim(), e = (A) => {
365
+ if (!A) return;
366
+ const L = A.trim();
367
+ if (!L) return;
368
+ const M = L.toLowerCase(), N = M.split("-")[0];
369
+ return N.length === 2 ? N : M;
370
+ }, n = typeof File < "u" && t.file instanceof File, o = n && t.file.name.split(".").pop() || "webm", a = t.ext || o, u = new FormData();
371
+ n ? u.set("file", t.file) : u.set("file", t.file, `audio.${a}`);
372
+ const i = e(r);
373
+ i && u.set("language", i), t.prompt && u.set("prompt", t.prompt), t.responseFormat && u.set("response_format", t.responseFormat);
374
+ const w = new URLSearchParams({ ext: a });
375
+ r && w.set("locale", r);
376
+ const d = await c(
377
+ `/app-api/audio/stt?${w.toString()}`,
334
378
  {
335
379
  method: "POST",
336
- body: c
380
+ body: u
337
381
  }
338
- ), o = (u.headers.get("content-type") || "").includes("application/json") ? await u.json() : await u.text();
339
- if (!u.ok)
382
+ ), s = (d.headers.get("content-type") || "").includes("application/json") ? await d.json() : await d.text();
383
+ if (!d.ok)
340
384
  throw new Error(
341
- typeof o == "string" ? o : ((i = o == null ? void 0 : o.error) == null ? void 0 : i.message) || `Request failed (${u.status})`
385
+ typeof s == "string" ? s : ((C = s == null ? void 0 : s.error) == null ? void 0 : C.message) || `Request failed (${d.status})`
342
386
  );
343
- return { text: typeof o == "string" ? o : (o == null ? void 0 : o.text) || (o == null ? void 0 : o.original) || ((P = (f = o == null ? void 0 : o.results) == null ? void 0 : f[0]) == null ? void 0 : P.text) || "", raw: o };
387
+ const m = typeof s == "string" ? s : (s == null ? void 0 : s.text) || (s == null ? void 0 : s.original) || ((O = (U = s == null ? void 0 : s.results) == null ? void 0 : U[0]) == null ? void 0 : O.text) || "", I = typeof s == "object" && typeof (s == null ? void 0 : s.language) == "string" ? s.language : void 0;
388
+ return { text: m, language: I, raw: s };
344
389
  },
345
390
  async voices(t) {
346
391
  const r = new URLSearchParams();
347
392
  t != null && t.locale && r.set("locale", t.locale);
348
- const e = await l(
393
+ const e = await c(
349
394
  `/app-api/audio/tts/voices${r.toString() ? `?${r}` : ""}`,
350
395
  { method: "GET" }
351
396
  ), n = await e.json().catch(() => []);
@@ -361,7 +406,7 @@ function _(p, d) {
361
406
  var e;
362
407
  const r = (e = t == null ? void 0 : t.url) == null ? void 0 : e.trim();
363
408
  if (!r) throw new Error("web.scrapeUrl requires a url");
364
- return j(
409
+ return v(
365
410
  "/app-api/web/scrape-url",
366
411
  {
367
412
  method: "POST",
@@ -374,18 +419,63 @@ function _(p, d) {
374
419
  );
375
420
  }
376
421
  },
422
+ knowledge: {
423
+ async search(t) {
424
+ var e;
425
+ const r = (e = t == null ? void 0 : t.query) == null ? void 0 : e.trim();
426
+ if (!r) throw new Error("knowledge.search requires a query");
427
+ return v(
428
+ "/app-api/knowledge/search",
429
+ {
430
+ method: "POST",
431
+ headers: { "Content-Type": "application/json" },
432
+ body: JSON.stringify({
433
+ workspaceId: t.workspaceId,
434
+ query: r,
435
+ maxResults: t.maxResults,
436
+ generateSearchQuery: t.generateSearchQuery,
437
+ sourceId: t.sourceId,
438
+ includeSourceUrls: t.includeSourceUrls,
439
+ queries: t.queries
440
+ })
441
+ }
442
+ );
443
+ }
444
+ },
445
+ translatorLiveShare: {
446
+ async create(t) {
447
+ return v("/app-api/translator/live-share", {
448
+ method: "POST",
449
+ headers: { "Content-Type": "application/json" },
450
+ body: JSON.stringify({ displayLanguage: t })
451
+ });
452
+ },
453
+ async update(t, r) {
454
+ await v(`/app-api/translator/live-share/${encodeURIComponent(t)}`, {
455
+ method: "PUT",
456
+ headers: { "Content-Type": "application/json" },
457
+ body: JSON.stringify(r)
458
+ });
459
+ },
460
+ async revoke(t) {
461
+ await v(`/app-api/translator/live-share/${encodeURIComponent(t)}`, {
462
+ method: "DELETE"
463
+ });
464
+ }
465
+ },
377
466
  data(t = "private") {
378
- return E(t, "");
467
+ return S(t, "");
379
468
  }
380
469
  };
381
470
  }
382
471
  export {
383
- N as PromteAppProvider,
384
- S as usePromte,
385
- F as usePromteClient,
386
- V as usePromteDarkMode,
387
- K as usePromteModels,
388
- z as usePromteSettings,
389
- I as usePromteToken,
390
- W as usePromteUser
472
+ W as PromteAppProvider,
473
+ K as PromteNativeProvider,
474
+ j as usePromte,
475
+ G as usePromteClient,
476
+ X as usePromteDarkMode,
477
+ Z as usePromteModels,
478
+ Q as usePromteSettings,
479
+ H as usePromteToken,
480
+ Y as usePromteUser
391
481
  };
@@ -1 +1 @@
1
- (function(w,T){typeof exports=="object"&&typeof module<"u"?T(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],T):(w=typeof globalThis<"u"?globalThis:w||self,T(w.PromteAppLibrary={},w.jsxRuntime,w.react))})(this,function(w,T,a){"use strict";const M=a.createContext(null);function L({children:d,expectedParentOrigin:m,initTargetOrigin:E,retryInit:l={enabled:!0,intervalMs:500,maxAttempts:20}}){const[y,$]=a.useState(null),[v,j]=a.useState(null),[g,S]=a.useState(null),[P,t]=a.useState(null),[s,e]=a.useState(null),n=a.useMemo(()=>s?"booting":y?v?"ready":"waiting_for_token":"waiting_for_settings",[y,v,s]),r=n==="ready",c=a.useMemo(()=>E||m||"*",[E,m]),i=a.useCallback(()=>{var o;try{const h={type:"init"};(o=window.parent)==null||o.postMessage(h,c)}catch(h){e((h==null?void 0:h.message)||"Failed to post init")}},[c]);a.useEffect(()=>{i()},[i]),a.useEffect(()=>{if(!(l!=null&&l.enabled)||y)return;const o=l.intervalMs??500,h=l.maxAttempts??20;let u=0;const p=window.setInterval(()=>{if(y){window.clearInterval(p);return}if(u+=1,u>h){window.clearInterval(p);return}i()},o);return()=>window.clearInterval(p)},[l,y,i]),a.useEffect(()=>{const o=h=>{if(m&&h.origin!==m)return;const u=h.data;if(!(!u||typeof u!="object")){if(u.type==="set-settings"){const p=u.value;if(!(p!=null&&p.backendUrl)||p.parentOrigin&&m&&p.parentOrigin!==m)return;$(p),p!=null&&p.user&&t(p.user),e(null);return}if(u.type==="set-token"&&typeof u.value=="string"){j(u.value),e(null);return}if(u.type==="set-dark-mode"&&typeof u.value=="boolean"){S(u.value);return}if(u.type==="set-user"&&typeof u.value=="object"){t(u.value);return}}};return window.addEventListener("message",o),()=>window.removeEventListener("message",o)},[m]);const f=a.useMemo(()=>J(()=>y,()=>v),[y,v]),b=a.useMemo(()=>({settings:y,token:v,isDarkMode:g,user:P,ready:r,state:n,error:s,client:f}),[y,v,g,P,r,n,s,f]);return T.jsx(M.Provider,{value:b,children:d})}function k(){const d=a.useContext(M);if(!d)throw new Error("usePromte must be used inside <PromteAppProvider>");return d}function B(){return k().settings}function D(){return k().token}function F(){return k().isDarkMode}function _(){return k().user}function C(){return k().client}function G(d={}){const{ready:m}=k(),E=C(),[l,y]=a.useState([]),[$,v]=a.useState(!1),[j,g]=a.useState(null),S=a.useMemo(()=>(Array.isArray(d.type)?d.type:d.type?[d.type]:[]).filter(Boolean).map(n=>String(n)).join(","),[d.type]),P=d.configuredOnly===!0,t=d.auto!==!1,s=a.useCallback(async()=>{if(!m)return[];v(!0),g(null);try{const e=S?S.split(",").filter(Boolean):void 0,n=await E.models({type:e,configuredOnly:P});return y(n),n}catch(e){const n=e instanceof Error?e.message:String(e);throw g(n),e}finally{v(!1)}},[E,P,m,S]);return a.useEffect(()=>{!t||!m||s().catch(()=>{})},[t,m,s]),{models:l,loading:$,error:j,reload:s}}function J(d,m){const E=t=>typeof t=="string"&&t.startsWith("gpt-5");async function l(t,s){const e=d(),n=m();if(!e)throw new Error("Promte settings not received yet");if(!n)throw new Error("Promte token not received yet");const r=e.backendUrl.replace(/\/+$/,""),c=String(t||"").replace(/^\/+/,""),i=`${r}/${c}`;return await fetch(i,{...s,headers:{...s.headers||{},Authorization:`Bearer ${n}`}})}async function y(t,s){const e=await l(`/app-api/data/${t}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)}),n=await e.json().catch(()=>({}));if(!e.ok)throw new Error((n==null?void 0:n.error)||`Request failed (${e.status})`);return n==null?void 0:n.value}async function $(t){const s=new URLSearchParams;t.scope&&s.set("scope",t.scope),t.path&&s.set("path",t.path);const e=await l(`/app-api/data?${s.toString()}`,{method:"GET"}),n=await e.json().catch(()=>({}));if(!e.ok)throw new Error((n==null?void 0:n.error)||`Request failed (${e.status})`);return n==null?void 0:n.value}async function v(t){const s=new URLSearchParams,e=Array.isArray(t==null?void 0:t.type)?t==null?void 0:t.type:t!=null&&t.type?[t.type]:[];e.length>0&&s.set("type",e.join(",")),t!=null&&t.configuredOnly&&s.set("configuredOnly","true");const n=await l(`/app-api/models${s.toString()?`?${s.toString()}`:""}`,{method:"GET"}),r=await n.json().catch(()=>({}));if(!n.ok)throw new Error((r==null?void 0:r.error)||`Request failed (${n.status})`);return(Array.isArray(r==null?void 0:r.models)?r.models:[]).map(i=>{if(!i||typeof i!="object")return null;const f=typeof i.id=="string"?i.id.trim():"",b=typeof i.label=="string"?i.label.trim():f,o=i.type,h=i.configured===!0,u=typeof i.source=="string"&&i.source.trim()?i.source.trim():void 0;return!f||o!=="llm"&&o!=="embedding"&&o!=="image"&&o!=="stt"&&o!=="tts"?null:{id:f,label:b||f,type:o,configured:h,source:u}}).filter(i=>!!i)}async function j(t,s){const e=await l(t,s),r=(e.headers.get("content-type")||"").includes("application/json")?await e.json().catch(()=>({})):await e.text();if(!e.ok)throw new Error(typeof r=="string"?r||`Request failed (${e.status})`:(r==null?void 0:r.error)||(r==null?void 0:r.message)||`Request failed (${e.status})`);return r}const g=t=>t?t.split("/").map(s=>s.trim()).filter(Boolean).join("/"):"",S=(t,s)=>{const e=g(t),n=g(s);return e?n?`${e}/${n}`:e:n},P=(t,s)=>{const e={scope:t};return{async get(){const n=g(s);return $({...e,path:n||void 0})},async set(n){const r=g(s);return y("set",{...e,path:r||void 0,value:n})},async update(n){if(!n||typeof n!="object")throw new Error("update requires an object");const r={};for(const[c,i]of Object.entries(n)){const f=S(s,c);if(!f)throw new Error("update paths must be non-empty");r[f]=i}return y("update",{...e,updates:r})},async remove(){const n=g(s);return y("remove",{...e,path:n||void 0})},async push(n){const r=g(s);if(!r)throw new Error("push requires a path");return y("array-push",{...e,path:r,value:n})},ref(n){const r=S(s,n);if(!r)throw new Error("ref requires a path");return P(t,r)}}};return{isReady(){return!!d()&&!!m()},getBackendUrl(){var t;return((t=d())==null?void 0:t.backendUrl)??null},async models(t){return v(t)},async chatCompletions(t){var o;const{reasoningEffort:s,reasoning_effort:e,...n}=t,r=s??e,c={...n,stream:!1};r&&E(t.model)&&(c.reasoning_effort=r);const i=await l("/openai/chat/completions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)}),b=(i.headers.get("content-type")||"").includes("application/json")?await i.json():await i.text();if(!i.ok)throw new Error(typeof b=="string"?b:((o=b==null?void 0:b.error)==null?void 0:o.message)||`Request failed (${i.status})`);return b},async chatText(t){var e,n,r;const s=await this.chatCompletions(t);return((r=(n=(e=s==null?void 0:s.choices)==null?void 0:e[0])==null?void 0:n.message)==null?void 0:r.content)??""},embeddings:{async create(t){var r;const s=(r=t==null?void 0:t.model)==null?void 0:r.trim();if(!s)throw new Error("embeddings.create requires a model");const e=t==null?void 0:t.input;if(!(typeof e=="string"?e.length>0:Array.isArray(e)&&e.length>0&&e.every(c=>typeof c=="string")))throw new Error("embeddings.create requires input as a string or string[]");return j("/openai/embeddings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...t,model:s,input:e})})}},audio:{async tts(t){var r;const s=(r=t==null?void 0:t.text)==null?void 0:r.trim();if(!s)throw new Error("audio.tts requires non-empty text");const e=await l("/app-api/audio/tts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:s,voice:t.voice,lang:t.lang})});if(!e.ok){const c=await e.text();throw new Error(c||`Request failed (${e.status})`)}return{audio:await e.arrayBuffer(),contentType:e.headers.get("content-type")}},async stt(t){var u,p,R;if(!(t!=null&&t.file))throw new Error("audio.stt requires a file");const s=x=>{if(!x)return;const A=x.trim();if(!A)return;const U=A.toLowerCase(),O=U.split("-")[0];return O.length===2?O:U},e=typeof File<"u"&&t.file instanceof File,n=e&&t.file.name.split(".").pop()||"webm",r=t.ext||n,c=new FormData;e?c.set("file",t.file):c.set("file",t.file,`audio.${r}`);const i=s(t.language);i&&c.set("language",i),t.prompt&&c.set("prompt",t.prompt);const f=await l(`/app-api/audio/stt?ext=${encodeURIComponent(r)}`,{method:"POST",body:c}),o=(f.headers.get("content-type")||"").includes("application/json")?await f.json():await f.text();if(!f.ok)throw new Error(typeof o=="string"?o:((u=o==null?void 0:o.error)==null?void 0:u.message)||`Request failed (${f.status})`);return{text:typeof o=="string"?o:(o==null?void 0:o.text)||(o==null?void 0:o.original)||((R=(p=o==null?void 0:o.results)==null?void 0:p[0])==null?void 0:R.text)||"",raw:o}},async voices(t){const s=new URLSearchParams;t!=null&&t.locale&&s.set("locale",t.locale);const e=await l(`/app-api/audio/tts/voices${s.toString()?`?${s}`:""}`,{method:"GET"}),n=await e.json().catch(()=>[]);if(!e.ok)throw new Error((n==null?void 0:n.error)||`Request failed (${e.status})`);return Array.isArray(n)?n:(n==null?void 0:n.voices)||[]}},web:{async scrapeUrl(t){var e;const s=(e=t==null?void 0:t.url)==null?void 0:e.trim();if(!s)throw new Error("web.scrapeUrl requires a url");return j("/app-api/web/scrape-url",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:s,maxChars:t.maxChars})})}},data(t="private"){return P(t,"")}}}w.PromteAppProvider=L,w.usePromte=k,w.usePromteClient=C,w.usePromteDarkMode=F,w.usePromteModels=G,w.usePromteSettings=B,w.usePromteToken=D,w.usePromteUser=_,Object.defineProperty(w,Symbol.toStringTag,{value:"Module"})});
1
+ (function(w,$){typeof exports=="object"&&typeof module<"u"?$(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],$):(w=typeof globalThis<"u"?globalThis:w||self,$(w.PromteAppLibrary={},w.jsxRuntime,w.react))})(this,function(w,$,u){"use strict";const C=u.createContext(null);function D({children:d,expectedParentOrigin:f,initTargetOrigin:S,retryInit:c={enabled:!0,intervalMs:500,maxAttempts:20}}){const[p,k]=u.useState(null),[v,P]=u.useState(null),[b,E]=u.useState(null),[T,e]=u.useState(null),[r,t]=u.useState(null),n=u.useMemo(()=>r?"booting":p?v?"ready":"waiting_for_token":"waiting_for_settings",[p,v,r]),o=n==="ready",a=u.useMemo(()=>S||f||"*",[S,f]),l=u.useCallback(()=>{var m;try{const h={type:"init"};(m=window.parent)==null||m.postMessage(h,a)}catch(h){t((h==null?void 0:h.message)||"Failed to post init")}},[a]);u.useEffect(()=>{l()},[l]),u.useEffect(()=>{if(!(c!=null&&c.enabled)||p)return;const m=c.intervalMs??500,h=c.maxAttempts??20;let s=0;const y=window.setInterval(()=>{if(p){window.clearInterval(y);return}if(s+=1,s>h){window.clearInterval(y);return}l()},m);return()=>window.clearInterval(y)},[c,p,l]),u.useEffect(()=>{const m=h=>{if(f&&h.origin!==f)return;const s=h.data;if(!(!s||typeof s!="object")){if(s.type==="set-settings"){const y=s.value;if(!(y!=null&&y.backendUrl)||y.parentOrigin&&f&&y.parentOrigin!==f)return;k(y),y!=null&&y.user&&e(y.user),t(null);return}if(s.type==="set-token"&&typeof s.value=="string"){P(s.value),t(null);return}if(s.type==="set-dark-mode"&&typeof s.value=="boolean"){E(s.value);return}if(s.type==="set-user"&&typeof s.value=="object"){e(s.value);return}}};return window.addEventListener("message",m),()=>window.removeEventListener("message",m)},[f]);const i=u.useMemo(()=>M(()=>p,()=>v),[p,v]),g=u.useMemo(()=>({settings:p,token:v,isDarkMode:b,user:T,ready:o,state:n,error:r,client:i}),[p,v,b,T,o,n,r,i]);return $.jsx(C.Provider,{value:g,children:d})}function F({children:d,settings:f,token:S,isDarkMode:c,user:p}){const k=u.useMemo(()=>M(()=>f,()=>S),[f,S]),v=!!S,P=u.useMemo(()=>({settings:f,token:S,isDarkMode:c,user:p,ready:v,state:v?"ready":"waiting_for_token",error:null,client:k}),[k,c,v,f,S,p]);return $.jsx(C.Provider,{value:P,children:d})}function j(){const d=u.useContext(C);if(!d)throw new Error("usePromte must be used inside <PromteAppProvider> or <PromteNativeProvider>");return d}function I(){return j().settings}function J(){return j().token}function G(){return j().isDarkMode}function V(){return j().user}function R(){return j().client}function z(d={}){const{ready:f}=j(),S=R(),[c,p]=u.useState([]),[k,v]=u.useState(!1),[P,b]=u.useState(null),E=u.useMemo(()=>(Array.isArray(d.type)?d.type:d.type?[d.type]:[]).filter(Boolean).map(n=>String(n)).join(","),[d.type]),T=d.configuredOnly===!0,e=d.auto!==!1,r=u.useCallback(async()=>{if(!f)return[];v(!0),b(null);try{const t=E?E.split(",").filter(Boolean):void 0,n=await S.models({type:t,configuredOnly:T});return p(n),n}catch(t){const n=t instanceof Error?t.message:String(t);throw b(n),t}finally{v(!1)}},[S,T,f,E]);return u.useEffect(()=>{!e||!f||r().catch(()=>{})},[e,f,r]),{models:c,loading:k,error:P,reload:r}}function M(d,f){const S=e=>typeof e=="string"&&(e.startsWith("gpt-5")||e.startsWith("gpt-6"));async function c(e,r){const t=d(),n=f();if(!t)throw new Error("Promte settings not received yet");if(!n)throw new Error("Promte token not received yet");const o=t.backendUrl.replace(/\/+$/,""),a=String(e||"").replace(/^\/+/,""),l=`${o}/${a}`;return await fetch(l,{...r,headers:{...r.headers||{},Authorization:`Bearer ${n}`}})}async function p(e,r){const t=await c(`/app-api/data/${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)}),n=await t.json().catch(()=>({}));if(!t.ok)throw new Error((n==null?void 0:n.error)||`Request failed (${t.status})`);return n==null?void 0:n.value}async function k(e){const r=new URLSearchParams;e.scope&&r.set("scope",e.scope),e.path&&r.set("path",e.path);const t=await c(`/app-api/data?${r.toString()}`,{method:"GET"}),n=await t.json().catch(()=>({}));if(!t.ok)throw new Error((n==null?void 0:n.error)||`Request failed (${t.status})`);return n==null?void 0:n.value}async function v(e){const r=new URLSearchParams,t=e==null?void 0:e.type,n=Array.isArray(t)?t:t?[t]:[];n.length>0&&r.set("type",n.join(",")),e!=null&&e.configuredOnly&&r.set("configuredOnly","true");const o=await c(`/app-api/models${r.toString()?`?${r.toString()}`:""}`,{method:"GET"}),a=await o.json().catch(()=>({}));if(!o.ok)throw new Error((a==null?void 0:a.error)||`Request failed (${o.status})`);return(Array.isArray(a==null?void 0:a.models)?a.models:[]).map(i=>{if(!i||typeof i!="object")return null;const g=typeof i.id=="string"?i.id.trim():"",m=typeof i.label=="string"?i.label.trim():g,h=i.type,s=i.configured===!0,y=typeof i.source=="string"&&i.source.trim()?i.source.trim():void 0;return!g||h!=="llm"&&h!=="embedding"&&h!=="image"&&h!=="stt"&&h!=="tts"?null:{id:g,label:m||g,type:h,configured:s,source:y}}).filter(i=>!!i)}async function P(e,r){const t=await c(e,r),o=(t.headers.get("content-type")||"").includes("application/json")?await t.json().catch(()=>({})):await t.text();if(!t.ok)throw new Error(typeof o=="string"?o||`Request failed (${t.status})`:(o==null?void 0:o.error)||(o==null?void 0:o.message)||`Request failed (${t.status})`);return o}const b=e=>e?e.split("/").map(r=>r.trim()).filter(Boolean).join("/"):"",E=(e,r)=>{const t=b(e),n=b(r);return t?n?`${t}/${n}`:t:n},T=(e,r)=>{const t={scope:e};return{async get(){const n=b(r);return k({...t,path:n||void 0})},async set(n){const o=b(r);return p("set",{...t,path:o||void 0,value:n})},async update(n){if(!n||typeof n!="object")throw new Error("update requires an object");const o={};for(const[a,l]of Object.entries(n)){const i=E(r,a);if(!i)throw new Error("update paths must be non-empty");o[i]=l}return p("update",{...t,updates:o})},async remove(){const n=b(r);return p("remove",{...t,path:n||void 0})},async push(n){const o=b(r);if(!o)throw new Error("push requires a path");return p("array-push",{...t,path:o,value:n})},ref(n){const o=E(r,n);if(!o)throw new Error("ref requires a path");return T(e,o)}}};return{isReady(){return!!d()&&!!f()},getBackendUrl(){var e;return((e=d())==null?void 0:e.backendUrl)??null},async models(e){return v(e)},async chatCompletions(e){var m;const{reasoningEffort:r,reasoning_effort:t,...n}=e,o=r??t,a={...n,stream:!1};o&&S(e.model)&&(a.reasoning_effort=o);const l=await c("/openai/chat/completions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}),g=(l.headers.get("content-type")||"").includes("application/json")?await l.json():await l.text();if(!l.ok)throw new Error(typeof g=="string"?g:((m=g==null?void 0:g.error)==null?void 0:m.message)||`Request failed (${l.status})`);return g},async chatText(e){var t,n,o;const r=await this.chatCompletions(e);return((o=(n=(t=r==null?void 0:r.choices)==null?void 0:t[0])==null?void 0:n.message)==null?void 0:o.content)??""},embeddings:{async create(e){var o;const r=(o=e==null?void 0:e.model)==null?void 0:o.trim();if(!r)throw new Error("embeddings.create requires a model");const t=e==null?void 0:e.input;if(!(typeof t=="string"?t.length>0:Array.isArray(t)&&t.length>0&&t.every(a=>typeof a=="string")))throw new Error("embeddings.create requires input as a string or string[]");return P("/openai/embeddings",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...e,model:r,input:t})})}},audio:{async speechToken(){const e=await c("/app-api/audio/speech-token",{method:"POST"});if(!e.ok)throw new Error("Live talegenkendelse er ikke tilgængelig. Kontakt administratoren.");return e.json()},async voiceLiveSession(){const e=await c("/app-api/audio/voice-live-session",{method:"POST"});if(!e.ok){const r=await e.text();throw new Error(r||"Voice Live er ikke tilgængelig.")}return e.json()},async tts(e){var o;const r=(o=e==null?void 0:e.text)==null?void 0:o.trim();if(!r)throw new Error("audio.tts requires non-empty text");const t=await c("/app-api/audio/tts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:r,voice:e.voice,lang:e.lang})});if(!t.ok){const a=await t.text();throw new Error(a||`Request failed (${t.status})`)}return{audio:await t.arrayBuffer(),contentType:t.headers.get("content-type")}},async stt(e){var x,U,A,O;if(!(e!=null&&e.file))throw new Error("audio.stt requires a file");const r=(x=e.language)==null?void 0:x.trim(),t=L=>{if(!L)return;const N=L.trim();if(!N)return;const B=N.toLowerCase(),_=B.split("-")[0];return _.length===2?_:B},n=typeof File<"u"&&e.file instanceof File,o=n&&e.file.name.split(".").pop()||"webm",a=e.ext||o,l=new FormData;n?l.set("file",e.file):l.set("file",e.file,`audio.${a}`);const i=t(r);i&&l.set("language",i),e.prompt&&l.set("prompt",e.prompt),e.responseFormat&&l.set("response_format",e.responseFormat);const g=new URLSearchParams({ext:a});r&&g.set("locale",r);const m=await c(`/app-api/audio/stt?${g.toString()}`,{method:"POST",body:l}),s=(m.headers.get("content-type")||"").includes("application/json")?await m.json():await m.text();if(!m.ok)throw new Error(typeof s=="string"?s:((U=s==null?void 0:s.error)==null?void 0:U.message)||`Request failed (${m.status})`);const y=typeof s=="string"?s:(s==null?void 0:s.text)||(s==null?void 0:s.original)||((O=(A=s==null?void 0:s.results)==null?void 0:A[0])==null?void 0:O.text)||"",W=typeof s=="object"&&typeof(s==null?void 0:s.language)=="string"?s.language:void 0;return{text:y,language:W,raw:s}},async voices(e){const r=new URLSearchParams;e!=null&&e.locale&&r.set("locale",e.locale);const t=await c(`/app-api/audio/tts/voices${r.toString()?`?${r}`:""}`,{method:"GET"}),n=await t.json().catch(()=>[]);if(!t.ok)throw new Error((n==null?void 0:n.error)||`Request failed (${t.status})`);return Array.isArray(n)?n:(n==null?void 0:n.voices)||[]}},web:{async scrapeUrl(e){var t;const r=(t=e==null?void 0:e.url)==null?void 0:t.trim();if(!r)throw new Error("web.scrapeUrl requires a url");return P("/app-api/web/scrape-url",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:r,maxChars:e.maxChars})})}},knowledge:{async search(e){var t;const r=(t=e==null?void 0:e.query)==null?void 0:t.trim();if(!r)throw new Error("knowledge.search requires a query");return P("/app-api/knowledge/search",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({workspaceId:e.workspaceId,query:r,maxResults:e.maxResults,generateSearchQuery:e.generateSearchQuery,sourceId:e.sourceId,includeSourceUrls:e.includeSourceUrls,queries:e.queries})})}},translatorLiveShare:{async create(e){return P("/app-api/translator/live-share",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({displayLanguage:e})})},async update(e,r){await P(`/app-api/translator/live-share/${encodeURIComponent(e)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)})},async revoke(e){await P(`/app-api/translator/live-share/${encodeURIComponent(e)}`,{method:"DELETE"})}},data(e="private"){return T(e,"")}}}w.PromteAppProvider=D,w.PromteNativeProvider=F,w.usePromte=j,w.usePromteClient=R,w.usePromteDarkMode=G,w.usePromteModels=z,w.usePromteSettings=I,w.usePromteToken=J,w.usePromteUser=V,Object.defineProperty(w,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promte/app-library",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "files": [