@better-giving/donation 3.0.4 → 3.0.6

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.
@@ -0,0 +1,316 @@
1
+ import type { Environment } from "@better-giving/types/list";
2
+ import type { IAllocation, TDonationSource, TDonorTitle } from "./schema.mjs";
3
+
4
+ interface IReferrerCommission {
5
+ from_tip: number;
6
+ from_fee: number;
7
+ /** exist when paid */
8
+ transfer_id?: number;
9
+ }
10
+
11
+ export interface ITributeNotif {
12
+ toEmail: string;
13
+ toFullName: string;
14
+ fromMsg: string;
15
+ }
16
+
17
+ export type TFiatRamp = "STRIPE" | "CHARIOT" | "PAYPAL";
18
+ export type TOnHoldStatus = "intent" | "pending";
19
+
20
+ export type TDonationOnholdStatus = "intent" | "pending";
21
+
22
+ export interface IDonationOnHoldAttrLegacy {
23
+ /** @deprecated */
24
+ apesComplianceReviewStatus?: "approved";
25
+ /** @deprecated */
26
+ apesComplianceTimeWindow?: string;
27
+ /** @deprecated */
28
+ client?: "apes";
29
+ /** @deprecated */
30
+ destinationChainId?: "fiat" | "137";
31
+ /** @deprecated */
32
+ donationFinalized?: false;
33
+ /** @deprecated 1-100 str */
34
+ splitLiq?: string;
35
+ /** @deprecated - no more inhouse pipeline */
36
+ third_party?: boolean;
37
+ }
38
+
39
+ export interface IDonationOnHoldAttr {
40
+ transactionDate: string;
41
+ transactionId: string;
42
+ allocation?: IAllocation;
43
+ amount: number;
44
+ status: TOnHoldStatus;
45
+ tipAmount: number;
46
+ /**
47
+ "USD", "TRX", "karate-295", "BRL", "GBP", "USDC", "JPY", "ETH", "USDCMATIC", "EUR", "INR", "THB", "PHP",
48
+ "XRP", "RUB", "CAD", "karate-1" ... */
49
+ denomination: string;
50
+ /** bg-marketplace | bg-widget */
51
+ appUsed: TDonationSource;
52
+ /** "fiat", "trx", "hbar", "eth", "matic", "xrp-mainnet" */
53
+ chainId: string;
54
+ /** "Fiat", "TRON", "Hedera", "Ethereum", "", "Polygon", "Stripe", "XRP Ledger" */
55
+ chainName: string;
56
+ charityName: string;
57
+ claimed?: boolean;
58
+ /** may be empty */
59
+ company_name?: string;
60
+ donor_public?: boolean;
61
+ kycEmail: string;
62
+ /** @legacy */
63
+ email?: string;
64
+ /** 0 when donating to fund */
65
+ endowmentId: number;
66
+ fiatRamp?: TFiatRamp;
67
+ feeAllowance?: number;
68
+ fiscalSponsored: boolean;
69
+ fullName: string;
70
+ /** may be empty, if donation is to npo */
71
+ fund_id?: string;
72
+ fund_members?: number[];
73
+ fund_name?: string;
74
+ hideBgTip?: boolean;
75
+ /** may be empty */
76
+ inHonorOf?: string;
77
+ isRecurring?: boolean;
78
+ msg_to_npo?: string;
79
+ network: Environment;
80
+ /** may be empty */
81
+ nonProfitMsg?: string;
82
+ /** Nowpayments: number, custom: uuid */
83
+ payment_id?: number | string;
84
+ /** e.g. Bank transfer */
85
+ paymentMethod?: string;
86
+ /** may be empty */
87
+ programId?: string;
88
+ /** may be empty */
89
+ programName?: string;
90
+ stripeDepositVerifyUrl?: string;
91
+ /** TTL attribute */
92
+ expireAt?: number;
93
+ title?: TDonorTitle;
94
+ tributeNotif?: ITributeNotif;
95
+ ukGiftAid?: boolean;
96
+ usdValue: number;
97
+ /** may be empty */
98
+ walletAddress?: string;
99
+ }
100
+
101
+ export interface IDonationOnHold
102
+ extends IDonationOnHoldAttr,
103
+ IDonationOnHoldAttrLegacy {}
104
+
105
+ export interface IDonationFinalAttrLegacy {
106
+ /** @deprecated "", " "*/
107
+ addressComplement?: string;
108
+ /** @deprecated 4 */
109
+ apesComplianceNewRecipient?: 4;
110
+ /** @deprecated "approved", "pending" */
111
+ apesComplianceReviewStatus?: string;
112
+ /** @deprecated */
113
+ apesComplianceTimeWindow?: string;
114
+ /** @deprecated */
115
+ charityId?: string | number;
116
+ /** @deprecated */
117
+ checked8283?: "no" | "yes";
118
+ /** @deprecated */
119
+ client?: "apes" | "normal";
120
+ /** @deprecated */
121
+ consent_marketing?: boolean;
122
+ /** @deprecated */
123
+ consent_tax?: boolean;
124
+ /** @deprecated */
125
+ cryptoFee?: number;
126
+ /** @deprecated - all donations in this table are settled/final */
127
+ donationFinalized?: boolean;
128
+ /** @deprecated */
129
+ fiscalSponsorshipFee?: number;
130
+ /** @deprecated */
131
+ fundDepositTxHash?: string;
132
+ /** @deprecated */
133
+ fundId?: number;
134
+ /** @deprecated */
135
+ fundMembers?: string[];
136
+ /** @deprecated may be empty */
137
+ nftAddress?: string;
138
+ nftRequested?: boolean;
139
+ /** @deprecated */
140
+ receiptRequested?: boolean;
141
+ /** @deprecated */
142
+ splitLiq?: string;
143
+ /** @deprecated "null", "UST", "axlUSDC", "USDC", "nulll" */
144
+ swapDenomination?: string;
145
+ /** @deprecated */
146
+ swapFinalAmount?: number;
147
+ /** @deprecated */
148
+ swapFinished?: boolean;
149
+ /** @deprecated */
150
+ swapStarted?: boolean;
151
+ /** @deprecated */
152
+ taxReceiptSent?: "yes" | "no";
153
+ /** @deprecated e.g. "White Whale", "Plutos Pot / Lunaverse", "Spaar"..*/
154
+ tcaAssociation?: string;
155
+ /** @deprecated */
156
+ ustFinal?: number;
157
+ /** @deprecated */
158
+ walletAddress?: string;
159
+ }
160
+
161
+ export type TExplicit<T> = { [K in keyof T]-?: T[K] };
162
+
163
+ export interface IDonationFinalAttr {
164
+ amount?: number;
165
+ allocation?: IAllocation;
166
+ /** "bg-marketplace", "restore-earth", "angel-protocol",
167
+ "ukraine-portal", "bg-widget", undefined, "aging", "black-history-month",
168
+ "make-whole", "mental-health" */
169
+ appUsed?: TDonationSource | (string & {});
170
+ baseFee?: number;
171
+ /**
172
+ "fiat", "columbus-5", "eth", "matic", "juno-1", "ltc", undefined, "btc", "phoenix-1", "56", "1", "137",
173
+ "xrp-mainnet", "zec", "sol", "bch", "bsc", "cchain", "xvg", "xrp", "sei-1", "icx", "base",
174
+ "trx", "avaxc""
175
+ */
176
+ chainId?: string;
177
+ /**
178
+ "Fiat", "Terra Mainnet", "STRIPE", "Ethereum Mainnet",
179
+ "Polygon", "Juno Mainnet", "Litecoin", undefined, "Ethereum", "Bitcoin", "Terra Phoenix Mainnet",
180
+ "Binance Smart Chain", "Polygon Mainnet", "XRP Ledger",
181
+ "Zcash", "Solana", "BNB Smart Chain Mainnet", "Bitcoin Cash",
182
+ "Avalanche C-Chain", "Verge", "XRP", "Sei", "ICON", "Base", "TRON", "CHARIOT"
183
+ */
184
+ chainName?: string;
185
+ charityName?: string;
186
+ /** may be empty */
187
+ city?: string;
188
+ claimed?: boolean;
189
+ /** may be empty */
190
+ company_name?: string;
191
+ /** may be empty */
192
+ country?: string;
193
+ donor_public?: boolean;
194
+ donor_message?: string;
195
+ /**
196
+ PHP", "UST", "USD", "LUNA", "ETH", "USDCMATIC", "axlUSDC", "LTC", undefined, "EUR", "NZD", "JUNO", "INR",
197
+ "IDR", "GBP", "USDTMATIC", "PKR", "BTC", "SEK", "HKD", "SGD", "BNB", "CAD", "MATICMAINNET",
198
+ "USDC", "MOP", "XRP", "JPY", "MATIC", "RSD", "ZEC", "TWD", "SOL", "AUD", "KRW", "BCH", "CHF", "TEL", "USDTBSC",
199
+ "YER", "ATOM", "AVAXC", "USDTERC20", "XVG", "BUSD", "SEI", "ICX", "ETHBASE", "USDC.e", "USDCBASE", "TRX",
200
+ "VND", "SZL", "GONE", "AFN", "PLN", "NOK", "WETH", "EGP", "BUSDBSC", "USDCARC20", "USDTTRC20", "THB"
201
+ */
202
+ denomination?: string;
203
+
204
+ donationFinalAmount?: number;
205
+ /**
206
+ "fiat", undefined, "matic", "137", "noble-1", "eth"*/
207
+ destinationChainId?: string;
208
+ /** "fiat", undefined, "matic", "juno-1", "137", "noble-1", "eth" */
209
+ donationFinalChainId?: string;
210
+ /**
211
+ * "USD", "aUSDC", "USDC", "axlUSDC"
212
+ */
213
+ donationFinalDenom?: string;
214
+ /** iso date */
215
+ donationFinalTxDate?: string;
216
+ donationFinalTxHash?: string;
217
+
218
+ endowmentId?: number;
219
+ excessFeeAllowanceUsd?: number;
220
+ feeAllowance?: number;
221
+
222
+ fiatRamp?: TFiatRamp;
223
+ fiscalSponsored?: boolean;
224
+ fiscalSponsorFee?: number;
225
+ /** may be empty */
226
+ fullName?: string;
227
+ fund_id?: string;
228
+ fund_name?: string;
229
+ fund_members?: number[];
230
+ /** may be empty */
231
+ inHonorOf?: string;
232
+ isRecurring?: boolean;
233
+ kycEmail?: string;
234
+ /** @warning, about 14 legacy records (~2021) contain invalid email */
235
+ email?: string;
236
+ msg_to_npo?: string;
237
+ network?: Environment;
238
+ /** may be empty */
239
+ nonProfitMsg?: string;
240
+ /** indicates this is a tip record */
241
+ parentTx?: string;
242
+ /**
243
+ "Credit Card", undefined, "Stripe Link", "Bank Transfer",
244
+ "Crypto", "Debit Card", "link", "Card", "Bank", "crypto", "Amazon Pay", "Daf", "Affirm", "eps", "card",
245
+ "p24", "affirm"
246
+ */
247
+ paymentMethod?: string;
248
+ processingFee?: number;
249
+ /** may be empty */
250
+ programId?: string;
251
+ /** may be empty */
252
+ programName?: string;
253
+ referrer_commission?: IReferrerCommission;
254
+ referrer?: string;
255
+ settledUsdAmount?: number;
256
+ state?: string;
257
+ /** @legacy may be empty */
258
+ stateAddress?: string;
259
+ streetAddress?: string;
260
+ taxReceiptId?: string;
261
+ /** Mr Ms Mrs Mx, may be empty */
262
+ title?: string;
263
+ /** iso */
264
+ transactionDate?: string;
265
+ transactionId: string;
266
+ tributeNotif?: ITributeNotif;
267
+ ukGiftAid?: boolean;
268
+ usdValue?: number;
269
+ /** may be empty */
270
+ zipCode?: string;
271
+ }
272
+
273
+ export interface IDonationFinal
274
+ extends IDonationFinalAttr,
275
+ IDonationFinalAttrLegacy {}
276
+
277
+ export interface IPublicDonor {
278
+ amount: number;
279
+ /** iso */
280
+ date: string;
281
+ donation_id: string;
282
+ donor_id: string;
283
+ donor_message: string;
284
+ donor_name: string;
285
+ env: Environment;
286
+ /** uuidv4 */
287
+ id: string;
288
+ /** Endow or fund ID */
289
+ recipient_id: string;
290
+ }
291
+
292
+ export interface ISubscription {
293
+ //PK
294
+ subscription_id: string;
295
+ app_used: string;
296
+ charity_name: string;
297
+ customer_id: string;
298
+ email: string;
299
+ endowment_id: number;
300
+ fiat_ramp: "STRIPE";
301
+ fiscal_sponsored: boolean;
302
+ hide_bg_tip: boolean;
303
+ /** url*/
304
+ latest_invoice?: string;
305
+ network: Environment;
306
+ product_id: string;
307
+ /**
308
+ * Determines overall price the user has to pay
309
+ * For example, we have a recurring subscription plan of $1 per month.
310
+ * If quantity is set to 2 then the user pays $2 per month
311
+ */
312
+ quantity: number;
313
+ split_liq: string;
314
+ /** @link https://docs.stripe.com/billing/subscriptions/overview#payment-status */
315
+ status: "active" | "incomplete";
316
+ }
@@ -0,0 +1,118 @@
1
+ import {
2
+ GetCommand,
3
+ PutCommand,
4
+ QueryCommand,
5
+ UpdateCommand,
6
+ } from "@aws-sdk/lib-dynamodb";
7
+ import { Db, type TxType, UpdateBuilder } from "@better-giving/db";
8
+ import type { IPageKeyed } from "@better-giving/types/api";
9
+ import type {
10
+ IDonationOnHold,
11
+ IDonationOnHoldAttr,
12
+ TExplicit,
13
+ } from "./interfaces.mjs";
14
+ import type { IDonationsSearch } from "./schema.mjs";
15
+
16
+ type K = keyof IDonationOnHoldAttr;
17
+
18
+ export class OnHoldDonationsDb extends Db {
19
+ static readonly table = "on_hold_donations";
20
+ static readonly gsi_email$tx_date = "email-tx_date-gsi";
21
+
22
+ key(id: string) {
23
+ return { transactionId: id } satisfies Pick<
24
+ IDonationOnHold,
25
+ "transactionId"
26
+ >;
27
+ }
28
+
29
+ async put(data: TExplicit<IDonationOnHoldAttr>) {
30
+ const cmd = new PutCommand({
31
+ TableName: OnHoldDonationsDb.table,
32
+ Item: data,
33
+ ConditionExpression: `attribute_not_exists(${"transactionId" satisfies keyof IDonationOnHoldAttr})`,
34
+ });
35
+ return this.client.send(cmd);
36
+ }
37
+
38
+ async update(
39
+ id: string,
40
+ data: Partial<Omit<IDonationOnHoldAttr, "transactionId">>
41
+ ): Promise<IDonationOnHold> {
42
+ const upd8 = new UpdateBuilder();
43
+ for (const k in data) {
44
+ upd8.set(k as K, (data as any)[k]);
45
+ }
46
+ const cmd = new UpdateCommand({
47
+ TableName: OnHoldDonationsDb.table,
48
+ Key: this.key(id),
49
+ ...upd8.collect(),
50
+ });
51
+ return this.client.send(cmd).then((r) => r.Attributes as any);
52
+ }
53
+
54
+ async item(id: string): Promise<IDonationOnHold | undefined> {
55
+ const cmd = new GetCommand({
56
+ TableName: OnHoldDonationsDb.table,
57
+ Key: this.key(id),
58
+ });
59
+ return this.client.send(cmd).then((r) => r.Item as any);
60
+ }
61
+
62
+ put_txi(data: TExplicit<IDonationOnHoldAttr>) {
63
+ const cmd = new PutCommand({
64
+ TableName: OnHoldDonationsDb.table,
65
+ Item: data,
66
+ ConditionExpression: `attribute_not_exists(${"transactionId" satisfies keyof IDonationOnHoldAttr})`,
67
+ });
68
+ return this.client.send(cmd);
69
+ }
70
+ del_txi(id: string): TxType["Delete"] {
71
+ return { TableName: OnHoldDonationsDb.table, Key: this.key(id) };
72
+ }
73
+
74
+ async list_by_email(
75
+ email: string,
76
+ opts?: IDonationsSearch
77
+ ): Promise<IPageKeyed<IDonationOnHold>> {
78
+ /** key condition expression */
79
+ let kce = "#email = :email";
80
+ /** expression attribute names */
81
+ const ean: Record<string, string> = {
82
+ "#email": "email" satisfies K,
83
+ };
84
+ /** expression attribute values */
85
+ const eav: Record<string, any> = {
86
+ ":email": email,
87
+ };
88
+
89
+ if (opts?.date_start && opts?.date_end) {
90
+ kce += " AND #settled_date BETWEEN :date_start AND :date_end";
91
+ ean["#settled_date"] = "transactionDate" satisfies K;
92
+ eav[":date_start"] = opts.date_start;
93
+ eav[":date_end"] = opts.date_end;
94
+ } else if (opts?.date_start) {
95
+ kce += " AND #settled_date >= :date_start";
96
+ ean["#settled_date"] = "transactionDate" satisfies K;
97
+ eav[":date_start"] = opts.date_start;
98
+ } else if (opts?.date_end) {
99
+ kce += " AND #settled_date <= :date_end";
100
+ ean["#settled_date"] = "transactionDate" satisfies K;
101
+ eav[":date_end"] = opts.date_end;
102
+ }
103
+
104
+ const cmd = new QueryCommand({
105
+ TableName: OnHoldDonationsDb.table,
106
+ IndexName: OnHoldDonationsDb.gsi_email$tx_date,
107
+ KeyConditionExpression: "#email = :email",
108
+ ExpressionAttributeNames: {
109
+ "#email": "email" satisfies K,
110
+ },
111
+ ExpressionAttributeValues: {
112
+ ":email": email,
113
+ },
114
+ ScanIndexForward: false,
115
+ });
116
+ return this.client.send(cmd).then(this.to_page<IDonationOnHold>);
117
+ }
118
+ }
package/src/paypal.mts ADDED
@@ -0,0 +1,85 @@
1
+ export declare namespace FiatDonations {
2
+ type Currency = {
3
+ /** lowercase ISO 4217 code */
4
+ currency_code: string;
5
+ minimum_amount: number;
6
+ rate: number;
7
+ timestamp: string;
8
+ };
9
+ }
10
+
11
+ export declare namespace PayPalDonation {
12
+ type CreateOrder = {
13
+ purchase_units: PurchaseUnit[];
14
+ intent: Intent;
15
+ payment_source?: PaymentSource;
16
+ };
17
+
18
+ // see Response object description in official docs
19
+ // https://developer.paypal.com/docs/api/orders/v2/#orders_create
20
+ type Order = {
21
+ id: string;
22
+ status: Status;
23
+ intent: Intent;
24
+ payment_source: PaymentSource;
25
+ purchase_units: PurchaseUnit[];
26
+ payer: Payer;
27
+ create_time: Date;
28
+ links: Link[];
29
+ };
30
+
31
+ type Link = {
32
+ href: string;
33
+ rel: string;
34
+ method: string;
35
+ };
36
+
37
+ type Payer = {
38
+ name: Name;
39
+ email_address: string;
40
+ payer_id: string;
41
+ };
42
+
43
+ type PaymentSource = {
44
+ paypal: {
45
+ name: Name;
46
+ email_address: string;
47
+ account_id: string;
48
+ };
49
+ };
50
+
51
+ type Name = {
52
+ given_name: string;
53
+ surname: string;
54
+ };
55
+
56
+ type PurchaseUnit = {
57
+ // don't need 'reference_id'
58
+ amount: {
59
+ /** Three-character ISO-4217 code. */
60
+ currency_code: string;
61
+ value: string;
62
+ };
63
+ /** @link https://developer.paypal.com/docs/api/orders/v2/#orders_get */
64
+ payments?: {
65
+ captures: CapturedPayment[];
66
+ };
67
+ };
68
+
69
+ type CapturedPayment = {
70
+ seller_receivable_breakdown: {
71
+ gross_amount: { value: number };
72
+ paypal_fee: { value: number };
73
+ net_amount: { value: number };
74
+ };
75
+ };
76
+
77
+ type Intent = "CAPTURE" | "AUTHORIZE";
78
+ type Status =
79
+ | "CREATED"
80
+ | "SAVED"
81
+ | "APPROVED"
82
+ | "VOIDED"
83
+ | "COMPLETED"
84
+ | "PAYER_ACTION_REQUIRED";
85
+ }
package/src/schema.mts CHANGED
@@ -1,3 +1,5 @@
1
+ import { $int_gte1 } from "@better-giving/schemas";
2
+ import { endOfDay, iso_date, startOfDay } from "@better-giving/schemas/date";
1
3
  import * as v from "valibot";
