@camstack/core 0.1.37 → 0.1.39
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/dist/auth/auth-manager.d.ts +12 -1
- package/dist/auth/auth-manager.d.ts.map +1 -1
- package/dist/auth/scope-matcher.d.ts +8 -0
- package/dist/auth/scope-matcher.d.ts.map +1 -0
- package/dist/auth/totp-manager.d.ts +0 -1
- package/dist/auth/totp-manager.d.ts.map +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +15 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts.map +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +27 -6
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js.map +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +27 -6
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs.map +1 -1
- package/dist/builtins/device-manager/device-config-contribution.d.ts +33 -0
- package/dist/builtins/device-manager/device-config-contribution.d.ts.map +1 -0
- package/dist/builtins/device-manager/device-manager.addon.d.ts +52 -17
- package/dist/builtins/device-manager/device-manager.addon.d.ts.map +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +285 -161
- package/dist/builtins/device-manager/device-manager.addon.js.map +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +286 -162
- package/dist/builtins/device-manager/device-manager.addon.mjs.map +1 -1
- package/dist/builtins/local-auth/auth-schema.d.ts +1 -0
- package/dist/builtins/local-auth/auth-schema.d.ts.map +1 -1
- package/dist/builtins/local-auth/local-auth.addon.d.ts +1 -0
- package/dist/builtins/local-auth/local-auth.addon.d.ts.map +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +354 -3
- package/dist/builtins/local-auth/local-auth.addon.js.map +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +355 -3
- package/dist/builtins/local-auth/local-auth.addon.mjs.map +1 -1
- package/dist/builtins/local-auth/oauth-grants.d.ts +46 -0
- package/dist/builtins/local-auth/oauth-grants.d.ts.map +1 -0
- package/dist/builtins/local-auth/oauth-session-manager.d.ts +51 -0
- package/dist/builtins/local-auth/oauth-session-manager.d.ts.map +1 -0
- package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts +97 -0
- package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts.map +1 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +24 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts.map +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +136 -56
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js.map +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +137 -57
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs.map +1 -1
- package/dist/builtins/snapshot/index.js +1 -3
- package/dist/builtins/snapshot/index.js.map +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -3
- package/dist/builtins/snapshot/index.mjs.map +1 -1
- package/dist/builtins/snapshot/snapshot.addon.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +428 -234
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +428 -235
- package/dist/index.mjs.map +1 -1
- package/package.json +19 -37
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.d.ts +0 -8
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.d.ts.map +0 -1
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.js +0 -75
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.js.map +0 -1
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.mjs +0 -69
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.mjs.map +0 -1
- package/dist/builtins/auth-orchestrator/index.d.ts +0 -2
- package/dist/builtins/auth-orchestrator/index.d.ts.map +0 -1
- package/dist/builtins/auth-orchestrator/index.js +0 -7
- package/dist/builtins/auth-orchestrator/index.mjs +0 -2
- package/dist/builtins/mesh-orchestrator/index.d.ts +0 -2
- package/dist/builtins/mesh-orchestrator/index.d.ts.map +0 -1
- package/dist/builtins/mesh-orchestrator/index.js +0 -7
- package/dist/builtins/mesh-orchestrator/index.mjs +0 -2
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.d.ts +0 -9
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.d.ts.map +0 -1
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.js +0 -113
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.js.map +0 -1
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.mjs +0 -107
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.mjs.map +0 -1
- package/dist/builtins/turn-orchestrator/index.d.ts +0 -2
- package/dist/builtins/turn-orchestrator/index.d.ts.map +0 -1
- package/dist/builtins/turn-orchestrator/index.js +0 -7
- package/dist/builtins/turn-orchestrator/index.mjs +0 -2
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.d.ts +0 -34
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.d.ts.map +0 -1
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.js +0 -126
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.js.map +0 -1
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.mjs +0 -120
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.mjs.map +0 -1
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { BaseAddon, meshOrchestratorCapability } from "@camstack/types";
|
|
2
|
-
//#region src/builtins/mesh-orchestrator/mesh-orchestrator.addon.ts
|
|
3
|
-
/**
|
|
4
|
-
* Mesh orchestrator — singleton facade over the `mesh-network`
|
|
5
|
-
* collection. One row per provider (Tailscale, Headscale, ZeroTier),
|
|
6
|
-
* aggregated for the admin UI's Mesh Networks page.
|
|
7
|
-
*/
|
|
8
|
-
var MeshOrchestratorAddon = class extends BaseAddon {
|
|
9
|
-
constructor() {
|
|
10
|
-
super({});
|
|
11
|
-
}
|
|
12
|
-
async onInitialize() {
|
|
13
|
-
const provider = {
|
|
14
|
-
listProviders: async () => this.listProviders(),
|
|
15
|
-
joinProvider: async ({ addonId, authKey, hostname }) => {
|
|
16
|
-
const impl = this.resolveImpl(addonId);
|
|
17
|
-
if (!impl?.join) throw new Error(`Mesh provider "${addonId}" does not support join`);
|
|
18
|
-
return await impl.join({
|
|
19
|
-
authKey,
|
|
20
|
-
...hostname ? { hostname } : {}
|
|
21
|
-
});
|
|
22
|
-
},
|
|
23
|
-
leaveProvider: async ({ addonId }) => {
|
|
24
|
-
const impl = this.resolveImpl(addonId);
|
|
25
|
-
if (impl?.leave) await impl.leave();
|
|
26
|
-
return { success: true };
|
|
27
|
-
},
|
|
28
|
-
startLoginProvider: async ({ addonId, hostname }) => {
|
|
29
|
-
const impl = this.resolveImpl(addonId);
|
|
30
|
-
if (!impl?.startLogin) throw new Error(`Mesh provider "${addonId}" does not support startLogin`);
|
|
31
|
-
return await impl.startLogin(hostname ? { hostname } : {});
|
|
32
|
-
},
|
|
33
|
-
logoutProvider: async ({ addonId }) => {
|
|
34
|
-
const impl = this.resolveImpl(addonId);
|
|
35
|
-
if (!impl?.logout) throw new Error(`Mesh provider "${addonId}" does not support logout`);
|
|
36
|
-
await impl.logout();
|
|
37
|
-
return { loggedOut: true };
|
|
38
|
-
},
|
|
39
|
-
listProviderPeers: async ({ addonId }) => {
|
|
40
|
-
const impl = this.resolveImpl(addonId);
|
|
41
|
-
if (!impl?.listPeers) return { peers: [] };
|
|
42
|
-
return await impl.listPeers();
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
this.ctx.logger.info("Mesh orchestrator initialized");
|
|
46
|
-
return [{
|
|
47
|
-
capability: meshOrchestratorCapability,
|
|
48
|
-
provider
|
|
49
|
-
}];
|
|
50
|
-
}
|
|
51
|
-
resolveImpl(addonId) {
|
|
52
|
-
return (this.capabilities?.getCollectionEntries("mesh-network") ?? []).find(([id]) => id === addonId)?.[1] ?? null;
|
|
53
|
-
}
|
|
54
|
-
async listProviders() {
|
|
55
|
-
const entries = this.capabilities?.getCollectionEntries("mesh-network") ?? [];
|
|
56
|
-
const out = [];
|
|
57
|
-
for (const [addonId, impl] of entries) {
|
|
58
|
-
let joined = false;
|
|
59
|
-
let meshIp = "";
|
|
60
|
-
let magicDnsHostname = "";
|
|
61
|
-
let peerCount = 0;
|
|
62
|
-
let endpoints = [];
|
|
63
|
-
let error;
|
|
64
|
-
let tenantName = "";
|
|
65
|
-
let magicDnsSuffix = "";
|
|
66
|
-
let userLogin = null;
|
|
67
|
-
let controlPlaneUrl = "";
|
|
68
|
-
let keyExpiry = null;
|
|
69
|
-
if (impl.getStatus) try {
|
|
70
|
-
const s = await impl.getStatus();
|
|
71
|
-
joined = s.joined;
|
|
72
|
-
meshIp = s.meshIp;
|
|
73
|
-
magicDnsHostname = s.magicDnsHostname;
|
|
74
|
-
peerCount = s.peerCount;
|
|
75
|
-
endpoints = s.endpoints;
|
|
76
|
-
error = s.error;
|
|
77
|
-
tenantName = s.tenantName;
|
|
78
|
-
magicDnsSuffix = s.magicDnsSuffix;
|
|
79
|
-
userLogin = s.userLogin;
|
|
80
|
-
controlPlaneUrl = s.controlPlaneUrl;
|
|
81
|
-
keyExpiry = s.keyExpiry;
|
|
82
|
-
} catch (err) {
|
|
83
|
-
error = err instanceof Error ? err.message : String(err);
|
|
84
|
-
}
|
|
85
|
-
out.push({
|
|
86
|
-
addonId,
|
|
87
|
-
displayName: impl.displayName ?? addonId,
|
|
88
|
-
joined,
|
|
89
|
-
meshIp,
|
|
90
|
-
magicDnsHostname,
|
|
91
|
-
peerCount,
|
|
92
|
-
endpoints,
|
|
93
|
-
...error !== void 0 ? { error } : {},
|
|
94
|
-
tenantName,
|
|
95
|
-
magicDnsSuffix,
|
|
96
|
-
userLogin,
|
|
97
|
-
controlPlaneUrl,
|
|
98
|
-
keyExpiry
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
return out;
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
//#endregion
|
|
105
|
-
export { MeshOrchestratorAddon, MeshOrchestratorAddon as default };
|
|
106
|
-
|
|
107
|
-
//# sourceMappingURL=mesh-orchestrator.addon.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mesh-orchestrator.addon.mjs","names":[],"sources":["../../../src/builtins/mesh-orchestrator/mesh-orchestrator.addon.ts"],"sourcesContent":["/**\n * Mesh orchestrator — singleton facade over the `mesh-network`\n * collection. One row per provider (Tailscale, Headscale, ZeroTier),\n * aggregated for the admin UI's Mesh Networks page.\n */\nimport {\n BaseAddon,\n meshOrchestratorCapability,\n type IMeshOrchestrator,\n type MeshPeer,\n type MeshProviderInfo,\n type ProviderRegistration,\n} from '@camstack/types'\n\ninterface MeshStatusLike {\n joined: boolean\n meshIp: string\n magicDnsHostname: string\n peerCount: number\n endpoints: readonly {\n id: string\n label: string\n scope: 'mesh' | 'public'\n url: string\n hostname: string\n port: number\n protocol: 'http' | 'https'\n }[]\n error?: string\n tenantName: string\n magicDnsSuffix: string\n userLogin: string | null\n controlPlaneUrl: string\n keyExpiry: number | null\n}\n\ninterface MeshNetworkLike {\n getStatus?: () => Promise<MeshStatusLike>\n join?: (input: { authKey: string; hostname?: string }) => Promise<{ joined: true }>\n startLogin?: (input: { hostname?: string }) => Promise<{ loginUrl: string }>\n leave?: () => Promise<{ left: true }>\n logout?: () => Promise<{ loggedOut: true }>\n listPeers?: () => Promise<{ peers: readonly MeshPeer[] }>\n}\n\ninterface MeshRegistrationMeta {\n readonly displayName?: string\n}\n\nexport class MeshOrchestratorAddon extends BaseAddon<Record<string, never>> {\n constructor() {\n super({})\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const provider: IMeshOrchestrator = {\n listProviders: async () => this.listProviders(),\n joinProvider: async ({ addonId, authKey, hostname }) => {\n const impl = this.resolveImpl(addonId)\n if (!impl?.join) throw new Error(`Mesh provider \"${addonId}\" does not support join`)\n return await impl.join({ authKey, ...(hostname ? { hostname } : {}) })\n },\n leaveProvider: async ({ addonId }) => {\n const impl = this.resolveImpl(addonId)\n if (impl?.leave) await impl.leave()\n return { success: true as const }\n },\n startLoginProvider: async ({ addonId, hostname }) => {\n const impl = this.resolveImpl(addonId)\n if (!impl?.startLogin) {\n throw new Error(`Mesh provider \"${addonId}\" does not support startLogin`)\n }\n return await impl.startLogin(hostname ? { hostname } : {})\n },\n logoutProvider: async ({ addonId }) => {\n const impl = this.resolveImpl(addonId)\n if (!impl?.logout) {\n throw new Error(`Mesh provider \"${addonId}\" does not support logout`)\n }\n await impl.logout()\n return { loggedOut: true as const }\n },\n listProviderPeers: async ({ addonId }) => {\n const impl = this.resolveImpl(addonId)\n if (!impl?.listPeers) return { peers: [] }\n return await impl.listPeers()\n },\n }\n this.ctx.logger.info('Mesh orchestrator initialized')\n return [{ capability: meshOrchestratorCapability, provider }]\n }\n\n private resolveImpl(addonId: string): MeshNetworkLike | null {\n const entries = this.capabilities?.getCollectionEntries<MeshNetworkLike>('mesh-network') ?? []\n const found = entries.find(([id]) => id === addonId)\n return found?.[1] ?? null\n }\n\n private async listProviders(): Promise<readonly MeshProviderInfo[]> {\n const entries = this.capabilities?.getCollectionEntries<MeshNetworkLike & MeshRegistrationMeta>(\n 'mesh-network',\n ) ?? []\n const out: MeshProviderInfo[] = []\n for (const [addonId, impl] of entries) {\n let joined = false\n let meshIp = ''\n let magicDnsHostname = ''\n let peerCount = 0\n let endpoints: MeshProviderInfo['endpoints'] = []\n let error: string | undefined\n let tenantName = ''\n let magicDnsSuffix = ''\n let userLogin: string | null = null\n let controlPlaneUrl = ''\n let keyExpiry: number | null = null\n if (impl.getStatus) {\n try {\n const s = await impl.getStatus()\n joined = s.joined\n meshIp = s.meshIp\n magicDnsHostname = s.magicDnsHostname\n peerCount = s.peerCount\n endpoints = s.endpoints\n error = s.error\n tenantName = s.tenantName\n magicDnsSuffix = s.magicDnsSuffix\n userLogin = s.userLogin\n controlPlaneUrl = s.controlPlaneUrl\n keyExpiry = s.keyExpiry\n } catch (err) {\n error = err instanceof Error ? err.message : String(err)\n }\n }\n out.push({\n addonId,\n displayName: impl.displayName ?? addonId,\n joined,\n meshIp,\n magicDnsHostname,\n peerCount,\n endpoints,\n ...(error !== undefined ? { error } : {}),\n tenantName,\n magicDnsSuffix,\n userLogin,\n controlPlaneUrl,\n keyExpiry,\n })\n }\n return out\n }\n}\n\nexport default MeshOrchestratorAddon\n"],"mappings":";;;;;;;AAiDA,IAAa,wBAAb,cAA2C,UAAiC;CAC1E,cAAc;EACZ,MAAM,EAAE,CAAC;;CAGX,MAAgB,eAAgD;EAC9D,MAAM,WAA8B;GAClC,eAAe,YAAY,KAAK,eAAe;GAC/C,cAAc,OAAO,EAAE,SAAS,SAAS,eAAe;IACtD,MAAM,OAAO,KAAK,YAAY,QAAQ;IACtC,IAAI,CAAC,MAAM,MAAM,MAAM,IAAI,MAAM,kBAAkB,QAAQ,yBAAyB;IACpF,OAAO,MAAM,KAAK,KAAK;KAAE;KAAS,GAAI,WAAW,EAAE,UAAU,GAAG,EAAE;KAAG,CAAC;;GAExE,eAAe,OAAO,EAAE,cAAc;IACpC,MAAM,OAAO,KAAK,YAAY,QAAQ;IACtC,IAAI,MAAM,OAAO,MAAM,KAAK,OAAO;IACnC,OAAO,EAAE,SAAS,MAAe;;GAEnC,oBAAoB,OAAO,EAAE,SAAS,eAAe;IACnD,MAAM,OAAO,KAAK,YAAY,QAAQ;IACtC,IAAI,CAAC,MAAM,YACT,MAAM,IAAI,MAAM,kBAAkB,QAAQ,+BAA+B;IAE3E,OAAO,MAAM,KAAK,WAAW,WAAW,EAAE,UAAU,GAAG,EAAE,CAAC;;GAE5D,gBAAgB,OAAO,EAAE,cAAc;IACrC,MAAM,OAAO,KAAK,YAAY,QAAQ;IACtC,IAAI,CAAC,MAAM,QACT,MAAM,IAAI,MAAM,kBAAkB,QAAQ,2BAA2B;IAEvE,MAAM,KAAK,QAAQ;IACnB,OAAO,EAAE,WAAW,MAAe;;GAErC,mBAAmB,OAAO,EAAE,cAAc;IACxC,MAAM,OAAO,KAAK,YAAY,QAAQ;IACtC,IAAI,CAAC,MAAM,WAAW,OAAO,EAAE,OAAO,EAAE,EAAE;IAC1C,OAAO,MAAM,KAAK,WAAW;;GAEhC;EACD,KAAK,IAAI,OAAO,KAAK,gCAAgC;EACrD,OAAO,CAAC;GAAE,YAAY;GAA4B;GAAU,CAAC;;CAG/D,YAAoB,SAAyC;EAG3D,QAFgB,KAAK,cAAc,qBAAsC,eAAe,IAAI,EAAE,EACxE,MAAM,CAAC,QAAQ,OAAO,QACrC,GAAQ,MAAM;;CAGvB,MAAc,gBAAsD;EAClE,MAAM,UAAU,KAAK,cAAc,qBACjC,eACD,IAAI,EAAE;EACP,MAAM,MAA0B,EAAE;EAClC,KAAK,MAAM,CAAC,SAAS,SAAS,SAAS;GACrC,IAAI,SAAS;GACb,IAAI,SAAS;GACb,IAAI,mBAAmB;GACvB,IAAI,YAAY;GAChB,IAAI,YAA2C,EAAE;GACjD,IAAI;GACJ,IAAI,aAAa;GACjB,IAAI,iBAAiB;GACrB,IAAI,YAA2B;GAC/B,IAAI,kBAAkB;GACtB,IAAI,YAA2B;GAC/B,IAAI,KAAK,WACP,IAAI;IACF,MAAM,IAAI,MAAM,KAAK,WAAW;IAChC,SAAS,EAAE;IACX,SAAS,EAAE;IACX,mBAAmB,EAAE;IACrB,YAAY,EAAE;IACd,YAAY,EAAE;IACd,QAAQ,EAAE;IACV,aAAa,EAAE;IACf,iBAAiB,EAAE;IACnB,YAAY,EAAE;IACd,kBAAkB,EAAE;IACpB,YAAY,EAAE;YACP,KAAK;IACZ,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;;GAG5D,IAAI,KAAK;IACP;IACA,aAAa,KAAK,eAAe;IACjC;IACA;IACA;IACA;IACA;IACA,GAAI,UAAU,KAAA,IAAY,EAAE,OAAO,GAAG,EAAE;IACxC;IACA;IACA;IACA;IACA;IACD,CAAC;;EAEJ,OAAO"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/builtins/turn-orchestrator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
Object.defineProperties(exports, {
|
|
2
|
-
__esModule: { value: true },
|
|
3
|
-
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
-
});
|
|
5
|
-
const require_builtins_turn_orchestrator_turn_orchestrator_addon = require("./turn-orchestrator.addon.js");
|
|
6
|
-
exports.TurnOrchestratorAddon = require_builtins_turn_orchestrator_turn_orchestrator_addon.TurnOrchestratorAddon;
|
|
7
|
-
exports.default = require_builtins_turn_orchestrator_turn_orchestrator_addon.TurnOrchestratorAddon;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { BaseAddon, ProviderRegistration } from '@camstack/types';
|
|
2
|
-
interface TurnOrchestratorConfig {
|
|
3
|
-
/**
|
|
4
|
-
* addonIds the operator has explicitly enabled. Persisted in the
|
|
5
|
-
* addon-store; first-launch defaults to "every provider enabled" so
|
|
6
|
-
* a freshly-installed TURN addon participates immediately (the
|
|
7
|
-
* operator can disable from the UI). See `effectivelyEnabled`.
|
|
8
|
-
*/
|
|
9
|
-
readonly enabledProviders: readonly string[];
|
|
10
|
-
/**
|
|
11
|
-
* Sentinel: true after `enabledProviders` has been written at least
|
|
12
|
-
* once. Distinguishes "operator hasn't touched the toggles yet —
|
|
13
|
-
* default-enable all" from "operator cleared the list — keep it
|
|
14
|
-
* empty". Same shape as local-network's bootSeeded.
|
|
15
|
-
*/
|
|
16
|
-
readonly enabledProvidersSeeded: boolean;
|
|
17
|
-
}
|
|
18
|
-
export declare class TurnOrchestratorAddon extends BaseAddon<TurnOrchestratorConfig> {
|
|
19
|
-
constructor();
|
|
20
|
-
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
21
|
-
private getEntries;
|
|
22
|
-
/**
|
|
23
|
-
* Operator-effective enabled set. Before the first toggle, default
|
|
24
|
-
* to "every registered provider is enabled" so a fresh install of a
|
|
25
|
-
* TURN addon participates without manual intervention. After the
|
|
26
|
-
* operator clicks anything, the persisted list is authoritative.
|
|
27
|
-
*/
|
|
28
|
-
private effectivelyEnabled;
|
|
29
|
-
private markEnabled;
|
|
30
|
-
private listProviders;
|
|
31
|
-
private getAllServers;
|
|
32
|
-
}
|
|
33
|
-
export default TurnOrchestratorAddon;
|
|
34
|
-
//# sourceMappingURL=turn-orchestrator.addon.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"turn-orchestrator.addon.d.ts","sourceRoot":"","sources":["../../../src/builtins/turn-orchestrator/turn-orchestrator.addon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EACL,SAAS,EAIT,KAAK,oBAAoB,EAC1B,MAAM,iBAAiB,CAAA;AAOxB,UAAU,sBAAsB;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5C;;;;;OAKG;IACH,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAA;CACzC;AAED,qBAAa,qBAAsB,SAAQ,SAAS,CAAC,sBAAsB,CAAC;;cAK1D,YAAY,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAkB/D,OAAO,CAAC,UAAU;IAIlB;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;YAOZ,WAAW;YAYX,aAAa;YAyCb,aAAa;CAiB5B;AAED,eAAe,qBAAqB,CAAA"}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
Object.defineProperties(exports, {
|
|
2
|
-
__esModule: { value: true },
|
|
3
|
-
[Symbol.toStringTag]: { value: "Module" }
|
|
4
|
-
});
|
|
5
|
-
require("../../chunk-C13QxCFV.js");
|
|
6
|
-
let _camstack_types = require("@camstack/types");
|
|
7
|
-
//#region src/builtins/turn-orchestrator/turn-orchestrator.addon.ts
|
|
8
|
-
/**
|
|
9
|
-
* TURN orchestrator — singleton facade over the `turn-provider`
|
|
10
|
-
* collection (Cloudflare TURN, coturn, Twilio, …). Mirrors the
|
|
11
|
-
* remote-access-orchestrator persistence + autostart contract:
|
|
12
|
-
* - `enabledProviders: string[]` in addon-store is the operator's
|
|
13
|
-
* intent. Boot reads it back; the Enable/Disable toggle in the
|
|
14
|
-
* admin UI writes it.
|
|
15
|
-
* - `getAllServers()` (consumed by the WebRTC layer) aggregates ICE
|
|
16
|
-
* servers ONLY from enabled providers.
|
|
17
|
-
* - `listProviders()` surfaces the persisted `enabled` flag so the
|
|
18
|
-
* UI can render the correct toggle state on first paint.
|
|
19
|
-
*
|
|
20
|
-
* Provides:
|
|
21
|
-
* - listProviders() — admin UI inventory
|
|
22
|
-
* - getAllServers() — combined ICE server list across enabled providers
|
|
23
|
-
* - setProviderEnabled() — toggle a provider on/off (persisted)
|
|
24
|
-
*/
|
|
25
|
-
var TurnOrchestratorAddon = class extends _camstack_types.BaseAddon {
|
|
26
|
-
constructor() {
|
|
27
|
-
super({
|
|
28
|
-
enabledProviders: [],
|
|
29
|
-
enabledProvidersSeeded: false
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
async onInitialize() {
|
|
33
|
-
const provider = {
|
|
34
|
-
listProviders: async () => this.listProviders(),
|
|
35
|
-
getAllServers: async () => this.getAllServers(),
|
|
36
|
-
setProviderEnabled: async ({ addonId, enabled }) => {
|
|
37
|
-
await this.markEnabled(addonId, enabled);
|
|
38
|
-
return { success: true };
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
this.ctx.logger.info("TURN orchestrator initialized", { meta: {
|
|
42
|
-
enabledCount: this.config.enabledProviders.length,
|
|
43
|
-
seeded: this.config.enabledProvidersSeeded
|
|
44
|
-
} });
|
|
45
|
-
return [{
|
|
46
|
-
capability: _camstack_types.turnOrchestratorCapability,
|
|
47
|
-
provider
|
|
48
|
-
}];
|
|
49
|
-
}
|
|
50
|
-
getEntries() {
|
|
51
|
-
return this.capabilities?.getCollectionEntries("turn-provider") ?? [];
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Operator-effective enabled set. Before the first toggle, default
|
|
55
|
-
* to "every registered provider is enabled" so a fresh install of a
|
|
56
|
-
* TURN addon participates without manual intervention. After the
|
|
57
|
-
* operator clicks anything, the persisted list is authoritative.
|
|
58
|
-
*/
|
|
59
|
-
effectivelyEnabled() {
|
|
60
|
-
if (this.config.enabledProvidersSeeded) return new Set(this.config.enabledProviders);
|
|
61
|
-
return new Set(this.getEntries().map(([id]) => id));
|
|
62
|
-
}
|
|
63
|
-
async markEnabled(addonId, enabled) {
|
|
64
|
-
const current = this.effectivelyEnabled();
|
|
65
|
-
const wasEnabled = current.has(addonId);
|
|
66
|
-
if (enabled) current.add(addonId);
|
|
67
|
-
else current.delete(addonId);
|
|
68
|
-
if (wasEnabled === enabled && this.config.enabledProvidersSeeded) return;
|
|
69
|
-
await this.updateGlobalSettings({
|
|
70
|
-
enabledProviders: [...current],
|
|
71
|
-
enabledProvidersSeeded: true
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
async listProviders() {
|
|
75
|
-
const enabled = this.effectivelyEnabled();
|
|
76
|
-
const out = [];
|
|
77
|
-
for (const [addonId, impl] of this.getEntries()) {
|
|
78
|
-
let serverCount = 0;
|
|
79
|
-
let urls = [];
|
|
80
|
-
let error;
|
|
81
|
-
const isEnabled = enabled.has(addonId);
|
|
82
|
-
if (isEnabled && impl.getTurnServers) try {
|
|
83
|
-
const servers = await impl.getTurnServers();
|
|
84
|
-
serverCount = servers.length;
|
|
85
|
-
const flat = [];
|
|
86
|
-
for (const s of servers) if (Array.isArray(s.urls)) flat.push(...s.urls);
|
|
87
|
-
else if (typeof s.urls === "string") flat.push(s.urls);
|
|
88
|
-
urls = flat;
|
|
89
|
-
} catch (err) {
|
|
90
|
-
error = err instanceof Error ? err.message : String(err);
|
|
91
|
-
}
|
|
92
|
-
out.push({
|
|
93
|
-
addonId,
|
|
94
|
-
displayName: impl.displayName ?? addonId,
|
|
95
|
-
enabled: isEnabled,
|
|
96
|
-
serverCount,
|
|
97
|
-
urls,
|
|
98
|
-
...error !== void 0 ? { error } : {}
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
return out;
|
|
102
|
-
}
|
|
103
|
-
async getAllServers() {
|
|
104
|
-
const enabled = this.effectivelyEnabled();
|
|
105
|
-
const out = [];
|
|
106
|
-
for (const [addonId, impl] of this.getEntries()) {
|
|
107
|
-
if (!enabled.has(addonId)) continue;
|
|
108
|
-
if (!impl.getTurnServers) continue;
|
|
109
|
-
try {
|
|
110
|
-
const servers = await impl.getTurnServers();
|
|
111
|
-
out.push(...servers);
|
|
112
|
-
} catch (err) {
|
|
113
|
-
this.ctx.logger.warn("TURN provider failed to enumerate servers", { meta: {
|
|
114
|
-
addonId,
|
|
115
|
-
error: err instanceof Error ? err.message : String(err)
|
|
116
|
-
} });
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return out;
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
//#endregion
|
|
123
|
-
exports.TurnOrchestratorAddon = TurnOrchestratorAddon;
|
|
124
|
-
exports.default = TurnOrchestratorAddon;
|
|
125
|
-
|
|
126
|
-
//# sourceMappingURL=turn-orchestrator.addon.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"turn-orchestrator.addon.js","names":[],"sources":["../../../src/builtins/turn-orchestrator/turn-orchestrator.addon.ts"],"sourcesContent":["/**\n * TURN orchestrator — singleton facade over the `turn-provider`\n * collection (Cloudflare TURN, coturn, Twilio, …). Mirrors the\n * remote-access-orchestrator persistence + autostart contract:\n * - `enabledProviders: string[]` in addon-store is the operator's\n * intent. Boot reads it back; the Enable/Disable toggle in the\n * admin UI writes it.\n * - `getAllServers()` (consumed by the WebRTC layer) aggregates ICE\n * servers ONLY from enabled providers.\n * - `listProviders()` surfaces the persisted `enabled` flag so the\n * UI can render the correct toggle state on first paint.\n *\n * Provides:\n * - listProviders() — admin UI inventory\n * - getAllServers() — combined ICE server list across enabled providers\n * - setProviderEnabled() — toggle a provider on/off (persisted)\n */\nimport {\n BaseAddon,\n turnOrchestratorCapability,\n type ITurnOrchestratorProvider,\n type TurnProviderInfo,\n type ProviderRegistration,\n} from '@camstack/types'\n\ninterface TurnProviderLike {\n getTurnServers?: () => Promise<readonly { urls: string | string[]; username?: string; credential?: string }[]>\n readonly displayName?: string\n}\n\ninterface TurnOrchestratorConfig {\n /**\n * addonIds the operator has explicitly enabled. Persisted in the\n * addon-store; first-launch defaults to \"every provider enabled\" so\n * a freshly-installed TURN addon participates immediately (the\n * operator can disable from the UI). See `effectivelyEnabled`.\n */\n readonly enabledProviders: readonly string[]\n /**\n * Sentinel: true after `enabledProviders` has been written at least\n * once. Distinguishes \"operator hasn't touched the toggles yet —\n * default-enable all\" from \"operator cleared the list — keep it\n * empty\". Same shape as local-network's bootSeeded.\n */\n readonly enabledProvidersSeeded: boolean\n}\n\nexport class TurnOrchestratorAddon extends BaseAddon<TurnOrchestratorConfig> {\n constructor() {\n super({ enabledProviders: [], enabledProvidersSeeded: false })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const provider: ITurnOrchestratorProvider = {\n listProviders: async () => this.listProviders(),\n getAllServers: async () => this.getAllServers(),\n setProviderEnabled: async ({ addonId, enabled }) => {\n await this.markEnabled(addonId, enabled)\n return { success: true as const }\n },\n }\n this.ctx.logger.info('TURN orchestrator initialized', {\n meta: {\n enabledCount: this.config.enabledProviders.length,\n seeded: this.config.enabledProvidersSeeded,\n },\n })\n return [{ capability: turnOrchestratorCapability, provider }]\n }\n\n private getEntries(): readonly (readonly [string, TurnProviderLike])[] {\n return this.capabilities?.getCollectionEntries<TurnProviderLike>('turn-provider') ?? []\n }\n\n /**\n * Operator-effective enabled set. Before the first toggle, default\n * to \"every registered provider is enabled\" so a fresh install of a\n * TURN addon participates without manual intervention. After the\n * operator clicks anything, the persisted list is authoritative.\n */\n private effectivelyEnabled(): Set<string> {\n if (this.config.enabledProvidersSeeded) {\n return new Set(this.config.enabledProviders)\n }\n return new Set(this.getEntries().map(([id]) => id))\n }\n\n private async markEnabled(addonId: string, enabled: boolean): Promise<void> {\n const current = this.effectivelyEnabled()\n const wasEnabled = current.has(addonId)\n if (enabled) current.add(addonId); else current.delete(addonId)\n // Always persist with seeded=true so the operator's choice locks in.\n if (wasEnabled === enabled && this.config.enabledProvidersSeeded) return\n await this.updateGlobalSettings({\n enabledProviders: [...current],\n enabledProvidersSeeded: true,\n })\n }\n\n private async listProviders(): Promise<readonly TurnProviderInfo[]> {\n const enabled = this.effectivelyEnabled()\n const out: TurnProviderInfo[] = []\n for (const [addonId, impl] of this.getEntries()) {\n let serverCount = 0\n let urls: readonly string[] = []\n let error: string | undefined\n const isEnabled = enabled.has(addonId)\n // Only fetch live server count for enabled providers — disabled\n // providers shouldn't be making outbound API calls just to render\n // an admin row.\n if (isEnabled && impl.getTurnServers) {\n try {\n const servers = await impl.getTurnServers()\n serverCount = servers.length\n // Flatten the urls field of every ICE-server entry into one\n // list — `{ urls: ['stun:a', 'stun:b'] }` becomes `['stun:a',\n // 'stun:b']`; `{ urls: 'turn:x' }` becomes `['turn:x']`. The\n // admin UI's compact per-provider chip list iterates this.\n const flat: string[] = []\n for (const s of servers) {\n if (Array.isArray(s.urls)) flat.push(...s.urls)\n else if (typeof s.urls === 'string') flat.push(s.urls)\n }\n urls = flat\n } catch (err) {\n error = err instanceof Error ? err.message : String(err)\n }\n }\n out.push({\n addonId,\n displayName: impl.displayName ?? addonId,\n enabled: isEnabled,\n serverCount,\n urls,\n ...(error !== undefined ? { error } : {}),\n })\n }\n return out\n }\n\n private async getAllServers(): Promise<readonly { urls: string | string[]; username?: string; credential?: string }[]> {\n const enabled = this.effectivelyEnabled()\n const out: { urls: string | string[]; username?: string; credential?: string }[] = []\n for (const [addonId, impl] of this.getEntries()) {\n if (!enabled.has(addonId)) continue\n if (!impl.getTurnServers) continue\n try {\n const servers = await impl.getTurnServers()\n out.push(...servers)\n } catch (err) {\n this.ctx.logger.warn('TURN provider failed to enumerate servers', {\n meta: { addonId, error: err instanceof Error ? err.message : String(err) },\n })\n }\n }\n return out\n }\n}\n\nexport default TurnOrchestratorAddon\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA+CA,IAAa,wBAAb,cAA2C,gBAAA,UAAkC;CAC3E,cAAc;EACZ,MAAM;GAAE,kBAAkB,EAAE;GAAE,wBAAwB;GAAO,CAAC;;CAGhE,MAAgB,eAAgD;EAC9D,MAAM,WAAsC;GAC1C,eAAe,YAAY,KAAK,eAAe;GAC/C,eAAe,YAAY,KAAK,eAAe;GAC/C,oBAAoB,OAAO,EAAE,SAAS,cAAc;IAClD,MAAM,KAAK,YAAY,SAAS,QAAQ;IACxC,OAAO,EAAE,SAAS,MAAe;;GAEpC;EACD,KAAK,IAAI,OAAO,KAAK,iCAAiC,EACpD,MAAM;GACJ,cAAc,KAAK,OAAO,iBAAiB;GAC3C,QAAQ,KAAK,OAAO;GACrB,EACF,CAAC;EACF,OAAO,CAAC;GAAE,YAAY,gBAAA;GAA4B;GAAU,CAAC;;CAG/D,aAAuE;EACrE,OAAO,KAAK,cAAc,qBAAuC,gBAAgB,IAAI,EAAE;;;;;;;;CASzF,qBAA0C;EACxC,IAAI,KAAK,OAAO,wBACd,OAAO,IAAI,IAAI,KAAK,OAAO,iBAAiB;EAE9C,OAAO,IAAI,IAAI,KAAK,YAAY,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC;;CAGrD,MAAc,YAAY,SAAiB,SAAiC;EAC1E,MAAM,UAAU,KAAK,oBAAoB;EACzC,MAAM,aAAa,QAAQ,IAAI,QAAQ;EACvC,IAAI,SAAS,QAAQ,IAAI,QAAQ;OAAO,QAAQ,OAAO,QAAQ;EAE/D,IAAI,eAAe,WAAW,KAAK,OAAO,wBAAwB;EAClE,MAAM,KAAK,qBAAqB;GAC9B,kBAAkB,CAAC,GAAG,QAAQ;GAC9B,wBAAwB;GACzB,CAAC;;CAGJ,MAAc,gBAAsD;EAClE,MAAM,UAAU,KAAK,oBAAoB;EACzC,MAAM,MAA0B,EAAE;EAClC,KAAK,MAAM,CAAC,SAAS,SAAS,KAAK,YAAY,EAAE;GAC/C,IAAI,cAAc;GAClB,IAAI,OAA0B,EAAE;GAChC,IAAI;GACJ,MAAM,YAAY,QAAQ,IAAI,QAAQ;GAItC,IAAI,aAAa,KAAK,gBACpB,IAAI;IACF,MAAM,UAAU,MAAM,KAAK,gBAAgB;IAC3C,cAAc,QAAQ;IAKtB,MAAM,OAAiB,EAAE;IACzB,KAAK,MAAM,KAAK,SACd,IAAI,MAAM,QAAQ,EAAE,KAAK,EAAE,KAAK,KAAK,GAAG,EAAE,KAAK;SAC1C,IAAI,OAAO,EAAE,SAAS,UAAU,KAAK,KAAK,EAAE,KAAK;IAExD,OAAO;YACA,KAAK;IACZ,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;;GAG5D,IAAI,KAAK;IACP;IACA,aAAa,KAAK,eAAe;IACjC,SAAS;IACT;IACA;IACA,GAAI,UAAU,KAAA,IAAY,EAAE,OAAO,GAAG,EAAE;IACzC,CAAC;;EAEJ,OAAO;;CAGT,MAAc,gBAAyG;EACrH,MAAM,UAAU,KAAK,oBAAoB;EACzC,MAAM,MAA6E,EAAE;EACrF,KAAK,MAAM,CAAC,SAAS,SAAS,KAAK,YAAY,EAAE;GAC/C,IAAI,CAAC,QAAQ,IAAI,QAAQ,EAAE;GAC3B,IAAI,CAAC,KAAK,gBAAgB;GAC1B,IAAI;IACF,MAAM,UAAU,MAAM,KAAK,gBAAgB;IAC3C,IAAI,KAAK,GAAG,QAAQ;YACb,KAAK;IACZ,KAAK,IAAI,OAAO,KAAK,6CAA6C,EAChE,MAAM;KAAE;KAAS,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;KAAE,EAC3E,CAAC;;;EAGN,OAAO"}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { BaseAddon, turnOrchestratorCapability } from "@camstack/types";
|
|
2
|
-
//#region src/builtins/turn-orchestrator/turn-orchestrator.addon.ts
|
|
3
|
-
/**
|
|
4
|
-
* TURN orchestrator — singleton facade over the `turn-provider`
|
|
5
|
-
* collection (Cloudflare TURN, coturn, Twilio, …). Mirrors the
|
|
6
|
-
* remote-access-orchestrator persistence + autostart contract:
|
|
7
|
-
* - `enabledProviders: string[]` in addon-store is the operator's
|
|
8
|
-
* intent. Boot reads it back; the Enable/Disable toggle in the
|
|
9
|
-
* admin UI writes it.
|
|
10
|
-
* - `getAllServers()` (consumed by the WebRTC layer) aggregates ICE
|
|
11
|
-
* servers ONLY from enabled providers.
|
|
12
|
-
* - `listProviders()` surfaces the persisted `enabled` flag so the
|
|
13
|
-
* UI can render the correct toggle state on first paint.
|
|
14
|
-
*
|
|
15
|
-
* Provides:
|
|
16
|
-
* - listProviders() — admin UI inventory
|
|
17
|
-
* - getAllServers() — combined ICE server list across enabled providers
|
|
18
|
-
* - setProviderEnabled() — toggle a provider on/off (persisted)
|
|
19
|
-
*/
|
|
20
|
-
var TurnOrchestratorAddon = class extends BaseAddon {
|
|
21
|
-
constructor() {
|
|
22
|
-
super({
|
|
23
|
-
enabledProviders: [],
|
|
24
|
-
enabledProvidersSeeded: false
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
async onInitialize() {
|
|
28
|
-
const provider = {
|
|
29
|
-
listProviders: async () => this.listProviders(),
|
|
30
|
-
getAllServers: async () => this.getAllServers(),
|
|
31
|
-
setProviderEnabled: async ({ addonId, enabled }) => {
|
|
32
|
-
await this.markEnabled(addonId, enabled);
|
|
33
|
-
return { success: true };
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
this.ctx.logger.info("TURN orchestrator initialized", { meta: {
|
|
37
|
-
enabledCount: this.config.enabledProviders.length,
|
|
38
|
-
seeded: this.config.enabledProvidersSeeded
|
|
39
|
-
} });
|
|
40
|
-
return [{
|
|
41
|
-
capability: turnOrchestratorCapability,
|
|
42
|
-
provider
|
|
43
|
-
}];
|
|
44
|
-
}
|
|
45
|
-
getEntries() {
|
|
46
|
-
return this.capabilities?.getCollectionEntries("turn-provider") ?? [];
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Operator-effective enabled set. Before the first toggle, default
|
|
50
|
-
* to "every registered provider is enabled" so a fresh install of a
|
|
51
|
-
* TURN addon participates without manual intervention. After the
|
|
52
|
-
* operator clicks anything, the persisted list is authoritative.
|
|
53
|
-
*/
|
|
54
|
-
effectivelyEnabled() {
|
|
55
|
-
if (this.config.enabledProvidersSeeded) return new Set(this.config.enabledProviders);
|
|
56
|
-
return new Set(this.getEntries().map(([id]) => id));
|
|
57
|
-
}
|
|
58
|
-
async markEnabled(addonId, enabled) {
|
|
59
|
-
const current = this.effectivelyEnabled();
|
|
60
|
-
const wasEnabled = current.has(addonId);
|
|
61
|
-
if (enabled) current.add(addonId);
|
|
62
|
-
else current.delete(addonId);
|
|
63
|
-
if (wasEnabled === enabled && this.config.enabledProvidersSeeded) return;
|
|
64
|
-
await this.updateGlobalSettings({
|
|
65
|
-
enabledProviders: [...current],
|
|
66
|
-
enabledProvidersSeeded: true
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
async listProviders() {
|
|
70
|
-
const enabled = this.effectivelyEnabled();
|
|
71
|
-
const out = [];
|
|
72
|
-
for (const [addonId, impl] of this.getEntries()) {
|
|
73
|
-
let serverCount = 0;
|
|
74
|
-
let urls = [];
|
|
75
|
-
let error;
|
|
76
|
-
const isEnabled = enabled.has(addonId);
|
|
77
|
-
if (isEnabled && impl.getTurnServers) try {
|
|
78
|
-
const servers = await impl.getTurnServers();
|
|
79
|
-
serverCount = servers.length;
|
|
80
|
-
const flat = [];
|
|
81
|
-
for (const s of servers) if (Array.isArray(s.urls)) flat.push(...s.urls);
|
|
82
|
-
else if (typeof s.urls === "string") flat.push(s.urls);
|
|
83
|
-
urls = flat;
|
|
84
|
-
} catch (err) {
|
|
85
|
-
error = err instanceof Error ? err.message : String(err);
|
|
86
|
-
}
|
|
87
|
-
out.push({
|
|
88
|
-
addonId,
|
|
89
|
-
displayName: impl.displayName ?? addonId,
|
|
90
|
-
enabled: isEnabled,
|
|
91
|
-
serverCount,
|
|
92
|
-
urls,
|
|
93
|
-
...error !== void 0 ? { error } : {}
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
return out;
|
|
97
|
-
}
|
|
98
|
-
async getAllServers() {
|
|
99
|
-
const enabled = this.effectivelyEnabled();
|
|
100
|
-
const out = [];
|
|
101
|
-
for (const [addonId, impl] of this.getEntries()) {
|
|
102
|
-
if (!enabled.has(addonId)) continue;
|
|
103
|
-
if (!impl.getTurnServers) continue;
|
|
104
|
-
try {
|
|
105
|
-
const servers = await impl.getTurnServers();
|
|
106
|
-
out.push(...servers);
|
|
107
|
-
} catch (err) {
|
|
108
|
-
this.ctx.logger.warn("TURN provider failed to enumerate servers", { meta: {
|
|
109
|
-
addonId,
|
|
110
|
-
error: err instanceof Error ? err.message : String(err)
|
|
111
|
-
} });
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return out;
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
//#endregion
|
|
118
|
-
export { TurnOrchestratorAddon, TurnOrchestratorAddon as default };
|
|
119
|
-
|
|
120
|
-
//# sourceMappingURL=turn-orchestrator.addon.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"turn-orchestrator.addon.mjs","names":[],"sources":["../../../src/builtins/turn-orchestrator/turn-orchestrator.addon.ts"],"sourcesContent":["/**\n * TURN orchestrator — singleton facade over the `turn-provider`\n * collection (Cloudflare TURN, coturn, Twilio, …). Mirrors the\n * remote-access-orchestrator persistence + autostart contract:\n * - `enabledProviders: string[]` in addon-store is the operator's\n * intent. Boot reads it back; the Enable/Disable toggle in the\n * admin UI writes it.\n * - `getAllServers()` (consumed by the WebRTC layer) aggregates ICE\n * servers ONLY from enabled providers.\n * - `listProviders()` surfaces the persisted `enabled` flag so the\n * UI can render the correct toggle state on first paint.\n *\n * Provides:\n * - listProviders() — admin UI inventory\n * - getAllServers() — combined ICE server list across enabled providers\n * - setProviderEnabled() — toggle a provider on/off (persisted)\n */\nimport {\n BaseAddon,\n turnOrchestratorCapability,\n type ITurnOrchestratorProvider,\n type TurnProviderInfo,\n type ProviderRegistration,\n} from '@camstack/types'\n\ninterface TurnProviderLike {\n getTurnServers?: () => Promise<readonly { urls: string | string[]; username?: string; credential?: string }[]>\n readonly displayName?: string\n}\n\ninterface TurnOrchestratorConfig {\n /**\n * addonIds the operator has explicitly enabled. Persisted in the\n * addon-store; first-launch defaults to \"every provider enabled\" so\n * a freshly-installed TURN addon participates immediately (the\n * operator can disable from the UI). See `effectivelyEnabled`.\n */\n readonly enabledProviders: readonly string[]\n /**\n * Sentinel: true after `enabledProviders` has been written at least\n * once. Distinguishes \"operator hasn't touched the toggles yet —\n * default-enable all\" from \"operator cleared the list — keep it\n * empty\". Same shape as local-network's bootSeeded.\n */\n readonly enabledProvidersSeeded: boolean\n}\n\nexport class TurnOrchestratorAddon extends BaseAddon<TurnOrchestratorConfig> {\n constructor() {\n super({ enabledProviders: [], enabledProvidersSeeded: false })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const provider: ITurnOrchestratorProvider = {\n listProviders: async () => this.listProviders(),\n getAllServers: async () => this.getAllServers(),\n setProviderEnabled: async ({ addonId, enabled }) => {\n await this.markEnabled(addonId, enabled)\n return { success: true as const }\n },\n }\n this.ctx.logger.info('TURN orchestrator initialized', {\n meta: {\n enabledCount: this.config.enabledProviders.length,\n seeded: this.config.enabledProvidersSeeded,\n },\n })\n return [{ capability: turnOrchestratorCapability, provider }]\n }\n\n private getEntries(): readonly (readonly [string, TurnProviderLike])[] {\n return this.capabilities?.getCollectionEntries<TurnProviderLike>('turn-provider') ?? []\n }\n\n /**\n * Operator-effective enabled set. Before the first toggle, default\n * to \"every registered provider is enabled\" so a fresh install of a\n * TURN addon participates without manual intervention. After the\n * operator clicks anything, the persisted list is authoritative.\n */\n private effectivelyEnabled(): Set<string> {\n if (this.config.enabledProvidersSeeded) {\n return new Set(this.config.enabledProviders)\n }\n return new Set(this.getEntries().map(([id]) => id))\n }\n\n private async markEnabled(addonId: string, enabled: boolean): Promise<void> {\n const current = this.effectivelyEnabled()\n const wasEnabled = current.has(addonId)\n if (enabled) current.add(addonId); else current.delete(addonId)\n // Always persist with seeded=true so the operator's choice locks in.\n if (wasEnabled === enabled && this.config.enabledProvidersSeeded) return\n await this.updateGlobalSettings({\n enabledProviders: [...current],\n enabledProvidersSeeded: true,\n })\n }\n\n private async listProviders(): Promise<readonly TurnProviderInfo[]> {\n const enabled = this.effectivelyEnabled()\n const out: TurnProviderInfo[] = []\n for (const [addonId, impl] of this.getEntries()) {\n let serverCount = 0\n let urls: readonly string[] = []\n let error: string | undefined\n const isEnabled = enabled.has(addonId)\n // Only fetch live server count for enabled providers — disabled\n // providers shouldn't be making outbound API calls just to render\n // an admin row.\n if (isEnabled && impl.getTurnServers) {\n try {\n const servers = await impl.getTurnServers()\n serverCount = servers.length\n // Flatten the urls field of every ICE-server entry into one\n // list — `{ urls: ['stun:a', 'stun:b'] }` becomes `['stun:a',\n // 'stun:b']`; `{ urls: 'turn:x' }` becomes `['turn:x']`. The\n // admin UI's compact per-provider chip list iterates this.\n const flat: string[] = []\n for (const s of servers) {\n if (Array.isArray(s.urls)) flat.push(...s.urls)\n else if (typeof s.urls === 'string') flat.push(s.urls)\n }\n urls = flat\n } catch (err) {\n error = err instanceof Error ? err.message : String(err)\n }\n }\n out.push({\n addonId,\n displayName: impl.displayName ?? addonId,\n enabled: isEnabled,\n serverCount,\n urls,\n ...(error !== undefined ? { error } : {}),\n })\n }\n return out\n }\n\n private async getAllServers(): Promise<readonly { urls: string | string[]; username?: string; credential?: string }[]> {\n const enabled = this.effectivelyEnabled()\n const out: { urls: string | string[]; username?: string; credential?: string }[] = []\n for (const [addonId, impl] of this.getEntries()) {\n if (!enabled.has(addonId)) continue\n if (!impl.getTurnServers) continue\n try {\n const servers = await impl.getTurnServers()\n out.push(...servers)\n } catch (err) {\n this.ctx.logger.warn('TURN provider failed to enumerate servers', {\n meta: { addonId, error: err instanceof Error ? err.message : String(err) },\n })\n }\n }\n return out\n }\n}\n\nexport default TurnOrchestratorAddon\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA+CA,IAAa,wBAAb,cAA2C,UAAkC;CAC3E,cAAc;EACZ,MAAM;GAAE,kBAAkB,EAAE;GAAE,wBAAwB;GAAO,CAAC;;CAGhE,MAAgB,eAAgD;EAC9D,MAAM,WAAsC;GAC1C,eAAe,YAAY,KAAK,eAAe;GAC/C,eAAe,YAAY,KAAK,eAAe;GAC/C,oBAAoB,OAAO,EAAE,SAAS,cAAc;IAClD,MAAM,KAAK,YAAY,SAAS,QAAQ;IACxC,OAAO,EAAE,SAAS,MAAe;;GAEpC;EACD,KAAK,IAAI,OAAO,KAAK,iCAAiC,EACpD,MAAM;GACJ,cAAc,KAAK,OAAO,iBAAiB;GAC3C,QAAQ,KAAK,OAAO;GACrB,EACF,CAAC;EACF,OAAO,CAAC;GAAE,YAAY;GAA4B;GAAU,CAAC;;CAG/D,aAAuE;EACrE,OAAO,KAAK,cAAc,qBAAuC,gBAAgB,IAAI,EAAE;;;;;;;;CASzF,qBAA0C;EACxC,IAAI,KAAK,OAAO,wBACd,OAAO,IAAI,IAAI,KAAK,OAAO,iBAAiB;EAE9C,OAAO,IAAI,IAAI,KAAK,YAAY,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC;;CAGrD,MAAc,YAAY,SAAiB,SAAiC;EAC1E,MAAM,UAAU,KAAK,oBAAoB;EACzC,MAAM,aAAa,QAAQ,IAAI,QAAQ;EACvC,IAAI,SAAS,QAAQ,IAAI,QAAQ;OAAO,QAAQ,OAAO,QAAQ;EAE/D,IAAI,eAAe,WAAW,KAAK,OAAO,wBAAwB;EAClE,MAAM,KAAK,qBAAqB;GAC9B,kBAAkB,CAAC,GAAG,QAAQ;GAC9B,wBAAwB;GACzB,CAAC;;CAGJ,MAAc,gBAAsD;EAClE,MAAM,UAAU,KAAK,oBAAoB;EACzC,MAAM,MAA0B,EAAE;EAClC,KAAK,MAAM,CAAC,SAAS,SAAS,KAAK,YAAY,EAAE;GAC/C,IAAI,cAAc;GAClB,IAAI,OAA0B,EAAE;GAChC,IAAI;GACJ,MAAM,YAAY,QAAQ,IAAI,QAAQ;GAItC,IAAI,aAAa,KAAK,gBACpB,IAAI;IACF,MAAM,UAAU,MAAM,KAAK,gBAAgB;IAC3C,cAAc,QAAQ;IAKtB,MAAM,OAAiB,EAAE;IACzB,KAAK,MAAM,KAAK,SACd,IAAI,MAAM,QAAQ,EAAE,KAAK,EAAE,KAAK,KAAK,GAAG,EAAE,KAAK;SAC1C,IAAI,OAAO,EAAE,SAAS,UAAU,KAAK,KAAK,EAAE,KAAK;IAExD,OAAO;YACA,KAAK;IACZ,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;;GAG5D,IAAI,KAAK;IACP;IACA,aAAa,KAAK,eAAe;IACjC,SAAS;IACT;IACA;IACA,GAAI,UAAU,KAAA,IAAY,EAAE,OAAO,GAAG,EAAE;IACzC,CAAC;;EAEJ,OAAO;;CAGT,MAAc,gBAAyG;EACrH,MAAM,UAAU,KAAK,oBAAoB;EACzC,MAAM,MAA6E,EAAE;EACrF,KAAK,MAAM,CAAC,SAAS,SAAS,KAAK,YAAY,EAAE;GAC/C,IAAI,CAAC,QAAQ,IAAI,QAAQ,EAAE;GAC3B,IAAI,CAAC,KAAK,gBAAgB;GAC1B,IAAI;IACF,MAAM,UAAU,MAAM,KAAK,gBAAgB;IAC3C,IAAI,KAAK,GAAG,QAAQ;YACb,KAAK;IACZ,KAAK,IAAI,OAAO,KAAK,6CAA6C,EAChE,MAAM;KAAE;KAAS,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;KAAE,EAC3E,CAAC;;;EAGN,OAAO"}
|