@memberjunction/connector-stripe 0.2.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.
@@ -0,0 +1,214 @@
1
+ import { type UserInfo } from '@memberjunction/core';
2
+ import type { MJCompanyIntegrationEntity, MJIntegrationObjectEntity } from '@memberjunction/core-entities';
3
+ import { BaseRESTIntegrationConnector, type RESTAuthContext, type RESTResponse, type PaginationState, type PaginationType, type ConnectionTestResult, type FetchContext, type FetchBatchResult, type RateLimitPolicy, type SourceSchemaInfo } from '@memberjunction/integration-engine';
4
+ /**
5
+ * Stripe connector — extends BaseRESTIntegrationConnector (REST/JSON over HTTP).
6
+ *
7
+ * Discovery, generic per-operation CRUD, template-var traversal (nested paths like
8
+ * `/v1/accounts/{account}/persons`), and the paginated GET loop are inherited. This class supplies only
9
+ * the Stripe-specific protocol surface: secret-key Bearer auth + version header, the `starting_after`
10
+ * cursor over the `data[]` envelope, form-encoded bracket-notation write bodies, the `created[gte]`
11
+ * incremental filter, connection testing, and the §7/§10 sync-efficiency hooks the contract evidences.
12
+ */
13
+ export declare class StripeConnector extends BaseRESTIntegrationConnector {
14
+ /** Cached auth for the lifetime of a single sync run (Stripe secret keys don't expire). */
15
+ private cachedAuth;
16
+ /** Verbatim `MJ: Integrations.Name`. Load-bearing: the T1 three-way name check compares this === metadata Name. */
17
+ get IntegrationName(): string;
18
+ get SupportsCreate(): boolean;
19
+ get SupportsUpdate(): boolean;
20
+ get SupportsDelete(): boolean;
21
+ /**
22
+ * Discovery is NON-authoritative: DiscoverObjects / IntrospectSchema are cache-driven (they re-read
23
+ * persisted ACTIVE Declared metadata, NOT a live full-gamut enumeration). Absence in a refresh proves
24
+ * nothing → never deactivate. Matches Configuration.DiscoveryIsAuthoritative semantics for a Declared connector.
25
+ */
26
+ get DiscoveryIsAuthoritative(): boolean;
27
+ /**
28
+ * IntrospectSchema — pure WIRING of MJ's existing sampler into the declared catalog (the connector
29
+ * sample-union standard; see CONNECTOR_DISCOVERY_STANDARD.md). This connector adds NO discovery,
30
+ * merge, or sync logic — it only wires `DiscoverFieldsViaFetch` (MJ's sampler) into IntrospectSchema.
31
+ *
32
+ * `super.IntrospectSchema` yields the cache-driven Declared catalog (no measured widths). For each
33
+ * object we then call MJ's `DiscoverFieldsViaFetch` — MJ's own read-path sampler that measures real
34
+ * field widths and surfaces custom columns — and the shared PURE `mergeDeclaredWithSampledFields`
35
+ * unions the two by field name (adopt MJ's measured width; append MJ-discovered custom columns). MJ
36
+ * owns everything else (measurement, type/PK inference, persistence, reconcile, sync).
37
+ *
38
+ * Recursion note: `DiscoverFieldsViaFetch` falls back to the UNCHANGED `DiscoverFields` (cache-driven)
39
+ * when the read path can't run — never back into THIS method — so there is no infinite recursion.
40
+ * This connector does NOT override `DiscoverFields` to call any ViaFetch/ViaStream.
41
+ *
42
+ * Robustness: objects are sampled IN PARALLEL under a small bounded pool; any per-object failure
43
+ * keeps that object's declared fields, so a single bad sample never breaks introspection.
44
+ */
45
+ IntrospectSchema(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<SourceSchemaInfo>;
46
+ /**
47
+ * From Configuration.RateLimitPolicy: LIVE mode 100 req/s per account, TEST mode 25 req/s. We pace at
48
+ * the conservative test-mode figure (the credential-free / self-serve path uses sk_test_ keys) with a
49
+ * live-mode burst headroom; the engine's AIMD bucket ramps toward the live ceiling on clean traffic and
50
+ * backs off on a 429. Per-resource overrides (payout create 15/s, etc.) are documented but not modeled —
51
+ * the account-wide baseline is the binding ceiling for the single shared bucket.
52
+ */
53
+ get RateLimitPolicy(): RateLimitPolicy | null;
54
+ /**
55
+ * Stripe returns `Retry-After` (seconds) on a 429 (`lock_timeout` / `rate_limit` errors). Parse it to ms
56
+ * so the engine's AIMD bucket backs off by Stripe's actual instruction rather than a guess.
57
+ */
58
+ ExtractRetryAfterMs(error: unknown): number | undefined;
59
+ /** Conservative in-flight cap. Stripe tolerates parallelism but the per-account req/s is the real ceiling. */
60
+ get MaxConcurrencyHint(): number | null;
61
+ /**
62
+ * No-watermark objects (payment_method, subscription_item, and the nested reporting lists) resume by the
63
+ * universal `id` keyset — Stripe lists are stably id-ordered within the reverse-chronological page, and the
64
+ * `starting_after` cursor IS an id keyset. Read the object's declared StableOrderingKey (typically `id`),
65
+ * else its PK. Returns null when no stable key exists or the cache is unavailable (unit-test context).
66
+ */
67
+ StableOrderingKey(objectName: string): string | null;
68
+ /**
69
+ * Resolves the Stripe secret key (and optional pinned API version) from the linked Credential entity
70
+ * (preferred) or the CompanyIntegration Configuration JSON (fallback). Cached for the run.
71
+ */
72
+ protected Authenticate(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<RESTAuthContext>;
73
+ /**
74
+ * Stripe auth: secret-key Bearer + the `Stripe-Version` header pinning the response shape. `Accept`
75
+ * is JSON (all reads/writes return JSON). The write Content-Type (`application/x-www-form-urlencoded`)
76
+ * is NOT set here — it is applied at MakeHTTPRequest only for requests that carry a body, because GET
77
+ * reads must not advertise a form content type.
78
+ */
79
+ protected BuildHeaders(auth: RESTAuthContext): Record<string, string>;
80
+ /**
81
+ * HTTP transport (fetch). Owns the wire boundary; test subclasses override this to capture requests.
82
+ *
83
+ * Stripe write bodies are **form-encoded** with bracket notation (NEVER JSON) — the single most
84
+ * Stripe-specific trap. When a body is present we serialize it via {@link EncodeFormBody} and set
85
+ * `Content-Type: application/x-www-form-urlencoded`. GET reads carry no body and no form content type.
86
+ */
87
+ protected MakeHTTPRequest(_auth: RESTAuthContext, url: string, method: string, headers: Record<string, string>, body?: unknown): Promise<RESTResponse>;
88
+ /**
89
+ * Strips the Stripe list envelope. List endpoints nest records under `data[]` (the metadata sets
90
+ * ResponseDataKey='data'); a bare-array or single-object body (get-one, delete-ack) is the record itself.
91
+ */
92
+ protected NormalizeResponse(rawBody: unknown, responseDataKey: string | null): Record<string, unknown>[];
93
+ /**
94
+ * Stripe pagination is ALWAYS cursor-based: `has_more` in the list envelope flags continuation, and the
95
+ * next cursor is the `id` of the LAST object in the current `data[]` page (passed back as
96
+ * `starting_after` by BuildPaginatedURL). currentPage/offset/pageSize are unused for cursor pagination.
97
+ */
98
+ protected ExtractPaginationInfo(rawBody: unknown, _paginationType: PaginationType, _currentPage: number, _currentOffset: number, _pageSize: number): PaginationState;
99
+ /**
100
+ * The Stripe API host. Defaults to the fixed production host, but is overridable via a `BaseURL`
101
+ * key on `CompanyIntegration.Configuration` — required so the credential-free e2e mock can point the
102
+ * REAL connector at a local mock server, and useful for a Stripe-compatible proxy. The `/v1` version
103
+ * segment stays metadata-driven (per-object APIPath).
104
+ */
105
+ protected GetBaseURL(companyIntegration?: MJCompanyIntegrationEntity): string;
106
+ /**
107
+ * Stripe uses the `starting_after` cursor query param (NOT the base default `cursor=`). On the first
108
+ * page no cursor is sent; subsequent pages send `starting_after=<last data[].id>`. `limit` caps the
109
+ * page size (≤100).
110
+ */
111
+ protected BuildPaginatedURL(basePath: string, obj: MJIntegrationObjectEntity, _page: number, _offset: number, cursor?: string, effectivePageSize?: number): string;
112
+ /**
113
+ * OVERRIDDEN because Stripe's incremental mechanism must inject a `created[gte]=<unix>` range filter
114
+ * into the list URL AND compute the new watermark from each record's own timestamp field — neither of
115
+ * which the base flat/paginated fetch does. The base's `starting_after` cursor paging (via our
116
+ * BuildPaginatedURL / ExtractPaginationInfo overrides) and full-record pass-through are reused.
117
+ *
118
+ * Routing:
119
+ * - A list-capable object WITH a watermark this run (SupportsIncrementalSync + a WatermarkValue) →
120
+ * the incremental path: append `created[gte]` to the base path, run the inherited pagination loop,
121
+ * then compute NewWatermarkValue from the max object-timestamp seen (only on full drain).
122
+ * - Everything else (first full pull, no-watermark objects, nested template-var paths) → the inherited
123
+ * base fetch, which handles the `starting_after` cursor and template-var traversal unchanged.
124
+ *
125
+ * The asymmetry the contract records: the record-cursor field is the object's own timestamp
126
+ * (IncrementalWatermarkField — `created` for most, `date` for invoiceitem), but the list-endpoint filter
127
+ * param is ALWAYS `created[gte]`. We track the watermark off the object field; we send `created[gte]`.
128
+ */
129
+ FetchChanges(ctx: FetchContext): Promise<FetchBatchResult>;
130
+ /**
131
+ * Incremental applies only when the object supports it, carries a watermark this run, and its APIPath is
132
+ * a flat list endpoint (no template vars — nested reporting lists don't take a `created` filter and are
133
+ * left to the base template-var traversal).
134
+ */
135
+ private UseIncremental;
136
+ /**
137
+ * Incremental fetch: append `created[gte]=<unix>` to the list APIPath, run the inherited paginated GET
138
+ * loop (which uses `starting_after` + `limit` and unwraps `data[]`), then advance the watermark to the
139
+ * max object-timestamp seen — but only on a fully-drained batch (HasMore=false), so a partial batch
140
+ * never advances the watermark (partial-failure safety; the engine persists it on full-batch success).
141
+ */
142
+ private FetchChangesIncremental;
143
+ /**
144
+ * Runs the paginated `starting_after` loop against a `created[gte]`-filtered base path, accumulating up
145
+ * to BatchSize records, tracking the max object-timestamp seen. Resumes from ctx.CurrentCursor.
146
+ */
147
+ private RunIncrementalPagination;
148
+ /**
149
+ * Substitute the record id into a Stripe single-resource path. Stripe names its id placeholder after
150
+ * the resource (`/v1/customers/{customer}`, `/v1/invoices/{invoice}`,
151
+ * `/v1/subscriptions/{subscription_exposed_id}`) rather than the generic `{id}`/`{ID}`/`{ExternalID}`
152
+ * the base handles, and it ALWAYS carries the update/delete target id in the PATH (never the request
153
+ * body). We let the base run first (a harmless no-op on a named placeholder), then substitute the
154
+ * TRAILING `{placeholder}` — the record's own id — leaving any LEADING parent placeholder (e.g. the
155
+ * `{account}` in `/v1/accounts/{account}/persons/{person}`) for parent-chain resolution. Substitution
156
+ * is driven by the path SHAPE (a trailing placeholder is unambiguously an id slot), not the metadata
157
+ * IDLocation — so it is correct even where an object's DeleteIDLocation was recorded as `body`.
158
+ */
159
+ protected SubstituteIDInPath(path: string, externalID: string, idLocation: string | null): string;
160
+ /**
161
+ * Tests the connection by hitting the balance endpoint (`GET /v1/balance`) — a cheap, always-present,
162
+ * account-scoped read. A 2xx confirms the secret key is valid; 401 → auth failure; anything else → error.
163
+ */
164
+ TestConnection(companyIntegration: MJCompanyIntegrationEntity, contextUser: UserInfo): Promise<ConnectionTestResult>;
165
+ /** Reads the secret key (+ optional version) from the linked Credential entity, or the Configuration JSON fallback. */
166
+ private LoadCredentials;
167
+ /** Loads a credential row and parses its Values JSON. */
168
+ private LoadFromCredentialEntity;
169
+ /** Extracts a Stripe secret key (+ optional pinned version) from a credential/config JSON string. */
170
+ private ParseCredentialJson;
171
+ /**
172
+ * Serializes an attributes object to `application/x-www-form-urlencoded` with Stripe BRACKET NOTATION
173
+ * for nested objects and arrays. This is the binding Stripe write idiosyncrasy — the API accepts ZERO
174
+ * JSON request bodies (spec S4.1). Examples:
175
+ * { name: 'A', metadata: { tier: 'gold' } } → name=A&metadata[tier]=gold
176
+ * { expand: ['customer'] } → expand[]=customer
177
+ * { items: [{ price: 'price_1' }] } → items[0][price]=price_1
178
+ * Null/undefined values are omitted (Stripe treats an absent param as unset, not clear-to-null).
179
+ */
180
+ private EncodeFormBody;
181
+ /** Recursively flattens a value into `key[...]=value` form pairs using Stripe bracket notation. */
182
+ private FlattenFormPairs;
183
+ /** Coerces a scalar (string/number/boolean) to its Stripe form value string. */
184
+ private ScalarToString;
185
+ /** Gets an IO from the cache without throwing (used by StableOrderingKey, which may be called early). */
186
+ private TryGetCachedObject;
187
+ /** Returns the first present, non-empty string value among the given keys. */
188
+ private FirstString;
189
+ /** PK field names in Sequence order (falls back to ['id'] — Stripe's universal PK — when unmarked). */
190
+ private FindPrimaryKeyFieldNamesLocal;
191
+ /**
192
+ * Builds an ExternalRecord with the FULL source record in Fields (full-record pass-through — the
193
+ * framework's custom-column capture diffs keys(Fields) against the field maps). ExternalID is the
194
+ * composite PK (when every component is present + non-empty) or the raw Stripe `id`.
195
+ */
196
+ private RawToExternalRecord;
197
+ /** Stripe's system id lives at the object root as `id` (e.g. `cus_...`, `ch_...`, `in_...`). */
198
+ private ExtractStripeID;
199
+ /** The `starting_after` cursor for the next page is the id of the last record emitted this batch. */
200
+ private CursorFromLast;
201
+ /**
202
+ * Converts a watermark value to a Stripe UNIX-seconds integer (Stripe's `created[gte]` filter compares
203
+ * against a unix timestamp). Accepts an ISO date, a unix-seconds string, an epoch-ms string, or null
204
+ * (→ 0, i.e. full pull). Epoch-ms is down-converted to seconds.
205
+ */
206
+ private WatermarkToUnix;
207
+ /**
208
+ * Reads a record's watermark timestamp as unix seconds. Stripe timestamp fields (`created`, `date`) are
209
+ * unix seconds already; tolerates a string form. Returns null when absent/unparseable.
210
+ */
211
+ private ReadTimestamp;
212
+ /** Best-effort extraction of response headers from an error object (for ExtractRetryAfterMs). */
213
+ private ExtractHeadersFromError;
214
+ }
@@ -0,0 +1,620 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { RegisterClass } from '@memberjunction/global';
8
+ import { Metadata } from '@memberjunction/core';
9
+ import { IntegrationEngineBase } from '@memberjunction/integration-engine-base';
10
+ import { BaseIntegrationConnector, BaseRESTIntegrationConnector,
11
+ // NOTE: no auth-helper crypto imported — Stripe uses a static secret-key Bearer (no signing, no OAuth flow).
12
+ } from '@memberjunction/integration-engine';
13
+ import { mergeDeclaredWithSampledFields } from '@memberjunction/connector-schema-merge';
14
+ // ─── Constants ────────────────────────────────────────────────────────
15
+ /** Stripe API host. Fixed base — the version segment (`/v1`) lives in each object's APIPath (metadata-driven). */
16
+ const STRIPE_API_BASE = 'https://api.stripe.com';
17
+ /** Stripe list page size cap (docs: limit range 1–100, default 10). We request the max to minimize round-trips. */
18
+ const STRIPE_LIST_MAX_PAGE = 100;
19
+ /**
20
+ * Default pinned Stripe API version. Overridable per-connection via the credential/Configuration JSON
21
+ * (APIVersion / stripeVersion). Omitting the header falls back to the key's account-default version;
22
+ * we pin a known-good date-version so the response shape is stable across accounts. Source:
23
+ * Configuration.APIVersioningStrategy (OpenAPI info.version + docs.stripe.com/api).
24
+ */
25
+ const STRIPE_DEFAULT_API_VERSION = '2026-06-24.dahlia';
26
+ // ─── StripeConnector ───────────────────────────────────────────────────
27
+ /**
28
+ * Stripe connector — extends BaseRESTIntegrationConnector (REST/JSON over HTTP).
29
+ *
30
+ * Discovery, generic per-operation CRUD, template-var traversal (nested paths like
31
+ * `/v1/accounts/{account}/persons`), and the paginated GET loop are inherited. This class supplies only
32
+ * the Stripe-specific protocol surface: secret-key Bearer auth + version header, the `starting_after`
33
+ * cursor over the `data[]` envelope, form-encoded bracket-notation write bodies, the `created[gte]`
34
+ * incremental filter, connection testing, and the §7/§10 sync-efficiency hooks the contract evidences.
35
+ */
36
+ let StripeConnector = class StripeConnector extends BaseRESTIntegrationConnector {
37
+ constructor() {
38
+ super(...arguments);
39
+ /** Cached auth for the lifetime of a single sync run (Stripe secret keys don't expire). */
40
+ this.cachedAuth = null;
41
+ }
42
+ // ── Identity (T1 three-way invariant) ────────────────────────────
43
+ /** Verbatim `MJ: Integrations.Name`. Load-bearing: the T1 three-way name check compares this === metadata Name. */
44
+ get IntegrationName() {
45
+ return 'stripe';
46
+ }
47
+ // ── Capability getters (kept in lockstep with the per-op metadata columns) ──
48
+ get SupportsCreate() { return true; }
49
+ get SupportsUpdate() { return true; }
50
+ get SupportsDelete() { return true; }
51
+ /**
52
+ * Discovery is NON-authoritative: DiscoverObjects / IntrospectSchema are cache-driven (they re-read
53
+ * persisted ACTIVE Declared metadata, NOT a live full-gamut enumeration). Absence in a refresh proves
54
+ * nothing → never deactivate. Matches Configuration.DiscoveryIsAuthoritative semantics for a Declared connector.
55
+ */
56
+ get DiscoveryIsAuthoritative() {
57
+ return false;
58
+ }
59
+ /**
60
+ * IntrospectSchema — pure WIRING of MJ's existing sampler into the declared catalog (the connector
61
+ * sample-union standard; see CONNECTOR_DISCOVERY_STANDARD.md). This connector adds NO discovery,
62
+ * merge, or sync logic — it only wires `DiscoverFieldsViaFetch` (MJ's sampler) into IntrospectSchema.
63
+ *
64
+ * `super.IntrospectSchema` yields the cache-driven Declared catalog (no measured widths). For each
65
+ * object we then call MJ's `DiscoverFieldsViaFetch` — MJ's own read-path sampler that measures real
66
+ * field widths and surfaces custom columns — and the shared PURE `mergeDeclaredWithSampledFields`
67
+ * unions the two by field name (adopt MJ's measured width; append MJ-discovered custom columns). MJ
68
+ * owns everything else (measurement, type/PK inference, persistence, reconcile, sync).
69
+ *
70
+ * Recursion note: `DiscoverFieldsViaFetch` falls back to the UNCHANGED `DiscoverFields` (cache-driven)
71
+ * when the read path can't run — never back into THIS method — so there is no infinite recursion.
72
+ * This connector does NOT override `DiscoverFields` to call any ViaFetch/ViaStream.
73
+ *
74
+ * Robustness: objects are sampled IN PARALLEL under a small bounded pool; any per-object failure
75
+ * keeps that object's declared fields, so a single bad sample never breaks introspection.
76
+ */
77
+ async IntrospectSchema(companyIntegration, contextUser) {
78
+ const schema = await super.IntrospectSchema(companyIntegration, contextUser);
79
+ await runBounded(schema.Objects, 8, async (obj) => {
80
+ try {
81
+ const sampled = await this.DiscoverFieldsViaFetch(companyIntegration, obj.ExternalName, contextUser);
82
+ obj.Fields = mergeDeclaredWithSampledFields(obj.Fields, sampled);
83
+ }
84
+ catch {
85
+ // Keep this object's declared fields — sampling is best-effort and never breaks introspection.
86
+ }
87
+ });
88
+ return schema;
89
+ }
90
+ // ── Sync-efficiency hooks (§7/§10 — populated from frozen-contract Configuration facts) ──
91
+ /**
92
+ * From Configuration.RateLimitPolicy: LIVE mode 100 req/s per account, TEST mode 25 req/s. We pace at
93
+ * the conservative test-mode figure (the credential-free / self-serve path uses sk_test_ keys) with a
94
+ * live-mode burst headroom; the engine's AIMD bucket ramps toward the live ceiling on clean traffic and
95
+ * backs off on a 429. Per-resource overrides (payout create 15/s, etc.) are documented but not modeled —
96
+ * the account-wide baseline is the binding ceiling for the single shared bucket.
97
+ */
98
+ get RateLimitPolicy() {
99
+ return { TokensPerSec: 25, Burst: 100 };
100
+ }
101
+ /**
102
+ * Stripe returns `Retry-After` (seconds) on a 429 (`lock_timeout` / `rate_limit` errors). Parse it to ms
103
+ * so the engine's AIMD bucket backs off by Stripe's actual instruction rather than a guess.
104
+ */
105
+ ExtractRetryAfterMs(error) {
106
+ const headers = this.ExtractHeadersFromError(error);
107
+ if (!headers)
108
+ return undefined;
109
+ const retryAfter = headers['retry-after'] ?? headers['Retry-After'];
110
+ if (retryAfter != null) {
111
+ const secs = Number(retryAfter);
112
+ if (!isNaN(secs) && secs >= 0)
113
+ return Math.ceil(secs * 1000);
114
+ }
115
+ return undefined;
116
+ }
117
+ /** Conservative in-flight cap. Stripe tolerates parallelism but the per-account req/s is the real ceiling. */
118
+ get MaxConcurrencyHint() {
119
+ return 4;
120
+ }
121
+ /**
122
+ * No-watermark objects (payment_method, subscription_item, and the nested reporting lists) resume by the
123
+ * universal `id` keyset — Stripe lists are stably id-ordered within the reverse-chronological page, and the
124
+ * `starting_after` cursor IS an id keyset. Read the object's declared StableOrderingKey (typically `id`),
125
+ * else its PK. Returns null when no stable key exists or the cache is unavailable (unit-test context).
126
+ */
127
+ StableOrderingKey(objectName) {
128
+ const obj = this.TryGetCachedObject(objectName);
129
+ if (!obj)
130
+ return null;
131
+ const declared = obj.StableOrderingKey;
132
+ if (declared && declared.trim().length > 0)
133
+ return declared.trim();
134
+ const pk = this.GetCachedFields(obj.ID).find(f => f.IsPrimaryKey);
135
+ return pk?.Name ?? null;
136
+ }
137
+ // ── Abstract REST hooks ──────────────────────────────────────────
138
+ /**
139
+ * Resolves the Stripe secret key (and optional pinned API version) from the linked Credential entity
140
+ * (preferred) or the CompanyIntegration Configuration JSON (fallback). Cached for the run.
141
+ */
142
+ async Authenticate(companyIntegration, contextUser) {
143
+ if (this.cachedAuth)
144
+ return this.cachedAuth;
145
+ const creds = await this.LoadCredentials(companyIntegration, contextUser);
146
+ this.cachedAuth = { Token: creds.SecretKey, APIVersion: creds.APIVersion };
147
+ return this.cachedAuth;
148
+ }
149
+ /**
150
+ * Stripe auth: secret-key Bearer + the `Stripe-Version` header pinning the response shape. `Accept`
151
+ * is JSON (all reads/writes return JSON). The write Content-Type (`application/x-www-form-urlencoded`)
152
+ * is NOT set here — it is applied at MakeHTTPRequest only for requests that carry a body, because GET
153
+ * reads must not advertise a form content type.
154
+ */
155
+ BuildHeaders(auth) {
156
+ const ctx = auth;
157
+ return {
158
+ 'Authorization': `Bearer ${ctx.Token}`,
159
+ 'Stripe-Version': ctx.APIVersion && ctx.APIVersion.length > 0 ? ctx.APIVersion : STRIPE_DEFAULT_API_VERSION,
160
+ 'Accept': 'application/json',
161
+ };
162
+ }
163
+ /**
164
+ * HTTP transport (fetch). Owns the wire boundary; test subclasses override this to capture requests.
165
+ *
166
+ * Stripe write bodies are **form-encoded** with bracket notation (NEVER JSON) — the single most
167
+ * Stripe-specific trap. When a body is present we serialize it via {@link EncodeFormBody} and set
168
+ * `Content-Type: application/x-www-form-urlencoded`. GET reads carry no body and no form content type.
169
+ */
170
+ async MakeHTTPRequest(_auth, url, method, headers, body) {
171
+ let fetchBody;
172
+ const outHeaders = { ...headers };
173
+ if (body !== undefined && body !== null) {
174
+ fetchBody = this.EncodeFormBody(body);
175
+ outHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
176
+ }
177
+ const response = await fetch(url, { method, headers: outHeaders, body: fetchBody });
178
+ const respHeaders = {};
179
+ response.headers.forEach((v, k) => { respHeaders[k.toLowerCase()] = v; });
180
+ const text = await response.text();
181
+ let parsed = null;
182
+ if (text.length > 0) {
183
+ try {
184
+ parsed = JSON.parse(text);
185
+ }
186
+ catch {
187
+ parsed = text;
188
+ }
189
+ }
190
+ return { Status: response.status, Body: parsed, Headers: respHeaders };
191
+ }
192
+ /**
193
+ * Strips the Stripe list envelope. List endpoints nest records under `data[]` (the metadata sets
194
+ * ResponseDataKey='data'); a bare-array or single-object body (get-one, delete-ack) is the record itself.
195
+ */
196
+ NormalizeResponse(rawBody, responseDataKey) {
197
+ if (rawBody == null)
198
+ return [];
199
+ if (Array.isArray(rawBody))
200
+ return rawBody;
201
+ if (typeof rawBody === 'object') {
202
+ const body = rawBody;
203
+ const key = responseDataKey ?? 'data';
204
+ const arr = body[key];
205
+ if (Array.isArray(arr))
206
+ return arr;
207
+ // get-one / delete-ack / non-list shape: the body IS the record.
208
+ return [body];
209
+ }
210
+ return [];
211
+ }
212
+ /**
213
+ * Stripe pagination is ALWAYS cursor-based: `has_more` in the list envelope flags continuation, and the
214
+ * next cursor is the `id` of the LAST object in the current `data[]` page (passed back as
215
+ * `starting_after` by BuildPaginatedURL). currentPage/offset/pageSize are unused for cursor pagination.
216
+ */
217
+ ExtractPaginationInfo(rawBody, _paginationType, _currentPage, _currentOffset, _pageSize) {
218
+ if (rawBody && typeof rawBody === 'object') {
219
+ const env = rawBody;
220
+ if (env.has_more === true && Array.isArray(env.data) && env.data.length > 0) {
221
+ const last = env.data[env.data.length - 1];
222
+ const lastId = this.ExtractStripeID(last);
223
+ if (lastId.length > 0) {
224
+ return { HasMore: true, NextCursor: lastId };
225
+ }
226
+ }
227
+ }
228
+ return { HasMore: false };
229
+ }
230
+ /**
231
+ * The Stripe API host. Defaults to the fixed production host, but is overridable via a `BaseURL`
232
+ * key on `CompanyIntegration.Configuration` — required so the credential-free e2e mock can point the
233
+ * REAL connector at a local mock server, and useful for a Stripe-compatible proxy. The `/v1` version
234
+ * segment stays metadata-driven (per-object APIPath).
235
+ */
236
+ GetBaseURL(companyIntegration) {
237
+ const cfg = companyIntegration?.Configuration;
238
+ if (cfg) {
239
+ try {
240
+ const parsed = JSON.parse(cfg);
241
+ const override = parsed.BaseURL ?? parsed.baseURL ?? parsed.BaseUrl;
242
+ if (typeof override === 'string' && override.trim().length > 0) {
243
+ return override.trim().replace(/\/+$/, '');
244
+ }
245
+ }
246
+ catch { /* Configuration is not JSON — fall through to the default host */ }
247
+ }
248
+ return STRIPE_API_BASE;
249
+ }
250
+ /**
251
+ * Stripe uses the `starting_after` cursor query param (NOT the base default `cursor=`). On the first
252
+ * page no cursor is sent; subsequent pages send `starting_after=<last data[].id>`. `limit` caps the
253
+ * page size (≤100).
254
+ */
255
+ BuildPaginatedURL(basePath, obj, _page, _offset, cursor, effectivePageSize) {
256
+ const pageSize = Math.min(effectivePageSize ?? obj.DefaultPageSize ?? STRIPE_LIST_MAX_PAGE, STRIPE_LIST_MAX_PAGE);
257
+ const separator = basePath.includes('?') ? '&' : '?';
258
+ const parts = [`limit=${pageSize}`];
259
+ if (cursor)
260
+ parts.push(`starting_after=${encodeURIComponent(cursor)}`);
261
+ return `${basePath}${separator}${parts.join('&')}`;
262
+ }
263
+ // ── FetchChanges override (incremental: created[gte] range filter + watermark tracking) ──
264
+ /**
265
+ * OVERRIDDEN because Stripe's incremental mechanism must inject a `created[gte]=<unix>` range filter
266
+ * into the list URL AND compute the new watermark from each record's own timestamp field — neither of
267
+ * which the base flat/paginated fetch does. The base's `starting_after` cursor paging (via our
268
+ * BuildPaginatedURL / ExtractPaginationInfo overrides) and full-record pass-through are reused.
269
+ *
270
+ * Routing:
271
+ * - A list-capable object WITH a watermark this run (SupportsIncrementalSync + a WatermarkValue) →
272
+ * the incremental path: append `created[gte]` to the base path, run the inherited pagination loop,
273
+ * then compute NewWatermarkValue from the max object-timestamp seen (only on full drain).
274
+ * - Everything else (first full pull, no-watermark objects, nested template-var paths) → the inherited
275
+ * base fetch, which handles the `starting_after` cursor and template-var traversal unchanged.
276
+ *
277
+ * The asymmetry the contract records: the record-cursor field is the object's own timestamp
278
+ * (IncrementalWatermarkField — `created` for most, `date` for invoiceitem), but the list-endpoint filter
279
+ * param is ALWAYS `created[gte]`. We track the watermark off the object field; we send `created[gte]`.
280
+ */
281
+ async FetchChanges(ctx) {
282
+ const obj = this.GetCachedObject(ctx.CompanyIntegration.IntegrationID, ctx.ObjectName);
283
+ if (!this.UseIncremental(obj, ctx)) {
284
+ return super.FetchChanges(ctx);
285
+ }
286
+ return this.FetchChangesIncremental(obj, ctx);
287
+ }
288
+ /**
289
+ * Incremental applies only when the object supports it, carries a watermark this run, and its APIPath is
290
+ * a flat list endpoint (no template vars — nested reporting lists don't take a `created` filter and are
291
+ * left to the base template-var traversal).
292
+ */
293
+ UseIncremental(obj, ctx) {
294
+ if (!obj.SupportsIncrementalSync)
295
+ return false;
296
+ if (ctx.WatermarkValue == null || ctx.WatermarkValue.length === 0)
297
+ return false;
298
+ if (/\{[A-Za-z]+\}/.test(obj.APIPath))
299
+ return false;
300
+ return true;
301
+ }
302
+ /**
303
+ * Incremental fetch: append `created[gte]=<unix>` to the list APIPath, run the inherited paginated GET
304
+ * loop (which uses `starting_after` + `limit` and unwraps `data[]`), then advance the watermark to the
305
+ * max object-timestamp seen — but only on a fully-drained batch (HasMore=false), so a partial batch
306
+ * never advances the watermark (partial-failure safety; the engine persists it on full-batch success).
307
+ */
308
+ async FetchChangesIncremental(obj, ctx) {
309
+ const watermarkField = obj.IncrementalWatermarkField ?? 'created';
310
+ const sinceUnix = this.WatermarkToUnix(ctx.WatermarkValue);
311
+ // Append the documented list-endpoint range filter (`created[gte]`) to the APIPath WITHOUT mutating
312
+ // the shared engine-cache row — we build the URL string locally and drive the pagination loop directly.
313
+ const separator = obj.APIPath.includes('?') ? '&' : '?';
314
+ const filteredPath = `${obj.APIPath}${separator}created[gte]=${sinceUnix}`;
315
+ const auth = await this.Authenticate(ctx.CompanyIntegration, ctx.ContextUser);
316
+ const fields = this.GetCachedFields(obj.ID);
317
+ const pkFieldNames = this.FindPrimaryKeyFieldNamesLocal(fields);
318
+ const baseURL = this.GetBaseURL();
319
+ const basePath = `${baseURL}${filteredPath.startsWith('/') ? '' : '/'}${filteredPath}`;
320
+ const { records, hasMore, maxWatermark } = await this.RunIncrementalPagination(auth, basePath, obj, fields, ctx, watermarkField, sinceUnix, pkFieldNames);
321
+ if (hasMore) {
322
+ return { Records: records, HasMore: true, NextCursor: this.CursorFromLast(records) };
323
+ }
324
+ return { Records: records, HasMore: false, NewWatermarkValue: String(maxWatermark) };
325
+ }
326
+ /**
327
+ * Runs the paginated `starting_after` loop against a `created[gte]`-filtered base path, accumulating up
328
+ * to BatchSize records, tracking the max object-timestamp seen. Resumes from ctx.CurrentCursor.
329
+ */
330
+ async RunIncrementalPagination(auth, basePath, obj, fields, ctx, watermarkField, sinceUnix, pkFieldNames) {
331
+ const headers = this.BuildHeaders(auth);
332
+ const batchLimit = ctx.BatchSize ?? Number.MAX_SAFE_INTEGER;
333
+ const out = [];
334
+ let cursor = ctx.CurrentCursor;
335
+ let maxWatermark = sinceUnix;
336
+ let hasMore = true;
337
+ while (hasMore && out.length < batchLimit) {
338
+ const remaining = batchLimit - out.length;
339
+ const url = this.BuildPaginatedURL(basePath, obj, 1, 0, cursor, remaining);
340
+ const response = await this.MakeHTTPRequest(auth, url, 'GET', headers);
341
+ if (response.Status < 200 || response.Status >= 300) {
342
+ throw new Error(`[stripe] incremental fetch failed for "${obj.Name}": HTTP ${response.Status}`);
343
+ }
344
+ const raw = this.NormalizeResponse(response.Body, obj.ResponseDataKey);
345
+ if (raw.length === 0) {
346
+ hasMore = false;
347
+ break;
348
+ }
349
+ for (const r of raw) {
350
+ out.push(this.RawToExternalRecord(this.applyTransformPreservingKeys(r, obj, fields), obj.Name, pkFieldNames));
351
+ const ts = this.ReadTimestamp(r, watermarkField);
352
+ if (ts != null && ts > maxWatermark)
353
+ maxWatermark = ts;
354
+ }
355
+ const page = this.ExtractPaginationInfo(response.Body, obj.PaginationType, 1, 0, obj.DefaultPageSize ?? raw.length);
356
+ hasMore = page.HasMore;
357
+ cursor = page.NextCursor;
358
+ }
359
+ return { records: out, hasMore, maxWatermark };
360
+ }
361
+ // ── CRUD ──────────────────────────────────────────────────────────
362
+ //
363
+ // Every writable IO (customer, charge, product, subscription, invoice, …) uses the INHERITED generic
364
+ // CreateRecord / UpdateRecord / DeleteRecord / GetRecord from BaseRESTIntegrationConnector, which read
365
+ // the per-operation IO columns (CreateAPIPath/Method, CreateBodyShape='flat', CreateIDLocation='body',
366
+ // UpdateMethod='POST', UpdateIDLocation='path', DeleteMethod/Location) and handle the path-substituted
367
+ // id + the loud-on-empty-id BuildCreatedResult correctly. Stripe's ONLY write idiosyncrasy —
368
+ // form-encoded bracket-notation bodies — is injected once at the MakeHTTPRequest transport boundary
369
+ // (EncodeFormBody), so NO CRUD verb needs overriding. Update-is-POST is metadata-driven (UpdateMethod),
370
+ // NOT hardcoded to PATCH. The ONE path-shaping override needed is SubstituteIDInPath below, because
371
+ // Stripe names its id placeholder after the resource ({customer}/{invoice}/…), which the generic base
372
+ // (which only knows {id}/{ID}/{ExternalID}) cannot substitute.
373
+ /**
374
+ * Substitute the record id into a Stripe single-resource path. Stripe names its id placeholder after
375
+ * the resource (`/v1/customers/{customer}`, `/v1/invoices/{invoice}`,
376
+ * `/v1/subscriptions/{subscription_exposed_id}`) rather than the generic `{id}`/`{ID}`/`{ExternalID}`
377
+ * the base handles, and it ALWAYS carries the update/delete target id in the PATH (never the request
378
+ * body). We let the base run first (a harmless no-op on a named placeholder), then substitute the
379
+ * TRAILING `{placeholder}` — the record's own id — leaving any LEADING parent placeholder (e.g. the
380
+ * `{account}` in `/v1/accounts/{account}/persons/{person}`) for parent-chain resolution. Substitution
381
+ * is driven by the path SHAPE (a trailing placeholder is unambiguously an id slot), not the metadata
382
+ * IDLocation — so it is correct even where an object's DeleteIDLocation was recorded as `body`.
383
+ */
384
+ SubstituteIDInPath(path, externalID, idLocation) {
385
+ const base = super.SubstituteIDInPath(path, externalID, idLocation);
386
+ if (!/\{[^}]+\}$/.test(base))
387
+ return base;
388
+ return base.replace(/\{[^}]+\}$/, encodeURIComponent(externalID));
389
+ }
390
+ // ── Connection test ──────────────────────────────────────────────
391
+ /**
392
+ * Tests the connection by hitting the balance endpoint (`GET /v1/balance`) — a cheap, always-present,
393
+ * account-scoped read. A 2xx confirms the secret key is valid; 401 → auth failure; anything else → error.
394
+ */
395
+ async TestConnection(companyIntegration, contextUser) {
396
+ try {
397
+ const auth = await this.Authenticate(companyIntegration, contextUser);
398
+ const headers = this.BuildHeaders(auth);
399
+ const url = `${this.GetBaseURL(companyIntegration)}/v1/balance`;
400
+ const response = await this.MakeHTTPRequest(auth, url, 'GET', headers);
401
+ if (response.Status >= 200 && response.Status < 300) {
402
+ return { Success: true, Message: 'Stripe connection successful.' };
403
+ }
404
+ if (response.Status === 401) {
405
+ return { Success: false, Message: 'Stripe authentication failed (HTTP 401). Check the secret key (sk_live_… / sk_test_…).' };
406
+ }
407
+ return { Success: false, Message: `Stripe connection test returned HTTP ${response.Status}.` };
408
+ }
409
+ catch (err) {
410
+ const msg = err instanceof Error ? err.message : String(err);
411
+ return { Success: false, Message: `Stripe connection test error: ${msg}` };
412
+ }
413
+ }
414
+ // ── Credential loading ───────────────────────────────────────────
415
+ /** Reads the secret key (+ optional version) from the linked Credential entity, or the Configuration JSON fallback. */
416
+ async LoadCredentials(companyIntegration, contextUser) {
417
+ const credentialID = companyIntegration.CredentialID;
418
+ if (credentialID) {
419
+ const creds = await this.LoadFromCredentialEntity(credentialID, contextUser);
420
+ if (creds)
421
+ return creds;
422
+ }
423
+ const configJson = companyIntegration.Configuration;
424
+ if (configJson) {
425
+ const creds = this.ParseCredentialJson(configJson);
426
+ if (creds)
427
+ return creds;
428
+ }
429
+ throw new Error('No Stripe credential found. Attach a credential carrying a secret key ' +
430
+ '(secretKey / apiKey / Token), or set Configuration JSON on the CompanyIntegration.');
431
+ }
432
+ /** Loads a credential row and parses its Values JSON. */
433
+ async LoadFromCredentialEntity(credentialID, contextUser, provider) {
434
+ const md = provider ?? new Metadata();
435
+ const credential = await md.GetEntityObject('MJ: Credentials', contextUser);
436
+ const loaded = await credential.Load(credentialID);
437
+ if (!loaded || !credential.Values)
438
+ return null;
439
+ return this.ParseCredentialJson(credential.Values);
440
+ }
441
+ /** Extracts a Stripe secret key (+ optional pinned version) from a credential/config JSON string. */
442
+ ParseCredentialJson(json) {
443
+ try {
444
+ const parsed = JSON.parse(json);
445
+ const key = this.FirstString(parsed, ['secretKey', 'SecretKey', 'apiKey', 'ApiKey', 'Token', 'token']);
446
+ if (!key)
447
+ return null;
448
+ const version = this.FirstString(parsed, ['stripeVersion', 'StripeVersion', 'apiVersion', 'APIVersion']);
449
+ return { SecretKey: key, APIVersion: version };
450
+ }
451
+ catch {
452
+ return null;
453
+ }
454
+ }
455
+ // ── Form-encoding (Stripe write bodies) ──────────────────────────
456
+ /**
457
+ * Serializes an attributes object to `application/x-www-form-urlencoded` with Stripe BRACKET NOTATION
458
+ * for nested objects and arrays. This is the binding Stripe write idiosyncrasy — the API accepts ZERO
459
+ * JSON request bodies (spec S4.1). Examples:
460
+ * { name: 'A', metadata: { tier: 'gold' } } → name=A&metadata[tier]=gold
461
+ * { expand: ['customer'] } → expand[]=customer
462
+ * { items: [{ price: 'price_1' }] } → items[0][price]=price_1
463
+ * Null/undefined values are omitted (Stripe treats an absent param as unset, not clear-to-null).
464
+ */
465
+ EncodeFormBody(body) {
466
+ const pairs = [];
467
+ this.FlattenFormPairs('', body, pairs);
468
+ return pairs.join('&');
469
+ }
470
+ /** Recursively flattens a value into `key[...]=value` form pairs using Stripe bracket notation. */
471
+ FlattenFormPairs(prefix, value, out) {
472
+ if (value === null || value === undefined)
473
+ return;
474
+ if (Array.isArray(value)) {
475
+ if (value.length === 0)
476
+ return;
477
+ value.forEach((item, i) => {
478
+ // Scalars in an array use `key[]=v`; objects/arrays are indexed `key[i]...`.
479
+ const isScalar = item === null || typeof item !== 'object';
480
+ const childPrefix = isScalar ? `${prefix}[]` : `${prefix}[${i}]`;
481
+ this.FlattenFormPairs(childPrefix, item, out);
482
+ });
483
+ return;
484
+ }
485
+ if (typeof value === 'object') {
486
+ for (const [k, v] of Object.entries(value)) {
487
+ const childPrefix = prefix.length === 0 ? k : `${prefix}[${k}]`;
488
+ this.FlattenFormPairs(childPrefix, v, out);
489
+ }
490
+ return;
491
+ }
492
+ // Scalar leaf. After excluding null/undefined/array/object above, narrow the residual `unknown`
493
+ // to the primitive types Stripe form values actually take; coerce any other residual defensively.
494
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
495
+ out.push(`${encodeURIComponent(prefix)}=${encodeURIComponent(this.ScalarToString(value))}`);
496
+ }
497
+ else {
498
+ out.push(`${encodeURIComponent(prefix)}=${encodeURIComponent(String(value))}`);
499
+ }
500
+ }
501
+ /** Coerces a scalar (string/number/boolean) to its Stripe form value string. */
502
+ ScalarToString(value) {
503
+ return typeof value === 'boolean' ? (value ? 'true' : 'false') : String(value);
504
+ }
505
+ // ── Helpers ──────────────────────────────────────────────────────
506
+ /** Gets an IO from the cache without throwing (used by StableOrderingKey, which may be called early). */
507
+ TryGetCachedObject(objectName) {
508
+ try {
509
+ const integ = IntegrationEngineBase.Instance.GetIntegrationByName(this.IntegrationName);
510
+ if (!integ)
511
+ return null;
512
+ return IntegrationEngineBase.Instance.GetIntegrationObject(integ.ID, objectName) ?? null;
513
+ }
514
+ catch {
515
+ return null;
516
+ }
517
+ }
518
+ /** Returns the first present, non-empty string value among the given keys. */
519
+ FirstString(obj, keys) {
520
+ for (const k of keys) {
521
+ const v = obj[k];
522
+ if (typeof v === 'string' && v.length > 0)
523
+ return v;
524
+ }
525
+ return undefined;
526
+ }
527
+ /** PK field names in Sequence order (falls back to ['id'] — Stripe's universal PK — when unmarked). */
528
+ FindPrimaryKeyFieldNamesLocal(fields) {
529
+ const pk = fields.filter(f => f.IsPrimaryKey).sort((a, b) => a.Sequence - b.Sequence).map(f => f.Name);
530
+ return pk.length > 0 ? pk : ['id'];
531
+ }
532
+ /**
533
+ * Builds an ExternalRecord with the FULL source record in Fields (full-record pass-through — the
534
+ * framework's custom-column capture diffs keys(Fields) against the field maps). ExternalID is the
535
+ * composite PK (when every component is present + non-empty) or the raw Stripe `id`.
536
+ */
537
+ RawToExternalRecord(raw, objectType, pkFieldNames) {
538
+ const allPresent = pkFieldNames.length > 0 && pkFieldNames.every(n => raw[n] != null && String(raw[n]).length > 0);
539
+ const externalID = allPresent
540
+ ? pkFieldNames.map(n => String(raw[n])).join('|')
541
+ : this.ExtractStripeID(raw);
542
+ return { ExternalID: externalID, ObjectType: objectType, Fields: raw };
543
+ }
544
+ /** Stripe's system id lives at the object root as `id` (e.g. `cus_...`, `ch_...`, `in_...`). */
545
+ ExtractStripeID(raw) {
546
+ return raw.id != null ? String(raw.id) : '';
547
+ }
548
+ /** The `starting_after` cursor for the next page is the id of the last record emitted this batch. */
549
+ CursorFromLast(records) {
550
+ if (records.length === 0)
551
+ return undefined;
552
+ const last = records[records.length - 1];
553
+ return last.ExternalID.length > 0 ? last.ExternalID : undefined;
554
+ }
555
+ /**
556
+ * Converts a watermark value to a Stripe UNIX-seconds integer (Stripe's `created[gte]` filter compares
557
+ * against a unix timestamp). Accepts an ISO date, a unix-seconds string, an epoch-ms string, or null
558
+ * (→ 0, i.e. full pull). Epoch-ms is down-converted to seconds.
559
+ */
560
+ WatermarkToUnix(watermark) {
561
+ if (!watermark || watermark.length === 0)
562
+ return 0;
563
+ if (/^\d+$/.test(watermark)) {
564
+ const n = Number(watermark);
565
+ // Heuristic: values > ~10 digits are epoch-ms → convert to seconds. Stripe unix seconds are 10 digits.
566
+ return n > 9_999_999_999 ? Math.floor(n / 1000) : n;
567
+ }
568
+ const t = Date.parse(watermark);
569
+ return isNaN(t) ? 0 : Math.floor(t / 1000);
570
+ }
571
+ /**
572
+ * Reads a record's watermark timestamp as unix seconds. Stripe timestamp fields (`created`, `date`) are
573
+ * unix seconds already; tolerates a string form. Returns null when absent/unparseable.
574
+ */
575
+ ReadTimestamp(raw, watermarkField) {
576
+ const v = raw[watermarkField];
577
+ if (v == null)
578
+ return null;
579
+ if (typeof v === 'number')
580
+ return v;
581
+ const s = String(v);
582
+ if (/^\d+$/.test(s))
583
+ return Number(s);
584
+ const t = Date.parse(s);
585
+ return isNaN(t) ? null : Math.floor(t / 1000);
586
+ }
587
+ /** Best-effort extraction of response headers from an error object (for ExtractRetryAfterMs). */
588
+ ExtractHeadersFromError(error) {
589
+ if (!error || typeof error !== 'object')
590
+ return undefined;
591
+ const e = error;
592
+ const resp = e.response ?? e;
593
+ if (resp && typeof resp === 'object') {
594
+ const headers = resp.headers ?? resp.Headers;
595
+ if (headers && typeof headers === 'object')
596
+ return headers;
597
+ }
598
+ return undefined;
599
+ }
600
+ };
601
+ StripeConnector = __decorate([
602
+ RegisterClass(BaseIntegrationConnector, '@memberjunction/connector-stripe')
603
+ ], StripeConnector);
604
+ export { StripeConnector };
605
+ /**
606
+ * Minimal bounded promise-pool: runs `worker` over `items` with at most `limit` in flight.
607
+ * (BaseRESTIntegrationConnector.RunBounded is private, so the sample-union override brings its own
608
+ * tiny pool — this is local plumbing, NOT a shared framework artifact.)
609
+ */
610
+ async function runBounded(items, limit, worker) {
611
+ const queue = [...items];
612
+ const size = Math.max(1, Math.min(limit, queue.length));
613
+ const runners = Array.from({ length: size }, async () => {
614
+ for (let next = queue.shift(); next !== undefined; next = queue.shift()) {
615
+ await worker(next);
616
+ }
617
+ });
618
+ await Promise.all(runners);
619
+ }
620
+ //# sourceMappingURL=StripeConnector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StripeConnector.js","sourceRoot":"","sources":["../src/StripeConnector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export * from './StripeConnector.js';
2
+ /** Open App bootstrap entry: importing this module ran the connector's @RegisterClass decorator;
3
+ * this no-op satisfies the loader's required startupExport and forces the import at MJAPI boot. */
4
+ export declare function registerConnector(): void;
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './StripeConnector.js';
2
+ /** Open App bootstrap entry: importing this module ran the connector's @RegisterClass decorator;
3
+ * this no-op satisfies the loader's required startupExport and forces the import at MJAPI boot. */
4
+ export function registerConnector() { }
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AAErC;oGACoG;AACpG,MAAM,UAAU,iBAAiB,KAAiD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@memberjunction/connector-stripe",
3
+ "version": "0.2.0",
4
+ "description": "MemberJunction Stripe connector.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "/dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc && tsc-alias -f",
13
+ "test": "vitest run"
14
+ },
15
+ "author": "MemberJunction.com",
16
+ "license": "ISC",
17
+ "peerDependencies": {
18
+ "@memberjunction/core": ">=5.42.0 <6.0.0",
19
+ "@memberjunction/core-entities": ">=5.42.0 <6.0.0",
20
+ "@memberjunction/global": ">=5.42.0 <6.0.0",
21
+ "@memberjunction/integration-engine": ">=5.42.0 <6.0.0"
22
+ },
23
+ "dependencies": {
24
+ "@memberjunction/connector-schema-merge": "^1.0.0",
25
+ "zod": "~3.24.4"
26
+ },
27
+ "devDependencies": {
28
+ "@memberjunction/connector-schema-merge": "^1.0.0",
29
+ "@memberjunction/core": "^5.42.0",
30
+ "@memberjunction/core-entities": "^5.42.0",
31
+ "@memberjunction/global": "^5.42.0",
32
+ "@memberjunction/integration-engine": "^5.42.0",
33
+ "@types/node": "24.10.11",
34
+ "tsc-alias": "^1.8.16",
35
+ "typescript": "^5.9.3",
36
+ "vitest": "^4.0.18"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/MemberJunction/Integrations"
41
+ }
42
+ }