|null $config * @return list */ public static function ids(?array $config): array { // Keeping leads in WConvert only is a promise not to forward future captures. if (self::captureMode($config) === 'local') return []; $bound = $config[self::KEY] ?? null; $ids = []; foreach (is_array($bound) ? $bound : [] as $id) { if (is_string($id) && \WConvert\Support\Ulid::isOne($id) && !in_array($id, $ids, true)) { $ids[] = $id; } } return $ids; } /** Every route for usage/recovery, without merging optional routes into the primary signup. * @param array|null $config * @return list */ public static function allIds(?array $config): array { $ids = self::ids($config); if (self::captureMode($config) === 'local') { return $ids; } foreach ($config['submission_settings'] ?? [] as $setting) { array_push($ids, ...self::ids(['capture_mode' => 'connected', 'destinations' => $setting['destination_ids'] ?? []])); } return array_values(array_unique($ids)); } /** * Where this Optin's leads go: `local` (kept in WConvert only) or * `connected` (forwarded to the bound services). The one reading of * `capture_mode`, so no caller can default it differently. * * **Local until a service is connected** (ADR 0133). An explicit choice * wins; with none stored, a config that binds a Destination anywhere is * connected and one that binds nothing is local — so a fresh setup has * nothing to fix, and a client that writes routes without naming a mode * is not silently cut off from them. The admin's `captureModeOf()` is the * other spelling; `tests/fixtures/link-and-capture-rules.json` holds both. * * @param array|null $config * @return 'local'|'connected' */ public static function captureMode(?array $config): string { $mode = $config['capture_mode'] ?? null; if ($mode === 'local' || $mode === 'connected') return $mode; $routes = is_array($config[self::KEY] ?? null) ? $config[self::KEY] : []; foreach (is_array($config['submission_settings'] ?? null) ? $config['submission_settings'] : [] as $setting) { if (is_array($setting) && is_array($setting['destination_ids'] ?? null)) array_push($routes, ...$setting['destination_ids']); } return array_filter($routes, static fn ($id): bool => is_string($id) && $id !== '') === [] ? 'local' : 'connected'; } /** * @param array|null $config */ public static function binds(?array $config, string $destinationId): bool { return in_array($destinationId, self::allIds($config), true); } }