@kazzle/app 0.1.927 → 0.1.930

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 (56) hide show
  1. package/dist/auth-react.d.ts +20 -0
  2. package/dist/auth-react.js +52 -0
  3. package/dist/auth-schema.d.ts +12 -0
  4. package/dist/auth-schema.js +66 -0
  5. package/dist/auth.d.ts +50 -0
  6. package/dist/auth.js +87 -0
  7. package/dist/connections.d.ts +11 -0
  8. package/dist/connections.js +56 -0
  9. package/dist/index.d.ts +7 -0
  10. package/dist/sdk.d.ts +1 -0
  11. package/dist/sdk.js +13 -0
  12. package/dist/vendor/kazzle/browsers.d.ts +56 -0
  13. package/dist/vendor/kazzle/browsers.js +88 -0
  14. package/dist/vendor/kazzle/browsers.profiles.d.ts +16 -0
  15. package/dist/vendor/kazzle/browsers.profiles.js +26 -0
  16. package/dist/vendor/kazzle/browsers.tabs.d.ts +62 -0
  17. package/dist/vendor/kazzle/browsers.tabs.js +132 -0
  18. package/dist/vendor/kazzle/computers.d.ts +35 -0
  19. package/dist/vendor/kazzle/computers.desktop.d.ts +152 -0
  20. package/dist/vendor/kazzle/computers.desktop.js +144 -0
  21. package/dist/vendor/kazzle/computers.fs.d.ts +44 -0
  22. package/dist/vendor/kazzle/computers.fs.js +37 -0
  23. package/dist/vendor/kazzle/computers.js +55 -0
  24. package/dist/vendor/kazzle/computers.terminals.d.ts +36 -0
  25. package/dist/vendor/kazzle/computers.terminals.js +38 -0
  26. package/dist/vendor/kazzle/generated/operations.d.ts +8 -0
  27. package/dist/vendor/kazzle/generated/operations.js +137 -0
  28. package/dist/vendor/kazzle/http.d.ts +39 -0
  29. package/dist/vendor/kazzle/http.js +103 -0
  30. package/dist/vendor/kazzle/index.d.ts +11 -0
  31. package/dist/vendor/kazzle/index.js +12 -0
  32. package/dist/vendor/kazzle/kazzle.d.ts +10 -0
  33. package/dist/vendor/kazzle/kazzle.js +18 -0
  34. package/dist/vendor/kazzle/sdk.types.d.ts +134 -0
  35. package/dist/vendor/kazzle/sdk.types.js +6 -0
  36. package/dist/vendor/kazzle/sse.d.ts +45 -0
  37. package/dist/vendor/kazzle/sse.js +112 -0
  38. package/package.json +43 -1
  39. package/templates/login-app/KAZZLE.md +18 -0
  40. package/templates/login-app/components/server/index.ts +93 -0
  41. package/templates/login-app/components/server/package.json +25 -0
  42. package/templates/login-app/components/server/tsconfig.json +11 -0
  43. package/templates/login-app/components/ui/index.html +12 -0
  44. package/templates/login-app/components/ui/package.json +29 -0
  45. package/templates/login-app/components/ui/public/favicon.svg +4 -0
  46. package/templates/login-app/components/ui/src/App.tsx +107 -0
  47. package/templates/login-app/components/ui/src/api.ts +37 -0
  48. package/templates/login-app/components/ui/src/main.tsx +13 -0
  49. package/templates/login-app/components/ui/src/styles/theme.css +181 -0
  50. package/templates/login-app/components/ui/src/vite-env.d.ts +1 -0
  51. package/templates/login-app/components/ui/tsconfig.json +21 -0
  52. package/templates/login-app/components/ui/vite.config.ts +19 -0
  53. package/templates/login-app/kazzle.config.ts +13 -0
  54. package/templates/login-app/package.json +17 -0
  55. package/templates/manifest.json +1 -0
  56. package/templates/ui-db-app/components/ui/tsconfig.json +1 -1