2
4
  export const frequencies = ["one-time", "recurring"] as const;
3
5
  export const frequency = v.picklist(
@@ -5,7 +7,7 @@ export const frequency = v.picklist(
5
7
  "Please select donation frequency"
6
8
  );
7
9
 
8
- export type Frequency = v.InferOutput<typeof frequency>;
10
+ export type TFrequency = v.InferOutput<typeof frequency>;
9
11
 
10
12
  export const donation_sources = [
11
13
  "bg-marketplace",
@@ -14,12 +16,12 @@ export const donation_sources = [
14
16
  ] as const;
15
17
 
16
18
  export const donation_source = v.picklist(donation_sources);
17
- export type DonationSource = v.InferOutput<typeof donation_source>;
19
+ export type TDonationSource = v.InferOutput<typeof donation_source>;
18
20
 
19
21
  export const donor_titles = ["Mr", "Mrs", "Ms", "Mx", ""] as const;
20
22
  export const donor_title = v.picklist(donor_titles);
21
23
 
22
- export type DonorTitle = v.InferOutput<typeof donor_title>;
24
+ export type TDonorTitle = v.InferOutput<typeof donor_title>;
23
25
 
24
26
  const pct = v.pipe(v.number(), v.minValue(0), v.maxValue(100));
25
27
  export const allocation = v.pipe(
@@ -31,4 +33,34 @@ export const allocation = v.pipe(
31
33
  v.check((x) => x.liq + x.lock + x.cash === 100, "Allocation must sum to 100%")
32
34
  );
33
35
 
34
- export type Allocation = v.InferOutput<typeof allocation>;
36
+ export type IAllocation = v.InferOutput<typeof allocation>;
37
+
38
+ export const page_opts = v.object({
39
+ limit: v.optional($int_gte1),
40
+ next: v.optional(v.pipe(v.string(), v.base64())),
41
+ });
42
+
43
+ export interface IPageOpts extends v.InferOutput<typeof page_opts> {}
44
+
45
+ const donations_search_raw = v.object({
46
+ ...page_opts.entries,
47
+ date_start: v.optional(iso_date(startOfDay)),
48
+ date_end: v.optional(iso_date(endOfDay)),
49
+ });
50
+
51
+ export const donations_search = v.pipe(
52
+ donations_search_raw,
53
+ v.forward(
54
+ v.partialCheck(
55
+ [["date_start"], ["date_end"]],
56
+ ({ date_start: a, date_end: b }) => {
57
+ return a && b ? a <= b : true;
58
+ },
59
+ "start date must be earlier than end date"
60
+ ),
61
+ ["date_start"]
62
+ )
63
+ );
64
+
65
+ export interface IDonationsSearch
66
+ extends v.InferOutput<typeof donations_search_raw> {}
@@ -0,0 +1,50 @@
1
+ import {
2
+ DeleteCommand,
3
+ PutCommand,
4
+ UpdateCommand,
5
+ } from "@aws-sdk/lib-dynamodb";
6
+ import { Db, UpdateBuilder } from "@better-giving/db";
7
+ import type { ISubscription } from "./interfaces.mjs";
8
+
9
+ type K = keyof ISubscription;
10
+ export class SubsDb extends Db {
11
+ static readonly table = "subscriptions";
12
+
13
+ key(id: string) {
14
+ return { subscription_id: id } satisfies Pick<
15
+ ISubscription,
16
+ "subscription_id"
17
+ >;
18
+ }
19
+ async put(data: ISubscription) {
20
+ const cmd = new PutCommand({
21
+ TableName: SubsDb.table,
22
+ Item: data,
23
+ ConditionExpression: `attribute_not_exists(${"subscription_id" satisfies K})`,
24
+ });
25
+ return this.client.send(cmd);
26
+ }
27
+ async update(
28
+ id: string,
29
+ data: Partial<Omit<ISubscription, "subscription_id">>
30
+ ): Promise<ISubscription> {
31
+ const upd8 = new UpdateBuilder();
32
+ for (const k in data) {
33
+ upd8.set(k as K, (data as any)[k]);
34
+ }
35
+ const cmd = new UpdateCommand({
36
+ TableName: SubsDb.table,
37
+ Key: this.key(id),
38
+ ...upd8.collect(),
39
+ });
40
+ return this.client.send(cmd).then((r) => r.Attributes as any);
41
+ }
42
+
43
+ async del(id: string) {
44
+ const cmd = new DeleteCommand({
45
+ TableName: SubsDb.table,
46
+ Key: this.key(id),
47
+ });
48
+ return this.client.send(cmd);
49
+ }
50
+ }
@@ -1,39 +0,0 @@
1
- import type { ISODate } from "@better-giving/types/alias";
2
- import type { Environment } from "@better-giving/types/list";
3
-
4
- export type DMKey = `DM#${string}`;
5
-
6
- export declare namespace GSI1 {
7
- type Name = "recipient-env-gsi";
8
-
9
- interface Key {
10
- /** `Recipient#{recipient_id}#{env}` */
11
- gsi1PK: `Recipient#${string}#${Environment}`;
12
- gsi1SK: ISODate;
13
- }
14
- }
15
-
16
- export declare namespace DonationMessage {
17
- /** `DM#{uuid}` */
18
- interface PrimaryKey {
19
- PK: DMKey;
20
- SK: DMKey;
21
- }
22
-
23
- interface NonKeyAttributes {
24
- /** USD amount at the time of donation */
25
- amount: number;
26
- date: ISODate;
27
- donation_id: string;
28
- donor_id: string;
29
- donor_message: string;
30
- donor_name: string;
31
- env: Environment;
32
- /** uuidv4 */
33
- id: string;
34
- /** Endow or fund ID */
35
- recipient_id: string;
36
- }
37
-
38
- interface DBRecord extends PrimaryKey, NonKeyAttributes, GSI1.Key {}
39
- }