@palettelab/sdk 0.1.20 → 0.1.22
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 +47 -1
- package/dist/components/index.d.mts +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/hooks/index.d.mts +2 -2
- package/dist/hooks/index.d.ts +2 -2
- package/dist/{index-D0i35Hem.d.ts → index-CGSwI4TZ.d.ts} +1 -1
- package/dist/{index-DsfTFnZb.d.mts → index-CmY9M7Rg.d.mts} +1 -1
- package/dist/index.d.mts +175 -4
- package/dist/index.d.ts +175 -4
- package/dist/index.js +293 -1
- package/dist/index.mjs +286 -1
- package/dist/{plugin-dpLzOtF6.d.mts → plugin-DXqw6d0s.d.mts} +37 -1
- package/dist/{plugin-dpLzOtF6.d.ts → plugin-DXqw6d0s.d.ts} +37 -1
- package/dist/router/index.d.mts +2 -2
- package/dist/router/index.d.ts +2 -2
- package/dist/types/index.d.mts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20,8 +20,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
+
BrokerCallError: () => BrokerCallError,
|
|
24
|
+
CrossAppGrantError: () => CrossAppGrantError,
|
|
23
25
|
DataRoomClient: () => DataRoomClient,
|
|
24
26
|
Link: () => Link,
|
|
27
|
+
MissingDependencyError: () => MissingDependencyError,
|
|
25
28
|
OrganizationClient: () => OrganizationClient,
|
|
26
29
|
PaletteApiError: () => PaletteApiError,
|
|
27
30
|
PaletteAppRouter: () => PaletteAppRouter,
|
|
@@ -31,12 +34,14 @@ __export(src_exports, {
|
|
|
31
34
|
UserClient: () => UserClient,
|
|
32
35
|
apiFetch: () => apiFetch,
|
|
33
36
|
apiUpload: () => apiUpload,
|
|
37
|
+
broker: () => broker,
|
|
34
38
|
createMockPlatformContext: () => createMockPlatformContext,
|
|
35
39
|
createPaletteClient: () => createPaletteClient,
|
|
36
40
|
createSandboxBridge: () => createSandboxBridge,
|
|
37
41
|
dataRooms: () => dataRooms,
|
|
38
42
|
disconnectConnection: () => disconnectConnection,
|
|
39
43
|
errorFromResponse: () => errorFromResponse,
|
|
44
|
+
events: () => events,
|
|
40
45
|
getBaseUrl: () => getBaseUrl,
|
|
41
46
|
getConnections: () => getConnections,
|
|
42
47
|
getInstallConfig: () => getInstallConfig,
|
|
@@ -47,7 +52,9 @@ __export(src_exports, {
|
|
|
47
52
|
isSandboxRuntime: () => isSandboxRuntime,
|
|
48
53
|
normalizePaletteLanguage: () => normalizePaletteLanguage,
|
|
49
54
|
notFound: () => notFound,
|
|
55
|
+
palette: () => palette,
|
|
50
56
|
requireConnection: () => requireConnection,
|
|
57
|
+
servicesProxy: () => servicesProxy,
|
|
51
58
|
setBaseUrl: () => setBaseUrl,
|
|
52
59
|
startConnection: () => startConnection,
|
|
53
60
|
translate: () => translate,
|
|
@@ -385,6 +392,272 @@ var DataRoomClient = class {
|
|
|
385
392
|
};
|
|
386
393
|
var dataRooms = new DataRoomClient();
|
|
387
394
|
|
|
395
|
+
// src/services.ts
|
|
396
|
+
var BrokerCallError = class extends Error {
|
|
397
|
+
constructor(message, target, status) {
|
|
398
|
+
super(message);
|
|
399
|
+
this.target = target;
|
|
400
|
+
this.status = status;
|
|
401
|
+
this.name = "BrokerCallError";
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
var MissingDependencyError = class extends BrokerCallError {
|
|
405
|
+
constructor(message, target, status) {
|
|
406
|
+
super(message, target, status);
|
|
407
|
+
this.name = "MissingDependencyError";
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
var CrossAppGrantError = class extends BrokerCallError {
|
|
411
|
+
constructor(message, target, status) {
|
|
412
|
+
super(message, target, status);
|
|
413
|
+
this.name = "CrossAppGrantError";
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
function brokerError(message, target, status) {
|
|
417
|
+
const lower = message.toLowerCase();
|
|
418
|
+
if (status === 424 || lower.includes("not installed") || lower.includes("provider app")) {
|
|
419
|
+
return new MissingDependencyError(message, target, status);
|
|
420
|
+
}
|
|
421
|
+
if (status === 403 && (lower.includes("grant") || lower.includes("declared"))) {
|
|
422
|
+
return new CrossAppGrantError(message, target, status);
|
|
423
|
+
}
|
|
424
|
+
return new BrokerCallError(message, target, status);
|
|
425
|
+
}
|
|
426
|
+
var CALLER_HEADER = "X-Palette-Caller-App";
|
|
427
|
+
function currentPluginId() {
|
|
428
|
+
if (typeof window === "undefined") return void 0;
|
|
429
|
+
const match = window.location.pathname.match(/\/apps\/([^/?#]+)/);
|
|
430
|
+
return match ? decodeURIComponent(match[1]) : void 0;
|
|
431
|
+
}
|
|
432
|
+
async function brokerCallDirect(target, payload, options = {}) {
|
|
433
|
+
const callerAppId = options.callerAppId ?? currentPluginId();
|
|
434
|
+
const headers = {};
|
|
435
|
+
if (callerAppId) headers[CALLER_HEADER] = callerAppId;
|
|
436
|
+
let res;
|
|
437
|
+
try {
|
|
438
|
+
res = await apiFetch("/api/v1/os-broker/dispatch", {
|
|
439
|
+
method: "POST",
|
|
440
|
+
headers,
|
|
441
|
+
body: JSON.stringify({ target, payload: payload ?? {}, caller_app_id: callerAppId }),
|
|
442
|
+
signal: options.signal
|
|
443
|
+
});
|
|
444
|
+
} catch (error) {
|
|
445
|
+
const e = error;
|
|
446
|
+
throw brokerError(typeof e.detail === "string" ? e.detail : e.message, target, e.status);
|
|
447
|
+
}
|
|
448
|
+
if (!res.ok) {
|
|
449
|
+
let detail;
|
|
450
|
+
try {
|
|
451
|
+
detail = (await res.json()).detail;
|
|
452
|
+
} catch {
|
|
453
|
+
detail = res.statusText;
|
|
454
|
+
}
|
|
455
|
+
throw brokerError(detail ?? `broker dispatch failed: ${res.status}`, target, res.status);
|
|
456
|
+
}
|
|
457
|
+
const body = await res.json();
|
|
458
|
+
return body.result;
|
|
459
|
+
}
|
|
460
|
+
async function brokerCallSandboxed(target, payload, options = {}) {
|
|
461
|
+
return sandboxRequest({
|
|
462
|
+
kind: "palette.broker.call",
|
|
463
|
+
target,
|
|
464
|
+
payload: payload ?? {},
|
|
465
|
+
callerAppId: options.callerAppId
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
async function brokerEmitDirect(target, payload, options = {}) {
|
|
469
|
+
const callerAppId = options.callerAppId ?? currentPluginId();
|
|
470
|
+
if (!callerAppId) {
|
|
471
|
+
throw new BrokerCallError(
|
|
472
|
+
"events.emit requires a caller app id \u2014 only plugins may emit declared events",
|
|
473
|
+
target
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
const res = await apiFetch("/api/v1/os-broker/events/emit", {
|
|
477
|
+
method: "POST",
|
|
478
|
+
headers: { [CALLER_HEADER]: callerAppId },
|
|
479
|
+
body: JSON.stringify({ target, payload: payload ?? {}, caller_app_id: callerAppId }),
|
|
480
|
+
signal: options.signal
|
|
481
|
+
});
|
|
482
|
+
if (!res.ok) {
|
|
483
|
+
let detail;
|
|
484
|
+
try {
|
|
485
|
+
detail = (await res.json()).detail;
|
|
486
|
+
} catch {
|
|
487
|
+
detail = res.statusText;
|
|
488
|
+
}
|
|
489
|
+
throw new BrokerCallError(detail ?? `event emit failed: ${res.status}`, target, res.status);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
async function brokerEmitSandboxed(target, payload, options = {}) {
|
|
493
|
+
await sandboxRequest({
|
|
494
|
+
kind: "palette.broker.emit",
|
|
495
|
+
target,
|
|
496
|
+
payload: payload ?? {},
|
|
497
|
+
callerAppId: options.callerAppId
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
function sandboxRequest(message) {
|
|
501
|
+
if (typeof window === "undefined") {
|
|
502
|
+
return Promise.reject(new BrokerCallError("sandbox bridge unavailable", message.target));
|
|
503
|
+
}
|
|
504
|
+
return new Promise((resolve, reject) => {
|
|
505
|
+
const id = `${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
506
|
+
const onMessage = (ev) => {
|
|
507
|
+
const data = ev.data;
|
|
508
|
+
if (!data || data.id !== id) return;
|
|
509
|
+
window.removeEventListener("message", onMessage);
|
|
510
|
+
if (data.error) {
|
|
511
|
+
reject(new BrokerCallError(data.error.message, message.target, data.error.status));
|
|
512
|
+
} else {
|
|
513
|
+
resolve(data.result);
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
window.addEventListener("message", onMessage);
|
|
517
|
+
window.parent?.postMessage({ ...message, id }, "*");
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
var broker = {
|
|
521
|
+
async call(target, payload, options) {
|
|
522
|
+
return isSandboxRuntime() ? brokerCallSandboxed(target, payload, options) : brokerCallDirect(target, payload, options);
|
|
523
|
+
},
|
|
524
|
+
async emit(target, payload, options) {
|
|
525
|
+
if (isSandboxRuntime()) return brokerEmitSandboxed(target, payload, options);
|
|
526
|
+
return brokerEmitDirect(target, payload, options);
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
function servicesProxy(namespaceVersion) {
|
|
530
|
+
if (!namespaceVersion.includes("/")) {
|
|
531
|
+
throw new BrokerCallError("namespaceVersion must look like 'org/v1'", namespaceVersion);
|
|
532
|
+
}
|
|
533
|
+
const buildProxy = (segments) => new Proxy(function() {
|
|
534
|
+
}, {
|
|
535
|
+
get(_target, prop) {
|
|
536
|
+
if (typeof prop !== "string") return void 0;
|
|
537
|
+
return buildProxy([...segments, prop]);
|
|
538
|
+
},
|
|
539
|
+
apply(_target, _thisArg, args) {
|
|
540
|
+
const method = segments.join(".");
|
|
541
|
+
if (!method) {
|
|
542
|
+
throw new BrokerCallError("missing method name", namespaceVersion);
|
|
543
|
+
}
|
|
544
|
+
const [payload, options] = args;
|
|
545
|
+
return broker.call(`${namespaceVersion}#${method}`, payload, options);
|
|
546
|
+
}
|
|
547
|
+
});
|
|
548
|
+
return buildProxy([]);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// src/events.ts
|
|
552
|
+
var SUBSCRIBERS = /* @__PURE__ */ new Map();
|
|
553
|
+
var activeStream = null;
|
|
554
|
+
var activeStreamUrl = null;
|
|
555
|
+
var sandboxBound = false;
|
|
556
|
+
function currentPluginId2() {
|
|
557
|
+
if (typeof window === "undefined") return void 0;
|
|
558
|
+
const match = window.location.pathname.match(/\/apps\/([^/?#]+)/);
|
|
559
|
+
return match ? decodeURIComponent(match[1]) : void 0;
|
|
560
|
+
}
|
|
561
|
+
function streamUrl() {
|
|
562
|
+
const params = new URLSearchParams();
|
|
563
|
+
const targets = Array.from(SUBSCRIBERS.keys());
|
|
564
|
+
if (targets.length) params.set("targets", targets.join(","));
|
|
565
|
+
const callerAppId = currentPluginId2();
|
|
566
|
+
if (callerAppId) params.set("caller_app_id", callerAppId);
|
|
567
|
+
const query = params.toString();
|
|
568
|
+
return `${getBaseUrl()}/api/v1/os-broker/events/stream${query ? `?${query}` : ""}`;
|
|
569
|
+
}
|
|
570
|
+
function ensureStream() {
|
|
571
|
+
if (activeStream || typeof window === "undefined") return;
|
|
572
|
+
activeStreamUrl = streamUrl();
|
|
573
|
+
activeStream = new EventSource(activeStreamUrl, { withCredentials: true });
|
|
574
|
+
activeStream.onmessage = (ev) => {
|
|
575
|
+
try {
|
|
576
|
+
const data = JSON.parse(ev.data);
|
|
577
|
+
const handlers = SUBSCRIBERS.get(data.target);
|
|
578
|
+
if (!handlers) return;
|
|
579
|
+
for (const handler of handlers) {
|
|
580
|
+
try {
|
|
581
|
+
handler(data.payload, data.meta);
|
|
582
|
+
} catch (err) {
|
|
583
|
+
console.error("palette.events handler threw", err);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
} catch (err) {
|
|
587
|
+
console.warn("palette.events: malformed event", err);
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
activeStream.onerror = () => {
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
function refreshStream() {
|
|
594
|
+
if (typeof window === "undefined" || isSandboxRuntime()) return;
|
|
595
|
+
const nextUrl = streamUrl();
|
|
596
|
+
if (activeStream && activeStreamUrl === nextUrl) return;
|
|
597
|
+
activeStream?.close();
|
|
598
|
+
activeStream = null;
|
|
599
|
+
activeStreamUrl = null;
|
|
600
|
+
if (SUBSCRIBERS.size > 0) ensureStream();
|
|
601
|
+
}
|
|
602
|
+
function ensureSandboxBound() {
|
|
603
|
+
if (sandboxBound || typeof window === "undefined") return;
|
|
604
|
+
sandboxBound = true;
|
|
605
|
+
window.addEventListener("message", (ev) => {
|
|
606
|
+
const data = ev.data;
|
|
607
|
+
if (!data || data.kind !== "palette.broker.event" || !data.target) return;
|
|
608
|
+
const handlers = SUBSCRIBERS.get(data.target);
|
|
609
|
+
if (!handlers) return;
|
|
610
|
+
const meta = data.meta ?? { target: data.target, organizationId: null, occurredAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
611
|
+
for (const handler of handlers) {
|
|
612
|
+
try {
|
|
613
|
+
handler(data.payload, meta);
|
|
614
|
+
} catch (err) {
|
|
615
|
+
console.error("palette.events handler threw", err);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
var events = {
|
|
621
|
+
on(target, handler) {
|
|
622
|
+
let handlers = SUBSCRIBERS.get(target);
|
|
623
|
+
if (!handlers) {
|
|
624
|
+
handlers = /* @__PURE__ */ new Set();
|
|
625
|
+
SUBSCRIBERS.set(target, handlers);
|
|
626
|
+
}
|
|
627
|
+
handlers.add(handler);
|
|
628
|
+
if (isSandboxRuntime()) {
|
|
629
|
+
ensureSandboxBound();
|
|
630
|
+
window.parent?.postMessage({ kind: "palette.broker.subscribe", target }, "*");
|
|
631
|
+
} else {
|
|
632
|
+
refreshStream();
|
|
633
|
+
}
|
|
634
|
+
return () => {
|
|
635
|
+
handlers.delete(handler);
|
|
636
|
+
if (handlers.size === 0) {
|
|
637
|
+
SUBSCRIBERS.delete(target);
|
|
638
|
+
if (isSandboxRuntime()) {
|
|
639
|
+
window.parent?.postMessage({ kind: "palette.broker.unsubscribe", target }, "*");
|
|
640
|
+
} else {
|
|
641
|
+
refreshStream();
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
},
|
|
646
|
+
async emit(target, payload) {
|
|
647
|
+
await broker.emit(target, payload);
|
|
648
|
+
},
|
|
649
|
+
async publishDurable(target, payload) {
|
|
650
|
+
await broker.emit(target, payload);
|
|
651
|
+
},
|
|
652
|
+
async emitDurable(target, payload) {
|
|
653
|
+
await broker.emit(target, payload);
|
|
654
|
+
},
|
|
655
|
+
/** Diagnostic: list active subscriptions in this page. */
|
|
656
|
+
active() {
|
|
657
|
+
return Array.from(SUBSCRIBERS.keys());
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
|
|
388
661
|
// src/permissions.ts
|
|
389
662
|
function hasPermission(ctx, permission) {
|
|
390
663
|
return ctx.permissions?.includes(permission) ?? false;
|
|
@@ -714,9 +987,21 @@ function createPaletteClient(ctx) {
|
|
|
714
987
|
success: (message) => ctx?.showToast(message, "success"),
|
|
715
988
|
error: (message) => ctx?.showToast(message, "error"),
|
|
716
989
|
info: (message) => ctx?.showToast(message, "info")
|
|
717
|
-
}
|
|
990
|
+
},
|
|
991
|
+
/**
|
|
992
|
+
* OS-broker RPC. Typed entry point: `palette.services("org/v1").members.list({...})`.
|
|
993
|
+
* The proxy resolves a dotted method chain into a qualified target string
|
|
994
|
+
* and dispatches via the broker (in-process for plugins on the host,
|
|
995
|
+
* postMessage for sandboxed iframe apps).
|
|
996
|
+
*/
|
|
997
|
+
services: (namespaceVersion) => servicesProxy(namespaceVersion),
|
|
998
|
+
/** Low-level broker accessor when you don't want the typed proxy. */
|
|
999
|
+
broker,
|
|
1000
|
+
/** OS-broker pub/sub. `events.on(target, fn)` returns an unsubscribe function. */
|
|
1001
|
+
events
|
|
718
1002
|
};
|
|
719
1003
|
}
|
|
1004
|
+
var palette = createPaletteClient();
|
|
720
1005
|
|
|
721
1006
|
// src/i18n.ts
|
|
722
1007
|
var import_react3 = require("react");
|
|
@@ -1179,8 +1464,11 @@ function usePluginChat(agentId) {
|
|
|
1179
1464
|
}
|
|
1180
1465
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1181
1466
|
0 && (module.exports = {
|
|
1467
|
+
BrokerCallError,
|
|
1468
|
+
CrossAppGrantError,
|
|
1182
1469
|
DataRoomClient,
|
|
1183
1470
|
Link,
|
|
1471
|
+
MissingDependencyError,
|
|
1184
1472
|
OrganizationClient,
|
|
1185
1473
|
PaletteApiError,
|
|
1186
1474
|
PaletteAppRouter,
|
|
@@ -1190,12 +1478,14 @@ function usePluginChat(agentId) {
|
|
|
1190
1478
|
UserClient,
|
|
1191
1479
|
apiFetch,
|
|
1192
1480
|
apiUpload,
|
|
1481
|
+
broker,
|
|
1193
1482
|
createMockPlatformContext,
|
|
1194
1483
|
createPaletteClient,
|
|
1195
1484
|
createSandboxBridge,
|
|
1196
1485
|
dataRooms,
|
|
1197
1486
|
disconnectConnection,
|
|
1198
1487
|
errorFromResponse,
|
|
1488
|
+
events,
|
|
1199
1489
|
getBaseUrl,
|
|
1200
1490
|
getConnections,
|
|
1201
1491
|
getInstallConfig,
|
|
@@ -1206,7 +1496,9 @@ function usePluginChat(agentId) {
|
|
|
1206
1496
|
isSandboxRuntime,
|
|
1207
1497
|
normalizePaletteLanguage,
|
|
1208
1498
|
notFound,
|
|
1499
|
+
palette,
|
|
1209
1500
|
requireConnection,
|
|
1501
|
+
servicesProxy,
|
|
1210
1502
|
setBaseUrl,
|
|
1211
1503
|
startConnection,
|
|
1212
1504
|
translate,
|
package/dist/index.mjs
CHANGED
|
@@ -317,6 +317,272 @@ var DataRoomClient = class {
|
|
|
317
317
|
};
|
|
318
318
|
var dataRooms = new DataRoomClient();
|
|
319
319
|
|
|
320
|
+
// src/services.ts
|
|
321
|
+
var BrokerCallError = class extends Error {
|
|
322
|
+
constructor(message, target, status) {
|
|
323
|
+
super(message);
|
|
324
|
+
this.target = target;
|
|
325
|
+
this.status = status;
|
|
326
|
+
this.name = "BrokerCallError";
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
var MissingDependencyError = class extends BrokerCallError {
|
|
330
|
+
constructor(message, target, status) {
|
|
331
|
+
super(message, target, status);
|
|
332
|
+
this.name = "MissingDependencyError";
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
var CrossAppGrantError = class extends BrokerCallError {
|
|
336
|
+
constructor(message, target, status) {
|
|
337
|
+
super(message, target, status);
|
|
338
|
+
this.name = "CrossAppGrantError";
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
function brokerError(message, target, status) {
|
|
342
|
+
const lower = message.toLowerCase();
|
|
343
|
+
if (status === 424 || lower.includes("not installed") || lower.includes("provider app")) {
|
|
344
|
+
return new MissingDependencyError(message, target, status);
|
|
345
|
+
}
|
|
346
|
+
if (status === 403 && (lower.includes("grant") || lower.includes("declared"))) {
|
|
347
|
+
return new CrossAppGrantError(message, target, status);
|
|
348
|
+
}
|
|
349
|
+
return new BrokerCallError(message, target, status);
|
|
350
|
+
}
|
|
351
|
+
var CALLER_HEADER = "X-Palette-Caller-App";
|
|
352
|
+
function currentPluginId() {
|
|
353
|
+
if (typeof window === "undefined") return void 0;
|
|
354
|
+
const match = window.location.pathname.match(/\/apps\/([^/?#]+)/);
|
|
355
|
+
return match ? decodeURIComponent(match[1]) : void 0;
|
|
356
|
+
}
|
|
357
|
+
async function brokerCallDirect(target, payload, options = {}) {
|
|
358
|
+
const callerAppId = options.callerAppId ?? currentPluginId();
|
|
359
|
+
const headers = {};
|
|
360
|
+
if (callerAppId) headers[CALLER_HEADER] = callerAppId;
|
|
361
|
+
let res;
|
|
362
|
+
try {
|
|
363
|
+
res = await apiFetch("/api/v1/os-broker/dispatch", {
|
|
364
|
+
method: "POST",
|
|
365
|
+
headers,
|
|
366
|
+
body: JSON.stringify({ target, payload: payload ?? {}, caller_app_id: callerAppId }),
|
|
367
|
+
signal: options.signal
|
|
368
|
+
});
|
|
369
|
+
} catch (error) {
|
|
370
|
+
const e = error;
|
|
371
|
+
throw brokerError(typeof e.detail === "string" ? e.detail : e.message, target, e.status);
|
|
372
|
+
}
|
|
373
|
+
if (!res.ok) {
|
|
374
|
+
let detail;
|
|
375
|
+
try {
|
|
376
|
+
detail = (await res.json()).detail;
|
|
377
|
+
} catch {
|
|
378
|
+
detail = res.statusText;
|
|
379
|
+
}
|
|
380
|
+
throw brokerError(detail ?? `broker dispatch failed: ${res.status}`, target, res.status);
|
|
381
|
+
}
|
|
382
|
+
const body = await res.json();
|
|
383
|
+
return body.result;
|
|
384
|
+
}
|
|
385
|
+
async function brokerCallSandboxed(target, payload, options = {}) {
|
|
386
|
+
return sandboxRequest({
|
|
387
|
+
kind: "palette.broker.call",
|
|
388
|
+
target,
|
|
389
|
+
payload: payload ?? {},
|
|
390
|
+
callerAppId: options.callerAppId
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
async function brokerEmitDirect(target, payload, options = {}) {
|
|
394
|
+
const callerAppId = options.callerAppId ?? currentPluginId();
|
|
395
|
+
if (!callerAppId) {
|
|
396
|
+
throw new BrokerCallError(
|
|
397
|
+
"events.emit requires a caller app id \u2014 only plugins may emit declared events",
|
|
398
|
+
target
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
const res = await apiFetch("/api/v1/os-broker/events/emit", {
|
|
402
|
+
method: "POST",
|
|
403
|
+
headers: { [CALLER_HEADER]: callerAppId },
|
|
404
|
+
body: JSON.stringify({ target, payload: payload ?? {}, caller_app_id: callerAppId }),
|
|
405
|
+
signal: options.signal
|
|
406
|
+
});
|
|
407
|
+
if (!res.ok) {
|
|
408
|
+
let detail;
|
|
409
|
+
try {
|
|
410
|
+
detail = (await res.json()).detail;
|
|
411
|
+
} catch {
|
|
412
|
+
detail = res.statusText;
|
|
413
|
+
}
|
|
414
|
+
throw new BrokerCallError(detail ?? `event emit failed: ${res.status}`, target, res.status);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
async function brokerEmitSandboxed(target, payload, options = {}) {
|
|
418
|
+
await sandboxRequest({
|
|
419
|
+
kind: "palette.broker.emit",
|
|
420
|
+
target,
|
|
421
|
+
payload: payload ?? {},
|
|
422
|
+
callerAppId: options.callerAppId
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
function sandboxRequest(message) {
|
|
426
|
+
if (typeof window === "undefined") {
|
|
427
|
+
return Promise.reject(new BrokerCallError("sandbox bridge unavailable", message.target));
|
|
428
|
+
}
|
|
429
|
+
return new Promise((resolve, reject) => {
|
|
430
|
+
const id = `${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
431
|
+
const onMessage = (ev) => {
|
|
432
|
+
const data = ev.data;
|
|
433
|
+
if (!data || data.id !== id) return;
|
|
434
|
+
window.removeEventListener("message", onMessage);
|
|
435
|
+
if (data.error) {
|
|
436
|
+
reject(new BrokerCallError(data.error.message, message.target, data.error.status));
|
|
437
|
+
} else {
|
|
438
|
+
resolve(data.result);
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
window.addEventListener("message", onMessage);
|
|
442
|
+
window.parent?.postMessage({ ...message, id }, "*");
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
var broker = {
|
|
446
|
+
async call(target, payload, options) {
|
|
447
|
+
return isSandboxRuntime() ? brokerCallSandboxed(target, payload, options) : brokerCallDirect(target, payload, options);
|
|
448
|
+
},
|
|
449
|
+
async emit(target, payload, options) {
|
|
450
|
+
if (isSandboxRuntime()) return brokerEmitSandboxed(target, payload, options);
|
|
451
|
+
return brokerEmitDirect(target, payload, options);
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
function servicesProxy(namespaceVersion) {
|
|
455
|
+
if (!namespaceVersion.includes("/")) {
|
|
456
|
+
throw new BrokerCallError("namespaceVersion must look like 'org/v1'", namespaceVersion);
|
|
457
|
+
}
|
|
458
|
+
const buildProxy = (segments) => new Proxy(function() {
|
|
459
|
+
}, {
|
|
460
|
+
get(_target, prop) {
|
|
461
|
+
if (typeof prop !== "string") return void 0;
|
|
462
|
+
return buildProxy([...segments, prop]);
|
|
463
|
+
},
|
|
464
|
+
apply(_target, _thisArg, args) {
|
|
465
|
+
const method = segments.join(".");
|
|
466
|
+
if (!method) {
|
|
467
|
+
throw new BrokerCallError("missing method name", namespaceVersion);
|
|
468
|
+
}
|
|
469
|
+
const [payload, options] = args;
|
|
470
|
+
return broker.call(`${namespaceVersion}#${method}`, payload, options);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
return buildProxy([]);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// src/events.ts
|
|
477
|
+
var SUBSCRIBERS = /* @__PURE__ */ new Map();
|
|
478
|
+
var activeStream = null;
|
|
479
|
+
var activeStreamUrl = null;
|
|
480
|
+
var sandboxBound = false;
|
|
481
|
+
function currentPluginId2() {
|
|
482
|
+
if (typeof window === "undefined") return void 0;
|
|
483
|
+
const match = window.location.pathname.match(/\/apps\/([^/?#]+)/);
|
|
484
|
+
return match ? decodeURIComponent(match[1]) : void 0;
|
|
485
|
+
}
|
|
486
|
+
function streamUrl() {
|
|
487
|
+
const params = new URLSearchParams();
|
|
488
|
+
const targets = Array.from(SUBSCRIBERS.keys());
|
|
489
|
+
if (targets.length) params.set("targets", targets.join(","));
|
|
490
|
+
const callerAppId = currentPluginId2();
|
|
491
|
+
if (callerAppId) params.set("caller_app_id", callerAppId);
|
|
492
|
+
const query = params.toString();
|
|
493
|
+
return `${getBaseUrl()}/api/v1/os-broker/events/stream${query ? `?${query}` : ""}`;
|
|
494
|
+
}
|
|
495
|
+
function ensureStream() {
|
|
496
|
+
if (activeStream || typeof window === "undefined") return;
|
|
497
|
+
activeStreamUrl = streamUrl();
|
|
498
|
+
activeStream = new EventSource(activeStreamUrl, { withCredentials: true });
|
|
499
|
+
activeStream.onmessage = (ev) => {
|
|
500
|
+
try {
|
|
501
|
+
const data = JSON.parse(ev.data);
|
|
502
|
+
const handlers = SUBSCRIBERS.get(data.target);
|
|
503
|
+
if (!handlers) return;
|
|
504
|
+
for (const handler of handlers) {
|
|
505
|
+
try {
|
|
506
|
+
handler(data.payload, data.meta);
|
|
507
|
+
} catch (err) {
|
|
508
|
+
console.error("palette.events handler threw", err);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
} catch (err) {
|
|
512
|
+
console.warn("palette.events: malformed event", err);
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
activeStream.onerror = () => {
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
function refreshStream() {
|
|
519
|
+
if (typeof window === "undefined" || isSandboxRuntime()) return;
|
|
520
|
+
const nextUrl = streamUrl();
|
|
521
|
+
if (activeStream && activeStreamUrl === nextUrl) return;
|
|
522
|
+
activeStream?.close();
|
|
523
|
+
activeStream = null;
|
|
524
|
+
activeStreamUrl = null;
|
|
525
|
+
if (SUBSCRIBERS.size > 0) ensureStream();
|
|
526
|
+
}
|
|
527
|
+
function ensureSandboxBound() {
|
|
528
|
+
if (sandboxBound || typeof window === "undefined") return;
|
|
529
|
+
sandboxBound = true;
|
|
530
|
+
window.addEventListener("message", (ev) => {
|
|
531
|
+
const data = ev.data;
|
|
532
|
+
if (!data || data.kind !== "palette.broker.event" || !data.target) return;
|
|
533
|
+
const handlers = SUBSCRIBERS.get(data.target);
|
|
534
|
+
if (!handlers) return;
|
|
535
|
+
const meta = data.meta ?? { target: data.target, organizationId: null, occurredAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
536
|
+
for (const handler of handlers) {
|
|
537
|
+
try {
|
|
538
|
+
handler(data.payload, meta);
|
|
539
|
+
} catch (err) {
|
|
540
|
+
console.error("palette.events handler threw", err);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
var events = {
|
|
546
|
+
on(target, handler) {
|
|
547
|
+
let handlers = SUBSCRIBERS.get(target);
|
|
548
|
+
if (!handlers) {
|
|
549
|
+
handlers = /* @__PURE__ */ new Set();
|
|
550
|
+
SUBSCRIBERS.set(target, handlers);
|
|
551
|
+
}
|
|
552
|
+
handlers.add(handler);
|
|
553
|
+
if (isSandboxRuntime()) {
|
|
554
|
+
ensureSandboxBound();
|
|
555
|
+
window.parent?.postMessage({ kind: "palette.broker.subscribe", target }, "*");
|
|
556
|
+
} else {
|
|
557
|
+
refreshStream();
|
|
558
|
+
}
|
|
559
|
+
return () => {
|
|
560
|
+
handlers.delete(handler);
|
|
561
|
+
if (handlers.size === 0) {
|
|
562
|
+
SUBSCRIBERS.delete(target);
|
|
563
|
+
if (isSandboxRuntime()) {
|
|
564
|
+
window.parent?.postMessage({ kind: "palette.broker.unsubscribe", target }, "*");
|
|
565
|
+
} else {
|
|
566
|
+
refreshStream();
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
},
|
|
571
|
+
async emit(target, payload) {
|
|
572
|
+
await broker.emit(target, payload);
|
|
573
|
+
},
|
|
574
|
+
async publishDurable(target, payload) {
|
|
575
|
+
await broker.emit(target, payload);
|
|
576
|
+
},
|
|
577
|
+
async emitDurable(target, payload) {
|
|
578
|
+
await broker.emit(target, payload);
|
|
579
|
+
},
|
|
580
|
+
/** Diagnostic: list active subscriptions in this page. */
|
|
581
|
+
active() {
|
|
582
|
+
return Array.from(SUBSCRIBERS.keys());
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
|
|
320
586
|
// src/permissions.ts
|
|
321
587
|
function hasPermission(ctx, permission) {
|
|
322
588
|
return ctx.permissions?.includes(permission) ?? false;
|
|
@@ -646,9 +912,21 @@ function createPaletteClient(ctx) {
|
|
|
646
912
|
success: (message) => ctx?.showToast(message, "success"),
|
|
647
913
|
error: (message) => ctx?.showToast(message, "error"),
|
|
648
914
|
info: (message) => ctx?.showToast(message, "info")
|
|
649
|
-
}
|
|
915
|
+
},
|
|
916
|
+
/**
|
|
917
|
+
* OS-broker RPC. Typed entry point: `palette.services("org/v1").members.list({...})`.
|
|
918
|
+
* The proxy resolves a dotted method chain into a qualified target string
|
|
919
|
+
* and dispatches via the broker (in-process for plugins on the host,
|
|
920
|
+
* postMessage for sandboxed iframe apps).
|
|
921
|
+
*/
|
|
922
|
+
services: (namespaceVersion) => servicesProxy(namespaceVersion),
|
|
923
|
+
/** Low-level broker accessor when you don't want the typed proxy. */
|
|
924
|
+
broker,
|
|
925
|
+
/** OS-broker pub/sub. `events.on(target, fn)` returns an unsubscribe function. */
|
|
926
|
+
events
|
|
650
927
|
};
|
|
651
928
|
}
|
|
929
|
+
var palette = createPaletteClient();
|
|
652
930
|
|
|
653
931
|
// src/i18n.ts
|
|
654
932
|
import { useCallback } from "react";
|
|
@@ -1119,8 +1397,11 @@ function usePluginChat(agentId) {
|
|
|
1119
1397
|
};
|
|
1120
1398
|
}
|
|
1121
1399
|
export {
|
|
1400
|
+
BrokerCallError,
|
|
1401
|
+
CrossAppGrantError,
|
|
1122
1402
|
DataRoomClient,
|
|
1123
1403
|
Link,
|
|
1404
|
+
MissingDependencyError,
|
|
1124
1405
|
OrganizationClient,
|
|
1125
1406
|
PaletteApiError,
|
|
1126
1407
|
PaletteAppRouter,
|
|
@@ -1130,12 +1411,14 @@ export {
|
|
|
1130
1411
|
UserClient,
|
|
1131
1412
|
apiFetch,
|
|
1132
1413
|
apiUpload,
|
|
1414
|
+
broker,
|
|
1133
1415
|
createMockPlatformContext,
|
|
1134
1416
|
createPaletteClient,
|
|
1135
1417
|
createSandboxBridge,
|
|
1136
1418
|
dataRooms,
|
|
1137
1419
|
disconnectConnection,
|
|
1138
1420
|
errorFromResponse,
|
|
1421
|
+
events,
|
|
1139
1422
|
getBaseUrl,
|
|
1140
1423
|
getConnections,
|
|
1141
1424
|
getInstallConfig,
|
|
@@ -1146,7 +1429,9 @@ export {
|
|
|
1146
1429
|
isSandboxRuntime,
|
|
1147
1430
|
normalizePaletteLanguage,
|
|
1148
1431
|
notFound,
|
|
1432
|
+
palette,
|
|
1149
1433
|
requireConnection,
|
|
1434
|
+
servicesProxy,
|
|
1150
1435
|
setBaseUrl,
|
|
1151
1436
|
startConnection,
|
|
1152
1437
|
translate,
|