@promte/app-library 0.1.2 → 0.1.3
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 +27 -0
- package/dist/index.mjs +220 -174
- 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: {
|
|
@@ -112,6 +113,21 @@ declare type PromteCtxValue = {
|
|
|
112
113
|
|
|
113
114
|
export declare type PromteHandshakeState = "booting" | "waiting_for_settings" | "waiting_for_token" | "ready";
|
|
114
115
|
|
|
116
|
+
export declare type PromteModelInfo = {
|
|
117
|
+
id: string;
|
|
118
|
+
label: string;
|
|
119
|
+
type: PromteModelType;
|
|
120
|
+
configured: boolean;
|
|
121
|
+
source?: string;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export declare type PromteModelsRequest = {
|
|
125
|
+
type?: PromteModelType | PromteModelType[];
|
|
126
|
+
configuredOnly?: boolean;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export declare type PromteModelType = "llm" | "embedding" | "image" | "stt" | "tts";
|
|
130
|
+
|
|
115
131
|
export declare type PromteSettings = {
|
|
116
132
|
workspaceId: string;
|
|
117
133
|
version: number;
|
|
@@ -135,6 +151,17 @@ export declare function usePromteClient(): PromteClient;
|
|
|
135
151
|
|
|
136
152
|
export declare function usePromteDarkMode(): boolean;
|
|
137
153
|
|
|
154
|
+
export declare function usePromteModels(options?: UsePromteModelsOptions): {
|
|
155
|
+
models: PromteModelInfo[];
|
|
156
|
+
loading: boolean;
|
|
157
|
+
error: string;
|
|
158
|
+
reload: () => Promise<PromteModelInfo[]>;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export declare type UsePromteModelsOptions = PromteModelsRequest & {
|
|
162
|
+
auto?: boolean;
|
|
163
|
+
};
|
|
164
|
+
|
|
138
165
|
export declare function usePromteSettings(): PromteSettings;
|
|
139
166
|
|
|
140
167
|
export declare function usePromteToken(): string;
|
package/dist/index.mjs
CHANGED
|
@@ -1,298 +1,344 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { createContext as
|
|
3
|
-
const U =
|
|
1
|
+
import { jsx as B } from "react/jsx-runtime";
|
|
2
|
+
import { createContext as L, useState as j, useMemo as P, useCallback as M, useEffect as S, useContext as D } from "react";
|
|
3
|
+
const U = L(null);
|
|
4
4
|
function z({
|
|
5
|
-
children:
|
|
6
|
-
expectedParentOrigin:
|
|
7
|
-
initTargetOrigin:
|
|
8
|
-
retryInit:
|
|
5
|
+
children: f,
|
|
6
|
+
expectedParentOrigin: p,
|
|
7
|
+
initTargetOrigin: E,
|
|
8
|
+
retryInit: d = { enabled: !0, intervalMs: 500, maxAttempts: 20 }
|
|
9
9
|
}) {
|
|
10
|
-
const [
|
|
11
|
-
var
|
|
10
|
+
const [m, x] = j(null), [h, g] = j(null), [k, b] = j(null), [t, r] = j(null), [n, e] = j(null), o = P(() => n ? "booting" : m ? h ? "ready" : "waiting_for_token" : "waiting_for_settings", [m, h, n]), u = o === "ready", s = P(() => E || p || "*", [E, p]), i = M(() => {
|
|
11
|
+
var v;
|
|
12
12
|
try {
|
|
13
|
-
const
|
|
14
|
-
(
|
|
15
|
-
} catch (
|
|
16
|
-
|
|
13
|
+
const w = { type: "init" };
|
|
14
|
+
(v = window.parent) == null || v.postMessage(w, s);
|
|
15
|
+
} catch (w) {
|
|
16
|
+
e((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
|
+
}, [s]);
|
|
19
|
+
S(() => {
|
|
20
|
+
i();
|
|
21
|
+
}, [i]), S(() => {
|
|
22
|
+
if (!(d != null && d.enabled) || m) return;
|
|
23
|
+
const v = d.intervalMs ?? 500, w = d.maxAttempts ?? 20;
|
|
24
|
+
let c = 0;
|
|
25
|
+
const l = window.setInterval(() => {
|
|
26
|
+
if (m) {
|
|
27
|
+
window.clearInterval(l);
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
|
-
if (
|
|
31
|
-
window.clearInterval(
|
|
30
|
+
if (c += 1, c > w) {
|
|
31
|
+
window.clearInterval(l);
|
|
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
|
+
i();
|
|
35
|
+
}, v);
|
|
36
|
+
return () => window.clearInterval(l);
|
|
37
|
+
}, [d, m, i]), S(() => {
|
|
38
|
+
const v = (w) => {
|
|
39
|
+
if (p && w.origin !== p) return;
|
|
40
|
+
const c = w.data;
|
|
41
|
+
if (!(!c || typeof c != "object")) {
|
|
42
|
+
if (c.type === "set-settings") {
|
|
43
|
+
const l = c.value;
|
|
44
|
+
if (!(l != null && l.backendUrl) || l.parentOrigin && p && l.parentOrigin !== p)
|
|
45
45
|
return;
|
|
46
|
-
|
|
46
|
+
x(l), l != null && l.user && r(l.user), e(null);
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
|
-
if (
|
|
50
|
-
|
|
49
|
+
if (c.type === "set-token" && typeof c.value == "string") {
|
|
50
|
+
g(c.value), e(null);
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
|
-
if (
|
|
54
|
-
|
|
53
|
+
if (c.type === "set-dark-mode" && typeof c.value == "boolean") {
|
|
54
|
+
b(c.value);
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
|
-
if (
|
|
58
|
-
|
|
57
|
+
if (c.type === "set-user" && typeof c.value == "object") {
|
|
58
|
+
r(c.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", v), () => window.removeEventListener("message", v);
|
|
64
|
+
}, [p]);
|
|
65
|
+
const y = P(() => O(
|
|
66
|
+
() => m,
|
|
67
|
+
() => h
|
|
68
|
+
), [m, h]), a = P(
|
|
69
69
|
() => ({
|
|
70
|
-
settings:
|
|
71
|
-
token:
|
|
70
|
+
settings: m,
|
|
71
|
+
token: h,
|
|
72
72
|
isDarkMode: k,
|
|
73
|
-
user:
|
|
74
|
-
ready:
|
|
75
|
-
state:
|
|
76
|
-
error:
|
|
77
|
-
client:
|
|
73
|
+
user: t,
|
|
74
|
+
ready: u,
|
|
75
|
+
state: o,
|
|
76
|
+
error: n,
|
|
77
|
+
client: y
|
|
78
78
|
}),
|
|
79
|
-
[
|
|
79
|
+
[m, h, k, t, u, o, n, y]
|
|
80
80
|
);
|
|
81
|
-
return /* @__PURE__ */
|
|
81
|
+
return /* @__PURE__ */ B(U.Provider, { value: a, children: f });
|
|
82
82
|
}
|
|
83
|
-
function
|
|
84
|
-
const
|
|
85
|
-
if (!
|
|
83
|
+
function $() {
|
|
84
|
+
const f = D(U);
|
|
85
|
+
if (!f)
|
|
86
86
|
throw new Error("usePromte must be used inside <PromteAppProvider>");
|
|
87
|
-
return
|
|
88
|
-
}
|
|
89
|
-
function G() {
|
|
90
|
-
return b().settings;
|
|
87
|
+
return f;
|
|
91
88
|
}
|
|
92
89
|
function J() {
|
|
93
|
-
return
|
|
90
|
+
return $().settings;
|
|
94
91
|
}
|
|
95
92
|
function N() {
|
|
96
|
-
return
|
|
93
|
+
return $().token;
|
|
97
94
|
}
|
|
98
|
-
function
|
|
99
|
-
return
|
|
95
|
+
function V() {
|
|
96
|
+
return $().isDarkMode;
|
|
100
97
|
}
|
|
101
98
|
function I() {
|
|
102
|
-
return
|
|
99
|
+
return $().user;
|
|
100
|
+
}
|
|
101
|
+
function F() {
|
|
102
|
+
return $().client;
|
|
103
103
|
}
|
|
104
|
-
function
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
function K(f = {}) {
|
|
105
|
+
const { ready: p } = $(), E = F(), [d, m] = j([]), [x, h] = j(!1), [g, k] = j(null), b = P(() => (Array.isArray(f.type) ? f.type : f.type ? [f.type] : []).filter(Boolean).map((o) => String(o)).join(","), [f.type]), t = f.configuredOnly === !0, r = f.auto !== !1, n = M(async () => {
|
|
106
|
+
if (!p) return [];
|
|
107
|
+
h(!0), k(null);
|
|
108
|
+
try {
|
|
109
|
+
const e = b ? b.split(",").filter(Boolean) : void 0, o = await E.models({ type: e, configuredOnly: t });
|
|
110
|
+
return m(o), o;
|
|
111
|
+
} catch (e) {
|
|
112
|
+
const o = e instanceof Error ? e.message : String(e);
|
|
113
|
+
throw k(o), e;
|
|
114
|
+
} finally {
|
|
115
|
+
h(!1);
|
|
116
|
+
}
|
|
117
|
+
}, [E, t, p, b]);
|
|
118
|
+
return S(() => {
|
|
119
|
+
!r || !p || n().catch(() => {
|
|
120
|
+
});
|
|
121
|
+
}, [r, p, n]), { models: d, loading: x, error: g, reload: n };
|
|
122
|
+
}
|
|
123
|
+
function O(f, p) {
|
|
124
|
+
const E = (t) => typeof t == "string" && t.startsWith("gpt-5");
|
|
125
|
+
async function d(t, r) {
|
|
126
|
+
const n = f(), e = p();
|
|
108
127
|
if (!n) throw new Error("Promte settings not received yet");
|
|
109
|
-
if (!
|
|
110
|
-
const o =
|
|
111
|
-
return await fetch(
|
|
128
|
+
if (!e) throw new Error("Promte token not received yet");
|
|
129
|
+
const o = n.backendUrl.replace(/\/+$/, ""), u = String(t || "").replace(/^\/+/, ""), s = `${o}/${u}`;
|
|
130
|
+
return await fetch(s, {
|
|
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 d(`/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 x(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 d(`/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 h(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 d(
|
|
164
|
+
`/app-api/models${r.toString() ? `?${r.toString()}` : ""}`,
|
|
165
|
+
{ method: "GET" }
|
|
166
|
+
), o = await e.json().catch(() => ({}));
|
|
167
|
+
if (!e.ok)
|
|
168
|
+
throw new Error((o == null ? void 0 : o.error) || `Request failed (${e.status})`);
|
|
169
|
+
return (Array.isArray(o == null ? void 0 : o.models) ? o.models : []).map((s) => {
|
|
170
|
+
if (!s || typeof s != "object") return null;
|
|
171
|
+
const i = typeof s.id == "string" ? s.id.trim() : "", y = typeof s.label == "string" ? s.label.trim() : i, a = s.type, v = s.configured === !0, w = typeof s.source == "string" && s.source.trim() ? s.source.trim() : void 0;
|
|
172
|
+
return !i || a !== "llm" && a !== "embedding" && a !== "image" && a !== "stt" && a !== "tts" ? null : {
|
|
173
|
+
id: i,
|
|
174
|
+
label: y || i,
|
|
175
|
+
type: a,
|
|
176
|
+
configured: v,
|
|
177
|
+
source: w
|
|
178
|
+
};
|
|
179
|
+
}).filter(
|
|
180
|
+
(s) => !!s
|
|
181
|
+
);
|
|
140
182
|
}
|
|
141
|
-
const
|
|
142
|
-
const n =
|
|
143
|
-
return n ?
|
|
144
|
-
},
|
|
145
|
-
const n = { scope:
|
|
183
|
+
const g = (t) => t ? t.split("/").map((r) => r.trim()).filter(Boolean).join("/") : "", k = (t, r) => {
|
|
184
|
+
const n = g(t), e = g(r);
|
|
185
|
+
return n ? e ? `${n}/${e}` : n : e;
|
|
186
|
+
}, b = (t, r) => {
|
|
187
|
+
const n = { scope: t };
|
|
146
188
|
return {
|
|
147
189
|
async get() {
|
|
148
|
-
const
|
|
149
|
-
return
|
|
190
|
+
const e = g(r);
|
|
191
|
+
return x({ ...n, path: e || void 0 });
|
|
150
192
|
},
|
|
151
|
-
async set(
|
|
152
|
-
const o =
|
|
153
|
-
return
|
|
193
|
+
async set(e) {
|
|
194
|
+
const o = g(r);
|
|
195
|
+
return m("set", {
|
|
154
196
|
...n,
|
|
155
197
|
path: o || void 0,
|
|
156
|
-
value:
|
|
198
|
+
value: e
|
|
157
199
|
});
|
|
158
200
|
},
|
|
159
|
-
async update(
|
|
160
|
-
if (!
|
|
201
|
+
async update(e) {
|
|
202
|
+
if (!e || typeof e != "object")
|
|
161
203
|
throw new Error("update requires an object");
|
|
162
204
|
const o = {};
|
|
163
|
-
for (const [
|
|
164
|
-
const
|
|
165
|
-
if (!
|
|
205
|
+
for (const [u, s] of Object.entries(e)) {
|
|
206
|
+
const i = k(r, u);
|
|
207
|
+
if (!i)
|
|
166
208
|
throw new Error("update paths must be non-empty");
|
|
167
|
-
o[
|
|
209
|
+
o[i] = s;
|
|
168
210
|
}
|
|
169
|
-
return
|
|
211
|
+
return m("update", { ...n, updates: o });
|
|
170
212
|
},
|
|
171
213
|
async remove() {
|
|
172
|
-
const
|
|
173
|
-
return
|
|
214
|
+
const e = g(r);
|
|
215
|
+
return m("remove", { ...n, path: e || void 0 });
|
|
174
216
|
},
|
|
175
|
-
async push(
|
|
176
|
-
const o =
|
|
217
|
+
async push(e) {
|
|
218
|
+
const o = g(r);
|
|
177
219
|
if (!o) throw new Error("push requires a path");
|
|
178
|
-
return
|
|
220
|
+
return m("array-push", { ...n, path: o, value: e });
|
|
179
221
|
},
|
|
180
|
-
ref(
|
|
181
|
-
const o =
|
|
222
|
+
ref(e) {
|
|
223
|
+
const o = k(r, e);
|
|
182
224
|
if (!o) throw new Error("ref requires a path");
|
|
183
|
-
return
|
|
225
|
+
return b(t, o);
|
|
184
226
|
}
|
|
185
227
|
};
|
|
186
228
|
};
|
|
187
229
|
return {
|
|
188
230
|
isReady() {
|
|
189
|
-
return !!
|
|
231
|
+
return !!f() && !!p();
|
|
190
232
|
},
|
|
191
233
|
getBackendUrl() {
|
|
192
|
-
var
|
|
193
|
-
return ((
|
|
234
|
+
var t;
|
|
235
|
+
return ((t = f()) == null ? void 0 : t.backendUrl) ?? null;
|
|
236
|
+
},
|
|
237
|
+
async models(t) {
|
|
238
|
+
return h(t);
|
|
194
239
|
},
|
|
195
|
-
async chatCompletions(
|
|
196
|
-
var
|
|
240
|
+
async chatCompletions(t) {
|
|
241
|
+
var a;
|
|
197
242
|
const {
|
|
198
243
|
reasoningEffort: r,
|
|
199
244
|
reasoning_effort: n,
|
|
200
|
-
...
|
|
201
|
-
} =
|
|
202
|
-
...
|
|
245
|
+
...e
|
|
246
|
+
} = t, o = r ?? n, u = {
|
|
247
|
+
...e,
|
|
203
248
|
stream: !1
|
|
204
249
|
};
|
|
205
|
-
o &&
|
|
206
|
-
const
|
|
250
|
+
o && E(t.model) && (u.reasoning_effort = o);
|
|
251
|
+
const s = await d("/openai/chat/completions", {
|
|
207
252
|
method: "POST",
|
|
208
253
|
headers: { "Content-Type": "application/json" },
|
|
209
|
-
body: JSON.stringify(
|
|
210
|
-
}),
|
|
211
|
-
if (!
|
|
254
|
+
body: JSON.stringify(u)
|
|
255
|
+
}), y = (s.headers.get("content-type") || "").includes("application/json") ? await s.json() : await s.text();
|
|
256
|
+
if (!s.ok)
|
|
212
257
|
throw new Error(
|
|
213
|
-
typeof
|
|
258
|
+
typeof y == "string" ? y : ((a = y == null ? void 0 : y.error) == null ? void 0 : a.message) || `Request failed (${s.status})`
|
|
214
259
|
);
|
|
215
|
-
return
|
|
260
|
+
return y;
|
|
216
261
|
},
|
|
217
|
-
async chatText(
|
|
218
|
-
var n,
|
|
219
|
-
const r = await this.chatCompletions(
|
|
220
|
-
return ((o = (
|
|
262
|
+
async chatText(t) {
|
|
263
|
+
var n, e, o;
|
|
264
|
+
const r = await this.chatCompletions(t);
|
|
265
|
+
return ((o = (e = (n = r == null ? void 0 : r.choices) == null ? void 0 : n[0]) == null ? void 0 : e.message) == null ? void 0 : o.content) ?? "";
|
|
221
266
|
},
|
|
222
267
|
audio: {
|
|
223
|
-
async tts(
|
|
268
|
+
async tts(t) {
|
|
224
269
|
var o;
|
|
225
|
-
const r = (o =
|
|
270
|
+
const r = (o = t == null ? void 0 : t.text) == null ? void 0 : o.trim();
|
|
226
271
|
if (!r) throw new Error("audio.tts requires non-empty text");
|
|
227
|
-
const n = await
|
|
272
|
+
const n = await d("/app-api/audio/tts", {
|
|
228
273
|
method: "POST",
|
|
229
274
|
headers: { "Content-Type": "application/json" },
|
|
230
275
|
body: JSON.stringify({
|
|
231
276
|
text: r,
|
|
232
|
-
voice:
|
|
233
|
-
lang:
|
|
277
|
+
voice: t.voice,
|
|
278
|
+
lang: t.lang
|
|
234
279
|
})
|
|
235
280
|
});
|
|
236
281
|
if (!n.ok) {
|
|
237
|
-
const
|
|
238
|
-
throw new Error(
|
|
282
|
+
const u = await n.text();
|
|
283
|
+
throw new Error(u || `Request failed (${n.status})`);
|
|
239
284
|
}
|
|
240
285
|
return {
|
|
241
286
|
audio: await n.arrayBuffer(),
|
|
242
287
|
contentType: n.headers.get("content-type")
|
|
243
288
|
};
|
|
244
289
|
},
|
|
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
|
|
290
|
+
async stt(t) {
|
|
291
|
+
var w, c, l;
|
|
292
|
+
if (!(t != null && t.file)) throw new Error("audio.stt requires a file");
|
|
293
|
+
const r = (R) => {
|
|
294
|
+
if (!R) return;
|
|
295
|
+
const T = R.trim();
|
|
296
|
+
if (!T) return;
|
|
297
|
+
const A = T.toLowerCase(), C = A.split("-")[0];
|
|
298
|
+
return C.length === 2 ? C : A;
|
|
299
|
+
}, n = typeof File < "u" && t.file instanceof File, e = n && t.file.name.split(".").pop() || "webm", o = t.ext || e, u = new FormData();
|
|
300
|
+
n ? u.set("file", t.file) : u.set("file", t.file, `audio.${o}`);
|
|
301
|
+
const s = r(t.language);
|
|
302
|
+
s && u.set("language", s), t.prompt && u.set("prompt", t.prompt);
|
|
303
|
+
const i = await d(
|
|
259
304
|
`/app-api/audio/stt?ext=${encodeURIComponent(o)}`,
|
|
260
305
|
{
|
|
261
306
|
method: "POST",
|
|
262
|
-
body:
|
|
307
|
+
body: u
|
|
263
308
|
}
|
|
264
|
-
),
|
|
265
|
-
if (!
|
|
309
|
+
), a = (i.headers.get("content-type") || "").includes("application/json") ? await i.json() : await i.text();
|
|
310
|
+
if (!i.ok)
|
|
266
311
|
throw new Error(
|
|
267
|
-
typeof
|
|
312
|
+
typeof a == "string" ? a : ((w = a == null ? void 0 : a.error) == null ? void 0 : w.message) || `Request failed (${i.status})`
|
|
268
313
|
);
|
|
269
|
-
return { text: typeof
|
|
314
|
+
return { text: typeof a == "string" ? a : (a == null ? void 0 : a.text) || (a == null ? void 0 : a.original) || ((l = (c = a == null ? void 0 : a.results) == null ? void 0 : c[0]) == null ? void 0 : l.text) || "", raw: a };
|
|
270
315
|
},
|
|
271
|
-
async voices(
|
|
316
|
+
async voices(t) {
|
|
272
317
|
const r = new URLSearchParams();
|
|
273
|
-
|
|
274
|
-
const n = await
|
|
318
|
+
t != null && t.locale && r.set("locale", t.locale);
|
|
319
|
+
const n = await d(
|
|
275
320
|
`/app-api/audio/tts/voices${r.toString() ? `?${r}` : ""}`,
|
|
276
321
|
{ method: "GET" }
|
|
277
|
-
),
|
|
322
|
+
), e = await n.json().catch(() => []);
|
|
278
323
|
if (!n.ok)
|
|
279
324
|
throw new Error(
|
|
280
|
-
(
|
|
325
|
+
(e == null ? void 0 : e.error) || `Request failed (${n.status})`
|
|
281
326
|
);
|
|
282
|
-
return Array.isArray(
|
|
327
|
+
return Array.isArray(e) ? e : (e == null ? void 0 : e.voices) || [];
|
|
283
328
|
}
|
|
284
329
|
},
|
|
285
|
-
data(
|
|
286
|
-
return
|
|
330
|
+
data(t = "private") {
|
|
331
|
+
return b(t, "");
|
|
287
332
|
}
|
|
288
333
|
};
|
|
289
334
|
}
|
|
290
335
|
export {
|
|
291
336
|
z as PromteAppProvider,
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
J as
|
|
297
|
-
|
|
337
|
+
$ as usePromte,
|
|
338
|
+
F as usePromteClient,
|
|
339
|
+
V as usePromteDarkMode,
|
|
340
|
+
K as usePromteModels,
|
|
341
|
+
J as usePromteSettings,
|
|
342
|
+
N as usePromteToken,
|
|
343
|
+
I as usePromteUser
|
|
298
344
|
};
|
package/dist/index.umd.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(y,M){typeof exports=="object"&&typeof module<"u"?M(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],M):(y=typeof globalThis<"u"?globalThis:y||self,M(y.PromteAppLibrary={},y.jsxRuntime,y.react))})(this,function(y,M,i){"use strict";const T=i.createContext(null);function L({children:p,expectedParentOrigin:d,initTargetOrigin:P,retryInit:m={enabled:!0,intervalMs:500,maxAttempts:20}}){const[w,$]=i.useState(null),[v,E]=i.useState(null),[b,S]=i.useState(null),[t,s]=i.useState(null),[n,e]=i.useState(null),o=i.useMemo(()=>n?"booting":w?v?"ready":"waiting_for_token":"waiting_for_settings",[w,v,n]),f=o==="ready",r=i.useMemo(()=>P||d||"*",[P,d]),u=i.useCallback(()=>{var k;try{const h={type:"init"};(k=window.parent)==null||k.postMessage(h,r)}catch(h){e((h==null?void 0:h.message)||"Failed to post init")}},[r]);i.useEffect(()=>{u()},[u]),i.useEffect(()=>{if(!(m!=null&&m.enabled)||w)return;const k=m.intervalMs??500,h=m.maxAttempts??20;let c=0;const l=window.setInterval(()=>{if(w){window.clearInterval(l);return}if(c+=1,c>h){window.clearInterval(l);return}u()},k);return()=>window.clearInterval(l)},[m,w,u]),i.useEffect(()=>{const k=h=>{if(d&&h.origin!==d)return;const c=h.data;if(!(!c||typeof c!="object")){if(c.type==="set-settings"){const l=c.value;if(!(l!=null&&l.backendUrl)||l.parentOrigin&&d&&l.parentOrigin!==d)return;$(l),l!=null&&l.user&&s(l.user),e(null);return}if(c.type==="set-token"&&typeof c.value=="string"){E(c.value),e(null);return}if(c.type==="set-dark-mode"&&typeof c.value=="boolean"){S(c.value);return}if(c.type==="set-user"&&typeof c.value=="object"){s(c.value);return}}};return window.addEventListener("message",k),()=>window.removeEventListener("message",k)},[d]);const g=i.useMemo(()=>G(()=>w,()=>v),[w,v]),a=i.useMemo(()=>({settings:w,token:v,isDarkMode:b,user:t,ready:f,state:o,error:n,client:g}),[w,v,b,t,f,o,n,g]);return M.jsx(T.Provider,{value:a,children:p})}function j(){const p=i.useContext(T);if(!p)throw new Error("usePromte must be used inside <PromteAppProvider>");return p}function B(){return j().settings}function D(){return j().token}function O(){return j().isDarkMode}function F(){return j().user}function R(){return j().client}function _(p={}){const{ready:d}=j(),P=R(),[m,w]=i.useState([]),[$,v]=i.useState(!1),[E,b]=i.useState(null),S=i.useMemo(()=>(Array.isArray(p.type)?p.type:p.type?[p.type]:[]).filter(Boolean).map(o=>String(o)).join(","),[p.type]),t=p.configuredOnly===!0,s=p.auto!==!1,n=i.useCallback(async()=>{if(!d)return[];v(!0),b(null);try{const e=S?S.split(",").filter(Boolean):void 0,o=await P.models({type:e,configuredOnly:t});return w(o),o}catch(e){const o=e instanceof Error?e.message:String(e);throw b(o),e}finally{v(!1)}},[P,t,d,S]);return i.useEffect(()=>{!s||!d||n().catch(()=>{})},[s,d,n]),{models:m,loading:$,error:E,reload:n}}function G(p,d){const P=t=>typeof t=="string"&&t.startsWith("gpt-5");async function m(t,s){const n=p(),e=d();if(!n)throw new Error("Promte settings not received yet");if(!e)throw new Error("Promte token not received yet");const o=n.backendUrl.replace(/\/+$/,""),f=String(t||"").replace(/^\/+/,""),r=`${o}/${f}`;return await fetch(r,{...s,headers:{...s.headers||{},Authorization:`Bearer ${e}`}})}async function w(t,s){const n=await m(`/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){const s=new URLSearchParams;t.scope&&s.set("scope",t.scope),t.path&&s.set("path",t.path);const n=await m(`/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 m(`/app-api/models${s.toString()?`?${s.toString()}`:""}`,{method:"GET"}),o=await e.json().catch(()=>({}));if(!e.ok)throw new Error((o==null?void 0:o.error)||`Request failed (${e.status})`);return(Array.isArray(o==null?void 0:o.models)?o.models:[]).map(r=>{if(!r||typeof r!="object")return null;const u=typeof r.id=="string"?r.id.trim():"",g=typeof r.label=="string"?r.label.trim():u,a=r.type,k=r.configured===!0,h=typeof r.source=="string"&&r.source.trim()?r.source.trim():void 0;return!u||a!=="llm"&&a!=="embedding"&&a!=="image"&&a!=="stt"&&a!=="tts"?null:{id:u,label:g||u,type:a,configured:k,source:h}}).filter(r=>!!r)}const E=t=>t?t.split("/").map(s=>s.trim()).filter(Boolean).join("/"):"",b=(t,s)=>{const n=E(t),e=E(s);return n?e?`${n}/${e}`:n:e},S=(t,s)=>{const n={scope:t};return{async get(){const e=E(s);return $({...n,path:e||void 0})},async set(e){const o=E(s);return w("set",{...n,path:o||void 0,value:e})},async update(e){if(!e||typeof e!="object")throw new Error("update requires an object");const o={};for(const[f,r]of Object.entries(e)){const u=b(s,f);if(!u)throw new Error("update paths must be non-empty");o[u]=r}return w("update",{...n,updates:o})},async remove(){const e=E(s);return w("remove",{...n,path:e||void 0})},async push(e){const o=E(s);if(!o)throw new Error("push requires a path");return w("array-push",{...n,path:o,value:e})},ref(e){const o=b(s,e);if(!o)throw new Error("ref requires a path");return S(t,o)}}};return{isReady(){return!!p()&&!!d()},getBackendUrl(){var t;return((t=p())==null?void 0:t.backendUrl)??null},async models(t){return v(t)},async chatCompletions(t){var a;const{reasoningEffort:s,reasoning_effort:n,...e}=t,o=s??n,f={...e,stream:!1};o&&P(t.model)&&(f.reasoning_effort=o);const r=await m("/openai/chat/completions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(f)}),g=(r.headers.get("content-type")||"").includes("application/json")?await r.json():await r.text();if(!r.ok)throw new Error(typeof g=="string"?g:((a=g==null?void 0:g.error)==null?void 0:a.message)||`Request failed (${r.status})`);return g},async chatText(t){var n,e,o;const s=await this.chatCompletions(t);return((o=(e=(n=s==null?void 0:s.choices)==null?void 0:n[0])==null?void 0:e.message)==null?void 0:o.content)??""},audio:{async tts(t){var o;const s=(o=t==null?void 0:t.text)==null?void 0:o.trim();if(!s)throw new Error("audio.tts requires non-empty text");const n=await m("/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 f=await n.text();throw new Error(f||`Request failed (${n.status})`)}return{audio:await n.arrayBuffer(),contentType:n.headers.get("content-type")}},async stt(t){var h,c,l;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 C=A.toLowerCase(),U=C.split("-")[0];return U.length===2?U:C},n=typeof File<"u"&&t.file instanceof File,e=n&&t.file.name.split(".").pop()||"webm",o=t.ext||e,f=new FormData;n?f.set("file",t.file):f.set("file",t.file,`audio.${o}`);const r=s(t.language);r&&f.set("language",r),t.prompt&&f.set("prompt",t.prompt);const u=await m(`/app-api/audio/stt?ext=${encodeURIComponent(o)}`,{method:"POST",body:f}),a=(u.headers.get("content-type")||"").includes("application/json")?await u.json():await u.text();if(!u.ok)throw new Error(typeof a=="string"?a:((h=a==null?void 0:a.error)==null?void 0:h.message)||`Request failed (${u.status})`);return{text:typeof a=="string"?a:(a==null?void 0:a.text)||(a==null?void 0:a.original)||((l=(c=a==null?void 0:a.results)==null?void 0:c[0])==null?void 0:l.text)||"",raw:a}},async voices(t){const s=new URLSearchParams;t!=null&&t.locale&&s.set("locale",t.locale);const n=await m(`/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)||[]}},data(t="private"){return S(t,"")}}}y.PromteAppProvider=L,y.usePromte=j,y.usePromteClient=R,y.usePromteDarkMode=O,y.usePromteModels=_,y.usePromteSettings=B,y.usePromteToken=D,y.usePromteUser=F,Object.defineProperty(y,Symbol.toStringTag,{value:"Module"})});
|