(ctx: DeleteSubscriptionContext)
| 121 | }, |
| 122 | |
| 123 | async deleteSubscription(ctx: DeleteSubscriptionContext): Promise<void> { |
| 124 | const { webhook, requestId } = ctx |
| 125 | try { |
| 126 | const config = getProviderConfig(webhook) |
| 127 | const apiKey = config.apiKey as string | undefined |
| 128 | const externalId = config.externalId as string | undefined |
| 129 | |
| 130 | if (!apiKey) { |
| 131 | logger.warn( |
| 132 | `[${requestId}] Missing apiKey for Lemlist webhook deletion ${webhook.id}, skipping cleanup` |
| 133 | ) |
| 134 | if (ctx.strict) throw new Error('Missing Lemlist apiKey for webhook deletion') |
| 135 | return |
| 136 | } |
| 137 | |
| 138 | const authString = Buffer.from(`:${apiKey}`).toString('base64') |
| 139 | |
| 140 | const deleteById = async (id: string) => { |
| 141 | const validation = validateAlphanumericId(id, 'Lemlist hook ID', 50) |
| 142 | if (!validation.isValid) { |
| 143 | logger.warn(`[${requestId}] Invalid Lemlist hook ID format, skipping deletion`, { |
| 144 | id: id.substring(0, 30), |
| 145 | }) |
| 146 | if (ctx.strict) throw new Error('Invalid Lemlist hook ID for deletion') |
| 147 | return |
| 148 | } |
| 149 | |
| 150 | const lemlistApiUrl = `https://api.lemlist.com/api/hooks/${id}` |
| 151 | const lemlistResponse = await fetch(lemlistApiUrl, { |
| 152 | method: 'DELETE', |
| 153 | headers: { |
| 154 | Authorization: `Basic ${authString}`, |
| 155 | }, |
| 156 | }) |
| 157 | |
| 158 | if (!lemlistResponse.ok && lemlistResponse.status !== 404) { |
| 159 | const responseBody = await lemlistResponse.json().catch(() => ({})) |
| 160 | logger.warn( |
| 161 | `[${requestId}] Failed to delete Lemlist webhook (non-fatal): ${lemlistResponse.status}`, |
| 162 | { response: responseBody } |
| 163 | ) |
| 164 | if (ctx.strict) { |
| 165 | throw new Error(`Failed to delete Lemlist webhook: ${lemlistResponse.status}`) |
| 166 | } |
| 167 | } else { |
| 168 | logger.info(`[${requestId}] Successfully deleted Lemlist webhook ${id}`) |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | if (externalId) { |
| 173 | await deleteById(externalId) |
| 174 | return |
| 175 | } |
| 176 | |
| 177 | if (ctx.strict) { |
| 178 | logger.warn( |
| 179 | `[${requestId}] Missing Lemlist externalId during strict cleanup; skipping unsafe URL-based remote deletion`, |
| 180 | { webhookId: webhook.id } |
nothing calls this directly
no test coverage detected