@promte/app-library 0.1.2 → 0.1.4
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 +109 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.mjs +256 -184
- package/dist/index.umd.cjs +1 -1
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# @promte/app-library
|
|
2
|
+
|
|
3
|
+
Docs for using the app DB API in embedded apps.
|
|
4
|
+
|
|
5
|
+
## What "DB" means here
|
|
6
|
+
|
|
7
|
+
In this library, DB access is exposed as:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
const client = usePromteClient();
|
|
11
|
+
const db = client.data(); // default scope: "private"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Scopes
|
|
15
|
+
|
|
16
|
+
- `private` (default): data is scoped per user.
|
|
17
|
+
- `public`: shared for the whole workspace.
|
|
18
|
+
- Reads are allowed for users with workspace access.
|
|
19
|
+
- Writes (`set`, `update`, `remove`, `push`) require workspace admin/owner.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
const privateDb = client.data(); // same as client.data("private")
|
|
23
|
+
const publicDb = client.data("public");
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Paths and refs
|
|
27
|
+
|
|
28
|
+
Use slash-separated paths:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
const settingsRef = client.data("public").ref("translator/settings");
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Path normalization trims spaces and removes extra slashes, so `" /a//b/ "` becomes `"a/b"`.
|
|
35
|
+
|
|
36
|
+
## Core operations
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// Read
|
|
40
|
+
const settings = await client.data("public").ref("translator/settings").get();
|
|
41
|
+
|
|
42
|
+
// Set/replace value at path
|
|
43
|
+
await client.data("public").ref("translator/settings").set({
|
|
44
|
+
temperature: 0.2,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Update multiple child paths relative to current ref
|
|
48
|
+
await client.data("public").ref("translator").update({
|
|
49
|
+
"settings/temperature": 0.3,
|
|
50
|
+
"features/context": true,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Remove path
|
|
54
|
+
await client.data("public").ref("translator/features").remove();
|
|
55
|
+
|
|
56
|
+
// Push into array at path (creates array if missing/not array)
|
|
57
|
+
await client.data().ref("sessions/session-1/events").push({
|
|
58
|
+
type: "message",
|
|
59
|
+
at: Date.now(),
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Models/capabilities
|
|
64
|
+
|
|
65
|
+
You can fetch configured models/capabilities from backend:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
const client = usePromteClient();
|
|
69
|
+
const allModels = await client.models();
|
|
70
|
+
const llmsOnly = await client.models({ type: "llm", configuredOnly: true });
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Or use the built-in hook:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const { models, loading, error, reload } = usePromteModels({
|
|
77
|
+
type: "llm",
|
|
78
|
+
configuredOnly: true,
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Each model includes `id`, `label`, `type` (`llm` | `embedding` | `image` | `stt` | `tts`) and `configured`.
|
|
83
|
+
|
|
84
|
+
## Return behavior
|
|
85
|
+
|
|
86
|
+
- `get()` returns the value at the current path, or `null` if missing.
|
|
87
|
+
- Mutations (`set`, `update`, `remove`, `push`) return the updated scope object.
|
|
88
|
+
|
|
89
|
+
## Common patterns
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
// Save one record by id
|
|
93
|
+
await client.data().ref(`sessions/${sessionId}`).set(session);
|
|
94
|
+
|
|
95
|
+
// List records under a collection-like object
|
|
96
|
+
const sessionsObj = await client.data().ref("sessions").get();
|
|
97
|
+
const sessions = sessionsObj ? Object.values(sessionsObj) : [];
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Errors to expect
|
|
101
|
+
|
|
102
|
+
- `Promte settings not received yet` / `Promte token not received yet`:
|
|
103
|
+
provider handshake not ready.
|
|
104
|
+
- `Admin only`:
|
|
105
|
+
trying to write to `public` scope without admin rights.
|
|
106
|
+
- `update requires an object`:
|
|
107
|
+
`ref.update(...)` got a non-object input.
|
|
108
|
+
- `push requires a path`:
|
|
109
|
+
attempted `client.data().push(...)` without a ref path.
|
package/dist/index.d.ts
CHANGED
|
@@ -89,6 +89,7 @@ export declare type PromteAppProviderProps = {
|
|
|
89
89
|
export declare type PromteClient = {
|
|
90
90
|
isReady(): boolean;
|
|
91
91
|
getBackendUrl(): string | null;
|
|
92
|
+
models(req?: PromteModelsRequest): Promise<PromteModelInfo[]>;
|
|
92
93
|
chatCompletions(req: ChatCompletionsRequest): Promise<ChatCompletionsResponse>;
|
|
93
94
|
chatText(req: ChatCompletionsRequest): Promise<string>;
|
|
94
95
|
audio: {
|
|
@@ -96,6 +97,9 @@ export declare type PromteClient = {
|
|
|
96
97
|
stt(req: AudioSttRequest): Promise<AudioSttResponse>;
|
|
97
98
|
voices(req?: AudioVoicesRequest): Promise<AudioVoiceInfo[]>;
|
|
98
99
|
};
|
|
100
|
+
web: {
|
|
101
|
+
scrapeUrl(req: ScrapeUrlRequest): Promise<ScrapeUrlResponse>;
|
|
102
|
+
};
|
|
99
103
|
data(scope?: AppDataScope): AppDataRef;
|
|
100
104
|
};
|
|
101
105
|
|
|
@@ -112,6 +116,21 @@ declare type PromteCtxValue = {
|
|
|
112
116
|
|
|
113
117
|
export declare type PromteHandshakeState = "booting" | "waiting_for_settings" | "waiting_for_token" | "ready";
|
|
114
118
|
|
|
119
|
+
export declare type PromteModelInfo = {
|
|
120
|
+
id: string;
|
|
121
|
+
label: string;
|
|
122
|
+
type: PromteModelType;
|
|
123
|
+
configured: boolean;
|
|
124
|
+
source?: string;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export declare type PromteModelsRequest = {
|
|
128
|
+
type?: PromteModelType | PromteModelType[];
|
|
129
|
+
configuredOnly?: boolean;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export declare type PromteModelType = "llm" | "embedding" | "image" | "stt" | "tts";
|
|
133
|
+
|
|
115
134
|
export declare type PromteSettings = {
|
|
116
135
|
workspaceId: string;
|
|
117
136
|
version: number;
|
|
@@ -129,12 +148,46 @@ export declare type PromteUser = {
|
|
|
129
148
|
|
|
130
149
|
export declare type ReasoningEffort = "minimal" | "low" | "medium" | "high";
|
|
131
150
|
|
|
151
|
+
export declare type ScrapeUrlRequest = {
|
|
152
|
+
url: string;
|
|
153
|
+
maxChars?: number;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export declare type ScrapeUrlResponse = {
|
|
157
|
+
requestedUrl: string;
|
|
158
|
+
url: string;
|
|
159
|
+
label: string;
|
|
160
|
+
text: string;
|
|
161
|
+
title?: string;
|
|
162
|
+
status?: number;
|
|
163
|
+
extractor?: string;
|
|
164
|
+
warning?: string;
|
|
165
|
+
cached?: boolean;
|
|
166
|
+
fallback?: {
|
|
167
|
+
provider?: string;
|
|
168
|
+
enabled?: boolean;
|
|
169
|
+
attempted?: boolean;
|
|
170
|
+
used?: boolean;
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
|
|
132
174
|
export declare function usePromte(): PromteCtxValue;
|
|
133
175
|
|
|
134
176
|
export declare function usePromteClient(): PromteClient;
|
|
135
177
|
|
|
136
178
|
export declare function usePromteDarkMode(): boolean;
|
|
137
179
|
|
|
180
|
+
export declare function usePromteModels(options?: UsePromteModelsOptions): {
|
|
181
|
+
models: PromteModelInfo[];
|
|
182
|
+
loading: boolean;
|
|
183
|
+
error: string;
|
|
184
|
+
reload: () => Promise<PromteModelInfo[]>;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export declare type UsePromteModelsOptions = PromteModelsRequest & {
|
|
188
|
+
auto?: boolean;
|
|
189
|
+
};
|
|
190
|
+
|
|
138
191
|
export declare function usePromteSettings(): PromteSettings;
|
|
139
192
|
|
|
140
193
|
export declare function usePromteToken(): string;
|
package/dist/index.mjs
CHANGED
|
@@ -1,298 +1,370 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { createContext as
|
|
3
|
-
const
|
|
4
|
-
function
|
|
5
|
-
children:
|
|
6
|
-
expectedParentOrigin:
|
|
1
|
+
import { jsx as L } from "react/jsx-runtime";
|
|
2
|
+
import { createContext as O, useState as k, useMemo as S, useCallback as U, useEffect as P, useContext as D } from "react";
|
|
3
|
+
const B = O(null);
|
|
4
|
+
function N({
|
|
5
|
+
children: p,
|
|
6
|
+
expectedParentOrigin: d,
|
|
7
7
|
initTargetOrigin: v,
|
|
8
|
-
retryInit:
|
|
8
|
+
retryInit: l = { enabled: !0, intervalMs: 500, maxAttempts: 20 }
|
|
9
9
|
}) {
|
|
10
|
-
const [
|
|
11
|
-
var
|
|
10
|
+
const [m, $] = k(null), [y, x] = k(null), [h, E] = k(null), [b, t] = k(null), [r, n] = k(null), e = S(() => r ? "booting" : m ? y ? "ready" : "waiting_for_token" : "waiting_for_settings", [m, y, r]), s = e === "ready", c = S(() => v || d || "*", [v, d]), a = U(() => {
|
|
11
|
+
var o;
|
|
12
12
|
try {
|
|
13
|
-
const
|
|
14
|
-
(
|
|
15
|
-
} catch (
|
|
16
|
-
|
|
13
|
+
const w = { type: "init" };
|
|
14
|
+
(o = window.parent) == null || o.postMessage(w, c);
|
|
15
|
+
} catch (w) {
|
|
16
|
+
n((w == null ? void 0 : w.message) || "Failed to post init");
|
|
17
17
|
}
|
|
18
|
-
}, [
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}, [
|
|
22
|
-
if (!(
|
|
23
|
-
const
|
|
24
|
-
let
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
27
|
-
window.clearInterval(
|
|
18
|
+
}, [c]);
|
|
19
|
+
P(() => {
|
|
20
|
+
a();
|
|
21
|
+
}, [a]), P(() => {
|
|
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);
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
|
-
if (
|
|
31
|
-
window.clearInterval(
|
|
30
|
+
if (i += 1, i > w) {
|
|
31
|
+
window.clearInterval(f);
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
-
|
|
35
|
-
},
|
|
36
|
-
return () => window.clearInterval(
|
|
37
|
-
}, [
|
|
38
|
-
const
|
|
39
|
-
if (
|
|
40
|
-
const
|
|
41
|
-
if (!(!
|
|
42
|
-
if (
|
|
43
|
-
const
|
|
44
|
-
if (!(
|
|
34
|
+
a();
|
|
35
|
+
}, o);
|
|
36
|
+
return () => window.clearInterval(f);
|
|
37
|
+
}, [l, m, a]), P(() => {
|
|
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)
|
|
45
45
|
return;
|
|
46
|
-
|
|
46
|
+
$(f), f != null && f.user && t(f.user), n(null);
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
|
-
if (
|
|
50
|
-
x(
|
|
49
|
+
if (i.type === "set-token" && typeof i.value == "string") {
|
|
50
|
+
x(i.value), n(null);
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
|
-
if (
|
|
54
|
-
|
|
53
|
+
if (i.type === "set-dark-mode" && typeof i.value == "boolean") {
|
|
54
|
+
E(i.value);
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
|
-
if (
|
|
58
|
-
|
|
57
|
+
if (i.type === "set-user" && typeof i.value == "object") {
|
|
58
|
+
t(i.value);
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
|
-
return window.addEventListener("message",
|
|
64
|
-
}, [
|
|
65
|
-
const
|
|
66
|
-
() =>
|
|
67
|
-
() =>
|
|
68
|
-
), [
|
|
63
|
+
return window.addEventListener("message", o), () => window.removeEventListener("message", o);
|
|
64
|
+
}, [d]);
|
|
65
|
+
const u = S(() => _(
|
|
66
|
+
() => m,
|
|
67
|
+
() => y
|
|
68
|
+
), [m, y]), g = S(
|
|
69
69
|
() => ({
|
|
70
|
-
settings:
|
|
71
|
-
token:
|
|
72
|
-
isDarkMode:
|
|
73
|
-
user:
|
|
74
|
-
ready:
|
|
75
|
-
state:
|
|
76
|
-
error:
|
|
77
|
-
client:
|
|
70
|
+
settings: m,
|
|
71
|
+
token: y,
|
|
72
|
+
isDarkMode: h,
|
|
73
|
+
user: b,
|
|
74
|
+
ready: s,
|
|
75
|
+
state: e,
|
|
76
|
+
error: r,
|
|
77
|
+
client: u
|
|
78
78
|
}),
|
|
79
|
-
[
|
|
79
|
+
[m, y, h, b, s, e, r, u]
|
|
80
80
|
);
|
|
81
|
-
return /* @__PURE__ */
|
|
81
|
+
return /* @__PURE__ */ L(B.Provider, { value: g, children: p });
|
|
82
82
|
}
|
|
83
|
-
function
|
|
84
|
-
const
|
|
85
|
-
if (!
|
|
83
|
+
function j() {
|
|
84
|
+
const p = D(B);
|
|
85
|
+
if (!p)
|
|
86
86
|
throw new Error("usePromte must be used inside <PromteAppProvider>");
|
|
87
|
-
return
|
|
87
|
+
return p;
|
|
88
88
|
}
|
|
89
|
-
function
|
|
90
|
-
return
|
|
89
|
+
function z() {
|
|
90
|
+
return j().settings;
|
|
91
91
|
}
|
|
92
|
-
function
|
|
93
|
-
return
|
|
92
|
+
function V() {
|
|
93
|
+
return j().token;
|
|
94
94
|
}
|
|
95
|
-
function
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
function O() {
|
|
99
|
-
return b().user;
|
|
95
|
+
function W() {
|
|
96
|
+
return j().isDarkMode;
|
|
100
97
|
}
|
|
101
98
|
function I() {
|
|
102
|
-
return
|
|
99
|
+
return j().user;
|
|
100
|
+
}
|
|
101
|
+
function F() {
|
|
102
|
+
return j().client;
|
|
103
|
+
}
|
|
104
|
+
function K(p = {}) {
|
|
105
|
+
const { ready: d } = j(), v = F(), [l, m] = k([]), [$, y] = k(!1), [x, h] = k(null), E = S(() => (Array.isArray(p.type) ? p.type : p.type ? [p.type] : []).filter(Boolean).map((e) => String(e)).join(","), [p.type]), b = p.configuredOnly === !0, t = p.auto !== !1, r = U(async () => {
|
|
106
|
+
if (!d) return [];
|
|
107
|
+
y(!0), h(null);
|
|
108
|
+
try {
|
|
109
|
+
const n = E ? E.split(",").filter(Boolean) : void 0, e = await v.models({ type: n, configuredOnly: b });
|
|
110
|
+
return m(e), e;
|
|
111
|
+
} catch (n) {
|
|
112
|
+
const e = n instanceof Error ? n.message : String(n);
|
|
113
|
+
throw h(e), n;
|
|
114
|
+
} finally {
|
|
115
|
+
y(!1);
|
|
116
|
+
}
|
|
117
|
+
}, [v, b, d, E]);
|
|
118
|
+
return P(() => {
|
|
119
|
+
!t || !d || r().catch(() => {
|
|
120
|
+
});
|
|
121
|
+
}, [t, d, r]), { models: l, loading: $, error: x, reload: r };
|
|
103
122
|
}
|
|
104
|
-
function
|
|
105
|
-
const v = (
|
|
106
|
-
async function
|
|
107
|
-
const n =
|
|
123
|
+
function _(p, d) {
|
|
124
|
+
const v = (t) => typeof t == "string" && t.startsWith("gpt-5");
|
|
125
|
+
async function l(t, r) {
|
|
126
|
+
const n = p(), e = d();
|
|
108
127
|
if (!n) throw new Error("Promte settings not received yet");
|
|
109
|
-
if (!
|
|
110
|
-
const
|
|
111
|
-
return await fetch(
|
|
128
|
+
if (!e) throw new Error("Promte token not received yet");
|
|
129
|
+
const s = n.backendUrl.replace(/\/+$/, ""), c = String(t || "").replace(/^\/+/, ""), a = `${s}/${c}`;
|
|
130
|
+
return await fetch(a, {
|
|
112
131
|
...r,
|
|
113
132
|
headers: {
|
|
114
133
|
...r.headers || {},
|
|
115
|
-
Authorization: `Bearer ${
|
|
134
|
+
Authorization: `Bearer ${e}`
|
|
116
135
|
}
|
|
117
136
|
});
|
|
118
137
|
}
|
|
119
|
-
async function
|
|
120
|
-
const n = await
|
|
138
|
+
async function m(t, r) {
|
|
139
|
+
const n = await l(`/app-api/data/${t}`, {
|
|
121
140
|
method: "POST",
|
|
122
141
|
headers: { "Content-Type": "application/json" },
|
|
123
142
|
body: JSON.stringify(r)
|
|
124
|
-
}),
|
|
143
|
+
}), e = await n.json().catch(() => ({}));
|
|
125
144
|
if (!n.ok)
|
|
126
145
|
throw new Error(
|
|
127
|
-
(
|
|
146
|
+
(e == null ? void 0 : e.error) || `Request failed (${n.status})`
|
|
128
147
|
);
|
|
129
|
-
return
|
|
148
|
+
return e == null ? void 0 : e.value;
|
|
130
149
|
}
|
|
131
|
-
async function
|
|
150
|
+
async function $(t) {
|
|
132
151
|
const r = new URLSearchParams();
|
|
133
|
-
|
|
134
|
-
const n = await
|
|
152
|
+
t.scope && r.set("scope", t.scope), t.path && r.set("path", t.path);
|
|
153
|
+
const n = await l(`/app-api/data?${r.toString()}`, {
|
|
135
154
|
method: "GET"
|
|
136
|
-
}),
|
|
155
|
+
}), e = await n.json().catch(() => ({}));
|
|
137
156
|
if (!n.ok)
|
|
138
|
-
throw new Error((
|
|
139
|
-
return
|
|
157
|
+
throw new Error((e == null ? void 0 : e.error) || `Request failed (${n.status})`);
|
|
158
|
+
return e == null ? void 0 : e.value;
|
|
159
|
+
}
|
|
160
|
+
async function y(t) {
|
|
161
|
+
const r = new URLSearchParams(), n = Array.isArray(t == null ? void 0 : t.type) ? t == null ? void 0 : t.type : t != null && t.type ? [t.type] : [];
|
|
162
|
+
n.length > 0 && r.set("type", n.join(",")), t != null && t.configuredOnly && r.set("configuredOnly", "true");
|
|
163
|
+
const e = await l(
|
|
164
|
+
`/app-api/models${r.toString() ? `?${r.toString()}` : ""}`,
|
|
165
|
+
{ method: "GET" }
|
|
166
|
+
), s = await e.json().catch(() => ({}));
|
|
167
|
+
if (!e.ok)
|
|
168
|
+
throw new Error((s == null ? void 0 : s.error) || `Request failed (${e.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
|
|
178
|
+
};
|
|
179
|
+
}).filter(
|
|
180
|
+
(a) => !!a
|
|
181
|
+
);
|
|
140
182
|
}
|
|
141
|
-
|
|
142
|
-
const n =
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
183
|
+
async function x(t, r) {
|
|
184
|
+
const n = await l(t, r), s = (n.headers.get("content-type") || "").includes("application/json") ? await n.json().catch(() => ({})) : await n.text();
|
|
185
|
+
if (!n.ok)
|
|
186
|
+
throw new Error(
|
|
187
|
+
typeof s == "string" ? s || `Request failed (${n.status})` : (s == null ? void 0 : s.error) || (s == null ? void 0 : s.message) || `Request failed (${n.status})`
|
|
188
|
+
);
|
|
189
|
+
return s;
|
|
190
|
+
}
|
|
191
|
+
const h = (t) => t ? t.split("/").map((r) => r.trim()).filter(Boolean).join("/") : "", E = (t, r) => {
|
|
192
|
+
const n = h(t), e = h(r);
|
|
193
|
+
return n ? e ? `${n}/${e}` : n : e;
|
|
194
|
+
}, b = (t, r) => {
|
|
195
|
+
const n = { scope: t };
|
|
146
196
|
return {
|
|
147
197
|
async get() {
|
|
148
|
-
const
|
|
149
|
-
return
|
|
198
|
+
const e = h(r);
|
|
199
|
+
return $({ ...n, path: e || void 0 });
|
|
150
200
|
},
|
|
151
|
-
async set(
|
|
152
|
-
const
|
|
153
|
-
return
|
|
201
|
+
async set(e) {
|
|
202
|
+
const s = h(r);
|
|
203
|
+
return m("set", {
|
|
154
204
|
...n,
|
|
155
|
-
path:
|
|
156
|
-
value:
|
|
205
|
+
path: s || void 0,
|
|
206
|
+
value: e
|
|
157
207
|
});
|
|
158
208
|
},
|
|
159
|
-
async update(
|
|
160
|
-
if (!
|
|
209
|
+
async update(e) {
|
|
210
|
+
if (!e || typeof e != "object")
|
|
161
211
|
throw new Error("update requires an object");
|
|
162
|
-
const
|
|
163
|
-
for (const [
|
|
164
|
-
const
|
|
165
|
-
if (!
|
|
212
|
+
const s = {};
|
|
213
|
+
for (const [c, a] of Object.entries(e)) {
|
|
214
|
+
const u = E(r, c);
|
|
215
|
+
if (!u)
|
|
166
216
|
throw new Error("update paths must be non-empty");
|
|
167
|
-
|
|
217
|
+
s[u] = a;
|
|
168
218
|
}
|
|
169
|
-
return
|
|
219
|
+
return m("update", { ...n, updates: s });
|
|
170
220
|
},
|
|
171
221
|
async remove() {
|
|
172
|
-
const
|
|
173
|
-
return
|
|
222
|
+
const e = h(r);
|
|
223
|
+
return m("remove", { ...n, path: e || void 0 });
|
|
174
224
|
},
|
|
175
|
-
async push(
|
|
176
|
-
const
|
|
177
|
-
if (!
|
|
178
|
-
return
|
|
225
|
+
async push(e) {
|
|
226
|
+
const s = h(r);
|
|
227
|
+
if (!s) throw new Error("push requires a path");
|
|
228
|
+
return m("array-push", { ...n, path: s, value: e });
|
|
179
229
|
},
|
|
180
|
-
ref(
|
|
181
|
-
const
|
|
182
|
-
if (!
|
|
183
|
-
return
|
|
230
|
+
ref(e) {
|
|
231
|
+
const s = E(r, e);
|
|
232
|
+
if (!s) throw new Error("ref requires a path");
|
|
233
|
+
return b(t, s);
|
|
184
234
|
}
|
|
185
235
|
};
|
|
186
236
|
};
|
|
187
237
|
return {
|
|
188
238
|
isReady() {
|
|
189
|
-
return !!
|
|
239
|
+
return !!p() && !!d();
|
|
190
240
|
},
|
|
191
241
|
getBackendUrl() {
|
|
192
|
-
var
|
|
193
|
-
return ((
|
|
242
|
+
var t;
|
|
243
|
+
return ((t = p()) == null ? void 0 : t.backendUrl) ?? null;
|
|
244
|
+
},
|
|
245
|
+
async models(t) {
|
|
246
|
+
return y(t);
|
|
194
247
|
},
|
|
195
|
-
async chatCompletions(
|
|
196
|
-
var
|
|
248
|
+
async chatCompletions(t) {
|
|
249
|
+
var o;
|
|
197
250
|
const {
|
|
198
251
|
reasoningEffort: r,
|
|
199
252
|
reasoning_effort: n,
|
|
200
|
-
...
|
|
201
|
-
} =
|
|
202
|
-
...
|
|
253
|
+
...e
|
|
254
|
+
} = t, s = r ?? n, c = {
|
|
255
|
+
...e,
|
|
203
256
|
stream: !1
|
|
204
257
|
};
|
|
205
|
-
|
|
206
|
-
const
|
|
258
|
+
s && v(t.model) && (c.reasoning_effort = s);
|
|
259
|
+
const a = await l("/openai/chat/completions", {
|
|
207
260
|
method: "POST",
|
|
208
261
|
headers: { "Content-Type": "application/json" },
|
|
209
|
-
body: JSON.stringify(
|
|
210
|
-
}),
|
|
211
|
-
if (!
|
|
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)
|
|
212
265
|
throw new Error(
|
|
213
|
-
typeof
|
|
266
|
+
typeof g == "string" ? g : ((o = g == null ? void 0 : g.error) == null ? void 0 : o.message) || `Request failed (${a.status})`
|
|
214
267
|
);
|
|
215
|
-
return
|
|
268
|
+
return g;
|
|
216
269
|
},
|
|
217
|
-
async chatText(
|
|
218
|
-
var n,
|
|
219
|
-
const r = await this.chatCompletions(
|
|
220
|
-
return ((
|
|
270
|
+
async chatText(t) {
|
|
271
|
+
var n, e, s;
|
|
272
|
+
const r = await this.chatCompletions(t);
|
|
273
|
+
return ((s = (e = (n = r == null ? void 0 : r.choices) == null ? void 0 : n[0]) == null ? void 0 : e.message) == null ? void 0 : s.content) ?? "";
|
|
221
274
|
},
|
|
222
275
|
audio: {
|
|
223
|
-
async tts(
|
|
224
|
-
var
|
|
225
|
-
const r = (
|
|
276
|
+
async tts(t) {
|
|
277
|
+
var s;
|
|
278
|
+
const r = (s = t == null ? void 0 : t.text) == null ? void 0 : s.trim();
|
|
226
279
|
if (!r) throw new Error("audio.tts requires non-empty text");
|
|
227
|
-
const n = await
|
|
280
|
+
const n = await l("/app-api/audio/tts", {
|
|
228
281
|
method: "POST",
|
|
229
282
|
headers: { "Content-Type": "application/json" },
|
|
230
283
|
body: JSON.stringify({
|
|
231
284
|
text: r,
|
|
232
|
-
voice:
|
|
233
|
-
lang:
|
|
285
|
+
voice: t.voice,
|
|
286
|
+
lang: t.lang
|
|
234
287
|
})
|
|
235
288
|
});
|
|
236
289
|
if (!n.ok) {
|
|
237
|
-
const
|
|
238
|
-
throw new Error(
|
|
290
|
+
const c = await n.text();
|
|
291
|
+
throw new Error(c || `Request failed (${n.status})`);
|
|
239
292
|
}
|
|
240
293
|
return {
|
|
241
294
|
audio: await n.arrayBuffer(),
|
|
242
295
|
contentType: n.headers.get("content-type")
|
|
243
296
|
};
|
|
244
297
|
},
|
|
245
|
-
async stt(
|
|
246
|
-
var
|
|
247
|
-
if (!(
|
|
248
|
-
const r = (
|
|
249
|
-
if (!
|
|
250
|
-
const
|
|
251
|
-
if (
|
|
252
|
-
const
|
|
253
|
-
return
|
|
254
|
-
}, n = typeof File < "u" &&
|
|
255
|
-
n ?
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
`/app-api/audio/stt?ext=${encodeURIComponent(
|
|
298
|
+
async stt(t) {
|
|
299
|
+
var i, f, T;
|
|
300
|
+
if (!(t != null && t.file)) throw new Error("audio.stt requires a file");
|
|
301
|
+
const r = (R) => {
|
|
302
|
+
if (!R) return;
|
|
303
|
+
const C = R.trim();
|
|
304
|
+
if (!C) return;
|
|
305
|
+
const A = C.toLowerCase(), M = A.split("-")[0];
|
|
306
|
+
return M.length === 2 ? M : A;
|
|
307
|
+
}, n = typeof File < "u" && t.file instanceof File, e = n && t.file.name.split(".").pop() || "webm", s = t.ext || e, c = new FormData();
|
|
308
|
+
n ? c.set("file", t.file) : c.set("file", t.file, `audio.${s}`);
|
|
309
|
+
const a = r(t.language);
|
|
310
|
+
a && c.set("language", a), t.prompt && c.set("prompt", t.prompt);
|
|
311
|
+
const u = await l(
|
|
312
|
+
`/app-api/audio/stt?ext=${encodeURIComponent(s)}`,
|
|
260
313
|
{
|
|
261
314
|
method: "POST",
|
|
262
|
-
body:
|
|
315
|
+
body: c
|
|
263
316
|
}
|
|
264
|
-
),
|
|
265
|
-
if (!
|
|
317
|
+
), o = (u.headers.get("content-type") || "").includes("application/json") ? await u.json() : await u.text();
|
|
318
|
+
if (!u.ok)
|
|
266
319
|
throw new Error(
|
|
267
|
-
typeof
|
|
320
|
+
typeof o == "string" ? o : ((i = o == null ? void 0 : o.error) == null ? void 0 : i.message) || `Request failed (${u.status})`
|
|
268
321
|
);
|
|
269
|
-
return { text: typeof
|
|
322
|
+
return { text: typeof o == "string" ? o : (o == null ? void 0 : o.text) || (o == null ? void 0 : o.original) || ((T = (f = o == null ? void 0 : o.results) == null ? void 0 : f[0]) == null ? void 0 : T.text) || "", raw: o };
|
|
270
323
|
},
|
|
271
|
-
async voices(
|
|
324
|
+
async voices(t) {
|
|
272
325
|
const r = new URLSearchParams();
|
|
273
|
-
|
|
274
|
-
const n = await
|
|
326
|
+
t != null && t.locale && r.set("locale", t.locale);
|
|
327
|
+
const n = await l(
|
|
275
328
|
`/app-api/audio/tts/voices${r.toString() ? `?${r}` : ""}`,
|
|
276
329
|
{ method: "GET" }
|
|
277
|
-
),
|
|
330
|
+
), e = await n.json().catch(() => []);
|
|
278
331
|
if (!n.ok)
|
|
279
332
|
throw new Error(
|
|
280
|
-
(
|
|
333
|
+
(e == null ? void 0 : e.error) || `Request failed (${n.status})`
|
|
281
334
|
);
|
|
282
|
-
return Array.isArray(
|
|
335
|
+
return Array.isArray(e) ? e : (e == null ? void 0 : e.voices) || [];
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
web: {
|
|
339
|
+
async scrapeUrl(t) {
|
|
340
|
+
var n;
|
|
341
|
+
const r = (n = t == null ? void 0 : t.url) == null ? void 0 : n.trim();
|
|
342
|
+
if (!r) throw new Error("web.scrapeUrl requires a url");
|
|
343
|
+
return x(
|
|
344
|
+
"/app-api/web/scrape-url",
|
|
345
|
+
{
|
|
346
|
+
method: "POST",
|
|
347
|
+
headers: { "Content-Type": "application/json" },
|
|
348
|
+
body: JSON.stringify({
|
|
349
|
+
url: r,
|
|
350
|
+
maxChars: t.maxChars
|
|
351
|
+
})
|
|
352
|
+
}
|
|
353
|
+
);
|
|
283
354
|
}
|
|
284
355
|
},
|
|
285
|
-
data(
|
|
286
|
-
return
|
|
356
|
+
data(t = "private") {
|
|
357
|
+
return b(t, "");
|
|
287
358
|
}
|
|
288
359
|
};
|
|
289
360
|
}
|
|
290
361
|
export {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
362
|
+
N as PromteAppProvider,
|
|
363
|
+
j as usePromte,
|
|
364
|
+
F as usePromteClient,
|
|
365
|
+
W as usePromteDarkMode,
|
|
366
|
+
K as usePromteModels,
|
|
367
|
+
z as usePromteSettings,
|
|
368
|
+
V as usePromteToken,
|
|
369
|
+
I as usePromteUser
|
|
298
370
|
};
|
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(y,j){typeof exports=="object"&&typeof module<"u"?j(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],j):(y=typeof globalThis<"u"?globalThis:y||self,j(y.PromteAppLibrary={},y.jsxRuntime,y.react))})(this,function(y,j,i){"use strict";const M=i.createContext(null);function O({children:d,expectedParentOrigin:m,initTargetOrigin:b,retryInit:l={enabled:!0,intervalMs:500,maxAttempts:20}}){const[w,T]=i.useState(null),[v,$]=i.useState(null),[g,k]=i.useState(null),[P,t]=i.useState(null),[s,n]=i.useState(null),e=i.useMemo(()=>s?"booting":w?v?"ready":"waiting_for_token":"waiting_for_settings",[w,v,s]),r=e==="ready",c=i.useMemo(()=>b||m||"*",[b,m]),a=i.useCallback(()=>{var o;try{const h={type:"init"};(o=window.parent)==null||o.postMessage(h,c)}catch(h){n((h==null?void 0:h.message)||"Failed to post init")}},[c]);i.useEffect(()=>{a()},[a]),i.useEffect(()=>{if(!(l!=null&&l.enabled)||w)return;const o=l.intervalMs??500,h=l.maxAttempts??20;let u=0;const p=window.setInterval(()=>{if(w){window.clearInterval(p);return}if(u+=1,u>h){window.clearInterval(p);return}a()},o);return()=>window.clearInterval(p)},[l,w,a]),i.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;T(p),p!=null&&p.user&&t(p.user),n(null);return}if(u.type==="set-token"&&typeof u.value=="string"){$(u.value),n(null);return}if(u.type==="set-dark-mode"&&typeof u.value=="boolean"){k(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=i.useMemo(()=>J(()=>w,()=>v),[w,v]),E=i.useMemo(()=>({settings:w,token:v,isDarkMode:g,user:P,ready:r,state:e,error:s,client:f}),[w,v,g,P,r,e,s,f]);return j.jsx(M.Provider,{value:E,children:d})}function S(){const d=i.useContext(M);if(!d)throw new Error("usePromte must be used inside <PromteAppProvider>");return d}function B(){return S().settings}function D(){return S().token}function F(){return S().isDarkMode}function _(){return S().user}function R(){return S().client}function G(d={}){const{ready:m}=S(),b=R(),[l,w]=i.useState([]),[T,v]=i.useState(!1),[$,g]=i.useState(null),k=i.useMemo(()=>(Array.isArray(d.type)?d.type:d.type?[d.type]:[]).filter(Boolean).map(e=>String(e)).join(","),[d.type]),P=d.configuredOnly===!0,t=d.auto!==!1,s=i.useCallback(async()=>{if(!m)return[];v(!0),g(null);try{const n=k?k.split(",").filter(Boolean):void 0,e=await b.models({type:n,configuredOnly:P});return w(e),e}catch(n){const e=n instanceof Error?n.message:String(n);throw g(e),n}finally{v(!1)}},[b,P,m,k]);return i.useEffect(()=>{!t||!m||s().catch(()=>{})},[t,m,s]),{models:l,loading:T,error:$,reload:s}}function J(d,m){const b=t=>typeof t=="string"&&t.startsWith("gpt-5");async function l(t,s){const n=d(),e=m();if(!n)throw new Error("Promte settings not received yet");if(!e)throw new Error("Promte token not received yet");const r=n.backendUrl.replace(/\/+$/,""),c=String(t||"").replace(/^\/+/,""),a=`${r}/${c}`;return await fetch(a,{...s,headers:{...s.headers||{},Authorization:`Bearer ${e}`}})}async function w(t,s){const n=await l(`/app-api/data/${t}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)}),e=await n.json().catch(()=>({}));if(!n.ok)throw new Error((e==null?void 0:e.error)||`Request failed (${n.status})`);return e==null?void 0:e.value}async function T(t){const s=new URLSearchParams;t.scope&&s.set("scope",t.scope),t.path&&s.set("path",t.path);const n=await l(`/app-api/data?${s.toString()}`,{method:"GET"}),e=await n.json().catch(()=>({}));if(!n.ok)throw new Error((e==null?void 0:e.error)||`Request failed (${n.status})`);return e==null?void 0:e.value}async function v(t){const s=new URLSearchParams,n=Array.isArray(t==null?void 0:t.type)?t==null?void 0:t.type:t!=null&&t.type?[t.type]:[];n.length>0&&s.set("type",n.join(",")),t!=null&&t.configuredOnly&&s.set("configuredOnly","true");const e=await l(`/app-api/models${s.toString()?`?${s.toString()}`:""}`,{method:"GET"}),r=await e.json().catch(()=>({}));if(!e.ok)throw new Error((r==null?void 0:r.error)||`Request failed (${e.status})`);return(Array.isArray(r==null?void 0:r.models)?r.models:[]).map(a=>{if(!a||typeof a!="object")return null;const f=typeof a.id=="string"?a.id.trim():"",E=typeof a.label=="string"?a.label.trim():f,o=a.type,h=a.configured===!0,u=typeof a.source=="string"&&a.source.trim()?a.source.trim():void 0;return!f||o!=="llm"&&o!=="embedding"&&o!=="image"&&o!=="stt"&&o!=="tts"?null:{id:f,label:E||f,type:o,configured:h,source:u}}).filter(a=>!!a)}async function $(t,s){const n=await l(t,s),r=(n.headers.get("content-type")||"").includes("application/json")?await n.json().catch(()=>({})):await n.text();if(!n.ok)throw new Error(typeof r=="string"?r||`Request failed (${n.status})`:(r==null?void 0:r.error)||(r==null?void 0:r.message)||`Request failed (${n.status})`);return r}const g=t=>t?t.split("/").map(s=>s.trim()).filter(Boolean).join("/"):"",k=(t,s)=>{const n=g(t),e=g(s);return n?e?`${n}/${e}`:n:e},P=(t,s)=>{const n={scope:t};return{async get(){const e=g(s);return T({...n,path:e||void 0})},async set(e){const r=g(s);return w("set",{...n,path:r||void 0,value:e})},async update(e){if(!e||typeof e!="object")throw new Error("update requires an object");const r={};for(const[c,a]of Object.entries(e)){const f=k(s,c);if(!f)throw new Error("update paths must be non-empty");r[f]=a}return w("update",{...n,updates:r})},async remove(){const e=g(s);return w("remove",{...n,path:e||void 0})},async push(e){const r=g(s);if(!r)throw new Error("push requires a path");return w("array-push",{...n,path:r,value:e})},ref(e){const r=k(s,e);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:n,...e}=t,r=s??n,c={...e,stream:!1};r&&b(t.model)&&(c.reasoning_effort=r);const a=await l("/openai/chat/completions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)}),E=(a.headers.get("content-type")||"").includes("application/json")?await a.json():await a.text();if(!a.ok)throw new Error(typeof E=="string"?E:((o=E==null?void 0:E.error)==null?void 0:o.message)||`Request failed (${a.status})`);return E},async chatText(t){var n,e,r;const s=await this.chatCompletions(t);return((r=(e=(n=s==null?void 0:s.choices)==null?void 0:n[0])==null?void 0:e.message)==null?void 0:r.content)??""},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 n=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(!n.ok){const c=await n.text();throw new Error(c||`Request failed (${n.status})`)}return{audio:await n.arrayBuffer(),contentType:n.headers.get("content-type")}},async stt(t){var u,p,x;if(!(t!=null&&t.file))throw new Error("audio.stt requires a file");const s=C=>{if(!C)return;const A=C.trim();if(!A)return;const U=A.toLowerCase(),L=U.split("-")[0];return L.length===2?L:U},n=typeof File<"u"&&t.file instanceof File,e=n&&t.file.name.split(".").pop()||"webm",r=t.ext||e,c=new FormData;n?c.set("file",t.file):c.set("file",t.file,`audio.${r}`);const a=s(t.language);a&&c.set("language",a),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)||((x=(p=o==null?void 0:o.results)==null?void 0:p[0])==null?void 0:x.text)||"",raw:o}},async voices(t){const s=new URLSearchParams;t!=null&&t.locale&&s.set("locale",t.locale);const n=await l(`/app-api/audio/tts/voices${s.toString()?`?${s}`:""}`,{method:"GET"}),e=await n.json().catch(()=>[]);if(!n.ok)throw new Error((e==null?void 0:e.error)||`Request failed (${n.status})`);return Array.isArray(e)?e:(e==null?void 0:e.voices)||[]}},web:{async scrapeUrl(t){var n;const s=(n=t==null?void 0:t.url)==null?void 0:n.trim();if(!s)throw new Error("web.scrapeUrl requires a url");return $("/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,"")}}}y.PromteAppProvider=O,y.usePromte=S,y.usePromteClient=R,y.usePromteDarkMode=F,y.usePromteModels=G,y.usePromteSettings=B,y.usePromteToken=D,y.usePromteUser=_,Object.defineProperty(y,Symbol.toStringTag,{value:"Module"})});
|