import path from "node:path"; import { composeUp } from "./docker"; import { upsertEnvValues } from "./env-file"; import type { ResolvedPushSettings } from "./global-settings"; import { listBusinessStacks, stackDir } from "./stacks"; export interface PushRolloutResult { slug: string; ok: boolean; error?: string; } /** * Pushes the global VAPID key pair into every business's own `.env` (same * mechanism as email-rollout.ts's applyEmailSettingsToAllBusinesses — the * surgical, non-destructive `upsertEnvValues` helper, then a * force-recreate so the change actually takes effect). Unlike email's * reply-to, every one of these fields is always overwritten: VAPID * identity is platform-wide infrastructure, never a business preference * (a business has no legitimate reason to run its own key pair — see * global-settings.ts's own header). * * Deliberately does NOT write NEXT_PUBLIC_VAPID_PUBLIC_KEY — that * variable is retired (see src/app/api/push/vapid-public-key/route.ts in * the main app, which now serves the public key at runtime instead of it * being build-time-inlined). Recreating the container is still required * for the *server-side* VAPID_* vars to take effect, exactly like email. * * Runs sequentially, not in parallel, for the same reason * email-rollout.ts does — see that file's own header. */ export async function applyPushSettingsToAllBusinesses(settings: ResolvedPushSettings): Promise { const businesses = await listBusinessStacks(); const results: PushRolloutResult[] = []; for (const business of businesses) { try { const dir = stackDir(business.slug); await upsertEnvValues(path.join(dir, ".env"), { PUSH_PROVIDER: "web-push", VAPID_PUBLIC_KEY: settings.publicKey, VAPID_PRIVATE_KEY: settings.privateKey, VAPID_SUBJECT: settings.subject, }); await composeUp(dir, { forceRecreate: true }); results.push({ slug: business.slug, ok: true }); } catch (error) { results.push({ slug: business.slug, ok: false, error: error instanceof Error ? error.message : String(error) }); } } return results; }