@camstack/core 0.1.34 → 0.1.36

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 (30) hide show
  1. package/dist/auth/auth-manager.d.ts +8 -0
  2. package/dist/auth/auth-manager.d.ts.map +1 -1
  3. package/dist/builtins/local-auth/local-auth.addon.d.ts.map +1 -1
  4. package/dist/builtins/local-auth/local-auth.addon.js +26 -5
  5. package/dist/builtins/local-auth/local-auth.addon.js.map +1 -1
  6. package/dist/builtins/local-auth/local-auth.addon.mjs +26 -5
  7. package/dist/builtins/local-auth/local-auth.addon.mjs.map +1 -1
  8. package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.d.ts.map +1 -1
  9. package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.js +32 -1
  10. package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.js.map +1 -1
  11. package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.mjs +32 -1
  12. package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.mjs.map +1 -1
  13. package/dist/builtins/platform-probe/hardware-encoder-probe.d.ts +14 -0
  14. package/dist/builtins/platform-probe/hardware-encoder-probe.d.ts.map +1 -0
  15. package/dist/builtins/platform-probe/index.d.ts +2 -0
  16. package/dist/builtins/platform-probe/index.d.ts.map +1 -1
  17. package/dist/builtins/platform-probe/index.js +198 -5
  18. package/dist/builtins/platform-probe/index.js.map +1 -1
  19. package/dist/builtins/platform-probe/index.mjs +198 -6
  20. package/dist/builtins/platform-probe/index.mjs.map +1 -1
  21. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts.map +1 -1
  22. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +16 -0
  23. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js.map +1 -1
  24. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +16 -0
  25. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs.map +1 -1
  26. package/dist/index.js +373 -181
  27. package/dist/index.js.map +1 -1
  28. package/dist/index.mjs +373 -181
  29. package/dist/index.mjs.map +1 -1
  30. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"mesh-orchestrator.addon.d.ts","sourceRoot":"","sources":["../../../src/builtins/mesh-orchestrator/mesh-orchestrator.addon.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,SAAS,EAIT,KAAK,oBAAoB,EAC1B,MAAM,iBAAiB,CAAA;AA2BxB,qBAAa,qBAAsB,SAAQ,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;;cAKzD,YAAY,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAkB/D,OAAO,CAAC,WAAW;YAML,aAAa;CAsC5B;AAED,eAAe,qBAAqB,CAAA"}
1
+ {"version":3,"file":"mesh-orchestrator.addon.d.ts","sourceRoot":"","sources":["../../../src/builtins/mesh-orchestrator/mesh-orchestrator.addon.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,SAAS,EAKT,KAAK,oBAAoB,EAC1B,MAAM,iBAAiB,CAAA;AAqCxB,qBAAa,qBAAsB,SAAQ,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;;cAKzD,YAAY,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAsC/D,OAAO,CAAC,WAAW;YAML,aAAa;CAqD5B;AAED,eAAe,qBAAqB,CAAA"}
@@ -29,6 +29,22 @@ var MeshOrchestratorAddon = class extends _camstack_types.BaseAddon {
29
29
  const impl = this.resolveImpl(addonId);
30
30
  if (impl?.leave) await impl.leave();
31
31
  return { success: true };
32
+ },
33
+ startLoginProvider: async ({ addonId, hostname }) => {
34
+ const impl = this.resolveImpl(addonId);
35
+ if (!impl?.startLogin) throw new Error(`Mesh provider "${addonId}" does not support startLogin`);
36
+ return await impl.startLogin(hostname ? { hostname } : {});
37
+ },
38
+ logoutProvider: async ({ addonId }) => {
39
+ const impl = this.resolveImpl(addonId);
40
+ if (!impl?.logout) throw new Error(`Mesh provider "${addonId}" does not support logout`);
41
+ await impl.logout();
42
+ return { loggedOut: true };
43
+ },
44
+ listProviderPeers: async ({ addonId }) => {
45
+ const impl = this.resolveImpl(addonId);
46
+ if (!impl?.listPeers) return { peers: [] };
47
+ return await impl.listPeers();
32
48
  }
33
49
  };
