@birtalanrobert/commerce 2.0.0 → 3.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.
package/README.md CHANGED
@@ -27,7 +27,7 @@ canTakeMoney('pending'); // false — the provider has not verified them yet
27
27
  ## Using it in a NestJS application
28
28
 
29
29
  ```ts
30
- import { StripeConnect } from '@birtalanrobert/commerce';
30
+ import { StripeConnect } from '@birtalanrobert/commerce/stripe';
31
31
  import {
32
32
  COMMERCE_PROVIDER,
33
33
  CommerceService,
@@ -55,6 +55,20 @@ export class PaymentsModule {}
55
55
  Register `commerceEntities` and `commerceMigrations` with the data source, as
56
56
  with every other package here.
57
57
 
58
+ Where a deployment takes no card payments — which is most of them in some
59
+ categories — provide `NoPayments` instead of `StripeConnect`. It reports `none`
60
+ and refuses every operation, so every gate that already asks whether a business
61
+ can be paid out answers no. **Do not construct the vendor client with an empty
62
+ key**: it throws inside its own constructor and the application does not start.
63
+
64
+ **Three entry points, and the split is deliberate.** The root is pure — what a
65
+ deposit comes to, whether a business may sell yet, whether a payment can still
66
+ be refunded — because a console decides all three while somebody drags a
67
+ slider. `/nestjs` holds the service, the entities and the migrations.
68
+ `/stripe` holds the vendor's client on its own, because importing it pulls in
69
+ the whole SDK, and a barrel that re-exported it once put a payments SDK into a
70
+ booking console's first load.
71
+
58
72
  ## The parts worth knowing before using it
59
73
 
60
74
  - **A business cannot be charged for until the provider says it may be paid
package/dist/index.d.ts CHANGED
@@ -12,13 +12,15 @@
12
12
  * the mistake that makes both hard to reason about — they differ in who pays
13
13
  * whom, in which Stripe account, and in what happens when one fails.
14
14
  *
15
- * **This entry point is pure.** What a deposit comes to and whether a business
16
- * may sell yet are decided without a database or a provider, because a console
17
- * shows both while somebody drags a slider. Everything needing storage or
18
- * somebody else's money-moving licence is behind `/nestjs`.
15
+ * **This entry point is pure**, and stays that way by leaving things out. What
16
+ * a deposit comes to and whether a business may sell yet are decided without a
17
+ * database or a provider, because a console shows both while somebody drags a
18
+ * slider. Storage and the container are behind `/nestjs`; the Stripe client is
19
+ * behind `/stripe`, because a barrel that re-exports it puts the vendor's whole
20
+ * SDK into every bundle that wanted to divide a price by three.
19
21
  */
20
22
  export { balanceAfter, canTakeMoney, depositFor, payoutBlockReason, type DepositKind, type DepositPolicy, type PayoutStatus, } from './deposits';
21
23
  export { isRefundable, refundableAmount, type PaymentKind, type PaymentMethod, type PaymentState, } from './payments';
24
+ export { NoPayments } from './providers/none';
22
25
  export type { ChargeRequest, ChargeResult, OnboardingLink, PaymentProvider, ProviderAccount, ProviderEvent, RefundRequest, SaveCardRequest, SaveCardResult, StoredCard, } from './providers/port';
23
- export { StripeConnect, type StripeConnectOptions } from './providers/stripe';
24
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAEpB,YAAY,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,eAAe,EACf,eAAe,EACf,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,EACd,UAAU,GACX,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,YAAY,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,eAAe,EACf,eAAe,EACf,aAAa,EACb,aAAa,EACb,eAAe,EACf,cAAc,EACd,UAAU,GACX,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.StripeConnect = exports.refundableAmount = exports.isRefundable = exports.payoutBlockReason = exports.depositFor = exports.canTakeMoney = exports.balanceAfter = void 0;
3
+ exports.NoPayments = exports.refundableAmount = exports.isRefundable = exports.payoutBlockReason = exports.depositFor = exports.canTakeMoney = exports.balanceAfter = void 0;
4
4
  /**
5
5
  * Taking money on a business's behalf.
6
6
  *
@@ -15,10 +15,12 @@ exports.StripeConnect = exports.refundableAmount = exports.isRefundable = export
15
15
  * the mistake that makes both hard to reason about — they differ in who pays
16
16
  * whom, in which Stripe account, and in what happens when one fails.
17
17
  *
18
- * **This entry point is pure.** What a deposit comes to and whether a business
19
- * may sell yet are decided without a database or a provider, because a console
20
- * shows both while somebody drags a slider. Everything needing storage or
21
- * somebody else's money-moving licence is behind `/nestjs`.
18
+ * **This entry point is pure**, and stays that way by leaving things out. What
19
+ * a deposit comes to and whether a business may sell yet are decided without a
20
+ * database or a provider, because a console shows both while somebody drags a
21
+ * slider. Storage and the container are behind `/nestjs`; the Stripe client is
22
+ * behind `/stripe`, because a barrel that re-exports it puts the vendor's whole
23
+ * SDK into every bundle that wanted to divide a price by three.
22
24
  */
23
25
  var deposits_1 = require("./deposits");
24
26
  Object.defineProperty(exports, "balanceAfter", { enumerable: true, get: function () { return deposits_1.balanceAfter; } });
@@ -28,6 +30,16 @@ Object.defineProperty(exports, "payoutBlockReason", { enumerable: true, get: fun
28
30
  var payments_1 = require("./payments");
29
31
  Object.defineProperty(exports, "isRefundable", { enumerable: true, get: function () { return payments_1.isRefundable; } });
30
32
  Object.defineProperty(exports, "refundableAmount", { enumerable: true, get: function () { return payments_1.refundableAmount; } });
31
- var stripe_1 = require("./providers/stripe");
32
- Object.defineProperty(exports, "StripeConnect", { enumerable: true, get: function () { return stripe_1.StripeConnect; } });
33
+ var none_1 = require("./providers/none");
34
+ Object.defineProperty(exports, "NoPayments", { enumerable: true, get: function () { return none_1.NoPayments; } });
35
+ /*
36
+ * `StripeConnect` is deliberately NOT re-exported here.
37
+ *
38
+ * It lives at `@birtalanrobert/commerce/stripe`, because importing it pulls in
39
+ * the vendor's whole SDK — and this entry point is imported by browser code
40
+ * that only wants to know what a deposit comes to. Re-exporting it put 30 KB of
41
+ * a payments SDK into a console's first load for a screen that never calls it:
42
+ * a barrel is a bundling decision, and the only way to keep this one pure is to
43
+ * leave the heavy thing out of it.
44
+ */
33
45
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,uCAQoB;AAPlB,wGAAA,YAAY,OAAA;AACZ,wGAAA,YAAY,OAAA;AACZ,sGAAA,UAAU,OAAA;AACV,6GAAA,iBAAiB,OAAA;AAMnB,uCAMoB;AALlB,wGAAA,YAAY,OAAA;AACZ,4GAAA,gBAAgB,OAAA;AAmBlB,6CAA8E;AAArE,uGAAA,aAAa,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,uCAQoB;AAPlB,wGAAA,YAAY,OAAA;AACZ,wGAAA,YAAY,OAAA;AACZ,sGAAA,UAAU,OAAA;AACV,6GAAA,iBAAiB,OAAA;AAMnB,uCAMoB;AALlB,wGAAA,YAAY,OAAA;AACZ,4GAAA,gBAAgB,OAAA;AAMlB,yCAA8C;AAArC,kGAAA,UAAU,OAAA;AAenB;;;;;;;;;GASG"}
@@ -16,6 +16,6 @@ import { Payment, PaymentRefund } from './payment.entity';
16
16
  import { SavedCard } from './saved-card.entity';
17
17
  import { CreateCommerce1789800000000 } from '../migrations/1789800000000-CreateCommerce';
18
18
  /** Register with the data source, the way every other mortar package is. */
19
- export declare const commerceEntities: (typeof PayoutAccount | typeof Payment | typeof PaymentRefund | typeof SavedCard)[];
19
+ export declare const commerceEntities: (typeof PayoutAccount | typeof Payment | typeof SavedCard | typeof PaymentRefund)[];
20
20
  export declare const commerceMigrations: (typeof CreateCommerce1789800000000)[];
21
21
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,50 @@
1
+ import type { ChargeRequest, ChargeResult, OnboardingLink, PaymentProvider, ProviderAccount, RefundRequest, SaveCardRequest, SaveCardResult, StoredCard } from './port';
2
+ /**
3
+ * No payment provider at all, said out loud rather than by failing.
4
+ *
5
+ * **Online payment is optional and never mandatory**, and this is what makes
6
+ * that true in the code rather than only in a document. A salon that takes cash
7
+ * at the counter and has never heard of Stripe runs its whole diary, writes
8
+ * down what it took, and reports on it — and nothing about that deployment
9
+ * should require a payment account to exist, least of all the application
10
+ * starting up.
11
+ *
12
+ * The alternative that looks simpler is constructing the vendor's client with
13
+ * an empty key. It throws inside its own constructor, and the whole API fails
14
+ * to boot — which is how this was found.
15
+ *
16
+ * **Not a permissive no-op.** Every operation refuses, and the account reports
17
+ * `none`, so every gate that already asks "can this business be paid out?"
18
+ * answers no without a special case. A provider that quietly returned success
19
+ * would write a trail of payments that never happened, which is worse than the
20
+ * crash it replaced.
21
+ */
22
+ export declare class NoPayments implements PaymentProvider {
23
+ readonly name = "none";
24
+ onboard(): Promise<OnboardingLink>;
25
+ /**
26
+ * `none` rather than `pending`.
27
+ *
28
+ * They are different facts: `pending` means the provider is still checking,
29
+ * and a business told that will wait for an email that is never coming.
30
+ */
31
+ account(externalId: string | null): Promise<ProviderAccount>;
32
+ charge(_request: ChargeRequest): Promise<ChargeResult>;
33
+ capture(): Promise<ChargeResult>;
34
+ release(): Promise<void>;
35
+ refund(_request: RefundRequest): Promise<{
36
+ externalId: string;
37
+ }>;
38
+ saveCard(_request: SaveCardRequest): Promise<SaveCardResult>;
39
+ storedCard(): Promise<StoredCard | undefined>;
40
+ forgetCard(): Promise<void>;
41
+ /**
42
+ * Never genuine.
43
+ *
44
+ * A deployment with no provider has no webhook to receive, so anything
45
+ * arriving at that address came from somebody else — and `undefined` is how
46
+ * the port says "not from the provider".
47
+ */
48
+ verify(): undefined;
49
+ }
50
+ //# sourceMappingURL=none.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"none.d.ts","sourceRoot":"","sources":["../../src/providers/none.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,cAAc,EACd,eAAe,EACf,eAAe,EACf,aAAa,EACb,eAAe,EACf,cAAc,EACd,UAAU,EACX,MAAM,QAAQ,CAAC;AAEhB;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,UAAW,YAAW,eAAe;IAChD,QAAQ,CAAC,IAAI,UAAU;IAEjB,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC;IAIxC;;;;;OAKG;IACG,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,eAAe,CAAC;IAI5D,MAAM,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAQtD,OAAO,IAAI,OAAO,CAAC,YAAY,CAAC;IAIhC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,MAAM,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAIhE,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAI5D,UAAU,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;IAI7C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;;;;;OAMG;IACH,MAAM,IAAI,SAAS;CAGpB"}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NoPayments = void 0;
4
+ /**
5
+ * No payment provider at all, said out loud rather than by failing.
6
+ *
7
+ * **Online payment is optional and never mandatory**, and this is what makes
8
+ * that true in the code rather than only in a document. A salon that takes cash
9
+ * at the counter and has never heard of Stripe runs its whole diary, writes
10
+ * down what it took, and reports on it — and nothing about that deployment
11
+ * should require a payment account to exist, least of all the application
12
+ * starting up.
13
+ *
14
+ * The alternative that looks simpler is constructing the vendor's client with
15
+ * an empty key. It throws inside its own constructor, and the whole API fails
16
+ * to boot — which is how this was found.
17
+ *
18
+ * **Not a permissive no-op.** Every operation refuses, and the account reports
19
+ * `none`, so every gate that already asks "can this business be paid out?"
20
+ * answers no without a special case. A provider that quietly returned success
21
+ * would write a trail of payments that never happened, which is worse than the
22
+ * crash it replaced.
23
+ */
24
+ class NoPayments {
25
+ name = 'none';
26
+ async onboard() {
27
+ throw new Error('This deployment has no payment provider configured.');
28
+ }
29
+ /**
30
+ * `none` rather than `pending`.
31
+ *
32
+ * They are different facts: `pending` means the provider is still checking,
33
+ * and a business told that will wait for an email that is never coming.
34
+ */
35
+ async account(externalId) {
36
+ return { externalId: externalId ?? '', status: 'none', requirements: [] };
37
+ }
38
+ async charge(_request) {
39
+ return {
40
+ externalId: '',
41
+ state: 'failed',
42
+ detail: 'This business cannot take card payments.',
43
+ };
44
+ }
45
+ async capture() {
46
+ return { externalId: '', state: 'failed', detail: 'There is nothing to capture.' };
47
+ }
48
+ async release() {
49
+ // Nothing was ever held.
50
+ }
51
+ async refund(_request) {
52
+ throw new Error('Nothing was taken through a provider, so nothing can be given back.');
53
+ }
54
+ async saveCard(_request) {
55
+ throw new Error('This deployment has no payment provider configured.');
56
+ }
57
+ async storedCard() {
58
+ return undefined;
59
+ }
60
+ async forgetCard() {
61
+ // There is nothing stored anywhere to forget.
62
+ }
63
+ /**
64
+ * Never genuine.
65
+ *
66
+ * A deployment with no provider has no webhook to receive, so anything
67
+ * arriving at that address came from somebody else — and `undefined` is how
68
+ * the port says "not from the provider".
69
+ */
70
+ verify() {
71
+ return undefined;
72
+ }
73
+ }
74
+ exports.NoPayments = NoPayments;
75
+ //# sourceMappingURL=none.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"none.js","sourceRoot":"","sources":["../../src/providers/none.ts"],"names":[],"mappings":";;;AAYA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAa,UAAU;IACZ,IAAI,GAAG,MAAM,CAAC;IAEvB,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CAAC,UAAyB;QACrC,OAAO,EAAE,UAAU,EAAE,UAAU,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAuB;QAClC,OAAO;YACL,UAAU,EAAE,EAAE;YACd,KAAK,EAAE,QAAQ;YACf,MAAM,EAAE,0CAA0C;SACnD,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,OAAO;QACX,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC;IACrF,CAAC;IAED,KAAK,CAAC,OAAO;QACX,yBAAyB;IAC3B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAuB;QAClC,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,QAAyB;QACtC,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,UAAU;QACd,8CAA8C;IAChD,CAAC;IAED;;;;;;OAMG;IACH,MAAM;QACJ,OAAO,SAAS,CAAC;IACnB,CAAC;CACF;AA3DD,gCA2DC"}
@@ -14,7 +14,14 @@
14
14
  /** Where a business's money goes, as the provider knows it. */
15
15
  export interface ProviderAccount {
16
16
  readonly externalId: string;
17
- readonly status: 'pending' | 'restricted' | 'ready';
17
+ /**
18
+ * `none` is a real answer, not an absence.
19
+ *
20
+ * It is what a deployment with no payment provider configured says, and it is
21
+ * different from `pending`: `pending` means somebody is checking, and a
22
+ * business told that will wait for an email nobody is going to send.
23
+ */
24
+ readonly status: 'none' | 'pending' | 'restricted' | 'ready';
18
25
  /** What the provider still wants, in its own words. */
19
26
  readonly requirements: readonly string[];
20
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../src/providers/port.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../../src/providers/port.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@birtalanrobert/commerce",
3
- "version": "2.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Taking money on a business's behalf: payout onboarding, payments, refunds and the record of both",
5
5
  "license": "AGPL-3.0-only",
6
6
  "author": "Robert Birtalan",
@@ -20,6 +20,10 @@
20
20
  "types": "./dist/index.d.ts",
21
21
  "default": "./dist/index.js"
22
22
  },
23
+ "./stripe": {
24
+ "types": "./dist/providers/stripe.d.ts",
25
+ "default": "./dist/providers/stripe.js"
26
+ },
23
27
  "./nestjs": {
24
28
  "types": "./dist/nestjs/index.d.ts",
25
29
  "default": "./dist/nestjs/index.js"
@@ -34,16 +38,17 @@
34
38
  "README.md",
35
39
  "LICENSE",
36
40
  "NOTICE",
41
+ "stripe",
37
42
  "nestjs",
38
43
  "CHANGELOG.md"
39
44
  ],
40
45
  "dependencies": {
41
46
  "stripe": "^22.6.0",
42
- "@birtalanrobert/database": "^1.0.0",
43
47
  "@birtalanrobert/context": "^1.1.0",
44
48
  "@birtalanrobert/http": "^2.0.0",
49
+ "@birtalanrobert/money": "^1.0.0",
45
50
  "@birtalanrobert/tenancy": "^1.1.0",
46
- "@birtalanrobert/money": "^1.0.0"
51
+ "@birtalanrobert/database": "^1.0.0"
47
52
  },
48
53
  "peerDependencies": {
49
54
  "@nestjs/common": "^11.0.0",
package/src/index.ts CHANGED
@@ -12,10 +12,12 @@
12
12
  * the mistake that makes both hard to reason about — they differ in who pays
13
13
  * whom, in which Stripe account, and in what happens when one fails.
14
14
  *
15
- * **This entry point is pure.** What a deposit comes to and whether a business
16
- * may sell yet are decided without a database or a provider, because a console
17
- * shows both while somebody drags a slider. Everything needing storage or
18
- * somebody else's money-moving licence is behind `/nestjs`.
15
+ * **This entry point is pure**, and stays that way by leaving things out. What
16
+ * a deposit comes to and whether a business may sell yet are decided without a
17
+ * database or a provider, because a console shows both while somebody drags a
18
+ * slider. Storage and the container are behind `/nestjs`; the Stripe client is
19
+ * behind `/stripe`, because a barrel that re-exports it puts the vendor's whole
20
+ * SDK into every bundle that wanted to divide a price by three.
19
21
  */
20
22
  export {
21
23
  balanceAfter,
@@ -35,6 +37,8 @@ export {
35
37
  type PaymentState,
36
38
  } from './payments';
37
39
 
40
+ export { NoPayments } from './providers/none';
41
+
38
42
  export type {
39
43
  ChargeRequest,
40
44
  ChargeResult,
@@ -48,4 +52,13 @@ export type {
48
52
  StoredCard,
49
53
  } from './providers/port';
50
54
 
51
- export { StripeConnect, type StripeConnectOptions } from './providers/stripe';
55
+ /*
56
+ * `StripeConnect` is deliberately NOT re-exported here.
57
+ *
58
+ * It lives at `@birtalanrobert/commerce/stripe`, because importing it pulls in
59
+ * the vendor's whole SDK — and this entry point is imported by browser code
60
+ * that only wants to know what a deposit comes to. Re-exporting it put 30 KB of
61
+ * a payments SDK into a console's first load for a screen that never calls it:
62
+ * a barrel is a bundling decision, and the only way to keep this one pure is to
63
+ * leave the heavy thing out of it.
64
+ */
@@ -0,0 +1,92 @@
1
+ import type {
2
+ ChargeRequest,
3
+ ChargeResult,
4
+ OnboardingLink,
5
+ PaymentProvider,
6
+ ProviderAccount,
7
+ RefundRequest,
8
+ SaveCardRequest,
9
+ SaveCardResult,
10
+ StoredCard,
11
+ } from './port';
12
+
13
+ /**
14
+ * No payment provider at all, said out loud rather than by failing.
15
+ *
16
+ * **Online payment is optional and never mandatory**, and this is what makes
17
+ * that true in the code rather than only in a document. A salon that takes cash
18
+ * at the counter and has never heard of Stripe runs its whole diary, writes
19
+ * down what it took, and reports on it — and nothing about that deployment
20
+ * should require a payment account to exist, least of all the application
21
+ * starting up.
22
+ *
23
+ * The alternative that looks simpler is constructing the vendor's client with
24
+ * an empty key. It throws inside its own constructor, and the whole API fails
25
+ * to boot — which is how this was found.
26
+ *
27
+ * **Not a permissive no-op.** Every operation refuses, and the account reports
28
+ * `none`, so every gate that already asks "can this business be paid out?"
29
+ * answers no without a special case. A provider that quietly returned success
30
+ * would write a trail of payments that never happened, which is worse than the
31
+ * crash it replaced.
32
+ */
33
+ export class NoPayments implements PaymentProvider {
34
+ readonly name = 'none';
35
+
36
+ async onboard(): Promise<OnboardingLink> {
37
+ throw new Error('This deployment has no payment provider configured.');
38
+ }
39
+
40
+ /**
41
+ * `none` rather than `pending`.
42
+ *
43
+ * They are different facts: `pending` means the provider is still checking,
44
+ * and a business told that will wait for an email that is never coming.
45
+ */
46
+ async account(externalId: string | null): Promise<ProviderAccount> {
47
+ return { externalId: externalId ?? '', status: 'none', requirements: [] };
48
+ }
49
+
50
+ async charge(_request: ChargeRequest): Promise<ChargeResult> {
51
+ return {
52
+ externalId: '',
53
+ state: 'failed',
54
+ detail: 'This business cannot take card payments.',
55
+ };
56
+ }
57
+
58
+ async capture(): Promise<ChargeResult> {
59
+ return { externalId: '', state: 'failed', detail: 'There is nothing to capture.' };
60
+ }
61
+
62
+ async release(): Promise<void> {
63
+ // Nothing was ever held.
64
+ }
65
+
66
+ async refund(_request: RefundRequest): Promise<{ externalId: string }> {
67
+ throw new Error('Nothing was taken through a provider, so nothing can be given back.');
68
+ }
69
+
70
+ async saveCard(_request: SaveCardRequest): Promise<SaveCardResult> {
71
+ throw new Error('This deployment has no payment provider configured.');
72
+ }
73
+
74
+ async storedCard(): Promise<StoredCard | undefined> {
75
+ return undefined;
76
+ }
77
+
78
+ async forgetCard(): Promise<void> {
79
+ // There is nothing stored anywhere to forget.
80
+ }
81
+
82
+ /**
83
+ * Never genuine.
84
+ *
85
+ * A deployment with no provider has no webhook to receive, so anything
86
+ * arriving at that address came from somebody else — and `undefined` is how
87
+ * the port says "not from the provider".
88
+ */
89
+ verify(): undefined {
90
+ return undefined;
91
+ }
92
+ }
@@ -15,7 +15,14 @@
15
15
  /** Where a business's money goes, as the provider knows it. */
16
16
  export interface ProviderAccount {
17
17
  readonly externalId: string;
18
- readonly status: 'pending' | 'restricted' | 'ready';
18
+ /**
19
+ * `none` is a real answer, not an absence.
20
+ *
21
+ * It is what a deployment with no payment provider configured says, and it is
22
+ * different from `pending`: `pending` means somebody is checking, and a
23
+ * business told that will wait for an email nobody is going to send.
24
+ */
25
+ readonly status: 'none' | 'pending' | 'restricted' | 'ready';
19
26
  /** What the provider still wants, in its own words. */
20
27
  readonly requirements: readonly string[];
21
28
  }
@@ -0,0 +1,5 @@
1
+ {
2
+ "main": "../dist/providers/stripe.js",
3
+ "types": "../dist/providers/stripe.d.ts",
4
+ "sideEffects": false
5
+ }