tauri-kargo-tools 0.1.0 → 0.1.2

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/dist/api.ts ADDED
@@ -0,0 +1,218 @@
1
+ // dist/client.ts
2
+ import * as T from "./types";
3
+
4
+ export type FetchLike = (input: RequestInfo, init?: RequestInit) => Promise<Response>;
5
+
6
+ export interface ClientOptions {
7
+ /** Exemple: "http://127.0.0.1:5173" ; si absent, utilise 127.0.0.1:8080 */
8
+ baseUrl?: string;
9
+ /** Port à utiliser si baseUrl est omis */
10
+ port?: number | string;
11
+ /** En-têtes par défaut à ajouter à chaque requête */
12
+ headers?: Record<string, string>;
13
+ /** fetch custom (ex. node-fetch) si l’environnement ne fournit pas fetch */
14
+ fetchImpl?: FetchLike;
15
+ }
16
+
17
+ export class TauriKargoClient {
18
+ readonly baseUrl: string;
19
+ readonly headers: Record<string, string>;
20
+ private readonly fetchImpl: FetchLike;
21
+
22
+ constructor(opts: ClientOptions = {}) {
23
+ const port = opts.port ?? 8080;
24
+ this.baseUrl = opts.baseUrl ?? (opts.port ?`http://127.0.0.1:${port}`:'');
25
+ this.headers = opts.headers ?? {};
26
+ this.fetchImpl = opts.fetchImpl ?? (globalThis.fetch?.bind(globalThis) as FetchLike);
27
+ if (!this.fetchImpl) throw new Error("No fetch implementation available.");
28
+ }
29
+
30
+ /* =============== Helpers HTTP =============== */
31
+
32
+ private req(path: string, init: RequestInit): Promise<Response> {
33
+ const url = this.baseUrl + path;
34
+ const headers = { ...this.headers, ...(init.headers || {}) } as Record<string, string>;
35
+ return this.fetchImpl(url, { ...init, headers });
36
+ }
37
+
38
+ private async postJson<R>(path: string, body: unknown): Promise<R> {
39
+ const res = await this.req(path, {
40
+ method: "POST",
41
+ headers: { "content-type": "application/json" },
42
+ body: body == null ? undefined : JSON.stringify(body),
43
+ });
44
+ return this.parseJsonOrThrow<R>(res);
45
+ }
46
+
47
+ private async parseJsonOrThrow<R>(res: Response): Promise<R> {
48
+ if (!res.ok) {
49
+ const text = await this.safeText(res);
50
+ throw new Error(`HTTP ${res.status} ${res.statusText}: ${text}`);
51
+ }
52
+ const ct = res.headers.get("content-type") || "";
53
+ if (ct.includes("application/json")) {
54
+ return (await res.json()) as R;
55
+ }
56
+ // Tolérance: certains endpoints peuvent répondre text/plain en erreur
57
+ const text = await res.text();
58
+ try {
59
+ return JSON.parse(text) as R;
60
+ } catch {
61
+ throw new Error(`Unexpected content-type: ${ct || "unknown"}; body: ${text}`);
62
+ }
63
+ }
64
+
65
+ private async safeText(res: Response): Promise<string> {
66
+ try { return await res.text(); } catch { return "<no-body>"; }
67
+ }
68
+
69
+ /* =============== Routes: Embed =============== */
70
+
71
+ /** POST /api/embed */
72
+ embed(body: T.EmbedReqAny): Promise<T.EmbedResp> {
73
+ return this.postJson<T.EmbedResp>("/api/embed", body);
74
+ }
75
+
76
+ /* =============== Routes: Config =============== */
77
+
78
+ /** POST /api/useConfig */
79
+ useConfig(body: T.UseConfigReq): Promise<T.UseConfigResp> {
80
+ return this.postJson<T.UseConfigResp>("/api/useConfig", body);
81
+ }
82
+
83
+ /** POST /api/get-config */
84
+ getConfig(): Promise<T.GetConfigResp> {
85
+ return this.postJson<T.GetConfigResp>("/api/get-config", {});
86
+ }
87
+
88
+ /* =============== Routes: Files =============== */
89
+
90
+ /** POST /api/current-directory */
91
+ setCurrentDirectory(body: T.CurrentDirReq): Promise<T.CurrentDirResp> {
92
+ return this.postJson<T.CurrentDirResp>("/api/current-directory", body);
93
+ }
94
+
95
+ /**
96
+ * Lire un fichier texte relatif au répertoire courant.
97
+ * (POST sans corps ⇒ READ ; renvoie text/plain ou octet-stream)
98
+ */
99
+ async readFileText(file: string, encoding: string = "utf-8"): Promise<string> {
100
+ const res = await this.req(`/api/file/${encodeURIComponent(file)}`, { method: "POST" });
101
+ if (!res.ok) throw new Error(`READ ${file} failed: ${res.status} ${await this.safeText(res)}`);
102
+ const ct = res.headers.get("content-type") || "";
103
+ if (ct.includes("application/octet-stream")) {
104
+ const buf = await res.arrayBuffer();
105
+ return new TextDecoder(encoding).decode(buf);
106
+ }
107
+ return res.text();
108
+ }
109
+
110
+ /** Lire un fichier binaire */
111
+ async readFileBinary(file: string): Promise<ArrayBuffer> {
112
+ const res = await this.req(`/api/file/${encodeURIComponent(file)}`, { method: "POST" });
113
+ if (!res.ok) throw new Error(`READ ${file} failed: ${res.status} ${await this.safeText(res)}`);
114
+ return res.arrayBuffer();
115
+ }
116
+
117
+ /** Écrire un fichier texte (UTF-8) */
118
+ async writeFileText(file: string, content: string): Promise<T.FileWriteResp> {
119
+ const res = await this.req(`/api/file/${encodeURIComponent(file)}`, {
120
+ method: "POST",
121
+ headers: { "content-type": "text/plain; charset=utf-8" },
122
+ body: content,
123
+ });
124
+ return this.parseJsonOrThrow<T.FileWriteResp>(res);
125
+ }
126
+
127
+ /** Écrire un fichier binaire */
128
+ async writeFileBinary(
129
+ file: string,
130
+ data: Blob
131
+ ): Promise<T.FileWriteResp> {
132
+ // Normalise en Blob (OK WebView2/WebKit/Chromium)
133
+ const blob = data
134
+
135
+ const res = await fetch(`${this.baseUrl}/api/file/${encodeURIComponent(file)}`, {
136
+ method: "POST",
137
+ // Laisser fetch gérer le Content-Length; Content-Type vient du blob
138
+ headers: { "content-type": blob.type || "application/octet-stream" },
139
+ body: blob,
140
+ });
141
+
142
+ if (!res.ok) {
143
+ const text = await res.text().catch(() => "<no-body>");
144
+ throw new Error(`WRITE ${file} failed: ${res.status} ${text}`);
145
+ }
146
+
147
+ // La route renvoie du JSON en cas d’écriture
148
+ const ct = res.headers.get("content-type") || "";
149
+ if (ct.includes("application/json")) {
150
+ return (await res.json()) as T.FileWriteResp;
151
+ }
152
+ // Fallback s'il répond "text/plain" avec un JSON sérialisé
153
+ return JSON.parse(await res.text()) as T.FileWriteResp;
154
+ }
155
+
156
+ /** DELETE /api/file/{file} */
157
+ async deleteFile(file: string): Promise<T.FileDeleteResp> {
158
+ const res = await this.req(`/api/file/${encodeURIComponent(file)}`, { method: "DELETE" });
159
+ return this.parseJsonOrThrow<T.FileDeleteResp>(res);
160
+ // En cas d'erreur 4xx/5xx, parseJsonOrThrow lève déjà une exception
161
+ }
162
+
163
+ /* =============== Routes: Run (process) =============== */
164
+
165
+ /** POST /api/run */
166
+ run(body: T.RunReq): Promise<T.RunResp> {
167
+ return this.postJson<T.RunResp>("/api/run", body);
168
+ }
169
+
170
+ /** POST /api/run/status */
171
+ runStatus(body: T.ProcIdReq): Promise<T.ProcStatusResp> {
172
+ return this.postJson<T.ProcStatusResp>("/api/run/status", body);
173
+ }
174
+
175
+ /** POST /api/run/stop */
176
+ runStop(body: T.ProcIdReq): Promise<T.ProcStopResp> {
177
+ return this.postJson<T.ProcStopResp>("/api/run/stop", body);
178
+ }
179
+
180
+ /** POST /api/run/stopAll */
181
+ runStopAll(): Promise<T.StopAllResp> {
182
+ return this.postJson<T.StopAllResp>("/api/run/stopAll", {});
183
+ }
184
+
185
+ /* =============== Routes: Explorer =============== */
186
+
187
+ /** POST /api/explorer */
188
+ explorer(body: T.ExplorerReq): Promise<T.ExplorerResult> {
189
+ return this.postJson<T.ExplorerResult>("/api/explorer", body);
190
+ }
191
+
192
+ /* =============== Routes: Servers =============== */
193
+
194
+ /** POST /api/newServer */
195
+ newServer(body: T.NewServerReq): Promise<T.NewServerResp> {
196
+ return this.postJson<T.NewServerResp>("/api/newServer", body);
197
+ }
198
+
199
+ /** POST /api/stop */
200
+ stopServer(body: T.StopServerReq = {}): Promise<T.StopServerResp> {
201
+ return this.postJson<T.StopServerResp>("/api/stop", body);
202
+ }
203
+ }
204
+
205
+ /* =============== Petit helper factory =============== */
206
+ export function createClient(opts?: ClientOptions) {
207
+ return new TauriKargoClient(opts);
208
+ }
209
+
210
+ /* =============== Exemple d'usage =============== */
211
+ /*
212
+ const api = createClient({ port: 5173 });
213
+ await api.useConfig({ code: "C:/code", executable: "C:/bin" });
214
+ const txt = await api.readFileText("README.md");
215
+ await api.writeFileText("out.txt", "hello");
216
+ const run = await api.run({ executableName: "mytool", arguments: ["--help"] });
217
+ const st = await api.runStatus({ id: run.id! });
218
+ */
package/dist/test.ts ADDED
@@ -0,0 +1,324 @@
1
+ // test.ts — mini runner front sans dépendances.
2
+ // Usage:
3
+ // import { test } from "./test.ts";
4
+ // test("grammar compiles", () => { assertEquals(typeof parser.parse, "function"); });
5
+ // test("examples parse to expected AST", async (t) => {
6
+ // for (let i = 0; i < tests.length; i++) {
7
+ // const tc = tests[i];
8
+ // await t.step(`case #${i + 1}`, () => {
9
+ // const got = parser.parse(tc.source);
10
+ // assertEquals(got, tc.prog);
11
+ // });
12
+ // }
13
+ // });
14
+
15
+ type StepFn = () => void | Promise<void>;
16
+ type TestFn = (t: { step: (name: string, fn: StepFn) => Promise<void> }) => void | Promise<void>;
17
+
18
+ function ensureRoot(): HTMLElement {
19
+ const id = "test-root";
20
+ let el = document.getElementById(id);
21
+ if (!el) {
22
+ el = document.createElement("div");
23
+ el.id = id;
24
+ el.style.cssText = "font-family: ui-sans-serif, system-ui, Arial; line-height:1.4; padding:16px;";
25
+ document.body.appendChild(el);
26
+ }
27
+ return el;
28
+ }
29
+
30
+ function createTestBlock(name: string): { block: HTMLElement; header: HTMLElement; list: HTMLUListElement } {
31
+ const root = ensureRoot();
32
+
33
+ const block = document.createElement("section");
34
+ block.style.cssText = "margin: 12px 0; padding: 12px; border: 1px solid #ddd; border-radius: 8px;";
35
+
36
+ const header = document.createElement("h3");
37
+ header.textContent = `Test: ${name}`;
38
+ header.style.cssText = "margin: 0 0 8px 0; font-size: 16px;";
39
+
40
+ const list = document.createElement("ul");
41
+ list.style.cssText = "margin: 8px 0 0 16px; padding: 0;";
42
+
43
+ block.appendChild(header);
44
+ block.appendChild(list);
45
+ root.appendChild(block);
46
+
47
+ return { block, header, list };
48
+ }
49
+
50
+ function formatError(e: unknown): string {
51
+ if (e instanceof Error) return e.stack || `${e.name}: ${e.message}`;
52
+ try { return JSON.stringify(e); } catch { return String(e); }
53
+ }
54
+
55
+ export function test(name: string, fn: TestFn): void {
56
+ const { block, header, list } = createTestBlock(name);
57
+
58
+ // status badge
59
+ const status = document.createElement("span");
60
+ status.textContent = "⏳ running…";
61
+ status.style.cssText = "margin-left: 8px; font-size: 12px; color: #555;";
62
+ header.appendChild(status);
63
+
64
+ // Collect step results
65
+ let failed = false;
66
+
67
+ const t = {
68
+ step: async (stepName: string, stepFn: StepFn): Promise<void> => {
69
+ const li = document.createElement("li");
70
+ li.style.cssText = "margin: 4px 0;";
71
+ li.textContent = `• ${stepName}: `;
72
+ const badge = document.createElement("span");
73
+ badge.style.marginLeft = "4px";
74
+ li.appendChild(badge);
75
+ list.appendChild(li);
76
+
77
+ try {
78
+ await stepFn();
79
+ badge.textContent = "✅ ok";
80
+ badge.style.color = "#1a7f37";
81
+ } catch (e) {
82
+ failed = true;
83
+ badge.textContent = "❌ fail";
84
+ badge.style.color = "#c62828";
85
+ const pre = document.createElement("pre");
86
+ pre.style.cssText = "white-space: pre-wrap; background:#fff5f5; border:1px solid #f0caca; padding:8px; border-radius:6px; margin:6px 0 0 0;";
87
+ pre.textContent = formatError(e);
88
+ li.appendChild(pre);
89
+ }
90
+ },
91
+ };
92
+
93
+ // Run test (and implicit single-step if user didn’t use t.step)
94
+ (async () => {
95
+ let usedStep = false;
96
+
97
+ // Proxy t.step to detect usage
98
+ const proxiedT = {
99
+ step: async (n: string, f: StepFn) => {
100
+ usedStep = true;
101
+ return t.step(n, f);
102
+ },
103
+ };
104
+
105
+ try {
106
+ const r = fn(proxiedT);
107
+ if (r instanceof Promise) await r;
108
+
109
+ if (!usedStep) {
110
+ // Wrap whole test as one step
111
+ await t.step("default", async () => {
112
+ // re-run nothing; the body has already executed
113
+ // but we still need to mark success
114
+ });
115
+ }
116
+ } catch (e) {
117
+ failed = true;
118
+ // show top-level failure as a step
119
+ await t.step("default", () => { throw e; }).catch(() => void 0);
120
+ } finally {
121
+ if (failed) {
122
+ status.textContent = "❌ failed";
123
+ status.style.color = "#c62828";
124
+ block.style.borderColor = "#f19999";
125
+ } else {
126
+ status.textContent = "✅ passed";
127
+ status.style.color = "#1a7f37";
128
+ block.style.borderColor = "#9fd3a7";
129
+ }
130
+ }
131
+ })();
132
+ }
133
+
134
+
135
+ // assert.ts
136
+ // Usage (Deno):
137
+ // import { assertEquals } from "./assert.ts";
138
+ // Deno.test("ex", () => assertEquals(parse("..."), expected));
139
+
140
+ // ————— Deep equality —————
141
+ function isTypedArray(x: unknown): x is
142
+ | Int8Array | Uint8Array | Uint8ClampedArray
143
+ | Int16Array | Uint16Array
144
+ | Int32Array | Uint32Array
145
+ | Float32Array | Float64Array
146
+ | BigInt64Array | BigUint64Array {
147
+ return ArrayBuffer.isView(x) && !(x instanceof DataView);
148
+ }
149
+
150
+ function sameValueZero(a: unknown, b: unknown): boolean {
151
+ // SameValueZero: like === but NaN equals NaN, and +0/-0 considered equal
152
+ return (a === b) || (Number.isNaN(a as number) && Number.isNaN(b as number));
153
+ }
154
+
155
+ function isPlainObject(x: unknown): x is Record<string, unknown> {
156
+ if (x === null || typeof x !== "object") return false;
157
+ const proto = Object.getPrototypeOf(x);
158
+ return proto === Object.prototype || proto === null;
159
+ }
160
+
161
+ export function deepEqual(a: unknown, b: unknown, seen = new Map<any, any>()): boolean {
162
+ if (sameValueZero(a, b)) return true;
163
+
164
+ // Handle null vs objects/types quickly
165
+ if (a === null || b === null) return false;
166
+
167
+ const ta = typeof a;
168
+ const tb = typeof b;
169
+ if (ta !== "object" && tb !== "object") return false; // two different primitives
170
+ if (ta !== tb) return false;
171
+
172
+ // Cycle handling
173
+ if (typeof a === "object" && typeof b === "object") {
174
+ const prev = seen.get(a);
175
+ if (prev && prev === b) return true;
176
+ seen.set(a, b);
177
+ }
178
+
179
+ // Dates
180
+ if (a instanceof Date || b instanceof Date) {
181
+ return a instanceof Date && b instanceof Date && a.getTime() === b.getTime();
182
+ }
183
+
184
+ // RegExp
185
+ if (a instanceof RegExp || b instanceof RegExp) {
186
+ return a instanceof RegExp && b instanceof RegExp &&
187
+ a.source === b.source && a.flags === b.flags;
188
+ }
189
+
190
+ // Typed arrays
191
+ if (isTypedArray(a) || isTypedArray(b)) {
192
+ if (!isTypedArray(a) || !isTypedArray(b)) return false;
193
+ if (Object.getPrototypeOf(a).constructor !== Object.getPrototypeOf(b).constructor) return false;
194
+ if (a.length !== b.length) return false;
195
+ for (let i = 0; i < a.length; i++) {
196
+ if (!sameValueZero(a[i], b[i])) return false;
197
+ }
198
+ return true;
199
+ }
200
+
201
+ // Array
202
+ if (Array.isArray(a) || Array.isArray(b)) {
203
+ if (!Array.isArray(a) || !Array.isArray(b)) return false;
204
+ if (a.length !== b.length) return false;
205
+ for (let i = 0; i < a.length; i++) {
206
+ if (!deepEqual(a[i], b[i], seen)) return false;
207
+ }
208
+ return true;
209
+ }
210
+
211
+ // Set
212
+ if (a instanceof Set || b instanceof Set) {
213
+ if (!(a instanceof Set) || !(b instanceof Set)) return false;
214
+ if (a.size !== b.size) return false;
215
+ // Compare as multisets with deep equality
216
+ const used = new Array<boolean>(b.size).fill(false);
217
+ const bArr = Array.from(b);
218
+ outer: for (const av of a) {
219
+ for (let i = 0; i < bArr.length; i++) {
220
+ if (!used[i] && deepEqual(av, bArr[i], seen)) {
221
+ used[i] = true;
222
+ continue outer;
223
+ }
224
+ }
225
+ return false;
226
+ }
227
+ return true;
228
+ }
229
+
230
+ // Map
231
+ if (a instanceof Map || b instanceof Map) {
232
+ if (!(a instanceof Map) || !(b instanceof Map)) return false;
233
+ if (a.size !== b.size) return false;
234
+ // For each entry in a, find deep-equal key in b, then compare values
235
+ const bEntries = Array.from(b.entries());
236
+ const used = new Array<boolean>(bEntries.length).fill(false);
237
+ outerMap: for (const [ak, av] of a.entries()) {
238
+ for (let i = 0; i < bEntries.length; i++) {
239
+ if (used[i]) continue;
240
+ const [bk, bv] = bEntries[i];
241
+ if (deepEqual(ak, bk, seen) && deepEqual(av, bv, seen)) {
242
+ used[i] = true;
243
+ continue outerMap;
244
+ }
245
+ }
246
+ return false;
247
+ }
248
+ return true;
249
+ }
250
+
251
+ // Plain objects
252
+ if (isPlainObject(a) || isPlainObject(b)) {
253
+ if (!isPlainObject(a) || !isPlainObject(b)) return false;
254
+ const ka = Object.keys(a as Record<string, unknown>);
255
+ const kb = Object.keys(b as Record<string, unknown>);
256
+ if (ka.length !== kb.length) return false;
257
+ // keys order-insensitive
258
+ ka.sort(); kb.sort();
259
+ for (let i = 0; i < ka.length; i++) {
260
+ if (ka[i] !== kb[i]) return false;
261
+ }
262
+ for (const k of ka) {
263
+ if (!deepEqual((a as any)[k], (b as any)[k], seen)) return false;
264
+ }
265
+ return true;
266
+ }
267
+
268
+ // Fallback for objects with prototypes/functions/etc.
269
+ // Compare own enumerable props + constructor
270
+ if (typeof a === "object" && typeof b === "object") {
271
+ if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return false;
272
+ const ka = Object.keys(a as any);
273
+ const kb = Object.keys(b as any);
274
+ if (ka.length !== kb.length) return false;
275
+ for (const k of ka) {
276
+ if (!(k in (b as any))) return false;
277
+ if (!deepEqual((a as any)[k], (b as any)[k], seen)) return false;
278
+ }
279
+ return true;
280
+ }
281
+
282
+ return false;
283
+ }
284
+
285
+ // ————— Pretty printers —————
286
+ function safeStringify(v: unknown, maxDepth = 10): string {
287
+ const seen = new WeakSet<object>();
288
+ function helper(x: unknown, depth: number): unknown {
289
+ if (depth <= 0) return "[Object]";
290
+ if (x && typeof x === "object") {
291
+ if (seen.has(x as object)) return "[Circular]";
292
+ seen.add(x as object);
293
+ if (Array.isArray(x)) return (x as unknown[]).map((e) => helper(e, depth - 1));
294
+ if (x instanceof Map) return { __map__: Array.from(x.entries()).map(([k, val]) => [helper(k, depth - 1), helper(val, depth - 1)]) };
295
+ if (x instanceof Set) return { __set__: Array.from(x.values()).map((e) => helper(e, depth - 1)) };
296
+ if (x instanceof Date) return { __date__: (x as Date).toISOString() };
297
+ if (x instanceof RegExp) return { __regexp__: x.toString() };
298
+ if (ArrayBuffer.isView(x)) return { __typedarray__: Object.getPrototypeOf(x).constructor.name, values: Array.from(x as any) };
299
+ const out: Record<string, unknown> = {};
300
+ for (const k of Object.keys(x as Record<string, unknown>)) {
301
+ out[k] = helper((x as any)[k], depth - 1);
302
+ }
303
+ return out;
304
+ }
305
+ if (typeof x === "number" && Number.isNaN(x)) return "NaN";
306
+ if (Object.is(x, -0)) return "-0";
307
+ return x as any;
308
+ }
309
+ try {
310
+ return JSON.stringify(helper(v, maxDepth), null, 2);
311
+ } catch {
312
+ return String(v);
313
+ }
314
+ }
315
+
316
+ // ————— Public assert —————
317
+ export function assertEquals(actual: unknown, expected: unknown, msg?: string): void {
318
+ if (deepEqual(actual, expected)) return;
319
+ const aStr = safeStringify(actual);
320
+ const eStr = safeStringify(expected);
321
+ const defaultMsg = `assertEquals failed:\nExpected:\n${eStr}\nActual:\n${aStr}`;
322
+ throw new Error(msg ? `${msg}\n${defaultMsg}` : defaultMsg);
323
+ }
324
+
package/dist/types.ts ADDED
@@ -0,0 +1,178 @@
1
+ /** OpenAPI: 3.0.3 — Tauri Static Server API — v1.0.0 */
2
+
3
+ /* =========================
4
+ Schemas (components)
5
+ ========================= */
6
+
7
+ export interface EmbedReqAny {
8
+ /** Code folder to package (required server-side) */
9
+ code: string | null;
10
+ /** Binary folder to package */
11
+ executable: string | null;
12
+ /** Path of the new executable */
13
+ output: string;
14
+ }
15
+
16
+ export interface EmbedResp {
17
+ ok: boolean;
18
+ message: string;
19
+ }
20
+
21
+ export interface UseConfigReq {
22
+ code: string;
23
+ executable: string;
24
+ }
25
+
26
+ export interface UseConfigResp {
27
+ ok: boolean;
28
+ message: string;
29
+ }
30
+
31
+ export interface GetConfigResp {
32
+ ok: boolean;
33
+ code: string;
34
+ executable: string;
35
+ fileBase: string;
36
+ }
37
+
38
+ export interface CurrentDirReq {
39
+ /** Absolute or relative path. Empty ⇒ CWD. */
40
+ path: string;
41
+ }
42
+
43
+ export interface CurrentDirResp {
44
+ ok: boolean;
45
+ message: string;
46
+ current: string;
47
+ }
48
+
49
+ export interface FileWriteResp {
50
+ ok: boolean;
51
+ message: string;
52
+ path: string;
53
+ }
54
+
55
+ export interface FileDeleteResp {
56
+ ok: boolean;
57
+ message: string;
58
+ path: string;
59
+ }
60
+
61
+ export interface RunReq {
62
+ executableName: string;
63
+ /** Either an argv array or a single command-line string */
64
+ arguments?: string[] | string;
65
+ }
66
+
67
+ export interface RunResp {
68
+ ok: boolean;
69
+ /** exit status code (when available) */
70
+ status?: number | null;
71
+ message: string;
72
+ stdout?: string;
73
+ stderr?: string;
74
+ /** internal id of started process */
75
+ id?: number | null; // int64 → number
76
+ /** OS pid (when available) */
77
+ pid?: number | null;
78
+ }
79
+
80
+ export interface ProcIdReq {
81
+ id: number; // int64
82
+ }
83
+
84
+ export interface ProcStatusResp {
85
+ ok: boolean;
86
+ running: boolean;
87
+ status?: number | null;
88
+ pid?: number | null;
89
+ stdout: string;
90
+ stderr: string;
91
+ message: string;
92
+ }
93
+
94
+ export interface ProcStopResp {
95
+ ok: boolean;
96
+ message: string;
97
+ }
98
+
99
+ export interface StopAllResp {
100
+ ok: boolean;
101
+ message: string;
102
+ }
103
+
104
+ export interface ExplorerReq {
105
+ path?: string;
106
+ }
107
+
108
+ export type ExplorerElement = ExplorerDirectory | ExplorerFile
109
+
110
+ export interface ExplorerFile {
111
+ type: "file";
112
+ path: string;
113
+ name: string;
114
+ parent: string | null;
115
+ }
116
+
117
+ export interface ExplorerDirectory {
118
+ type: "directory";
119
+ path: string;
120
+ parent: string | null;
121
+ content: ExplorerElement[];
122
+ }
123
+
124
+ export interface ExplorerError {
125
+ type: "error";
126
+ message: string;
127
+ }
128
+
129
+ export interface NewServerReq {
130
+ code: string;
131
+ executable: string;
132
+ /** 0..65535 (nullable) */
133
+ port?: number | null;
134
+ }
135
+
136
+ export interface NewServerResp {
137
+ ok: boolean;
138
+ port?: number | null;
139
+ message: string;
140
+ }
141
+
142
+ export interface StopServerReq {
143
+ /** if omitted, targets current server (parent) */
144
+ port?: number | null;
145
+ }
146
+
147
+ export interface StopServerResp {
148
+ ok: boolean;
149
+ port?: number | null;
150
+ message: string;
151
+ }
152
+
153
+ /* =========================
154
+ Helper union types
155
+ ========================= */
156
+
157
+ /** Result of /api/explorer (200) */
158
+ export type ExplorerResult = ExplorerFile | ExplorerDirectory;
159
+
160
+ /** Error shapes from /api/explorer (404/500) */
161
+ export type ExplorerErrorResult = ExplorerError;
162
+
163
+ /* =========================
164
+ (Optionnel) Types d’IO par route
165
+ — utiles si tu veux typer ton client HTTP
166
+ ========================= */
167
+
168
+ /* =========================
169
+ (Optionnel) Types utilitaires client
170
+ ========================= */
171
+
172
+ export type Json =
173
+ | null
174
+ | boolean
175
+ | number
176
+ | string
177
+ | Json[]
178
+ | { [k: string]: Json };
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "tauri-kargo-tools",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
8
- },
5
+ "files": ["dist"],
6
+ "exports": { "./*": "./dist/*" },
7
+ "publishConfig": { "access": "public" },
9
8
  "repository": {
10
9
  "type": "git",
11
10
  "url": "git+https://github.com/blockapicoder/tauriKargoTools.git"