@actuate-media/plugin-commerce 0.0.14 → 0.1.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
1
  # @actuate-media/plugin-commerce
2
2
 
3
+ ## 0.1.1
4
+
5
+ ### Patch Changes
6
+
7
+ - cd8a061: Remove dead sidebar nav from bundled plugins and guard the whole class.
8
+
9
+ `plugin-ai`, `plugin-commerce`, and `plugin-blocks` each advertised
10
+ `adminNavItems` paths (`/ai/*`, `/commerce/*`, `/blocks`) that the admin router
11
+ has no view for — plugins cannot register views, and these plugins register no
12
+ collection backing those paths — so every one of those sidebar links landed on
13
+ the 404 page. The commerce items were also duplicates of the working collection
14
+ nav (its collections already appear under the "Commerce" group at their real
15
+ `/<slug>` routes).
16
+ - Dropped the dead `adminNavItems` from all three plugins. Commerce collections
17
+ remain reachable at `/products`, `/orders`, `/discounts`, …; plugin-ai and
18
+ plugin-blocks are backend/page-builder plugins with no standalone admin route.
19
+ - Added `cms-admin`'s `router/admin-routes` resolver (`adminPathResolves`) plus
20
+ a table-driven test asserting **every** bundled plugin's nav paths resolve to a
21
+ real view, and a drift test that keeps the known-route list in sync with
22
+ `AdminRoot`. This is the systemic guard for a bug class that has now shipped in
23
+ published packages three times.
24
+
25
+ ## 0.1.0
26
+
27
+ ### Minor Changes
28
+
29
+ - d278add: Verify Stripe webhook signatures and lock in the checkout money-mapping.
30
+
31
+ The webhook handler previously "verified" a payload by only checking that the
32
+ signature and secret strings were non-empty before parsing it — so a forged POST
33
+ with any non-empty `Stripe-Signature` would be processed as a real event (a fake
34
+ `payment_intent.succeeded` is a direct fraud risk). `handleStripeWebhook` now
35
+ performs real HMAC-SHA256 verification via a new exported `verifyStripeSignature`
36
+ (a dependency-free equivalent of `stripe.webhooks.constructEvent`: signed-payload
37
+ HMAC, constant-time compare, multi-`v1` key rotation, and timestamp replay
38
+ tolerance).
39
+
40
+ The money-critical checkout mapping (dollar→integer-cents rounding for line items
41
+ and shipping, discounts, metadata) is extracted into a pure, exported
42
+ `buildCheckoutSessionParams` so it is unit-tested independently of the
43
+ (still-stubbed) Stripe API call. Adds 15 behavioral tests covering signature
44
+ accept/reject/replay/rotation, event routing, and cents/shipping/discount mapping.
45
+
3
46
  ## 0.0.14
4
47
 