34
50
  this.ctx.logger.info("Mesh orchestrator initialized");
@@ -50,6 +66,11 @@ var MeshOrchestratorAddon = class extends _camstack_types.BaseAddon {
50
66
  let peerCount = 0;
51
67
  let endpoints = [];
52
68
  let error;
69
+ let tenantName = "";
70
+ let magicDnsSuffix = "";
71
+ let userLogin = null;
72
+ let controlPlaneUrl = "";
73
+ let keyExpiry = null;
53
74
  if (impl.getStatus) try {
54
75
  const s = await impl.getStatus();
55
76
  joined = s.joined;
@@ -58,6 +79,11 @@ var MeshOrchestratorAddon = class extends _camstack_types.BaseAddon {
58
79
  peerCount = s.peerCount;
59
80
  endpoints = s.endpoints;
60
81
  error = s.error;
82
+ tenantName = s.tenantName;
83
+ magicDnsSuffix = s.magicDnsSuffix;
84
+ userLogin = s.userLogin;
85
+ controlPlaneUrl = s.controlPlaneUrl;
86
+ keyExpiry = s.keyExpiry;
61
87
  } catch (err) {
62
88
  error = err instanceof Error ? err.message : String(err);
63
89
  }
@@ -69,7 +95,12 @@ var MeshOrchestratorAddon = class extends _camstack_types.BaseAddon {
69
95
  magicDnsHostname,
70
96
  peerCount,
71
97
  endpoints,
72
- ...error !== void 0 ? { error } : {}
98
+ ...error !== void 0 ? { error } : {},
99
+ tenantName,
100
+ magicDnsSuffix,
101
+ userLogin,
102
+ controlPlaneUrl,
103
+ keyExpiry
73
104
  });
74
105
  }
75
106
  return out;
@@ -1 +1 @@
1
- {"version":3,"file":"mesh-orchestrator.addon.js","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 MeshProviderInfo,\n type ProviderRegistration,\n} from '@camstack/types'\n\ninterface MeshNetworkLike {\n getStatus?: () => Promise<{\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 }>\n join?: (input: { authKey: string; hostname?: string }) => Promise<{ joined: true }>\n leave?: () => Promise<{ left: true }>\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 }\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 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 } 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 })\n }\n return out\n }\n}\n\nexport default MeshOrchestratorAddon\n"],"mappings":";;;;;;;;;;;;AAsCA,IAAa,wBAAb,cAA2C,gBAAA,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;;GAEpC;EACD,KAAK,IAAI,OAAO,KAAK,gCAAgC;EACrD,OAAO,CAAC;GAAE,YAAY,gBAAA;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,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;YACH,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;IACzC,CAAC;;EAEJ,OAAO"}
1
+ {"version":3,"file":"mesh-orchestrator.addon.js","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,gBAAA,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,gBAAA;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"}
@@ -24,6 +24,22 @@ var MeshOrchestratorAddon = class extends BaseAddon {
24
24
  const impl = this.resolveImpl(addonId);
25
25
  if (impl?.leave) await impl.leave();
26
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();
27
43
  }
28
44
  };
29
45
  this.ctx.logger.info("Mesh orchestrator initialized");
