@rawdash/connector-stripe 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -47,7 +47,7 @@ const stripe = new StripeConnector(
47
47
  Or using `StripeConnector.create` (validates via `configFields` Zod schema):
48
48
 
49
49
  ```ts
50
- const { connector: stripe } = StripeConnector.create({
50
+ const stripe = StripeConnector.create({
51
51
  apiKey: { $secret: 'STRIPE_API_KEY' },
52
52
  // accountId: 'acct_…',
53
53
  // resources: ['customers', 'subscriptions', 'invoices'],
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { BaseConnector, SyncOptions, StorageHandle, SyncResult } from '@rawdash/core';
1
+ import { BaseConnector, ConnectorContext, SyncOptions, StorageHandle, SyncResult } from '@rawdash/core';
2
2
  import { z } from 'zod';
3
3
 
4
4
  declare const configFields: z.ZodObject<{
@@ -67,9 +67,7 @@ type StripeResource = StripePhase;
67
67
  declare function computeMrrAmountCents(subscription: StripeSubscription): number | null;
68
68
  declare class StripeConnector extends BaseConnector<StripeSettings, StripeCredentials> {
69
69
  static readonly id = "stripe";
70
- static create(input: unknown): {
71
- connector: StripeConnector;
72
- };
70
+ static create(input: unknown, ctx?: ConnectorContext): StripeConnector;
73
71
  readonly id = "stripe";
74
72
  readonly credentials: {
75
73
  apiKey: {
package/dist/index.js CHANGED
@@ -123,14 +123,13 @@ function computeMrrAmountCents(subscription) {
123
123
  }
124
124
  var StripeConnector = class _StripeConnector extends BaseConnector {
125
125
  static id = "stripe";
126
- static create(input) {
126
+ static create(input, ctx) {
127
127
  const parsed = configFields.parse(input);
128
- return {
129
- connector: new _StripeConnector(
130
- { accountId: parsed.accountId, resources: parsed.resources },
131
- { apiKey: parsed.apiKey }
132
- )
133
- };
128
+ return new _StripeConnector(
129
+ { accountId: parsed.accountId, resources: parsed.resources },
130
+ { apiKey: parsed.apiKey },
131
+ ctx
132
+ );
134
133
  }
135
134
  id = "stripe";
136
135
  credentials = stripeCredentials;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stripe.ts"],"sourcesContent":["import type { HttpResponse } from '@rawdash/connector-shared';\nimport {\n BaseConnector,\n type ChunkedSyncCursor,\n type CredentialsSchema,\n type StorageHandle,\n type SyncOptions,\n type SyncResult,\n defineConfigFields,\n paginateChunked,\n} from '@rawdash/core';\nimport { z } from 'zod';\n\nexport const configFields = defineConfigFields(\n z.object({\n apiKey: z.object({ $secret: z.string() }).meta({\n label: 'API Key',\n description:\n 'Stripe Restricted API key with read-only access. Create one at Dashboard → Developers → API keys.',\n placeholder: 'rk_live_...',\n secret: true,\n }),\n accountId: z.string().optional().meta({\n label: 'Account ID (optional)',\n description:\n 'Stripe Connect account ID. Only needed if you are a platform accessing a connected account.',\n placeholder: 'acct_...',\n }),\n resources: z\n .array(\n z.enum([\n 'customers',\n 'products',\n 'prices',\n 'subscriptions',\n 'invoices',\n 'charges',\n 'payment_intents',\n 'disputes',\n 'refunds',\n ]),\n )\n .nonempty()\n .optional()\n .meta({\n label: 'Resources',\n description:\n 'Which Stripe resources to sync. Omit to sync all resources. The API key only needs Read scope for the resources listed here.',\n }),\n }),\n);\n\nexport interface StripeSettings {\n accountId?: string;\n resources?: readonly StripeResource[];\n}\n\n// ---------------------------------------------------------------------------\n// Stripe API types\n// ---------------------------------------------------------------------------\n\ninterface StripeListResponse<T> {\n object: 'list';\n data: T[];\n has_more: boolean;\n url: string;\n}\n\ninterface StripeCustomer {\n id: string;\n email: string | null;\n name: string | null;\n created: number;\n currency: string | null;\n delinquent: boolean | null;\n livemode: boolean;\n}\n\ninterface StripePriceRecurring {\n interval: 'day' | 'week' | 'month' | 'year';\n interval_count: number;\n}\n\ninterface StripePrice {\n id: string;\n product: string;\n unit_amount: number | null;\n currency: string;\n recurring: StripePriceRecurring | null;\n active: boolean;\n created: number;\n}\n\ninterface StripeSubscriptionItem {\n price: StripePrice;\n quantity: number | null;\n}\n\ninterface StripeSubscription {\n id: string;\n customer: string;\n status: string;\n items: { data: StripeSubscriptionItem[] };\n current_period_start: number;\n current_period_end: number;\n cancel_at_period_end: boolean;\n canceled_at: number | null;\n trial_end: number | null;\n currency: string;\n created: number;\n}\n\ninterface StripeInvoice {\n id: string;\n customer: string | null;\n subscription: string | null;\n status: string | null;\n amount_due: number;\n amount_paid: number;\n currency: string;\n created: number;\n due_date: number | null;\n hosted_invoice_url: string | null;\n}\n\ninterface StripeCharge {\n id: string;\n customer: string | null;\n amount: number;\n currency: string;\n status: string;\n failure_code: string | null;\n created: number;\n payment_intent: string | null;\n}\n\ninterface StripePaymentIntent {\n id: string;\n customer: string | null;\n amount: number;\n currency: string;\n status: string;\n created: number;\n}\n\ninterface StripeProduct {\n id: string;\n name: string;\n active: boolean;\n created: number;\n}\n\ninterface StripeDispute {\n id: string;\n charge: string;\n amount: number;\n currency: string;\n reason: string;\n status: string;\n created: number;\n}\n\ninterface StripeRefund {\n id: string;\n charge: string | null;\n amount: number;\n currency: string;\n reason: string | null;\n status: string | null;\n created: number;\n}\n\n// ---------------------------------------------------------------------------\n// Credentials\n// ---------------------------------------------------------------------------\n\nconst stripeCredentials = {\n apiKey: {\n description: 'Stripe API key',\n auth: 'required' as const,\n },\n} satisfies CredentialsSchema;\n\ntype StripeCredentials = typeof stripeCredentials;\n\n// ---------------------------------------------------------------------------\n// Sync phases + cursor\n// ---------------------------------------------------------------------------\n\nconst PHASE_ORDER = [\n 'customers',\n 'products',\n 'prices',\n 'subscriptions',\n 'invoices',\n 'charges',\n 'payment_intents',\n 'disputes',\n 'refunds',\n] as const;\n\ntype StripePhase = (typeof PHASE_ORDER)[number];\n\nexport type StripeResource = StripePhase;\n\ntype StripeSyncCursor = ChunkedSyncCursor<StripePhase, string>;\n\nfunction isStripeSyncCursor(value: unknown): value is StripeSyncCursor {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n const v = value as { phase?: unknown; page?: unknown };\n if (typeof v.phase !== 'string') {\n return false;\n }\n if (!(PHASE_ORDER as readonly string[]).includes(v.phase)) {\n return false;\n }\n if (v.page !== null && typeof v.page !== 'string') {\n return false;\n }\n return true;\n}\n\nconst ENTITY_TYPE_BY_PHASE: Partial<Record<StripePhase, string>> = {\n customers: 'stripe_customer',\n products: 'stripe_product',\n prices: 'stripe_price',\n subscriptions: 'stripe_subscription',\n invoices: 'stripe_invoice',\n};\n\nconst EVENT_NAME_BY_PHASE: Partial<Record<StripePhase, string>> = {\n charges: 'stripe_charge',\n payment_intents: 'stripe_payment_intent',\n disputes: 'stripe_dispute',\n refunds: 'stripe_refund',\n};\n\n// ---------------------------------------------------------------------------\n// MRR helper\n// ---------------------------------------------------------------------------\n\nexport function computeMrrAmountCents(\n subscription: StripeSubscription,\n): number | null {\n let sum = 0;\n let counted = 0;\n for (const item of subscription.items.data) {\n const { unit_amount, recurring } = item.price;\n if (unit_amount === null || unit_amount === undefined || !recurring) {\n continue;\n }\n const quantity = item.quantity ?? 1;\n const total = unit_amount * quantity;\n const intervalCount = recurring.interval_count || 1;\n let monthly: number | null;\n switch (recurring.interval) {\n case 'month':\n monthly = total / intervalCount;\n break;\n case 'year':\n monthly = total / (12 * intervalCount);\n break;\n case 'week':\n monthly = (total * 52) / (12 * intervalCount);\n break;\n case 'day':\n monthly = (total * 365) / (12 * intervalCount);\n break;\n default:\n monthly = null;\n }\n if (monthly === null) {\n continue;\n }\n sum += monthly;\n counted++;\n }\n if (counted === 0) {\n return null;\n }\n return Math.round(sum);\n}\n\n// ---------------------------------------------------------------------------\n// StripeConnector\n// ---------------------------------------------------------------------------\n\nexport class StripeConnector extends BaseConnector<\n StripeSettings,\n StripeCredentials\n> {\n static readonly id = 'stripe';\n\n static create(input: unknown): { connector: StripeConnector } {\n const parsed = configFields.parse(input);\n return {\n connector: new StripeConnector(\n { accountId: parsed.accountId, resources: parsed.resources },\n { apiKey: parsed.apiKey },\n ),\n };\n }\n\n readonly id = 'stripe';\n override readonly credentials = stripeCredentials;\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.creds.apiKey}`,\n 'Stripe-Version': '2024-06-20',\n 'User-Agent': 'rawdash/connector-stripe (+https://rawdash.dev)',\n };\n if (this.settings.accountId) {\n headers['Stripe-Account'] = this.settings.accountId;\n }\n return headers;\n }\n\n private fetch<T>(\n url: string,\n resource: string,\n signal?: AbortSignal,\n ): Promise<HttpResponse<T>> {\n return this.get<T>(url, {\n resource,\n headers: this.buildHeaders(),\n signal,\n });\n }\n\n private buildListUrl(\n path: string,\n params: Record<string, string | undefined>,\n ): string {\n const url = new URL(`https://api.stripe.com/v1/${path}`);\n url.searchParams.set('limit', '100');\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, value);\n }\n }\n return url.toString();\n }\n\n // created[gte] cutoff for entity phases in incremental mode (7-day lookback)\n private entityCreatedGte(options: SyncOptions): string | undefined {\n if (options.mode !== 'latest' || !options.since) {\n return undefined;\n }\n const sinceMs = new Date(options.since).getTime();\n return String(Math.floor((sinceMs - 7 * 24 * 60 * 60 * 1000) / 1000));\n }\n\n // created[gt] cutoff for event phases in incremental mode\n private eventCreatedGt(options: SyncOptions): string | undefined {\n if (options.mode !== 'latest' || !options.since) {\n return undefined;\n }\n return String(Math.floor(new Date(options.since).getTime() / 1000));\n }\n\n private buildPhaseUrl(\n phase: StripePhase,\n page: string | null,\n options: SyncOptions,\n ): string {\n const startingAfter = page ?? undefined;\n if (phase in ENTITY_TYPE_BY_PHASE) {\n const extra: Record<string, string | undefined> =\n phase === 'subscriptions' ? { status: 'all' } : {};\n return this.buildListUrl(phase, {\n ...extra,\n starting_after: startingAfter,\n 'created[gte]': this.entityCreatedGte(options),\n });\n }\n return this.buildListUrl(phase, {\n starting_after: startingAfter,\n 'created[gt]': this.eventCreatedGt(options),\n });\n }\n\n private async clearScopeOnFirstPage(\n storage: StorageHandle,\n phase: StripePhase,\n ): Promise<void> {\n const entityType = ENTITY_TYPE_BY_PHASE[phase];\n if (entityType) {\n await storage.entities([], { types: [entityType] });\n return;\n }\n const eventName = EVENT_NAME_BY_PHASE[phase];\n if (eventName) {\n await storage.events([], { names: [eventName] });\n }\n }\n\n private async writePhase(\n storage: StorageHandle,\n phase: StripePhase,\n items: unknown[],\n ): Promise<void> {\n switch (phase) {\n case 'customers':\n for (const c of items as StripeCustomer[]) {\n await storage.entity({\n type: 'stripe_customer',\n id: c.id,\n attributes: {\n email: c.email ?? null,\n name: c.name ?? null,\n created: c.created,\n currency: c.currency ?? null,\n delinquent: c.delinquent ?? false,\n livemode: c.livemode,\n },\n updated_at: c.created * 1000,\n });\n }\n return;\n case 'products':\n for (const p of items as StripeProduct[]) {\n await storage.entity({\n type: 'stripe_product',\n id: p.id,\n attributes: { name: p.name, active: p.active, created: p.created },\n updated_at: p.created * 1000,\n });\n }\n return;\n case 'prices':\n for (const p of items as StripePrice[]) {\n await storage.entity({\n type: 'stripe_price',\n id: p.id,\n attributes: {\n productId: p.product,\n unitAmount: p.unit_amount ?? null,\n currency: p.currency,\n interval: p.recurring?.interval ?? null,\n intervalCount: p.recurring?.interval_count ?? null,\n active: p.active,\n created: p.created,\n },\n updated_at: p.created * 1000,\n });\n }\n return;\n case 'subscriptions':\n for (const s of items as StripeSubscription[]) {\n await storage.entity({\n type: 'stripe_subscription',\n id: s.id,\n attributes: {\n customerId: s.customer,\n status: s.status,\n planId: s.items.data[0]?.price.id ?? null,\n currentPeriodStart: s.current_period_start,\n currentPeriodEnd: s.current_period_end,\n cancelAtPeriodEnd: s.cancel_at_period_end,\n canceledAt: s.canceled_at ?? null,\n trialEnd: s.trial_end ?? null,\n mrrAmount: computeMrrAmountCents(s),\n currency: s.currency,\n created: s.created,\n },\n updated_at: s.current_period_end * 1000,\n });\n }\n return;\n case 'invoices':\n for (const inv of items as StripeInvoice[]) {\n await storage.entity({\n type: 'stripe_invoice',\n id: inv.id,\n attributes: {\n customerId: inv.customer ?? null,\n subscriptionId: inv.subscription ?? null,\n status: inv.status ?? null,\n amountDue: inv.amount_due,\n amountPaid: inv.amount_paid,\n currency: inv.currency,\n created: inv.created,\n dueDate: inv.due_date ?? null,\n hostedInvoiceUrl: inv.hosted_invoice_url ?? null,\n },\n updated_at: inv.created * 1000,\n });\n }\n return;\n case 'charges':\n for (const c of items as StripeCharge[]) {\n await storage.event({\n name: 'stripe_charge',\n start_ts: c.created * 1000,\n end_ts: null,\n attributes: {\n id: c.id,\n customerId: c.customer ?? null,\n amount: c.amount,\n currency: c.currency,\n status: c.status,\n failureCode: c.failure_code ?? null,\n paymentIntentId: c.payment_intent ?? null,\n },\n });\n }\n return;\n case 'payment_intents':\n for (const pi of items as StripePaymentIntent[]) {\n await storage.event({\n name: 'stripe_payment_intent',\n start_ts: pi.created * 1000,\n end_ts: null,\n attributes: {\n id: pi.id,\n customerId: pi.customer ?? null,\n amount: pi.amount,\n currency: pi.currency,\n status: pi.status,\n },\n });\n }\n return;\n case 'disputes':\n for (const d of items as StripeDispute[]) {\n await storage.event({\n name: 'stripe_dispute',\n start_ts: d.created * 1000,\n end_ts: null,\n attributes: {\n id: d.id,\n chargeId: d.charge,\n amount: d.amount,\n currency: d.currency,\n reason: d.reason,\n status: d.status,\n },\n });\n }\n return;\n case 'refunds':\n for (const r of items as StripeRefund[]) {\n await storage.event({\n name: 'stripe_refund',\n start_ts: r.created * 1000,\n end_ts: null,\n attributes: {\n id: r.id,\n chargeId: r.charge ?? null,\n amount: r.amount,\n currency: r.currency,\n reason: r.reason ?? null,\n status: r.status ?? null,\n },\n });\n }\n return;\n }\n }\n\n async sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult> {\n const cursor = isStripeSyncCursor(options.cursor)\n ? options.cursor\n : undefined;\n const isFull = options.mode === 'full';\n\n const enabled = this.settings.resources;\n const phases =\n enabled && enabled.length > 0\n ? PHASE_ORDER.filter((p) => enabled.includes(p))\n : PHASE_ORDER;\n\n return paginateChunked<StripePhase, string>({\n phases,\n cursor,\n signal,\n fetchPage: async (phase, page, sig) => {\n const url = this.buildPhaseUrl(phase, page, options);\n const res = await this.fetch<StripeListResponse<{ id: string }>>(\n url,\n phase,\n sig,\n );\n const { data, has_more } = res.body;\n const next = has_more && data.length > 0 ? data.at(-1)!.id : null;\n return { items: data, next };\n },\n writeBatch: async (phase, items, page) => {\n if (isFull && page === null) {\n await this.clearScopeOnFirstPage(storage, phase);\n }\n await this.writePhase(storage, phase, items);\n },\n });\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/stripe.ts"],"sourcesContent":["import type { HttpResponse } from '@rawdash/connector-shared';\nimport {\n BaseConnector,\n type ChunkedSyncCursor,\n type ConnectorContext,\n type CredentialsSchema,\n type StorageHandle,\n type SyncOptions,\n type SyncResult,\n defineConfigFields,\n paginateChunked,\n} from '@rawdash/core';\nimport { z } from 'zod';\n\nexport const configFields = defineConfigFields(\n z.object({\n apiKey: z.object({ $secret: z.string() }).meta({\n label: 'API Key',\n description:\n 'Stripe Restricted API key with read-only access. Create one at Dashboard → Developers → API keys.',\n placeholder: 'rk_live_...',\n secret: true,\n }),\n accountId: z.string().optional().meta({\n label: 'Account ID (optional)',\n description:\n 'Stripe Connect account ID. Only needed if you are a platform accessing a connected account.',\n placeholder: 'acct_...',\n }),\n resources: z\n .array(\n z.enum([\n 'customers',\n 'products',\n 'prices',\n 'subscriptions',\n 'invoices',\n 'charges',\n 'payment_intents',\n 'disputes',\n 'refunds',\n ]),\n )\n .nonempty()\n .optional()\n .meta({\n label: 'Resources',\n description:\n 'Which Stripe resources to sync. Omit to sync all resources. The API key only needs Read scope for the resources listed here.',\n }),\n }),\n);\n\nexport interface StripeSettings {\n accountId?: string;\n resources?: readonly StripeResource[];\n}\n\n// ---------------------------------------------------------------------------\n// Stripe API types\n// ---------------------------------------------------------------------------\n\ninterface StripeListResponse<T> {\n object: 'list';\n data: T[];\n has_more: boolean;\n url: string;\n}\n\ninterface StripeCustomer {\n id: string;\n email: string | null;\n name: string | null;\n created: number;\n currency: string | null;\n delinquent: boolean | null;\n livemode: boolean;\n}\n\ninterface StripePriceRecurring {\n interval: 'day' | 'week' | 'month' | 'year';\n interval_count: number;\n}\n\ninterface StripePrice {\n id: string;\n product: string;\n unit_amount: number | null;\n currency: string;\n recurring: StripePriceRecurring | null;\n active: boolean;\n created: number;\n}\n\ninterface StripeSubscriptionItem {\n price: StripePrice;\n quantity: number | null;\n}\n\ninterface StripeSubscription {\n id: string;\n customer: string;\n status: string;\n items: { data: StripeSubscriptionItem[] };\n current_period_start: number;\n current_period_end: number;\n cancel_at_period_end: boolean;\n canceled_at: number | null;\n trial_end: number | null;\n currency: string;\n created: number;\n}\n\ninterface StripeInvoice {\n id: string;\n customer: string | null;\n subscription: string | null;\n status: string | null;\n amount_due: number;\n amount_paid: number;\n currency: string;\n created: number;\n due_date: number | null;\n hosted_invoice_url: string | null;\n}\n\ninterface StripeCharge {\n id: string;\n customer: string | null;\n amount: number;\n currency: string;\n status: string;\n failure_code: string | null;\n created: number;\n payment_intent: string | null;\n}\n\ninterface StripePaymentIntent {\n id: string;\n customer: string | null;\n amount: number;\n currency: string;\n status: string;\n created: number;\n}\n\ninterface StripeProduct {\n id: string;\n name: string;\n active: boolean;\n created: number;\n}\n\ninterface StripeDispute {\n id: string;\n charge: string;\n amount: number;\n currency: string;\n reason: string;\n status: string;\n created: number;\n}\n\ninterface StripeRefund {\n id: string;\n charge: string | null;\n amount: number;\n currency: string;\n reason: string | null;\n status: string | null;\n created: number;\n}\n\n// ---------------------------------------------------------------------------\n// Credentials\n// ---------------------------------------------------------------------------\n\nconst stripeCredentials = {\n apiKey: {\n description: 'Stripe API key',\n auth: 'required' as const,\n },\n} satisfies CredentialsSchema;\n\ntype StripeCredentials = typeof stripeCredentials;\n\n// ---------------------------------------------------------------------------\n// Sync phases + cursor\n// ---------------------------------------------------------------------------\n\nconst PHASE_ORDER = [\n 'customers',\n 'products',\n 'prices',\n 'subscriptions',\n 'invoices',\n 'charges',\n 'payment_intents',\n 'disputes',\n 'refunds',\n] as const;\n\ntype StripePhase = (typeof PHASE_ORDER)[number];\n\nexport type StripeResource = StripePhase;\n\ntype StripeSyncCursor = ChunkedSyncCursor<StripePhase, string>;\n\nfunction isStripeSyncCursor(value: unknown): value is StripeSyncCursor {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n const v = value as { phase?: unknown; page?: unknown };\n if (typeof v.phase !== 'string') {\n return false;\n }\n if (!(PHASE_ORDER as readonly string[]).includes(v.phase)) {\n return false;\n }\n if (v.page !== null && typeof v.page !== 'string') {\n return false;\n }\n return true;\n}\n\nconst ENTITY_TYPE_BY_PHASE: Partial<Record<StripePhase, string>> = {\n customers: 'stripe_customer',\n products: 'stripe_product',\n prices: 'stripe_price',\n subscriptions: 'stripe_subscription',\n invoices: 'stripe_invoice',\n};\n\nconst EVENT_NAME_BY_PHASE: Partial<Record<StripePhase, string>> = {\n charges: 'stripe_charge',\n payment_intents: 'stripe_payment_intent',\n disputes: 'stripe_dispute',\n refunds: 'stripe_refund',\n};\n\n// ---------------------------------------------------------------------------\n// MRR helper\n// ---------------------------------------------------------------------------\n\nexport function computeMrrAmountCents(\n subscription: StripeSubscription,\n): number | null {\n let sum = 0;\n let counted = 0;\n for (const item of subscription.items.data) {\n const { unit_amount, recurring } = item.price;\n if (unit_amount === null || unit_amount === undefined || !recurring) {\n continue;\n }\n const quantity = item.quantity ?? 1;\n const total = unit_amount * quantity;\n const intervalCount = recurring.interval_count || 1;\n let monthly: number | null;\n switch (recurring.interval) {\n case 'month':\n monthly = total / intervalCount;\n break;\n case 'year':\n monthly = total / (12 * intervalCount);\n break;\n case 'week':\n monthly = (total * 52) / (12 * intervalCount);\n break;\n case 'day':\n monthly = (total * 365) / (12 * intervalCount);\n break;\n default:\n monthly = null;\n }\n if (monthly === null) {\n continue;\n }\n sum += monthly;\n counted++;\n }\n if (counted === 0) {\n return null;\n }\n return Math.round(sum);\n}\n\n// ---------------------------------------------------------------------------\n// StripeConnector\n// ---------------------------------------------------------------------------\n\nexport class StripeConnector extends BaseConnector<\n StripeSettings,\n StripeCredentials\n> {\n static readonly id = 'stripe';\n\n static create(input: unknown, ctx?: ConnectorContext): StripeConnector {\n const parsed = configFields.parse(input);\n return new StripeConnector(\n { accountId: parsed.accountId, resources: parsed.resources },\n { apiKey: parsed.apiKey },\n ctx,\n );\n }\n\n readonly id = 'stripe';\n override readonly credentials = stripeCredentials;\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.creds.apiKey}`,\n 'Stripe-Version': '2024-06-20',\n 'User-Agent': 'rawdash/connector-stripe (+https://rawdash.dev)',\n };\n if (this.settings.accountId) {\n headers['Stripe-Account'] = this.settings.accountId;\n }\n return headers;\n }\n\n private fetch<T>(\n url: string,\n resource: string,\n signal?: AbortSignal,\n ): Promise<HttpResponse<T>> {\n return this.get<T>(url, {\n resource,\n headers: this.buildHeaders(),\n signal,\n });\n }\n\n private buildListUrl(\n path: string,\n params: Record<string, string | undefined>,\n ): string {\n const url = new URL(`https://api.stripe.com/v1/${path}`);\n url.searchParams.set('limit', '100');\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, value);\n }\n }\n return url.toString();\n }\n\n // created[gte] cutoff for entity phases in incremental mode (7-day lookback)\n private entityCreatedGte(options: SyncOptions): string | undefined {\n if (options.mode !== 'latest' || !options.since) {\n return undefined;\n }\n const sinceMs = new Date(options.since).getTime();\n return String(Math.floor((sinceMs - 7 * 24 * 60 * 60 * 1000) / 1000));\n }\n\n // created[gt] cutoff for event phases in incremental mode\n private eventCreatedGt(options: SyncOptions): string | undefined {\n if (options.mode !== 'latest' || !options.since) {\n return undefined;\n }\n return String(Math.floor(new Date(options.since).getTime() / 1000));\n }\n\n private buildPhaseUrl(\n phase: StripePhase,\n page: string | null,\n options: SyncOptions,\n ): string {\n const startingAfter = page ?? undefined;\n if (phase in ENTITY_TYPE_BY_PHASE) {\n const extra: Record<string, string | undefined> =\n phase === 'subscriptions' ? { status: 'all' } : {};\n return this.buildListUrl(phase, {\n ...extra,\n starting_after: startingAfter,\n 'created[gte]': this.entityCreatedGte(options),\n });\n }\n return this.buildListUrl(phase, {\n starting_after: startingAfter,\n 'created[gt]': this.eventCreatedGt(options),\n });\n }\n\n private async clearScopeOnFirstPage(\n storage: StorageHandle,\n phase: StripePhase,\n ): Promise<void> {\n const entityType = ENTITY_TYPE_BY_PHASE[phase];\n if (entityType) {\n await storage.entities([], { types: [entityType] });\n return;\n }\n const eventName = EVENT_NAME_BY_PHASE[phase];\n if (eventName) {\n await storage.events([], { names: [eventName] });\n }\n }\n\n private async writePhase(\n storage: StorageHandle,\n phase: StripePhase,\n items: unknown[],\n ): Promise<void> {\n switch (phase) {\n case 'customers':\n for (const c of items as StripeCustomer[]) {\n await storage.entity({\n type: 'stripe_customer',\n id: c.id,\n attributes: {\n email: c.email ?? null,\n name: c.name ?? null,\n created: c.created,\n currency: c.currency ?? null,\n delinquent: c.delinquent ?? false,\n livemode: c.livemode,\n },\n updated_at: c.created * 1000,\n });\n }\n return;\n case 'products':\n for (const p of items as StripeProduct[]) {\n await storage.entity({\n type: 'stripe_product',\n id: p.id,\n attributes: { name: p.name, active: p.active, created: p.created },\n updated_at: p.created * 1000,\n });\n }\n return;\n case 'prices':\n for (const p of items as StripePrice[]) {\n await storage.entity({\n type: 'stripe_price',\n id: p.id,\n attributes: {\n productId: p.product,\n unitAmount: p.unit_amount ?? null,\n currency: p.currency,\n interval: p.recurring?.interval ?? null,\n intervalCount: p.recurring?.interval_count ?? null,\n active: p.active,\n created: p.created,\n },\n updated_at: p.created * 1000,\n });\n }\n return;\n case 'subscriptions':\n for (const s of items as StripeSubscription[]) {\n await storage.entity({\n type: 'stripe_subscription',\n id: s.id,\n attributes: {\n customerId: s.customer,\n status: s.status,\n planId: s.items.data[0]?.price.id ?? null,\n currentPeriodStart: s.current_period_start,\n currentPeriodEnd: s.current_period_end,\n cancelAtPeriodEnd: s.cancel_at_period_end,\n canceledAt: s.canceled_at ?? null,\n trialEnd: s.trial_end ?? null,\n mrrAmount: computeMrrAmountCents(s),\n currency: s.currency,\n created: s.created,\n },\n updated_at: s.current_period_end * 1000,\n });\n }\n return;\n case 'invoices':\n for (const inv of items as StripeInvoice[]) {\n await storage.entity({\n type: 'stripe_invoice',\n id: inv.id,\n attributes: {\n customerId: inv.customer ?? null,\n subscriptionId: inv.subscription ?? null,\n status: inv.status ?? null,\n amountDue: inv.amount_due,\n amountPaid: inv.amount_paid,\n currency: inv.currency,\n created: inv.created,\n dueDate: inv.due_date ?? null,\n hostedInvoiceUrl: inv.hosted_invoice_url ?? null,\n },\n updated_at: inv.created * 1000,\n });\n }\n return;\n case 'charges':\n for (const c of items as StripeCharge[]) {\n await storage.event({\n name: 'stripe_charge',\n start_ts: c.created * 1000,\n end_ts: null,\n attributes: {\n id: c.id,\n customerId: c.customer ?? null,\n amount: c.amount,\n currency: c.currency,\n status: c.status,\n failureCode: c.failure_code ?? null,\n paymentIntentId: c.payment_intent ?? null,\n },\n });\n }\n return;\n case 'payment_intents':\n for (const pi of items as StripePaymentIntent[]) {\n await storage.event({\n name: 'stripe_payment_intent',\n start_ts: pi.created * 1000,\n end_ts: null,\n attributes: {\n id: pi.id,\n customerId: pi.customer ?? null,\n amount: pi.amount,\n currency: pi.currency,\n status: pi.status,\n },\n });\n }\n return;\n case 'disputes':\n for (const d of items as StripeDispute[]) {\n await storage.event({\n name: 'stripe_dispute',\n start_ts: d.created * 1000,\n end_ts: null,\n attributes: {\n id: d.id,\n chargeId: d.charge,\n amount: d.amount,\n currency: d.currency,\n reason: d.reason,\n status: d.status,\n },\n });\n }\n return;\n case 'refunds':\n for (const r of items as StripeRefund[]) {\n await storage.event({\n name: 'stripe_refund',\n start_ts: r.created * 1000,\n end_ts: null,\n attributes: {\n id: r.id,\n chargeId: r.charge ?? null,\n amount: r.amount,\n currency: r.currency,\n reason: r.reason ?? null,\n status: r.status ?? null,\n },\n });\n }\n return;\n }\n }\n\n async sync(\n options: SyncOptions,\n storage: StorageHandle,\n signal?: AbortSignal,\n ): Promise<SyncResult> {\n const cursor = isStripeSyncCursor(options.cursor)\n ? options.cursor\n : undefined;\n const isFull = options.mode === 'full';\n\n const enabled = this.settings.resources;\n const phases =\n enabled && enabled.length > 0\n ? PHASE_ORDER.filter((p) => enabled.includes(p))\n : PHASE_ORDER;\n\n return paginateChunked<StripePhase, string>({\n phases,\n cursor,\n signal,\n fetchPage: async (phase, page, sig) => {\n const url = this.buildPhaseUrl(phase, page, options);\n const res = await this.fetch<StripeListResponse<{ id: string }>>(\n url,\n phase,\n sig,\n );\n const { data, has_more } = res.body;\n const next = has_more && data.length > 0 ? data.at(-1)!.id : null;\n return { items: data, next };\n },\n writeBatch: async (phase, items, page) => {\n if (isFull && page === null) {\n await this.clearScopeOnFirstPage(storage, phase);\n }\n await this.writePhase(storage, phase, items);\n },\n });\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rawdash/connector-stripe",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Rawdash connector for Stripe — billing, subscriptions, and payments",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "zod": "^4.4.3",
26
- "@rawdash/core": "0.11.0"
26
+ "@rawdash/core": "0.12.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "tsup": "^8.0.0",