@realtimex/sdk 1.0.8 → 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 +44 -7
- package/dist/index.d.ts +44 -7
- package/dist/index.js +232 -62
- package/dist/index.mjs +230 -62
- 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,11 +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;
|
|
141
|
-
|
|
162
|
+
private appName;
|
|
163
|
+
constructor(realtimexUrl: string, appId: string, appName?: string);
|
|
142
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;
|
|
143
173
|
getAgents(): Promise<Agent[]>;
|
|
144
174
|
getWorkspaces(): Promise<Workspace[]>;
|
|
145
175
|
getThreads(workspaceSlug: string): Promise<Thread[]>;
|
|
@@ -234,12 +264,19 @@ declare class RealtimeXSDK {
|
|
|
234
264
|
port: PortModule;
|
|
235
265
|
readonly appId: string;
|
|
236
266
|
readonly appName: string | undefined;
|
|
267
|
+
private readonly realtimexUrl;
|
|
268
|
+
private readonly permissions;
|
|
237
269
|
private static DEFAULT_REALTIMEX_URL;
|
|
238
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>;
|
|
239
276
|
/**
|
|
240
277
|
* Get environment variable (works in Node.js and browser)
|
|
241
278
|
*/
|
|
242
279
|
private getEnvVar;
|
|
243
280
|
}
|
|
244
281
|
|
|
245
|
-
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,11 +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;
|
|
141
|
-
|
|
162
|
+
private appName;
|
|
163
|
+
constructor(realtimexUrl: string, appId: string, appName?: string);
|
|
142
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;
|
|
143
173
|
getAgents(): Promise<Agent[]>;
|
|
144
174
|
getWorkspaces(): Promise<Workspace[]>;
|
|
145
175
|
getThreads(workspaceSlug: string): Promise<Thread[]>;
|
|
@@ -234,12 +264,19 @@ declare class RealtimeXSDK {
|
|
|
234
264
|
port: PortModule;
|
|
235
265
|
readonly appId: string;
|
|
236
266
|
readonly appName: string | undefined;
|
|
267
|
+
private readonly realtimexUrl;
|
|
268
|
+
private readonly permissions;
|
|
237
269
|
private static DEFAULT_REALTIMEX_URL;
|
|
238
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>;
|
|
239
276
|
/**
|
|
240
277
|
* Get environment variable (works in Node.js and browser)
|
|
241
278
|
*/
|
|
242
279
|
private getEnvVar;
|
|
243
280
|
}
|
|
244
281
|
|
|
245
|
-
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,69 +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, appId) {
|
|
174
|
-
this.realtimexUrl = realtimexUrl.replace(/\/$/, "");
|
|
175
|
-
this.appId = appId;
|
|
176
|
-
}
|
|
177
|
-
getHeaders() {
|
|
178
|
-
return {
|
|
179
|
-
"Content-Type": "application/json",
|
|
180
|
-
"x-app-id": this.appId
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
async getAgents() {
|
|
184
|
-
const response = await fetch(`${this.realtimexUrl}/agents`, {
|
|
185
|
-
headers: this.getHeaders()
|
|
186
|
-
});
|
|
187
|
-
const data = await response.json();
|
|
188
|
-
if (!response.ok) throw new Error(data.error || "Failed to get agents");
|
|
189
|
-
return data.agents;
|
|
190
|
-
}
|
|
191
|
-
async getWorkspaces() {
|
|
192
|
-
const response = await fetch(`${this.realtimexUrl}/workspaces`, {
|
|
193
|
-
headers: this.getHeaders()
|
|
194
|
-
});
|
|
195
|
-
const data = await response.json();
|
|
196
|
-
if (!response.ok) throw new Error(data.error || "Failed to get workspaces");
|
|
197
|
-
return data.workspaces;
|
|
198
|
-
}
|
|
199
|
-
async getThreads(workspaceSlug) {
|
|
200
|
-
const response = await fetch(`${this.realtimexUrl}/workspaces/${encodeURIComponent(workspaceSlug)}/threads`, {
|
|
201
|
-
headers: this.getHeaders()
|
|
202
|
-
});
|
|
203
|
-
const data = await response.json();
|
|
204
|
-
if (!response.ok) throw new Error(data.error || "Failed to get threads");
|
|
205
|
-
return data.threads;
|
|
206
|
-
}
|
|
207
|
-
async getTask(taskUuid) {
|
|
208
|
-
const response = await fetch(`${this.realtimexUrl}/task/${encodeURIComponent(taskUuid)}`, {
|
|
209
|
-
headers: this.getHeaders()
|
|
210
|
-
});
|
|
211
|
-
const data = await response.json();
|
|
212
|
-
if (!response.ok) throw new Error(data.error || "Failed to get task");
|
|
213
|
-
return { ...data.task, runs: data.runs };
|
|
214
350
|
}
|
|
215
351
|
};
|
|
216
352
|
|
|
@@ -343,12 +479,44 @@ var _RealtimeXSDK = class _RealtimeXSDK {
|
|
|
343
479
|
const envAppName = this.getEnvVar("RTX_APP_NAME");
|
|
344
480
|
this.appId = config.realtimex?.appId || envAppId || "";
|
|
345
481
|
this.appName = config.realtimex?.appName || envAppName;
|
|
346
|
-
|
|
347
|
-
this.
|
|
348
|
-
this.
|
|
349
|
-
this.
|
|
350
|
-
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);
|
|
351
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
|
+
}
|
|
352
520
|
}
|
|
353
521
|
/**
|
|
354
522
|
* Get environment variable (works in Node.js and browser)
|
|
@@ -369,6 +537,8 @@ var RealtimeXSDK = _RealtimeXSDK;
|
|
|
369
537
|
0 && (module.exports = {
|
|
370
538
|
ActivitiesModule,
|
|
371
539
|
ApiModule,
|
|
540
|
+
PermissionDeniedError,
|
|
541
|
+
PermissionRequiredError,
|
|
372
542
|
PortModule,
|
|
373
543
|
RealtimeXSDK,
|
|
374
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,69 +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, appId) {
|
|
133
|
-
this.realtimexUrl = realtimexUrl.replace(/\/$/, "");
|
|
134
|
-
this.appId = appId;
|
|
135
|
-
}
|
|
136
|
-
getHeaders() {
|
|
137
|
-
return {
|
|
138
|
-
"Content-Type": "application/json",
|
|
139
|
-
"x-app-id": this.appId
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
async getAgents() {
|
|
143
|
-
const response = await fetch(`${this.realtimexUrl}/agents`, {
|
|
144
|
-
headers: this.getHeaders()
|
|
145
|
-
});
|
|
146
|
-
const data = await response.json();
|
|
147
|
-
if (!response.ok) throw new Error(data.error || "Failed to get agents");
|
|
148
|
-
return data.agents;
|
|
149
|
-
}
|
|
150
|
-
async getWorkspaces() {
|
|
151
|
-
const response = await fetch(`${this.realtimexUrl}/workspaces`, {
|
|
152
|
-
headers: this.getHeaders()
|
|
153
|
-
});
|
|
154
|
-
const data = await response.json();
|
|
155
|
-
if (!response.ok) throw new Error(data.error || "Failed to get workspaces");
|
|
156
|
-
return data.workspaces;
|
|
157
|
-
}
|
|
158
|
-
async getThreads(workspaceSlug) {
|
|
159
|
-
const response = await fetch(`${this.realtimexUrl}/workspaces/${encodeURIComponent(workspaceSlug)}/threads`, {
|
|
160
|
-
headers: this.getHeaders()
|
|
161
|
-
});
|
|
162
|
-
const data = await response.json();
|
|
163
|
-
if (!response.ok) throw new Error(data.error || "Failed to get threads");
|
|
164
|
-
return data.threads;
|
|
165
|
-
}
|
|
166
|
-
async getTask(taskUuid) {
|
|
167
|
-
const response = await fetch(`${this.realtimexUrl}/task/${encodeURIComponent(taskUuid)}`, {
|
|
168
|
-
headers: this.getHeaders()
|
|
169
|
-
});
|
|
170
|
-
const data = await response.json();
|
|
171
|
-
if (!response.ok) throw new Error(data.error || "Failed to get task");
|
|
172
|
-
return { ...data.task, runs: data.runs };
|
|
173
307
|
}
|
|
174
308
|
};
|
|
175
309
|
|
|
@@ -302,12 +436,44 @@ var _RealtimeXSDK = class _RealtimeXSDK {
|
|
|
302
436
|
const envAppName = this.getEnvVar("RTX_APP_NAME");
|
|
303
437
|
this.appId = config.realtimex?.appId || envAppId || "";
|
|
304
438
|
this.appName = config.realtimex?.appName || envAppName;
|
|
305
|
-
|
|
306
|
-
this.
|
|
307
|
-
this.
|
|
308
|
-
this.
|
|
309
|
-
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);
|
|
310
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
|
+
}
|
|
311
477
|
}
|
|
312
478
|
/**
|
|
313
479
|
* Get environment variable (works in Node.js and browser)
|
|
@@ -327,6 +493,8 @@ var RealtimeXSDK = _RealtimeXSDK;
|
|
|
327
493
|
export {
|
|
328
494
|
ActivitiesModule,
|
|
329
495
|
ApiModule,
|
|
496
|
+
PermissionDeniedError,
|
|
497
|
+
PermissionRequiredError,
|
|
330
498
|
PortModule,
|
|
331
499
|
RealtimeXSDK,
|
|
332
500
|
TaskModule,
|