@@ -45,6 +61,11 @@ var MeshOrchestratorAddon = class extends BaseAddon {
45
61
  let peerCount = 0;
46
62
  let endpoints = [];
47
63
  let error;
64
+ let tenantName = "";
65
+ let magicDnsSuffix = "";
66
+ let userLogin = null;
67
+ let controlPlaneUrl = "";
68
+ let keyExpiry = null;
48
69
  if (impl.getStatus) try {
49
70
  const s = await impl.getStatus();
50
71
  joined = s.joined;
@@ -53,6 +74,11 @@ var MeshOrchestratorAddon = class extends BaseAddon {
53
74
  peerCount = s.peerCount;
54
75
  endpoints = s.endpoints;
55
76
  error = s.error;
77
+ tenantName = s.tenantName;
78
+ magicDnsSuffix = s.magicDnsSuffix;
79
+ userLogin = s.userLogin;
80
+ controlPlaneUrl = s.controlPlaneUrl;
81
+ keyExpiry = s.keyExpiry;
56
82
  } catch (err) {
57
83
  error = err instanceof Error ? err.message : String(err);
58
84
  }
@@ -64,7 +90,12 @@ var MeshOrchestratorAddon = class extends BaseAddon {
64
90
  magicDnsHostname,
65
91
  peerCount,
66
92
  endpoints,
67
- ...error !== void 0 ? { error } : {}
93
+ ...error !== void 0 ? { error } : {},
94
+ tenantName,
95
+ magicDnsSuffix,
96
+ userLogin,
97
+ controlPlaneUrl,
98
+ keyExpiry
68
99
  });
69
100
  }
70
101
  return out;
@@ -1 +1 @@
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 MeshProviderInfo,\n type ProviderRegistration,\n} from '@camstack/types'\n\ninterface MeshNetworkLike {\n getStatus?: () => Promise<{\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 }>\n join?: (input: { authKey: string; hostname?: string }) => Promise<{ joined: true }>\n leave?: () => Promise<{ left: true }>\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 }\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 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 } 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 })\n }\n return out\n }\n}\n\nexport default MeshOrchestratorAddon\n"],"mappings":";;;;;;;AAsCA,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;;GAEpC;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,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;YACH,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;IACzC,CAAC;;EAEJ,OAAO"}
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"}
@@ -0,0 +1,14 @@
1
+ import { HardwareInfo, HardwareEncoders, IScopedLogger } from '@camstack/types';
2
+ export declare class HardwareEncoderProber {
3
+ private cached;
4
+ private inflight;
5
+ private readonly logger;
6
+ private readonly ffmpegPath;
7
+ constructor(logger: IScopedLogger, ffmpegPath?: string);
8
+ getCached(): HardwareEncoders | null;
9
+ probe(hardware: HardwareInfo, options?: {
10
+ readonly force?: boolean;
11
+ }): Promise<HardwareEncoders>;
12
+ private runProbe;
13
+ }
14
+ //# sourceMappingURL=hardware-encoder-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hardware-encoder-probe.d.ts","sourceRoot":"","sources":["../../../src/builtins/platform-probe/hardware-encoder-probe.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,YAAY,EAGZ,gBAAgB,EAChB,aAAa,EACd,MAAM,iBAAiB,CAAA;AA4ExB,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,QAAQ,CAAyC;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;gBAEvB,MAAM,EAAE,aAAa,EAAE,UAAU,SAAW;IAKxD,SAAS,IAAI,gBAAgB,GAAG,IAAI;IAI9B,KAAK,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,GAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC;YAiB5F,QAAQ;CAuCvB"}
@@ -1,8 +1,10 @@
1
1
  import { ProviderRegistration, BaseAddon } from '@camstack/types';
2
2
  export { PlatformScorer } from './platform-scorer.js';
3
3
  export { InferenceConfigResolver } from './inference-config-resolver.js';
