@opencard-dev/core 0.1.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.
Files changed (53) hide show
  1. package/dist/db.d.ts +145 -0
  2. package/dist/db.d.ts.map +1 -0
  3. package/dist/db.js +373 -0
  4. package/dist/db.js.map +1 -0
  5. package/dist/errors.d.ts +72 -0
  6. package/dist/errors.d.ts.map +1 -0
  7. package/dist/errors.js +124 -0
  8. package/dist/errors.js.map +1 -0
  9. package/dist/index.d.ts +34 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +67 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/logger.d.ts +53 -0
  14. package/dist/logger.d.ts.map +1 -0
  15. package/dist/logger.js +109 -0
  16. package/dist/logger.js.map +1 -0
  17. package/dist/rules-engine.d.ts +159 -0
  18. package/dist/rules-engine.d.ts.map +1 -0
  19. package/dist/rules-engine.js +375 -0
  20. package/dist/rules-engine.js.map +1 -0
  21. package/dist/rules-store.d.ts +187 -0
  22. package/dist/rules-store.d.ts.map +1 -0
  23. package/dist/rules-store.js +291 -0
  24. package/dist/rules-store.js.map +1 -0
  25. package/dist/rules-validation.d.ts +54 -0
  26. package/dist/rules-validation.d.ts.map +1 -0
  27. package/dist/rules-validation.js +110 -0
  28. package/dist/rules-validation.js.map +1 -0
  29. package/dist/stripe-client.d.ts +154 -0
  30. package/dist/stripe-client.d.ts.map +1 -0
  31. package/dist/stripe-client.js +444 -0
  32. package/dist/stripe-client.js.map +1 -0
  33. package/dist/test-utils.d.ts +55 -0
  34. package/dist/test-utils.d.ts.map +1 -0
  35. package/dist/test-utils.js +91 -0
  36. package/dist/test-utils.js.map +1 -0
  37. package/dist/tracker.d.ts +130 -0
  38. package/dist/tracker.d.ts.map +1 -0
  39. package/dist/tracker.js +196 -0
  40. package/dist/tracker.js.map +1 -0
  41. package/dist/transaction-reconciler.d.ts +30 -0
  42. package/dist/transaction-reconciler.d.ts.map +1 -0
  43. package/dist/transaction-reconciler.js +131 -0
  44. package/dist/transaction-reconciler.js.map +1 -0
  45. package/dist/types.d.ts +194 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +7 -0
  48. package/dist/types.js.map +1 -0
  49. package/dist/webhooks.d.ts +121 -0
  50. package/dist/webhooks.d.ts.map +1 -0
  51. package/dist/webhooks.js +307 -0
  52. package/dist/webhooks.js.map +1 -0
  53. package/package.json +46 -0