5
48
  ### Patch Changes
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=checkout.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkout.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/checkout.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,68 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { buildCheckoutSessionParams } from '../stripe/checkout.js';
3
+ const base = { successUrl: '/success', cancelUrl: '/cancel' };
4
+ const lineItem = (over = {}) => ({
5
+ productId: 'p1',
6
+ name: 'Widget',
7
+ quantity: 1,
8
+ unitPrice: 5,
9
+ ...over,
10
+ });
11
+ describe('buildCheckoutSessionParams', () => {
12
+ it('converts dollar unit prices to integer cents (float-safe)', () => {
13
+ const params = buildCheckoutSessionParams({
14
+ ...base,
15
+ lineItems: [lineItem({ unitPrice: 19.99, quantity: 2 })],
16
+ });
17
+ const li = params.line_items[0];
18
+ expect(li.price_data.unit_amount).toBe(1999); // 19.99*100 = 1998.999… → round
19
+ expect(li.quantity).toBe(2);
20
+ expect(params.mode).toBe('payment');
21
+ expect(params.success_url).toBe('/success');
22
+ });
23
+ it('rounds a value that floats below the integer (10.1 → 1010c)', () => {
24
+ const params = buildCheckoutSessionParams({
25
+ ...base,
26
+ lineItems: [lineItem({ unitPrice: 10.1 })],
27
+ });
28
+ expect(params.line_items[0].price_data.unit_amount).toBe(1010);
29
+ });
30
+ it('includes variant metadata + image only when present', () => {
31
+ const withVariant = buildCheckoutSessionParams({
32
+ ...base,
33
+ lineItems: [lineItem({ variantId: 'v1', image: 'https://img/x.png' })],
34
+ });
35
+ const pd = withVariant.line_items[0].price_data.product_data;
36
+ expect(pd.metadata).toEqual({ productId: 'p1', variantId: 'v1' });
37
+ expect(pd.images).toEqual(['https://img/x.png']);
38
+ const bare = buildCheckoutSessionParams({ ...base, lineItems: [lineItem()] });
39
+ const pd2 = bare.line_items[0].price_data.product_data;
40
+ expect(pd2.metadata).toEqual({ productId: 'p1' });
41
+ expect(pd2.images).toEqual([]);
42
+ });
43
+ it('maps shipping options to fixed_amount cents', () => {
44
+ const params = buildCheckoutSessionParams({
45
+ ...base,
46
+ lineItems: [lineItem()],
47
+ shippingOptions: [{ id: 's1', label: 'Express', amount: 12.5 }],
48
+ });
49
+ const so = params.shipping_options[0];
50
+ expect(so.shipping_rate_data.fixed_amount).toEqual({ amount: 1250, currency: 'usd' });
51
+ expect(so.shipping_rate_data.display_name).toBe('Express');
52
+ });
53
+ it('adds discounts + customer_email only when provided', () => {
54
+ const full = buildCheckoutSessionParams({
55
+ ...base,
56
+ lineItems: [lineItem()],
57
+ discountCode: 'SAVE10',
58
+ customerEmail: 'a@b.com',
59
+ });
60
+ expect(full.discounts).toEqual([{ coupon: 'SAVE10' }]);
61
+ expect(full.customer_email).toBe('a@b.com');
62
+ const bare = buildCheckoutSessionParams({ ...base, lineItems: [lineItem()] });
63
+ expect(bare.discounts).toBeUndefined();
64
+ expect(bare.customer_email).toBeUndefined();
65
+ expect(bare.shipping_options).toBeUndefined();
66
+ });
67
+ });
68
+ //# sourceMappingURL=checkout.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkout.test.js","sourceRoot":"","sources":["../../src/__tests__/checkout.test.ts"],"names":[],"mappings":"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"}
@@ -13,18 +13,13 @@ describe('commerce', () => {
13
13
  expect(plugin.collections).toBeDefined();
14
14
  expect(Object.keys(plugin.collections ?? {}).length).toBeGreaterThan(0);
15
15
  });
