@shadowob/sdk 1.1.6 → 1.1.8
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/bin/shadow-server-app.mjs +58 -0
- package/dist/bridge.cjs +364 -0
- package/dist/bridge.d.cts +105 -0
- package/dist/bridge.d.ts +105 -0
- package/dist/bridge.js +26 -0
- package/dist/chunk-5QQ7ZR6B.js +192 -0
- package/dist/chunk-OMTGSMTQ.js +525 -0
- package/dist/index.cjs +943 -4
- package/dist/index.d.cts +198 -1844
- package/dist/index.d.ts +198 -1844
- package/dist/index.js +270 -3
- package/dist/server-app-node.cjs +82 -0
- package/dist/server-app-node.d.cts +21 -0
- package/dist/server-app-node.d.ts +21 -0
- package/dist/server-app-node.js +56 -0
- package/dist/server-app-qqsBtGmE.d.cts +2445 -0
- package/dist/server-app-qqsBtGmE.d.ts +2445 -0
- package/dist/server-app.cjs +575 -0
- package/dist/server-app.d.cts +2 -0
- package/dist/server-app.d.ts +2 -0
- package/dist/server-app.js +58 -0
- package/package.json +29 -2
package/dist/index.cjs
CHANGED
|
@@ -32,15 +32,717 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
CLIENT_EVENTS: () => import_shared.CLIENT_EVENTS,
|
|
34
34
|
SERVER_EVENTS: () => import_shared.SERVER_EVENTS,
|
|
35
|
+
SHADOW_SERVER_APP_COMMAND_COMPLETED_EVENT: () => SHADOW_SERVER_APP_COMMAND_COMPLETED_EVENT,
|
|
36
|
+
SHADOW_SERVER_APP_COMMAND_EVENTS: () => SHADOW_SERVER_APP_COMMAND_EVENTS,
|
|
37
|
+
SHADOW_SERVER_APP_COMMAND_FAILED_EVENT: () => SHADOW_SERVER_APP_COMMAND_FAILED_EVENT,
|
|
38
|
+
SHADOW_SERVER_APP_PROTOCOL: () => SHADOW_SERVER_APP_PROTOCOL,
|
|
39
|
+
ShadowBridge: () => ShadowBridge,
|
|
35
40
|
ShadowClient: () => ShadowClient,
|
|
41
|
+
ShadowServerAppCommandError: () => ShadowServerAppCommandError,
|
|
42
|
+
ShadowServerAppOutbox: () => ShadowServerAppOutbox,
|
|
43
|
+
ShadowServerAppRuntime: () => ShadowServerAppRuntime,
|
|
36
44
|
ShadowSocket: () => ShadowSocket,
|
|
37
45
|
ShadowVoiceConsumer: () => ShadowVoiceConsumer,
|
|
46
|
+
buildShadowServerAppInboxDelivery: () => buildShadowServerAppInboxDelivery,
|
|
47
|
+
buildShadowServerAppInboxTaskRequest: () => buildShadowServerAppInboxTaskRequest,
|
|
38
48
|
channelRoom: () => channelRoom,
|
|
49
|
+
createShadowServerAppManifest: () => createShadowServerAppManifest,
|
|
50
|
+
defineShadowServerApp: () => defineShadowServerApp,
|
|
51
|
+
extractShadowServerAppBearerToken: () => extractShadowServerAppBearerToken,
|
|
52
|
+
getShadowServerAppChannelMessageDeliveries: () => getShadowServerAppChannelMessageDeliveries,
|
|
53
|
+
getShadowServerAppChannelMessageErrors: () => getShadowServerAppChannelMessageErrors,
|
|
54
|
+
getShadowServerAppTaskCardId: () => getShadowServerAppTaskCardId,
|
|
55
|
+
introspectShadowServerAppToken: () => introspectShadowServerAppToken,
|
|
56
|
+
normalizeShadowServerAppCommandInput: () => normalizeShadowServerAppCommandInput,
|
|
57
|
+
parseShadowServerAppCommandRequest: () => parseShadowServerAppCommandRequest,
|
|
58
|
+
shadowServerAppActorAvatarUrl: () => shadowServerAppActorAvatarUrl,
|
|
59
|
+
shadowServerAppActorDisplayName: () => shadowServerAppActorDisplayName,
|
|
60
|
+
shadowServerAppActorRef: () => shadowServerAppActorRef,
|
|
61
|
+
shadowServerAppError: () => shadowServerAppError,
|
|
62
|
+
shadowServerAppInboxTaskEndpoint: () => shadowServerAppInboxTaskEndpoint,
|
|
39
63
|
threadRoom: () => threadRoom,
|
|
40
|
-
userRoom: () => userRoom
|
|
64
|
+
userRoom: () => userRoom,
|
|
65
|
+
validateShadowServerAppJsonSchema: () => validateShadowServerAppJsonSchema
|
|
41
66
|
});
|
|
42
67
|
module.exports = __toCommonJS(index_exports);
|
|
43
68
|
|
|
69
|
+
// src/server-app.ts
|
|
70
|
+
var SHADOW_SERVER_APP_PROTOCOL = "shadow.app/1";
|
|
71
|
+
var SHADOW_SERVER_APP_COMMAND_COMPLETED_EVENT = "server_app.command.completed";
|
|
72
|
+
var SHADOW_SERVER_APP_COMMAND_FAILED_EVENT = "server_app.command.failed";
|
|
73
|
+
var SHADOW_SERVER_APP_COMMAND_EVENTS = [
|
|
74
|
+
SHADOW_SERVER_APP_COMMAND_COMPLETED_EVENT,
|
|
75
|
+
SHADOW_SERVER_APP_COMMAND_FAILED_EVENT
|
|
76
|
+
];
|
|
77
|
+
function isProtocolRecord(value) {
|
|
78
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
79
|
+
}
|
|
80
|
+
function optionalProtocolString(value) {
|
|
81
|
+
return typeof value === "string" && value ? value : void 0;
|
|
82
|
+
}
|
|
83
|
+
function protocolPathSegment(value) {
|
|
84
|
+
return encodeURIComponent(value);
|
|
85
|
+
}
|
|
86
|
+
function shadowServerAppInboxTaskEndpoint(serverIdOrSlug, target) {
|
|
87
|
+
if ("channelId" in target && target.channelId) {
|
|
88
|
+
return `/api/channels/${protocolPathSegment(target.channelId)}/inbox/tasks`;
|
|
89
|
+
}
|
|
90
|
+
if ("agentId" in target && target.agentId) {
|
|
91
|
+
return `/api/servers/${protocolPathSegment(serverIdOrSlug)}/inboxes/${protocolPathSegment(
|
|
92
|
+
target.agentId
|
|
93
|
+
)}/tasks`;
|
|
94
|
+
}
|
|
95
|
+
throw new Error("Missing Inbox task target");
|
|
96
|
+
}
|
|
97
|
+
function buildShadowServerAppInboxTaskRequest(input) {
|
|
98
|
+
const appId = input.app.id ?? input.app.appId ?? input.app.appKey;
|
|
99
|
+
const serverAppData = isProtocolRecord(input.task.data?.serverApp) ? input.task.data.serverApp : {};
|
|
100
|
+
return {
|
|
101
|
+
endpoint: shadowServerAppInboxTaskEndpoint(input.serverIdOrSlug, input.target),
|
|
102
|
+
body: {
|
|
103
|
+
title: input.task.title,
|
|
104
|
+
body: input.task.body,
|
|
105
|
+
priority: input.task.priority,
|
|
106
|
+
idempotencyKey: input.task.idempotencyKey,
|
|
107
|
+
source: {
|
|
108
|
+
kind: "server_app",
|
|
109
|
+
id: appId,
|
|
110
|
+
appId,
|
|
111
|
+
appKey: input.app.appKey,
|
|
112
|
+
...input.app.serverId ? { serverId: input.app.serverId } : {},
|
|
113
|
+
...input.commandName ? { command: input.commandName } : {},
|
|
114
|
+
label: input.app.label ?? input.app.name ?? input.app.appKey,
|
|
115
|
+
...input.task.resource ? { resource: input.task.resource } : {}
|
|
116
|
+
},
|
|
117
|
+
data: {
|
|
118
|
+
...input.task.data ?? {},
|
|
119
|
+
serverApp: {
|
|
120
|
+
...serverAppData,
|
|
121
|
+
appKey: input.app.appKey,
|
|
122
|
+
...input.commandName ? { command: input.commandName } : {}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function getShadowServerAppTaskCardId(message) {
|
|
129
|
+
const metadata = isProtocolRecord(message) ? message.metadata : null;
|
|
130
|
+
const cards = isProtocolRecord(metadata) && Array.isArray(metadata.cards) ? metadata.cards : [];
|
|
131
|
+
for (const item of cards) {
|
|
132
|
+
if (!isProtocolRecord(item)) continue;
|
|
133
|
+
if (item.kind === "task" && typeof item.id === "string" && item.id) return item.id;
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
function buildShadowServerAppInboxDelivery(input) {
|
|
138
|
+
const message = isProtocolRecord(input.message) ? input.message : {};
|
|
139
|
+
return {
|
|
140
|
+
..."agentId" in input.target && input.target.agentId ? { agentId: input.target.agentId } : {},
|
|
141
|
+
channelId: optionalProtocolString(message.channelId),
|
|
142
|
+
messageId: optionalProtocolString(message.id),
|
|
143
|
+
cardId: getShadowServerAppTaskCardId(message),
|
|
144
|
+
idempotencyKey: input.idempotencyKey
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function shadowFromPayload(payload) {
|
|
148
|
+
if (payload.protocol === SHADOW_SERVER_APP_PROTOCOL) {
|
|
149
|
+
return payload;
|
|
150
|
+
}
|
|
151
|
+
const shadow = isProtocolRecord(payload.shadow) ? payload.shadow : null;
|
|
152
|
+
if (shadow?.protocol === SHADOW_SERVER_APP_PROTOCOL) {
|
|
153
|
+
return shadow;
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
function mergeShadowResult(value, shadow) {
|
|
158
|
+
if (!shadow) return value;
|
|
159
|
+
const existing = shadowFromPayload(value);
|
|
160
|
+
if (!existing) return { ...value, shadow };
|
|
161
|
+
return {
|
|
162
|
+
...value,
|
|
163
|
+
shadow: {
|
|
164
|
+
protocol: SHADOW_SERVER_APP_PROTOCOL,
|
|
165
|
+
outbox: {
|
|
166
|
+
...existing.outbox ?? {},
|
|
167
|
+
...shadow.outbox ?? {}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
function getShadowServerAppInboxDeliveries(payload) {
|
|
173
|
+
if (!isProtocolRecord(payload)) return [];
|
|
174
|
+
const shadow = shadowFromPayload(payload);
|
|
175
|
+
return shadow?.outbox?.deliveries ?? [];
|
|
176
|
+
}
|
|
177
|
+
function getShadowServerAppInboxErrors(payload) {
|
|
178
|
+
if (!isProtocolRecord(payload)) return [];
|
|
179
|
+
const shadow = shadowFromPayload(payload);
|
|
180
|
+
return shadow?.outbox?.errors ?? [];
|
|
181
|
+
}
|
|
182
|
+
function getShadowServerAppChannelMessageDeliveries(payload) {
|
|
183
|
+
if (!isProtocolRecord(payload)) return [];
|
|
184
|
+
const shadow = shadowFromPayload(payload);
|
|
185
|
+
return shadow?.outbox?.channelMessageDeliveries ?? [];
|
|
186
|
+
}
|
|
187
|
+
function getShadowServerAppChannelMessageErrors(payload) {
|
|
188
|
+
if (!isProtocolRecord(payload)) return [];
|
|
189
|
+
const shadow = shadowFromPayload(payload);
|
|
190
|
+
return shadow?.outbox?.channelMessageErrors ?? [];
|
|
191
|
+
}
|
|
192
|
+
function unwrapShadowServerAppCommandPayload(payload) {
|
|
193
|
+
if (isProtocolRecord(payload) && payload.ok === false) {
|
|
194
|
+
throw new Error(typeof payload.error === "string" ? payload.error : "Command failed");
|
|
195
|
+
}
|
|
196
|
+
if (isProtocolRecord(payload) && "result" in payload && payload.result !== void 0) {
|
|
197
|
+
const nested = unwrapShadowServerAppCommandPayload(payload.result);
|
|
198
|
+
const shadow = shadowFromPayload(payload);
|
|
199
|
+
if (isProtocolRecord(nested)) return mergeShadowResult(nested, shadow);
|
|
200
|
+
return nested;
|
|
201
|
+
}
|
|
202
|
+
return payload;
|
|
203
|
+
}
|
|
204
|
+
var ShadowServerAppOutbox = class {
|
|
205
|
+
inboxTasks = [];
|
|
206
|
+
channelMessages = [];
|
|
207
|
+
enqueueInboxTask(task) {
|
|
208
|
+
this.inboxTasks.push(task);
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
211
|
+
enqueueInboxTasks(tasks) {
|
|
212
|
+
for (const task of tasks) this.enqueueInboxTask(task);
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
sendChannelMessage(message) {
|
|
216
|
+
this.channelMessages.push(message);
|
|
217
|
+
return this;
|
|
218
|
+
}
|
|
219
|
+
sendChannelMessages(messages) {
|
|
220
|
+
for (const message of messages) this.sendChannelMessage(message);
|
|
221
|
+
return this;
|
|
222
|
+
}
|
|
223
|
+
toShadow() {
|
|
224
|
+
return {
|
|
225
|
+
protocol: SHADOW_SERVER_APP_PROTOCOL,
|
|
226
|
+
outbox: {
|
|
227
|
+
...this.inboxTasks.length > 0 ? { inboxTasks: [...this.inboxTasks] } : {},
|
|
228
|
+
...this.channelMessages.length > 0 ? { channelMessages: [...this.channelMessages] } : {}
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
attachTo(result) {
|
|
233
|
+
return { ...result, shadow: this.toShadow() };
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
function trimTrailingSlash(value) {
|
|
237
|
+
return value.replace(/\/$/, "");
|
|
238
|
+
}
|
|
239
|
+
function joinBasePath(baseUrl, path) {
|
|
240
|
+
const cleanBase = trimTrailingSlash(baseUrl);
|
|
241
|
+
const cleanPath = path.startsWith("/") ? path : `/${path}`;
|
|
242
|
+
return `${cleanBase}${cleanPath}`;
|
|
243
|
+
}
|
|
244
|
+
function extractShadowServerAppBearerToken(value) {
|
|
245
|
+
if (!value) return null;
|
|
246
|
+
return value.toLowerCase().startsWith("bearer ") ? value.slice(7).trim() : null;
|
|
247
|
+
}
|
|
248
|
+
function normalizeShadowServerAppCommandInput(value) {
|
|
249
|
+
if (value && typeof value === "object" && !Array.isArray(value) && "input" in value && Object.keys(value).every((key) => key === "input" || key === "channelId")) {
|
|
250
|
+
return value.input ?? {};
|
|
251
|
+
}
|
|
252
|
+
return value;
|
|
253
|
+
}
|
|
254
|
+
function createShadowServerAppManifest(manifest, options = {}) {
|
|
255
|
+
const publicBaseUrl = trimTrailingSlash(
|
|
256
|
+
options.publicBaseUrl ?? `http://localhost:${options.port ?? 4201}`
|
|
257
|
+
);
|
|
258
|
+
const apiBaseUrl = trimTrailingSlash(options.apiBaseUrl ?? publicBaseUrl);
|
|
259
|
+
const iframePath = options.iframePath ?? "/shadow/server";
|
|
260
|
+
const iconPath = options.iconPath ?? "/assets/icon.svg";
|
|
261
|
+
return {
|
|
262
|
+
...manifest,
|
|
263
|
+
iconUrl: joinBasePath(publicBaseUrl, iconPath),
|
|
264
|
+
iframe: manifest.iframe ? {
|
|
265
|
+
...manifest.iframe,
|
|
266
|
+
entry: joinBasePath(publicBaseUrl, iframePath),
|
|
267
|
+
allowedOrigins: options.allowedOrigins ?? [publicBaseUrl]
|
|
268
|
+
} : manifest.iframe,
|
|
269
|
+
api: {
|
|
270
|
+
...manifest.api,
|
|
271
|
+
baseUrl: apiBaseUrl
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function defineShadowServerApp(manifest, options = {}) {
|
|
276
|
+
return new ShadowServerAppRuntime(manifest, options);
|
|
277
|
+
}
|
|
278
|
+
var ShadowServerAppCommandError = class extends Error {
|
|
279
|
+
status;
|
|
280
|
+
issues;
|
|
281
|
+
constructor(status, error, issues) {
|
|
282
|
+
super(error);
|
|
283
|
+
this.name = "ShadowServerAppCommandError";
|
|
284
|
+
this.status = status;
|
|
285
|
+
this.issues = issues;
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
function shadowServerAppError(status, error, issues) {
|
|
289
|
+
return new ShadowServerAppCommandError(status, error, issues);
|
|
290
|
+
}
|
|
291
|
+
var ShadowServerAppRuntime = class {
|
|
292
|
+
constructor(sourceManifest, options = {}) {
|
|
293
|
+
this.sourceManifest = sourceManifest;
|
|
294
|
+
this.options = options;
|
|
295
|
+
}
|
|
296
|
+
manifest(options = {}) {
|
|
297
|
+
return createShadowServerAppManifest(this.sourceManifest, options);
|
|
298
|
+
}
|
|
299
|
+
defineCommands(handlers) {
|
|
300
|
+
return handlers;
|
|
301
|
+
}
|
|
302
|
+
actor(envelopeOrContext) {
|
|
303
|
+
return shadowServerAppActorRef(envelopeOrContext);
|
|
304
|
+
}
|
|
305
|
+
error(status, error, issues) {
|
|
306
|
+
return shadowServerAppError(status, error, issues);
|
|
307
|
+
}
|
|
308
|
+
async parseCommand(commandName, request) {
|
|
309
|
+
return parseShadowServerAppCommandRequest(
|
|
310
|
+
{
|
|
311
|
+
...request,
|
|
312
|
+
expectedCommand: commandName,
|
|
313
|
+
shadowBaseUrl: this.options.shadowBaseUrl,
|
|
314
|
+
fetchImpl: this.options.fetchImpl
|
|
315
|
+
}
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
async executeCommand(commandName, request, handlers) {
|
|
319
|
+
const parsed = await this.parseCommand(commandName, request);
|
|
320
|
+
if (!parsed.ok) return parseErrorResult(parsed);
|
|
321
|
+
return this.executeEnvelope(commandName, parsed.envelope, handlers);
|
|
322
|
+
}
|
|
323
|
+
async executeLocal(commandName, input, context, handlers) {
|
|
324
|
+
return this.executeEnvelope(
|
|
325
|
+
commandName,
|
|
326
|
+
{
|
|
327
|
+
input,
|
|
328
|
+
context: {
|
|
329
|
+
...context,
|
|
330
|
+
command: commandName
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
handlers
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
async executeEnvelope(commandName, envelope, handlers) {
|
|
337
|
+
const command = this.sourceManifest.commands.find((item) => item.name === commandName);
|
|
338
|
+
if (!command) return failureResult(404, "command_not_found");
|
|
339
|
+
const validation = validateShadowServerAppJsonSchema(command.inputSchema, envelope.input);
|
|
340
|
+
if (!validation.ok) return failureResult(422, "invalid_input", validation.issues);
|
|
341
|
+
const handler = handlers[commandName];
|
|
342
|
+
if (!handler) return failureResult(404, "command_not_found");
|
|
343
|
+
try {
|
|
344
|
+
const result = await handler(envelope.input, {
|
|
345
|
+
context: envelope.context,
|
|
346
|
+
actor: this.actor(envelope)
|
|
347
|
+
});
|
|
348
|
+
return { ok: true, status: 200, body: { ok: true, result } };
|
|
349
|
+
} catch (error) {
|
|
350
|
+
if (error instanceof ShadowServerAppCommandError) {
|
|
351
|
+
return failureResult(error.status, error.message, error.issues);
|
|
352
|
+
}
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
async function introspectShadowServerAppToken(input) {
|
|
358
|
+
const baseUrl = trimTrailingSlash(input.shadowBaseUrl ?? "http://localhost:3002");
|
|
359
|
+
const fetchImpl = input.fetchImpl ?? fetch;
|
|
360
|
+
const response = await fetchImpl(
|
|
361
|
+
`${baseUrl}/api/servers/${encodeURIComponent(input.serverId)}/apps/${encodeURIComponent(
|
|
362
|
+
input.appKey
|
|
363
|
+
)}/oauth/introspect`,
|
|
364
|
+
{
|
|
365
|
+
method: "POST",
|
|
366
|
+
headers: {
|
|
367
|
+
Authorization: `Bearer ${input.token}`,
|
|
368
|
+
"Content-Type": "application/json"
|
|
369
|
+
},
|
|
370
|
+
body: JSON.stringify({ token: input.token })
|
|
371
|
+
}
|
|
372
|
+
);
|
|
373
|
+
if (!response.ok) return null;
|
|
374
|
+
const payload = await response.json();
|
|
375
|
+
return payload.active ? payload : null;
|
|
376
|
+
}
|
|
377
|
+
async function parseShadowServerAppCommandRequest(input) {
|
|
378
|
+
const token = extractShadowServerAppBearerToken(input.authorizationHeader);
|
|
379
|
+
const serverId = input.serverIdHeader;
|
|
380
|
+
const appKey = input.appKeyHeader;
|
|
381
|
+
if (!token || !serverId || !appKey) {
|
|
382
|
+
return { ok: false, status: 401, error: "missing_oauth" };
|
|
383
|
+
}
|
|
384
|
+
const introspection = await introspectShadowServerAppToken({
|
|
385
|
+
token,
|
|
386
|
+
serverId,
|
|
387
|
+
appKey,
|
|
388
|
+
shadowBaseUrl: input.shadowBaseUrl,
|
|
389
|
+
fetchImpl: input.fetchImpl
|
|
390
|
+
}).catch(() => null);
|
|
391
|
+
const context = introspection?.shadow;
|
|
392
|
+
if (!context) return { ok: false, status: 401, error: "invalid_token" };
|
|
393
|
+
if (context.command !== input.expectedCommand) {
|
|
394
|
+
return { ok: false, status: 403, error: "wrong_command" };
|
|
395
|
+
}
|
|
396
|
+
let commandInput;
|
|
397
|
+
if (input.requestInput !== void 0) {
|
|
398
|
+
commandInput = input.requestInput;
|
|
399
|
+
} else {
|
|
400
|
+
let body;
|
|
401
|
+
try {
|
|
402
|
+
body = JSON.parse(input.requestBody ?? "{}");
|
|
403
|
+
} catch {
|
|
404
|
+
return { ok: false, status: 400, error: "invalid_json" };
|
|
405
|
+
}
|
|
406
|
+
commandInput = body.input ?? {};
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
ok: true,
|
|
410
|
+
envelope: {
|
|
411
|
+
input: commandInput,
|
|
412
|
+
context
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function validateShadowServerAppJsonSchema(schema, value) {
|
|
417
|
+
if (!schema) return { ok: true };
|
|
418
|
+
const issues = [];
|
|
419
|
+
validateJsonSchemaValue(schema, value, "", issues);
|
|
420
|
+
return issues.length ? { ok: false, issues } : { ok: true };
|
|
421
|
+
}
|
|
422
|
+
function shadowServerAppActorDisplayName(envelopeOrContext) {
|
|
423
|
+
const context = "context" in envelopeOrContext ? envelopeOrContext.context : envelopeOrContext;
|
|
424
|
+
const actor = context.actor;
|
|
425
|
+
const profile = actor.profile;
|
|
426
|
+
return profile?.displayName?.trim() || profile?.username?.trim() || (actor.buddyAgentId ? `Buddy ${actor.buddyAgentId.slice(0, 8)}` : null) || (actor.userId ? `${actor.kind}:${actor.userId.slice(0, 8)}` : null) || `${actor.kind}:unknown`;
|
|
427
|
+
}
|
|
428
|
+
function shadowServerAppActorAvatarUrl(envelopeOrContext) {
|
|
429
|
+
const context = "context" in envelopeOrContext ? envelopeOrContext.context : envelopeOrContext;
|
|
430
|
+
return context.actor.profile?.avatarUrl ?? null;
|
|
431
|
+
}
|
|
432
|
+
function shadowServerAppActorRef(envelopeOrContext) {
|
|
433
|
+
const context = "context" in envelopeOrContext ? envelopeOrContext.context : envelopeOrContext;
|
|
434
|
+
const actor = context.actor;
|
|
435
|
+
return {
|
|
436
|
+
kind: actor.kind,
|
|
437
|
+
id: actor.buddyAgentId ?? actor.userId ?? actor.ownerId ?? "unknown",
|
|
438
|
+
userId: actor.userId ?? null,
|
|
439
|
+
buddyAgentId: actor.buddyAgentId ?? null,
|
|
440
|
+
ownerId: actor.ownerId ?? null,
|
|
441
|
+
displayName: shadowServerAppActorDisplayName(context),
|
|
442
|
+
avatarUrl: shadowServerAppActorAvatarUrl(context)
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
function parseErrorResult(error) {
|
|
446
|
+
return failureResult(error.status, error.error, error.issues);
|
|
447
|
+
}
|
|
448
|
+
function failureResult(status, error, issues) {
|
|
449
|
+
return {
|
|
450
|
+
ok: false,
|
|
451
|
+
status,
|
|
452
|
+
body: issues === void 0 ? { ok: false, error } : { ok: false, error, issues }
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
function validateJsonSchemaValue(schema, value, path, issues) {
|
|
456
|
+
if (Array.isArray(schema.oneOf)) {
|
|
457
|
+
const matches = schema.oneOf.some((option) => {
|
|
458
|
+
const nestedIssues = [];
|
|
459
|
+
if (option && typeof option === "object" && !Array.isArray(option)) {
|
|
460
|
+
validateJsonSchemaValue(
|
|
461
|
+
option,
|
|
462
|
+
value,
|
|
463
|
+
path,
|
|
464
|
+
nestedIssues
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
return nestedIssues.length === 0;
|
|
468
|
+
});
|
|
469
|
+
if (!matches) issues.push({ path, message: "Expected value matching one schema option" });
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
const enumValues = schema.enum;
|
|
473
|
+
if (Array.isArray(enumValues) && !enumValues.includes(value)) {
|
|
474
|
+
issues.push({ path, message: `Expected one of ${enumValues.map(String).join(", ")}` });
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
const type = schema.type;
|
|
478
|
+
if (type === "object") {
|
|
479
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
480
|
+
issues.push({ path, message: "Expected object" });
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
const record = value;
|
|
484
|
+
const properties = schema.properties && typeof schema.properties === "object" && !Array.isArray(schema.properties) ? schema.properties : {};
|
|
485
|
+
const required = Array.isArray(schema.required) ? schema.required.map(String) : [];
|
|
486
|
+
for (const key of required) {
|
|
487
|
+
if (!(key in record)) issues.push({ path: joinJsonPath(path, key), message: "Required" });
|
|
488
|
+
}
|
|
489
|
+
for (const [key, propertySchema] of Object.entries(properties)) {
|
|
490
|
+
if (record[key] !== void 0) {
|
|
491
|
+
validateJsonSchemaValue(propertySchema, record[key], joinJsonPath(path, key), issues);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
const additionalProperties = schema.additionalProperties && typeof schema.additionalProperties === "object" && !Array.isArray(schema.additionalProperties) ? schema.additionalProperties : null;
|
|
495
|
+
if (additionalProperties) {
|
|
496
|
+
for (const [key, nestedValue] of Object.entries(record)) {
|
|
497
|
+
if (!(key in properties)) {
|
|
498
|
+
validateJsonSchemaValue(
|
|
499
|
+
additionalProperties,
|
|
500
|
+
nestedValue,
|
|
501
|
+
joinJsonPath(path, key),
|
|
502
|
+
issues
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
} else if (schema.additionalProperties === false) {
|
|
507
|
+
for (const key of Object.keys(record)) {
|
|
508
|
+
if (!(key in properties)) {
|
|
509
|
+
issues.push({ path: joinJsonPath(path, key), message: "Unknown property" });
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
if (type === "array") {
|
|
516
|
+
if (!Array.isArray(value)) {
|
|
517
|
+
issues.push({ path, message: "Expected array" });
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
const maxItems = typeof schema.maxItems === "number" ? schema.maxItems : null;
|
|
521
|
+
if (maxItems !== null && value.length > maxItems) {
|
|
522
|
+
issues.push({ path, message: `Expected at most ${maxItems} items` });
|
|
523
|
+
}
|
|
524
|
+
const itemSchema = schema.items && typeof schema.items === "object" && !Array.isArray(schema.items) ? schema.items : null;
|
|
525
|
+
if (itemSchema) {
|
|
526
|
+
value.forEach(
|
|
527
|
+
(item, index) => validateJsonSchemaValue(itemSchema, item, `${path}[${index}]`, issues)
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
if (type === "string") {
|
|
533
|
+
if (typeof value !== "string") {
|
|
534
|
+
issues.push({ path, message: "Expected string" });
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const maxLength = typeof schema.maxLength === "number" ? schema.maxLength : null;
|
|
538
|
+
const minLength = typeof schema.minLength === "number" ? schema.minLength : null;
|
|
539
|
+
if (minLength !== null && value.length < minLength) {
|
|
540
|
+
issues.push({ path, message: `Expected at least ${minLength} characters` });
|
|
541
|
+
}
|
|
542
|
+
if (maxLength !== null && value.length > maxLength) {
|
|
543
|
+
issues.push({ path, message: `Expected at most ${maxLength} characters` });
|
|
544
|
+
}
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
if (type === "number" || type === "integer") {
|
|
548
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
549
|
+
issues.push({ path, message: "Expected number" });
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
if (type === "integer" && !Number.isInteger(value)) {
|
|
553
|
+
issues.push({ path, message: "Expected integer" });
|
|
554
|
+
}
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
if (type === "boolean" && typeof value !== "boolean") {
|
|
558
|
+
issues.push({ path, message: "Expected boolean" });
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
function joinJsonPath(parent, key) {
|
|
562
|
+
return parent ? `${parent}.${key}` : key;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// src/bridge.ts
|
|
566
|
+
var ShadowBridge = class _ShadowBridge {
|
|
567
|
+
static commandRequestType = "shadow.app.command.request";
|
|
568
|
+
static commandResponseType = "shadow.app.command.response";
|
|
569
|
+
static inboxesRequestType = "shadow.app.inboxes.request";
|
|
570
|
+
static inboxesResponseType = "shadow.app.inboxes.response";
|
|
571
|
+
static enqueueInboxTaskRequestType = "shadow.app.inbox.enqueue.request";
|
|
572
|
+
static enqueueInboxTaskResponseType = "shadow.app.inbox.enqueue.response";
|
|
573
|
+
static openBuddyCreatorRequestType = "shadow.app.buddy.create.request";
|
|
574
|
+
static openBuddyCreatorResponseType = "shadow.app.buddy.create.response";
|
|
575
|
+
static inboxDeliveries(payload) {
|
|
576
|
+
return getShadowServerAppInboxDeliveries(payload);
|
|
577
|
+
}
|
|
578
|
+
static inboxErrors(payload) {
|
|
579
|
+
return getShadowServerAppInboxErrors(payload);
|
|
580
|
+
}
|
|
581
|
+
static channelMessageDeliveries(payload) {
|
|
582
|
+
return getShadowServerAppChannelMessageDeliveries(payload);
|
|
583
|
+
}
|
|
584
|
+
static channelMessageErrors(payload) {
|
|
585
|
+
return getShadowServerAppChannelMessageErrors(payload);
|
|
586
|
+
}
|
|
587
|
+
static unwrapCommandPayload(payload) {
|
|
588
|
+
return unwrapShadowServerAppCommandPayload(payload);
|
|
589
|
+
}
|
|
590
|
+
appKey;
|
|
591
|
+
targetOrigin;
|
|
592
|
+
timeoutMs;
|
|
593
|
+
win;
|
|
594
|
+
hasLaunchContext;
|
|
595
|
+
pending = /* @__PURE__ */ new Map();
|
|
596
|
+
onMessage = (event) => {
|
|
597
|
+
let data = event.data;
|
|
598
|
+
if (typeof data === "string") {
|
|
599
|
+
try {
|
|
600
|
+
data = JSON.parse(data || "{}");
|
|
601
|
+
} catch {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
if (!data || typeof data !== "object") return;
|
|
606
|
+
const record = data;
|
|
607
|
+
if (typeof record.requestId !== "string" || typeof record.type !== "string") return;
|
|
608
|
+
const entry = this.pending.get(record.requestId);
|
|
609
|
+
if (!entry || record.type !== entry.responseType) return;
|
|
610
|
+
this.pending.delete(record.requestId);
|
|
611
|
+
if (record.ok) entry.resolve(record.result);
|
|
612
|
+
else
|
|
613
|
+
entry.reject(
|
|
614
|
+
new Error(typeof record.error === "string" ? record.error : "Bridge request failed")
|
|
615
|
+
);
|
|
616
|
+
};
|
|
617
|
+
constructor(options) {
|
|
618
|
+
this.appKey = options.appKey;
|
|
619
|
+
this.targetOrigin = options.targetOrigin ?? "*";
|
|
620
|
+
this.timeoutMs = options.timeoutMs ?? 6e4;
|
|
621
|
+
this.win = options.windowRef ?? (typeof window === "undefined" ? null : window);
|
|
622
|
+
this.hasLaunchContext = this.resolveLaunchContext();
|
|
623
|
+
this.win?.addEventListener("message", this.onMessage);
|
|
624
|
+
}
|
|
625
|
+
dispose() {
|
|
626
|
+
this.win?.removeEventListener("message", this.onMessage);
|
|
627
|
+
for (const entry of this.pending.values()) {
|
|
628
|
+
entry.reject(new Error("ShadowBridge disposed"));
|
|
629
|
+
}
|
|
630
|
+
this.pending.clear();
|
|
631
|
+
}
|
|
632
|
+
isAvailable() {
|
|
633
|
+
if (!this.win) return false;
|
|
634
|
+
return this.hasLaunchContext && (this.win.parent !== this.win || !!this.win.ReactNativeWebView);
|
|
635
|
+
}
|
|
636
|
+
command(commandName, input, options = {}) {
|
|
637
|
+
return this.request(
|
|
638
|
+
_ShadowBridge.commandRequestType,
|
|
639
|
+
_ShadowBridge.commandResponseType,
|
|
640
|
+
{
|
|
641
|
+
commandName,
|
|
642
|
+
input,
|
|
643
|
+
...options.channelId ? { channelId: options.channelId } : {},
|
|
644
|
+
...options.task ? { task: options.task } : {}
|
|
645
|
+
},
|
|
646
|
+
options.timeoutMs
|
|
647
|
+
).then(
|
|
648
|
+
(payload) => unwrapShadowServerAppCommandPayload(payload)
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
inboxes(options = {}) {
|
|
652
|
+
return this.request(
|
|
653
|
+
_ShadowBridge.inboxesRequestType,
|
|
654
|
+
_ShadowBridge.inboxesResponseType,
|
|
655
|
+
{},
|
|
656
|
+
options.timeoutMs ?? 15e3
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
enqueueInboxTask(input, options = {}) {
|
|
660
|
+
return this.request(
|
|
661
|
+
_ShadowBridge.enqueueInboxTaskRequestType,
|
|
662
|
+
_ShadowBridge.enqueueInboxTaskResponseType,
|
|
663
|
+
input,
|
|
664
|
+
options.timeoutMs
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
openBuddyCreator(input = {}, options = {}) {
|
|
668
|
+
return this.request(
|
|
669
|
+
_ShadowBridge.openBuddyCreatorRequestType,
|
|
670
|
+
_ShadowBridge.openBuddyCreatorResponseType,
|
|
671
|
+
input,
|
|
672
|
+
options.timeoutMs ?? 10 * 60 * 1e3
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
unwrapCommandPayload(payload) {
|
|
676
|
+
return unwrapShadowServerAppCommandPayload(payload);
|
|
677
|
+
}
|
|
678
|
+
inboxDeliveries(payload) {
|
|
679
|
+
return getShadowServerAppInboxDeliveries(payload);
|
|
680
|
+
}
|
|
681
|
+
inboxErrors(payload) {
|
|
682
|
+
return getShadowServerAppInboxErrors(payload);
|
|
683
|
+
}
|
|
684
|
+
channelMessageDeliveries(payload) {
|
|
685
|
+
return getShadowServerAppChannelMessageDeliveries(payload);
|
|
686
|
+
}
|
|
687
|
+
channelMessageErrors(payload) {
|
|
688
|
+
return getShadowServerAppChannelMessageErrors(payload);
|
|
689
|
+
}
|
|
690
|
+
request(requestType, responseType, payload, timeoutMs = this.timeoutMs) {
|
|
691
|
+
if (!this.isAvailable()) {
|
|
692
|
+
return Promise.reject(
|
|
693
|
+
new Error("ShadowBridge is not available outside a Shadow launch frame")
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
const requestId = `req_${Math.random().toString(36).slice(2)}`;
|
|
697
|
+
this.postMessage({
|
|
698
|
+
type: requestType,
|
|
699
|
+
requestId,
|
|
700
|
+
appKey: this.appKey,
|
|
701
|
+
...payload
|
|
702
|
+
});
|
|
703
|
+
return new Promise((resolve, reject) => {
|
|
704
|
+
this.pending.set(requestId, {
|
|
705
|
+
responseType,
|
|
706
|
+
resolve,
|
|
707
|
+
reject
|
|
708
|
+
});
|
|
709
|
+
this.win?.setTimeout(() => {
|
|
710
|
+
if (!this.pending.has(requestId)) return;
|
|
711
|
+
this.pending.delete(requestId);
|
|
712
|
+
reject(new Error("Bridge request timed out"));
|
|
713
|
+
}, timeoutMs);
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
postMessage(message) {
|
|
717
|
+
if (!this.win) return;
|
|
718
|
+
if (this.win.ReactNativeWebView) {
|
|
719
|
+
this.win.ReactNativeWebView.postMessage(JSON.stringify(message));
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
this.win.parent.postMessage(message, this.targetOrigin);
|
|
723
|
+
}
|
|
724
|
+
resolveLaunchContext() {
|
|
725
|
+
if (!this.win) return false;
|
|
726
|
+
const storageKey = `shadow.bridge.launch:${this.appKey}`;
|
|
727
|
+
const memoryContexts = this.win.__shadowBridgeLaunchContexts ??= {};
|
|
728
|
+
const hasLaunchToken = new URLSearchParams(this.win.location.search).has("shadow_launch");
|
|
729
|
+
if (hasLaunchToken) {
|
|
730
|
+
memoryContexts[this.appKey] = true;
|
|
731
|
+
try {
|
|
732
|
+
this.win.sessionStorage?.setItem(storageKey, "1");
|
|
733
|
+
} catch {
|
|
734
|
+
}
|
|
735
|
+
return true;
|
|
736
|
+
}
|
|
737
|
+
if (memoryContexts[this.appKey]) return true;
|
|
738
|
+
try {
|
|
739
|
+
return this.win.sessionStorage?.getItem(storageKey) === "1";
|
|
740
|
+
} catch {
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
|
|
44
746
|
// src/client.ts
|
|
45
747
|
function sanitizeErrorBody(body) {
|
|
46
748
|
if (!body) return "(empty response)";
|
|
@@ -71,6 +773,9 @@ var ShadowClient = class {
|
|
|
71
773
|
this.baseUrl = baseUrl.replace(/\/api\/?$/, "");
|
|
72
774
|
}
|
|
73
775
|
baseUrl;
|
|
776
|
+
serverAppEventStreamUrl(eventStreamPath) {
|
|
777
|
+
return new URL(eventStreamPath, `${this.baseUrl}/`).toString();
|
|
778
|
+
}
|
|
74
779
|
isShadowPrivateMediaUrl(value) {
|
|
75
780
|
if (value.startsWith("/shadow/uploads/") || value.startsWith("/api/media/signed/")) {
|
|
76
781
|
return true;
|
|
@@ -161,6 +866,18 @@ var ShadowClient = class {
|
|
|
161
866
|
body: JSON.stringify(data)
|
|
162
867
|
});
|
|
163
868
|
}
|
|
869
|
+
async startPasswordReset(data) {
|
|
870
|
+
return this.request("/api/auth/password-reset/start", {
|
|
871
|
+
method: "POST",
|
|
872
|
+
body: JSON.stringify(data)
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
async completePasswordReset(data) {
|
|
876
|
+
return this.request("/api/auth/password-reset/complete", {
|
|
877
|
+
method: "POST",
|
|
878
|
+
body: JSON.stringify(data)
|
|
879
|
+
});
|
|
880
|
+
}
|
|
164
881
|
async refreshToken(refreshToken) {
|
|
165
882
|
return this.request("/api/auth/refresh", {
|
|
166
883
|
method: "POST",
|
|
@@ -246,6 +963,27 @@ var ShadowClient = class {
|
|
|
246
963
|
async generateAgentToken(agentId) {
|
|
247
964
|
return this.request(`/api/agents/${agentId}/token`, { method: "POST" });
|
|
248
965
|
}
|
|
966
|
+
async listConnectorComputers() {
|
|
967
|
+
return this.request("/api/connector/computers");
|
|
968
|
+
}
|
|
969
|
+
async createConnectorBootstrap(data) {
|
|
970
|
+
return this.request("/api/connector/computers/bootstrap", {
|
|
971
|
+
method: "POST",
|
|
972
|
+
body: JSON.stringify(data)
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
async createAgentOnConnectorComputer(computerId, data) {
|
|
976
|
+
return this.request(`/api/connector/computers/${computerId}/buddies`, {
|
|
977
|
+
method: "POST",
|
|
978
|
+
body: JSON.stringify(data)
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
async configureAgentOnConnectorComputer(computerId, agentId, data) {
|
|
982
|
+
return this.request(`/api/connector/computers/${computerId}/buddies/${agentId}/configure`, {
|
|
983
|
+
method: "POST",
|
|
984
|
+
body: JSON.stringify(data)
|
|
985
|
+
});
|
|
986
|
+
}
|
|
249
987
|
async startAgent(agentId) {
|
|
250
988
|
return this.request(`/api/agents/${agentId}/start`, { method: "POST" });
|
|
251
989
|
}
|
|
@@ -291,6 +1029,7 @@ var ShadowClient = class {
|
|
|
291
1029
|
const policy = {
|
|
292
1030
|
serverId,
|
|
293
1031
|
...data.channelId !== void 0 ? { channelId: data.channelId } : {},
|
|
1032
|
+
...data.listen !== void 0 ? { listen: data.listen } : {},
|
|
294
1033
|
...data.mentionOnly !== void 0 ? { mentionOnly: data.mentionOnly } : {},
|
|
295
1034
|
...data.reply !== void 0 ? { reply: data.reply } : {},
|
|
296
1035
|
...data.config !== void 0 ? { config: data.config } : {}
|
|
@@ -384,6 +1123,24 @@ var ShadowClient = class {
|
|
|
384
1123
|
}
|
|
385
1124
|
);
|
|
386
1125
|
}
|
|
1126
|
+
async updateServerAppAccessPolicy(serverIdOrSlug, appKey, data) {
|
|
1127
|
+
return this.request(
|
|
1128
|
+
`/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(appKey)}/access-policy`,
|
|
1129
|
+
{
|
|
1130
|
+
method: "PATCH",
|
|
1131
|
+
body: JSON.stringify(data)
|
|
1132
|
+
}
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
async approveServerAppCommand(serverIdOrSlug, appKey, data) {
|
|
1136
|
+
return this.request(
|
|
1137
|
+
`/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(appKey)}/approvals`,
|
|
1138
|
+
{
|
|
1139
|
+
method: "POST",
|
|
1140
|
+
body: JSON.stringify(data)
|
|
1141
|
+
}
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
387
1144
|
async getServerAppSkills(serverIdOrSlug, appKey) {
|
|
388
1145
|
return this.request(`/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(appKey)}/skills`);
|
|
389
1146
|
}
|
|
@@ -429,6 +1186,7 @@ var ShadowClient = class {
|
|
|
429
1186
|
const form = new FormData();
|
|
430
1187
|
form.set("input", JSON.stringify(data.input ?? {}));
|
|
431
1188
|
if (data.channelId) form.set("channelId", data.channelId);
|
|
1189
|
+
if (data.task) form.set("task", JSON.stringify(data.task));
|
|
432
1190
|
form.set(data.field ?? "file", data.file, data.filename);
|
|
433
1191
|
return this.request(
|
|
434
1192
|
`/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(appKey)}/commands/${encodeURIComponent(
|
|
@@ -651,6 +1409,83 @@ var ShadowClient = class {
|
|
|
651
1409
|
async getMessage(messageId) {
|
|
652
1410
|
return this.request(`/api/messages/${messageId}`);
|
|
653
1411
|
}
|
|
1412
|
+
async listBuddyInboxes() {
|
|
1413
|
+
return this.request("/api/buddy-inboxes");
|
|
1414
|
+
}
|
|
1415
|
+
async listServerBuddyInboxes(serverIdOrSlug) {
|
|
1416
|
+
return this.request(`/api/servers/${serverIdOrSlug}/inboxes`);
|
|
1417
|
+
}
|
|
1418
|
+
async ensureBuddyInbox(serverIdOrSlug, agentId) {
|
|
1419
|
+
return this.request(`/api/servers/${serverIdOrSlug}/inboxes/${agentId}`, {
|
|
1420
|
+
method: "POST"
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
async getBuddyInboxAdmissionPolicy(serverIdOrSlug, agentId) {
|
|
1424
|
+
return this.request(`/api/servers/${serverIdOrSlug}/inboxes/${agentId}/admission-policy`);
|
|
1425
|
+
}
|
|
1426
|
+
async updateBuddyInboxAdmissionPolicy(serverIdOrSlug, agentId, policy) {
|
|
1427
|
+
return this.request(`/api/servers/${serverIdOrSlug}/inboxes/${agentId}/admission-policy`, {
|
|
1428
|
+
method: "PUT",
|
|
1429
|
+
body: JSON.stringify(policy)
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
async listBuddyInboxAdmissionPending(serverIdOrSlug, agentId) {
|
|
1433
|
+
return this.request(`/api/servers/${serverIdOrSlug}/inboxes/${agentId}/admission-pending`);
|
|
1434
|
+
}
|
|
1435
|
+
async approveBuddyInboxAdmissionPending(serverIdOrSlug, agentId, pendingId) {
|
|
1436
|
+
return this.request(
|
|
1437
|
+
`/api/servers/${serverIdOrSlug}/inboxes/${agentId}/admission-pending/${pendingId}/approve`,
|
|
1438
|
+
{ method: "POST" }
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
async rejectBuddyInboxAdmissionPending(serverIdOrSlug, agentId, pendingId) {
|
|
1442
|
+
return this.request(
|
|
1443
|
+
`/api/servers/${serverIdOrSlug}/inboxes/${agentId}/admission-pending/${pendingId}/reject`,
|
|
1444
|
+
{ method: "POST" }
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1447
|
+
async enqueueInboxTaskForAgent(serverIdOrSlug, agentId, task) {
|
|
1448
|
+
return this.request(`/api/servers/${serverIdOrSlug}/inboxes/${agentId}/tasks`, {
|
|
1449
|
+
method: "POST",
|
|
1450
|
+
body: JSON.stringify(task)
|
|
1451
|
+
});
|
|
1452
|
+
}
|
|
1453
|
+
async enqueueInboxTask(channelId, task) {
|
|
1454
|
+
return this.request(`/api/channels/${channelId}/inbox/tasks`, {
|
|
1455
|
+
method: "POST",
|
|
1456
|
+
body: JSON.stringify(task)
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
async claimTaskCard(messageId, cardId, data = {}) {
|
|
1460
|
+
return this.request(`/api/messages/${messageId}/cards/${cardId}/claim`, {
|
|
1461
|
+
method: "POST",
|
|
1462
|
+
body: JSON.stringify(data)
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
async updateTaskCard(messageId, cardId, data) {
|
|
1466
|
+
return this.request(`/api/messages/${messageId}/cards/${cardId}`, {
|
|
1467
|
+
method: "PATCH",
|
|
1468
|
+
body: JSON.stringify(data)
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
async retryTaskCard(messageId, cardId, data = {}) {
|
|
1472
|
+
return this.request(`/api/messages/${messageId}/cards/${cardId}/retry`, {
|
|
1473
|
+
method: "POST",
|
|
1474
|
+
body: JSON.stringify(data)
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
async claimNextInboxTask(serverIdOrSlug, agentId, data = {}) {
|
|
1478
|
+
return this.request(`/api/servers/${serverIdOrSlug}/inboxes/${agentId}/claim-next`, {
|
|
1479
|
+
method: "POST",
|
|
1480
|
+
body: JSON.stringify(data)
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
async promoteMessageToInboxTask(messageId, data) {
|
|
1484
|
+
return this.request(`/api/messages/${messageId}/inbox/tasks`, {
|
|
1485
|
+
method: "POST",
|
|
1486
|
+
body: JSON.stringify(data)
|
|
1487
|
+
});
|
|
1488
|
+
}
|
|
654
1489
|
async submitInteractiveAction(messageId, input) {
|
|
655
1490
|
return this.request(`/api/messages/${messageId}/interactive`, {
|
|
656
1491
|
method: "POST",
|
|
@@ -802,6 +1637,19 @@ var ShadowClient = class {
|
|
|
802
1637
|
formData.append("messageId", messageId);
|
|
803
1638
|
} else if (messageId) {
|
|
804
1639
|
if (messageId.messageId) formData.append("messageId", messageId.messageId);
|
|
1640
|
+
if (messageId.kind) formData.append("kind", messageId.kind);
|
|
1641
|
+
if (typeof messageId.durationMs === "number") {
|
|
1642
|
+
formData.append("durationMs", String(messageId.durationMs));
|
|
1643
|
+
}
|
|
1644
|
+
if (messageId.waveformPeaks) {
|
|
1645
|
+
formData.append("waveformPeaks", JSON.stringify(messageId.waveformPeaks));
|
|
1646
|
+
}
|
|
1647
|
+
if (messageId.transcriptText) formData.append("transcriptText", messageId.transcriptText);
|
|
1648
|
+
if (messageId.transcriptLanguage) {
|
|
1649
|
+
formData.append("transcriptLanguage", messageId.transcriptLanguage);
|
|
1650
|
+
}
|
|
1651
|
+
if (messageId.transcriptSource)
|
|
1652
|
+
formData.append("transcriptSource", messageId.transcriptSource);
|
|
805
1653
|
}
|
|
806
1654
|
const url = `${this.baseUrl}/api/media/upload`;
|
|
807
1655
|
const res = await fetch(url, {
|
|
@@ -817,6 +1665,43 @@ var ShadowClient = class {
|
|
|
817
1665
|
}
|
|
818
1666
|
return res.json();
|
|
819
1667
|
}
|
|
1668
|
+
async sendVoiceMessage(channelId, file, filename, contentType, opts) {
|
|
1669
|
+
const message = await this.sendMessage(channelId, "\u200B", {
|
|
1670
|
+
threadId: opts.threadId,
|
|
1671
|
+
replyToId: opts.replyToId
|
|
1672
|
+
});
|
|
1673
|
+
await this.uploadMedia(file, filename, contentType, {
|
|
1674
|
+
messageId: message.id,
|
|
1675
|
+
kind: "voice",
|
|
1676
|
+
durationMs: opts.durationMs,
|
|
1677
|
+
waveformPeaks: opts.waveformPeaks,
|
|
1678
|
+
transcriptText: opts.transcriptText,
|
|
1679
|
+
transcriptLanguage: opts.transcriptLanguage,
|
|
1680
|
+
transcriptSource: opts.transcriptSource
|
|
1681
|
+
});
|
|
1682
|
+
return this.getMessage(message.id);
|
|
1683
|
+
}
|
|
1684
|
+
async markVoicePlayed(attachmentId, input) {
|
|
1685
|
+
return this.request(`/api/attachments/${attachmentId}/voice-playback`, {
|
|
1686
|
+
method: "PUT",
|
|
1687
|
+
body: JSON.stringify(input ?? {})
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
async requestVoiceTranscript(attachmentId, input) {
|
|
1691
|
+
return this.request(`/api/attachments/${attachmentId}/transcript`, {
|
|
1692
|
+
method: "POST",
|
|
1693
|
+
body: JSON.stringify({
|
|
1694
|
+
mode: "server",
|
|
1695
|
+
...input?.language ? { language: input.language } : {}
|
|
1696
|
+
})
|
|
1697
|
+
});
|
|
1698
|
+
}
|
|
1699
|
+
async updateVoiceTranscript(attachmentId, input) {
|
|
1700
|
+
return this.request(`/api/attachments/${attachmentId}/transcript`, {
|
|
1701
|
+
method: "PUT",
|
|
1702
|
+
body: JSON.stringify(input)
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
820
1705
|
async resolveAttachmentMediaUrl(attachmentId, options) {
|
|
821
1706
|
const params = new URLSearchParams();
|
|
822
1707
|
params.set("disposition", options?.disposition ?? "inline");
|
|
@@ -1072,9 +1957,14 @@ var ShadowClient = class {
|
|
|
1072
1957
|
return this.request(`/api/auth/sessions/${sessionId}`, { method: "DELETE" });
|
|
1073
1958
|
}
|
|
1074
1959
|
async changePassword(data) {
|
|
1960
|
+
const oldPassword = data.oldPassword ?? data.currentPassword;
|
|
1075
1961
|
return this.request("/api/auth/password", {
|
|
1076
1962
|
method: "PUT",
|
|
1077
|
-
body: JSON.stringify(
|
|
1963
|
+
body: JSON.stringify({
|
|
1964
|
+
oldPassword,
|
|
1965
|
+
newPassword: data.newPassword,
|
|
1966
|
+
confirmPassword: data.confirmPassword ?? data.newPassword
|
|
1967
|
+
})
|
|
1078
1968
|
});
|
|
1079
1969
|
}
|
|
1080
1970
|
async getDashboard() {
|
|
@@ -1083,7 +1973,13 @@ var ShadowClient = class {
|
|
|
1083
1973
|
async loginWithGoogleIdToken(idToken) {
|
|
1084
1974
|
return this.request("/api/auth/google/id-token", {
|
|
1085
1975
|
method: "POST",
|
|
1086
|
-
body: JSON.stringify({ idToken })
|
|
1976
|
+
body: JSON.stringify({ credential: idToken })
|
|
1977
|
+
});
|
|
1978
|
+
}
|
|
1979
|
+
async loginWithAppleIdentityToken(data) {
|
|
1980
|
+
return this.request("/api/auth/oauth/apple/mobile", {
|
|
1981
|
+
method: "POST",
|
|
1982
|
+
body: JSON.stringify(data)
|
|
1087
1983
|
});
|
|
1088
1984
|
}
|
|
1089
1985
|
// ── Friendships ───────────────────────────────────────────────────────
|
|
@@ -1832,6 +2728,24 @@ var ShadowClient = class {
|
|
|
1832
2728
|
const suffix = qs.toString();
|
|
1833
2729
|
return this.request(`/api/discover/business${suffix ? `?${suffix}` : ""}`);
|
|
1834
2730
|
}
|
|
2731
|
+
async discoverMarketplaceProducts(params) {
|
|
2732
|
+
const qs = new URLSearchParams();
|
|
2733
|
+
if (params?.q) qs.set("q", params.q);
|
|
2734
|
+
if (params?.tag) qs.set("tag", params.tag);
|
|
2735
|
+
if (params?.category) qs.set("category", params.category);
|
|
2736
|
+
if (params?.scope) qs.set("scope", params.scope);
|
|
2737
|
+
if (params?.limit) qs.set("limit", String(params.limit));
|
|
2738
|
+
if (params?.offset) qs.set("offset", String(params.offset));
|
|
2739
|
+
const suffix = qs.toString();
|
|
2740
|
+
return this.request(`/api/discover/marketplace/products${suffix ? `?${suffix}` : ""}`);
|
|
2741
|
+
}
|
|
2742
|
+
async discoverMarketplaceCategories(params) {
|
|
2743
|
+
const qs = new URLSearchParams();
|
|
2744
|
+
if (params?.q) qs.set("q", params.q);
|
|
2745
|
+
if (params?.limit) qs.set("limit", String(params.limit));
|
|
2746
|
+
const suffix = qs.toString();
|
|
2747
|
+
return this.request(`/api/discover/marketplace/categories${suffix ? `?${suffix}` : ""}`);
|
|
2748
|
+
}
|
|
1835
2749
|
async discoverBusinessHub(params) {
|
|
1836
2750
|
return this.discoverCommerce(params);
|
|
1837
2751
|
}
|
|
@@ -2299,10 +3213,35 @@ var ShadowVoiceConsumer = class {
|
|
|
2299
3213
|
0 && (module.exports = {
|
|
2300
3214
|
CLIENT_EVENTS,
|
|
2301
3215
|
SERVER_EVENTS,
|
|
3216
|
+
SHADOW_SERVER_APP_COMMAND_COMPLETED_EVENT,
|
|
3217
|
+
SHADOW_SERVER_APP_COMMAND_EVENTS,
|
|
3218
|
+
SHADOW_SERVER_APP_COMMAND_FAILED_EVENT,
|
|
3219
|
+
SHADOW_SERVER_APP_PROTOCOL,
|
|
3220
|
+
ShadowBridge,
|
|
2302
3221
|
ShadowClient,
|
|
3222
|
+
ShadowServerAppCommandError,
|
|
3223
|
+
ShadowServerAppOutbox,
|
|
3224
|
+
ShadowServerAppRuntime,
|
|
2303
3225
|
ShadowSocket,
|
|
2304
3226
|
ShadowVoiceConsumer,
|
|
3227
|
+
buildShadowServerAppInboxDelivery,
|
|
3228
|
+
buildShadowServerAppInboxTaskRequest,
|
|
2305
3229
|
channelRoom,
|
|
3230
|
+
createShadowServerAppManifest,
|
|
3231
|
+
defineShadowServerApp,
|
|
3232
|
+
extractShadowServerAppBearerToken,
|
|
3233
|
+
getShadowServerAppChannelMessageDeliveries,
|
|
3234
|
+
getShadowServerAppChannelMessageErrors,
|
|
3235
|
+
getShadowServerAppTaskCardId,
|
|
3236
|
+
introspectShadowServerAppToken,
|
|
3237
|
+
normalizeShadowServerAppCommandInput,
|
|
3238
|
+
parseShadowServerAppCommandRequest,
|
|
3239
|
+
shadowServerAppActorAvatarUrl,
|
|
3240
|
+
shadowServerAppActorDisplayName,
|
|
3241
|
+
shadowServerAppActorRef,
|
|
3242
|
+
shadowServerAppError,
|
|
3243
|
+
shadowServerAppInboxTaskEndpoint,
|
|
2306
3244
|
threadRoom,
|
|
2307
|
-
userRoom
|
|
3245
|
+
userRoom,
|
|
3246
|
+
validateShadowServerAppJsonSchema
|
|
2308
3247
|
});
|