percher 0.5.22 → 0.5.24

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.
@@ -1,91 +1,15 @@
1
+ import { createManagedInferenceClient } from "./ai-client";
1
2
  import { pb } from "./db";
2
3
 
3
- // Managed inference endpoint, injected at build time (a public URL, not a
4
- // secret). The Dockerfile declares ARG VITE_PERCHER_AI_URL.
5
- const AI_URL = import.meta.env.VITE_PERCHER_AI_URL;
6
-
7
- /**
8
- * Keyless managed inference — NO API key, billed to the app owner's Percher
9
- * plan. Only works for SIGNED-IN users (the proxy validates the current PB
10
- * session against this app's sidecar). Returns the completion text.
11
- *
12
- * const reply = await complete("Summarize: " + text);
13
- */
14
- export async function complete(
15
- prompt: string,
16
- opts?: { model?: string; maxTokens?: number },
17
- ): Promise<string> {
18
- if (!AI_URL) throw new Error("Managed inference isn't configured for this app.");
19
- if (!pb.authStore.isValid) throw new Error("Sign in to use AI.");
20
- const res = await fetch(AI_URL, {
21
- method: "POST",
22
- headers: { "content-type": "application/json", authorization: pb.authStore.token },
23
- body: JSON.stringify({
24
- model: opts?.model,
25
- max_tokens: opts?.maxTokens ?? 512,
26
- messages: [{ role: "user", content: prompt }],
27
- }),
28
- });
29
- if (!res.ok) throw new Error(`AI request failed (${res.status})`);
30
- const data = (await res.json()) as { choices?: Array<{ message?: { content?: string } }> };
31
- return data.choices?.[0]?.message?.content ?? "";
32
- }
33
-
34
- /**
35
- * Streaming variant of {@link complete} — calls `onToken` with each text delta
36
- * as it arrives and resolves with the full text. Same auth + billing as
37
- * `complete` (keyless, billed to the app owner). Use it for a typewriter UI:
38
- *
39
- * const full = await streamComplete("Write a haiku", (t) => { output.value += t; });
40
- */
41
- export async function streamComplete(
42
- prompt: string,
43
- onToken: (delta: string) => void,
44
- opts?: { model?: string; maxTokens?: number },
45
- ): Promise<string> {
46
- if (!AI_URL) throw new Error("Managed inference isn't configured for this app.");
47
- if (!pb.authStore.isValid) throw new Error("Sign in to use AI.");
48
- const res = await fetch(AI_URL, {
49
- method: "POST",
50
- headers: { "content-type": "application/json", authorization: pb.authStore.token },
51
- body: JSON.stringify({
52
- model: opts?.model,
53
- max_tokens: opts?.maxTokens ?? 512,
54
- messages: [{ role: "user", content: prompt }],
55
- stream: true,
56
- }),
57
- });
58
- if (!res.ok || !res.body) throw new Error(`AI request failed (${res.status})`);
59
-
60
- const reader = res.body.getReader();
61
- const decoder = new TextDecoder();
62
- let buffer = "";
63
- let full = "";
64
- for (;;) {
65
- const { done, value } = await reader.read();
66
- if (done) break;
67
- buffer += decoder.decode(value, { stream: true });
68
- // SSE events are separated by a blank line; parse each complete one.
69
- let sep = buffer.indexOf("\n\n");
70
- while (sep !== -1) {
71
- const event = buffer.slice(0, sep);
72
- buffer = buffer.slice(sep + 2);
73
- sep = buffer.indexOf("\n\n");
74
- const line = event.startsWith("data:") ? event.slice(5).trim() : "";
75
- if (!line || line === "[DONE]") continue;
76
- try {
77
- const chunk = JSON.parse(line) as {
78
- choices?: Array<{ delta?: { content?: string } }>;
79
- };
80
- const delta = chunk.choices?.[0]?.delta?.content ?? "";
81
- if (delta) {
82
- full += delta;
83
- onToken(delta);
84
- }
85
- } catch {
86
- /* ignore keep-alive / non-JSON lines */
87
- }
88
- }
89
- }
90
- return full;
91
- }
4
+ // This is a public URL, never a provider credential. Percher injects it only
5
+ // when the shared server-side feature gate is operational.
6
+ const client = createManagedInferenceClient({
7
+ endpoint: import.meta.env.VITE_PERCHER_AI_URL as string | undefined,
8
+ getSession: () => ({ valid: pb.authStore.isValid, token: pb.authStore.token }),
9
+ });
10
+
11
+ export { ManagedInferenceError } from "./ai-client";
12
+ export type { ManagedInferenceOptions } from "./ai-client";
13
+ export const isManagedInferenceConfigured = client.isConfigured;
14
+ export const complete = client.complete;
15
+ export const streamComplete = client.streamComplete;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "percher",
3
- "version": "0.5.22",
3
+ "version": "0.5.24",
4
4
  "description": "CLI for the Percher hosting platform — publish apps with one command",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,9 +27,9 @@
27
27
  "typecheck": "tsc --noEmit"
28
28
  },
29
29
  "dependencies": {
30
- "@percher/client": "^0.2.21",
31
- "@percher/core": "^0.4.27",
32
- "@percher/toml": "^0.1.10",
30
+ "@percher/client": "^0.3.1",
31
+ "@percher/core": "^0.4.29",
32
+ "@percher/toml": "^0.1.11",
33
33
  "cac": "^7.0.0",
34
34
  "picocolors": "^1.1.1"
35
35
  },