16
- it('registers four commerce admin nav items', () => {
16
+ it('does not register dead admin nav items', () => {
17
+ // The old /commerce/* nav paths had no admin view and duplicated the
18
+ // working collection nav — commerce collections already surface under
19
+ // their "Commerce" group at /products, /orders, /discounts, …. Guarded
20
+ // centrally by cms-admin's plugin-nav-resolves test.
17
21
  const plugin = commercePlugin();
18
- expect(plugin.adminNavItems).toEqual([
19
- { label: 'Products', icon: 'package', path: '/commerce/products' },
20
- { label: 'Orders', icon: 'shopping-cart', path: '/commerce/orders' },
21
- { label: 'Discounts', icon: 'percent', path: '/commerce/discounts' },
22
- {
23
- label: 'Commerce Dashboard',
24
- icon: 'bar-chart',
25
- path: '/commerce/dashboard',
26
- },
27
- ]);
22
+ expect(plugin.adminNavItems).toBeUndefined();
28
23
  });
29
24
  it('registers hooks', () => {
30
25
  const plugin = commercePlugin();
@@ -1 +1 @@
1
- {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;YAC/B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;YACnC,MAAM,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC3C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAA;YACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;QACzE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;YAC/B,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC;gBACnC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,oBAAoB,EAAE;gBAClE,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,kBAAkB,EAAE;gBACpE,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,qBAAqB,EAAE;gBACpE;oBACE,KAAK,EAAE,oBAAoB;oBAC3B,IAAI,EAAE,WAAW;oBACjB,IAAI,EAAE,qBAAqB;iBAC5B;aACF,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;YACzB,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;YAC/B,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;YAC/C,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAA;QACzD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;YACtC,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,CAAC,CAAA;YACjC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACtC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../src/__tests__/index.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,CAAC,cAAc,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;YAC/B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAA;YACnC,MAAM,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC3C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAA;YACxC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;QACzE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,qEAAqE;YACrE,sEAAsE;YACtE,uEAAuE;YACvE,qDAAqD;YACrD,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;YAC/B,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,aAAa,EAAE,CAAA;QAC9C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;YACzB,MAAM,MAAM,GAAG,cAAc,EAAE,CAAA;YAC/B,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;YAC/C,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAA;QACzD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;YACtC,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,CAAC,CAAA;YACjC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACtC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=webhooks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/webhooks.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,71 @@
1
+ import { createHmac } from 'node:crypto';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { handleStripeWebhook, verifyStripeSignature } from '../stripe/webhooks.js';
4
+ const SECRET = 'whsec_test';
5
+ const NOW = 1_700_000_000_000; // fixed ms for deterministic replay checks
6
+ const NOW_SEC = Math.floor(NOW / 1000);
7
+ function sign(payload, ts = NOW_SEC, secret = SECRET) {
8
+ const sig = createHmac('sha256', secret).update(`${ts}.${payload}`).digest('hex');
9
+ return `t=${ts},v1=${sig}`;
10
+ }
11
+ describe('verifyStripeSignature', () => {
12
+ it('accepts a valid signature within the tolerance window', () => {
13
+ const payload = JSON.stringify({ type: 'x' });
14
+ expect(() => verifyStripeSignature(payload, sign(payload), SECRET, { now: NOW })).not.toThrow();
15
+ });
16
+ it('rejects a tampered payload', () => {
17
+ const header = sign('{"amount":100}');
18
+ expect(() => verifyStripeSignature('{"amount":999}', header, SECRET, { now: NOW })).toThrow(/mismatch/);
19
+ });
20
+ it('rejects a signature made with a different secret', () => {
21
+ const payload = '{}';
22
+ expect(() => verifyStripeSignature(payload, sign(payload, NOW_SEC, 'whsec_other'), SECRET, { now: NOW })).toThrow(/mismatch/);
23
+ });
24
+ it('rejects an out-of-tolerance timestamp (replay protection)', () => {
25
+ const payload = '{}';
26
+ expect(() => verifyStripeSignature(payload, sign(payload, NOW_SEC - 10_000), SECRET, { now: NOW })).toThrow(/tolerance/);
27
+ });
28
+ it('rejects a missing signature or missing secret', () => {
29
+ expect(() => verifyStripeSignature('{}', '', SECRET, { now: NOW })).toThrow(/Missing webhook signature/);
30
+ expect(() => verifyStripeSignature('{}', sign('{}'), '', { now: NOW })).toThrow(/Missing webhook signing secret/);
31
+ });
32
+ it('rejects a malformed signature header', () => {
33
+ expect(() => verifyStripeSignature('{}', 'garbage', SECRET, { now: NOW })).toThrow(/Malformed/);
34
+ });
35
+ it('accepts when any of multiple v1 signatures matches (key rotation)', () => {
36
+ const payload = '{}';
37
+ const good = createHmac('sha256', SECRET).update(`${NOW_SEC}.${payload}`).digest('hex');
38
+ const header = `t=${NOW_SEC},v1=deadbeef,v1=${good}`;
39
+ expect(() => verifyStripeSignature(payload, header, SECRET, { now: NOW })).not.toThrow();
40
+ });
41
+ });
42
+ describe('handleStripeWebhook', () => {
43
+ function evt(type, object = {}) {
44
+ const payload = JSON.stringify({ type, data: { object } });
45
+ return { payload, header: sign(payload) };
46
+ }
47
+ it('routes each known event type to handled=true', async () => {
48
+ for (const type of [
49
+ 'checkout.session.completed',
50
+ 'payment_intent.succeeded',
51
+ 'charge.refunded',
52
+ ]) {
53
+ const { payload, header } = evt(type);
54
+ const res = await handleStripeWebhook(payload, header, SECRET, { now: NOW });
55
+ expect(res).toMatchObject({ handled: true, event: type });
56
+ }
57
+ });
58
+ it('returns handled=false for an unknown but authentic event', async () => {
59
+ const { payload, header } = evt('customer.created');
60
+ const res = await handleStripeWebhook(payload, header, SECRET, { now: NOW });
61
+ expect(res).toEqual({ handled: false, event: 'customer.created' });
62
+ });
63
+ it('does NOT process a forged event (invalid signature)', async () => {
64
+ // A fake "payment succeeded" — this must be rejected, not handled.
65
+ const payload = JSON.stringify({ type: 'payment_intent.succeeded', data: { object: {} } });
66
+ const res = await handleStripeWebhook(payload, `t=${NOW_SEC},v1=forged`, SECRET, { now: NOW });
67
+ expect(res.handled).toBe(false);
68
+ expect(res.error).toMatch(/verification failed/i);
69
+ });
70
+ });
71
+ //# sourceMappingURL=webhooks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.test.js","sourceRoot":"","sources":["../../src/__tests__/webhooks.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAElF,MAAM,MAAM,GAAG,YAAY,CAAA;AAC3B,MAAM,GAAG,GAAG,iBAAiB,CAAA,CAAC,2CAA2C;AACzE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAA;AAEtC,SAAS,IAAI,CAAC,OAAe,EAAE,KAAa,OAAO,EAAE,MAAM,GAAG,MAAM;IAClE,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACjF,OAAO,KAAK,EAAE,OAAO,GAAG,EAAE,CAAA;AAC5B,CAAC;AAED,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;QAC7C,MAAM,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAA;IACjG,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAA;QACrC,MAAM,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CACzF,UAAU,CACX,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,OAAO,GAAG,IAAI,CAAA;QACpB,MAAM,CAAC,GAAG,EAAE,CACV,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAC5F,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACvB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,OAAO,GAAG,IAAI,CAAA;QACpB,MAAM,CAAC,GAAG,EAAE,CACV,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CACtF,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IACxB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CACzE,2BAA2B,CAC5B,CAAA;QACD,MAAM,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAC7E,gCAAgC,CACjC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IACjG,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,OAAO,GAAG,IAAI,CAAA;QACpB,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACvF,MAAM,MAAM,GAAG,KAAK,OAAO,mBAAmB,IAAI,EAAE,CAAA;QACpD,MAAM,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAA;IAC1F,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,SAAS,GAAG,CAAC,IAAY,EAAE,SAAkC,EAAE;QAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAA;QAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAA;IAC3C,CAAC;IAED,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,KAAK,MAAM,IAAI,IAAI;YACjB,4BAA4B;YAC5B,0BAA0B;YAC1B,iBAAiB;SAClB,EAAE,CAAC;YACF,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;YACrC,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;YAC5E,MAAM,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3D,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,kBAAkB,CAAC,CAAA;QACnD,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;QAC5E,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAA;IACpE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,mEAAmE;QACnE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,0BAA0B,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;QAC1F,MAAM,GAAG,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE,KAAK,OAAO,YAAY,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;QAC9F,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC/B,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAKpF,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE;QACP,SAAS,EAAE,MAAM,CAAA;QACjB,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;IACD,GAAG,CAAC,EAAE;QACJ,aAAa,CAAC,EAAE,OAAO,CAAA;KACxB,CAAA;IACD,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,OAAO,CAAA;KAClB,CAAA;CACF;AAED,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,MAAM,GAAE,oBAAyB,GAAG,gBAAgB,CAiBlF;AAED,YAAY,EAAE,oBAAoB,IAAI,cAAc,EAAE,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AAKpF,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE;QACP,SAAS,EAAE,MAAM,CAAA;QACjB,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;IACD,GAAG,CAAC,EAAE;QACJ,aAAa,CAAC,EAAE,OAAO,CAAA;KACxB,CAAA;IACD,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,OAAO,CAAA;KAClB,CAAA;CACF;AAED,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,MAAM,GAAE,oBAAyB,GAAG,gBAAgB,CAYlF;AAED,YAAY,EAAE,oBAAoB,IAAI,cAAc,EAAE,CAAA;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}
package/dist/index.js CHANGED
@@ -8,16 +8,11 @@ export function commercePlugin(config = {}) {
8
8
  name: 'commerce',
9
9
  fields: commerceFields,
10
10
  collections: commerceCollections,
11
- adminNavItems: [
12
- { label: 'Products', icon: 'package', path: '/commerce/products' },
13
- { label: 'Orders', icon: 'shopping-cart', path: '/commerce/orders' },
14
- { label: 'Discounts', icon: 'percent', path: '/commerce/discounts' },
15
- {
16
- label: 'Commerce Dashboard',
17
- icon: 'bar-chart',
18
- path: '/commerce/dashboard',
19
- },
20
- ],
11
+ // No adminNavItems: the commerce collections already surface in the sidebar
12
+ // under their "Commerce" group at their real /<slug> routes (/products,
13
+ // /orders, /discounts, …). The old /commerce/* items pointed at routes the
14
+ // admin router has no view for, so they were dead 404s that also duplicated
15
+ // the working collection nav. Guarded by cms-admin's plugin-nav-resolves test.
21
16
  hooks: commerceHooks,
22
17
  });
23
18
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAyB,MAAM,gCAAgC,CAAA;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAgB1C,iGAAiG;AACjG,MAAM,UAAU,cAAc,CAAC,SAA+B,EAAE;IAC9D,OAAO,YAAY,CAAC;QAClB,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,cAAc;QACtB,WAAW,EAAE,mBAAmB;QAChC,aAAa,EAAE;YACb,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,oBAAoB,EAAE;YAClE,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,kBAAkB,EAAE;YACpE,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,qBAAqB,EAAE;YACpE;gBACE,KAAK,EAAE,oBAAoB;gBAC3B,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,qBAAqB;aAC5B;SACF;QACD,KAAK,EAAE,aAAa;KACrB,CAAC,CAAA;AACJ,CAAC;AAGD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAyB,MAAM,gCAAgC,CAAA;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAgB1C,iGAAiG;AACjG,MAAM,UAAU,cAAc,CAAC,SAA+B,EAAE;IAC9D,OAAO,YAAY,CAAC;QAClB,IAAI,EAAE,UAAU;QAChB,MAAM,EAAE,cAAc;QACtB,WAAW,EAAE,mBAAmB;QAChC,4EAA4E;QAC5E,wEAAwE;QACxE,2EAA2E;QAC3E,4EAA4E;QAC5E,+EAA+E;QAC/E,KAAK,EAAE,aAAa;KACrB,CAAC,CAAA;AACJ,CAAC;AAGD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA"}
@@ -24,6 +24,16 @@ export interface CheckoutSession {
24
24
  url: string;
25
25
  expiresAt: Date;
26
26
  }
27
+ /**
28
+ * Build the Stripe Checkout Session params from cart line items and options.
29
+ *
30
+ * Pure and money-critical: it converts dollar amounts to integer cents
31
+ * (`Math.round(x * 100)`) for every line item and shipping rate. Extracted from
32
+ * `createCheckoutSession` so this mapping is unit-testable independently of the
33
+ * (still-stubbed) Stripe API call — a cents-rounding or field-shape bug here is
34
+ * a real overcharge/undercharge once the SDK is wired.
35
+ */
36
+ export declare function buildCheckoutSessionParams(options: CheckoutSessionOptions): Record<string, unknown>;
27
37
  /** Creates a Stripe Checkout session from cart line items and configuration. */
28
38
  export declare function createCheckoutSession(options: CheckoutSessionOptions): Promise<CheckoutSession>;
29
39
  //# sourceMappingURL=checkout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../../src/stripe/checkout.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,gBAAgB,EAAE,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,cAAc,EAAE,CAAA;IAClC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,IAAI,CAAA;CAChB;AAED,gFAAgF;AAChF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC,CAgD1B"}
1
+ {"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../../src/stripe/checkout.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,gBAAgB,EAAE,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,cAAc,EAAE,CAAA;IAClC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,IAAI,CAAA;CAChB;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,sBAAsB,GAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwCzB;AAED,gFAAgF;AAChF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC,CAa1B"}
@@ -1,5 +1,13 @@
1
- /** Creates a Stripe Checkout session from cart line items and configuration. */
2
- export async function createCheckoutSession(options) {
1
+ /**
2
+ * Build the Stripe Checkout Session params from cart line items and options.
3
+ *
4
+ * Pure and money-critical: it converts dollar amounts to integer cents
5
+ * (`Math.round(x * 100)`) for every line item and shipping rate. Extracted from
6
+ * `createCheckoutSession` so this mapping is unit-testable independently of the
7
+ * (still-stubbed) Stripe API call — a cents-rounding or field-shape bug here is
8
+ * a real overcharge/undercharge once the SDK is wired.
9
+ */
10
+ export function buildCheckoutSessionParams(options) {
3
11
  const stripeLineItems = options.lineItems.map((item) => ({
4
12
  price_data: {
5
13
  currency: 'usd',
@@ -34,7 +42,13 @@ export async function createCheckoutSession(options) {
34
42
  if (options.discountCode) {
35
43
  sessionParams['discounts'] = [{ coupon: options.discountCode }];
36
44
  }
45
+ return sessionParams;
46
+ }
47
+ /** Creates a Stripe Checkout session from cart line items and configuration. */
48
+ export async function createCheckoutSession(options) {
49
+ const sessionParams = buildCheckoutSessionParams(options);
37
50
  // TODO: Call Stripe SDK — stripe.checkout.sessions.create(sessionParams)
51
+ void sessionParams;
38
52
  const expiresAt = new Date();
39
53
  expiresAt.setMinutes(expiresAt.getMinutes() + 30);
40
54
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"checkout.js","sourceRoot":"","sources":["../../src/stripe/checkout.ts"],"names":[],"mappings":"AA8BA,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAA+B;IAE/B,MAAM,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvD,UAAU,EAAE;YACV,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE;gBACZ,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;gBACtC,QAAQ,EAAE;oBACR,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACzD;aACF;YACD,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;SAC9C;QACD,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACxB,CAAC,CAAC,CAAA;IAEH,MAAM,aAAa,GAA4B;QAC7C,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,eAAe;QAC3B,WAAW,EAAE,OAAO,CAAC,UAAU;QAC/B,UAAU,EAAE,OAAO,CAAC,SAAS;QAC7B,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAA;IAED,IAAI,OAAO,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;QACpC,aAAa,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACxE,kBAAkB,EAAE;gBAClB,YAAY,EAAE,GAAG,CAAC,KAAK;gBACvB,IAAI,EAAE,cAAc;gBACpB,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE;aACxE;SACF,CAAC,CAAC,CAAA;IACL,CAAC;IAED,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,aAAa,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;IACjE,CAAC;IAED,yEAAyE;IACzE,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAA;IAC5B,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAA;IAEjD,OAAO;QACL,EAAE,EAAE,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE;QAC3B,GAAG,EAAE,2CAA2C,IAAI,CAAC,GAAG,EAAE,EAAE;QAC5D,SAAS;KACV,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"checkout.js","sourceRoot":"","sources":["../../src/stripe/checkout.ts"],"names":[],"mappings":"AA8BA;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAA+B;IAE/B,MAAM,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACvD,UAAU,EAAE;YACV,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE;gBACZ,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;gBACtC,QAAQ,EAAE;oBACR,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACzD;aACF;YACD,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;SAC9C;QACD,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACxB,CAAC,CAAC,CAAA;IAEH,MAAM,aAAa,GAA4B;QAC7C,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,eAAe;QAC3B,WAAW,EAAE,OAAO,CAAC,UAAU;QAC/B,UAAU,EAAE,OAAO,CAAC,SAAS;QAC7B,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5E,CAAA;IAED,IAAI,OAAO,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;QACpC,aAAa,CAAC,kBAAkB,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACxE,kBAAkB,EAAE;gBAClB,YAAY,EAAE,GAAG,CAAC,KAAK;gBACvB,IAAI,EAAE,cAAc;gBACpB,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE;aACxE;SACF,CAAC,CAAC,CAAA;IACL,CAAC;IAED,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,aAAa,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;IACjE,CAAC;IAED,OAAO,aAAa,CAAA;AACtB,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAA+B;IAE/B,MAAM,aAAa,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAA;IAEzD,yEAAyE;IACzE,KAAK,aAAa,CAAA;IAClB,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAA;IAC5B,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAA;IAEjD,OAAO;QACL,EAAE,EAAE,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE;QAC3B,GAAG,EAAE,2CAA2C,IAAI,CAAC,GAAG,EAAE,EAAE;QAC5D,SAAS;KACV,CAAA;AACH,CAAC"}
@@ -3,6 +3,26 @@ export interface WebhookResult {
3
3
  event: string;
4
4
  error?: string;
5
5
  }
6
+ export interface VerifyOptions {
7
+ /** Reject events whose timestamp is further than this from now. Default 300s. */
8
+ toleranceSeconds?: number;
9
+ /** Current time in ms — injectable for deterministic tests. Default Date.now(). */
10
+ now?: number;
11
+ }
12
+ /**
13
+ * Verify a Stripe webhook signature (the `Stripe-Signature` header) against the
14
+ * raw request body using the endpoint's signing secret. This is a
15
+ * dependency-free equivalent of `stripe.webhooks.constructEvent`:
16
+ *
17
+ * signed_payload = `${t}.${rawBody}`
18
+ * expected = HMAC-SHA256(signed_payload, secret) // hex
19
+ * valid = any provided v1 == expected (constant-time) AND |now - t| ≤ tolerance
20
+ *
21
+ * Throws on any failure. Multiple `v1` signatures (key rotation) are supported.
22
+ * Without this, a forged POST with any non-empty signature would be processed —
23
+ * a fake "payment succeeded" is a direct money/fraud risk.
24
+ */
25
+ export declare function verifyStripeSignature(payload: string, signatureHeader: string, secret: string, options?: VerifyOptions): void;
6
26
  /** Verifies and processes a Stripe webhook event payload. */
7
- export declare function handleStripeWebhook(payload: string, signature: string, secret: string): Promise<WebhookResult>;
27
+ export declare function handleStripeWebhook(payload: string, signature: string, secret: string, options?: VerifyOptions): Promise<WebhookResult>;
8
28
  //# sourceMappingURL=webhooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/stripe/webhooks.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAqCD,6DAA6D;AAC7D,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,CAAC,CAiCxB"}
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/stripe/webhooks.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAUD,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC1B,IAAI,CAkCN;AAgCD,6DAA6D;AAC7D,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,aAAa,CAAC,CA8BxB"}
@@ -1,3 +1,57 @@
1
+ import { createHmac, timingSafeEqual } from 'node:crypto';
2
+ /** Default replay-protection window, matching Stripe's SDK (5 minutes). */
3
+ const DEFAULT_TOLERANCE_SECONDS = 300;
4
+ /**
5
+ * Verify a Stripe webhook signature (the `Stripe-Signature` header) against the
6
+ * raw request body using the endpoint's signing secret. This is a
7
+ * dependency-free equivalent of `stripe.webhooks.constructEvent`:
8
+ *
9
+ * signed_payload = `${t}.${rawBody}`
10
+ * expected = HMAC-SHA256(signed_payload, secret) // hex
11
+ * valid = any provided v1 == expected (constant-time) AND |now - t| ≤ tolerance
12
+ *
13
+ * Throws on any failure. Multiple `v1` signatures (key rotation) are supported.
14
+ * Without this, a forged POST with any non-empty signature would be processed —
15
+ * a fake "payment succeeded" is a direct money/fraud risk.
16
+ */
17
+ export function verifyStripeSignature(payload, signatureHeader, secret, options = {}) {
18
+ if (!secret)
19
+ throw new Error('Missing webhook signing secret');
20
+ if (!signatureHeader)
21
+ throw new Error('Missing webhook signature');
22
+ let timestamp;
23
+ const signatures = [];
24
+ for (const part of signatureHeader.split(',')) {
25
+ const eq = part.indexOf('=');
26
+ if (eq === -1)
27
+ continue;
28
+ const key = part.slice(0, eq).trim();
29
+ const value = part.slice(eq + 1).trim();
30
+ if (key === 't')
31
+ timestamp = value;
32
+ else if (key === 'v1')
33
+ signatures.push(value);
34
+ }
35
+ if (!timestamp || signatures.length === 0) {
36
+ throw new Error('Malformed webhook signature header');
37
+ }
38
+ const timestampSec = Number(timestamp);
39
+ if (!Number.isFinite(timestampSec))
40
+ throw new Error('Invalid webhook timestamp');
41
+ const nowSec = Math.floor((options.now ?? Date.now()) / 1000);
42
+ const tolerance = options.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
43
+ if (Math.abs(nowSec - timestampSec) > tolerance) {
44
+ throw new Error('Webhook timestamp outside tolerance (possible replay)');
45
+ }
46
+ const expected = createHmac('sha256', secret).update(`${timestamp}.${payload}`).digest('hex');
47
+ const expectedBuf = Buffer.from(expected);
48
+ const matches = signatures.some((sig) => {
49
+ const sigBuf = Buffer.from(sig);
50
+ return sigBuf.length === expectedBuf.length && timingSafeEqual(sigBuf, expectedBuf);
51
+ });
52
+ if (!matches)
53
+ throw new Error('Webhook signature mismatch');
54
+ }
1
55
  async function handleCheckoutCompleted(session) {
2
56
  const customerEmail = session['customer_email'];
3
57
  const paymentIntentId = session['payment_intent'];
@@ -19,13 +73,10 @@ async function handleChargeRefunded(charge) {
19
73
  console.info(`[commerce:webhook] Charge refunded — charge=${chargeId} intent=${paymentIntentId} refunded=${amountRefunded}`);
20
74
  }
21
75
  /** Verifies and processes a Stripe webhook event payload. */
22
- export async function handleStripeWebhook(payload, signature, secret) {
76
+ export async function handleStripeWebhook(payload, signature, secret, options = {}) {
23
77
  let event;
24
78
  try {
25
- // TODO: Replace with stripe.webhooks.constructEvent(payload, signature, secret)
26
- if (!signature || !secret) {
27
- throw new Error('Missing webhook signature or secret');
28
- }
79
+ verifyStripeSignature(payload, signature, secret, options);
29
80
  event = JSON.parse(payload);
30
81
  }
31
82
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/stripe/webhooks.ts"],"names":[],"mappings":"AAWA,KAAK,UAAU,uBAAuB,CAAC,OAAgC;IACrE,MAAM,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAuB,CAAA;IACrE,MAAM,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAuB,CAAA;IACvE,MAAM,WAAW,GAAG,OAAO,CAAC,cAAc,CAAuB,CAAA;IAEjE,8CAA8C;IAC9C,OAAO,CAAC,IAAI,CACV,iDAAiD,aAAa,YAAY,eAAe,UAAU,WAAW,EAAE,CACjH,CAAA;AACH,CAAC;AAED,KAAK,UAAU,sBAAsB,CAAC,aAAsC;IAC1E,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAuB,CAAA;IAC1D,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAuB,CAAA;IAE5D,oDAAoD;IACpD,OAAO,CAAC,IAAI,CAAC,iDAAiD,QAAQ,WAAW,MAAM,EAAE,CAAC,CAAA;AAC5F,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,MAA+B;IACjE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAuB,CAAA;IACnD,MAAM,cAAc,GAAG,MAAM,CAAC,iBAAiB,CAAuB,CAAA;IACtE,MAAM,eAAe,GAAG,MAAM,CAAC,gBAAgB,CAAuB,CAAA;IAEtE,wEAAwE;IACxE,OAAO,CAAC,IAAI,CACV,+CAA+C,QAAQ,WAAW,eAAe,aAAa,cAAc,EAAE,CAC/G,CAAA;AACH,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAe,EACf,SAAiB,EACjB,MAAc;IAEd,IAAI,KAAkB,CAAA;IAEtB,IAAI,CAAC;QACH,gFAAgF;QAChF,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;QACxD,CAAC;QACD,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAA;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,gCAAgC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;SAC1F,CAAA;IACH,CAAC;IAED,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,4BAA4B;YAC/B,MAAM,uBAAuB,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAChD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;QAE7C,KAAK,0BAA0B;YAC7B,MAAM,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAC/C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;QAE7C,KAAK,iBAAiB;YACpB,MAAM,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YAC7C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;QAE7C;YACE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;IAChD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/stripe/webhooks.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actuate-media/plugin-commerce",
3
- "version": "0.0.14",
3
+ "version": "0.1.1",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,7 +28,7 @@
28
28
  "@types/react": "^19.0.0",
29
29
  "typescript": "^5.7.0",
30
30
  "vitest": "^4.1.0",
31
- "@actuate-media/cms-core": "0.93.0"
31
+ "@actuate-media/cms-core": "0.93.3"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "@actuate-media/cms-core": ">=0.1.0",