@runappsai/sdk 0.0.0-stage → 0.3.1

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.
Files changed (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -2
  3. package/dist/activity-tracker.d.ts +113 -0
  4. package/dist/activity-tracker.d.ts.map +1 -0
  5. package/dist/activity-tracker.js +176 -0
  6. package/dist/activity-tracker.js.map +1 -0
  7. package/dist/audio.d.ts +129 -0
  8. package/dist/audio.d.ts.map +1 -0
  9. package/dist/audio.js +267 -0
  10. package/dist/audio.js.map +1 -0
  11. package/dist/browser-auth.d.ts +179 -0
  12. package/dist/browser-auth.d.ts.map +1 -0
  13. package/dist/browser-auth.js +1361 -0
  14. package/dist/browser-auth.js.map +1 -0
  15. package/dist/chat.d.ts +221 -0
  16. package/dist/chat.d.ts.map +1 -0
  17. package/dist/chat.js +155 -0
  18. package/dist/chat.js.map +1 -0
  19. package/dist/client.d.ts +155 -0
  20. package/dist/client.d.ts.map +1 -0
  21. package/dist/client.js +157 -0
  22. package/dist/client.js.map +1 -0
  23. package/dist/computer.d.ts +57 -0
  24. package/dist/computer.d.ts.map +1 -0
  25. package/dist/computer.js +21 -0
  26. package/dist/computer.js.map +1 -0
  27. package/dist/embeddings.d.ts +64 -0
  28. package/dist/embeddings.d.ts.map +1 -0
  29. package/dist/embeddings.js +30 -0
  30. package/dist/embeddings.js.map +1 -0
  31. package/dist/errors.d.ts +24 -0
  32. package/dist/errors.d.ts.map +1 -0
  33. package/dist/errors.js +29 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/event-wrap.d.ts +59 -0
  36. package/dist/event-wrap.d.ts.map +1 -0
  37. package/dist/event-wrap.js +142 -0
  38. package/dist/event-wrap.js.map +1 -0
  39. package/dist/events.d.ts +119 -0
  40. package/dist/events.d.ts.map +1 -0
  41. package/dist/events.js +87 -0
  42. package/dist/events.js.map +1 -0
  43. package/dist/files.d.ts +218 -0
  44. package/dist/files.d.ts.map +1 -0
  45. package/dist/files.js +212 -0
  46. package/dist/files.js.map +1 -0
  47. package/dist/image.d.ts +185 -0
  48. package/dist/image.d.ts.map +1 -0
  49. package/dist/image.js +148 -0
  50. package/dist/image.js.map +1 -0
  51. package/dist/index.d.ts +30 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +26 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/media.d.ts +56 -0
  56. package/dist/media.d.ts.map +1 -0
  57. package/dist/media.js +133 -0
  58. package/dist/media.js.map +1 -0
  59. package/dist/model_options.d.ts +165 -0
  60. package/dist/model_options.d.ts.map +1 -0
  61. package/dist/model_options.js +59 -0
  62. package/dist/model_options.js.map +1 -0
  63. package/dist/models.d.ts +88 -0
  64. package/dist/models.d.ts.map +1 -0
  65. package/dist/models.js +55 -0
  66. package/dist/models.js.map +1 -0
  67. package/dist/sdk.umd.js +4 -0
  68. package/dist/sdk.umd.js.map +1 -0
  69. package/dist/transport.d.ts +120 -0
  70. package/dist/transport.d.ts.map +1 -0
  71. package/dist/transport.js +214 -0
  72. package/dist/transport.js.map +1 -0
  73. package/dist/types.d.ts +31 -0
  74. package/dist/types.d.ts.map +1 -0
  75. package/dist/types.js +2 -0
  76. package/dist/types.js.map +1 -0
  77. package/dist/validate.d.ts +16 -0
  78. package/dist/validate.d.ts.map +1 -0
  79. package/dist/validate.js +329 -0
  80. package/dist/validate.js.map +1 -0
  81. package/dist/video.d.ts +134 -0
  82. package/dist/video.d.ts.map +1 -0
  83. package/dist/video.js +60 -0
  84. package/dist/video.js.map +1 -0
  85. package/package.json +54 -4
  86. package/src/activity-tracker.ts +251 -0
  87. package/src/audio.ts +440 -0
  88. package/src/browser-auth.ts +1529 -0
  89. package/src/chat.ts +368 -0
  90. package/src/client.ts +250 -0
  91. package/src/computer.ts +80 -0
  92. package/src/embeddings.ts +97 -0
  93. package/src/errors.ts +29 -0
  94. package/src/event-wrap.ts +168 -0
  95. package/src/events.ts +172 -0
  96. package/src/files.ts +347 -0
  97. package/src/image.ts +339 -0
  98. package/src/index.ts +151 -0
  99. package/src/media.ts +147 -0
  100. package/src/model_options.ts +220 -0
  101. package/src/models.ts +121 -0
  102. package/src/transport.ts +292 -0
  103. package/src/types.ts +31 -0
  104. package/src/validate.ts +364 -0
  105. package/src/video.ts +215 -0
@@ -0,0 +1,129 @@
1
+ import type { Transport } from "./transport.js";
2
+ import type { Usage } from "./types.js";
3
+ import type { SDKEvents } from "./events.js";
4
+ export interface SpeechParams {
5
+ input: string;
6
+ /** Named voice id (`alloy`, `nova`, …; provider-dependent). Omit
7
+ * when supplying `reference_audio_url` for zero-shot voice
8
+ * cloning — the cloned timbre overrides any named voice. */
9
+ voice?: string;
10
+ response_format?: string;
11
+ speed?: number;
12
+ /** Provider-specific. Inspect the chosen TTS model's
13
+ * `options.supported_emotions` (via `client.models.get(name)`) for
14
+ * the legal enum values. */
15
+ emotion?: string;
16
+ /** -12 … 12 semitones (provider-dependent). */
17
+ pitch?: number;
18
+ /** 0.1 … 10.0 — 1.0 = normal. */
19
+ volume?: number;
20
+ /** -12 … 12 — voice timbre shift (provider-dependent). */
21
+ timber?: number;
22
+ /**
23
+ * Free-form natural-language directive for voiceclone (CosyVoice).
24
+ * e.g. "用四川话快速地说"
25
+ */
26
+ instruct_text?: string;
27
+ /**
28
+ * Public URL of a reference clip whose timbre to match (zero-shot
29
+ * voice cloning). When set, voiceclone-capable models ignore `voice`
30
+ * and synthesize matching the referenced audio.
31
+ */
32
+ reference_audio_url?: string;
33
+ /** Transcript of the reference clip — improves CosyVoice quality. */
34
+ reference_text?: string;
35
+ user?: string;
36
+ /**
37
+ * Vendor-specific top-level fields the canonical params don't model.
38
+ * Used for music-generation models on the TTS bucket — ACE-Step needs
39
+ * `tags` (genre, required), `duration`, `seed`, `scheduler`, etc.
40
+ * The SDK spreads these at the request body's TOP LEVEL (not nested
41
+ * under "extra") to match the gateway's extractSpeechExtra contract.
42
+ * Canonical fields above always win over extra keys with the same name.
43
+ */
44
+ extra?: Record<string, unknown>;
45
+ }
46
+ export interface SpeechResponse {
47
+ /** Decoded audio bytes. */
48
+ data: Uint8Array;
49
+ /** MIME type reported by the gateway (e.g. "audio/mpeg"). */
50
+ contentType: string;
51
+ usage: Usage;
52
+ }
53
+ /** Same shape as image.ImageFileInput — kept independent so callers can import either. */
54
+ export interface AudioFileInput {
55
+ data: Blob | ArrayBuffer | Uint8Array | string;
56
+ filename: string;
57
+ contentType?: string;
58
+ }
59
+ export interface TranscribeParams {
60
+ file: AudioFileInput;
61
+ language?: string;
62
+ prompt?: string;
63
+ response_format?: string;
64
+ timestamp_granularities?: ("segment" | "word")[];
65
+ user?: string;
66
+ }
67
+ export interface TranscribeResponse {
68
+ text: string;
69
+ usage: Usage;
70
+ /** Raw upstream payload — segment timings, etc., when present. */
71
+ raw?: Record<string, unknown>;
72
+ }
73
+ export declare class AudioService {
74
+ private readonly transport;
75
+ private readonly events;
76
+ constructor(transport: Transport, events: SDKEvents);
77
+ /**
78
+ * Generate speech from text. Output bytes are base64-decoded by the SDK
79
+ * — `response.data` is a `Uint8Array` you can write directly to disk:
80
+ *
81
+ * ```ts
82
+ * await fs.writeFile("out.mp3", await client.audio.speech("OpenAI/TTS", {
83
+ * input: "Hello!",
84
+ * voice: "nova",
85
+ * }).then(r => r.data));
86
+ * ```
87
+ */
88
+ speech(model: string, params: SpeechParams, init?: {
89
+ signal?: AbortSignal;
90
+ }): Promise<SpeechResponse>;
91
+ /**
92
+ * Async equivalent of `speech()`. Submits the job to the gateway's
93
+ * async TTS endpoint, polls every ~3s until terminal, then decodes
94
+ * the result audio_url. Use this when a request may exceed the
95
+ * ~100s origin timeout — ACE-Step music generation at high quality,
96
+ * large CosyVoice batches, etc. The sync `speech()` method is the
97
+ * right choice for short-clip TTS that fits inside Cloudflare's
98
+ * timeout (skips the submit + poll round-trips).
99
+ *
100
+ * Returns the same `SpeechResponse` shape as `speech()` — `data` +
101
+ * `usage` — so callers can swap the two methods with no other change.
102
+ *
103
+ * Caller's `signal` deadline bounds the poll wait. Without one,
104
+ * an internal 10-minute cap applies.
105
+ */
106
+ speechAsync(model: string, params: SpeechParams, init?: {
107
+ signal?: AbortSignal;
108
+ pollIntervalMs?: number;
109
+ }): Promise<SpeechResponse>;
110
+ /** Transcribe audio to text via multipart upload. */
111
+ transcribe(model: string, params: TranscribeParams, init?: {
112
+ signal?: AbortSignal;
113
+ }): Promise<TranscribeResponse>;
114
+ /**
115
+ * Async equivalent of `transcribe()`. Submits the upload, polls
116
+ * every ~3s until terminal, returns the same `TranscribeResponse`.
117
+ * Use this for long audio (lectures, podcasts, multi-hour
118
+ * recordings) where Whisper can take minutes — well past
119
+ * Cloudflare's ~100s sync ceiling.
120
+ *
121
+ * Caller's `signal` deadline bounds the poll wait. Without one,
122
+ * an internal 10-minute cap applies.
123
+ */
124
+ transcribeAsync(model: string, params: TranscribeParams, init?: {
125
+ signal?: AbortSignal;
126
+ pollIntervalMs?: number;
127
+ }): Promise<TranscribeResponse>;
128
+ }
129
+ //# sourceMappingURL=audio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"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"}
package/dist/audio.js ADDED
@@ -0,0 +1,267 @@
1
+ import { wrapEvents } from "./event-wrap.js";
2
+ import { decodeMediaUrl } from "./media.js";
3
+ /* ------------------------------------------------------------------ */
4
+ /* Service */
5
+ /* ------------------------------------------------------------------ */
6
+ export class AudioService {
7
+ transport;
8
+ events;
9
+ constructor(transport, events) {
10
+ this.transport = transport;
11
+ this.events = events;
12
+ }
13
+ // (Removed: listVoices — fetch voice metadata via client.models.get /
14
+ // client.models.list and read model.options.voices /
15
+ // model.options.supported_emotions.)
16
+ /**
17
+ * Generate speech from text. Output bytes are base64-decoded by the SDK
18
+ * — `response.data` is a `Uint8Array` you can write directly to disk:
19
+ *
20
+ * ```ts
21
+ * await fs.writeFile("out.mp3", await client.audio.speech("OpenAI/TTS", {
22
+ * input: "Hello!",
23
+ * voice: "nova",
24
+ * }).then(r => r.data));
25
+ * ```
26
+ */
27
+ async speech(model, params, init) {
28
+ return wrapEvents(this.events, { model, capability: "text_to_speech" }, async () => {
29
+ // Wire shape: {audio_url: "data:<mime>;base64,...", usage: ...}.
30
+ const raw = await this.transport.postJSON("/v1/audio/speech", buildSpeechBody(model, params), init);
31
+ const { bytes, contentType } = await decodeMediaUrl(raw.audio_url);
32
+ return { data: bytes, contentType, usage: raw.usage };
33
+ }, (r) => ({ costUSD: r.usage?.total_cost }));
34
+ }
35
+ /**
36
+ * Async equivalent of `speech()`. Submits the job to the gateway's
37
+ * async TTS endpoint, polls every ~3s until terminal, then decodes
38
+ * the result audio_url. Use this when a request may exceed the
39
+ * ~100s origin timeout — ACE-Step music generation at high quality,
40
+ * large CosyVoice batches, etc. The sync `speech()` method is the
41
+ * right choice for short-clip TTS that fits inside Cloudflare's
42
+ * timeout (skips the submit + poll round-trips).
43
+ *
44
+ * Returns the same `SpeechResponse` shape as `speech()` — `data` +
45
+ * `usage` — so callers can swap the two methods with no other change.
46
+ *
47
+ * Caller's `signal` deadline bounds the poll wait. Without one,
48
+ * an internal 10-minute cap applies.
49
+ */
50
+ async speechAsync(model, params, init) {
51
+ return wrapEvents(this.events, { model, capability: "text_to_speech" }, async () => {
52
+ const submit = await this.transport.postJSON("/v1/async/audio/speech", buildSpeechBody(model, params), init);
53
+ if (!submit.id) {
54
+ throw new Error("runapps: speech submit response missing job id");
55
+ }
56
+ return waitSpeechJob(this.transport, submit.id, init);
57
+ }, (r) => ({ costUSD: r.usage?.total_cost }));
58
+ }
59
+ /** Transcribe audio to text via multipart upload. */
60
+ async transcribe(model, params, init) {
61
+ const form = buildTranscribeForm(model, params);
62
+ return wrapEvents(this.events, { model, capability: "speech_to_text" }, () => this.transport.postMultipart("/v1/audio/transcriptions", form, init), (r) => ({ costUSD: r.usage?.total_cost }));
63
+ }
64
+ /**
65
+ * Async equivalent of `transcribe()`. Submits the upload, polls
66
+ * every ~3s until terminal, returns the same `TranscribeResponse`.
67
+ * Use this for long audio (lectures, podcasts, multi-hour
68
+ * recordings) where Whisper can take minutes — well past
69
+ * Cloudflare's ~100s sync ceiling.
70
+ *
71
+ * Caller's `signal` deadline bounds the poll wait. Without one,
72
+ * an internal 10-minute cap applies.
73
+ */
74
+ async transcribeAsync(model, params, init) {
75
+ return wrapEvents(this.events, { model, capability: "speech_to_text" }, async () => {
76
+ const form = buildTranscribeForm(model, params);
77
+ const submit = await this.transport.postMultipart("/v1/async/audio/transcriptions", form, init);
78
+ if (!submit.id) {
79
+ throw new Error("runapps: transcribe submit response missing job id");
80
+ }
81
+ return waitTranscribeJob(this.transport, submit.id, init);
82
+ }, (r) => ({ costUSD: r.usage?.total_cost }));
83
+ }
84
+ }
85
+ /* ------------------------------------------------------------------ */
86
+ /* Helpers */
87
+ /* ------------------------------------------------------------------ */
88
+ /**
89
+ * Polls the gateway's async speech-status endpoint until the job
90
+ * reaches a terminal state, then decodes the result `audio_url`
91
+ * data: URI into raw bytes + mime. Used by `AudioService.speechAsync`.
92
+ *
93
+ * Default poll cadence: first poll 2s after submit, then every 3s.
94
+ * Caller can override via `init.pollIntervalMs`. `init.signal`
95
+ * cancels the poll loop.
96
+ */
97
+ async function waitSpeechJob(transport, jobId, init) {
98
+ const path = `/v1/async/audio/speech/${encodeURIComponent(jobId)}`;
99
+ const interval = init?.pollIntervalMs ?? 3000;
100
+ // First poll happens fast — typical TTS already done in 2-5s.
101
+ await sleep(2000, init?.signal);
102
+ // 10-minute hard cap if caller didn't supply a signal with a
103
+ // narrower deadline. Long enough for the slowest ACE-Step jobs.
104
+ const startedAt = Date.now();
105
+ const internalDeadline = startedAt + 10 * 60 * 1000;
106
+ for (;;) {
107
+ if (init?.signal?.aborted) {
108
+ throw new DOMException("speech poll aborted", "AbortError");
109
+ }
110
+ if (!init?.signal && Date.now() > internalDeadline) {
111
+ throw new Error("runapps: speech job timed out (10 min internal cap)");
112
+ }
113
+ const status = await transport.getJSON(path, init);
114
+ if (status.status === "succeeded") {
115
+ if (!status.audio_url) {
116
+ throw new Error("runapps: speech job succeeded but no audio_url returned");
117
+ }
118
+ const { bytes, contentType } = await decodeMediaUrl(status.audio_url);
119
+ return {
120
+ data: bytes,
121
+ contentType,
122
+ usage: status.usage ?? { total_cost: 0 },
123
+ };
124
+ }
125
+ if (status.status === "failed") {
126
+ throw new Error(status.error || "runapps: speech job failed");
127
+ }
128
+ // queued | running → wait + retry.
129
+ await sleep(interval, init?.signal);
130
+ }
131
+ }
132
+ /**
133
+ * Polls the gateway's async transcribe-status endpoint until terminal,
134
+ * then assembles a TranscribeResponse from the final payload. Used by
135
+ * `AudioService.transcribeAsync`.
136
+ */
137
+ async function waitTranscribeJob(transport, jobId, init) {
138
+ const path = `/v1/async/audio/transcriptions/${encodeURIComponent(jobId)}`;
139
+ const interval = init?.pollIntervalMs ?? 3000;
140
+ await sleep(2000, init?.signal);
141
+ const internalDeadline = Date.now() + 10 * 60 * 1000;
142
+ for (;;) {
143
+ if (init?.signal?.aborted) {
144
+ throw new DOMException("transcribe poll aborted", "AbortError");
145
+ }
146
+ if (!init?.signal && Date.now() > internalDeadline) {
147
+ throw new Error("runapps: transcribe job timed out (10 min internal cap)");
148
+ }
149
+ const status = await transport.getJSON(path, init);
150
+ switch (status.status) {
151
+ case "succeeded":
152
+ return assembleTranscribeResponse(status);
153
+ case "failed":
154
+ throw new Error(status.error || "runapps: transcribe job failed");
155
+ case "queued":
156
+ case "running":
157
+ await sleep(interval, init?.signal);
158
+ break;
159
+ default:
160
+ throw new Error(`runapps: unknown transcribe job status ${JSON.stringify(status.status)}`);
161
+ }
162
+ }
163
+ }
164
+ /**
165
+ * Pulls canonical text + usage out of a succeeded transcribe-status
166
+ * payload, leaves the rest under .raw — matches the sync response
167
+ * shape produced by `transcribe()`.
168
+ */
169
+ function assembleTranscribeResponse(payload) {
170
+ const out = {
171
+ text: payload.text ?? "",
172
+ usage: payload.usage ?? { total_cost: 0 },
173
+ };
174
+ const raw = {};
175
+ for (const [k, v] of Object.entries(payload)) {
176
+ if (k === "text" || k === "usage" || k === "id" || k === "status")
177
+ continue;
178
+ raw[k] = v;
179
+ }
180
+ if (Object.keys(raw).length > 0) {
181
+ out.raw = raw;
182
+ }
183
+ return out;
184
+ }
185
+ function sleep(ms, signal) {
186
+ return new Promise((resolve, reject) => {
187
+ if (signal?.aborted) {
188
+ reject(new DOMException("aborted", "AbortError"));
189
+ return;
190
+ }
191
+ const timer = setTimeout(() => {
192
+ signal?.removeEventListener("abort", onAbort);
193
+ resolve();
194
+ }, ms);
195
+ const onAbort = () => {
196
+ clearTimeout(timer);
197
+ reject(new DOMException("aborted", "AbortError"));
198
+ };
199
+ signal?.addEventListener("abort", onAbort, { once: true });
200
+ });
201
+ }
202
+ /**
203
+ * buildSpeechBody assembles the wire body for /v1/audio/speech (and
204
+ * its async sibling): `{model, ...canonical, ...extra}` flattened at
205
+ * the top level. The gateway's extractSpeechExtra peels non-canonical
206
+ * keys back into req.Extra, so the round-trip is symmetric. Canonical
207
+ * fields always win over `extra` keys of the same name — never let
208
+ * Extra silently override a typed field.
209
+ */
210
+ function buildSpeechBody(model, params) {
211
+ const { extra, ...canonical } = params;
212
+ const body = { model, ...canonical };
213
+ if (extra) {
214
+ for (const [k, v] of Object.entries(extra)) {
215
+ if (k in body)
216
+ continue;
217
+ body[k] = v;
218
+ }
219
+ }
220
+ return body;
221
+ }
222
+ function buildTranscribeForm(model, params) {
223
+ const form = new FormData();
224
+ form.set("model", model);
225
+ if (params.language)
226
+ form.set("language", params.language);
227
+ if (params.prompt)
228
+ form.set("prompt", params.prompt);
229
+ if (params.response_format)
230
+ form.set("response_format", params.response_format);
231
+ if (params.timestamp_granularities) {
232
+ for (const g of params.timestamp_granularities) {
233
+ form.append("timestamp_granularities[]", g);
234
+ }
235
+ }
236
+ if (params.user)
237
+ form.set("user", params.user);
238
+ const ct = params.file.contentType ?? guessAudioMime(params.file.filename);
239
+ const blob = params.file.data instanceof Blob
240
+ ? params.file.data
241
+ : new Blob([params.file.data], { type: ct });
242
+ form.set("file", blob, params.file.filename);
243
+ return form;
244
+ }
245
+ function guessAudioMime(filename) {
246
+ const ext = filename.toLowerCase().split(".").pop() ?? "";
247
+ switch (ext) {
248
+ case "mp3":
249
+ return "audio/mpeg";
250
+ case "wav":
251
+ return "audio/wav";
252
+ case "m4a":
253
+ return "audio/mp4";
254
+ case "flac":
255
+ return "audio/flac";
256
+ case "ogg":
257
+ return "audio/ogg";
258
+ case "webm":
259
+ return "audio/webm";
260
+ default:
261
+ return "application/octet-stream";
262
+ }
263
+ }
264
+ // (base64ToBytes was here — promoted to media.ts as part of
265
+ // decodeMediaUrl. The audio path now goes through that single helper
266
+ // so image and audio decode through one implementation.)
267
+ //# sourceMappingURL=audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.js","sourceRoot":"","sources":["../src/audio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,179 @@
1
+ import type { SDKEvents } from "./events.js";
2
+ export interface BrowserAuthOptions {
3
+ /**
4
+ * Origin where the RunApps gateway lives — also the page that issues
5
+ * tokens at /api/sdk/grant. Default `https://www.runapps.ai`.
6
+ */
7
+ origin?: string;
8
+ /**
9
+ * Suppress the floating identity badge. Default `false` at this
10
+ * layer. The wrapping `RunApps` client passes `hideBadge: false`
11
+ * by default (badge SHOWN — it's now a live activity indicator,
12
+ * see `activity-tracker.ts`); callers wanting their own status UI
13
+ * opt out via `RunApps({ showIdentityBadge: false })`. Set this
14
+ * directly only when constructing BrowserAuth without going
15
+ * through `RunApps`.
16
+ */
17
+ hideBadge?: boolean;
18
+ /**
19
+ * Pin the grant flow to a named runapps.ai project. When set, the
20
+ * SDK passes `project_id=<value>` to `/api/sdk/grant`, asking the
21
+ * gateway to mint a project-bound `rrt_*` resource token for THAT
22
+ * project regardless of which (origin, app) pair the bundle is
23
+ * served from.
24
+ *
25
+ * Use cases:
26
+ * - **Local dev** for a 1:1 bundle/project app: the localhost
27
+ * origin isn't registered with any project, so without this
28
+ * option the grant flow can't pick one and `client.files` 403s
29
+ * on every call. Pin the project explicitly and `pnpm dev`
30
+ * hits the same files namespace as production.
31
+ * - **Multi-tenant bundles** that let the user pick a project at
32
+ * runtime — pass the chosen project id, then call `signOut()` +
33
+ * `signIn()` (or reconstruct the client) on switch.
34
+ *
35
+ * Omit to keep the default behaviour: the gateway derives the
36
+ * project from the registered (origin, app) pair.
37
+ */
38
+ project?: string;
39
+ /**
40
+ * Optional event bus from the parent RunApps client. When wired,
41
+ * the identity badge subscribes to call telemetry events and
42
+ * renders a real-time activity ring + LED dot + click-through
43
+ * popover with active / recent / session stats — turning the
44
+ * static "signed in" badge into a desktop-ball-style live
45
+ * indicator (similar to a tray-app gauge).
46
+ *
47
+ * Optional and back-compat: when omitted (or when `hideBadge` is
48
+ * true), the badge falls back to its original static behaviour.
49
+ */
50
+ events?: SDKEvents;
51
+ /**
52
+ * Which corner the badge floats in. See `RunApps.badgePosition`
53
+ * for the user-facing flavour. Defaults to `"bottom-right"`.
54
+ */
55
+ badgePosition?: BadgePosition;
56
+ }
57
+ /** Four-corner anchor for the floating activity badge. */
58
+ export type BadgePosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";
59
+ export interface BrowserUser {
60
+ id?: string;
61
+ name?: string;
62
+ }
63
+ /**
64
+ * BrowserAuth encapsulates the browser-side auth state for a RunApps
65
+ * client. Exposes:
66
+ *
67
+ * - getToken() fresh bearer (auto-refreshes / signs in)
68
+ * - signIn() force a redirect to the grant page
69
+ * - user { id, name } — null until signed in
70
+ * - onTokenChange(fn) subscribe to token (re)acquisition
71
+ *
72
+ * Construct once per page; the SDK passes its `getToken` as the
73
+ * transport's `apiKeyResolver`.
74
+ */
75
+ export declare class BrowserAuth {
76
+ private readonly origin;
77
+ private readonly hideBadge;
78
+ private readonly project;
79
+ private readonly events;
80
+ /** Lazily-constructed when events are present — drives the badge's
81
+ * activity ring / LED / popover. nullable for tests / non-browser. */
82
+ private readonly tracker;
83
+ private readonly badgePosition;
84
+ private token;
85
+ private expiresAt;
86
+ private userInfo;
87
+ private listeners;
88
+ private parentHandshake;
89
+ private signingIn;
90
+ constructor(opts?: BrowserAuthOptions);
91
+ /** Public token-fetcher; pass to RunApps as `apiKeyResolver`. */
92
+ getToken: () => Promise<string>;
93
+ /** Subscribe to (re)acquisition events. Returns an unsubscribe fn. */
94
+ onTokenChange(handler: (token: string) => void): () => void;
95
+ /** Currently-authenticated user, or null. */
96
+ get user(): BrowserUser | null;
97
+ /**
98
+ * True iff a cached bearer token is present AND not within the
99
+ * 60-second pre-expiry refresh margin. Use this — not `user !==
100
+ * null` — to decide whether to show "please sign in" UI: the user
101
+ * metadata is only populated when the SDK was fed fresh user info
102
+ * (post-redirect fragment carries it; iframe handshake carries it;
103
+ * an older localStorage save format may have persisted only the
104
+ * token). A token without metadata is still a fully-usable
105
+ * session — every gateway call will succeed — and prompting the
106
+ * user to sign in there causes a redirect that loses session
107
+ * continuity for no reason.
108
+ */
109
+ hasFreshToken(): boolean;
110
+ /**
111
+ * Clear the cached token / user / badge and the persisted copy in
112
+ * localStorage. Next gateway call will trigger a redirect to the
113
+ * grant page — i.e. the standard sign-in flow. Wire this to a
114
+ * "Sign out" button in the bundle's settings UI.
115
+ *
116
+ * Does NOT redirect on its own; the bundle decides whether to
117
+ * also navigate the user (e.g. to a logged-out splash page) or
118
+ * just refresh state and let the next API call re-prompt.
119
+ */
120
+ signOut(): void;
121
+ /**
122
+ * Drop the in-memory + persisted token without setting the sticky
123
+ * "signed out" flag. Used by the transport layer when the gateway
124
+ * returns 401 (token revoked server-side, e.g. user unsubscribed in
125
+ * another tab). The next `getToken()` will trigger the standard
126
+ * `signIn()` redirect-grant flow and the user re-auths transparently.
127
+ */
128
+ invalidate(): void;
129
+ /** Force a redirect to the grant page. */
130
+ signIn(): void;
131
+ /**
132
+ * Build the `/api/sdk/grant?…` URL the user is redirected to. Split
133
+ * out so tests can assert URL formation without a `window` context;
134
+ * `signIn` is the only production caller.
135
+ *
136
+ * Public surface, but namespaced under `_buildGrantUrlForTest` so it
137
+ * doesn't show up in IntelliSense as a normal API.
138
+ */
139
+ _buildGrantUrlForTest(args: {
140
+ pageOrigin: string;
141
+ app: string;
142
+ redirectTo: string;
143
+ scheme: "light" | "dark";
144
+ }): string;
145
+ /**
146
+ * Return the localStorage keys this instance reads / writes for its
147
+ * persisted token + sign-out flag. Exposed for tests so we can
148
+ * assert per-project namespacing without a real DOM; not part of
149
+ * the public API surface (the leading underscore + `ForTest` suffix
150
+ * is the SDK's convention for this).
151
+ */
152
+ _storageKeysForTest(): {
153
+ auth: string;
154
+ signedOut: string;
155
+ };
156
+ private buildGrantUrl;
157
+ private nowSec;
158
+ private tokenIsFresh;
159
+ private inIframe;
160
+ private setToken;
161
+ private savePersisted;
162
+ private loadPersisted;
163
+ private clearPersisted;
164
+ private isSignedOut;
165
+ private markSignedOut;
166
+ private clearSignedOut;
167
+ private removeBadge;
168
+ /** Parse the #runjobs_token=… fragment, install, then strip it. */
169
+ private consumeFragment;
170
+ /** postMessage handshake with the dashboard parent (iframe path). */
171
+ private requestTokenFromParent;
172
+ /** Floating identity badge — bottom-right pill showing the user.
173
+ * Click opens the runapps.ai dashboard in a new tab so the user
174
+ * can manage their account / billing without losing the bundle's
175
+ * in-flight state. Uses `noopener,noreferrer` so the new tab
176
+ * can't reach back into the bundle window via `window.opener`. */
177
+ private renderBadge;
178
+ }
179
+ //# sourceMappingURL=browser-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-auth.d.ts","sourceRoot":"","sources":["../src/browser-auth.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,0DAA0D;AAC1D,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;AAEtF,MAAM,WAAW,WAAW;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA8CD;;;;;;;;;;;GAWG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C;2EACuE;IACvE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,KAAK,CAAuB;IACpC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,eAAe,CAA8B;IACrD,OAAO,CAAC,SAAS,CAAS;gBAEd,IAAI,GAAE,kBAAuB;IA+CzC,iEAAiE;IACjE,QAAQ,QAAa,OAAO,CAAC,MAAM,CAAC,CA0DlC;IAEF,sEAAsE;IACtE,aAAa,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAQ3D,6CAA6C;IAC7C,IAAI,IAAI,IAAI,WAAW,GAAG,IAAI,CAE7B;IAED;;;;;;;;;;;OAWG;IACH,aAAa,IAAI,OAAO;IAIxB;;;;;;;;;OASG;IACH,OAAO,IAAI,IAAI;IAWf;;;;;;OAMG;IACH,UAAU,IAAI,IAAI;IASlB,0CAA0C;IAC1C,MAAM,IAAI,IAAI;IAmBd;;;;;;;OAOG;IACH,qBAAqB,CAAC,IAAI,EAAE;QAC1B,UAAU,EAAE,MAAM,CAAC;QACnB,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;KAC1B,GAAG,MAAM;IAIV;;;;;;OAMG;IACH,mBAAmB,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAO1D,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,QAAQ;IAiBhB,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,aAAa;IAyBrB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,WAAW;IAKnB,mEAAmE;IACnE,OAAO,CAAC,eAAe;IAkCvB,qEAAqE;IACrE,OAAO,CAAC,sBAAsB;IAoD9B;;;;uEAImE;IACnE,OAAO,CAAC,WAAW;CAqCpB"}