@debros/network-ts-sdk 0.3.2 → 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/README.md +49 -0
- package/dist/index.d.ts +109 -13
- package/dist/index.js +137 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/http.ts +46 -6
- package/src/core/ws.ts +14 -5
- package/src/functions/client.ts +62 -0
- package/src/functions/types.ts +21 -0
- package/src/index.ts +17 -7
- package/src/pubsub/client.ts +104 -31
- package/src/pubsub/types.ts +46 -0
package/README.md
CHANGED
|
@@ -215,6 +215,55 @@ const topics = await client.pubsub.topics();
|
|
|
215
215
|
console.log("Active topics:", topics);
|
|
216
216
|
```
|
|
217
217
|
|
|
218
|
+
### Presence Support
|
|
219
|
+
|
|
220
|
+
The SDK supports real-time presence tracking, allowing you to see who is currently subscribed to a topic.
|
|
221
|
+
|
|
222
|
+
#### Subscribe with Presence
|
|
223
|
+
|
|
224
|
+
Enable presence by providing `presence` options in `subscribe`:
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
const subscription = await client.pubsub.subscribe("room.123", {
|
|
228
|
+
onMessage: (msg) => console.log("Message:", msg.data),
|
|
229
|
+
presence: {
|
|
230
|
+
enabled: true,
|
|
231
|
+
memberId: "user-alice",
|
|
232
|
+
meta: { displayName: "Alice", avatar: "URL" },
|
|
233
|
+
onJoin: (member) => {
|
|
234
|
+
console.log(`${member.memberId} joined at ${new Date(member.joinedAt)}`);
|
|
235
|
+
console.log("Meta:", member.meta);
|
|
236
|
+
},
|
|
237
|
+
onLeave: (member) => {
|
|
238
|
+
console.log(`${member.memberId} left`);
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### Get Presence for a Topic
|
|
245
|
+
|
|
246
|
+
Query current members without subscribing:
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
const presence = await client.pubsub.getPresence("room.123");
|
|
250
|
+
console.log(`Total members: ${presence.count}`);
|
|
251
|
+
presence.members.forEach((member) => {
|
|
252
|
+
console.log(`- ${member.memberId} (joined: ${new Date(member.joinedAt)})`);
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
#### Subscription Helpers
|
|
257
|
+
|
|
258
|
+
Get presence information from an active subscription:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
if (subscription.hasPresence()) {
|
|
262
|
+
const members = await subscription.getPresence();
|
|
263
|
+
console.log("Current members:", members);
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
218
267
|
### Authentication
|
|
219
268
|
|
|
220
269
|
#### Switch API Key
|
package/dist/index.d.ts
CHANGED
|
@@ -21,6 +21,10 @@ declare class HttpClient {
|
|
|
21
21
|
private getAuthHeaders;
|
|
22
22
|
private getAuthToken;
|
|
23
23
|
getApiKey(): string | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Get the base URL
|
|
26
|
+
*/
|
|
27
|
+
getBaseURL(): string;
|
|
24
28
|
request<T = any>(method: "GET" | "POST" | "PUT" | "DELETE", path: string, options?: {
|
|
25
29
|
body?: any;
|
|
26
30
|
headers?: Record<string, string>;
|
|
@@ -290,10 +294,11 @@ type WSCloseHandler = () => void;
|
|
|
290
294
|
type WSOpenHandler = () => void;
|
|
291
295
|
/**
|
|
292
296
|
* Simple WebSocket client with minimal abstractions
|
|
293
|
-
* No complex reconnection, no
|
|
297
|
+
* No complex reconnection, no failover - keep it simple
|
|
298
|
+
* Gateway failover is handled at the application layer
|
|
294
299
|
*/
|
|
295
300
|
declare class WSClient {
|
|
296
|
-
private
|
|
301
|
+
private wsURL;
|
|
297
302
|
private timeout;
|
|
298
303
|
private authToken?;
|
|
299
304
|
private WebSocketClass;
|
|
@@ -304,6 +309,10 @@ declare class WSClient {
|
|
|
304
309
|
private openHandlers;
|
|
305
310
|
private isClosed;
|
|
306
311
|
constructor(config: WSClientConfig);
|
|
312
|
+
/**
|
|
313
|
+
* Get the current WebSocket URL
|
|
314
|
+
*/
|
|
315
|
+
get url(): string;
|
|
307
316
|
/**
|
|
308
317
|
* Connect to WebSocket server
|
|
309
318
|
*/
|
|
@@ -358,17 +367,41 @@ declare class WSClient {
|
|
|
358
367
|
setAuthToken(token?: string): void;
|
|
359
368
|
}
|
|
360
369
|
|
|
361
|
-
interface
|
|
370
|
+
interface PubSubMessage {
|
|
362
371
|
data: string;
|
|
363
372
|
topic: string;
|
|
364
373
|
timestamp: number;
|
|
365
374
|
}
|
|
366
|
-
|
|
375
|
+
interface PresenceMember {
|
|
376
|
+
memberId: string;
|
|
377
|
+
joinedAt: number;
|
|
378
|
+
meta?: Record<string, unknown>;
|
|
379
|
+
}
|
|
380
|
+
interface PresenceResponse {
|
|
381
|
+
topic: string;
|
|
382
|
+
members: PresenceMember[];
|
|
383
|
+
count: number;
|
|
384
|
+
}
|
|
385
|
+
interface PresenceOptions {
|
|
386
|
+
enabled: boolean;
|
|
387
|
+
memberId: string;
|
|
388
|
+
meta?: Record<string, unknown>;
|
|
389
|
+
onJoin?: (member: PresenceMember) => void;
|
|
390
|
+
onLeave?: (member: PresenceMember) => void;
|
|
391
|
+
}
|
|
392
|
+
interface SubscribeOptions {
|
|
393
|
+
onMessage?: MessageHandler;
|
|
394
|
+
onError?: ErrorHandler;
|
|
395
|
+
onClose?: CloseHandler;
|
|
396
|
+
presence?: PresenceOptions;
|
|
397
|
+
}
|
|
398
|
+
type MessageHandler = (message: PubSubMessage) => void;
|
|
367
399
|
type ErrorHandler = (error: Error) => void;
|
|
368
400
|
type CloseHandler = () => void;
|
|
401
|
+
|
|
369
402
|
/**
|
|
370
403
|
* Simple PubSub client - one WebSocket connection per topic
|
|
371
|
-
*
|
|
404
|
+
* Gateway failover is handled at the application layer
|
|
372
405
|
*/
|
|
373
406
|
declare class PubSubClient {
|
|
374
407
|
private httpClient;
|
|
@@ -382,15 +415,15 @@ declare class PubSubClient {
|
|
|
382
415
|
* List active topics in the current namespace
|
|
383
416
|
*/
|
|
384
417
|
topics(): Promise<string[]>;
|
|
418
|
+
/**
|
|
419
|
+
* Get current presence for a topic without subscribing
|
|
420
|
+
*/
|
|
421
|
+
getPresence(topic: string): Promise<PresenceResponse>;
|
|
385
422
|
/**
|
|
386
423
|
* Subscribe to a topic via WebSocket
|
|
387
424
|
* Creates one WebSocket connection per topic
|
|
388
425
|
*/
|
|
389
|
-
subscribe(topic: string,
|
|
390
|
-
onMessage?: MessageHandler;
|
|
391
|
-
onError?: ErrorHandler;
|
|
392
|
-
onClose?: CloseHandler;
|
|
393
|
-
}): Promise<Subscription>;
|
|
426
|
+
subscribe(topic: string, options?: SubscribeOptions): Promise<Subscription>;
|
|
394
427
|
}
|
|
395
428
|
/**
|
|
396
429
|
* Subscription represents an active WebSocket subscription to a topic
|
|
@@ -398,6 +431,7 @@ declare class PubSubClient {
|
|
|
398
431
|
declare class Subscription {
|
|
399
432
|
private wsClient;
|
|
400
433
|
private topic;
|
|
434
|
+
private presenceOptions?;
|
|
401
435
|
private messageHandlers;
|
|
402
436
|
private errorHandlers;
|
|
403
437
|
private closeHandlers;
|
|
@@ -405,7 +439,16 @@ declare class Subscription {
|
|
|
405
439
|
private wsMessageHandler;
|
|
406
440
|
private wsErrorHandler;
|
|
407
441
|
private wsCloseHandler;
|
|
408
|
-
|
|
442
|
+
private getPresenceFn;
|
|
443
|
+
constructor(wsClient: WSClient, topic: string, presenceOptions: PresenceOptions | undefined, getPresenceFn: () => Promise<PresenceResponse>);
|
|
444
|
+
/**
|
|
445
|
+
* Get current presence (requires presence.enabled on subscribe)
|
|
446
|
+
*/
|
|
447
|
+
getPresence(): Promise<PresenceMember[]>;
|
|
448
|
+
/**
|
|
449
|
+
* Check if presence is enabled for this subscription
|
|
450
|
+
*/
|
|
451
|
+
hasPresence(): boolean;
|
|
409
452
|
/**
|
|
410
453
|
* Register message handler
|
|
411
454
|
*/
|
|
@@ -695,6 +738,37 @@ declare class StorageClient {
|
|
|
695
738
|
unpin(cid: string): Promise<void>;
|
|
696
739
|
}
|
|
697
740
|
|
|
741
|
+
/**
|
|
742
|
+
* Functions Client
|
|
743
|
+
* Client for calling serverless functions on the Orama Network
|
|
744
|
+
*/
|
|
745
|
+
|
|
746
|
+
interface FunctionsClientConfig {
|
|
747
|
+
/**
|
|
748
|
+
* Base URL for the functions gateway
|
|
749
|
+
* Defaults to using the same baseURL as the HTTP client
|
|
750
|
+
*/
|
|
751
|
+
gatewayURL?: string;
|
|
752
|
+
/**
|
|
753
|
+
* Namespace for the functions
|
|
754
|
+
*/
|
|
755
|
+
namespace: string;
|
|
756
|
+
}
|
|
757
|
+
declare class FunctionsClient {
|
|
758
|
+
private httpClient;
|
|
759
|
+
private gatewayURL?;
|
|
760
|
+
private namespace;
|
|
761
|
+
constructor(httpClient: HttpClient, config?: FunctionsClientConfig);
|
|
762
|
+
/**
|
|
763
|
+
* Invoke a serverless function by name
|
|
764
|
+
*
|
|
765
|
+
* @param functionName - Name of the function to invoke
|
|
766
|
+
* @param input - Input payload for the function
|
|
767
|
+
* @returns The function response
|
|
768
|
+
*/
|
|
769
|
+
invoke<TInput = any, TOutput = any>(functionName: string, input: TInput): Promise<TOutput>;
|
|
770
|
+
}
|
|
771
|
+
|
|
698
772
|
declare class SDKError extends Error {
|
|
699
773
|
readonly httpStatus: number;
|
|
700
774
|
readonly code: string;
|
|
@@ -710,11 +784,32 @@ declare class SDKError extends Error {
|
|
|
710
784
|
};
|
|
711
785
|
}
|
|
712
786
|
|
|
787
|
+
/**
|
|
788
|
+
* Serverless Functions Types
|
|
789
|
+
* Type definitions for calling serverless functions on the Orama Network
|
|
790
|
+
*/
|
|
791
|
+
/**
|
|
792
|
+
* Generic response from a serverless function
|
|
793
|
+
*/
|
|
794
|
+
interface FunctionResponse<T = unknown> {
|
|
795
|
+
success: boolean;
|
|
796
|
+
error?: string;
|
|
797
|
+
data?: T;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Standard success/error response used by many functions
|
|
801
|
+
*/
|
|
802
|
+
interface SuccessResponse {
|
|
803
|
+
success: boolean;
|
|
804
|
+
error?: string;
|
|
805
|
+
}
|
|
806
|
+
|
|
713
807
|
interface ClientConfig extends Omit<HttpClientConfig, "fetch"> {
|
|
714
808
|
apiKey?: string;
|
|
715
809
|
jwt?: string;
|
|
716
810
|
storage?: StorageAdapter;
|
|
717
|
-
wsConfig?: Partial<WSClientConfig
|
|
811
|
+
wsConfig?: Partial<Omit<WSClientConfig, "wsURL">>;
|
|
812
|
+
functionsConfig?: FunctionsClientConfig;
|
|
718
813
|
fetch?: typeof fetch;
|
|
719
814
|
}
|
|
720
815
|
interface Client {
|
|
@@ -724,7 +819,8 @@ interface Client {
|
|
|
724
819
|
network: NetworkClient;
|
|
725
820
|
cache: CacheClient;
|
|
726
821
|
storage: StorageClient;
|
|
822
|
+
functions: FunctionsClient;
|
|
727
823
|
}
|
|
728
824
|
declare function createClient(config: ClientConfig): Client;
|
|
729
825
|
|
|
730
|
-
export { AuthClient, type AuthConfig, CacheClient, type CacheDeleteRequest, type CacheDeleteResponse, type CacheGetRequest, type CacheGetResponse, type CacheHealthResponse, type CacheMultiGetRequest, type CacheMultiGetResponse, type CachePutRequest, type CachePutResponse, type CacheScanRequest, type CacheScanResponse, type Client, type ClientConfig, type CloseHandler, type ColumnDefinition, DBClient, type Entity, type ErrorHandler, type FindOptions, HttpClient, LocalStorageAdapter, MemoryStorage, type
|
|
826
|
+
export { AuthClient, type AuthConfig, CacheClient, type CacheDeleteRequest, type CacheDeleteResponse, type CacheGetRequest, type CacheGetResponse, type CacheHealthResponse, type CacheMultiGetRequest, type CacheMultiGetResponse, type CachePutRequest, type CachePutResponse, type CacheScanRequest, type CacheScanResponse, type Client, type ClientConfig, type CloseHandler, type ColumnDefinition, DBClient, type Entity, type ErrorHandler, type FindOptions, type FunctionResponse, FunctionsClient, type FunctionsClientConfig, HttpClient, LocalStorageAdapter, MemoryStorage, type MessageHandler, NetworkClient, type NetworkStatus, type PeerInfo, type PresenceMember, type PresenceOptions, type PresenceResponse, type ProxyRequest, type ProxyResponse, PubSubClient, type PubSubMessage, QueryBuilder, type QueryResponse, Repository, SDKError, type SelectOptions, type StorageAdapter, StorageClient, type StoragePinRequest, type StoragePinResponse, type StorageStatus, type StorageUploadResponse, type SubscribeOptions, Subscription, type SuccessResponse, type TransactionOp, type TransactionRequest, WSClient, type WhoAmI, createClient, extractPrimaryKey, extractTableName };
|
package/dist/index.js
CHANGED
|
@@ -24,13 +24,22 @@ var SDKError = class _SDKError extends Error {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
// src/core/http.ts
|
|
27
|
+
function createFetchWithTLSConfig() {
|
|
28
|
+
if (typeof process !== "undefined" && process.versions?.node) {
|
|
29
|
+
const isDevelopmentOrStaging = process.env.NODE_ENV !== "production" || process.env.DEBROS_ALLOW_STAGING_CERTS === "true" || process.env.DEBROS_USE_HTTPS === "true";
|
|
30
|
+
if (isDevelopmentOrStaging) {
|
|
31
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return globalThis.fetch;
|
|
35
|
+
}
|
|
27
36
|
var HttpClient = class {
|
|
28
37
|
constructor(config) {
|
|
29
38
|
this.baseURL = config.baseURL.replace(/\/$/, "");
|
|
30
39
|
this.timeout = config.timeout ?? 6e4;
|
|
31
40
|
this.maxRetries = config.maxRetries ?? 3;
|
|
32
41
|
this.retryDelayMs = config.retryDelayMs ?? 1e3;
|
|
33
|
-
this.fetch = config.fetch ??
|
|
42
|
+
this.fetch = config.fetch ?? createFetchWithTLSConfig();
|
|
34
43
|
}
|
|
35
44
|
setApiKey(apiKey) {
|
|
36
45
|
this.apiKey = apiKey;
|
|
@@ -82,6 +91,12 @@ var HttpClient = class {
|
|
|
82
91
|
getApiKey() {
|
|
83
92
|
return this.apiKey;
|
|
84
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Get the base URL
|
|
96
|
+
*/
|
|
97
|
+
getBaseURL() {
|
|
98
|
+
return this.baseURL;
|
|
99
|
+
}
|
|
85
100
|
async request(method, path, options = {}) {
|
|
86
101
|
const startTime = performance.now();
|
|
87
102
|
const url = new URL(this.baseURL + path);
|
|
@@ -203,7 +218,13 @@ var HttpClient = class {
|
|
|
203
218
|
}
|
|
204
219
|
return response.text();
|
|
205
220
|
} catch (error) {
|
|
206
|
-
|
|
221
|
+
const isRetryableError = error instanceof SDKError && [408, 429, 500, 502, 503, 504].includes(error.httpStatus);
|
|
222
|
+
if (isRetryableError && attempt < this.maxRetries) {
|
|
223
|
+
if (typeof console !== "undefined") {
|
|
224
|
+
console.warn(
|
|
225
|
+
`[HttpClient] Retrying request (attempt ${attempt + 1}/${this.maxRetries})`
|
|
226
|
+
);
|
|
227
|
+
}
|
|
207
228
|
await new Promise(
|
|
208
229
|
(resolve) => setTimeout(resolve, this.retryDelayMs * (attempt + 1))
|
|
209
230
|
);
|
|
@@ -789,11 +810,17 @@ var WSClient = class {
|
|
|
789
810
|
this.closeHandlers = /* @__PURE__ */ new Set();
|
|
790
811
|
this.openHandlers = /* @__PURE__ */ new Set();
|
|
791
812
|
this.isClosed = false;
|
|
792
|
-
this.
|
|
813
|
+
this.wsURL = config.wsURL;
|
|
793
814
|
this.timeout = config.timeout ?? 3e4;
|
|
794
815
|
this.authToken = config.authToken;
|
|
795
816
|
this.WebSocketClass = config.WebSocket ?? WebSocket;
|
|
796
817
|
}
|
|
818
|
+
/**
|
|
819
|
+
* Get the current WebSocket URL
|
|
820
|
+
*/
|
|
821
|
+
get url() {
|
|
822
|
+
return this.wsURL;
|
|
823
|
+
}
|
|
797
824
|
/**
|
|
798
825
|
* Connect to WebSocket server
|
|
799
826
|
*/
|
|
@@ -811,7 +838,7 @@ var WSClient = class {
|
|
|
811
838
|
}, this.timeout);
|
|
812
839
|
this.ws.addEventListener("open", () => {
|
|
813
840
|
clearTimeout(timeout);
|
|
814
|
-
console.log("[WSClient] Connected to", this.
|
|
841
|
+
console.log("[WSClient] Connected to", this.wsURL);
|
|
815
842
|
this.openHandlers.forEach((handler) => handler());
|
|
816
843
|
resolve();
|
|
817
844
|
});
|
|
@@ -824,6 +851,7 @@ var WSClient = class {
|
|
|
824
851
|
clearTimeout(timeout);
|
|
825
852
|
const error = new SDKError("WebSocket error", 500, "WS_ERROR", event);
|
|
826
853
|
this.errorHandlers.forEach((handler) => handler(error));
|
|
854
|
+
reject(error);
|
|
827
855
|
});
|
|
828
856
|
this.ws.addEventListener("close", () => {
|
|
829
857
|
clearTimeout(timeout);
|
|
@@ -839,7 +867,7 @@ var WSClient = class {
|
|
|
839
867
|
* Build WebSocket URL with auth token
|
|
840
868
|
*/
|
|
841
869
|
buildWSUrl() {
|
|
842
|
-
let url = this.
|
|
870
|
+
let url = this.wsURL;
|
|
843
871
|
if (this.authToken) {
|
|
844
872
|
const separator = url.includes("?") ? "&" : "?";
|
|
845
873
|
const paramName = this.authToken.startsWith("ak_") ? "api_key" : "token";
|
|
@@ -1000,14 +1028,32 @@ var PubSubClient = class {
|
|
|
1000
1028
|
);
|
|
1001
1029
|
return response.topics || [];
|
|
1002
1030
|
}
|
|
1031
|
+
/**
|
|
1032
|
+
* Get current presence for a topic without subscribing
|
|
1033
|
+
*/
|
|
1034
|
+
async getPresence(topic) {
|
|
1035
|
+
const response = await this.httpClient.get(
|
|
1036
|
+
`/v1/pubsub/presence?topic=${encodeURIComponent(topic)}`
|
|
1037
|
+
);
|
|
1038
|
+
return response;
|
|
1039
|
+
}
|
|
1003
1040
|
/**
|
|
1004
1041
|
* Subscribe to a topic via WebSocket
|
|
1005
1042
|
* Creates one WebSocket connection per topic
|
|
1006
1043
|
*/
|
|
1007
|
-
async subscribe(topic,
|
|
1044
|
+
async subscribe(topic, options = {}) {
|
|
1008
1045
|
const wsUrl = new URL(this.wsConfig.wsURL || "ws://127.0.0.1:6001");
|
|
1009
1046
|
wsUrl.pathname = "/v1/pubsub/ws";
|
|
1010
1047
|
wsUrl.searchParams.set("topic", topic);
|
|
1048
|
+
let presence;
|
|
1049
|
+
if (options.presence?.enabled) {
|
|
1050
|
+
presence = options.presence;
|
|
1051
|
+
wsUrl.searchParams.set("presence", "true");
|
|
1052
|
+
wsUrl.searchParams.set("member_id", presence.memberId);
|
|
1053
|
+
if (presence.meta) {
|
|
1054
|
+
wsUrl.searchParams.set("member_meta", JSON.stringify(presence.meta));
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1011
1057
|
const authToken = this.httpClient.getApiKey() ?? this.httpClient.getToken();
|
|
1012
1058
|
const wsClient = new WSClient({
|
|
1013
1059
|
...this.wsConfig,
|
|
@@ -1015,21 +1061,26 @@ var PubSubClient = class {
|
|
|
1015
1061
|
authToken
|
|
1016
1062
|
});
|
|
1017
1063
|
await wsClient.connect();
|
|
1018
|
-
const subscription = new Subscription(
|
|
1019
|
-
|
|
1020
|
-
|
|
1064
|
+
const subscription = new Subscription(
|
|
1065
|
+
wsClient,
|
|
1066
|
+
topic,
|
|
1067
|
+
presence,
|
|
1068
|
+
() => this.getPresence(topic)
|
|
1069
|
+
);
|
|
1070
|
+
if (options.onMessage) {
|
|
1071
|
+
subscription.onMessage(options.onMessage);
|
|
1021
1072
|
}
|
|
1022
|
-
if (
|
|
1023
|
-
subscription.onError(
|
|
1073
|
+
if (options.onError) {
|
|
1074
|
+
subscription.onError(options.onError);
|
|
1024
1075
|
}
|
|
1025
|
-
if (
|
|
1026
|
-
subscription.onClose(
|
|
1076
|
+
if (options.onClose) {
|
|
1077
|
+
subscription.onClose(options.onClose);
|
|
1027
1078
|
}
|
|
1028
1079
|
return subscription;
|
|
1029
1080
|
}
|
|
1030
1081
|
};
|
|
1031
1082
|
var Subscription = class {
|
|
1032
|
-
constructor(wsClient, topic) {
|
|
1083
|
+
constructor(wsClient, topic, presenceOptions, getPresenceFn) {
|
|
1033
1084
|
this.messageHandlers = /* @__PURE__ */ new Set();
|
|
1034
1085
|
this.errorHandlers = /* @__PURE__ */ new Set();
|
|
1035
1086
|
this.closeHandlers = /* @__PURE__ */ new Set();
|
|
@@ -1039,12 +1090,31 @@ var Subscription = class {
|
|
|
1039
1090
|
this.wsCloseHandler = null;
|
|
1040
1091
|
this.wsClient = wsClient;
|
|
1041
1092
|
this.topic = topic;
|
|
1093
|
+
this.presenceOptions = presenceOptions;
|
|
1094
|
+
this.getPresenceFn = getPresenceFn;
|
|
1042
1095
|
this.wsMessageHandler = (data) => {
|
|
1043
1096
|
try {
|
|
1044
1097
|
const envelope = JSON.parse(data);
|
|
1045
1098
|
if (!envelope || typeof envelope !== "object") {
|
|
1046
1099
|
throw new Error("Invalid envelope: not an object");
|
|
1047
1100
|
}
|
|
1101
|
+
if (envelope.type === "presence.join" || envelope.type === "presence.leave") {
|
|
1102
|
+
if (!envelope.member_id) {
|
|
1103
|
+
console.warn("[Subscription] Presence event missing member_id");
|
|
1104
|
+
return;
|
|
1105
|
+
}
|
|
1106
|
+
const presenceMember = {
|
|
1107
|
+
memberId: envelope.member_id,
|
|
1108
|
+
joinedAt: envelope.timestamp,
|
|
1109
|
+
meta: envelope.meta
|
|
1110
|
+
};
|
|
1111
|
+
if (envelope.type === "presence.join" && this.presenceOptions?.onJoin) {
|
|
1112
|
+
this.presenceOptions.onJoin(presenceMember);
|
|
1113
|
+
} else if (envelope.type === "presence.leave" && this.presenceOptions?.onLeave) {
|
|
1114
|
+
this.presenceOptions.onLeave(presenceMember);
|
|
1115
|
+
}
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1048
1118
|
if (!envelope.data || typeof envelope.data !== "string") {
|
|
1049
1119
|
throw new Error("Invalid envelope: missing or invalid data field");
|
|
1050
1120
|
}
|
|
@@ -1081,6 +1151,22 @@ var Subscription = class {
|
|
|
1081
1151
|
};
|
|
1082
1152
|
this.wsClient.onClose(this.wsCloseHandler);
|
|
1083
1153
|
}
|
|
1154
|
+
/**
|
|
1155
|
+
* Get current presence (requires presence.enabled on subscribe)
|
|
1156
|
+
*/
|
|
1157
|
+
async getPresence() {
|
|
1158
|
+
if (!this.presenceOptions?.enabled) {
|
|
1159
|
+
throw new Error("Presence is not enabled for this subscription");
|
|
1160
|
+
}
|
|
1161
|
+
const response = await this.getPresenceFn();
|
|
1162
|
+
return response.members;
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Check if presence is enabled for this subscription
|
|
1166
|
+
*/
|
|
1167
|
+
hasPresence() {
|
|
1168
|
+
return !!this.presenceOptions?.enabled;
|
|
1169
|
+
}
|
|
1084
1170
|
/**
|
|
1085
1171
|
* Register message handler
|
|
1086
1172
|
*/
|
|
@@ -1502,6 +1588,38 @@ var StorageClient = class {
|
|
|
1502
1588
|
}
|
|
1503
1589
|
};
|
|
1504
1590
|
|
|
1591
|
+
// src/functions/client.ts
|
|
1592
|
+
var FunctionsClient = class {
|
|
1593
|
+
constructor(httpClient, config) {
|
|
1594
|
+
this.httpClient = httpClient;
|
|
1595
|
+
this.gatewayURL = config?.gatewayURL;
|
|
1596
|
+
this.namespace = config?.namespace ?? "default";
|
|
1597
|
+
}
|
|
1598
|
+
/**
|
|
1599
|
+
* Invoke a serverless function by name
|
|
1600
|
+
*
|
|
1601
|
+
* @param functionName - Name of the function to invoke
|
|
1602
|
+
* @param input - Input payload for the function
|
|
1603
|
+
* @returns The function response
|
|
1604
|
+
*/
|
|
1605
|
+
async invoke(functionName, input) {
|
|
1606
|
+
const url = this.gatewayURL ? `${this.gatewayURL}/v1/invoke/${this.namespace}/${functionName}` : `/v1/invoke/${this.namespace}/${functionName}`;
|
|
1607
|
+
try {
|
|
1608
|
+
const response = await this.httpClient.post(url, input);
|
|
1609
|
+
return response;
|
|
1610
|
+
} catch (error) {
|
|
1611
|
+
if (error instanceof SDKError) {
|
|
1612
|
+
throw error;
|
|
1613
|
+
}
|
|
1614
|
+
throw new SDKError(
|
|
1615
|
+
`Function ${functionName} failed`,
|
|
1616
|
+
500,
|
|
1617
|
+
error instanceof Error ? error.message : String(error)
|
|
1618
|
+
);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
};
|
|
1622
|
+
|
|
1505
1623
|
// src/index.ts
|
|
1506
1624
|
function createClient(config) {
|
|
1507
1625
|
const httpClient = new HttpClient({
|
|
@@ -1517,7 +1635,7 @@ function createClient(config) {
|
|
|
1517
1635
|
apiKey: config.apiKey,
|
|
1518
1636
|
jwt: config.jwt
|
|
1519
1637
|
});
|
|
1520
|
-
const wsURL = config.
|
|
1638
|
+
const wsURL = config.baseURL.replace(/^http/, "ws").replace(/\/$/, "");
|
|
1521
1639
|
const db = new DBClient(httpClient);
|
|
1522
1640
|
const pubsub = new PubSubClient(httpClient, {
|
|
1523
1641
|
...config.wsConfig,
|
|
@@ -1526,19 +1644,22 @@ function createClient(config) {
|
|
|
1526
1644
|
const network = new NetworkClient(httpClient);
|
|
1527
1645
|
const cache = new CacheClient(httpClient);
|
|
1528
1646
|
const storage = new StorageClient(httpClient);
|
|
1647
|
+
const functions = new FunctionsClient(httpClient, config.functionsConfig);
|
|
1529
1648
|
return {
|
|
1530
1649
|
auth,
|
|
1531
1650
|
db,
|
|
1532
1651
|
pubsub,
|
|
1533
1652
|
network,
|
|
1534
1653
|
cache,
|
|
1535
|
-
storage
|
|
1654
|
+
storage,
|
|
1655
|
+
functions
|
|
1536
1656
|
};
|
|
1537
1657
|
}
|
|
1538
1658
|
export {
|
|
1539
1659
|
AuthClient,
|
|
1540
1660
|
CacheClient,
|
|
1541
1661
|
DBClient,
|
|
1662
|
+
FunctionsClient,
|
|
1542
1663
|
HttpClient,
|
|
1543
1664
|
LocalStorageAdapter,
|
|
1544
1665
|
MemoryStorage,
|