@birtalanrobert/game-economy 1.0.0 → 2.0.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/CHANGELOG.md CHANGED
@@ -4,6 +4,114 @@ Each package carries its own version. A release publishes only the packages
4
4
  whose version is not yet on the registry; `pnpm release` asks npm and skips the
5
5
  rest.
6
6
 
7
+ ## game-economy 2.0.0
8
+
9
+ ### Breaking
10
+
11
+ - **`EntryKind` has `reversal`, a debit.** A reader that switches over the
12
+ kinds exhaustively, or keeps a record keyed by them, has one more.
13
+
14
+ ### Added
15
+
16
+ - **`reverse`: a purchase's currency taken back because its money went back
17
+ another way** — a refund made at the payment provider, a chargeback.
18
+ `refund` gives back only a whole purchase, which is right for a buyer asking
19
+ and wrong for money already gone: a reversal takes whatever of the purchase is
20
+ left, which may be less than all of it, or nothing, and answers with what it
21
+ took and what the holder had spent already — what nothing can take back, for
22
+ the game to decide what it costs them. A purchase is given back once, by a
23
+ refund or a reversal, whichever comes first: a reversal of one given back
24
+ already takes nothing and names the entry that did. Idempotent by key, as
25
+ every write is. Designed against Holdfast's Silver, whose chargebacks take
26
+ back what is unspent and flag what was spent.
27
+ - **The migration `AddReversals1791548064129`**, in `gameEconomyMigrations`:
28
+ the kind, and the check that a reversal, like a refund, names its purchase.
29
+
30
+ ### Migrating from 1.x
31
+
32
+ Run the new migration. A product that only credits, spends, refunds and reads
33
+ needs nothing else.
34
+
35
+ ## billing 4.0.0
36
+
37
+ Selling a pack — a premium currency, a ticket — as a single payment, rather
38
+ than a plan by the month: what four of the seventeen specifications sell.
39
+ First consumed by Holdfast's Silver.
40
+
41
+ ### Breaking
42
+
43
+ - **`BillingProvider` has `refund`.** An implementation of the port — a test
44
+ fake among them — needs one; `NoBilling`'s refuses, as everything else of
45
+ its does.
46
+ - **`BillingEvent` has `eventId`, and two more kinds.** The event's own
47
+ identifier, the same on every delivery, is what makes a webhook delivered
48
+ twice recognisable as one. `kind` may now also be `refund` and `dispute`:
49
+ a reader that switches over it exhaustively has two more cases, and a fake
50
+ that builds events needs the id.
51
+ - **`CheckoutRequest.price` may be an `InlinePrice`.** A provider reading it
52
+ as a string must handle the other shape.
53
+
54
+ ### Added
55
+
56
+ - **A single payment priced by its amount** (`InlinePrice`): the amount in
57
+ minor units, the currency, the name the buyer reads, whether the tax is
58
+ inside the amount, and the provider's tax code. A pack whose price an
59
+ operator edits in the product's own settings is charged as written, with no
60
+ price in the provider's dashboard to drift from it. For `payment` mode only;
61
+ a subscription is still priced by its plan's identifier.
62
+ - **`CheckoutRequest.metadata` and `locale`.** The caller's own keys travel
63
+ with `subject` onto the session and, for a single payment, onto the payment
64
+ itself — which a refund or a dispute names, never the session. The payment
65
+ page opens in the buyer's language.
66
+ - **`refund({ payment, amount?, reference })`**, idempotent on the reference,
67
+ answering with the refund's status: `pending` until the payment method
68
+ confirms, `succeeded`, or `failed`.
69
+ - **Events for a single payment's life.** A checkout event carries the
70
+ payment, the tax the provider worked out and the caller's metadata, and is
71
+ paid only when the money arrived — a session completed with a bank debit
72
+ still clearing is not, and `checkout.session.async_payment_succeeded` and
73
+ `…_failed` say what became of it. `charge.refunded` is a `refund` event with
74
+ how much has gone back so far, every refund together — the only way a
75
+ product hears of one made in the provider's dashboard. `charge.dispute
76
+ .funds_withdrawn` and `…_reinstated` are `dispute` events, with whether the
77
+ money left or came back; an inquiry that moves nothing raises neither.
78
+ - **`StripeBillingOptions.apiUrl`**: the provider's API somewhere other than
79
+ Stripe's own — stripe-mock in a pipeline, a suite's stub vendor.
80
+
81
+ ### Migrating from 3.x
82
+
83
+ Add `refund` to any implementation of `BillingProvider`, and `eventId` to any
84
+ `BillingEvent` a test builds. A product that only reads events, starts
85
+ subscriptions and calls `NoBilling` or `StripeBilling` needs nothing else.
86
+
87
+ ## http 2.0.1
88
+
89
+ ### Fixed
90
+
91
+ - **A request the client could fix was answered "an unexpected error
92
+ occurred".** body-parser and raw-body throw `http-errors` before any handler
93
+ runs — a body past the limit (413), a charset or an encoding nothing reads
94
+ (415), and JSON that does not parse (400), which Nest alone turns into a 400
95
+ of its own — and `toProblemDetails` knew neither their class nor their
96
+ shape, so the rest became a 500 and were logged as the service's own
97
+ failure. An `Error` carrying a 4xx `status` and `expose: true`, the
98
+ library's word that its message was written for the client, now keeps its
99
+ status, its code and its message; one not so marked is a 500 that says
100
+ nothing, as before.
101
+
102
+ ## idempotency 1.2.1
103
+
104
+ ### Fixed
105
+
106
+ - **A raw body was fingerprinted one byte at a time.** A request whose body is
107
+ bytes rather than JSON — an image sent as itself, which Express's raw parser
108
+ hands over as a `Buffer` — was walked as an object: one entry per byte, each
109
+ keyed by its index and sorted as text, so a two-megabyte upload became four
110
+ million strings before the key could be claimed. A body that is any view of
111
+ bytes now stands for their SHA-256, behind a prefix no JSON value can begin
112
+ with, so the same bytes are the same request and no JSON body can pass for a
113
+ binary one.
114
+
7
115
  ## game-economy 1.0.0
8
116
 
9
117
  ### Added
package/README.md CHANGED
@@ -98,6 +98,24 @@ any of it is spent or it was refunded already, and `not_found` for one that is
98
98
  not the holder's purchase. Whether it is still within a refund window, and the
99
99
  money's own return, are the game's and its payment provider's.
100
100
 
101
+ `reverse` is for money that went back another way — a refund made at the
102
+ payment provider, a chargeback. It takes whatever of the purchase is left,
103
+ which may be less than all of it, or nothing, and answers with what it took
104
+ and what the holder had spent already:
105
+
106
+ ```ts
107
+ const { entry, taken, spent, earlier } = await economy.reverse(holderId, {
108
+ purchaseId,
109
+ reason: 'stripe.dispute',
110
+ idempotencyKey: `dispute:${eventId}`,
111
+ });
112
+ // spent > 0: currency the holder used that nothing took back — the game decides what that costs them.
113
+ ```
114
+
115
+ A purchase is given back once, by a refund or a reversal, whichever comes
116
+ first: a reversal of one given back already takes nothing and names the entry
117
+ that did (`earlier`), and two at once leave one of them standing.
118
+
101
119
  ## Two things it deliberately does not do
102
120
 
103
121
  - **Move currency between holders.** A gift between players is a transfer
package/dist/kinds.d.ts CHANGED
@@ -6,10 +6,13 @@
6
6
  */
7
7
  export declare const CREDIT_KINDS: readonly ["purchase", "grant"];
8
8
  /**
9
- * The two ways it leaves: **spent** in the game, or a purchase **refunded** —
10
- * its money handed back and its currency taken back with it.
9
+ * The ways it leaves: **spent** in the game; a purchase **refunded** — its
10
+ * money handed back and all its currency taken back with it; or a purchase
11
+ * **reversed** — its money gone back another way, a refund made at the
12
+ * payment provider or a chargeback, and whatever of its currency is left
13
+ * taken back.
11
14
  */
12
- export declare const DEBIT_KINDS: readonly ["spend", "refund"];
15
+ export declare const DEBIT_KINDS: readonly ["spend", "refund", "reversal"];
13
16
  export type CreditKind = (typeof CREDIT_KINDS)[number];
14
17
  export type DebitKind = (typeof DEBIT_KINDS)[number];
15
18
  export type EntryKind = CreditKind | DebitKind;
@@ -1 +1 @@
1
- {"version":3,"file":"kinds.d.ts","sourceRoot":"","sources":["../src/kinds.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,YAAY,gCAAiC,CAAC;AAE3D;;;GAGG;AACH,eAAO,MAAM,WAAW,8BAA+B,CAAC;AAExD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AACvD,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AACrD,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC"}
1
+ {"version":3,"file":"kinds.d.ts","sourceRoot":"","sources":["../src/kinds.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,YAAY,gCAAiC,CAAC;AAE3D;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,0CAA2C,CAAC;AAEpE,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AACvD,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AACrD,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC"}
package/dist/kinds.js CHANGED
@@ -9,8 +9,11 @@ exports.DEBIT_KINDS = exports.CREDIT_KINDS = void 0;
9
9
  */
10
10
  exports.CREDIT_KINDS = ['purchase', 'grant'];
11
11
  /**
12
- * The two ways it leaves: **spent** in the game, or a purchase **refunded** —
13
- * its money handed back and its currency taken back with it.
12
+ * The ways it leaves: **spent** in the game; a purchase **refunded** — its
13
+ * money handed back and all its currency taken back with it; or a purchase
14
+ * **reversed** — its money gone back another way, a refund made at the
15
+ * payment provider or a chargeback, and whatever of its currency is left
16
+ * taken back.
14
17
  */
15
- exports.DEBIT_KINDS = ['spend', 'refund'];
18
+ exports.DEBIT_KINDS = ['spend', 'refund', 'reversal'];
16
19
  //# sourceMappingURL=kinds.js.map
package/dist/kinds.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"kinds.js","sourceRoot":"","sources":["../src/kinds.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACU,QAAA,YAAY,GAAG,CAAC,UAAU,EAAE,OAAO,CAAU,CAAC;AAE3D;;;GAGG;AACU,QAAA,WAAW,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAU,CAAC"}
1
+ {"version":3,"file":"kinds.js","sourceRoot":"","sources":["../src/kinds.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACU,QAAA,YAAY,GAAG,CAAC,UAAU,EAAE,OAAO,CAAU,CAAC;AAE3D;;;;;;GAMG;AACU,QAAA,WAAW,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAU,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { MigrationInterface, QueryRunner } from 'typeorm';
2
+ /**
3
+ * Adds the reversal: a purchase's currency taken back because its money went
4
+ * back another way — a refund made at the payment provider, a chargeback.
5
+ *
6
+ * A debit like a refund, and of the same purchase — so it carries
7
+ * `refund_of`, and the unique index on that column makes a purchase given
8
+ * back once, by a refund or by a reversal, whichever comes first. Unlike a
9
+ * refund it takes whatever of the purchase is left, which may be less than
10
+ * all of it.
11
+ *
12
+ * `down` restores the narrower checks, and so fails while any reversal is
13
+ * recorded: an append-only ledger is not narrowed by forgetting its entries.
14
+ */
15
+ export declare class AddReversals1791548064129 implements MigrationInterface {
16
+ name: string;
17
+ up(queryRunner: QueryRunner): Promise<void>;
18
+ down(queryRunner: QueryRunner): Promise<void>;
19
+ }
20
+ //# sourceMappingURL=1791548064129-AddReversals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1791548064129-AddReversals.d.ts","sourceRoot":"","sources":["../../src/migrations/1791548064129-AddReversals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;;;;;;;;;GAYG;AACH,qBAAa,yBAA0B,YAAW,kBAAkB;IAClE,IAAI,SAA+B;IAE7B,EAAE,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3C,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAWpD"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AddReversals1791548064129 = void 0;
4
+ /**
5
+ * Adds the reversal: a purchase's currency taken back because its money went
6
+ * back another way — a refund made at the payment provider, a chargeback.
7
+ *
8
+ * A debit like a refund, and of the same purchase — so it carries
9
+ * `refund_of`, and the unique index on that column makes a purchase given
10
+ * back once, by a refund or by a reversal, whichever comes first. Unlike a
11
+ * refund it takes whatever of the purchase is left, which may be less than
12
+ * all of it.
13
+ *
14
+ * `down` restores the narrower checks, and so fails while any reversal is
15
+ * recorded: an append-only ledger is not narrowed by forgetting its entries.
16
+ */
17
+ class AddReversals1791548064129 {
18
+ name = 'AddReversals1791548064129';
19
+ async up(queryRunner) {
20
+ await queryRunner.query(`
21
+ ALTER TABLE "mortar_economy_entries"
22
+ DROP CONSTRAINT "ck_economy_entries_kind",
23
+ DROP CONSTRAINT "ck_economy_entries_refund",
24
+ ADD CONSTRAINT "ck_economy_entries_kind"
25
+ CHECK ("kind" IN ('purchase', 'grant', 'spend', 'refund', 'reversal')),
26
+ ADD CONSTRAINT "ck_economy_entries_refund"
27
+ CHECK (("kind" IN ('refund', 'reversal')) = ("refund_of" IS NOT NULL))
28
+ `);
29
+ }
30
+ async down(queryRunner) {
31
+ await queryRunner.query(`
32
+ ALTER TABLE "mortar_economy_entries"
33
+ DROP CONSTRAINT "ck_economy_entries_kind",
34
+ DROP CONSTRAINT "ck_economy_entries_refund",
35
+ ADD CONSTRAINT "ck_economy_entries_kind"
36
+ CHECK ("kind" IN ('purchase', 'grant', 'spend', 'refund')),
37
+ ADD CONSTRAINT "ck_economy_entries_refund"
38
+ CHECK (("kind" = 'refund') = ("refund_of" IS NOT NULL))
39
+ `);
40
+ }
41
+ }
42
+ exports.AddReversals1791548064129 = AddReversals1791548064129;
43
+ //# sourceMappingURL=1791548064129-AddReversals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1791548064129-AddReversals.js","sourceRoot":"","sources":["../../src/migrations/1791548064129-AddReversals.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;GAYG;AACH,MAAa,yBAAyB;IACpC,IAAI,GAAG,2BAA2B,CAAC;IAEnC,KAAK,CAAC,EAAE,CAAC,WAAwB;QAC/B,MAAM,WAAW,CAAC,KAAK,CAAC;;;;;;;;KAQvB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,WAAwB;QACjC,MAAM,WAAW,CAAC,KAAK,CAAC;;;;;;;;KAQvB,CAAC,CAAC;IACL,CAAC;CACF;AA1BD,8DA0BC"}
@@ -11,7 +11,7 @@ export interface EntryView {
11
11
  readonly balanceAfter: number;
12
12
  readonly reason: string;
13
13
  readonly reference: string | null;
14
- /** For a refund, the purchase it gives back. */
14
+ /** For a refund or a reversal, the purchase it gives back. */
15
15
  readonly refundOf: string | null;
16
16
  readonly metadata: Record<string, unknown> | null;
17
17
  readonly occurredAt: Date;
@@ -35,4 +35,19 @@ export interface Reconciliation {
35
35
  readonly lots: number;
36
36
  readonly agrees: boolean;
37
37
  }
38
+ /**
39
+ * A purchase reversed: the entry that took back what was left of it — none
40
+ * when nothing was — how much that was, and how much of the purchase the
41
+ * holder had spent already, which nothing can take back.
42
+ */
43
+ export interface Reversal {
44
+ readonly entry: EntryView | null;
45
+ readonly taken: number;
46
+ readonly spent: number;
47
+ /**
48
+ * The refund or reversal that had given the purchase back before, under
49
+ * another key: nothing more is taken, and nothing is newly spent.
50
+ */
51
+ readonly earlier: EntryView | null;
52
+ }
38
53
  //# sourceMappingURL=economy-views.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"economy-views.d.ts","sourceRoot":"","sources":["../../src/nestjs/economy-views.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEtD,0DAA0D;AAC1D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAClD,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC;CAC3B;AAED,yFAAyF;AACzF,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B"}
1
+ {"version":3,"file":"economy-views.d.ts","sourceRoot":"","sources":["../../src/nestjs/economy-views.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAEtD,0DAA0D;AAC1D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAClD,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAC;CAC3B;AAED,yFAAyF;AACzF,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wCAAwC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;CACpC"}
@@ -1,5 +1,5 @@
1
1
  import type { DataSource } from 'typeorm';
2
- import type { EntryView, LotView, Reconciliation } from './economy-views';
2
+ import type { EntryView, LotView, Reconciliation, Reversal } from './economy-views';
3
3
  import type { GameEconomyOptions } from './game-economy-options.types';
4
4
  import type { MovementRequest, RefundRequest } from './movement-request.types';
5
5
  /**
@@ -37,6 +37,19 @@ export declare class GameEconomyService {
37
37
  * when it was refunded already, and `not_found` for one not the holder's.
38
38
  */
39
39
  refund(holderId: string, request: RefundRequest): Promise<EntryView>;
40
+ /**
41
+ * A purchase reversed: its money gone back another way — a refund made at
42
+ * the payment provider, a chargeback — and whatever of its currency is left
43
+ * taken back, which may be less than all of it, or nothing. Answers with
44
+ * what was taken and what the holder had spent of it already, which nothing
45
+ * takes back; the game decides what that costs them.
46
+ *
47
+ * A purchase given back before — refunded, or reversed under another key —
48
+ * takes nothing more, and the answer names that entry instead. The same key
49
+ * again answers as it did the first time. `not_found` for a purchase not the
50
+ * holder's.
51
+ */
52
+ reverse(holderId: string, request: RefundRequest): Promise<Reversal>;
40
53
  /** A holder's balance in a currency: nothing for one never credited. */
41
54
  balance(holderId: string, currency: string): Promise<number>;
42
55
  /** A page of a holder's entries in a currency, the newest first. */
@@ -1 +1 @@
1
- {"version":3,"file":"game-economy.service.d.ts","sourceRoot":"","sources":["../../src/nestjs/game-economy.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,SAAS,CAAC;AASzD,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAuB/E;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,kBAAkB;IAI3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAH7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;gBAG3B,UAAU,EAAE,UAAU,EACvC,OAAO,EAAE,kBAAkB;IAU7B,+FAA+F;IACzF,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAI3E,yEAAyE;IACnE,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAI9E;;;OAGG;IACG,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IA+B3E;;;;OAIG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC;IAsC1E,wEAAwE;IAClE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQlE,oEAAoE;IAC9D,OAAO,CACX,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAC/D,OAAO,CAAC;QAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAgBrE,iHAAiH;IAC3G,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAoBlE;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;YAmB9D,MAAM;IA4BpB,wGAAwG;YAC1F,IAAI;IAclB;;;OAGG;YACW,OAAO;YAsBP,MAAM;YA+BN,IAAI;YAiBJ,UAAU;YAaV,QAAQ;YAmBR,KAAK;CAYpB"}
1
+ {"version":3,"file":"game-economy.service.d.ts","sourceRoot":"","sources":["../../src/nestjs/game-economy.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,SAAS,CAAC;AASzD,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEpF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAuB/E;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,kBAAkB;IAI3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAH7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;gBAG3B,UAAU,EAAE,UAAU,EACvC,OAAO,EAAE,kBAAkB;IAU7B,+FAA+F;IACzF,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAI3E,yEAAyE;IACnE,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IAI9E;;;OAGG;IACG,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IA+B3E;;;;OAIG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC;IAsC1E;;;;;;;;;;;OAWG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC;IAgD1E,wEAAwE;IAClE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQlE,oEAAoE;IAC9D,OAAO,CACX,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;QAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAC/D,OAAO,CAAC;QAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAgBrE,iHAAiH;IAC3G,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAoBlE;;;;;OAKG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;YAmB9D,MAAM;IA4BpB,wGAAwG;YAC1F,IAAI;IAclB;;;OAGG;YACW,OAAO;YAsBP,MAAM;YA+BN,IAAI;YAiBJ,UAAU;YAaV,QAAQ;YAmBR,KAAK;CAYpB"}
@@ -108,6 +108,52 @@ class GameEconomyService {
108
108
  return entry;
109
109
  });
110
110
  }
111
+ /**
112
+ * A purchase reversed: its money gone back another way — a refund made at
113
+ * the payment provider, a chargeback — and whatever of its currency is left
114
+ * taken back, which may be less than all of it, or nothing. Answers with
115
+ * what was taken and what the holder had spent of it already, which nothing
116
+ * takes back; the game decides what that costs them.
117
+ *
118
+ * A purchase given back before — refunded, or reversed under another key —
119
+ * takes nothing more, and the answer names that entry instead. The same key
120
+ * again answers as it did the first time. `not_found` for a purchase not the
121
+ * holder's.
122
+ */
123
+ async reverse(holderId, request) {
124
+ (0, check_request_1.checkRequest)(holderId, request);
125
+ if (!UUID.test(request.purchaseId))
126
+ throw new http_1.NotFoundError('Purchase', request.purchaseId);
127
+ return (0, database_1.runInTransaction)(this.dataSource, async (manager) => {
128
+ const found = await this.lotOf(manager, holderId, request.purchaseId);
129
+ if (!found || found.kind !== 'purchase') {
130
+ throw new http_1.NotFoundError('Purchase', request.purchaseId);
131
+ }
132
+ const balance = await this.lock(manager, holderId, found.currency);
133
+ const amount = (0, to_amount_1.toAmount)(found.amount);
134
+ const [keyed] = (await manager.query(`SELECT ${entry_view_of_1.ENTRY_COLUMNS} FROM "mortar_economy_entries"
135
+ WHERE "holder_id" = $1 AND "idempotency_key" = $2`, [holderId, request.idempotencyKey]));
136
+ if (keyed) {
137
+ const entry = (0, entry_view_of_1.entryViewOf)(keyed);
138
+ if (entry.kind !== 'reversal' || entry.refundOf !== found.entry_id) {
139
+ throw new errors_1.LedgerKeyReusedError(request.idempotencyKey);
140
+ }
141
+ return { entry, taken: entry.amount, spent: amount - entry.amount, earlier: null };
142
+ }
143
+ const [given] = (await manager.query(`SELECT ${entry_view_of_1.ENTRY_COLUMNS} FROM "mortar_economy_entries" WHERE "refund_of" = $1`, [found.entry_id]));
144
+ if (given)
145
+ return { entry: null, taken: 0, spent: 0, earlier: (0, entry_view_of_1.entryViewOf)(given) };
146
+ // Read again under the lock: a spend may have drawn on it meanwhile.
147
+ const lot = (await this.lotOf(manager, holderId, request.purchaseId));
148
+ const remaining = (0, to_amount_1.toAmount)(lot.remaining);
149
+ if (remaining === 0)
150
+ return { entry: null, taken: 0, spent: amount, earlier: null };
151
+ const entry = await this.insert(manager, holderId, 'reversal', { ...request, currency: lot.currency, amount: remaining }, balance - remaining, lot.entry_id);
152
+ await this.draw(manager, entry.id, [{ lotId: lot.entry_id, amount: remaining }]);
153
+ await this.setBalance(manager, holderId, lot.currency, entry.balanceAfter);
154
+ return { entry, taken: remaining, spent: amount - remaining, earlier: null };
155
+ });
156
+ }
111
157
  /** A holder's balance in a currency: nothing for one never credited. */
112
158
  async balance(holderId, currency) {
113
159
  const [row] = (await (0, database_1.resolveManager)(this.dataSource).query(`SELECT "balance" FROM "mortar_economy_balances" WHERE "holder_id" = $1 AND "currency" = $2`, [holderId, currency]));
@@ -1 +1 @@
1
- {"version":3,"file":"game-economy.service.js","sourceRoot":"","sources":["../../src/nestjs/game-economy.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"game-economy.service.js","sourceRoot":"","sources":["../../src/nestjs/game-economy.service.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,18 @@
1
1
  import { CreateGameEconomy1791401023940 } from '../migrations/1791401023940-CreateGameEconomy';
2
+ import { AddReversals1791548064129 } from '../migrations/1791548064129-AddReversals';
2
3
  import { EconomyBalance } from './economy-balance.entity';
3
4
  import { EconomyDraw } from './economy-draw.entity';
4
5
  import { EconomyEntry } from './economy-entry.entity';
5
6
  import { EconomyLot } from './economy-lot.entity';
6
7
  export { EconomyBalance, EconomyDraw, EconomyEntry, EconomyLot };
7
- export { CreateGameEconomy1791401023940 };
8
+ export { AddReversals1791548064129, CreateGameEconomy1791401023940 };
8
9
  export { GameEconomyModule } from './game-economy.module';
9
10
  export { GameEconomyService } from './game-economy.service';
10
11
  export type { GameEconomyOptions } from './game-economy-options.types';
11
12
  export type { MovementRequest, RefundRequest } from './movement-request.types';
12
- export type { EntryView, LotView, Reconciliation } from './economy-views';
13
+ export type { EntryView, LotView, Reconciliation, Reversal } from './economy-views';
13
14
  /** Register alongside the project's own entities. */
14
- export declare const gameEconomyEntities: (typeof EconomyBalance | typeof EconomyDraw | typeof EconomyEntry | typeof EconomyLot)[];
15
+ export declare const gameEconomyEntities: (typeof EconomyEntry | typeof EconomyBalance | typeof EconomyLot | typeof EconomyDraw)[];
15
16
  /** Register alongside the project's own migrations. */
16
17
  export declare const gameEconomyMigrations: (typeof CreateGameEconomy1791401023940)[];
17
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/nestjs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,+CAA+C,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AACjE,OAAO,EAAE,8BAA8B,EAAE,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC/E,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE1E,qDAAqD;AACrD,eAAO,MAAM,mBAAmB,0FAA0D,CAAC;AAE3F,uDAAuD;AACvD,eAAO,MAAM,qBAAqB,2CAAmC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/nestjs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,+CAA+C,CAAC;AAC/F,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,YAAY,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC/E,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEpF,qDAAqD;AACrD,eAAO,MAAM,mBAAmB,0FAA0D,CAAC;AAE3F,uDAAuD;AACvD,eAAO,MAAM,qBAAqB,2CAA8D,CAAC"}
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.gameEconomyMigrations = exports.gameEconomyEntities = exports.GameEconomyService = exports.GameEconomyModule = exports.CreateGameEconomy1791401023940 = exports.EconomyLot = exports.EconomyEntry = exports.EconomyDraw = exports.EconomyBalance = void 0;
3
+ exports.gameEconomyMigrations = exports.gameEconomyEntities = exports.GameEconomyService = exports.GameEconomyModule = exports.CreateGameEconomy1791401023940 = exports.AddReversals1791548064129 = exports.EconomyLot = exports.EconomyEntry = exports.EconomyDraw = exports.EconomyBalance = void 0;
4
4
  const _1791401023940_CreateGameEconomy_1 = require("../migrations/1791401023940-CreateGameEconomy");
5
5
  Object.defineProperty(exports, "CreateGameEconomy1791401023940", { enumerable: true, get: function () { return _1791401023940_CreateGameEconomy_1.CreateGameEconomy1791401023940; } });
6
+ const _1791548064129_AddReversals_1 = require("../migrations/1791548064129-AddReversals");
7
+ Object.defineProperty(exports, "AddReversals1791548064129", { enumerable: true, get: function () { return _1791548064129_AddReversals_1.AddReversals1791548064129; } });
6
8
  const economy_balance_entity_1 = require("./economy-balance.entity");
7
9
  Object.defineProperty(exports, "EconomyBalance", { enumerable: true, get: function () { return economy_balance_entity_1.EconomyBalance; } });
8
10
  const economy_draw_entity_1 = require("./economy-draw.entity");
@@ -18,5 +20,5 @@ Object.defineProperty(exports, "GameEconomyService", { enumerable: true, get: fu
18
20
  /** Register alongside the project's own entities. */
19
21
  exports.gameEconomyEntities = [economy_entry_entity_1.EconomyEntry, economy_balance_entity_1.EconomyBalance, economy_lot_entity_1.EconomyLot, economy_draw_entity_1.EconomyDraw];
20
22
  /** Register alongside the project's own migrations. */
21
- exports.gameEconomyMigrations = [_1791401023940_CreateGameEconomy_1.CreateGameEconomy1791401023940];
23
+ exports.gameEconomyMigrations = [_1791401023940_CreateGameEconomy_1.CreateGameEconomy1791401023940, _1791548064129_AddReversals_1.AddReversals1791548064129];
22
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/nestjs/index.ts"],"names":[],"mappings":";;;AAAA,oGAA+F;AAOtF,+GAPA,iEAA8B,OAOA;AANvC,qEAA0D;AAKjD,+FALA,uCAAc,OAKA;AAJvB,+DAAoD;AAI3B,4FAJhB,iCAAW,OAIgB;AAHpC,iEAAsD;AAGhB,6FAH7B,mCAAY,OAG6B;AAFlD,6DAAkD;AAEE,2FAF3C,+BAAU,OAE2C;AAE9D,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,+DAA4D;AAAnD,0HAAA,kBAAkB,OAAA;AAK3B,qDAAqD;AACxC,QAAA,mBAAmB,GAAG,CAAC,mCAAY,EAAE,uCAAc,EAAE,+BAAU,EAAE,iCAAW,CAAC,CAAC;AAE3F,uDAAuD;AAC1C,QAAA,qBAAqB,GAAG,CAAC,iEAA8B,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/nestjs/index.ts"],"names":[],"mappings":";;;AAAA,oGAA+F;AAQ3D,+GAR3B,iEAA8B,OAQ2B;AAPlE,0FAAqF;AAO5E,0GAPA,uDAAyB,OAOA;AANlC,qEAA0D;AAKjD,+FALA,uCAAc,OAKA;AAJvB,+DAAoD;AAI3B,4FAJhB,iCAAW,OAIgB;AAHpC,iEAAsD;AAGhB,6FAH7B,mCAAY,OAG6B;AAFlD,6DAAkD;AAEE,2FAF3C,+BAAU,OAE2C;AAE9D,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,+DAA4D;AAAnD,0HAAA,kBAAkB,OAAA;AAK3B,qDAAqD;AACxC,QAAA,mBAAmB,GAAG,CAAC,mCAAY,EAAE,uCAAc,EAAE,+BAAU,EAAE,iCAAW,CAAC,CAAC;AAE3F,uDAAuD;AAC1C,QAAA,qBAAqB,GAAG,CAAC,iEAA8B,EAAE,uDAAyB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@birtalanrobert/game-economy",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "A game's premium currency as an append-only ledger: every purchase, grant, spend and refund, reconcilable to the last unit",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -38,7 +38,7 @@
38
38
  "type": "commonjs",
39
39
  "dependencies": {
40
40
  "@birtalanrobert/database": "^1.2.0",
41
- "@birtalanrobert/http": "^2.0.0"
41
+ "@birtalanrobert/http": "^2.0.1"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@nestjs/common": "^11.0.0",
package/src/kinds.ts CHANGED
@@ -7,10 +7,13 @@
7
7
  export const CREDIT_KINDS = ['purchase', 'grant'] as const;
8
8
 
9
9
  /**
10
- * The two ways it leaves: **spent** in the game, or a purchase **refunded** —
11
- * its money handed back and its currency taken back with it.
10
+ * The ways it leaves: **spent** in the game; a purchase **refunded** — its
11
+ * money handed back and all its currency taken back with it; or a purchase
12
+ * **reversed** — its money gone back another way, a refund made at the
13
+ * payment provider or a chargeback, and whatever of its currency is left
14
+ * taken back.
12
15
  */
13
- export const DEBIT_KINDS = ['spend', 'refund'] as const;
16
+ export const DEBIT_KINDS = ['spend', 'refund', 'reversal'] as const;
14
17
 
15
18
  export type CreditKind = (typeof CREDIT_KINDS)[number];
16
19
  export type DebitKind = (typeof DEBIT_KINDS)[number];
@@ -0,0 +1,42 @@
1
+ import type { MigrationInterface, QueryRunner } from 'typeorm';
2
+
3
+ /**
4
+ * Adds the reversal: a purchase's currency taken back because its money went
5
+ * back another way — a refund made at the payment provider, a chargeback.
6
+ *
7
+ * A debit like a refund, and of the same purchase — so it carries
8
+ * `refund_of`, and the unique index on that column makes a purchase given
9
+ * back once, by a refund or by a reversal, whichever comes first. Unlike a
10
+ * refund it takes whatever of the purchase is left, which may be less than
11
+ * all of it.
12
+ *
13
+ * `down` restores the narrower checks, and so fails while any reversal is
14
+ * recorded: an append-only ledger is not narrowed by forgetting its entries.
15
+ */
16
+ export class AddReversals1791548064129 implements MigrationInterface {
17
+ name = 'AddReversals1791548064129';
18
+
19
+ async up(queryRunner: QueryRunner): Promise<void> {
20
+ await queryRunner.query(`
21
+ ALTER TABLE "mortar_economy_entries"
22
+ DROP CONSTRAINT "ck_economy_entries_kind",
23
+ DROP CONSTRAINT "ck_economy_entries_refund",
24
+ ADD CONSTRAINT "ck_economy_entries_kind"
25
+ CHECK ("kind" IN ('purchase', 'grant', 'spend', 'refund', 'reversal')),
26
+ ADD CONSTRAINT "ck_economy_entries_refund"
27
+ CHECK (("kind" IN ('refund', 'reversal')) = ("refund_of" IS NOT NULL))
28
+ `);
29
+ }
30
+
31
+ async down(queryRunner: QueryRunner): Promise<void> {
32
+ await queryRunner.query(`
33
+ ALTER TABLE "mortar_economy_entries"
34
+ DROP CONSTRAINT "ck_economy_entries_kind",
35
+ DROP CONSTRAINT "ck_economy_entries_refund",
36
+ ADD CONSTRAINT "ck_economy_entries_kind"
37
+ CHECK ("kind" IN ('purchase', 'grant', 'spend', 'refund')),
38
+ ADD CONSTRAINT "ck_economy_entries_refund"
39
+ CHECK (("kind" = 'refund') = ("refund_of" IS NOT NULL))
40
+ `);
41
+ }
42
+ }
@@ -12,7 +12,7 @@ export interface EntryView {
12
12
  readonly balanceAfter: number;
13
13
  readonly reason: string;
14
14
  readonly reference: string | null;
15
- /** For a refund, the purchase it gives back. */
15
+ /** For a refund or a reversal, the purchase it gives back. */
16
16
  readonly refundOf: string | null;
17
17
  readonly metadata: Record<string, unknown> | null;
18
18
  readonly occurredAt: Date;
@@ -38,3 +38,19 @@ export interface Reconciliation {
38
38
  readonly lots: number;
39
39
  readonly agrees: boolean;
40
40
  }
41
+
42
+ /**
43
+ * A purchase reversed: the entry that took back what was left of it — none
44
+ * when nothing was — how much that was, and how much of the purchase the
45
+ * holder had spent already, which nothing can take back.
46
+ */
47
+ export interface Reversal {
48
+ readonly entry: EntryView | null;
49
+ readonly taken: number;
50
+ readonly spent: number;
51
+ /**
52
+ * The refund or reversal that had given the purchase back before, under
53
+ * another key: nothing more is taken, and nothing is newly spent.
54
+ */
55
+ readonly earlier: EntryView | null;
56
+ }
@@ -9,7 +9,7 @@ import type { CreditKind, EntryKind } from '../kinds';
9
9
  import { isSpendOrder } from '../spend-order';
10
10
  import type { Draw, Lot } from '../types';
11
11
  import { checkRequest } from './check-request';
12
- import type { EntryView, LotView, Reconciliation } from './economy-views';
12
+ import type { EntryView, LotView, Reconciliation, Reversal } from './economy-views';
13
13
  import { ENTRY_COLUMNS, entryViewOf, type EntryRow } from './entry-view-of';
14
14
  import type { GameEconomyOptions } from './game-economy-options.types';
15
15
  import type { MovementRequest, RefundRequest } from './movement-request.types';
@@ -154,6 +154,66 @@ export class GameEconomyService {
154
154
  });
155
155
  }
156
156
 
157
+ /**
158
+ * A purchase reversed: its money gone back another way — a refund made at
159
+ * the payment provider, a chargeback — and whatever of its currency is left
160
+ * taken back, which may be less than all of it, or nothing. Answers with
161
+ * what was taken and what the holder had spent of it already, which nothing
162
+ * takes back; the game decides what that costs them.
163
+ *
164
+ * A purchase given back before — refunded, or reversed under another key —
165
+ * takes nothing more, and the answer names that entry instead. The same key
166
+ * again answers as it did the first time. `not_found` for a purchase not the
167
+ * holder's.
168
+ */
169
+ async reverse(holderId: string, request: RefundRequest): Promise<Reversal> {
170
+ checkRequest(holderId, request);
171
+ if (!UUID.test(request.purchaseId)) throw new NotFoundError('Purchase', request.purchaseId);
172
+ return runInTransaction(this.dataSource, async (manager) => {
173
+ const found = await this.lotOf(manager, holderId, request.purchaseId);
174
+ if (!found || found.kind !== 'purchase') {
175
+ throw new NotFoundError('Purchase', request.purchaseId);
176
+ }
177
+ const balance = await this.lock(manager, holderId, found.currency);
178
+ const amount = toAmount(found.amount);
179
+
180
+ const [keyed] = (await manager.query(
181
+ `SELECT ${ENTRY_COLUMNS} FROM "mortar_economy_entries"
182
+ WHERE "holder_id" = $1 AND "idempotency_key" = $2`,
183
+ [holderId, request.idempotencyKey],
184
+ )) as EntryRow[];
185
+ if (keyed) {
186
+ const entry = entryViewOf(keyed);
187
+ if (entry.kind !== 'reversal' || entry.refundOf !== found.entry_id) {
188
+ throw new LedgerKeyReusedError(request.idempotencyKey);
189
+ }
190
+ return { entry, taken: entry.amount, spent: amount - entry.amount, earlier: null };
191
+ }
192
+
193
+ const [given] = (await manager.query(
194
+ `SELECT ${ENTRY_COLUMNS} FROM "mortar_economy_entries" WHERE "refund_of" = $1`,
195
+ [found.entry_id],
196
+ )) as EntryRow[];
197
+ if (given) return { entry: null, taken: 0, spent: 0, earlier: entryViewOf(given) };
198
+
199
+ // Read again under the lock: a spend may have drawn on it meanwhile.
200
+ const lot = (await this.lotOf(manager, holderId, request.purchaseId))!;
201
+ const remaining = toAmount(lot.remaining);
202
+ if (remaining === 0) return { entry: null, taken: 0, spent: amount, earlier: null };
203
+ const entry = await this.insert(
204
+ manager,
205
+ holderId,
206
+ 'reversal',
207
+ { ...request, currency: lot.currency, amount: remaining },
208
+ balance - remaining,
209
+ lot.entry_id,
210
+ );
211
+ await this.draw(manager, entry.id, [{ lotId: lot.entry_id, amount: remaining }]);
212
+ await this.setBalance(manager, holderId, lot.currency, entry.balanceAfter);
213
+ return { entry, taken: remaining, spent: amount - remaining, earlier: null };
214
+ });
215
+ }
216
+
157
217
  /** A holder's balance in a currency: nothing for one never credited. */
158
218
  async balance(holderId: string, currency: string): Promise<number> {
159
219
  const [row] = (await resolveManager(this.dataSource).query(
@@ -1,19 +1,20 @@
1
1
  import { CreateGameEconomy1791401023940 } from '../migrations/1791401023940-CreateGameEconomy';
2
+ import { AddReversals1791548064129 } from '../migrations/1791548064129-AddReversals';
2
3
  import { EconomyBalance } from './economy-balance.entity';
3
4
  import { EconomyDraw } from './economy-draw.entity';
4
5
  import { EconomyEntry } from './economy-entry.entity';
5
6
  import { EconomyLot } from './economy-lot.entity';
6
7
 
7
8
  export { EconomyBalance, EconomyDraw, EconomyEntry, EconomyLot };
8
- export { CreateGameEconomy1791401023940 };
9
+ export { AddReversals1791548064129, CreateGameEconomy1791401023940 };
9
10
  export { GameEconomyModule } from './game-economy.module';
10
11
  export { GameEconomyService } from './game-economy.service';
11
12
  export type { GameEconomyOptions } from './game-economy-options.types';
12
13
  export type { MovementRequest, RefundRequest } from './movement-request.types';
13
- export type { EntryView, LotView, Reconciliation } from './economy-views';
14
+ export type { EntryView, LotView, Reconciliation, Reversal } from './economy-views';
14
15
 
15
16
  /** Register alongside the project's own entities. */
16
17
  export const gameEconomyEntities = [EconomyEntry, EconomyBalance, EconomyLot, EconomyDraw];
17
18
 
18
19
  /** Register alongside the project's own migrations. */
19
- export const gameEconomyMigrations = [CreateGameEconomy1791401023940];
20
+ export const gameEconomyMigrations = [CreateGameEconomy1791401023940, AddReversals1791548064129];