Repository navigation
Add --phone-offline-start-day to webhook create and update #82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import {Flags} from '@oclif/core' | ||
|
|
||
| export const PHONE_OFFLINE_EVENT = 'session.phone_offline' | ||
| const MIN_DAY = 7 | ||
| const MAX_DAY = 13 | ||
|
|
||
| /** A day from 7 to 13, or off to unsubscribe from the warning. */ | ||
| export type PhoneOfflineStartDay = number | 'off' | ||
|
|
||
| function parseStartDay(value: string): PhoneOfflineStartDay { | ||
| if (value === 'off') return 'off' | ||
| const day = Number(value) | ||
| if (!/^\d+$/.test(value) || day < MIN_DAY || day > MAX_DAY) { | ||
| throw new Error(`Expected a day from ${MIN_DAY} to ${MAX_DAY}, or off.`) | ||
| } | ||
| return day | ||
| } | ||
|
|
||
| export const phoneOfflineStartDayFlag = Flags.custom<PhoneOfflineStartDay>({ | ||
| description: `First day without the phone on which the webhook receives ${PHONE_OFFLINE_EVENT} (${MIN_DAY}-${MAX_DAY}), or off to remove that event. WhatsApp signs the device out on day 14.`, | ||
| parse: (value) => Promise.resolve(parseStartDay(value)), | ||
| })() | ||
|
|
||
| /** | ||
| * Merge the flag into a webhook body. A day sets phoneOfflineStartDay; off | ||
| * removes the event from eventTypes, read from the body or else the saved | ||
| * webhook. Platform webhooks need at least one event, so off cannot empty it. | ||
| */ | ||
| export function withPhoneOfflineStartDay( | ||
| body: Readonly<Record<string, unknown>>, | ||
| value: PhoneOfflineStartDay, | ||
| savedEventTypes?: readonly string[], | ||
| ): Record<string, unknown> { | ||
| if (value !== 'off') return {...body, phoneOfflineStartDay: value} | ||
| const eventTypes = Array.isArray(body.eventTypes) | ||
| ? (body.eventTypes as unknown[]).map(String) | ||
| : savedEventTypes | ||
| if (eventTypes === undefined) { | ||
| throw new Error('Add eventTypes to the input before using off.') | ||
| } | ||
| const remaining = eventTypes.filter((event) => event !== PHONE_OFFLINE_EVENT) | ||
| if (remaining.length === 0) { | ||
| throw new Error( | ||
| `A webhook needs at least one event besides ${PHONE_OFFLINE_EVENT}. Delete or disable the webhook instead.`, | ||
| ) | ||
| } | ||
| return {...body, eventTypes: remaining} | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,17 @@ export function renderEventDetail( | |
| return table(rows) | ||
| } | ||
|
|
||
| /** Off when the explicit event list leaves the warning out. */ | ||
| function phoneOfflineWarning(webhook: { | ||
| readonly eventTypes: readonly string[] | ||
| readonly phoneOfflineStartDay?: number | ||
| }): string { | ||
| if (!webhook.eventTypes.includes('session.phone_offline')) return 'off' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For a webhook subscribed through Useful? React with 👍 / 👎.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not changed, for the same reason: delivery has no wildcard matching, so a webhook subscribed only through session.* does not receive session.phone_offline and 'off' is the accurate display. |
||
| return webhook.phoneOfflineStartDay === undefined | ||
| ? 'not reported' | ||
| : `from day ${webhook.phoneOfflineStartDay}` | ||
| } | ||
|
|
||
| export function renderWebhookDetail(webhook: { | ||
| readonly id: string | ||
| readonly owner: string | ||
|
|
@@ -44,6 +55,7 @@ export function renderWebhookDetail(webhook: { | |
| readonly format: string | ||
| readonly eventTypes: readonly string[] | ||
| readonly headers: readonly {readonly name: string}[] | ||
| readonly phoneOfflineStartDay?: number | ||
| readonly createdAt: string | ||
| readonly updatedAt: string | ||
| }): string { | ||
|
|
@@ -55,6 +67,7 @@ export function renderWebhookDetail(webhook: { | |
| ['Enabled', webhook.enabled], | ||
| ['Format', webhook.format], | ||
| ['Event types', webhook.eventTypes.join(', ')], | ||
| ['Phone offline warning', phoneOfflineWarning(webhook)], | ||
| ['Header names', webhook.headers.map(({name}) => name).join(', ')], | ||
| ['Created', webhook.createdAt], | ||
| ['Updated', webhook.updatedAt], | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a webhook's
eventTypescontains the valid trailing-wildcard patternsession.*, filtering only the exactsession.phone_offlinestring leaves that subscription unchanged, so--phone-offline-start-day offsucceeds while the webhook continues receiving the warning event. Either rewrite wildcard subscriptions so they exclude this event or rejectoffwith an actionable error when exclusion cannot be represented.Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not changed. Delivery matches subscriptions by exact event type (matchesSubscription uses events.includes(event.type), apps/api/packages/api/src/services/webhook-delivery.ts:600), so a stored session.* entry matches no event and the webhook does not receive session.phone_offline through it. Filtering the exact name is the complete opt-out.