@stacksjs/defaults 0.75.77 → 0.75.78

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.
@@ -16,6 +16,7 @@ Full Stripe integration via the Payment facade. Uses Stripe API version `2026-01
16
16
 
17
17
  - Money is `{ amount, currency }` in minor units; `assertMoney` refuses floats before a request leaves.
18
18
  - Methods: `customer`, `charge(payer, money, paymentMethodId)`, `createPayment` (browser completes: `clientConfirmation` is a Stripe client secret or an Adyen session), `refund`, `checkout(payer, { mode, lines, successUrl, ... })`, `paymentMethods`, `removePaymentMethod`, `subscribe`, `cancelSubscription`, `subscriptions`, `verifyWebhook({ payload, headers })` -> `PaymentEvent[]`, `acknowledgeWebhook()`.
19
+ - `checkout` copies `reference` and `metadata` onto the payment / subscription / setup intent it creates (Stripe: `payment_intent_data`, `subscription_data`, `setup_intent_data`), so their webhooks can be attributed. `allowPromotionCodes` and `automaticTax` are Stripe only; Adyen refuses them.
19
20
  - Unsupported operations throw `PaymentUnsupportedError` (driver + operation). Adyen has no catalog, subscriptions, invoices, coupons or portal.
20
21
  - Adyen: Checkout API v72, `X-API-Key`; shopper reference `user-<id>` (no PII); full refunds go to `/reversals`; webhooks verified per item with HMAC-SHA256 over 8 colon-joined fields under the hex key, acknowledged with 202.
21
22
  - `PaymentEvent` carries `provider` and `id` (together, the retry key), `reference` (the payment; for a refund, the payment refunded), `amount` (for a refund, that one refund - Stripe's cumulative `amount_refunded` is turned into a delta from `previous_attributes`) and `reason`. Adyen's id is `eventCode:pspReference:success`, since Adyen may resend a pair with the outcome changed.
@@ -0,0 +1,69 @@
1
+ import { afterEach, describe, expect, it } from 'bun:test'
2
+ import { fetchBillingOverview } from './dashboard'
3
+
4
+ /**
5
+ * The billing page reads what BillingShowAction sends: the stored subscription
6
+ * row beside the payment driver's `SubscriptionSummary`, and the driver's
7
+ * `StoredPaymentMethod`s - JSON, so dates arrive as ISO strings. It used to
8
+ * read Stripe's own objects (`items.data[0].price`, `current_period_end`),
9
+ * which the driver no longer passes to a browser.
10
+ */
11
+ const realFetch = globalThis.fetch
12
+
13
+ function serve(payload: unknown): void {
14
+ globalThis.fetch = (async () => Response.json(payload)) as unknown as typeof fetch
15
+ }
16
+
17
+ afterEach(() => {
18
+ globalThis.fetch = realFetch
19
+ })
20
+
21
+ describe('fetchBillingOverview', () => {
22
+ it('reads the plan, amount and period from the driver\'s subscription summary', async () => {
23
+ serve({
24
+ subscription: {
25
+ subscription: { id: 4, type: 'default', provider_id: 'sub_1', provider_status: 'active' },
26
+ providerSubscription: {
27
+ id: 'sub_1',
28
+ status: 'active',
29
+ price: { id: 'price_pro', name: 'Pro monthly', amount: { amount: 2900, currency: 'eur' }, interval: 'month' },
30
+ currentPeriodEnd: '2026-11-05T00:00:00.000Z',
31
+ cancelAtPeriodEnd: true,
32
+ },
33
+ },
34
+ paymentMethods: [],
35
+ transactions: [],
36
+ })
37
+
38
+ const { subscription } = await fetchBillingOverview()
39
+ expect(subscription).toEqual({
40
+ // The provider's id: what cancelling the subscription takes.
41
+ id: 'sub_1',
42
+ plan: 'default',
43
+ type: 'default',
44
+ status: 'active',
45
+ amount: 2900,
46
+ currency: 'eur',
47
+ periodEnd: '2026-11-05T00:00:00.000Z',
48
+ cancelAtPeriodEnd: true,
49
+ })
50
+ })
51
+
52
+ it('reads the driver\'s stored payment methods, default included', async () => {
53
+ serve({
54
+ subscription: null,
55
+ paymentMethods: [
56
+ { id: 'pm_1', type: 'card', brand: 'visa', last4: '4242', expMonth: 4, expYear: 2030, isDefault: false },
57
+ { id: 'pm_2', type: 'card', brand: 'amex', last4: '0005', expMonth: 1, expYear: 2031, isDefault: true },
58
+ ],
59
+ transactions: [],
60
+ })
61
+
62
+ const { paymentMethods, subscription } = await fetchBillingOverview()
63
+ expect(subscription).toBeNull()
64
+ expect(paymentMethods).toEqual([
65
+ { id: 'pm_1', brand: 'visa', lastFour: '4242', expMonth: 4, expYear: 2030, isDefault: false },
66
+ { id: 'pm_2', brand: 'amex', lastFour: '0005', expMonth: 1, expYear: 2031, isDefault: true },
67
+ ])
68
+ })
69
+ })
@@ -2,7 +2,7 @@
2
2
  "publisher": "Stacks",
3
3
  "name": "vscode-stacks",
4
4
  "displayName": "Stacks",
5
- "version": "0.75.77",
5
+ "version": "0.75.78",
6
6
  "description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
7
7
  "license": "MIT",
8
8
  "funding": "https://github.com/sponsors/chrisbbreuer",
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/defaults",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.77",
5
+ "version": "0.75.78",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/stacksjs/stacks.git",
@@ -55,7 +55,7 @@
55
55
  "dependencies": {
56
56
  "@iconify-json/f7": "^1.2.2",
57
57
  "@iconify-json/hugeicons": "^1.2.35",
58
- "@stacksjs/mobile": "^0.75.77",
58
+ "@stacksjs/mobile": "^0.75.78",
59
59
  "@stacksjs/sanitizer": "^0.2.378",
60
60
  "@xterm/addon-fit": "^0.11.0",
61
61
  "@xterm/xterm": "^6.0.0",