4
+ export { HardwareEncoderProber } from './hardware-encoder-probe.js';
4
5
  export declare class PlatformProbeNativeAddon extends BaseAddon {
5
6
  private scorer;
7
+ private encoderProber;
6
8
  private cachedCaps;
7
9
  constructor();
8
10
  protected onInitialize(): Promise<ProviderRegistration[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/builtins/platform-probe/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EACV,oBAAoB,EAOrB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,SAAS,EAAkD,MAAM,iBAAiB,CAAA;AAI3F,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AAExE,qBAAa,wBAAyB,SAAQ,SAAS;IACrD,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,UAAU,CAAoC;;cAItC,YAAY,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;cA4E/C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAI5C;AAED,eAAe,wBAAwB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/builtins/platform-probe/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EACV,oBAAoB,EAQrB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,SAAS,EAAkD,MAAM,iBAAiB,CAAA;AAK3F,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAA;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;AAEnE,qBAAa,wBAAyB,SAAQ,SAAS;IACrD,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,UAAU,CAAoC;;cAItC,YAAY,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;cA0F/C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAK5C;AAED,eAAe,wBAAwB,CAAA"}
@@ -16,7 +16,7 @@ node_os = require_chunk.__toESM(node_os);
16
16
  * entire Node process (WS handshakes, tRPC subscriptions, metrics — all
17
17
  * stalled). Keeping it async turns the probe into a true background task.
18
18
  */
19
- var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
19
+ var execFileAsync$1 = (0, node_util.promisify)(node_child_process.execFile);
20
20
  /** Minimal no-op logger for default parameter */
21
21
  var noopLogger = {
22
22
  debug() {},
@@ -44,7 +44,7 @@ async function getAvailableRAM_MB() {
44
44
  const platform = node_os.platform();
45
45
  try {
46
46
  if (platform === "darwin") {
47
- const { stdout: output } = await execFileAsync("vm_stat", [], {
47
+ const { stdout: output } = await execFileAsync$1("vm_stat", [], {
48
48
  encoding: "utf8",
49
49
  timeout: 3e3
50
50
  });
@@ -169,7 +169,7 @@ var PlatformScorer = class {
169
169
  npu = { type: "apple-ane" };
170
170
  }
171
171
  if (platform === "linux") try {
172
- const { stdout } = await execFileAsync("nvidia-smi", ["--query-gpu=name,memory.total", "--format=csv,noheader"], {
172
+ const { stdout } = await execFileAsync$1("nvidia-smi", ["--query-gpu=name,memory.total", "--format=csv,noheader"], {
173
173
  encoding: "utf8",
174
174
  timeout: 5e3
175
175
  });
@@ -230,7 +230,7 @@ var PlatformScorer = class {
230
230
  async probePythonBackends() {
231
231
  let pythonPath = null;
232
232
  for (const cmd of ["python3", "python"]) try {
233
- await execFileAsync(cmd, ["--version"], { timeout: 5e3 });
233
+ await execFileAsync$1(cmd, ["--version"], { timeout: 5e3 });
234
234
  pythonPath = cmd;
235
235
  break;
236
236
  } catch (err) {
@@ -265,7 +265,7 @@ var PlatformScorer = class {
265
265
  const probeStart = Date.now();
266
266
  let available = false;
267
267
  try {
268
- await execFileAsync(pythonPath, ["-c", `import ${mod}`], { timeout: 3e4 });
268
+ await execFileAsync$1(pythonPath, ["-c", `import ${mod}`], { timeout: 3e4 });
269
269
  available = true;
270
270
  } catch (err) {
271
271
  console.debug(`Python module "${mod}" not installed: ${(0, _camstack_types.errMsg)(err)}`);
@@ -459,15 +459,192 @@ var InferenceConfigResolver = class {
459
459
  }
460
460
  };
461
461
  //#endregion
462
+ //#region src/builtins/platform-probe/hardware-encoder-probe.ts
463
+ var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
464
+ function buildCandidates(hardware) {
465
+ const out = [];
466
+ if (hardware.platform === "darwin") {
467
+ out.push({
468
+ encoder: "h264_videotoolbox",
469
+ codec: "H264",
470
+ family: "videotoolbox"
471
+ });
472
+ out.push({
473
+ encoder: "hevc_videotoolbox",
474
+ codec: "H265",
475
+ family: "videotoolbox"
476
+ });
477
+ }
478
+ if (hardware.platform === "linux") {
479
+ if (hardware.gpu?.type === "nvidia") {
480
+ out.push({
481
+ encoder: "h264_nvenc",
482
+ codec: "H264",
483
+ family: "nvenc"
484
+ });
485
+ out.push({
486
+ encoder: "hevc_nvenc",
487
+ codec: "H265",
488
+ family: "nvenc"
489
+ });
490
+ }
491
+ if (hardware.gpu?.type === "intel" || hardware.gpu?.type === "amd" || !hardware.gpu) {
492
+ out.push({
493
+ encoder: "h264_vaapi",
494
+ codec: "H264",
495
+ family: "vaapi"
496
+ });
497
+ out.push({
498
+ encoder: "hevc_vaapi",
499
+ codec: "H265",
500
+ family: "vaapi"
501
+ });
502
+ }
503
+ }
504
+ return out;
505
+ }
506
+ async function runTestEncode(candidate, opts) {
507
+ const ffmpeg = opts.ffmpegPath ?? "ffmpeg";
508
+ const timeout = opts.timeoutMs ?? 8e3;
509
+ const nullSink = node_os.platform() === "win32" ? "NUL" : "/dev/null";
510
+ const baseArgs = [
511
+ "-hide_banner",
512
+ "-loglevel",
513
+ "error"
514
+ ];
515
+ const inArgs = [
516
+ "-f",
517
+ "lavfi",
518
+ "-i",
519
+ "testsrc=duration=0.04:size=16x16:rate=25"
520
+ ];
521
+ let outArgs;
522
+ if (candidate.family === "vaapi") outArgs = [
523
+ "-vaapi_device",
524
+ "/dev/dri/renderD128",
525
+ "-vf",
526
+ "format=nv12,hwupload",
527
+ "-c:v",
528
+ candidate.encoder,
529
+ "-frames:v",
530
+ "1",
531
+ "-f",
532
+ "null",
533
+ nullSink
534
+ ];
535
+ else outArgs = [
536
+ "-c:v",
537
+ candidate.encoder,
538
+ "-frames:v",
539
+ "1",
540
+ "-f",
541
+ "null",
542
+ nullSink
543
+ ];
544
+ try {
545
+ await execFileAsync(ffmpeg, [
546
+ ...baseArgs,
547
+ ...inArgs,
548
+ ...outArgs
549
+ ], {
550
+ timeout,
551
+ encoding: "utf8"
552
+ });
553
+ return {
554
+ encoder: candidate.encoder,
555
+ codec: candidate.codec,
556
+ family: candidate.family,
557
+ available: true
558
+ };
559
+ } catch (err) {
560
+ return {
561
+ encoder: candidate.encoder,
562
+ codec: candidate.codec,
563
+ family: candidate.family,
564
+ available: false,
565
+ reason: (0, _camstack_types.errMsg)(err)
566
+ };
567
+ }
568
+ }
569
+ var HardwareEncoderProber = class {
570
+ cached = null;
571
+ inflight = null;
572
+ logger;
573
+ ffmpegPath;
574
+ constructor(logger, ffmpegPath = "ffmpeg") {
575
+ this.logger = logger;
576
+ this.ffmpegPath = ffmpegPath;
577
+ }
578
+ getCached() {
579
+ return this.cached;
580
+ }
581
+ async probe(hardware, options = {}) {
582
+ if (!options.force && this.cached) return this.cached;
583
+ if (this.inflight) return this.inflight;
584
+ this.inflight = this.runProbe(hardware).then((res) => {
585
+ this.cached = res;
586
+ this.inflight = null;
587
+ return res;
588
+ }).catch((err) => {
589
+ this.inflight = null;
590
+ throw err;
591
+ });
592
+ return this.inflight;
593
+ }
594
+ async runProbe(hardware) {
595
+ const candidates = buildCandidates(hardware);
596
+ const start = Date.now();
597
+ this.logger.info("Probing hardware encoders", { meta: {
598
+ platform: hardware.platform,
599
+ arch: hardware.arch,
600
+ candidates: candidates.length
601
+ } });
602
+ const probes = await Promise.all(candidates.map((c) => runTestEncode(c, { ffmpegPath: this.ffmpegPath })));
603
+ probes.push({
604
+ encoder: "libx264",
605
+ codec: "H264",
606
+ family: "software",
607
+ available: true
608
+ });
609
+ probes.push({
610
+ encoder: "libx265",
611
+ codec: "H265",
612
+ family: "software",
613
+ available: true
614
+ });
615
+ const pickDefault = (codec) => {
616
+ const hw = probes.find((p) => p.codec === codec && p.available && p.family !== "software");
617
+ if (hw) return hw.encoder;
618
+ return codec === "H264" ? "libx264" : "libx265";
619
+ };
620
+ const result = {
621
+ encoders: probes,
622
+ defaultH264: pickDefault("H264"),
623
+ defaultH265: pickDefault("H265"),
624
+ probedAt: Date.now()
625
+ };
626
+ const elapsed = Date.now() - start;
627
+ this.logger.info("Hardware encoder probe complete", { meta: {
628
+ elapsedMs: elapsed,
629
+ defaultH264: result.defaultH264,
630
+ defaultH265: result.defaultH265,
631
+ availableHw: probes.filter((p) => p.available && p.family !== "software").map((p) => p.encoder)
632
+ } });
633
+ return result;
634
+ }
635
+ };
636
+ //#endregion
462
637
  //#region src/builtins/platform-probe/index.ts
463
638
  var PlatformProbeNativeAddon = class extends _camstack_types.BaseAddon {
464
639
  scorer = null;
640
+ encoderProber = null;
465
641
  cachedCaps = null;
466
642
  constructor() {
467
643
  super({});
468
644
  }
469
645
  async onInitialize() {
470
646
  this.scorer = new PlatformScorer(this.ctx.logger);
647
+ this.encoderProber = new HardwareEncoderProber(this.ctx.logger);
471
648
  const emitPhase = (phase, payload) => {
472
649
  this.ctx.eventBus?.emit({
473
650
  id: `platform-probe-${phase}-${Date.now()}`,
@@ -521,16 +698,32 @@ var PlatformProbeNativeAddon = class extends _camstack_types.BaseAddon {
521
698
  const hwaccel = this.ctx.kernel.hwaccel;
522
699
  if (!hwaccel) return { preferred: [] };
523
700
  return { preferred: (await hwaccel.resolve(input.prefer ?? null)).preferred };
701
+ },
702
+ getHardwareEncoders: async () => {
703
+ const prober = this.encoderProber;
704
+ if (!prober) throw new Error("Hardware encoder prober not initialized");
705
+ const cached = prober.getCached();
706
+ if (cached) return cached;
707
+ const caps = await getCaps();
708
+ return prober.probe(caps.hardware);
709
+ },
710
+ refreshHardwareEncoders: async () => {
711
+ const prober = this.encoderProber;
712
+ if (!prober) throw new Error("Hardware encoder prober not initialized");
713
+ const caps = await getCaps();
714
+ return prober.probe(caps.hardware, { force: true });
524
715
  }
525
716
  }
526
717
  }];
527
718
  }
528
719
  async onShutdown() {
529
720
  this.scorer = null;
721
+ this.encoderProber = null;
530
722
  this.cachedCaps = null;
531
723
  }
532
724
  };
533
725
  //#endregion
726
+ exports.HardwareEncoderProber = HardwareEncoderProber;
534
727
  exports.InferenceConfigResolver = InferenceConfigResolver;
535
728
  exports.PlatformProbeNativeAddon = PlatformProbeNativeAddon;
536
729
  exports.default = PlatformProbeNativeAddon;