@camstack/core 0.1.36 → 0.1.38

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.
Files changed (41) hide show
  1. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +7 -1
  2. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts.map +1 -1
  3. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +46 -56
  4. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js.map +1 -1
  5. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +47 -57
  6. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs.map +1 -1
  7. package/dist/index.js +89 -143
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +89 -143
  10. package/dist/index.mjs.map +1 -1
  11. package/package.json +2 -37
  12. package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.d.ts +0 -8
  13. package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.d.ts.map +0 -1
  14. package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.js +0 -75
  15. package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.js.map +0 -1
  16. package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.mjs +0 -69
  17. package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.mjs.map +0 -1
  18. package/dist/builtins/auth-orchestrator/index.d.ts +0 -2
  19. package/dist/builtins/auth-orchestrator/index.d.ts.map +0 -1
  20. package/dist/builtins/auth-orchestrator/index.js +0 -7
  21. package/dist/builtins/auth-orchestrator/index.mjs +0 -2
  22. package/dist/builtins/mesh-orchestrator/index.d.ts +0 -2
  23. package/dist/builtins/mesh-orchestrator/index.d.ts.map +0 -1
  24. package/dist/builtins/mesh-orchestrator/index.js +0 -7
  25. package/dist/builtins/mesh-orchestrator/index.mjs +0 -2
  26. package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.d.ts +0 -9
  27. package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.d.ts.map +0 -1
  28. package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.js +0 -113
  29. package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.js.map +0 -1
  30. package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.mjs +0 -107
  31. package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.mjs.map +0 -1
  32. package/dist/builtins/turn-orchestrator/index.d.ts +0 -2
  33. package/dist/builtins/turn-orchestrator/index.d.ts.map +0 -1
  34. package/dist/builtins/turn-orchestrator/index.js +0 -7
  35. package/dist/builtins/turn-orchestrator/index.mjs +0 -2
  36. package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.d.ts +0 -34
  37. package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.d.ts.map +0 -1
  38. package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.js +0 -126
  39. package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.js.map +0 -1
  40. package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.mjs +0 -120
  41. package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.mjs.map +0 -1
@@ -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"}