chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import { RevenueCatIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRevenueCatExtraFields,
|
||||
buildRevenueCatOutputs,
|
||||
revenueCatSetupInstructions,
|
||||
revenueCatTriggerOptions,
|
||||
} from '@/triggers/revenuecat/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* RevenueCat Cancellation Trigger. Fires on CANCELLATION events.
|
||||
*/
|
||||
export const revenueCatCancellationTrigger: TriggerConfig = {
|
||||
id: 'revenuecat_cancellation',
|
||||
name: 'RevenueCat Cancellation',
|
||||
provider: 'revenuecat',
|
||||
description: 'Trigger workflow when a subscriber cancels a RevenueCat subscription',
|
||||
version: '1.0.0',
|
||||
icon: RevenueCatIcon,
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'revenuecat_cancellation',
|
||||
triggerOptions: revenueCatTriggerOptions,
|
||||
setupInstructions: revenueCatSetupInstructions('Cancellation'),
|
||||
extraFields: buildRevenueCatExtraFields('revenuecat_cancellation'),
|
||||
}),
|
||||
outputs: buildRevenueCatOutputs(),
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'your-configured-secret',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { RevenueCatIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRevenueCatExtraFields,
|
||||
buildRevenueCatOutputs,
|
||||
revenueCatSetupInstructions,
|
||||
revenueCatTriggerOptions,
|
||||
} from '@/triggers/revenuecat/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* RevenueCat Expiration Trigger. Fires on EXPIRATION events.
|
||||
*/
|
||||
export const revenueCatExpirationTrigger: TriggerConfig = {
|
||||
id: 'revenuecat_expiration',
|
||||
name: 'RevenueCat Expiration',
|
||||
provider: 'revenuecat',
|
||||
description: 'Trigger workflow when a RevenueCat subscription expires',
|
||||
version: '1.0.0',
|
||||
icon: RevenueCatIcon,
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'revenuecat_expiration',
|
||||
triggerOptions: revenueCatTriggerOptions,
|
||||
setupInstructions: revenueCatSetupInstructions('Expiration'),
|
||||
extraFields: buildRevenueCatExtraFields('revenuecat_expiration'),
|
||||
}),
|
||||
outputs: buildRevenueCatOutputs(),
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'your-configured-secret',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export { revenueCatCancellationTrigger } from './cancellation'
|
||||
export { revenueCatExpirationTrigger } from './expiration'
|
||||
export { revenueCatInitialPurchaseTrigger } from './initial_purchase'
|
||||
export { revenueCatNonRenewingPurchaseTrigger } from './non_renewing_purchase'
|
||||
export { revenueCatProductChangeTrigger } from './product_change'
|
||||
export { revenueCatRenewalTrigger } from './renewal'
|
||||
@@ -0,0 +1,39 @@
|
||||
import { RevenueCatIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRevenueCatExtraFields,
|
||||
buildRevenueCatOutputs,
|
||||
revenueCatSetupInstructions,
|
||||
revenueCatTriggerOptions,
|
||||
} from '@/triggers/revenuecat/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* RevenueCat Initial Purchase Trigger.
|
||||
*
|
||||
* PRIMARY trigger — includes the trigger-type dropdown listing every RevenueCat event.
|
||||
* Fires on INITIAL_PURCHASE events.
|
||||
*/
|
||||
export const revenueCatInitialPurchaseTrigger: TriggerConfig = {
|
||||
id: 'revenuecat_initial_purchase',
|
||||
name: 'RevenueCat Initial Purchase',
|
||||
provider: 'revenuecat',
|
||||
description: 'Trigger workflow when a subscriber makes their first purchase in RevenueCat',
|
||||
version: '1.0.0',
|
||||
icon: RevenueCatIcon,
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'revenuecat_initial_purchase',
|
||||
triggerOptions: revenueCatTriggerOptions,
|
||||
includeDropdown: true,
|
||||
setupInstructions: revenueCatSetupInstructions('Initial Purchase'),
|
||||
extraFields: buildRevenueCatExtraFields('revenuecat_initial_purchase'),
|
||||
}),
|
||||
outputs: buildRevenueCatOutputs(),
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'your-configured-secret',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { RevenueCatIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRevenueCatExtraFields,
|
||||
buildRevenueCatOutputs,
|
||||
revenueCatSetupInstructions,
|
||||
revenueCatTriggerOptions,
|
||||
} from '@/triggers/revenuecat/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* RevenueCat Non-Renewing Purchase Trigger. Fires on NON_RENEWING_PURCHASE events.
|
||||
*/
|
||||
export const revenueCatNonRenewingPurchaseTrigger: TriggerConfig = {
|
||||
id: 'revenuecat_non_renewing_purchase',
|
||||
name: 'RevenueCat Non-Renewing Purchase',
|
||||
provider: 'revenuecat',
|
||||
description: 'Trigger workflow when a subscriber makes a non-renewing purchase in RevenueCat',
|
||||
version: '1.0.0',
|
||||
icon: RevenueCatIcon,
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'revenuecat_non_renewing_purchase',
|
||||
triggerOptions: revenueCatTriggerOptions,
|
||||
setupInstructions: revenueCatSetupInstructions('Non-Renewing Purchase'),
|
||||
extraFields: buildRevenueCatExtraFields('revenuecat_non_renewing_purchase'),
|
||||
}),
|
||||
outputs: buildRevenueCatOutputs(),
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'your-configured-secret',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { RevenueCatIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRevenueCatExtraFields,
|
||||
buildRevenueCatOutputs,
|
||||
revenueCatSetupInstructions,
|
||||
revenueCatTriggerOptions,
|
||||
} from '@/triggers/revenuecat/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* RevenueCat Product Change Trigger. Fires on PRODUCT_CHANGE events.
|
||||
*/
|
||||
export const revenueCatProductChangeTrigger: TriggerConfig = {
|
||||
id: 'revenuecat_product_change',
|
||||
name: 'RevenueCat Product Change',
|
||||
provider: 'revenuecat',
|
||||
description: 'Trigger workflow when a subscriber changes their RevenueCat subscription product',
|
||||
version: '1.0.0',
|
||||
icon: RevenueCatIcon,
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'revenuecat_product_change',
|
||||
triggerOptions: revenueCatTriggerOptions,
|
||||
setupInstructions: revenueCatSetupInstructions('Product Change'),
|
||||
extraFields: buildRevenueCatExtraFields('revenuecat_product_change'),
|
||||
}),
|
||||
outputs: buildRevenueCatOutputs(),
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'your-configured-secret',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { RevenueCatIcon } from '@/components/icons'
|
||||
import { buildTriggerSubBlocks } from '@/triggers'
|
||||
import {
|
||||
buildRevenueCatExtraFields,
|
||||
buildRevenueCatOutputs,
|
||||
revenueCatSetupInstructions,
|
||||
revenueCatTriggerOptions,
|
||||
} from '@/triggers/revenuecat/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* RevenueCat Renewal Trigger. Fires on RENEWAL events.
|
||||
*/
|
||||
export const revenueCatRenewalTrigger: TriggerConfig = {
|
||||
id: 'revenuecat_renewal',
|
||||
name: 'RevenueCat Renewal',
|
||||
provider: 'revenuecat',
|
||||
description: 'Trigger workflow when a RevenueCat subscription renews',
|
||||
version: '1.0.0',
|
||||
icon: RevenueCatIcon,
|
||||
subBlocks: buildTriggerSubBlocks({
|
||||
triggerId: 'revenuecat_renewal',
|
||||
triggerOptions: revenueCatTriggerOptions,
|
||||
setupInstructions: revenueCatSetupInstructions('Renewal'),
|
||||
extraFields: buildRevenueCatExtraFields('revenuecat_renewal'),
|
||||
}),
|
||||
outputs: buildRevenueCatOutputs(),
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'your-configured-secret',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
import type { SubBlockConfig } from '@/blocks/types'
|
||||
import type { TriggerOutput } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Shared trigger dropdown options for all RevenueCat triggers.
|
||||
* All RevenueCat events POST to the same webhook endpoint; the active trigger is
|
||||
* differentiated by `event.type` at match time.
|
||||
*/
|
||||
export const revenueCatTriggerOptions = [
|
||||
{ label: 'Initial Purchase', id: 'revenuecat_initial_purchase' },
|
||||
{ label: 'Renewal', id: 'revenuecat_renewal' },
|
||||
{ label: 'Cancellation', id: 'revenuecat_cancellation' },
|
||||
{ label: 'Expiration', id: 'revenuecat_expiration' },
|
||||
{ label: 'Non-Renewing Purchase', id: 'revenuecat_non_renewing_purchase' },
|
||||
{ label: 'Product Change', id: 'revenuecat_product_change' },
|
||||
]
|
||||
|
||||
/**
|
||||
* Maps each RevenueCat trigger ID to the exact uppercase `event.type` string
|
||||
* RevenueCat sends in the webhook payload.
|
||||
*/
|
||||
export const REVENUECAT_TRIGGER_TO_EVENT_TYPE: Record<string, string> = {
|
||||
revenuecat_initial_purchase: 'INITIAL_PURCHASE',
|
||||
revenuecat_renewal: 'RENEWAL',
|
||||
revenuecat_cancellation: 'CANCELLATION',
|
||||
revenuecat_expiration: 'EXPIRATION',
|
||||
revenuecat_non_renewing_purchase: 'NON_RENEWING_PURCHASE',
|
||||
revenuecat_product_change: 'PRODUCT_CHANGE',
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps each RevenueCat trigger ID to the lowercase `WebhookEventType` enum value
|
||||
* the REST API v2 expects when creating a webhook integration.
|
||||
*
|
||||
* @see https://www.revenuecat.com/docs/api-v2 (Integration > Create a webhook integration)
|
||||
*/
|
||||
export const REVENUECAT_TRIGGER_TO_API_EVENT_TYPE: Record<string, string> = {
|
||||
revenuecat_initial_purchase: 'initial_purchase',
|
||||
revenuecat_renewal: 'renewal',
|
||||
revenuecat_cancellation: 'cancellation',
|
||||
revenuecat_expiration: 'expiration',
|
||||
revenuecat_non_renewing_purchase: 'non_renewing_purchase',
|
||||
revenuecat_product_change: 'product_change',
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate setup instructions for a specific RevenueCat event type.
|
||||
*
|
||||
* Sim creates and tears down the webhook integration automatically through the
|
||||
* RevenueCat REST API v2, so the user only supplies a Secret API key and the
|
||||
* project ID — no manual dashboard webhook configuration is required.
|
||||
*/
|
||||
export function revenueCatSetupInstructions(eventLabel: string): string {
|
||||
const instructions = [
|
||||
'In the RevenueCat dashboard, go to <strong>Project settings > API keys</strong> and create a <strong>v2 Secret API key</strong> with the <code>project_configuration:integrations:read_write</code> permission.',
|
||||
'Paste the Secret API key into the <strong>API Key</strong> field below.',
|
||||
'Enter your <strong>Project ID</strong> (the <code>proj...</code> identifier shown in your project settings or the dashboard URL) in the <strong>Project ID</strong> field below.',
|
||||
'Optionally restrict the trigger to a single <strong>Environment</strong> (Production or Sandbox). Leave it on <strong>All</strong> to receive both.',
|
||||
`Sim creates the webhook integration in RevenueCat automatically when you deploy and removes it when you undeploy. This trigger fires on <strong>${eventLabel}</strong> events.`,
|
||||
'Sim generates the Authorization header secret for you and verifies every incoming request against it — you do not need to set it manually.',
|
||||
'Click "Save" above to deploy and activate your trigger.',
|
||||
]
|
||||
return instructions
|
||||
.map(
|
||||
(instruction, index) =>
|
||||
`<div class="mb-3"><strong>${index + 1}.</strong> ${instruction}</div>`
|
||||
)
|
||||
.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra trigger fields shared by all RevenueCat triggers.
|
||||
*
|
||||
* `apiKey` (a RevenueCat v2 Secret API key) and `projectId` let Sim create and
|
||||
* delete the webhook integration through the REST API v2 during deploy/undeploy.
|
||||
* `environment` optionally scopes the integration to production or sandbox.
|
||||
* The Authorization header secret is generated by Sim during registration and
|
||||
* stored in `providerConfig.authHeaderSecret`; the provider handler verifies
|
||||
* every incoming `Authorization` header against it.
|
||||
*/
|
||||
export function buildRevenueCatExtraFields(triggerId: string): SubBlockConfig[] {
|
||||
const condition = { field: 'selectedTriggerId', value: triggerId }
|
||||
return [
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
type: 'short-input',
|
||||
password: true,
|
||||
paramVisibility: 'user-only',
|
||||
placeholder: 'RevenueCat v2 Secret API key (sk_...)',
|
||||
description:
|
||||
'Secret API key with the project_configuration:integrations:read_write permission. Sim uses it to create and remove the webhook in RevenueCat.',
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition,
|
||||
},
|
||||
{
|
||||
id: 'projectId',
|
||||
title: 'Project ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'proj1ab2c3d4',
|
||||
description: 'RevenueCat project identifier the webhook integration is created in.',
|
||||
required: true,
|
||||
mode: 'trigger',
|
||||
condition,
|
||||
},
|
||||
{
|
||||
id: 'environment',
|
||||
title: 'Environment',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'All', id: 'all' },
|
||||
{ label: 'Production', id: 'production' },
|
||||
{ label: 'Sandbox', id: 'sandbox' },
|
||||
],
|
||||
value: () => 'all',
|
||||
description: 'Restrict events to a single environment, or receive all of them.',
|
||||
mode: 'trigger',
|
||||
condition,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the output schema for RevenueCat events.
|
||||
*
|
||||
* Fields are flattened from the `event` object of the webhook payload
|
||||
* (RevenueCat wraps the event under `event` and the wrapper carries `api_version`).
|
||||
* Event-specific fields (`new_product_id`, `cancel_reason`, `expiration_reason`) are
|
||||
* present for all triggers and are `null` when not applicable to the received event type.
|
||||
*
|
||||
* @see https://www.revenuecat.com/docs/integrations/webhooks/event-types-and-fields
|
||||
*/
|
||||
export function buildRevenueCatOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
type: { type: 'string', description: 'Event type (e.g., INITIAL_PURCHASE, RENEWAL)' },
|
||||
id: { type: 'string', description: 'Unique event identifier' },
|
||||
app_id: { type: 'string', description: 'RevenueCat app public identifier' },
|
||||
event_timestamp_ms: {
|
||||
type: 'number',
|
||||
description: 'Timestamp (ms since epoch) when the event was generated',
|
||||
},
|
||||
app_user_id: { type: 'string', description: 'Current App User ID' },
|
||||
original_app_user_id: { type: 'string', description: 'First App User ID ever used' },
|
||||
aliases: { type: 'json', description: 'All App User IDs ever used by the subscriber' },
|
||||
product_id: { type: 'string', description: 'Product identifier' },
|
||||
new_product_id: {
|
||||
type: 'string',
|
||||
description: 'Product identifier changed to (PRODUCT_CHANGE events only)',
|
||||
},
|
||||
period_type: {
|
||||
type: 'string',
|
||||
description: 'Period type (TRIAL, INTRO, NORMAL, PROMOTIONAL, or PREPAID)',
|
||||
},
|
||||
purchased_at_ms: { type: 'number', description: 'Purchase timestamp (ms since epoch)' },
|
||||
expiration_at_ms: {
|
||||
type: 'number',
|
||||
description: 'Expiration timestamp (ms since epoch), nullable',
|
||||
},
|
||||
environment: { type: 'string', description: 'Environment (SANDBOX or PRODUCTION)' },
|
||||
entitlement_id: { type: 'string', description: 'Deprecated single entitlement identifier' },
|
||||
entitlement_ids: { type: 'json', description: 'Associated entitlement identifiers' },
|
||||
presented_offering_id: {
|
||||
type: 'string',
|
||||
description: 'Identifier of the offering presented to the user',
|
||||
},
|
||||
transaction_id: { type: 'string', description: 'Store transaction ID' },
|
||||
original_transaction_id: {
|
||||
type: 'string',
|
||||
description: 'Original subscription transaction ID',
|
||||
},
|
||||
is_family_share: { type: 'boolean', description: 'Whether the purchase was family shared' },
|
||||
country_code: { type: 'string', description: 'ISO country code of the subscriber' },
|
||||
currency: { type: 'string', description: 'ISO 4217 currency code' },
|
||||
price: { type: 'number', description: 'Price in USD' },
|
||||
price_in_purchased_currency: {
|
||||
type: 'number',
|
||||
description: 'Price in the currency the purchase was made in',
|
||||
},
|
||||
store: { type: 'string', description: 'Store the purchase was made on (e.g., APP_STORE)' },
|
||||
takehome_percentage: {
|
||||
type: 'number',
|
||||
description: 'Estimated percentage of the price taken home after store commission',
|
||||
},
|
||||
tax_percentage: { type: 'number', description: 'Estimated percentage taken as tax' },
|
||||
commission_percentage: {
|
||||
type: 'number',
|
||||
description: 'Estimated percentage taken by the store as commission',
|
||||
},
|
||||
offer_code: { type: 'string', description: 'Offer code applied to the purchase, if any' },
|
||||
subscriber_attributes: {
|
||||
type: 'json',
|
||||
description: 'Subscriber attributes at the time of the event',
|
||||
},
|
||||
experiments: { type: 'json', description: 'Experiments the subscriber was enrolled in' },
|
||||
cancel_reason: {
|
||||
type: 'string',
|
||||
description: 'Reason for cancellation (CANCELLATION events only)',
|
||||
},
|
||||
expiration_reason: {
|
||||
type: 'string',
|
||||
description: 'Reason for expiration (EXPIRATION events only)',
|
||||
},
|
||||
api_version: { type: 'string', description: 'RevenueCat webhook API version' },
|
||||
event: { type: 'json', description: 'Full RevenueCat event object' },
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an incoming RevenueCat event matches the configured trigger.
|
||||
* Returns true for unknown trigger IDs so unexpected configs fall through rather than drop.
|
||||
*/
|
||||
export function isRevenueCatEventMatch(triggerId: string, body: Record<string, unknown>): boolean {
|
||||
const expectedType = REVENUECAT_TRIGGER_TO_EVENT_TYPE[triggerId]
|
||||
if (!expectedType) {
|
||||
return true
|
||||
}
|
||||
const event = body.event as Record<string, unknown> | undefined
|
||||
const actualType = event?.type as string | undefined
|
||||
return actualType === expectedType
|
||||
}
|
||||
Reference in New Issue
Block a user