@@ -0,0 +1,8 @@
1
+ export interface ApiOperation {
2
+ method: string;
3
+ path: string;
4
+ }
5
+ /** Every customer API operation the SDK must cover. */
6
+ export declare const API_OPERATIONS: readonly ApiOperation[];
7
+ /** URL segments under /browsers/{browserId}/tabs/{tabId}/. */
8
+ export declare const TAB_ACTION_SEGMENTS: readonly string[];
@@ -0,0 +1,137 @@
1
+ // GENERATED FILE — do not edit.
2
+ // Source of truth: shared/api/openapi.json (Computers API + Browsers API tags).
3
+ // Regenerate with `bun run generate` in packages/kazzle-sdk after the server
4
+ // API surface changes; src/operations.sync.test.ts fails on drift.
5
+ /** Every customer API operation the SDK must cover. */
6
+ export const API_OPERATIONS = [
7
+ { method: 'GET', path: '/browsers' },
8
+ { method: 'POST', path: '/browsers' },
9
+ { method: 'DELETE', path: '/browsers/{browserId}' },
10
+ { method: 'GET', path: '/browsers/{browserId}' },
11
+ { method: 'GET', path: '/browsers/{browserId}/tabs' },
12
+ { method: 'POST', path: '/browsers/{browserId}/tabs' },
13
+ { method: 'DELETE', path: '/browsers/{browserId}/tabs/{tabId}' },
14
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/back' },
15
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/check' },
16
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/click' },
17
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/close' },
18
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/console' },
19
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/content' },
20
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/dialog' },
21
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/dom' },
22
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/download' },
23
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/drag' },
24
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/eval' },
25
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/extract' },
26
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/fill_form' },
27
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/find' },
28
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/focus' },
29
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/forward' },
30
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/hover' },
31
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/key' },
32
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/live' },
33
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/move' },
34
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/nav' },
35
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/network' },
36
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/options' },
37
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/pdf' },
38
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/reload' },
39
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/screenshot' },
40
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/scroll' },
41
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/select' },
42
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/snapshot' },
43
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/status' },
44
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/type' },
45
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/uncheck' },
46
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/upload' },
47
+ { method: 'POST', path: '/browsers/{browserId}/tabs/{tabId}/wait' },
48
+ { method: 'GET', path: '/browsers/profiles' },
49
+ { method: 'POST', path: '/browsers/profiles' },
50
+ { method: 'DELETE', path: '/browsers/profiles/{profileId}' },
51
+ { method: 'GET', path: '/computers' },
52
+ { method: 'POST', path: '/computers' },
53
+ { method: 'DELETE', path: '/computers/{computerId}' },
54
+ { method: 'GET', path: '/computers/{computerId}' },
55
+ { method: 'GET', path: '/computers/{computerId}/desktop/apps' },
56
+ { method: 'POST', path: '/computers/{computerId}/desktop/apps/capture' },
57
+ { method: 'POST', path: '/computers/{computerId}/desktop/apps/inspect' },
58
+ { method: 'POST', path: '/computers/{computerId}/desktop/apps/press' },
59
+ { method: 'POST', path: '/computers/{computerId}/desktop/apps/set_value' },
60
+ { method: 'POST', path: '/computers/{computerId}/desktop/apps/start' },
61
+ { method: 'POST', path: '/computers/{computerId}/desktop/apps/status' },
62
+ { method: 'POST', path: '/computers/{computerId}/desktop/apps/stop' },
63
+ { method: 'POST', path: '/computers/{computerId}/desktop/capture' },
64
+ { method: 'GET', path: '/computers/{computerId}/desktop/displays' },
65
+ { method: 'POST', path: '/computers/{computerId}/desktop/input/click' },
66
+ { method: 'POST', path: '/computers/{computerId}/desktop/input/double_click' },
67
+ { method: 'POST', path: '/computers/{computerId}/desktop/input/drag' },
68
+ { method: 'POST', path: '/computers/{computerId}/desktop/input/key' },
69
+ { method: 'POST', path: '/computers/{computerId}/desktop/input/mouse_down' },
70
+ { method: 'POST', path: '/computers/{computerId}/desktop/input/mouse_up' },
71
+ { method: 'POST', path: '/computers/{computerId}/desktop/input/move' },
72
+ { method: 'POST', path: '/computers/{computerId}/desktop/input/scroll' },
73
+ { method: 'POST', path: '/computers/{computerId}/desktop/input/type' },
74
+ { method: 'GET', path: '/computers/{computerId}/desktop/permissions' },
75
+ { method: 'POST', path: '/computers/{computerId}/desktop/screen' },
76
+ { method: 'GET', path: '/computers/{computerId}/desktop/sessions' },
77
+ { method: 'POST', path: '/computers/{computerId}/desktop/sessions' },
78
+ { method: 'DELETE', path: '/computers/{computerId}/desktop/sessions/{sessionId}' },
79
+ { method: 'POST', path: '/computers/{computerId}/desktop/windows/active' },
80
+ { method: 'POST', path: '/computers/{computerId}/desktop/windows/place' },
81
+ { method: 'POST', path: '/computers/{computerId}/desktop/windows/raise' },
82
+ { method: 'POST', path: '/computers/{computerId}/exec' },
83
+ { method: 'POST', path: '/computers/{computerId}/fs/copy' },
84
+ { method: 'POST', path: '/computers/{computerId}/fs/delete' },
85
+ { method: 'POST', path: '/computers/{computerId}/fs/glob' },
86
+ { method: 'POST', path: '/computers/{computerId}/fs/grep' },
87
+ { method: 'POST', path: '/computers/{computerId}/fs/move' },
88
+ { method: 'POST', path: '/computers/{computerId}/fs/read' },
89
+ { method: 'POST', path: '/computers/{computerId}/fs/write' },
90
+ { method: 'POST', path: '/computers/{computerId}/repair' },
91
+ { method: 'POST', path: '/computers/{computerId}/stop' },
92
+ { method: 'GET', path: '/computers/{computerId}/terminals' },
93
+ { method: 'POST', path: '/computers/{computerId}/terminals' },
94
+ { method: 'DELETE', path: '/computers/{computerId}/terminals/{sessionId}' },
95
+ { method: 'POST', path: '/computers/{computerId}/terminals/{sessionId}/ctrl' },
96
+ { method: 'POST', path: '/computers/{computerId}/terminals/{sessionId}/read' },
97
+ { method: 'POST', path: '/computers/{computerId}/terminals/{sessionId}/wait' },
98
+ { method: 'POST', path: '/computers/{computerId}/terminals/{sessionId}/write' },
99
+ { method: 'POST', path: '/computers/{computerId}/wake' },
100
+ ];
101
+ /** URL segments under /browsers/{browserId}/tabs/{tabId}/. */
102
+ export const TAB_ACTION_SEGMENTS = [
103
+ 'back',
104
+ 'check',
105
+ 'click',
106
+ 'close',
107
+ 'console',
108
+ 'content',
109
+ 'dialog',
110
+ 'dom',
111
+ 'download',
112
+ 'drag',
113
+ 'eval',
114
+ 'extract',
115
+ 'fill_form',
116
+ 'find',
117
+ 'focus',
118
+ 'forward',
119
+ 'hover',
120
+ 'key',
121
+ 'live',
122
+ 'move',
123
+ 'nav',
124
+ 'network',
125
+ 'options',
126
+ 'pdf',
127
+ 'reload',
128
+ 'screenshot',
129
+ 'scroll',
130
+ 'select',
131
+ 'snapshot',
132
+ 'status',
133
+ 'type',
134
+ 'uncheck',
135
+ 'upload',
136
+ 'wait',
137
+ ];
@@ -0,0 +1,39 @@
1
+ export interface KazzleOptions {
2
+ /** `kzl_` API key. Defaults to the KAZZLE_API_KEY environment variable. */
3
+ apiKey?: string;
4
+ /** API base URL override for dev/local, e.g. http://localhost:8080. Defaults to the KAZZLE_API_URL environment variable, then https://api.kazzle.app. */
5
+ baseUrl?: string;
6
+ /** Fetch implementation override, for tests. */
7
+ fetch?: typeof globalThis.fetch;
8
+ }
9
+ /** A non-2xx response from the API. `status` and the body's `error` are always set. */
10
+ export declare class KazzleApiError extends Error {
11
+ readonly status: number;
12
+ readonly code: string | undefined;
13
+ readonly body: Record<string, unknown>;
14
+ constructor(status: number, body: Record<string, unknown>);
15
+ }
16
+ /** Template tag that URL-encodes interpolated path params: apiPath`/computers/${id}/wake`. */
17
+ export declare function apiPath(strings: TemplateStringsArray, ...params: string[]): string;
18
+ export type Query = Record<string, string | number | undefined>;
19
+ /**
20
+ * Wire casing: SDK request options are camelCase; the API's documented surface
21
+ * is snake_case. JSON bodies are deep-converted on the way out, so every
22
+ * namespace method can pass its options object straight through.
23
+ */
24
+ export declare function toWireBody(value: unknown): unknown;
25
+ export declare class KazzleHttp {
26
+ readonly baseUrl: string;
27
+ private readonly apiKey;
28
+ private readonly fetchImpl;
29
+ constructor(options?: KazzleOptions);
30
+ url(path: string, query?: Query): string;
31
+ /**
32
+ * Raw request. JSON bodies are re-cased to the snake_case wire shape; non-2xx
33
+ * responses are read as JSON and thrown as KazzleApiError.
34
+ */
35
+ request(method: string, path: string, body?: unknown, query?: Query): Promise<Response>;
36
+ json<T>(method: string, path: string, body?: unknown, query?: Query): Promise<T>;
37
+ /** POST returning raw bytes (screenshot, pdf, capture). */
38
+ binary(path: string, body?: unknown): Promise<Uint8Array>;
39
+ }
@@ -0,0 +1,103 @@
1
+ // HTTP core for the `kazzle` package: auth, URL building, JSON/binary/SSE requests.
2
+ //
3
+ // Dependency-free on purpose (uses global fetch). Every namespace call funnels
4
+ // through KazzleHttp, so auth and error mapping live in exactly one place.
5
+ /** Default API base. Source of truth: shared/types/auth.types.ts (apiUrlForEnv). */
6
+ const DEFAULT_BASE_URL = 'https://api.kazzle.app';
7
+ /** A non-2xx response from the API. `status` and the body's `error` are always set. */
8
+ export class KazzleApiError extends Error {
9
+ status;
10
+ code;
11
+ body;
12
+ constructor(status, body) {
13
+ const message = typeof body.error === 'string' ? body.error : `Kazzle API request failed with status ${status}`;
14
+ super(message);
15
+ this.name = 'KazzleApiError';
16
+ this.status = status;
17
+ this.code = typeof body.code === 'string' ? body.code : undefined;
18
+ this.body = body;
19
+ }
20
+ }
21
+ function envVar(name) {
22
+ if (typeof process === 'undefined' || !process.env)
23
+ return undefined;
24
+ return process.env[name];
25
+ }
26
+ /** Template tag that URL-encodes interpolated path params: apiPath`/computers/${id}/wake`. */
27
+ export function apiPath(strings, ...params) {
28
+ return strings.reduce((out, part, i) => out + part + (i < params.length ? encodeURIComponent(params[i]) : ''), '');
29
+ }
30
+ /**
31
+ * Keys whose VALUES are opaque customer data (env var names like MY_VAR, JSON
32
+ * eval arguments) — never re-cased. Source of truth: server/tools/tool-api.casing.ts.
33
+ */
34
+ const OPAQUE_VALUE_KEYS = new Set(['env', 'arguments']);
35
+ function camelToSnakeKey(key) {
36
+ return key.replace(/([A-Z])/g, '_$1').toLowerCase();
37
+ }
38
+ /**
39
+ * Wire casing: SDK request options are camelCase; the API's documented surface
40
+ * is snake_case. JSON bodies are deep-converted on the way out, so every
41
+ * namespace method can pass its options object straight through.
42
+ */
43
+ export function toWireBody(value) {
44
+ if (Array.isArray(value))
45
+ return value.map(toWireBody);
46
+ if (value === null || typeof value !== 'object')
47
+ return value;
48
+ const out = {};
49
+ for (const [key, entry] of Object.entries(value)) {
50
+ out[camelToSnakeKey(key)] = OPAQUE_VALUE_KEYS.has(key) ? entry : toWireBody(entry);
51
+ }
52
+ return out;
53
+ }
54
+ export class KazzleHttp {
55
+ baseUrl;
56
+ apiKey;
57
+ fetchImpl;
58
+ constructor(options = {}) {
59
+ const apiKey = options.apiKey ?? envVar('KAZZLE_API_KEY');
60
+ if (!apiKey) {
61
+ throw new Error('Missing Kazzle API key. Pass `new Kazzle({ apiKey })` or set the KAZZLE_API_KEY environment variable.');
62
+ }
63
+ this.apiKey = apiKey;
64
+ const baseUrl = options.baseUrl ?? envVar('KAZZLE_API_URL') ?? DEFAULT_BASE_URL;
65
+ this.baseUrl = baseUrl.replace(/\/+$/, '');
66
+ this.fetchImpl = options.fetch ?? globalThis.fetch;
67
+ }
68
+ url(path, query) {
69
+ const params = Object.entries(query ?? {}).filter(([, value]) => value !== undefined);
70
+ const search = params.length
71
+ ? `?${new URLSearchParams(params.map(([key, value]) => [key, String(value)])).toString()}`
72
+ : '';
73
+ return `${this.baseUrl}${path}${search}`;
74
+ }
75
+ /**
76
+ * Raw request. JSON bodies are re-cased to the snake_case wire shape; non-2xx
77
+ * responses are read as JSON and thrown as KazzleApiError.
78
+ */
79
+ async request(method, path, body, query) {
80
+ const response = await this.fetchImpl(this.url(path, query), {
81
+ method,
82
+ headers: {
83
+ authorization: `Bearer ${this.apiKey}`,
84
+ ...(body !== undefined ? { 'content-type': 'application/json' } : {}),
85
+ },
86
+ ...(body !== undefined ? { body: JSON.stringify(toWireBody(body)) } : {}),
87
+ });
88
+ if (!response.ok) {
89
+ const errorBody = await response.json().catch(() => ({}));
90
+ throw new KazzleApiError(response.status, errorBody);
91
+ }
92
+ return response;
93
+ }
94
+ async json(method, path, body, query) {
95
+ const response = await this.request(method, path, body, query);
96
+ return await response.json();
97
+ }
98
+ /** POST returning raw bytes (screenshot, pdf, capture). */
99
+ async binary(path, body) {
100
+ const response = await this.request('POST', path, body ?? {});
101
+ return new Uint8Array(await response.arrayBuffer());
102
+ }
103
+ }
@@ -0,0 +1,11 @@
1
+ export { Kazzle } from './kazzle';
2
+ export { KazzleApiError, type KazzleOptions } from './http';
3
+ export { ExecStream, KazzleExecError, type ExecEvent, type ExecResult } from './sse';
4
+ export { ComputersApi } from './computers';
5
+ export { FsApi, type FsGrepOptions } from './computers.fs';
6
+ export { TerminalsApi } from './computers.terminals';
7
+ export { DesktopApi } from './computers.desktop';
8
+ export { Browser, BrowsersApi } from './browsers';
9
+ export { TabsApi } from './browsers.tabs';
10
+ export { ProfilesApi } from './browsers.profiles';
11
+ export type { ActionResult, BrowserCreateOptions, BrowserCreateResponse, BrowserRow, BrowserState, ComputerCreateResponse, ComputerRow, ExecOptions, FsDeleteResponse, FsGlobResponse, FsGrepMatch, FsGrepResponse, FsReadResponse, FsTransferResponse, FsWriteResponse, ListResponse, OkResponse, ProfileCreateOptions, ProfileCreateResponse, ProfileRow, TabRow, } from './sdk.types';
@@ -0,0 +1,12 @@
1
+ // kazzle — typed client for the Kazzle computers and browsers REST API.
2
+ // Quickstart in README.md; endpoint semantics in docs/platform/computers-api.mdx.
3
+ export { Kazzle } from './kazzle';
4
+ export { KazzleApiError } from './http';
5
+ export { ExecStream, KazzleExecError } from './sse';
6
+ export { ComputersApi } from './computers';
7
+ export { FsApi } from './computers.fs';
8
+ export { TerminalsApi } from './computers.terminals';
9
+ export { DesktopApi } from './computers.desktop';
10
+ export { Browser, BrowsersApi } from './browsers';
11
+ export { TabsApi } from './browsers.tabs';
12
+ export { ProfilesApi } from './browsers.profiles';
@@ -0,0 +1,10 @@
1
+ import { type KazzleOptions } from './http';
2
+ import { ComputersApi } from './computers';
3
+ import { BrowsersApi } from './browsers';
4
+ export declare class Kazzle {
5
+ readonly computers: ComputersApi;
6
+ readonly browsers: BrowsersApi;
7
+ /** Resolved API base URL (option, then KAZZLE_API_URL, then https://api.kazzle.app). */
8
+ readonly baseUrl: string;
9
+ constructor(options?: KazzleOptions);
10
+ }
@@ -0,0 +1,18 @@
1
+ // Kazzle SDK entry: `new Kazzle({ apiKey })` → kazzle.computers.* and
2
+ // kazzle.browsers.*. One KazzleHttp instance owns auth and error mapping for
3
+ // every namespace.
4
+ import { KazzleHttp } from './http';
5
+ import { ComputersApi } from './computers';
6
+ import { BrowsersApi } from './browsers';
7
+ export class Kazzle {
8
+ computers;
9
+ browsers;
10
+ /** Resolved API base URL (option, then KAZZLE_API_URL, then https://api.kazzle.app). */
11
+ baseUrl;
12
+ constructor(options = {}) {
13
+ const http = new KazzleHttp(options);
14
+ this.baseUrl = http.baseUrl;
15
+ this.computers = new ComputersApi(http);
16
+ this.browsers = new BrowsersApi(http);
17
+ }
18
+ }
@@ -0,0 +1,134 @@
1
+ /** Every list endpoint returns { items, total }. */
2
+ export interface ListResponse<T> {
3
+ items: T[];
4
+ total: number;
5
+ }
6
+ export interface OkResponse {
7
+ ok: boolean;
8
+ }
9
+ export interface ComputerCreateResponse {
10
+ id: string;
11
+ /** Connection state: "offline" right after create, "online" once up. */
12
+ state: string;
13
+ }
14
+ export interface ComputerRow {
15
+ id: string;
16
+ label: string | null;
17
+ type: string | null;
18
+ platform: string;
19
+ state: string;
20
+ created_at: number;
21
+ }
22
+ export interface ExecOptions {
23
+ command: string;
24
+ cwd?: string;
25
+ shell?: string;
26
+ timeoutMs?: number;
27
+ env?: Record<string, string>;
28
+ }
29
+ /**
30
+ * Tool-action result (terminals, desktop, tabs): `content` plus optional
31
+ * `row`/`items`/`total` and action-specific fields. All keys are snake_case
32
+ * on the wire, matching the documented API surface.
33
+ */
34
+ export interface ActionResult {
35
+ content?: string;
36
+ row?: Record<string, unknown>;
37
+ items?: unknown[];
38
+ total?: number;
39
+ [key: string]: unknown;
40
+ }
41
+ /** POST /computers/{id}/terminals — the new PTY session id is top-level. */
42
+ export interface TerminalCreateResponse extends ActionResult {
43
+ session_id: string;
44
+ }
45
+ export interface FsReadResponse {
46
+ path: string;
47
+ /** utf8 text, or base64 when `encoding` is "base64". */
48
+ content: string;
49
+ encoding?: 'base64';
50
+ size_bytes: number;
51
+ }
52
+ export interface FsWriteResponse {
53
+ ok: boolean;
54
+ path: string;
55
+ size_bytes: number;
56
+ }
57
+ export interface FsDeleteResponse {
58
+ ok: boolean;
59
+ path: string;
60
+ }
61
+ export interface FsTransferResponse {
62
+ ok: boolean;
63
+ from: string;
64
+ to: string;
65
+ }
66
+ export interface FsGrepMatch {
67
+ path: string;
68
+ line: number;
69
+ snippet: string;
70
+ }
71
+ export interface FsGrepResponse {
72
+ matches: FsGrepMatch[];
73
+ total: number;
74
+ }
75
+ export interface FsGlobResponse {
76
+ files: string[];
77
+ total: number;
78
+ }
79
+ export interface BrowserCreateOptions {
80
+ /** Host the browser on this computer (its own pages: app previews, localhost). Omit for a stealth cloud browser. */
81
+ computerId?: string;
82
+ /** Reuse a saved profile's logins and cookies. */
83
+ profileId?: string;
84
+ /** Open this page in the first tab. */
85
+ url?: string;
86
+ }
87
+ export interface BrowserCreateResponse {
88
+ id: string;
89
+ tab_id: string;
90
+ computer_id: string | null;
91
+ provider: string;
92
+ url: string | null;
93
+ live_view_url: string | null;
94
+ }
95
+ export interface BrowserRow {
96
+ id: string;
97
+ computer_id: string | null;
98
+ provider: string;
99
+ live_view_url: string | null;
100
+ }
101
+ export interface TabRow {
102
+ id: string;
103
+ url: string | null;
104
+ title: string | null;
105
+ active: boolean | null;
106
+ }
107
+ export interface BrowserState {
108
+ id: string;
109
+ computer_id: string | null;
110
+ provider: string;
111
+ profile_id: string | null;
112
+ live_view_url: string | null;
113
+ tabs: TabRow[];
114
+ }
115
+ /** POST /browsers/{id}/tabs — the new tab id is top-level. */
116
+ export interface TabOpenResponse extends ActionResult {
117
+ tab_id: string;
118
+ }
119
+ export interface ProfileCreateOptions {
120
+ /** The computer whose built-in browser profile to ensure. Omit for the space's stealth profile. */
121
+ computerId?: string;
122
+ name?: string;
123
+ }
124
+ export interface ProfileRow {
125
+ id: string;
126
+ name: string;
127
+ provider: string;
128
+ computer_id: string | null;
129
+ created_at: number;
130
+ }
131
+ export interface ProfileCreateResponse extends ProfileRow {
132
+ /** False when the durable profile already existed (create is an ensure). */
133
+ created: boolean;
134
+ }
@@ -0,0 +1,6 @@
1
+ // Wire types for the Kazzle computers and browsers REST API.
2
+ //
3
+ // Field names mirror the JSON the API returns (snake_case), so a response can
4
+ // be logged or forwarded without translation. Request options are camelCase
5
+ // and mapped to the wire shape inside the SDK.
6
+ export {};
@@ -0,0 +1,45 @@
1
+ export type ExecEvent = {
2
+ type: 'stdout';
3
+ text: string;
4
+ } | {
5
+ type: 'stderr';
6
+ text: string;
7
+ } | {
8
+ type: 'error';
9
+ error: string;
10
+ } | {
11
+ type: 'exit';
12
+ code: number;
13
+ };
14
+ export interface ExecResult {
15
+ /** Joined stdout (stderr is merged into stdout by the PTY). */
16
+ text: string;
17
+ exitCode: number;
18
+ }
19
+ /** The exec `error` frame: offline computer, spawn failure, or timeout. */
20
+ export declare class KazzleExecError extends Error {
21
+ readonly result: ExecResult;
22
+ constructor(message: string, result: ExecResult);
23
+ }
24
+ interface SseFrame {
25
+ event: string;
26
+ data: string;
27
+ }
28
+ /** Parse an SSE byte stream into frames. Handles frames split across chunks. */
29
+ export declare function parseSseStream(stream: ReadableStream<Uint8Array>): AsyncGenerator<SseFrame>;
30
+ /**
31
+ * The result of `kazzle.computers.exec()`: an async iterable of ExecEvents,
32
+ * plus `.text()` which drains the stream and resolves the joined stdout and
33
+ * exit code. Iterate OR call `.text()` — the underlying stream reads once.
34
+ */
35
+ export declare class ExecStream implements AsyncIterable<ExecEvent> {
36
+ private readonly response;
37
+ constructor(response: Promise<Response>);
38
+ [Symbol.asyncIterator](): AsyncIterator<ExecEvent>;
39
+ /**
40
+ * Drain the stream: joined stdout plus the exit code. Throws KazzleExecError
41
+ * when the server reports an `error` frame (offline, spawn failure, timeout).
42
+ */
43
+ text(): Promise<ExecResult>;
44
+ }
45
+ export {};
@@ -0,0 +1,112 @@
1
+ // Server-sent events parsing for `POST /computers/{id}/exec`.
2
+ //
3
+ // The exec endpoint streams `stdout` frames ({ text }), optional `error`
4
+ // frames ({ error }), then exactly one `exit` frame ({ code }). ExecStream
5
+ // exposes the frames as an async iterator plus a `.text()` convenience.
6
+ /** The exec `error` frame: offline computer, spawn failure, or timeout. */
7
+ export class KazzleExecError extends Error {
8
+ result;
9
+ constructor(message, result) {
10
+ super(message);
11
+ this.name = 'KazzleExecError';
12
+ this.result = result;
13
+ }
14
+ }
15
+ /** Parse an SSE byte stream into frames. Handles frames split across chunks. */
16
+ export async function* parseSseStream(stream) {
17
+ const decoder = new TextDecoder();
18
+ const reader = stream.getReader();
19
+ let buffer = '';
20
+ try {
21
+ while (true) {
22
+ const { done, value } = await reader.read();
23
+ if (done)
24
+ break;
25
+ buffer += decoder.decode(value, { stream: true });
26
+ let boundary;
27
+ while ((boundary = buffer.indexOf('\n\n')) !== -1) {
28
+ const raw = buffer.slice(0, boundary);
29
+ buffer = buffer.slice(boundary + 2);
30
+ const frame = parseFrame(raw);
31
+ if (frame)
32
+ yield frame;
33
+ }
34
+ }
35
+ const tail = parseFrame(buffer);
36
+ if (tail)
37
+ yield tail;
38
+ }
39
+ finally {
40
+ reader.releaseLock();
41
+ }
42
+ }
43
+ function parseFrame(raw) {
44
+ let event = 'message';
45
+ const data = [];
46
+ for (const line of raw.split('\n')) {
47
+ if (line.startsWith('event:'))
48
+ event = line.slice('event:'.length).trim();
49
+ else if (line.startsWith('data:'))
50
+ data.push(line.slice('data:'.length).trimStart());
51
+ }
52
+ if (data.length === 0)
53
+ return null;
54
+ return { event, data: data.join('\n') };
55
+ }
56
+ function toExecEvent(frame) {
57
+ const payload = JSON.parse(frame.data);
58
+ switch (frame.event) {
59
+ case 'stdout':
60
+ return { type: 'stdout', text: String(payload.text ?? '') };
61
+ case 'stderr':
62
+ return { type: 'stderr', text: String(payload.text ?? '') };
63
+ case 'error':
64
+ return { type: 'error', error: String(payload.error ?? 'Command failed') };
65
+ case 'exit':
66
+ return { type: 'exit', code: typeof payload.code === 'number' ? payload.code : -1 };
67
+ default:
68
+ return null;
69
+ }
70
+ }
71
+ /**
72
+ * The result of `kazzle.computers.exec()`: an async iterable of ExecEvents,
73
+ * plus `.text()` which drains the stream and resolves the joined stdout and
74
+ * exit code. Iterate OR call `.text()` — the underlying stream reads once.
75
+ */
76
+ export class ExecStream {
77
+ response;
78
+ constructor(response) {
79
+ this.response = response;
80
+ }
81
+ async *[Symbol.asyncIterator]() {
82
+ const response = await this.response;
83
+ if (!response.body)
84
+ throw new Error('Exec response has no body stream');
85
+ for await (const frame of parseSseStream(response.body)) {
86
+ const event = toExecEvent(frame);
87
+ if (event)
88
+ yield event;
89
+ }
90
+ }
91
+ /**
92
+ * Drain the stream: joined stdout plus the exit code. Throws KazzleExecError
93
+ * when the server reports an `error` frame (offline, spawn failure, timeout).
94
+ */
95
+ async text() {
96
+ const chunks = [];
97
+ let exitCode = -1;
98
+ let error;
99
+ for await (const event of this) {
100
+ if (event.type === 'stdout' || event.type === 'stderr')
101
+ chunks.push(event.text);
102
+ else if (event.type === 'exit')
103
+ exitCode = event.code;
104
+ else if (event.type === 'error')
105
+ error = event.error;
106
+ }
107
+ const result = { text: chunks.join(''), exitCode };
108
+ if (error)
109
+ throw new KazzleExecError(error, result);
110
+ return result;
111
+ }
112
+ }