@parcae/sdk 0.4.0 → 0.4.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/chunk-LGUSPLZM.js +866 -0
- package/dist/chunk-LGUSPLZM.js.map +1 -0
- package/dist/{client-CeIUZzoo.d.ts → client-0OLcV8PA.d.ts} +4 -4
- package/dist/index.d.ts +26 -26
- package/dist/index.js +1 -1
- package/dist/react/index.d.ts +10 -12
- package/dist/react/index.js +110 -96
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-KFISHMU4.js +0 -386
- package/dist/chunk-KFISHMU4.js.map +0 -1
package/dist/chunk-KFISHMU4.js
DELETED
|
@@ -1,386 +0,0 @@
|
|
|
1
|
-
import SocketIO from 'socket.io-client';
|
|
2
|
-
import pako from 'pako';
|
|
3
|
-
import { decompress } from 'compress-json';
|
|
4
|
-
import { EventEmitter } from 'eventemitter3';
|
|
5
|
-
import ShortId from 'short-unique-id';
|
|
6
|
-
import { Model, FrontendAdapter } from '@parcae/model';
|
|
7
|
-
|
|
8
|
-
// src/auth-gate.ts
|
|
9
|
-
var AuthGate = class {
|
|
10
|
-
_state = "pending";
|
|
11
|
-
_resolve = null;
|
|
12
|
-
_promise;
|
|
13
|
-
constructor() {
|
|
14
|
-
this._promise = this._makePending();
|
|
15
|
-
}
|
|
16
|
-
get state() {
|
|
17
|
-
return this._state;
|
|
18
|
-
}
|
|
19
|
-
get ready() {
|
|
20
|
-
return this._promise;
|
|
21
|
-
}
|
|
22
|
-
resolve() {
|
|
23
|
-
this._state = "ready";
|
|
24
|
-
if (this._resolve) {
|
|
25
|
-
this._resolve();
|
|
26
|
-
this._resolve = null;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
reset() {
|
|
30
|
-
if (this._state === "ready") {
|
|
31
|
-
this._state = "pending";
|
|
32
|
-
this._promise = this._makePending();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
_makePending() {
|
|
36
|
-
return new Promise((r) => {
|
|
37
|
-
this._resolve = r;
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
var uid = new ShortId({ length: 10 });
|
|
42
|
-
var SocketTransport = class extends EventEmitter {
|
|
43
|
-
auth = new AuthGate();
|
|
44
|
-
isConnected = false;
|
|
45
|
-
isLoading = false;
|
|
46
|
-
userId = null;
|
|
47
|
-
socket;
|
|
48
|
-
url;
|
|
49
|
-
version;
|
|
50
|
-
inflight = /* @__PURE__ */ new Map();
|
|
51
|
-
constructor(config) {
|
|
52
|
-
super();
|
|
53
|
-
this.url = config.url;
|
|
54
|
-
this.version = config.version ?? "v1";
|
|
55
|
-
this.socket = SocketIO(this.url, {
|
|
56
|
-
path: config.path ?? "/ws",
|
|
57
|
-
transports: ["websocket"],
|
|
58
|
-
withCredentials: true
|
|
59
|
-
});
|
|
60
|
-
this.socket.on("connect", () => {
|
|
61
|
-
const wasConnected = this.isConnected;
|
|
62
|
-
this.isConnected = true;
|
|
63
|
-
this.emit(wasConnected ? "reconnected" : "connected");
|
|
64
|
-
});
|
|
65
|
-
this.socket.on("disconnect", () => {
|
|
66
|
-
this.isConnected = false;
|
|
67
|
-
this.auth.reset();
|
|
68
|
-
this.emit("disconnected");
|
|
69
|
-
});
|
|
70
|
-
this.socket.on("error", (err) => {
|
|
71
|
-
this.emit("error", err);
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
// ── Authenticate ──────────────────────────────────────────────────
|
|
75
|
-
/**
|
|
76
|
-
* Authenticate with the backend. Resolves the AuthGate when done.
|
|
77
|
-
*
|
|
78
|
-
* - token=string → send to server, wait for confirmation
|
|
79
|
-
* - token=null → no auth, resolve gate immediately (unauthenticated)
|
|
80
|
-
*/
|
|
81
|
-
async authenticate(token) {
|
|
82
|
-
this.auth.reset();
|
|
83
|
-
this.userId = null;
|
|
84
|
-
if (!token) {
|
|
85
|
-
this.auth.resolve();
|
|
86
|
-
return { userId: null };
|
|
87
|
-
}
|
|
88
|
-
if (!this.socket.connected) {
|
|
89
|
-
await new Promise((resolve) => {
|
|
90
|
-
if (this.socket.connected) return resolve();
|
|
91
|
-
this.socket.once("connect", () => resolve());
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
return new Promise((resolve) => {
|
|
95
|
-
this.socket.emit("authenticate", token, (response) => {
|
|
96
|
-
this.userId = response?.userId ?? null;
|
|
97
|
-
this.auth.resolve();
|
|
98
|
-
resolve({ userId: this.userId });
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
// ── Request/Response ──────────────────────────────────────────────
|
|
103
|
-
async fetch(method, path, data = {}) {
|
|
104
|
-
await this.auth.ready;
|
|
105
|
-
if (!this.socket.connected) {
|
|
106
|
-
await new Promise((resolve, reject) => {
|
|
107
|
-
if (this.socket.connected) return resolve();
|
|
108
|
-
const timeout = setTimeout(() => {
|
|
109
|
-
cleanup();
|
|
110
|
-
reject(new Error("Connection timeout"));
|
|
111
|
-
}, 3e4);
|
|
112
|
-
const onConnect = () => {
|
|
113
|
-
cleanup();
|
|
114
|
-
resolve();
|
|
115
|
-
};
|
|
116
|
-
const onError = (err) => {
|
|
117
|
-
cleanup();
|
|
118
|
-
reject(err);
|
|
119
|
-
};
|
|
120
|
-
const cleanup = () => {
|
|
121
|
-
clearTimeout(timeout);
|
|
122
|
-
this.socket.off("connect", onConnect);
|
|
123
|
-
this.socket.off("connect_error", onError);
|
|
124
|
-
};
|
|
125
|
-
this.socket.once("connect", onConnect);
|
|
126
|
-
this.socket.once("connect_error", onError);
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
const upper = method.toUpperCase();
|
|
130
|
-
if (upper === "GET") {
|
|
131
|
-
const dedupeKey = `${path}:${JSON.stringify(data)}`;
|
|
132
|
-
const existing = this.inflight.get(dedupeKey);
|
|
133
|
-
if (existing) return existing;
|
|
134
|
-
const req = this._call(method, path, data);
|
|
135
|
-
this.inflight.set(dedupeKey, req);
|
|
136
|
-
req.finally(() => this.inflight.delete(dedupeKey));
|
|
137
|
-
return req;
|
|
138
|
-
}
|
|
139
|
-
return this._call(method, path, data);
|
|
140
|
-
}
|
|
141
|
-
_call(method, path, data) {
|
|
142
|
-
const id = uid.rnd();
|
|
143
|
-
return new Promise((resolve, reject) => {
|
|
144
|
-
const timeout = setTimeout(() => {
|
|
145
|
-
this.socket.off(id);
|
|
146
|
-
reject(new Error(`RPC timeout: ${method} ${path}`));
|
|
147
|
-
}, 3e4);
|
|
148
|
-
this.socket.once(id, (msg) => {
|
|
149
|
-
clearTimeout(timeout);
|
|
150
|
-
try {
|
|
151
|
-
const uncompressed = pako.ungzip(msg, { to: "string" });
|
|
152
|
-
const parsed = decompress(JSON.parse(uncompressed));
|
|
153
|
-
if (parsed.success) {
|
|
154
|
-
resolve(parsed.result);
|
|
155
|
-
} else {
|
|
156
|
-
reject(
|
|
157
|
-
new Error(
|
|
158
|
-
parsed.message || parsed.error || `${method} ${path} failed`
|
|
159
|
-
)
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
} catch (err) {
|
|
163
|
-
reject(err);
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
this.socket.emit(
|
|
167
|
-
"call",
|
|
168
|
-
id,
|
|
169
|
-
method.toUpperCase(),
|
|
170
|
-
`/${this.version}${path}`,
|
|
171
|
-
data
|
|
172
|
-
);
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
async get(path, data) {
|
|
176
|
-
return this.fetch("GET", path, data);
|
|
177
|
-
}
|
|
178
|
-
async post(path, data) {
|
|
179
|
-
return this.fetch("POST", path, data);
|
|
180
|
-
}
|
|
181
|
-
async put(path, data) {
|
|
182
|
-
return this.fetch("PUT", path, data);
|
|
183
|
-
}
|
|
184
|
-
async patch(path, data) {
|
|
185
|
-
return this.fetch("PATCH", path, data);
|
|
186
|
-
}
|
|
187
|
-
async delete(path, data) {
|
|
188
|
-
return this.fetch("DELETE", path, data);
|
|
189
|
-
}
|
|
190
|
-
// ── Subscriptions ─────────────────────────────────────────────────
|
|
191
|
-
subscribe(event, handler) {
|
|
192
|
-
this.socket.on(event, handler);
|
|
193
|
-
return () => this.socket.off(event, handler);
|
|
194
|
-
}
|
|
195
|
-
unsubscribe(event, handler) {
|
|
196
|
-
this.socket.off(event, handler);
|
|
197
|
-
}
|
|
198
|
-
// ── Control ───────────────────────────────────────────────────────
|
|
199
|
-
async send(event, ...args) {
|
|
200
|
-
await this.auth.ready;
|
|
201
|
-
this.socket.emit(event, ...args);
|
|
202
|
-
}
|
|
203
|
-
// ── Lifecycle ─────────────────────────────────────────────────────
|
|
204
|
-
disconnect() {
|
|
205
|
-
this.socket.disconnect();
|
|
206
|
-
this.isConnected = false;
|
|
207
|
-
}
|
|
208
|
-
async reconnect() {
|
|
209
|
-
this.socket.connect();
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
var SSETransport = class extends EventEmitter {
|
|
213
|
-
url;
|
|
214
|
-
version;
|
|
215
|
-
apiKey;
|
|
216
|
-
key = null;
|
|
217
|
-
eventSources = /* @__PURE__ */ new Map();
|
|
218
|
-
isConnected = true;
|
|
219
|
-
// HTTP is "always connected"
|
|
220
|
-
isLoading = true;
|
|
221
|
-
loading;
|
|
222
|
-
constructor(config) {
|
|
223
|
-
super();
|
|
224
|
-
this.url = config.url.replace(/\/$/, "");
|
|
225
|
-
this.version = config.version ?? "v1";
|
|
226
|
-
this.apiKey = config.key ?? null;
|
|
227
|
-
this.loading = this.resolveKey();
|
|
228
|
-
}
|
|
229
|
-
async resolveKey() {
|
|
230
|
-
try {
|
|
231
|
-
this.key = typeof this.apiKey === "function" ? await this.apiKey() : this.apiKey;
|
|
232
|
-
this.isLoading = false;
|
|
233
|
-
this.emit("connected");
|
|
234
|
-
} catch (err) {
|
|
235
|
-
this.isLoading = false;
|
|
236
|
-
this.emit("error", err);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
headers() {
|
|
240
|
-
const h = { "Content-Type": "application/json" };
|
|
241
|
-
if (this.key) h["Authorization"] = `Bearer ${this.key}`;
|
|
242
|
-
return h;
|
|
243
|
-
}
|
|
244
|
-
fullUrl(path) {
|
|
245
|
-
return `${this.url}/${this.version}${path}`;
|
|
246
|
-
}
|
|
247
|
-
// ── Request/Response ──────────────────────────────────────────────────
|
|
248
|
-
async request(method, path, data) {
|
|
249
|
-
await this.loading;
|
|
250
|
-
const isGet = method.toUpperCase() === "GET";
|
|
251
|
-
let url = this.fullUrl(path);
|
|
252
|
-
if (isGet && data) {
|
|
253
|
-
const params = new URLSearchParams();
|
|
254
|
-
for (const [k, v] of Object.entries(data)) {
|
|
255
|
-
params.set(k, typeof v === "object" ? JSON.stringify(v) : String(v));
|
|
256
|
-
}
|
|
257
|
-
url += `?${params.toString()}`;
|
|
258
|
-
}
|
|
259
|
-
const res = await fetch(url, {
|
|
260
|
-
method: method.toUpperCase(),
|
|
261
|
-
headers: this.headers(),
|
|
262
|
-
body: isGet ? void 0 : JSON.stringify(data)
|
|
263
|
-
});
|
|
264
|
-
if (!res.ok) {
|
|
265
|
-
const body2 = await res.json().catch(() => ({ error: res.statusText }));
|
|
266
|
-
throw new Error(body2.error || body2.message || `HTTP ${res.status}`);
|
|
267
|
-
}
|
|
268
|
-
const body = await res.json();
|
|
269
|
-
if (body.success === false) throw new Error(body.error || "Request failed");
|
|
270
|
-
return body.result ?? body;
|
|
271
|
-
}
|
|
272
|
-
async get(path, data) {
|
|
273
|
-
return this.request("GET", path, data);
|
|
274
|
-
}
|
|
275
|
-
async post(path, data) {
|
|
276
|
-
return this.request("POST", path, data);
|
|
277
|
-
}
|
|
278
|
-
async put(path, data) {
|
|
279
|
-
return this.request("PUT", path, data);
|
|
280
|
-
}
|
|
281
|
-
async patch(path, data) {
|
|
282
|
-
return this.request("PATCH", path, data);
|
|
283
|
-
}
|
|
284
|
-
async delete(path, data) {
|
|
285
|
-
return this.request("DELETE", path, data);
|
|
286
|
-
}
|
|
287
|
-
// ── Subscriptions (via Server-Sent Events) ────────────────────────────
|
|
288
|
-
subscribe(event, handler) {
|
|
289
|
-
const url = `${this.url}/${this.version}/__events/${encodeURIComponent(event)}`;
|
|
290
|
-
const source = new EventSource(url, { withCredentials: true });
|
|
291
|
-
source.onmessage = (e) => {
|
|
292
|
-
try {
|
|
293
|
-
const data = JSON.parse(e.data);
|
|
294
|
-
handler(data);
|
|
295
|
-
} catch {
|
|
296
|
-
handler(e.data);
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
source.onerror = () => {
|
|
300
|
-
};
|
|
301
|
-
this.eventSources.set(event, source);
|
|
302
|
-
return () => {
|
|
303
|
-
source.close();
|
|
304
|
-
this.eventSources.delete(event);
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
unsubscribe(event) {
|
|
308
|
-
const source = this.eventSources.get(event);
|
|
309
|
-
if (source) {
|
|
310
|
-
source.close();
|
|
311
|
-
this.eventSources.delete(event);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
// ── Control messages ──────────────────────────────────────────────────
|
|
315
|
-
async send(event, ...args) {
|
|
316
|
-
await this.request("POST", "/__control", { event, args });
|
|
317
|
-
}
|
|
318
|
-
// ── Lifecycle ─────────────────────────────────────────────────────────
|
|
319
|
-
disconnect() {
|
|
320
|
-
for (const [, source] of this.eventSources) source.close();
|
|
321
|
-
this.eventSources.clear();
|
|
322
|
-
this.isConnected = false;
|
|
323
|
-
this.emit("disconnected");
|
|
324
|
-
}
|
|
325
|
-
async reconnect() {
|
|
326
|
-
this.loading = this.resolveKey();
|
|
327
|
-
await this.loading;
|
|
328
|
-
}
|
|
329
|
-
};
|
|
330
|
-
function createClient(config) {
|
|
331
|
-
const version = config.version ?? "v1";
|
|
332
|
-
let transport;
|
|
333
|
-
if (config.transport && typeof config.transport === "object") {
|
|
334
|
-
transport = config.transport;
|
|
335
|
-
} else if (config.transport === "sse") {
|
|
336
|
-
transport = new SSETransport({ url: config.url, version });
|
|
337
|
-
} else {
|
|
338
|
-
transport = new SocketTransport({ url: config.url, version });
|
|
339
|
-
}
|
|
340
|
-
Model.use(new FrontendAdapter(transport));
|
|
341
|
-
const client = {
|
|
342
|
-
transport,
|
|
343
|
-
get: (path, data) => transport.get(path, data),
|
|
344
|
-
post: (path, data) => transport.post(path, data),
|
|
345
|
-
put: (path, data) => transport.put(path, data),
|
|
346
|
-
patch: (path, data) => transport.patch(path, data),
|
|
347
|
-
delete: (path, data) => transport.delete(path, data),
|
|
348
|
-
subscribe(event, handler) {
|
|
349
|
-
if (transport.subscribe) return transport.subscribe(event, handler);
|
|
350
|
-
return () => {
|
|
351
|
-
};
|
|
352
|
-
},
|
|
353
|
-
unsubscribe(event, handler) {
|
|
354
|
-
transport.unsubscribe?.(event, handler);
|
|
355
|
-
},
|
|
356
|
-
send(event, ...args) {
|
|
357
|
-
transport.send?.(event, ...args);
|
|
358
|
-
},
|
|
359
|
-
get isConnected() {
|
|
360
|
-
return transport.isConnected ?? false;
|
|
361
|
-
},
|
|
362
|
-
async authenticate(token) {
|
|
363
|
-
if (typeof transport.authenticate === "function") {
|
|
364
|
-
return transport.authenticate(token);
|
|
365
|
-
}
|
|
366
|
-
return { userId: null };
|
|
367
|
-
},
|
|
368
|
-
on(event, handler) {
|
|
369
|
-
transport.on?.(event, handler);
|
|
370
|
-
},
|
|
371
|
-
off(event, handler) {
|
|
372
|
-
transport.off?.(event, handler);
|
|
373
|
-
},
|
|
374
|
-
disconnect() {
|
|
375
|
-
transport.disconnect?.();
|
|
376
|
-
},
|
|
377
|
-
async reconnect() {
|
|
378
|
-
await transport.reconnect?.();
|
|
379
|
-
}
|
|
380
|
-
};
|
|
381
|
-
return client;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
export { AuthGate, SSETransport, SocketTransport, createClient };
|
|
385
|
-
//# sourceMappingURL=chunk-KFISHMU4.js.map
|
|
386
|
-
//# sourceMappingURL=chunk-KFISHMU4.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth-gate.ts","../src/transports/socket.ts","../src/transports/sse.ts","../src/client.ts"],"names":["EventEmitter","body"],"mappings":"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","file":"chunk-KFISHMU4.js","sourcesContent":["/**\n * AuthGate — resettable deferred promise for authentication state.\n *\n * - resolve(): auth confirmed (authenticated or confirmed unauthenticated)\n * - reset(): back to pending (reconnect, token change)\n * - ready: awaitable promise that resolves when auth is confirmed\n */\n\nexport type AuthGateState = \"pending\" | \"ready\";\n\nexport class AuthGate {\n private _state: AuthGateState = \"pending\";\n private _resolve: (() => void) | null = null;\n private _promise: Promise<void>;\n\n constructor() {\n this._promise = this._makePending();\n }\n\n get state(): AuthGateState {\n return this._state;\n }\n\n get ready(): Promise<void> {\n return this._promise;\n }\n\n resolve(): void {\n this._state = \"ready\";\n if (this._resolve) {\n this._resolve();\n this._resolve = null;\n }\n }\n\n reset(): void {\n if (this._state === \"ready\") {\n this._state = \"pending\";\n this._promise = this._makePending();\n }\n }\n\n private _makePending(): Promise<void> {\n return new Promise<void>((r) => {\n this._resolve = r;\n });\n }\n}\n","/**\n * SocketTransport — Socket.IO transport with AuthGate.\n *\n * Connection and authentication are separate concerns:\n * - Constructor connects the socket\n * - authenticate(token) sends the token and waits for server confirmation\n * - fetch() awaits auth.ready before sending any request\n * - Disconnect resets the gate; reconnect event lets the Provider re-auth\n */\n\nimport SocketIO from \"socket.io-client\";\nimport pako from \"pako\";\nimport { decompress } from \"compress-json\";\nimport { EventEmitter } from \"eventemitter3\";\nimport ShortId from \"short-unique-id\";\nimport type { Transport } from \"@parcae/model\";\nimport { AuthGate } from \"../auth-gate\";\n\nconst uid = new ShortId({ length: 10 });\n\nexport interface SocketTransportConfig {\n url: string;\n version?: string;\n path?: string;\n}\n\nexport class SocketTransport extends EventEmitter implements Transport {\n public auth = new AuthGate();\n public isConnected = false;\n public isLoading = false;\n public userId: string | null = null;\n\n private socket: any;\n private url: string;\n private version: string;\n private inflight = new Map<string, Promise<any>>();\n\n constructor(config: SocketTransportConfig) {\n super();\n this.url = config.url;\n this.version = config.version ?? \"v1\";\n\n this.socket = SocketIO(this.url, {\n path: config.path ?? \"/ws\",\n transports: [\"websocket\"],\n withCredentials: true,\n });\n\n this.socket.on(\"connect\", () => {\n const wasConnected = this.isConnected;\n this.isConnected = true;\n this.emit(wasConnected ? \"reconnected\" : \"connected\");\n });\n\n this.socket.on(\"disconnect\", () => {\n this.isConnected = false;\n this.auth.reset();\n this.emit(\"disconnected\");\n });\n\n this.socket.on(\"error\", (err: Error) => {\n this.emit(\"error\", err);\n });\n }\n\n // ── Authenticate ──────────────────────────────────────────────────\n\n /**\n * Authenticate with the backend. Resolves the AuthGate when done.\n *\n * - token=string → send to server, wait for confirmation\n * - token=null → no auth, resolve gate immediately (unauthenticated)\n */\n async authenticate(token: string | null): Promise<{ userId: string | null }> {\n this.auth.reset();\n this.userId = null;\n\n if (!token) {\n this.auth.resolve();\n return { userId: null };\n }\n\n // Wait for socket to be connected\n if (!this.socket.connected) {\n await new Promise<void>((resolve) => {\n if (this.socket.connected) return resolve();\n this.socket.once(\"connect\", () => resolve());\n });\n }\n\n // Send token, wait for server callback\n return new Promise((resolve) => {\n this.socket.emit(\"authenticate\", token, (response: any) => {\n this.userId = response?.userId ?? null;\n this.auth.resolve();\n resolve({ userId: this.userId });\n });\n });\n }\n\n // ── Request/Response ──────────────────────────────────────────────\n\n private async fetch(\n method: string,\n path: string,\n data: any = {},\n ): Promise<any> {\n // Wait for auth to be confirmed before any request\n await this.auth.ready;\n\n // Wait for socket connection\n if (!this.socket.connected) {\n await new Promise<void>((resolve, reject) => {\n if (this.socket.connected) return resolve();\n const timeout = setTimeout(() => {\n cleanup();\n reject(new Error(\"Connection timeout\"));\n }, 30000);\n const onConnect = () => {\n cleanup();\n resolve();\n };\n const onError = (err: Error) => {\n cleanup();\n reject(err);\n };\n const cleanup = () => {\n clearTimeout(timeout);\n this.socket.off(\"connect\", onConnect);\n this.socket.off(\"connect_error\", onError);\n };\n this.socket.once(\"connect\", onConnect);\n this.socket.once(\"connect_error\", onError);\n });\n }\n\n // Deduplicate GET requests\n const upper = method.toUpperCase();\n if (upper === \"GET\") {\n const dedupeKey = `${path}:${JSON.stringify(data)}`;\n const existing = this.inflight.get(dedupeKey);\n if (existing) return existing;\n const req = this._call(method, path, data);\n this.inflight.set(dedupeKey, req);\n req.finally(() => this.inflight.delete(dedupeKey));\n return req;\n }\n\n return this._call(method, path, data);\n }\n\n private _call(method: string, path: string, data: any): Promise<any> {\n const id = uid.rnd();\n\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.socket.off(id);\n reject(new Error(`RPC timeout: ${method} ${path}`));\n }, 30000);\n\n this.socket.once(id, (msg: any) => {\n clearTimeout(timeout);\n try {\n const uncompressed = pako.ungzip(msg, { to: \"string\" });\n const parsed = decompress(JSON.parse(uncompressed));\n if (parsed.success) {\n resolve(parsed.result);\n } else {\n reject(\n new Error(\n parsed.message || parsed.error || `${method} ${path} failed`,\n ),\n );\n }\n } catch (err) {\n reject(err);\n }\n });\n\n this.socket.emit(\n \"call\",\n id,\n method.toUpperCase(),\n `/${this.version}${path}`,\n data,\n );\n });\n }\n\n async get(path: string, data?: any): Promise<any> {\n return this.fetch(\"GET\", path, data);\n }\n async post(path: string, data?: any): Promise<any> {\n return this.fetch(\"POST\", path, data);\n }\n async put(path: string, data?: any): Promise<any> {\n return this.fetch(\"PUT\", path, data);\n }\n async patch(path: string, data?: any): Promise<any> {\n return this.fetch(\"PATCH\", path, data);\n }\n async delete(path: string, data?: any): Promise<any> {\n return this.fetch(\"DELETE\", path, data);\n }\n\n // ── Subscriptions ─────────────────────────────────────────────────\n\n subscribe(event: string, handler: (...args: any[]) => void): () => void {\n this.socket.on(event, handler);\n return () => this.socket.off(event, handler);\n }\n\n unsubscribe(event: string, handler?: (...args: any[]) => void): void {\n this.socket.off(event, handler);\n }\n\n // ── Control ───────────────────────────────────────────────────────\n\n async send(event: string, ...args: any[]): Promise<void> {\n await this.auth.ready;\n this.socket.emit(event, ...args);\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────\n\n disconnect(): void {\n this.socket.disconnect();\n this.isConnected = false;\n }\n\n async reconnect(): Promise<void> {\n this.socket.connect();\n }\n}\n\nexport default SocketTransport;\n","/**\n * SSETransport — HTTP + Server-Sent Events implementation of the Transport interface.\n *\n * Request/response via standard fetch(). Subscriptions via EventSource.\n * Simpler than Socket.IO — no websocket infra needed. Good for read-heavy\n * apps, serverless backends, or environments where WebSocket isn't available.\n *\n * Trade-offs vs SocketTransport:\n * - Simpler infra (no sticky sessions, works behind any CDN/proxy)\n * - Server → client streaming only (no client → server streaming)\n * - Request/response is standard HTTP (cacheable, observable, debuggable)\n * - No compression (relies on HTTP gzip)\n * - No request deduplication (relies on HTTP/2 multiplexing)\n */\n\nimport { EventEmitter } from \"eventemitter3\";\nimport type { Transport } from \"@parcae/model\";\n\nexport interface SSETransportConfig {\n /** Base URL of the Parcae backend. */\n url: string;\n /** API key or async function returning a key. */\n key?: string | null | (() => Promise<string | null>);\n /** API version prefix. Default: \"v1\" */\n version?: string;\n}\n\nexport class SSETransport extends EventEmitter implements Transport {\n private url: string;\n private version: string;\n private apiKey: string | null | (() => Promise<string | null>);\n private key: string | null = null;\n private eventSources = new Map<string, EventSource>();\n\n public isConnected = true; // HTTP is \"always connected\"\n public isLoading = true;\n public loading: Promise<void>;\n\n constructor(config: SSETransportConfig) {\n super();\n this.url = config.url.replace(/\\/$/, \"\");\n this.version = config.version ?? \"v1\";\n this.apiKey = config.key ?? null;\n this.loading = this.resolveKey();\n }\n\n private async resolveKey(): Promise<void> {\n try {\n this.key =\n typeof this.apiKey === \"function\" ? await this.apiKey() : this.apiKey;\n this.isLoading = false;\n this.emit(\"connected\");\n } catch (err) {\n this.isLoading = false;\n this.emit(\"error\", err);\n }\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (this.key) h[\"Authorization\"] = `Bearer ${this.key}`;\n return h;\n }\n\n private fullUrl(path: string): string {\n return `${this.url}/${this.version}${path}`;\n }\n\n // ── Request/Response ──────────────────────────────────────────────────\n\n private async request(\n method: string,\n path: string,\n data?: any,\n ): Promise<any> {\n await this.loading;\n\n const isGet = method.toUpperCase() === \"GET\";\n let url = this.fullUrl(path);\n\n if (isGet && data) {\n const params = new URLSearchParams();\n for (const [k, v] of Object.entries(data)) {\n params.set(k, typeof v === \"object\" ? JSON.stringify(v) : String(v));\n }\n url += `?${params.toString()}`;\n }\n\n const res = await fetch(url, {\n method: method.toUpperCase(),\n headers: this.headers(),\n body: isGet ? undefined : JSON.stringify(data),\n });\n\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: res.statusText }));\n throw new Error(body.error || body.message || `HTTP ${res.status}`);\n }\n\n const body = await res.json();\n if (body.success === false) throw new Error(body.error || \"Request failed\");\n return body.result ?? body;\n }\n\n async get(path: string, data?: any): Promise<any> {\n return this.request(\"GET\", path, data);\n }\n async post(path: string, data?: any): Promise<any> {\n return this.request(\"POST\", path, data);\n }\n async put(path: string, data?: any): Promise<any> {\n return this.request(\"PUT\", path, data);\n }\n async patch(path: string, data?: any): Promise<any> {\n return this.request(\"PATCH\", path, data);\n }\n async delete(path: string, data?: any): Promise<any> {\n return this.request(\"DELETE\", path, data);\n }\n\n // ── Subscriptions (via Server-Sent Events) ────────────────────────────\n\n subscribe(event: string, handler: (...args: any[]) => void): () => void {\n const url = `${this.url}/${this.version}/__events/${encodeURIComponent(event)}`;\n const source = new EventSource(url, { withCredentials: true });\n\n source.onmessage = (e) => {\n try {\n const data = JSON.parse(e.data);\n handler(data);\n } catch {\n handler(e.data);\n }\n };\n\n source.onerror = () => {\n // EventSource auto-reconnects\n };\n\n this.eventSources.set(event, source);\n\n return () => {\n source.close();\n this.eventSources.delete(event);\n };\n }\n\n unsubscribe(event: string): void {\n const source = this.eventSources.get(event);\n if (source) {\n source.close();\n this.eventSources.delete(event);\n }\n }\n\n // ── Control messages ──────────────────────────────────────────────────\n\n async send(event: string, ...args: any[]): Promise<void> {\n await this.request(\"POST\", \"/__control\", { event, args });\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────\n\n disconnect(): void {\n for (const [, source] of this.eventSources) source.close();\n this.eventSources.clear();\n this.isConnected = false;\n this.emit(\"disconnected\");\n }\n\n async reconnect(): Promise<void> {\n this.loading = this.resolveKey();\n await this.loading;\n }\n}\n\nexport default SSETransport;\n","/**\n * @parcae/sdk — createClient()\n *\n * Creates a Parcae client with a pluggable transport.\n * Authentication is driven by the consumer (Provider) via client.authenticate().\n */\n\nimport { Model, FrontendAdapter } from \"@parcae/model\";\nimport type { Transport } from \"@parcae/model\";\nimport { SocketTransport } from \"./transports/socket\";\nimport { SSETransport } from \"./transports/sse\";\n\n// ─── Configuration ───────────────────────────────────────────────────────────\n\nexport interface ClientConfig {\n url: string;\n version?: string;\n transport?: \"socket\" | \"sse\" | Transport;\n}\n\nexport interface ParcaeClient {\n transport: Transport;\n get(path: string, data?: any): Promise<any>;\n post(path: string, data?: any): Promise<any>;\n put(path: string, data?: any): Promise<any>;\n patch(path: string, data?: any): Promise<any>;\n delete(path: string, data?: any): Promise<any>;\n subscribe(event: string, handler: (...args: any[]) => void): () => void;\n unsubscribe(event: string, handler?: (...args: any[]) => void): void;\n send(event: string, ...args: any[]): void;\n readonly isConnected: boolean;\n\n /** Authenticate with the backend. Resolves when auth is confirmed. */\n authenticate(token: string | null): Promise<{ userId: string | null }>;\n\n /** Listen for transport events: connected, disconnected, reconnected, error */\n on(event: string, handler: (...args: any[]) => void): void;\n off(event: string, handler?: (...args: any[]) => void): void;\n\n disconnect(): void;\n reconnect(): Promise<void>;\n}\n\n// ─── createClient ────────────────────────────────────────────────────────────\n\nexport function createClient(config: ClientConfig): ParcaeClient {\n const version = config.version ?? \"v1\";\n\n let transport: any;\n\n if (config.transport && typeof config.transport === \"object\") {\n transport = config.transport;\n } else if (config.transport === \"sse\") {\n transport = new SSETransport({ url: config.url, version });\n } else {\n transport = new SocketTransport({ url: config.url, version });\n }\n\n // Wire FrontendAdapter so Model.where() etc work\n Model.use(new FrontendAdapter(transport));\n\n const client: ParcaeClient = {\n transport,\n\n get: (path, data) => transport.get(path, data),\n post: (path, data) => transport.post(path, data),\n put: (path, data) => transport.put(path, data),\n patch: (path, data) => transport.patch(path, data),\n delete: (path, data) => transport.delete(path, data),\n\n subscribe(event, handler) {\n if (transport.subscribe) return transport.subscribe(event, handler);\n return () => {};\n },\n unsubscribe(event, handler) {\n transport.unsubscribe?.(event, handler);\n },\n send(event, ...args) {\n transport.send?.(event, ...args);\n },\n\n get isConnected() {\n return transport.isConnected ?? false;\n },\n\n async authenticate(token: string | null) {\n if (typeof transport.authenticate === \"function\") {\n return transport.authenticate(token);\n }\n // SSE/custom transports: resolve immediately\n return { userId: null };\n },\n\n on(event, handler) {\n transport.on?.(event, handler);\n },\n off(event, handler) {\n transport.off?.(event, handler);\n },\n\n disconnect() {\n transport.disconnect?.();\n },\n async reconnect() {\n await transport.reconnect?.();\n },\n };\n\n return client;\n}\n"]}
|