@realtimex/sdk 1.0.7 → 1.0.9
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 +3 -2
- package/dist/index.d.mts +46 -7
- package/dist/index.d.ts +46 -7
- package/dist/index.js +232 -47
- package/dist/index.mjs +230 -47
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,8 +24,9 @@ Before using this SDK, ensure your Supabase database is set up:
|
|
|
24
24
|
```typescript
|
|
25
25
|
import { RealtimeXSDK } from '@realtimex/sdk';
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
const sdk = new RealtimeXSDK({
|
|
28
|
+
permissions: ['activities.read', 'activities.write', 'webhook.trigger']
|
|
29
|
+
});
|
|
29
30
|
|
|
30
31
|
// Insert activity
|
|
31
32
|
const activity = await sdk.activities.insert({
|
package/dist/index.d.mts
CHANGED
|
@@ -8,6 +8,7 @@ interface SDKConfig {
|
|
|
8
8
|
appName?: string;
|
|
9
9
|
};
|
|
10
10
|
defaultPort?: number;
|
|
11
|
+
permissions?: string[];
|
|
11
12
|
}
|
|
12
13
|
interface Activity {
|
|
13
14
|
id: string;
|
|
@@ -86,7 +87,12 @@ interface Task {
|
|
|
86
87
|
declare class ActivitiesModule {
|
|
87
88
|
private baseUrl;
|
|
88
89
|
private appId;
|
|
89
|
-
|
|
90
|
+
private appName;
|
|
91
|
+
constructor(realtimexUrl: string, appId: string, appName?: string);
|
|
92
|
+
/**
|
|
93
|
+
* Request a single permission from Electron via internal API
|
|
94
|
+
*/
|
|
95
|
+
private requestPermission;
|
|
90
96
|
private request;
|
|
91
97
|
/**
|
|
92
98
|
* Insert a new activity
|
|
@@ -114,15 +120,16 @@ declare class ActivitiesModule {
|
|
|
114
120
|
}): Promise<Activity[]>;
|
|
115
121
|
}
|
|
116
122
|
|
|
117
|
-
/**
|
|
118
|
-
* Webhook Module - Call RealtimeX webhook
|
|
119
|
-
*/
|
|
120
|
-
|
|
121
123
|
declare class WebhookModule {
|
|
122
124
|
private realtimexUrl;
|
|
123
125
|
private appName?;
|
|
124
126
|
private appId?;
|
|
125
127
|
constructor(realtimexUrl: string, appName?: string, appId?: string);
|
|
128
|
+
/**
|
|
129
|
+
* Request a single permission from Electron via internal API
|
|
130
|
+
*/
|
|
131
|
+
private requestPermission;
|
|
132
|
+
private request;
|
|
126
133
|
triggerAgent(payload: TriggerAgentPayload): Promise<TriggerAgentResponse>;
|
|
127
134
|
ping(): Promise<{
|
|
128
135
|
success: boolean;
|
|
@@ -135,9 +142,34 @@ declare class WebhookModule {
|
|
|
135
142
|
* API Module - Call RealtimeX public APIs
|
|
136
143
|
*/
|
|
137
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Error thrown when a permission is permanently denied
|
|
147
|
+
*/
|
|
148
|
+
declare class PermissionDeniedError extends Error {
|
|
149
|
+
readonly permission: string;
|
|
150
|
+
constructor(permission: string, message?: string);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Error thrown when a permission needs to be granted
|
|
154
|
+
*/
|
|
155
|
+
declare class PermissionRequiredError extends Error {
|
|
156
|
+
readonly permission: string;
|
|
157
|
+
constructor(permission: string, message?: string);
|
|
158
|
+
}
|
|
138
159
|
declare class ApiModule {
|
|
139
160
|
private realtimexUrl;
|
|
140
|
-
|
|
161
|
+
private appId;
|
|
162
|
+
private appName;
|
|
163
|
+
constructor(realtimexUrl: string, appId: string, appName?: string);
|
|
164
|
+
private getHeaders;
|
|
165
|
+
/**
|
|
166
|
+
* Request a single permission from Electron via internal API
|
|
167
|
+
*/
|
|
168
|
+
private requestPermission;
|
|
169
|
+
/**
|
|
170
|
+
* Make an API call with automatic permission handling
|
|
171
|
+
*/
|
|
172
|
+
private apiCall;
|
|
141
173
|
getAgents(): Promise<Agent[]>;
|
|
142
174
|
getWorkspaces(): Promise<Workspace[]>;
|
|
143
175
|
getThreads(workspaceSlug: string): Promise<Thread[]>;
|
|
@@ -232,12 +264,19 @@ declare class RealtimeXSDK {
|
|
|
232
264
|
port: PortModule;
|
|
233
265
|
readonly appId: string;
|
|
234
266
|
readonly appName: string | undefined;
|
|
267
|
+
private readonly realtimexUrl;
|
|
268
|
+
private readonly permissions;
|
|
235
269
|
private static DEFAULT_REALTIMEX_URL;
|
|
236
270
|
constructor(config?: SDKConfig);
|
|
271
|
+
/**
|
|
272
|
+
* Register app with RealtimeX hub and request declared permissions upfront.
|
|
273
|
+
* This is called automatically if permissions are provided in constructor.
|
|
274
|
+
*/
|
|
275
|
+
register(permissions?: string[]): Promise<void>;
|
|
237
276
|
/**
|
|
238
277
|
* Get environment variable (works in Node.js and browser)
|
|
239
278
|
*/
|
|
240
279
|
private getEnvVar;
|
|
241
280
|
}
|
|
242
281
|
|
|
243
|
-
export { ActivitiesModule, type Activity, type Agent, ApiModule, PortModule, RealtimeXSDK, type SDKConfig, type Task, TaskModule, type TaskRun, type Thread, type TriggerAgentPayload, type TriggerAgentResponse, WebhookModule, type Workspace };
|
|
282
|
+
export { ActivitiesModule, type Activity, type Agent, ApiModule, PermissionDeniedError, PermissionRequiredError, PortModule, RealtimeXSDK, type SDKConfig, type Task, TaskModule, type TaskRun, type Thread, type TriggerAgentPayload, type TriggerAgentResponse, WebhookModule, type Workspace };
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ interface SDKConfig {
|
|
|
8
8
|
appName?: string;
|
|
9
9
|
};
|
|
10
10
|
defaultPort?: number;
|
|
11
|
+
permissions?: string[];
|
|
11
12
|
}
|
|
12
13
|
interface Activity {
|
|
13
14
|
id: string;
|
|
@@ -86,7 +87,12 @@ interface Task {
|
|
|
86
87
|
declare class ActivitiesModule {
|
|
87
88
|
private baseUrl;
|
|
88
89
|
private appId;
|
|
89
|
-
|
|
90
|
+
private appName;
|
|
91
|
+
constructor(realtimexUrl: string, appId: string, appName?: string);
|
|
92
|
+
/**
|
|
93
|
+
* Request a single permission from Electron via internal API
|
|
94
|
+
*/
|
|
95
|
+
private requestPermission;
|
|
90
96
|
private request;
|
|
91
97
|
/**
|
|
92
98
|
* Insert a new activity
|
|
@@ -114,15 +120,16 @@ declare class ActivitiesModule {
|
|
|
114
120
|
}): Promise<Activity[]>;
|
|
115
121
|
}
|
|
116
122
|
|
|
117
|
-
/**
|
|
118
|
-
* Webhook Module - Call RealtimeX webhook
|
|
119
|
-
*/
|
|
120
|
-
|
|
121
123
|
declare class WebhookModule {
|
|
122
124
|
private realtimexUrl;
|
|
123
125
|
private appName?;
|
|
124
126
|
private appId?;
|
|
125
127
|
constructor(realtimexUrl: string, appName?: string, appId?: string);
|
|
128
|
+
/**
|
|
129
|
+
* Request a single permission from Electron via internal API
|
|
130
|
+
*/
|
|
131
|
+
private requestPermission;
|
|
132
|
+
private request;
|
|
126
133
|
triggerAgent(payload: TriggerAgentPayload): Promise<TriggerAgentResponse>;
|
|
127
134
|
ping(): Promise<{
|
|
128
135
|
success: boolean;
|
|
@@ -135,9 +142,34 @@ declare class WebhookModule {
|
|
|
135
142
|
* API Module - Call RealtimeX public APIs
|
|
136
143
|
*/
|
|
137
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Error thrown when a permission is permanently denied
|
|
147
|
+
*/
|
|
148
|
+
declare class PermissionDeniedError extends Error {
|
|
149
|
+
readonly permission: string;
|
|
150
|
+
constructor(permission: string, message?: string);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Error thrown when a permission needs to be granted
|
|
154
|
+
*/
|
|
155
|
+
declare class PermissionRequiredError extends Error {
|
|
156
|
+
readonly permission: string;
|
|
157
|
+
constructor(permission: string, message?: string);
|
|
158
|
+
}
|
|
138
159
|
declare class ApiModule {
|
|
139
160
|
private realtimexUrl;
|
|
140
|
-
|
|
161
|
+
private appId;
|
|
162
|
+
private appName;
|
|
163
|
+
constructor(realtimexUrl: string, appId: string, appName?: string);
|
|
164
|
+
private getHeaders;
|
|
165
|
+
/**
|
|
166
|
+
* Request a single permission from Electron via internal API
|
|
167
|
+
*/
|
|
168
|
+
private requestPermission;
|
|
169
|
+
/**
|
|
170
|
+
* Make an API call with automatic permission handling
|
|
171
|
+
*/
|
|
172
|
+
private apiCall;
|
|
141
173
|
getAgents(): Promise<Agent[]>;
|
|
142
174
|
getWorkspaces(): Promise<Workspace[]>;
|
|
143
175
|
getThreads(workspaceSlug: string): Promise<Thread[]>;
|
|
@@ -232,12 +264,19 @@ declare class RealtimeXSDK {
|
|
|
232
264
|
port: PortModule;
|
|
233
265
|
readonly appId: string;
|
|
234
266
|
readonly appName: string | undefined;
|
|
267
|
+
private readonly realtimexUrl;
|
|
268
|
+
private readonly permissions;
|
|
235
269
|
private static DEFAULT_REALTIMEX_URL;
|
|
236
270
|
constructor(config?: SDKConfig);
|
|
271
|
+
/**
|
|
272
|
+
* Register app with RealtimeX hub and request declared permissions upfront.
|
|
273
|
+
* This is called automatically if permissions are provided in constructor.
|
|
274
|
+
*/
|
|
275
|
+
register(permissions?: string[]): Promise<void>;
|
|
237
276
|
/**
|
|
238
277
|
* Get environment variable (works in Node.js and browser)
|
|
239
278
|
*/
|
|
240
279
|
private getEnvVar;
|
|
241
280
|
}
|
|
242
281
|
|
|
243
|
-
export { ActivitiesModule, type Activity, type Agent, ApiModule, PortModule, RealtimeXSDK, type SDKConfig, type Task, TaskModule, type TaskRun, type Thread, type TriggerAgentPayload, type TriggerAgentResponse, WebhookModule, type Workspace };
|
|
282
|
+
export { ActivitiesModule, type Activity, type Agent, ApiModule, PermissionDeniedError, PermissionRequiredError, PortModule, RealtimeXSDK, type SDKConfig, type Task, TaskModule, type TaskRun, type Thread, type TriggerAgentPayload, type TriggerAgentResponse, WebhookModule, type Workspace };
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,8 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
ActivitiesModule: () => ActivitiesModule,
|
|
34
34
|
ApiModule: () => ApiModule,
|
|
35
|
+
PermissionDeniedError: () => PermissionDeniedError,
|
|
36
|
+
PermissionRequiredError: () => PermissionRequiredError,
|
|
35
37
|
PortModule: () => PortModule,
|
|
36
38
|
RealtimeXSDK: () => RealtimeXSDK,
|
|
37
39
|
TaskModule: () => TaskModule,
|
|
@@ -39,11 +41,131 @@ __export(index_exports, {
|
|
|
39
41
|
});
|
|
40
42
|
module.exports = __toCommonJS(index_exports);
|
|
41
43
|
|
|
44
|
+
// src/modules/api.ts
|
|
45
|
+
var PermissionDeniedError = class extends Error {
|
|
46
|
+
constructor(permission, message) {
|
|
47
|
+
super(message || `Permission '${permission}' was denied`);
|
|
48
|
+
this.name = "PermissionDeniedError";
|
|
49
|
+
this.permission = permission;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var PermissionRequiredError = class extends Error {
|
|
53
|
+
constructor(permission, message) {
|
|
54
|
+
super(message || `Permission '${permission}' is required`);
|
|
55
|
+
this.name = "PermissionRequiredError";
|
|
56
|
+
this.permission = permission;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var ApiModule = class {
|
|
60
|
+
constructor(realtimexUrl, appId, appName) {
|
|
61
|
+
this.realtimexUrl = realtimexUrl.replace(/\/$/, "");
|
|
62
|
+
this.appId = appId;
|
|
63
|
+
this.appName = appName || process.env.RTX_APP_NAME || "Local App";
|
|
64
|
+
}
|
|
65
|
+
getHeaders() {
|
|
66
|
+
return {
|
|
67
|
+
"Content-Type": "application/json",
|
|
68
|
+
"x-app-id": this.appId
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Request a single permission from Electron via internal API
|
|
73
|
+
*/
|
|
74
|
+
async requestPermission(permission) {
|
|
75
|
+
try {
|
|
76
|
+
const response = await fetch(`${this.realtimexUrl}/api/local-apps/request-permission`, {
|
|
77
|
+
method: "POST",
|
|
78
|
+
headers: { "Content-Type": "application/json" },
|
|
79
|
+
body: JSON.stringify({
|
|
80
|
+
app_id: this.appId,
|
|
81
|
+
app_name: this.appName,
|
|
82
|
+
permission
|
|
83
|
+
})
|
|
84
|
+
});
|
|
85
|
+
const data = await response.json();
|
|
86
|
+
return data.granted === true;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Make an API call with automatic permission handling
|
|
93
|
+
*/
|
|
94
|
+
async apiCall(method, endpoint, options) {
|
|
95
|
+
const url = `${this.realtimexUrl}${endpoint}`;
|
|
96
|
+
const response = await fetch(url, {
|
|
97
|
+
method,
|
|
98
|
+
headers: this.getHeaders(),
|
|
99
|
+
...options
|
|
100
|
+
});
|
|
101
|
+
const data = await response.json();
|
|
102
|
+
if (response.status === 403) {
|
|
103
|
+
const errorCode = data.error;
|
|
104
|
+
const permission = data.permission;
|
|
105
|
+
const message = data.message;
|
|
106
|
+
if (errorCode === "PERMISSION_REQUIRED" && permission) {
|
|
107
|
+
const granted = await this.requestPermission(permission);
|
|
108
|
+
if (granted) {
|
|
109
|
+
return this.apiCall(method, endpoint, options);
|
|
110
|
+
} else {
|
|
111
|
+
throw new PermissionDeniedError(permission, message);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (errorCode === "PERMISSION_DENIED") {
|
|
115
|
+
throw new PermissionDeniedError(permission, message);
|
|
116
|
+
}
|
|
117
|
+
throw new Error(data.error || "Permission denied");
|
|
118
|
+
}
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
throw new Error(data.error || `API call failed: ${response.status}`);
|
|
121
|
+
}
|
|
122
|
+
return data;
|
|
123
|
+
}
|
|
124
|
+
async getAgents() {
|
|
125
|
+
const data = await this.apiCall("GET", "/agents");
|
|
126
|
+
return data.agents;
|
|
127
|
+
}
|
|
128
|
+
async getWorkspaces() {
|
|
129
|
+
const data = await this.apiCall("GET", "/workspaces");
|
|
130
|
+
return data.workspaces;
|
|
131
|
+
}
|
|
132
|
+
async getThreads(workspaceSlug) {
|
|
133
|
+
const data = await this.apiCall("GET", `/workspaces/${encodeURIComponent(workspaceSlug)}/threads`);
|
|
134
|
+
return data.threads;
|
|
135
|
+
}
|
|
136
|
+
async getTask(taskUuid) {
|
|
137
|
+
const data = await this.apiCall("GET", `/task/${encodeURIComponent(taskUuid)}`);
|
|
138
|
+
return { ...data.task, runs: data.runs };
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
42
142
|
// src/modules/activities.ts
|
|
43
143
|
var ActivitiesModule = class {
|
|
44
|
-
constructor(realtimexUrl, appId) {
|
|
144
|
+
constructor(realtimexUrl, appId, appName) {
|
|
45
145
|
this.baseUrl = realtimexUrl.replace(/\/$/, "");
|
|
46
146
|
this.appId = appId;
|
|
147
|
+
this.appName = appName || process.env.RTX_APP_NAME || "Local App";
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Request a single permission from Electron via internal API
|
|
151
|
+
*/
|
|
152
|
+
async requestPermission(permission) {
|
|
153
|
+
try {
|
|
154
|
+
const response = await fetch(`${this.baseUrl}/api/local-apps/request-permission`, {
|
|
155
|
+
method: "POST",
|
|
156
|
+
headers: { "Content-Type": "application/json" },
|
|
157
|
+
body: JSON.stringify({
|
|
158
|
+
app_id: this.appId,
|
|
159
|
+
app_name: this.appName,
|
|
160
|
+
permission
|
|
161
|
+
})
|
|
162
|
+
});
|
|
163
|
+
const data = await response.json();
|
|
164
|
+
return data.granted === true;
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error("[SDK] Permission request failed:", error);
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
47
169
|
}
|
|
48
170
|
async request(path, options = {}) {
|
|
49
171
|
const url = `${this.baseUrl}${path}`;
|
|
@@ -61,6 +183,22 @@ var ActivitiesModule = class {
|
|
|
61
183
|
}
|
|
62
184
|
});
|
|
63
185
|
const data = await response.json();
|
|
186
|
+
if (response.status === 403) {
|
|
187
|
+
const errorCode = data.error;
|
|
188
|
+
const permission = data.permission;
|
|
189
|
+
const message = data.message;
|
|
190
|
+
if (errorCode === "PERMISSION_REQUIRED" && permission) {
|
|
191
|
+
const granted = await this.requestPermission(permission);
|
|
192
|
+
if (granted) {
|
|
193
|
+
return this.request(path, options);
|
|
194
|
+
} else {
|
|
195
|
+
throw new PermissionDeniedError(permission, message);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (errorCode === "PERMISSION_DENIED") {
|
|
199
|
+
throw new PermissionDeniedError(permission, message);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
64
202
|
if (!response.ok) {
|
|
65
203
|
throw new Error(data.error || `Request failed: ${response.status}`);
|
|
66
204
|
}
|
|
@@ -127,13 +265,64 @@ var WebhookModule = class {
|
|
|
127
265
|
this.appName = appName;
|
|
128
266
|
this.appId = appId;
|
|
129
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* Request a single permission from Electron via internal API
|
|
270
|
+
*/
|
|
271
|
+
async requestPermission(permission) {
|
|
272
|
+
try {
|
|
273
|
+
const response = await fetch(`${this.realtimexUrl}/api/local-apps/request-permission`, {
|
|
274
|
+
method: "POST",
|
|
275
|
+
headers: { "Content-Type": "application/json" },
|
|
276
|
+
body: JSON.stringify({
|
|
277
|
+
app_id: this.appId,
|
|
278
|
+
app_name: this.appName,
|
|
279
|
+
permission
|
|
280
|
+
})
|
|
281
|
+
});
|
|
282
|
+
const data = await response.json();
|
|
283
|
+
return data.granted === true;
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error("[SDK] Permission request failed:", error);
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async request(path, options = {}) {
|
|
290
|
+
const url = `${this.realtimexUrl}${path}`;
|
|
291
|
+
const response = await fetch(url, {
|
|
292
|
+
...options,
|
|
293
|
+
headers: {
|
|
294
|
+
"Content-Type": "application/json",
|
|
295
|
+
...options.headers
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
const data = await response.json();
|
|
299
|
+
if (response.status === 403) {
|
|
300
|
+
const errorCode = data.error;
|
|
301
|
+
const permission = data.permission;
|
|
302
|
+
const message = data.message;
|
|
303
|
+
if (errorCode === "PERMISSION_REQUIRED" && permission) {
|
|
304
|
+
const granted = await this.requestPermission(permission);
|
|
305
|
+
if (granted) {
|
|
306
|
+
return this.request(path, options);
|
|
307
|
+
} else {
|
|
308
|
+
throw new PermissionDeniedError(permission, message);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (errorCode === "PERMISSION_DENIED") {
|
|
312
|
+
throw new PermissionDeniedError(permission, message);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (!response.ok) {
|
|
316
|
+
throw new Error(data.error || `Request failed: ${response.status}`);
|
|
317
|
+
}
|
|
318
|
+
return data;
|
|
319
|
+
}
|
|
130
320
|
async triggerAgent(payload) {
|
|
131
321
|
if (payload.auto_run && (!payload.agent_name || !payload.workspace_slug)) {
|
|
132
322
|
throw new Error("auto_run requires agent_name and workspace_slug");
|
|
133
323
|
}
|
|
134
|
-
|
|
324
|
+
return this.request("/webhooks/realtimex", {
|
|
135
325
|
method: "POST",
|
|
136
|
-
headers: { "Content-Type": "application/json" },
|
|
137
326
|
body: JSON.stringify({
|
|
138
327
|
app_name: this.appName,
|
|
139
328
|
app_id: this.appId,
|
|
@@ -148,54 +337,16 @@ var WebhookModule = class {
|
|
|
148
337
|
}
|
|
149
338
|
})
|
|
150
339
|
});
|
|
151
|
-
const data = await response.json();
|
|
152
|
-
if (!response.ok) throw new Error(data.error || "Failed to trigger agent");
|
|
153
|
-
return data;
|
|
154
340
|
}
|
|
155
341
|
async ping() {
|
|
156
|
-
|
|
342
|
+
return this.request("/webhooks/realtimex", {
|
|
157
343
|
method: "POST",
|
|
158
|
-
headers: { "Content-Type": "application/json" },
|
|
159
344
|
body: JSON.stringify({
|
|
160
345
|
app_name: this.appName,
|
|
161
346
|
app_id: this.appId,
|
|
162
347
|
event: "ping"
|
|
163
348
|
})
|
|
164
349
|
});
|
|
165
|
-
const data = await response.json();
|
|
166
|
-
if (!response.ok) throw new Error(data.error || "Ping failed");
|
|
167
|
-
return data;
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
// src/modules/api.ts
|
|
172
|
-
var ApiModule = class {
|
|
173
|
-
constructor(realtimexUrl) {
|
|
174
|
-
this.realtimexUrl = realtimexUrl.replace(/\/$/, "");
|
|
175
|
-
}
|
|
176
|
-
async getAgents() {
|
|
177
|
-
const response = await fetch(`${this.realtimexUrl}/agents`);
|
|
178
|
-
const data = await response.json();
|
|
179
|
-
if (!response.ok) throw new Error(data.error || "Failed to get agents");
|
|
180
|
-
return data.agents;
|
|
181
|
-
}
|
|
182
|
-
async getWorkspaces() {
|
|
183
|
-
const response = await fetch(`${this.realtimexUrl}/workspaces`);
|
|
184
|
-
const data = await response.json();
|
|
185
|
-
if (!response.ok) throw new Error(data.error || "Failed to get workspaces");
|
|
186
|
-
return data.workspaces;
|
|
187
|
-
}
|
|
188
|
-
async getThreads(workspaceSlug) {
|
|
189
|
-
const response = await fetch(`${this.realtimexUrl}/workspaces/${encodeURIComponent(workspaceSlug)}/threads`);
|
|
190
|
-
const data = await response.json();
|
|
191
|
-
if (!response.ok) throw new Error(data.error || "Failed to get threads");
|
|
192
|
-
return data.threads;
|
|
193
|
-
}
|
|
194
|
-
async getTask(taskUuid) {
|
|
195
|
-
const response = await fetch(`${this.realtimexUrl}/task/${encodeURIComponent(taskUuid)}`);
|
|
196
|
-
const data = await response.json();
|
|
197
|
-
if (!response.ok) throw new Error(data.error || "Failed to get task");
|
|
198
|
-
return { ...data.task, runs: data.runs };
|
|
199
350
|
}
|
|
200
351
|
};
|
|
201
352
|
|
|
@@ -328,12 +479,44 @@ var _RealtimeXSDK = class _RealtimeXSDK {
|
|
|
328
479
|
const envAppName = this.getEnvVar("RTX_APP_NAME");
|
|
329
480
|
this.appId = config.realtimex?.appId || envAppId || "";
|
|
330
481
|
this.appName = config.realtimex?.appName || envAppName;
|
|
331
|
-
|
|
332
|
-
this.
|
|
333
|
-
this.
|
|
334
|
-
this.
|
|
335
|
-
this.
|
|
482
|
+
this.permissions = config.permissions || [];
|
|
483
|
+
this.realtimexUrl = config.realtimex?.url || _RealtimeXSDK.DEFAULT_REALTIMEX_URL;
|
|
484
|
+
this.activities = new ActivitiesModule(this.realtimexUrl, this.appId, this.appName);
|
|
485
|
+
this.webhook = new WebhookModule(this.realtimexUrl, this.appName, this.appId);
|
|
486
|
+
this.api = new ApiModule(this.realtimexUrl, this.appId, this.appName);
|
|
487
|
+
this.task = new TaskModule(this.realtimexUrl, this.appName, this.appId);
|
|
336
488
|
this.port = new PortModule(config.defaultPort);
|
|
489
|
+
if (this.permissions.length > 0) {
|
|
490
|
+
this.register().catch((err) => {
|
|
491
|
+
console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Register app with RealtimeX hub and request declared permissions upfront.
|
|
497
|
+
* This is called automatically if permissions are provided in constructor.
|
|
498
|
+
*/
|
|
499
|
+
async register(permissions) {
|
|
500
|
+
const perms = permissions || this.permissions;
|
|
501
|
+
if (perms.length === 0) return;
|
|
502
|
+
try {
|
|
503
|
+
const response = await fetch(`${this.realtimexUrl.replace(/\/$/, "")}/sdk/register`, {
|
|
504
|
+
method: "POST",
|
|
505
|
+
headers: { "Content-Type": "application/json" },
|
|
506
|
+
body: JSON.stringify({
|
|
507
|
+
app_id: this.appId,
|
|
508
|
+
app_name: this.appName,
|
|
509
|
+
permissions: perms
|
|
510
|
+
})
|
|
511
|
+
});
|
|
512
|
+
const data = await response.json();
|
|
513
|
+
if (!response.ok) {
|
|
514
|
+
throw new Error(data.error || "Registration failed");
|
|
515
|
+
}
|
|
516
|
+
console.log(`[RealtimeX SDK] App registered successfully (${data.message})`);
|
|
517
|
+
} catch (error) {
|
|
518
|
+
throw new Error(`Failed to register app: ${error.message}`);
|
|
519
|
+
}
|
|
337
520
|
}
|
|
338
521
|
/**
|
|
339
522
|
* Get environment variable (works in Node.js and browser)
|
|
@@ -354,6 +537,8 @@ var RealtimeXSDK = _RealtimeXSDK;
|
|
|
354
537
|
0 && (module.exports = {
|
|
355
538
|
ActivitiesModule,
|
|
356
539
|
ApiModule,
|
|
540
|
+
PermissionDeniedError,
|
|
541
|
+
PermissionRequiredError,
|
|
357
542
|
PortModule,
|
|
358
543
|
RealtimeXSDK,
|
|
359
544
|
TaskModule,
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,128 @@
|
|
|
1
|
+
// src/modules/api.ts
|
|
2
|
+
var PermissionDeniedError = class extends Error {
|
|
3
|
+
constructor(permission, message) {
|
|
4
|
+
super(message || `Permission '${permission}' was denied`);
|
|
5
|
+
this.name = "PermissionDeniedError";
|
|
6
|
+
this.permission = permission;
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
var PermissionRequiredError = class extends Error {
|
|
10
|
+
constructor(permission, message) {
|
|
11
|
+
super(message || `Permission '${permission}' is required`);
|
|
12
|
+
this.name = "PermissionRequiredError";
|
|
13
|
+
this.permission = permission;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var ApiModule = class {
|
|
17
|
+
constructor(realtimexUrl, appId, appName) {
|
|
18
|
+
this.realtimexUrl = realtimexUrl.replace(/\/$/, "");
|
|
19
|
+
this.appId = appId;
|
|
20
|
+
this.appName = appName || process.env.RTX_APP_NAME || "Local App";
|
|
21
|
+
}
|
|
22
|
+
getHeaders() {
|
|
23
|
+
return {
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
"x-app-id": this.appId
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Request a single permission from Electron via internal API
|
|
30
|
+
*/
|
|
31
|
+
async requestPermission(permission) {
|
|
32
|
+
try {
|
|
33
|
+
const response = await fetch(`${this.realtimexUrl}/api/local-apps/request-permission`, {
|
|
34
|
+
method: "POST",
|
|
35
|
+
headers: { "Content-Type": "application/json" },
|
|
36
|
+
body: JSON.stringify({
|
|
37
|
+
app_id: this.appId,
|
|
38
|
+
app_name: this.appName,
|
|
39
|
+
permission
|
|
40
|
+
})
|
|
41
|
+
});
|
|
42
|
+
const data = await response.json();
|
|
43
|
+
return data.granted === true;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Make an API call with automatic permission handling
|
|
50
|
+
*/
|
|
51
|
+
async apiCall(method, endpoint, options) {
|
|
52
|
+
const url = `${this.realtimexUrl}${endpoint}`;
|
|
53
|
+
const response = await fetch(url, {
|
|
54
|
+
method,
|
|
55
|
+
headers: this.getHeaders(),
|
|
56
|
+
...options
|
|
57
|
+
});
|
|
58
|
+
const data = await response.json();
|
|
59
|
+
if (response.status === 403) {
|
|
60
|
+
const errorCode = data.error;
|
|
61
|
+
const permission = data.permission;
|
|
62
|
+
const message = data.message;
|
|
63
|
+
if (errorCode === "PERMISSION_REQUIRED" && permission) {
|
|
64
|
+
const granted = await this.requestPermission(permission);
|
|
65
|
+
if (granted) {
|
|
66
|
+
return this.apiCall(method, endpoint, options);
|
|
67
|
+
} else {
|
|
68
|
+
throw new PermissionDeniedError(permission, message);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (errorCode === "PERMISSION_DENIED") {
|
|
72
|
+
throw new PermissionDeniedError(permission, message);
|
|
73
|
+
}
|
|
74
|
+
throw new Error(data.error || "Permission denied");
|
|
75
|
+
}
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
throw new Error(data.error || `API call failed: ${response.status}`);
|
|
78
|
+
}
|
|
79
|
+
return data;
|
|
80
|
+
}
|
|
81
|
+
async getAgents() {
|
|
82
|
+
const data = await this.apiCall("GET", "/agents");
|
|
83
|
+
return data.agents;
|
|
84
|
+
}
|
|
85
|
+
async getWorkspaces() {
|
|
86
|
+
const data = await this.apiCall("GET", "/workspaces");
|
|
87
|
+
return data.workspaces;
|
|
88
|
+
}
|
|
89
|
+
async getThreads(workspaceSlug) {
|
|
90
|
+
const data = await this.apiCall("GET", `/workspaces/${encodeURIComponent(workspaceSlug)}/threads`);
|
|
91
|
+
return data.threads;
|
|
92
|
+
}
|
|
93
|
+
async getTask(taskUuid) {
|
|
94
|
+
const data = await this.apiCall("GET", `/task/${encodeURIComponent(taskUuid)}`);
|
|
95
|
+
return { ...data.task, runs: data.runs };
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
1
99
|
// src/modules/activities.ts
|
|
2
100
|
var ActivitiesModule = class {
|
|
3
|
-
constructor(realtimexUrl, appId) {
|
|
101
|
+
constructor(realtimexUrl, appId, appName) {
|
|
4
102
|
this.baseUrl = realtimexUrl.replace(/\/$/, "");
|
|
5
103
|
this.appId = appId;
|
|
104
|
+
this.appName = appName || process.env.RTX_APP_NAME || "Local App";
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Request a single permission from Electron via internal API
|
|
108
|
+
*/
|
|
109
|
+
async requestPermission(permission) {
|
|
110
|
+
try {
|
|
111
|
+
const response = await fetch(`${this.baseUrl}/api/local-apps/request-permission`, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
headers: { "Content-Type": "application/json" },
|
|
114
|
+
body: JSON.stringify({
|
|
115
|
+
app_id: this.appId,
|
|
116
|
+
app_name: this.appName,
|
|
117
|
+
permission
|
|
118
|
+
})
|
|
119
|
+
});
|
|
120
|
+
const data = await response.json();
|
|
121
|
+
return data.granted === true;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error("[SDK] Permission request failed:", error);
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
6
126
|
}
|
|
7
127
|
async request(path, options = {}) {
|
|
8
128
|
const url = `${this.baseUrl}${path}`;
|
|
@@ -20,6 +140,22 @@ var ActivitiesModule = class {
|
|
|
20
140
|
}
|
|
21
141
|
});
|
|
22
142
|
const data = await response.json();
|
|
143
|
+
if (response.status === 403) {
|
|
144
|
+
const errorCode = data.error;
|
|
145
|
+
const permission = data.permission;
|
|
146
|
+
const message = data.message;
|
|
147
|
+
if (errorCode === "PERMISSION_REQUIRED" && permission) {
|
|
148
|
+
const granted = await this.requestPermission(permission);
|
|
149
|
+
if (granted) {
|
|
150
|
+
return this.request(path, options);
|
|
151
|
+
} else {
|
|
152
|
+
throw new PermissionDeniedError(permission, message);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (errorCode === "PERMISSION_DENIED") {
|
|
156
|
+
throw new PermissionDeniedError(permission, message);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
23
159
|
if (!response.ok) {
|
|
24
160
|
throw new Error(data.error || `Request failed: ${response.status}`);
|
|
25
161
|
}
|
|
@@ -86,13 +222,64 @@ var WebhookModule = class {
|
|
|
86
222
|
this.appName = appName;
|
|
87
223
|
this.appId = appId;
|
|
88
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Request a single permission from Electron via internal API
|
|
227
|
+
*/
|
|
228
|
+
async requestPermission(permission) {
|
|
229
|
+
try {
|
|
230
|
+
const response = await fetch(`${this.realtimexUrl}/api/local-apps/request-permission`, {
|
|
231
|
+
method: "POST",
|
|
232
|
+
headers: { "Content-Type": "application/json" },
|
|
233
|
+
body: JSON.stringify({
|
|
234
|
+
app_id: this.appId,
|
|
235
|
+
app_name: this.appName,
|
|
236
|
+
permission
|
|
237
|
+
})
|
|
238
|
+
});
|
|
239
|
+
const data = await response.json();
|
|
240
|
+
return data.granted === true;
|
|
241
|
+
} catch (error) {
|
|
242
|
+
console.error("[SDK] Permission request failed:", error);
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
async request(path, options = {}) {
|
|
247
|
+
const url = `${this.realtimexUrl}${path}`;
|
|
248
|
+
const response = await fetch(url, {
|
|
249
|
+
...options,
|
|
250
|
+
headers: {
|
|
251
|
+
"Content-Type": "application/json",
|
|
252
|
+
...options.headers
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
const data = await response.json();
|
|
256
|
+
if (response.status === 403) {
|
|
257
|
+
const errorCode = data.error;
|
|
258
|
+
const permission = data.permission;
|
|
259
|
+
const message = data.message;
|
|
260
|
+
if (errorCode === "PERMISSION_REQUIRED" && permission) {
|
|
261
|
+
const granted = await this.requestPermission(permission);
|
|
262
|
+
if (granted) {
|
|
263
|
+
return this.request(path, options);
|
|
264
|
+
} else {
|
|
265
|
+
throw new PermissionDeniedError(permission, message);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (errorCode === "PERMISSION_DENIED") {
|
|
269
|
+
throw new PermissionDeniedError(permission, message);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (!response.ok) {
|
|
273
|
+
throw new Error(data.error || `Request failed: ${response.status}`);
|
|
274
|
+
}
|
|
275
|
+
return data;
|
|
276
|
+
}
|
|
89
277
|
async triggerAgent(payload) {
|
|
90
278
|
if (payload.auto_run && (!payload.agent_name || !payload.workspace_slug)) {
|
|
91
279
|
throw new Error("auto_run requires agent_name and workspace_slug");
|
|
92
280
|
}
|
|
93
|
-
|
|
281
|
+
return this.request("/webhooks/realtimex", {
|
|
94
282
|
method: "POST",
|
|
95
|
-
headers: { "Content-Type": "application/json" },
|
|
96
283
|
body: JSON.stringify({
|
|
97
284
|
app_name: this.appName,
|
|
98
285
|
app_id: this.appId,
|
|
@@ -107,54 +294,16 @@ var WebhookModule = class {
|
|
|
107
294
|
}
|
|
108
295
|
})
|
|
109
296
|
});
|
|
110
|
-
const data = await response.json();
|
|
111
|
-
if (!response.ok) throw new Error(data.error || "Failed to trigger agent");
|
|
112
|
-
return data;
|
|
113
297
|
}
|
|
114
298
|
async ping() {
|
|
115
|
-
|
|
299
|
+
return this.request("/webhooks/realtimex", {
|
|
116
300
|
method: "POST",
|
|
117
|
-
headers: { "Content-Type": "application/json" },
|
|
118
301
|
body: JSON.stringify({
|
|
119
302
|
app_name: this.appName,
|
|
120
303
|
app_id: this.appId,
|
|
121
304
|
event: "ping"
|
|
122
305
|
})
|
|
123
306
|
});
|
|
124
|
-
const data = await response.json();
|
|
125
|
-
if (!response.ok) throw new Error(data.error || "Ping failed");
|
|
126
|
-
return data;
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
// src/modules/api.ts
|
|
131
|
-
var ApiModule = class {
|
|
132
|
-
constructor(realtimexUrl) {
|
|
133
|
-
this.realtimexUrl = realtimexUrl.replace(/\/$/, "");
|
|
134
|
-
}
|
|
135
|
-
async getAgents() {
|
|
136
|
-
const response = await fetch(`${this.realtimexUrl}/agents`);
|
|
137
|
-
const data = await response.json();
|
|
138
|
-
if (!response.ok) throw new Error(data.error || "Failed to get agents");
|
|
139
|
-
return data.agents;
|
|
140
|
-
}
|
|
141
|
-
async getWorkspaces() {
|
|
142
|
-
const response = await fetch(`${this.realtimexUrl}/workspaces`);
|
|
143
|
-
const data = await response.json();
|
|
144
|
-
if (!response.ok) throw new Error(data.error || "Failed to get workspaces");
|
|
145
|
-
return data.workspaces;
|
|
146
|
-
}
|
|
147
|
-
async getThreads(workspaceSlug) {
|
|
148
|
-
const response = await fetch(`${this.realtimexUrl}/workspaces/${encodeURIComponent(workspaceSlug)}/threads`);
|
|
149
|
-
const data = await response.json();
|
|
150
|
-
if (!response.ok) throw new Error(data.error || "Failed to get threads");
|
|
151
|
-
return data.threads;
|
|
152
|
-
}
|
|
153
|
-
async getTask(taskUuid) {
|
|
154
|
-
const response = await fetch(`${this.realtimexUrl}/task/${encodeURIComponent(taskUuid)}`);
|
|
155
|
-
const data = await response.json();
|
|
156
|
-
if (!response.ok) throw new Error(data.error || "Failed to get task");
|
|
157
|
-
return { ...data.task, runs: data.runs };
|
|
158
307
|
}
|
|
159
308
|
};
|
|
160
309
|
|
|
@@ -287,12 +436,44 @@ var _RealtimeXSDK = class _RealtimeXSDK {
|
|
|
287
436
|
const envAppName = this.getEnvVar("RTX_APP_NAME");
|
|
288
437
|
this.appId = config.realtimex?.appId || envAppId || "";
|
|
289
438
|
this.appName = config.realtimex?.appName || envAppName;
|
|
290
|
-
|
|
291
|
-
this.
|
|
292
|
-
this.
|
|
293
|
-
this.
|
|
294
|
-
this.
|
|
439
|
+
this.permissions = config.permissions || [];
|
|
440
|
+
this.realtimexUrl = config.realtimex?.url || _RealtimeXSDK.DEFAULT_REALTIMEX_URL;
|
|
441
|
+
this.activities = new ActivitiesModule(this.realtimexUrl, this.appId, this.appName);
|
|
442
|
+
this.webhook = new WebhookModule(this.realtimexUrl, this.appName, this.appId);
|
|
443
|
+
this.api = new ApiModule(this.realtimexUrl, this.appId, this.appName);
|
|
444
|
+
this.task = new TaskModule(this.realtimexUrl, this.appName, this.appId);
|
|
295
445
|
this.port = new PortModule(config.defaultPort);
|
|
446
|
+
if (this.permissions.length > 0) {
|
|
447
|
+
this.register().catch((err) => {
|
|
448
|
+
console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Register app with RealtimeX hub and request declared permissions upfront.
|
|
454
|
+
* This is called automatically if permissions are provided in constructor.
|
|
455
|
+
*/
|
|
456
|
+
async register(permissions) {
|
|
457
|
+
const perms = permissions || this.permissions;
|
|
458
|
+
if (perms.length === 0) return;
|
|
459
|
+
try {
|
|
460
|
+
const response = await fetch(`${this.realtimexUrl.replace(/\/$/, "")}/sdk/register`, {
|
|
461
|
+
method: "POST",
|
|
462
|
+
headers: { "Content-Type": "application/json" },
|
|
463
|
+
body: JSON.stringify({
|
|
464
|
+
app_id: this.appId,
|
|
465
|
+
app_name: this.appName,
|
|
466
|
+
permissions: perms
|
|
467
|
+
})
|
|
468
|
+
});
|
|
469
|
+
const data = await response.json();
|
|
470
|
+
if (!response.ok) {
|
|
471
|
+
throw new Error(data.error || "Registration failed");
|
|
472
|
+
}
|
|
473
|
+
console.log(`[RealtimeX SDK] App registered successfully (${data.message})`);
|
|
474
|
+
} catch (error) {
|
|
475
|
+
throw new Error(`Failed to register app: ${error.message}`);
|
|
476
|
+
}
|
|
296
477
|
}
|
|
297
478
|
/**
|
|
298
479
|
* Get environment variable (works in Node.js and browser)
|
|
@@ -312,6 +493,8 @@ var RealtimeXSDK = _RealtimeXSDK;
|
|
|
312
493
|
export {
|
|
313
494
|
ActivitiesModule,
|
|
314
495
|
ApiModule,
|
|
496
|
+
PermissionDeniedError,
|
|
497
|
+
PermissionRequiredError,
|
|
315
498
|
PortModule,
|
|
316
499
|
RealtimeXSDK,
|
|
317
500
|
TaskModule,
|