@birtalanrobert/commerce 3.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
@@ -55,6 +55,12 @@ 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
+
58
64
  **Three entry points, and the split is deliberate.** The root is pure — what a
59
65
  deposit comes to, whether a business may sell yet, whether a payment can still
60
66
  be refunded — because a console decides all three while somebody drags a
package/dist/index.d.ts CHANGED
@@ -21,5 +21,6 @@
21
21
  */
22
22
  export { balanceAfter, canTakeMoney, depositFor, payoutBlockReason, type DepositKind, type DepositPolicy, type PayoutStatus, } from './deposits';
23
23
  export { isRefundable, refundableAmount, type PaymentKind, type PaymentMethod, type PaymentState, } from './payments';
24
+ export { NoPayments } from './providers/none';
24
25
  export type { ChargeRequest, ChargeResult, OnboardingLink, PaymentProvider, ProviderAccount, ProviderEvent, RefundRequest, SaveCardRequest, SaveCardResult, StoredCard, } from './providers/port';
25
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
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,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"}
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.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
  *
@@ -30,6 +30,8 @@ Object.defineProperty(exports, "payoutBlockReason", { enumerable: true, get: fun
30
30
  var payments_1 = require("./payments");
31
31
  Object.defineProperty(exports, "isRefundable", { enumerable: true, get: function () { return payments_1.isRefundable; } });
32
32
  Object.defineProperty(exports, "refundableAmount", { enumerable: true, get: function () { return payments_1.refundableAmount; } });
33
+ var none_1 = require("./providers/none");
34
+ Object.defineProperty(exports, "NoPayments", { enumerable: true, get: function () { return none_1.NoPayments; } });
33
35
  /*
34
36
  * `StripeConnect` is deliberately NOT re-exported here.
35
37
  *
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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;AAmBlB;;;;;;;;;GASG"}
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": "3.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",
@@ -47,8 +47,8 @@
47
47
  "@birtalanrobert/context": "^1.1.0",
48
48
  "@birtalanrobert/http": "^2.0.0",
49
49
  "@birtalanrobert/money": "^1.0.0",
50
- "@birtalanrobert/database": "^1.0.0",
51
- "@birtalanrobert/tenancy": "^1.1.0"
50
+ "@birtalanrobert/tenancy": "^1.1.0",
51
+ "@birtalanrobert/database": "^1.0.0"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "@nestjs/common": "^11.0.0",
package/src/index.ts CHANGED
@@ -37,6 +37,8 @@ export {
37
37
  type PaymentState,
38
38
  } from './payments';
39
39
 
40
+ export { NoPayments } from './providers/none';
41
+
40
42
  export type {
41
43
  ChargeRequest,
42
44
  ChargeResult,
@@ -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
  }