@wtfalch/foundry 0.41.0 → 0.41.1

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.
@@ -5975,6 +5975,7 @@ export class FoundryStepExecutor {
5975
5975
  apex: ownHostnames(org).zone,
5976
5976
  version: action.desired.version,
5977
5977
  project: { ensure: () => this.ensureCoolifyProject(org, context) },
5978
+ ...(context.serverIpv4 ? { serverIpv4: context.serverIpv4 } : {}),
5978
5979
  });
5979
5980
  }
5980
5981
  async jobsRegistration(action, org, context) {
@@ -45,6 +45,8 @@ export interface SfuAppInput {
45
45
  /** The pinned LiveKit release tag. */
46
46
  version: string;
47
47
  project: ProjectSource;
48
+ /** The platform's declared public IPv4: LiveKit's `node_ip`. Absent: the Coolify server's ip, when it is an IPv4. */
49
+ serverIpv4?: string;
48
50
  }
49
51
  /** The compose `ports` lines for a slot: the UDP range and the TCP fallback port, one to one. */
50
52
  export declare function sfuComposePorts(slot: number): string[];
@@ -1,3 +1,4 @@
1
+ import { isIPv4 } from 'node:net';
1
2
  import { DIGESTS, VERSIONS } from '../bootstrap/versions.js';
2
3
  import { mintLivekitCredentials } from '../calls-sfu-keys.js';
3
4
  import { LIVEKIT_SIGNALLING_PORT, sfuSlotPorts } from '../calls-sfu.js';
@@ -132,8 +133,12 @@ export async function provisionSfuApp(scope, deps, target, input) {
132
133
  const server = servers.find((s) => s.is_usable && s.is_reachable) ?? servers[0];
133
134
  if (!server)
134
135
  throw new Error(`${label}: no usable Coolify server is registered`);
135
- if (!server.ip)
136
- throw new Error(`${label}: the Coolify server has no address to give LiveKit`);
136
+ // Coolify reports its localhost server as `host.docker.internal`, which LiveKit refuses as `node_ip`
137
+ // and then restarts forever; the declared address wins, the same rule as the platform's mail server.
138
+ const nodeIp = input.serverIpv4 ?? (server.ip && isIPv4(server.ip) ? server.ip : undefined);
139
+ if (!nodeIp) {
140
+ throw new Error(`${label}: no public IPv4 to give LiveKit; declare the server's public IPv4 as serverIpv4 in the platform config`);
141
+ }
137
142
  const compose = sfuCompose({
138
143
  serviceName: target.internal.sfu,
139
144
  slot: input.slot,
@@ -213,7 +218,7 @@ export async function provisionSfuApp(scope, deps, target, input) {
213
218
  keysJustSet = true;
214
219
  }
215
220
  }
216
- const config = sfuConfig({ slot: input.slot, nodeIp: server.ip, keys });
221
+ const config = sfuConfig({ slot: input.slot, nodeIp, keys });
217
222
  deps.onSecret?.(config);
218
223
  const envChanged = liveConfig !== config;
219
224
  const pending = Boolean(scope.recordedIds()[OWN_SFU_DEPLOY_PENDING_SCOPE_KEY]) || changed || envChanged;
@@ -130,6 +130,12 @@ export interface StepExecutionContext {
130
130
  * platform's Docker network, not on `co-<slug>`, so Archon reaches its database. Absent: false.
131
131
  */
132
132
  readonly ownerCompany?: boolean;
133
+ /**
134
+ * The platform's declared public IPv4 (`DeclaredPlatform.serverIpv4`). A company's media server
135
+ * gives it to LiveKit as `node_ip`: Coolify reports its localhost server as `host.docker.internal`,
136
+ * which LiveKit refuses. Absent: none declared.
137
+ */
138
+ readonly serverIpv4?: string;
133
139
  /**
134
140
  * Every id foundry has recorded for this org so far — both `system:kind:key`
135
141
  * resource ids (`runSteps` records these itself from `execute`'s own return
@@ -908,10 +908,13 @@ export class FoundryPlanApply {
908
908
  const checkpoints = [];
909
909
  // Backed by the very `serviceIds` map this method persists once, at the
910
910
  // end — see `StepExecutionContext`'s doc comment for why.
911
- const ownerCompany = (await this.platformDeps?.store.get())?.ownerOrgId === orgId;
911
+ const declaredPlatform = await this.platformDeps?.store.get();
912
+ const ownerCompany = declaredPlatform?.ownerOrgId === orgId;
913
+ const serverIpv4 = declaredPlatform?.serverIpv4 ?? undefined;
912
914
  const context = {
913
915
  org,
914
916
  ownerCompany,
917
+ ...(serverIpv4 ? { serverIpv4 } : {}),
915
918
  recordedIds: () => ({ ...serviceIds }),
916
919
  now: () => this.now().getTime(),
917
920
  recordScopeId: (key, id) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wtfalch/foundry",
3
- "version": "0.41.0",
3
+ "version": "0.41.1",
4
4
  "description": "Foundry's SDK: the declared org's types, the plan and apply contracts, and the state store's interface.",
5
5
  "repository": {
6
6
  "type": "git",