@@ -0,0 +1,444 @@
1
+ "use strict";
2
+ /**
3
+ * StripeClient
4
+ * ============
5
+ * A clean, typed wrapper around Stripe's Issuing API.
6
+ *
7
+ * Stripe's Issuing product lets you create virtual (and physical) payment cards
8
+ * programmatically. OpenCard uses it to give AI agents their own cards with
9
+ * spending controls attached.
10
+ *
11
+ * ─── Why a wrapper? ─────────────────────────────────────────────────────────
12
+ * The raw Stripe SDK is powerful but returns Stripe's own types, which don't
13
+ * always match what OpenCard needs. This wrapper:
14
+ * - Converts Stripe's snake_case fields to camelCase (matches our TypeScript style)
15
+ * - Maps Stripe's types to our internal interfaces (Card, Cardholder, etc.)
16
+ * - Centralizes error handling in one place
17
+ * - Makes the API surface smaller and easier to understand
18
+ *
19
+ * ─── Stripe API version ─────────────────────────────────────────────────────
20
+ * We pin to "2023-10-16". If you upgrade the Stripe SDK, check if the API
21
+ * version needs updating and whether any field names/types changed.
22
+ *
23
+ * ─── Test vs. Live mode ─────────────────────────────────────────────────────
24
+ * Stripe uses the key prefix to determine mode:
25
+ * sk_test_... → test mode (no real money, safe to experiment)
26
+ * sk_live_... → live mode (REAL money — be careful!)
27
+ * Never commit a live key to git.
28
+ */
29
+ var __importDefault = (this && this.__importDefault) || function (mod) {
30
+ return (mod && mod.__esModule) ? mod : { "default": mod };
31
+ };
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.StripeClient = void 0;
34
+ const stripe_1 = __importDefault(require("stripe"));
35
+ const rules_store_1 = require("./rules-store");
36
+ const errors_1 = require("./errors");
37
+ class StripeClient {
38
+ /** The underlying Stripe SDK instance. Use this for any Stripe calls not yet wrapped here. */
39
+ stripe;
40
+ /** Stored config so we can reference it in later operations. */
41
+ config;
42
+ /**
43
+ * Creates a new StripeClient.
44
+ *
45
+ * @param config - Optional configuration. If omitted, reads from environment variables.
46
+ *
47
+ * @throws Error if no API key is found (neither in config nor in STRIPE_SECRET_KEY env var)
48
+ *
49
+ * @example
50
+ * // Use environment variable (recommended for production)
51
+ * const client = new StripeClient();
52
+ *
53
+ * // Pass key directly (good for testing)
54
+ * const client = new StripeClient({ secretKey: 'sk_test_...' });
55
+ */
56
+ constructor(config = {}) {
57
+ // The API key can come from either the config object or the environment variable.
58
+ // If neither is set, we throw early with a helpful message.
59
+ const secretKey = config.secretKey || process.env.STRIPE_SECRET_KEY;
60
+ // Check if key is missing or empty
61
+ if (!secretKey || secretKey.trim() === '') {
62
+ throw new errors_1.StripeAuthenticationError('STRIPE_SECRET_KEY not set. Get your test key from https://dashboard.stripe.com/apikeys', { source: 'config' });
63
+ }
64
+ // Validate key format
65
+ const trimmedKey = secretKey.trim();
66
+ if (!trimmedKey.startsWith('sk_test_') && !trimmedKey.startsWith('sk_live_')) {
67
+ console.warn('STRIPE_SECRET_KEY looks invalid — test keys start with sk_test_, live keys with sk_live_');
68
+ }
69
+ // Initialize the Stripe SDK. The apiVersion pin ensures consistent behavior
70
+ // even if the SDK package is updated.
71
+ this.stripe = new stripe_1.default(trimmedKey, {
72
+ apiVersion: '2023-10-16',
73
+ });
74
+ this.config = {
75
+ secretKey: trimmedKey,
76
+ // defaultRules is optional — if not provided, use an empty rule set
77
+ defaultRules: config.defaultRules ?? {},
78
+ apiVersion: config.apiVersion || '2023-10-16',
79
+ };
80
+ }
81
+ // ─── Cardholders ────────────────────────────────────────────────────────────
82
+ /**
83
+ * Creates a new cardholder in Stripe Issuing.
84
+ *
85
+ * A cardholder is the entity that "owns" the cards. In a typical OpenCard
86
+ * setup, you'd create one cardholder per agent or per project, then create
87
+ * multiple cards under that cardholder.
88
+ *
89
+ * Stripe requires a billing address for cardholders in most configurations.
90
+ * In test mode this requirement may be relaxed.
91
+ *
92
+ * @param name - Display name for the cardholder (e.g. "Atlas Agent", "Research Bot")
93
+ * @param email - Contact email (used by Stripe for notifications)
94
+ * @param billing - Billing address (required for live mode)
95
+ * @returns The created Cardholder object
96
+ */
97
+ async createCardholder(name, email, billing) {
98
+ try {
99
+ const cardholder = await this.stripe.issuing.cardholders.create({
100
+ name,
101
+ email,
102
+ type: 'individual', // Stripe supports 'individual' and 'company'
103
+ billing: billing
104
+ ? {
105
+ address: {
106
+ line1: billing.line1,
107
+ line2: billing.line2,
108
+ city: billing.city,
109
+ state: billing.state,
110
+ postal_code: billing.postalCode,
111
+ country: billing.country,
112
+ },
113
+ }
114
+ : {
115
+ // Stripe requires a billing field even if minimal.
116
+ // In test mode, a placeholder address is acceptable.
117
+ address: {
118
+ line1: '354 Oyster Point Blvd',
119
+ city: 'South San Francisco',
120
+ state: 'CA',
121
+ postal_code: '94080',
122
+ country: 'US',
123
+ },
124
+ },
125
+ status: 'active',
126
+ });
127
+ // Map Stripe's response to our internal Cardholder type.
128
+ // Note: Stripe's `email` field can be null, so we fall back to the
129
+ // input email (which we know is a string since the caller passed it).
130
+ return {
131
+ id: cardholder.id,
132
+ name: cardholder.name,
133
+ email: cardholder.email ?? email,
134
+ billing,
135
+ createdAt: new Date(cardholder.created * 1000), // Stripe uses Unix timestamps (seconds)
136
+ status: 'active',
137
+ };
138
+ }
139
+ catch (error) {
140
+ throw (0, errors_1.wrapStripeError)(error, 'Failed to create cardholder', 'stripe-client', { name, email });
141
+ }
142
+ }
143
+ // ─── Cards ──────────────────────────────────────────────────────────────────
144
+ /**
145
+ * Creates a new virtual card for an agent.
146
+ *
147
+ * The card is issued under the specified cardholder. Spending limits can be
148
+ * applied either via Stripe's native spending_controls (enforced at the
149
+ * Stripe level, last-resort safeguard) or via OpenCard's rules engine
150
+ * (enforced via the webhook server, smarter but requires the server to be running).
151
+ *
152
+ * The `agentName` is stored in card metadata so you can identify which
153
+ * agent this card belongs to when reviewing Stripe dashboard or logs.
154
+ *
155
+ * @param cardholderId - The Stripe cardholder ID (e.g. "ich_abc123")
156
+ * @param options - Card creation options (name, rules, status, metadata)
157
+ * @returns The created Card object
158
+ */
159
+ async createCard(cardholderId, options) {
160
+ try {
161
+ // ── Resolve the rule ID ───────────────────────────────────────────────
162
+ // We want to store only a rule reference ID in Stripe metadata, not the
163
+ // full rule JSON. This prevents anyone with Stripe dashboard access from
164
+ // modifying rules by editing card metadata.
165
+ //
166
+ // Three cases:
167
+ // 1. Caller passed `ruleId` directly → use it as-is
168
+ // 2. Caller passed `rules` (inline) without a ruleId → auto-create in store
169
+ // 3. Neither passed → no rules on this card
170
+ let resolvedRuleId = options.ruleId;
171
+ if (!resolvedRuleId && options.rules) {
172
+ // Auto-migrate: create the inline rules in the store and use the returned ID.
173
+ // This maintains backward compatibility — callers don't HAVE to know about
174
+ // the rules store, it just happens automatically.
175
+ console.log(`[StripeClient] createCard: inline rules provided without ruleId — auto-creating in rules store`);
176
+ resolvedRuleId = await rules_store_1.rulesStore.createRule(options.rules);
177
+ console.log(`[StripeClient] createCard: auto-created rule ${resolvedRuleId} for card under cardholder ${cardholderId}`);
178
+ }
179
+ const card = await this.stripe.issuing.cards.create({
180
+ cardholder: cardholderId,
181
+ currency: 'usd',
182
+ type: 'virtual', // We only create virtual cards (no physical plastic)
183
+ status: options.status || 'active',
184
+ // spending_controls are Stripe-native limits — they're enforced even if
185
+ // our webhook server is down. Think of them as the safety net under the net.
186
+ spending_controls: options.spendingLimits
187
+ ? {
188
+ spending_limits: [
189
+ {
190
+ amount: options.spendingLimits.amount,
191
+ interval: options.spendingLimits.intervalType,
192
+ },
193
+ ],
194
+ }
195
+ : undefined,
196
+ metadata: {
197
+ // Store the agent name so we can identify this card in Stripe's dashboard
198
+ // and in our webhook logs.
199
+ agentName: options.agentName,
200
+ // Store only the rule reference ID, not the full rule JSON.
201
+ // The webhook server will look up the actual rule from our rules store.
202
+ // This is the core security improvement: Stripe metadata no longer holds
203
+ // the actual rules, so modifying metadata cannot change spending behavior.
204
+ ...(resolvedRuleId ? { opencard_rule_id: resolvedRuleId } : {}),
205
+ // Human-readable description of what this card is for. Helps agents
206
+ // pick the right card at purchase time without guessing from limits alone.
207
+ ...(options.description ? { opencard_description: options.description } : {}),
208
+ // Spread any caller-provided custom metadata (project IDs, tags, etc.)
209
+ ...options.metadata,
210
+ },
211
+ });
212
+ return mapCardResponse(card, cardholderId, options);
213
+ }
214
+ catch (error) {
215
+ throw (0, errors_1.wrapStripeError)(error, 'Failed to create card', 'stripe-client', { cardholderId, ruleId: options.ruleId });
216
+ }
217
+ }
218
+ /**
219
+ * Retrieves a card by its Stripe card ID.
220
+ * Useful for checking current status, limits, and metadata.
221
+ *
222
+ * @param cardId - Stripe card ID (e.g. "ic_abc123")
223
+ */
224
+ async getCard(cardId) {
225
+ try {
226
+ const card = await this.stripe.issuing.cards.retrieve(cardId);
227
+ const cardholderId = typeof card.cardholder === 'string'
228
+ ? card.cardholder
229
+ : card.cardholder?.id || '';
230
+ return mapCardResponse(card, cardholderId, {
231
+ agentName: card.metadata?.agentName || 'unknown',
232
+ });
233
+ }
234
+ catch (error) {
235
+ throw (0, errors_1.wrapStripeError)(error, 'Failed to get card', 'stripe-client', { cardId });
236
+ }
237
+ }
238
+ /**
239
+ * Pauses a card by setting its status to 'inactive'.
240
+ *
241
+ * A paused card will decline all new charges but can be resumed later.
242
+ * This is different from canceling — canceled cards cannot be reactivated.
243
+ *
244
+ * Use this when an agent has violated rules and needs to be stopped temporarily,
245
+ * or when you want to manually review spending before re-enabling.
246
+ *
247
+ * @param cardId - Stripe card ID to pause
248
+ */
249
+ async pauseCard(cardId) {
250
+ try {
251
+ const card = await this.stripe.issuing.cards.update(cardId, {
252
+ status: 'inactive', // Stripe's term for "paused" on virtual cards
253
+ });
254
+ const cardholderId = typeof card.cardholder === 'string'
255
+ ? card.cardholder
256
+ : card.cardholder?.id || '';
257
+ return mapCardResponse(card, cardholderId, {
258
+ agentName: card.metadata?.agentName || 'unknown',
259
+ });
260
+ }
261
+ catch (error) {
262
+ throw (0, errors_1.wrapStripeError)(error, 'Failed to pause card', 'stripe-client', { cardId });
263
+ }
264
+ }
265
+ /**
266
+ * Resumes a paused card by setting its status back to 'active'.
267
+ * The card will accept new charges again immediately after this call.
268
+ *
269
+ * @param cardId - Stripe card ID to resume
270
+ */
271
+ async resumeCard(cardId) {
272
+ try {
273
+ const card = await this.stripe.issuing.cards.update(cardId, {
274
+ status: 'active',
275
+ });
276
+ const cardholderId = typeof card.cardholder === 'string'
277
+ ? card.cardholder
278
+ : card.cardholder?.id || '';
279
+ return mapCardResponse(card, cardholderId, {
280
+ agentName: card.metadata?.agentName || 'unknown',
281
+ });
282
+ }
283
+ catch (error) {
284
+ throw (0, errors_1.wrapStripeError)(error, 'Failed to resume card', 'stripe-client', { cardId });
285
+ }
286
+ }
287
+ /**
288
+ * Updates the spending limits on a card.
289
+ *
290
+ * These are Stripe-native limits (not OpenCard rules). They're enforced at
291
+ * the Stripe level regardless of whether our webhook server is running.
292
+ * Good for setting hard floors that can never be bypassed.
293
+ *
294
+ * @param cardId - Stripe card ID
295
+ * @param limits - Array of spending limit objects
296
+ */
297
+ async setSpendingLimits(cardId, limits) {
298
+ try {
299
+ const card = await this.stripe.issuing.cards.update(cardId, {
300
+ spending_controls: {
301
+ spending_limits: limits.map((limit) => ({
302
+ amount: limit.amount,
303
+ interval: limit.intervalType,
304
+ })),
305
+ },
306
+ });
307
+ const cardholderId = typeof card.cardholder === 'string'
308
+ ? card.cardholder
309
+ : card.cardholder?.id || '';
310
+ return mapCardResponse(card, cardholderId, {
311
+ agentName: card.metadata?.agentName || 'unknown',
312
+ spendingLimits: limits[0], // Return the first limit for display purposes
313
+ });
314
+ }
315
+ catch (error) {
316
+ throw (0, errors_1.wrapStripeError)(error, 'Failed to set spending limits', 'stripe-client', { cardId, limits });
317
+ }
318
+ }
319
+ // ─── Transactions ────────────────────────────────────────────────────────────
320
+ /**
321
+ * Retrieves the transaction history for a card.
322
+ *
323
+ * Note: Stripe Issuing transactions are distinct from regular Stripe charges.
324
+ * They represent captured spending on issued cards.
325
+ *
326
+ * Note on Stripe v14 Transaction type: The `status` and `decline_reason` fields
327
+ * don't exist on Issuing.Transaction in the v14 type definitions (the transaction
328
+ * object represents *completed* captures, not pending authorizations). For
329
+ * pending/declined status, use the Issuing.Authorization type instead.
330
+ *
331
+ * @param cardId - Stripe card ID
332
+ * @param options - Optional filters (limit, date range, etc.)
333
+ */
334
+ async getTransactions(cardId, options) {
335
+ try {
336
+ const transactions = await this.stripe.issuing.transactions.list({
337
+ card: cardId,
338
+ limit: options?.limit || 100,
339
+ });
340
+ return transactions.data.map((tx) => ({
341
+ id: tx.id,
342
+ // tx.card can be either a card ID string or a full Card object
343
+ cardId: typeof tx.card === 'string' ? tx.card : tx.card?.id || '',
344
+ amount: tx.amount,
345
+ currency: tx.currency,
346
+ merchant: {
347
+ name: tx.merchant_data?.name || 'Unknown',
348
+ category: tx.merchant_data?.category || 'unknown',
349
+ // Stripe returns null for optional geo fields — convert to undefined
350
+ // for consistency with our Transaction type (which uses string | undefined)
351
+ city: tx.merchant_data?.city ?? undefined,
352
+ country: tx.merchant_data?.country ?? undefined,
353
+ },
354
+ // Issuing transactions represent completed captures, so status is always 'captured'
355
+ // unless the transaction was reversed.
356
+ status: tx.type === 'capture' ? 'captured' : 'reversed',
357
+ createdAt: new Date(tx.created * 1000),
358
+ metadata: tx.metadata || {},
359
+ }));
360
+ }
361
+ catch (error) {
362
+ throw (0, errors_1.wrapStripeError)(error, 'Failed to get transactions', 'stripe-client', { cardId });
363
+ }
364
+ }
365
+ // ─── Balance ─────────────────────────────────────────────────────────────────
366
+ /**
367
+ * Returns a balance snapshot for this account.
368
+ *
369
+ * Note: Stripe Issuing doesn't expose a per-card balance API. The "balance"
370
+ * for virtual cards is determined by your spending limits, not a pre-loaded
371
+ * amount. This is a stub that returns zeroes.
372
+ *
373
+ * Phase 2 will compute this by summing transactions against spending limits.
374
+ */
375
+ async getBalance() {
376
+ return {
377
+ available: 0,
378
+ reserved: 0,
379
+ spent: 0,
380
+ asOf: new Date(),
381
+ };
382
+ }
383
+ /**
384
+ * Returns pending authorizations for a card.
385
+ *
386
+ * Stripe doesn't provide a REST API for pending authorizations — they're
387
+ * delivered exclusively via webhooks. This stub exists for API completeness.
388
+ * Phase 1 uses the webhook server for real-time authorization handling.
389
+ *
390
+ * @param _cardId - Card ID (unused in Phase 1)
391
+ */
392
+ async getPendingAuthorizations(_cardId) {
393
+ // In Phase 1, authorizations are handled via webhooks, not polling.
394
+ // The webhook server receives issuing_authorization.request events in real time.
395
+ // This endpoint is here for future use (Phase 2 may add a polling fallback).
396
+ return [];
397
+ }
398
+ }
399
+ exports.StripeClient = StripeClient;
400
+ // ─── Internal helpers ─────────────────────────────────────────────────────────
401
+ /**
402
+ * Converts a Stripe.Issuing.Card response into our internal Card type.
403
+ *
404
+ * This helper is used by multiple methods (createCard, getCard, pauseCard, etc.)
405
+ * to avoid duplicating the mapping logic. Any time the Stripe SDK returns a card
406
+ * object, we run it through this function to get our clean Card interface.
407
+ *
408
+ * @param card - Raw Stripe.Issuing.Card from the SDK
409
+ * @param cardholderId - The cardholder's ID string
410
+ * @param options - The original creation options (for agentName and rules)
411
+ */
412
+ function mapCardResponse(card, cardholderId, options) {
413
+ // Stripe stores expiry as separate month/year integers.
414
+ // We combine them into MM/YY format (e.g. "03/28" for March 2028).
415
+ const expiry = `${String(card.exp_month).padStart(2, '0')}/${String(card.exp_year).slice(-2)}`;
416
+ // card.metadata is typed as Stripe.Metadata (Record<string, string>), but
417
+ // can be null in some edge cases. We cast to our expected shape.
418
+ const metadata = card.metadata;
419
+ return {
420
+ id: card.id,
421
+ last4: card.last4,
422
+ brand: 'visa', // Stripe Issuing only issues Visa cards (in the US)
423
+ expiry,
424
+ // Stripe card status: 'active', 'inactive', or 'canceled'
425
+ status: card.status,
426
+ cardholderId,
427
+ agentName: metadata?.agentName || options.agentName || 'unknown',
428
+ // Human-readable description of what this card is for.
429
+ // Stored in Stripe metadata as opencard_description. Null if not set.
430
+ description: metadata?.opencard_description ?? null,
431
+ rules: options.rules,
432
+ // Stripe returns spending limits as an array of SpendingLimit objects.
433
+ // Our SpendingLimits type has different field names (camelCase vs snake_case),
434
+ // so we map them here. If there are no limits set, return an empty array.
435
+ spendingControls: (card.spending_controls?.spending_limits || []).map((sl) => ({
436
+ amount: sl.amount,
437
+ intervalType: sl.interval,
438
+ intervalCurrencyUnit: 'usd',
439
+ })),
440
+ metadata: metadata ?? undefined,
441
+ createdAt: new Date(card.created * 1000),
442
+ };
443
+ }
444
+ //# sourceMappingURL=stripe-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stripe-client.js","sourceRoot":"","sources":["../src/stripe-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @opencard/core — Test Utilities
3
+ * ================================
4
+ * Shared helpers for testing code that depends on Stripe Issuing types.
5
+ *
6
+ * These utilities exist to avoid duplicating fake Stripe object construction
7
+ * across test files and examples. All builders produce minimal partial objects
8
+ * that contain only the fields our code actually reads — the real Stripe
9
+ * authorization has ~30 fields, but we only need a handful for evaluation.
10
+ *
11
+ * ─── Usage ───────────────────────────────────────────────────────────────────
12
+ *
13
+ * import { mockAuthorization } from '@opencard-dev/core/test-utils';
14
+ *
15
+ * const auth = mockAuthorization({ amount: 2500, category: 'saas' });
16
+ *
17
+ * ─── Why cast through unknown? ───────────────────────────────────────────────
18
+ * We intentionally build partial Stripe objects — only the fields our rules
19
+ * engine reads. TypeScript would complain about missing required fields, so we
20
+ * cast via `unknown` as a deliberate signal that this is a test-only shortcut.
21
+ */
22
+ import Stripe from 'stripe';
23
+ /**
24
+ * Parameters for `mockAuthorization()`.
25
+ * All fields are optional — sensible defaults are provided for each.
26
+ */
27
+ export interface MockAuthorizationParams {
28
+ /** Transaction amount in cents. Default: 2500 ($25.00) */
29
+ amount?: number;
30
+ /** Merchant category code (e.g. 'saas', 'grocery'). Default: 'saas' */
31
+ category?: string;
32
+ /** Merchant display name. Default: 'Acme Corp' */
33
+ merchantName?: string;
34
+ /** Stripe card ID. Default: 'ic_test123' */
35
+ cardId?: string;
36
+ /** Additional metadata to set on the card object. Default: {} */
37
+ cardMetadata?: Record<string, string>;
38
+ }
39
+ /**
40
+ * Creates a minimal fake `Stripe.Issuing.Authorization` for use in tests
41
+ * and runnable examples.
42
+ *
43
+ * Only the fields read by `evaluateAuthorization` are populated:
44
+ * - `amount`
45
+ * - `merchant_data.category` and `merchant_data.name`
46
+ * - `card.id` and `card.metadata`
47
+ *
48
+ * All other required Stripe fields are set to null/empty/defaults to satisfy
49
+ * TypeScript without pulling in the full Stripe fixture machinery.
50
+ *
51
+ * @param params - Override defaults for any field
52
+ * @returns A partial Stripe.Issuing.Authorization cast to the full type
53
+ */
54
+ export declare function mockAuthorization(params?: MockAuthorizationParams): Stripe.Issuing.Authorization;
55
+ //# sourceMappingURL=test-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,GAAE,uBAA4B,GACnC,MAAM,CAAC,OAAO,CAAC,aAAa,CAuD9B"}
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ /**
3
+ * @opencard/core — Test Utilities
4
+ * ================================
5
+ * Shared helpers for testing code that depends on Stripe Issuing types.
6
+ *
7
+ * These utilities exist to avoid duplicating fake Stripe object construction
8
+ * across test files and examples. All builders produce minimal partial objects
9
+ * that contain only the fields our code actually reads — the real Stripe
10
+ * authorization has ~30 fields, but we only need a handful for evaluation.
11
+ *
12
+ * ─── Usage ───────────────────────────────────────────────────────────────────
13
+ *
14
+ * import { mockAuthorization } from '@opencard-dev/core/test-utils';
15
+ *
16
+ * const auth = mockAuthorization({ amount: 2500, category: 'saas' });
17
+ *
18
+ * ─── Why cast through unknown? ───────────────────────────────────────────────
19
+ * We intentionally build partial Stripe objects — only the fields our rules
20
+ * engine reads. TypeScript would complain about missing required fields, so we
21
+ * cast via `unknown` as a deliberate signal that this is a test-only shortcut.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.mockAuthorization = mockAuthorization;
25
+ /**
26
+ * Creates a minimal fake `Stripe.Issuing.Authorization` for use in tests
27
+ * and runnable examples.
28
+ *
29
+ * Only the fields read by `evaluateAuthorization` are populated:
30
+ * - `amount`
31
+ * - `merchant_data.category` and `merchant_data.name`
32
+ * - `card.id` and `card.metadata`
33
+ *
34
+ * All other required Stripe fields are set to null/empty/defaults to satisfy
35
+ * TypeScript without pulling in the full Stripe fixture machinery.
36
+ *
37
+ * @param params - Override defaults for any field
38
+ * @returns A partial Stripe.Issuing.Authorization cast to the full type
39
+ */
40
+ function mockAuthorization(params = {}) {
41
+ const { amount = 2500, // Default: $25.00
42
+ category = 'saas', // Default: software category
43
+ merchantName = 'Acme Corp', cardId = 'ic_test123', cardMetadata = {}, } = params;
44
+ return {
45
+ id: `iauth_${Date.now()}`,
46
+ object: 'issuing.authorization',
47
+ amount,
48
+ approved: false, // Before evaluation, always false
49
+ currency: 'usd',
50
+ merchant_data: {
51
+ category,
52
+ name: merchantName,
53
+ city: 'San Francisco',
54
+ country: 'US',
55
+ network_id: '',
56
+ postal_code: '94105',
57
+ state: 'CA',
58
+ },
59
+ // The card object embedded in the authorization.
60
+ // Our code reads card.id and card.metadata from here.
61
+ card: {
62
+ id: cardId,
63
+ metadata: cardMetadata,
64
+ },
65
+ metadata: {},
66
+ // Fields below exist in real authorizations but are unused by our code.
67
+ pending_request: null,
68
+ request_history: [],
69
+ status: 'pending',
70
+ created: Math.floor(Date.now() / 1000),
71
+ livemode: false,
72
+ network_data: null,
73
+ transactions: [],
74
+ verification_data: {
75
+ address_line1_check: 'not_provided',
76
+ address_postal_code_check: 'not_provided',
77
+ cvc_check: 'not_provided',
78
+ expiry_check: 'match',
79
+ },
80
+ wallet: null,
81
+ amount_details: null,
82
+ balance_transactions: [],
83
+ cardholder: 'ich_test',
84
+ fleet: null,
85
+ fuel: null,
86
+ merchant_amount: amount,
87
+ merchant_currency: 'usd',
88
+ token: null,
89
+ };
90
+ }
91
+ //# sourceMappingURL=test-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;AAoCH,8CAyDC;AAxED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,iBAAiB,CAC/B,SAAkC,EAAE;IAEpC,MAAM,EACJ,MAAM,GAAG,IAAI,EAAa,kBAAkB;IAC5C,QAAQ,GAAG,MAAM,EAAS,6BAA6B;IACvD,YAAY,GAAG,WAAW,EAC1B,MAAM,GAAG,YAAY,EACrB,YAAY,GAAG,EAAE,GAClB,GAAG,MAAM,CAAC;IAEX,OAAO;QACL,EAAE,EAAE,SAAS,IAAI,CAAC,GAAG,EAAE,EAAE;QACzB,MAAM,EAAE,uBAAuB;QAC/B,MAAM;QACN,QAAQ,EAAE,KAAK,EAAW,kCAAkC;QAC5D,QAAQ,EAAE,KAAK;QACf,aAAa,EAAE;YACb,QAAQ;YACR,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,EAAE;YACd,WAAW,EAAE,OAAO;YACpB,KAAK,EAAE,IAAI;SACZ;QACD,iDAAiD;QACjD,sDAAsD;QACtD,IAAI,EAAE;YACJ,EAAE,EAAE,MAAM;YACV,QAAQ,EAAE,YAAY;SACW;QACnC,QAAQ,EAAE,EAAE;QACZ,wEAAwE;QACxE,eAAe,EAAE,IAAkE;QACnF,eAAe,EAAE,EAAE;QACnB,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QACtC,QAAQ,EAAE,KAAK;QACf,YAAY,EAAE,IAA+D;QAC7E,YAAY,EAAE,EAAE;QAChB,iBAAiB,EAAE;YACjB,mBAAmB,EAAE,cAAc;YACnC,yBAAyB,EAAE,cAAc;YACzC,SAAS,EAAE,cAAc;YACzB,YAAY,EAAE,OAAO;SACtB;QACD,MAAM,EAAE,IAAI;QACZ,cAAc,EAAE,IAAI;QACpB,oBAAoB,EAAE,EAAE;QACxB,UAAU,EAAE,UAAU;QACtB,KAAK,EAAE,IAAI;QACX,IAAI,EAAE,IAAI;QACV,eAAe,EAAE,MAAM;QACvB,iBAAiB,EAAE,KAAK;QACxB,KAAK,EAAE,IAAI;KAC+B,CAAC;AAC/C,CAAC"}