@better-giving/fundraiser 3.0.6 → 3.0.8

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.
@@ -1,6 +1,7 @@
1
1
  import type { ToDoc, ToHitFields, ToUpdate } from "@better-giving/types/cloudsearch";
2
- import type { FundInternal, NewFund } from "./schema.mjs";
3
- export interface CloudsearchFund extends Pick<NewFund, "name" | "description" | "logo" | "banner" | "featured" | "members" | "target">, Pick<FundInternal, "id" | "env" | "active" | "verified" | "donation_total_usd" | "creator_id" | "creator_name"> {
2
+ import type { IFundInternal } from "./interfaces.mjs";
3
+ import type { IFundNew } from "./schema.mjs";
4
+ export interface CloudsearchFund extends Pick<IFundNew, "name" | "description" | "logo" | "banner" | "featured" | "members" | "target">, Pick<IFundInternal, "id" | "env" | "active" | "verified" | "donation_total_usd" | "creator_id" | "creator_name"> {
4
5
  /** iso | "9999-12-31T23:59:59Z" year 9999 */
5
6
  expiration: string;
6
7
  }
package/dist/db.d.mts CHANGED
@@ -1,20 +1,38 @@
1
- import type { FundInternal, NewFund } from "./schema.mjs";
2
- export declare const fundGsi: {
3
- readonly slugEnv: "slug-env-gsi";
4
- };
5
- export interface Keys {
6
- /** Fund#${uuid} */
7
- PK: `Fund#${string}`;
8
- SK: `Fund#${string}`;
9
- }
10
- export interface Attributes extends NewFund, FundInternal {
11
- }
12
- export interface DbRecord extends Keys, Attributes {
13
- }
14
- export declare namespace SlugEnvGsi {
15
- type Name = typeof fundGsi.slugEnv;
16
- interface Keys extends Pick<Attributes, "slug" | "env"> {
17
- }
18
- interface Record extends DbRecord {
19
- }
1
+ import { Db, type TxType } from "@better-giving/db";
2
+ import type { IFund } from "./interfaces.mjs";
3
+ import type { IFundUpdate } from "./schema.mjs";
4
+ export declare class FundDb extends Db {
5
+ static readonly table = "funds";
6
+ static readonly slug_env_gsi = "slug-env-gsi";
7
+ key_fund(id: string): {
8
+ PK: string;
9
+ SK: string;
10
+ };
11
+ fund_record(data: IFund): {
12
+ name: string;
13
+ description: string;
14
+ banner: string;
15
+ logo: string;
16
+ members: number[];
17
+ target: string;
18
+ videos: string[];
19
+ featured: boolean;
20
+ npo_owner: number;
21
+ expiration?: string | undefined;
22
+ slug?: string | undefined;
23
+ id: string;
24
+ env: import("@better-giving/schemas").Environment;
25
+ active: boolean;
26
+ verified: boolean;
27
+ donation_total_usd: number;
28
+ settings: import("./interfaces.mjs").IFundSettings;
29
+ creator_id: string;
30
+ creator_name: string;
31
+ PK: string;
32
+ SK: string;
33
+ };
34
+ fund_put_txi(data: IFund): TxType["Put"];
35
+ /**@param id - slug or uuid */
36
+ fund(id: string): Promise<IFund | undefined>;
37
+ fund_edit(id: string, { target, slug, ...update }: IFundUpdate): Promise<Record<string, any>>;
20
38
  }
package/dist/db.mjs CHANGED
@@ -1,3 +1,68 @@
1
- export const fundGsi = {
2
- slugEnv: "slug-env-gsi",
3
- };
1
+ import { QueryCommand, UpdateCommand, } from "@aws-sdk/lib-dynamodb";
2
+ import { Db, UpdateBuilder } from "@better-giving/db";
3
+ import { UUID_REGEX } from "valibot";
4
+ export class FundDb extends Db {
5
+ static table = "funds";
6
+ static slug_env_gsi = "slug-env-gsi";
7
+ key_fund(id) {
8
+ return {
9
+ PK: `Fund#${id}`,
10
+ SK: `Fund#${id}`,
11
+ };
12
+ }
13
+ fund_record(data) {
14
+ return {
15
+ ...this.key_fund(data.id),
16
+ ...data,
17
+ };
18
+ }
19
+ fund_put_txi(data) {
20
+ return {
21
+ TableName: FundDb.table,
22
+ Item: this.fund_record(data),
23
+ };
24
+ }
25
+ /**@param id - slug or uuid */
26
+ async fund(id) {
27
+ const q = {
28
+ TableName: FundDb.table,
29
+ Limit: 1,
30
+ };
31
+ if (UUID_REGEX.test(id)) {
32
+ q.KeyConditionExpression = "PK = :PK AND SK = :SK";
33
+ q.ExpressionAttributeValues = this.key_fund(id);
34
+ }
35
+ else {
36
+ q.IndexName = FundDb.slug_env_gsi;
37
+ q.KeyConditionExpression = "slug = :slug AND env = :env";
38
+ q.ExpressionAttributeValues = {
39
+ ":slug": id,
40
+ ":env": this.env,
41
+ };
42
+ }
43
+ const { Items: i = [] } = await this.client.send(new QueryCommand(q));
44
+ return i[0] && this.sans_keys(i[0]);
45
+ }
46
+ async fund_edit(id, { target, slug, ...update }) {
47
+ const updates = new UpdateBuilder();
48
+ if (slug)
49
+ updates.set("slug", slug);
50
+ if (slug === "")
51
+ updates.remove("slug");
52
+ if (target || target === "0") {
53
+ updates.set("target", target);
54
+ }
55
+ for (const [k, v] of Object.entries(update)) {
56
+ if (v === undefined)
57
+ continue;
58
+ updates.set(k, v);
59
+ }
60
+ const command = new UpdateCommand({
61
+ TableName: FundDb.table,
62
+ Key: this.key_fund(id),
63
+ ReturnValues: "ALL_NEW",
64
+ ...updates.collect(),
65
+ });
66
+ return this.client.send(command).then((res) => res.Attributes ?? {});
67
+ }
68
+ }
package/dist/index.d.mts CHANGED
@@ -1,17 +1,4 @@
1
- import type { IPageNumbered } from "@better-giving/types/api";
2
- import type { CloudsearchFund as FundItem } from "./cloudsearch.mjs";
3
- import type { FundInternal, NewFund } from "./schema.mjs";
4
- export type { Environment, FundSettings, FundUpdate, FundsEndowMemberOfParams, FundsParams, NewFund, } from "./schema.mjs";
5
- export type { FundItem };
6
- export interface FundMember {
7
- id: number;
8
- name: string;
9
- logo: string | undefined;
10
- banner: string | undefined;
11
- }
12
- export interface SingleFund extends Omit<NewFund, "members">, FundInternal {
13
- members: FundMember[];
14
- }
15
- export interface FundsPage extends IPageNumbered<FundItem> {
16
- }
1
+ export type { CloudsearchFund as FundItem } from "./cloudsearch.mjs";
2
+ export type { IFundNew, IFundUpdate, IFundsNpoMemberOfSearchObj, IFundsSearchObj, DonateMethodId, Environment, } from "./schema.mjs";
3
+ export { FundDb } from "./db.mjs";
17
4
  export declare const MAX_EXPIRATION = "9999-12-31T23:59:59Z";
package/dist/index.mjs CHANGED
@@ -1 +1,2 @@
1
+ export { FundDb } from "./db.mjs";
1
2
  export const MAX_EXPIRATION = "9999-12-31T23:59:59Z";
@@ -0,0 +1,28 @@
1
+ import type { DonateMethodId, Environment } from "@better-giving/schemas";
2
+ import type { IPageNumbered } from "@better-giving/types/api";
3
+ import type { CloudsearchFund } from "./cloudsearch.mjs";
4
+ import type { IFundNew } from "./schema.mjs";
5
+ export interface IFundSettings {
6
+ hide_bg_tip: boolean;
7
+ donateMethods?: DonateMethodId[];
8
+ }
9
+ export interface IFundCreator {
10
+ /** "{number}" - endow id, "{email} - user*/
11
+ creator_id: string;
12
+ creator_name: string;
13
+ }
14
+ export interface IFundInternal extends IFundCreator {
15
+ /** uuid */
16
+ id: string;
17
+ env: Environment;
18
+ /** fund can be closed before expiration */
19
+ active: boolean;
20
+ verified: boolean;
21
+ /** to date received: initialized to `0` */
22
+ donation_total_usd: number;
23
+ settings: IFundSettings;
24
+ }
25
+ export interface IFund extends IFundNew, IFundInternal {
26
+ }
27
+ export interface IFundsPage extends IPageNumbered<CloudsearchFund> {
28
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/schema.d.mts CHANGED
@@ -1,15 +1,13 @@
1
- import { type DonateMethodId } from "@better-giving/schemas";
2
- import type { Environment } from "@better-giving/types/list";
3
1
  import { type InferOutput } from "valibot";
4
2
  export { type DonateMethodId, slug } from "@better-giving/schemas";
5
3
  export type { Environment } from "@better-giving/types/list";
6
- export declare const fundId: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").UuidAction<string, undefined>]>;
4
+ export declare const fund_id: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").UuidAction<string, undefined>]>;
7
5
  /**
8
6
  * when fundraiser is created in the context of an NPO, all members of that NPO can edit the fundraiser
9
7
  * 0 - none
10
8
  */
11
9
  export declare const npo_owner: import("valibot").SchemaWithPipe<[import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 0, undefined>]>;
12
- export declare const newFund: import("valibot").ObjectSchema<{
10
+ export declare const fund_new: import("valibot").ObjectSchema<{
13
11
  readonly name: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").NonEmptyAction<string, "required">]>;
14
12
  readonly description: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").NonEmptyAction<string, "required">]>;
15
13
  readonly banner: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").UrlAction<string, undefined>]>;
@@ -24,7 +22,7 @@ export declare const newFund: import("valibot").ObjectSchema<{
24
22
  readonly npo_owner: import("valibot").SchemaWithPipe<[import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 0, undefined>]>;
25
23
  readonly slug: import("valibot").OptionalSchema<import("valibot").LazySchema<import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]> | import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").MaxLengthAction<string, 30, ({ requirement: r }: import("valibot").MaxLengthIssue<string, 30>) => string>, import("valibot").RegexAction<string, "should not be an id">, import("valibot").RegexAction<string, "allowed: numbers | letters | - | . | _ | ~">, import("valibot").ExcludesAction<string, "..", "should not contain double periods">, import("valibot").CustomSchema<string, "should not start with dot">, import("valibot").CustomSchema<string, "should not end with dot">]>>, never>;
26
24
  }, undefined>;
27
- export declare const fundUpdate: Omit<Omit<import("valibot").ObjectSchema<{
25
+ export declare const fund_update: Omit<Omit<import("valibot").ObjectSchema<{
28
26
  readonly name: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").NonEmptyAction<string, "required">]>;
29
27
  readonly description: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").NonEmptyAction<string, "required">]>;
30
28
  readonly banner: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").UrlAction<string, undefined>]>;
@@ -132,38 +130,20 @@ export declare const fundUpdate: Omit<Omit<import("valibot").ObjectSchema<{
132
130
  readonly issue: import("valibot").StringIssue | import("valibot").NumberIssue | import("valibot").MinValueIssue<number, 0> | import("valibot").NonEmptyIssue<string> | import("valibot").UrlIssue<string> | import("valibot").ArrayIssue | import("valibot").BooleanIssue | import("valibot").LiteralIssue | import("valibot").UnionIssue<import("valibot").StringIssue | import("valibot").NumberIssue | import("valibot").MinValueIssue<number, 0> | import("valibot").LiteralIssue> | import("valibot").CustomIssue | import("valibot").MaxLengthIssue<string, 30> | import("valibot").RegexIssue<string> | import("valibot").ExcludesIssue<string, ".."> | import("valibot").ObjectIssue;
133
131
  } | undefined;
134
132
  };
135
- export declare const fundsParams: import("valibot").ObjectSchema<{
133
+ export declare const funds_search: import("valibot").ObjectSchema<{
136
134
  /** search text */
137
135
  readonly query: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, never>;
138
136
  /** input str: from url */
139
- readonly page: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").TransformAction<string, number>, import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 1, undefined>]>, never>;
137
+ readonly page: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").TransformAction<string, number>, import("valibot").SchemaWithPipe<[import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 1, undefined>]>]>;
140
138
  }, undefined>;
141
- export declare const fundsEndowMemberOfParams: import("valibot").ObjectSchema<{
142
- readonly npoProfileFeatured: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").TransformAction<string, boolean>, import("valibot").BooleanSchema<undefined>]>, never>;
139
+ export declare const funds_npo_memberof_search: import("valibot").ObjectSchema<{
140
+ readonly npo_profile_featured: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").TransformAction<string, boolean>, import("valibot").BooleanSchema<undefined>]>, never>;
143
141
  }, undefined>;
144
- export interface NewFund extends InferOutput<typeof newFund> {
142
+ export interface IFundNew extends InferOutput<typeof fund_new> {
145
143
  }
146
- export interface FundUpdate extends InferOutput<typeof fundUpdate> {
144
+ export interface IFundUpdate extends InferOutput<typeof fund_update> {
147
145
  }
148
- export interface FundsParams extends InferOutput<typeof fundsParams> {
146
+ export interface IFundsSearchObj extends InferOutput<typeof funds_search> {
149
147
  }
150
- export interface FundsEndowMemberOfParams extends InferOutput<typeof fundsEndowMemberOfParams> {
151
- }
152
- export interface FundSettings {
153
- hide_bg_tip: boolean;
154
- donateMethods?: DonateMethodId[];
155
- }
156
- export interface FundInternal {
157
- /** uuid */
158
- id: string;
159
- env: Environment;
160
- /** fund can be closed before expiration */
161
- active: boolean;
162
- verified: boolean;
163
- /** to date received: initialized to `0` */
164
- donation_total_usd: number;
165
- /** "{number}" - endow id, "{email} - user*/
166
- creator_id: string;
167
- creator_name: string;
168
- settings: FundSettings;
148
+ export interface IFundsNpoMemberOfSearchObj extends InferOutput<typeof funds_npo_memberof_search> {
169
149
  }
package/dist/schema.mjs CHANGED
@@ -1,33 +1,32 @@
1
- import { slug } from "@better-giving/schemas";
2
- import { url, array, boolean, integer, isoTimestamp, literal, maxLength, minValue, nonEmpty, number, object, optional, partial, pick, pipe, string, transform, trim, union, uuid, } from "valibot";
1
+ import { $, $int_gte1, slug } from "@better-giving/schemas";
2
+ import { url, array, boolean, integer, isoTimestamp, literal, maxLength, minValue, nonEmpty, number, object, optional, partial, pick, pipe, string, transform, union, uuid, } from "valibot";
3
3
  export { slug } from "@better-giving/schemas";
4
- const str = pipe(string(), trim());
5
- export const fundId = pipe(str, uuid());
4
+ export const fund_id = pipe($, uuid());
6
5
  /**
7
6
  * when fundraiser is created in the context of an NPO, all members of that NPO can edit the fundraiser
8
7
  * 0 - none
9
8
  */
10
9
  export const npo_owner = pipe(number(), integer(), minValue(0));
11
- export const newFund = object({
12
- name: pipe(str, nonEmpty("required")),
13
- description: pipe(str, nonEmpty("required")),
14
- banner: pipe(str, url()),
15
- logo: pipe(str, url()),
10
+ export const fund_new = object({
11
+ name: pipe($, nonEmpty("required")),
12
+ description: pipe($, nonEmpty("required")),
13
+ banner: pipe($, url()),
14
+ logo: pipe($, url()),
16
15
  /** endowment ids */
17
16
  members: pipe(array(pipe(number(), integer(), minValue(1))), nonEmpty(), maxLength(10)),
18
17
  featured: boolean(),
19
- expiration: optional(pipe(str, isoTimestamp("invalid date"), minValue(new Date().toISOString()) //created each parsing
18
+ expiration: optional(pipe($, isoTimestamp("invalid date"), minValue(new Date().toISOString()) //created each parsing
20
19
  )),
21
20
  /** `"0"` - none, {"number"} = fixed */
22
21
  target: union([
23
22
  literal("smart"),
24
23
  pipe(string(), transform((v) => +v), number(), minValue(0), transform((v) => v.toString())),
25
24
  ]),
26
- videos: array(pipe(str, url())),
25
+ videos: array(pipe($, url())),
27
26
  npo_owner,
28
27
  slug: optional(slug),
29
28
  });
30
- export const fundUpdate = partial(pick(newFund, [
29
+ export const fund_update = partial(pick(fund_new, [
31
30
  "name",
32
31
  "description",
33
32
  "banner",
@@ -37,13 +36,13 @@ export const fundUpdate = partial(pick(newFund, [
37
36
  "videos",
38
37
  "slug",
39
38
  ]));
40
- export const fundsParams = object({
39
+ export const funds_search = object({
41
40
  /** search text */
42
- query: optional(str),
41
+ query: optional($),
43
42
  /** input str: from url */
44
- page: optional(pipe(str, transform((x) => +x), number(), integer(), minValue(1))),
43
+ page: $int_gte1,
45
44
  });
46
- export const fundsEndowMemberOfParams = object({
45
+ export const funds_npo_memberof_search = object({
47
46
  /*
48
47
  * this endow is the only member (not an index fund),
49
48
  * and is approved:
@@ -52,5 +51,5 @@ export const fundsEndowMemberOfParams = object({
52
51
  *
53
52
  * input str: from url
54
53
  */
55
- npoProfileFeatured: optional(pipe(str, transform((x) => x === "true"), boolean())),
54
+ npo_profile_featured: optional(pipe($, transform((x) => x === "true"), boolean())),
56
55
  });
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@better-giving/fundraiser",
3
- "version": "3.0.6",
3
+ "version": "3.0.8",
4
4
  "peerDependencies": {
5
5
  "valibot": "0.42.0",
6
6
  "@better-giving/schemas": "2.0.0",
7
- "@better-giving/types": "1.1.8"
7
+ "@better-giving/types": "1.1.8",
8
+ "@better-giving/db": "2.0.1",
9
+ "@aws-sdk/lib-dynamodb": "3.485.0"
8
10
  },
9
11
  "devDependencies": {
10
12
  "@better-giving/config": "1.1.2"
@@ -3,11 +3,12 @@ import type {
3
3
  ToHitFields,
4
4
  ToUpdate,
5
5
  } from "@better-giving/types/cloudsearch";
6
- import type { FundInternal, NewFund } from "./schema.mjs";
6
+ import type { IFundInternal } from "./interfaces.mjs";
7
+ import type { IFundNew } from "./schema.mjs";
7
8
 
8
9
  export interface CloudsearchFund
9
10
  extends Pick<
10
- NewFund,
11
+ IFundNew,
11
12
  | "name"
12
13
  | "description"
13
14
  | "logo"
@@ -17,7 +18,7 @@ export interface CloudsearchFund
17
18
  | "target"
18
19
  >,
19
20
  Pick<
20
- FundInternal,
21
+ IFundInternal,
21
22
  | "id"
22
23
  | "env"
23
24
  | "active"
package/src/db.mts CHANGED
@@ -1,20 +1,78 @@
1
- import type { FundInternal, NewFund } from "./schema.mjs";
1
+ import {
2
+ QueryCommand,
3
+ type QueryCommandInput,
4
+ UpdateCommand,
5
+ } from "@aws-sdk/lib-dynamodb";
6
+ import { Db, type TxType, UpdateBuilder } from "@better-giving/db";
7
+ import { UUID_REGEX } from "valibot";
8
+ import type { IFund } from "./interfaces.mjs";
9
+ import type { IFundUpdate } from "./schema.mjs";
2
10
 
3
- export const fundGsi = {
4
- slugEnv: "slug-env-gsi",
5
- } as const;
11
+ export class FundDb extends Db {
12
+ static readonly table = "funds";
13
+ static readonly slug_env_gsi = "slug-env-gsi";
14
+ key_fund(id: string) {
15
+ return {
16
+ PK: `Fund#${id}`,
17
+ SK: `Fund#${id}`,
18
+ };
19
+ }
20
+ fund_record(data: IFund) {
21
+ return {
22
+ ...this.key_fund(data.id),
23
+ ...data,
24
+ };
25
+ }
26
+ fund_put_txi(data: IFund): TxType["Put"] {
27
+ return {
28
+ TableName: FundDb.table,
29
+ Item: this.fund_record(data),
30
+ };
31
+ }
32
+ /**@param id - slug or uuid */
33
+ async fund(id: string): Promise<IFund | undefined> {
34
+ const q: QueryCommandInput = {
35
+ TableName: FundDb.table,
36
+ Limit: 1,
37
+ };
38
+ if (UUID_REGEX.test(id)) {
39
+ q.KeyConditionExpression = "PK = :PK AND SK = :SK";
40
+ q.ExpressionAttributeValues = this.key_fund(id);
41
+ } else {
42
+ q.IndexName = FundDb.slug_env_gsi;
43
+ q.KeyConditionExpression = "slug = :slug AND env = :env";
44
+ q.ExpressionAttributeValues = {
45
+ ":slug": id,
46
+ ":env": this.env,
47
+ };
48
+ }
6
49
 
7
- export interface Keys {
8
- /** Fund#${uuid} */
9
- PK: `Fund#${string}`;
10
- SK: `Fund#${string}`;
11
- }
50
+ const { Items: i = [] } = await this.client.send(new QueryCommand(q));
51
+ return i[0] && this.sans_keys(i[0]);
52
+ }
53
+
54
+ async fund_edit(id: string, { target, slug, ...update }: IFundUpdate) {
55
+ const updates = new UpdateBuilder();
56
+
57
+ if (slug) updates.set("slug", slug);
58
+ if (slug === "") updates.remove("slug");
59
+
60
+ if (target || target === "0") {
61
+ updates.set("target", target);
62
+ }
63
+
64
+ for (const [k, v] of Object.entries(update)) {
65
+ if (v === undefined) continue;
66
+ updates.set(k, v);
67
+ }
12
68
 
13
- export interface Attributes extends NewFund, FundInternal {}
14
- export interface DbRecord extends Keys, Attributes {}
69
+ const command = new UpdateCommand({
70
+ TableName: FundDb.table,
71
+ Key: this.key_fund(id),
72
+ ReturnValues: "ALL_NEW",
73
+ ...updates.collect(),
74
+ });
15
75
 
16
- export namespace SlugEnvGsi {
17
- export type Name = typeof fundGsi.slugEnv;
18
- export interface Keys extends Pick<Attributes, "slug" | "env"> {}
19
- export interface Record extends DbRecord {} //all attributes are copied to this index
76
+ return this.client.send(command).then((res) => res.Attributes ?? {});
77
+ }
20
78
  }
package/src/index.mts CHANGED
@@ -1,27 +1,12 @@
1
- import type { IPageNumbered } from "@better-giving/types/api";
2
- import type { CloudsearchFund as FundItem } from "./cloudsearch.mjs";
3
- import type { FundInternal, NewFund } from "./schema.mjs";
1
+ export type { CloudsearchFund as FundItem } from "./cloudsearch.mjs";
4
2
  export type {
3
+ IFundNew,
4
+ IFundUpdate,
5
+ IFundsNpoMemberOfSearchObj,
6
+ IFundsSearchObj,
7
+ DonateMethodId,
5
8
  Environment,
6
- FundSettings,
7
- FundUpdate,
8
- FundsEndowMemberOfParams,
9
- FundsParams,
10
- NewFund,
11
9
  } from "./schema.mjs";
12
- export type { FundItem };
13
-
14
- export interface FundMember {
15
- id: number;
16
- name: string;
17
- logo: string | undefined;
18
- banner: string | undefined;
19
- }
20
-
21
- export interface SingleFund extends Omit<NewFund, "members">, FundInternal {
22
- members: FundMember[];
23
- }
24
-
25
- export interface FundsPage extends IPageNumbered<FundItem> {}
10
+ export { FundDb } from "./db.mjs";
26
11
 
27
12
  export const MAX_EXPIRATION = "9999-12-31T23:59:59Z";
@@ -0,0 +1,31 @@
1
+ import type { DonateMethodId, Environment } from "@better-giving/schemas";
2
+ import type { IPageNumbered } from "@better-giving/types/api";
3
+ import type { CloudsearchFund } from "./cloudsearch.mjs";
4
+ import type { IFundNew } from "./schema.mjs";
5
+
6
+ export interface IFundSettings {
7
+ hide_bg_tip: boolean;
8
+ donateMethods?: DonateMethodId[];
9
+ }
10
+
11
+ export interface IFundCreator {
12
+ /** "{number}" - endow id, "{email} - user*/
13
+ creator_id: string;
14
+ creator_name: string;
15
+ }
16
+
17
+ export interface IFundInternal extends IFundCreator {
18
+ /** uuid */
19
+ id: string;
20
+ env: Environment;
21
+ /** fund can be closed before expiration */
22
+ active: boolean;
23
+ verified: boolean;
24
+ /** to date received: initialized to `0` */
25
+ donation_total_usd: number;
26
+ settings: IFundSettings;
27
+ }
28
+
29
+ export interface IFund extends IFundNew, IFundInternal {}
30
+
31
+ export interface IFundsPage extends IPageNumbered<CloudsearchFund> {}
package/src/schema.mts CHANGED
@@ -1,5 +1,4 @@
1
- import { type DonateMethodId, slug } from "@better-giving/schemas";
2
- import type { Environment } from "@better-giving/types/list";
1
+ import { $, $int_gte1, slug } from "@better-giving/schemas";
3
2
  import {
4
3
  url,
5
4
  type InferOutput,
@@ -19,7 +18,6 @@ import {
19
18
  pipe,
20
19
  string,
21
20
  transform,
22
- trim,
23
21
  union,
24
22
  uuid,
25
23
  } from "valibot";
@@ -27,20 +25,18 @@ import {
27
25
  export { type DonateMethodId, slug } from "@better-giving/schemas";
28
26
  export type { Environment } from "@better-giving/types/list";
29
27
 
30
- const str = pipe(string(), trim());
31
-
32
- export const fundId = pipe(str, uuid());
28
+ export const fund_id = pipe($, uuid());
33
29
  /**
34
30
  * when fundraiser is created in the context of an NPO, all members of that NPO can edit the fundraiser
35
31
  * 0 - none
36
32
  */
37
33
  export const npo_owner = pipe(number(), integer(), minValue(0));
38
34
 
39
- export const newFund = object({
40
- name: pipe(str, nonEmpty("required")),
41
- description: pipe(str, nonEmpty("required")),
42
- banner: pipe(str, url()),
43
- logo: pipe(str, url()),
35
+ export const fund_new = object({
36
+ name: pipe($, nonEmpty("required")),
37
+ description: pipe($, nonEmpty("required")),
38
+ banner: pipe($, url()),
39
+ logo: pipe($, url()),
44
40
  /** endowment ids */
45
41
  members: pipe(
46
42
  array(pipe(number(), integer(), minValue(1))),
@@ -50,7 +46,7 @@ export const newFund = object({
50
46
  featured: boolean(),
51
47
  expiration: optional(
52
48
  pipe(
53
- str,
49
+ $,
54
50
  isoTimestamp("invalid date"),
55
51
  minValue(new Date().toISOString()) //created each parsing
56
52
  )
@@ -66,13 +62,13 @@ export const newFund = object({
66
62
  transform((v) => v.toString())
67
63
  ),
68
64
  ]),
69
- videos: array(pipe(str, url())),
65
+ videos: array(pipe($, url())),
70
66
  npo_owner,
71
67
  slug: optional(slug),
72
68
  });
73
69
 
74
- export const fundUpdate = partial(
75
- pick(newFund, [
70
+ export const fund_update = partial(
71
+ pick(fund_new, [
76
72
  "name",
77
73
  "description",
78
74
  "banner",
@@ -84,22 +80,14 @@ export const fundUpdate = partial(
84
80
  ])
85
81
  );
86
82
 
87
- export const fundsParams = object({
83
+ export const funds_search = object({
88
84
  /** search text */
89
- query: optional(str),
85
+ query: optional($),
90
86
  /** input str: from url */
91
- page: optional(
92
- pipe(
93
- str,
94
- transform((x) => +x),
95
- number(),
96
- integer(),
97
- minValue(1)
98
- )
99
- ),
87
+ page: $int_gte1,
100
88
  });
101
89
 
102
- export const fundsEndowMemberOfParams = object({
90
+ export const funds_npo_memberof_search = object({
103
91
  /*
104
92
  * this endow is the only member (not an index fund),
105
93
  * and is approved:
@@ -108,37 +96,17 @@ export const fundsEndowMemberOfParams = object({
108
96
  *
109
97
  * input str: from url
110
98
  */
111
- npoProfileFeatured: optional(
99
+ npo_profile_featured: optional(
112
100
  pipe(
113
- str,
101
+ $,
114
102
  transform((x) => x === "true"),
115
103
  boolean()
116
104
  )
117
105
  ),
118
106
  });
119
107
 
120
- export interface NewFund extends InferOutput<typeof newFund> {}
121
- export interface FundUpdate extends InferOutput<typeof fundUpdate> {}
122
- export interface FundsParams extends InferOutput<typeof fundsParams> {}
123
- export interface FundsEndowMemberOfParams
124
- extends InferOutput<typeof fundsEndowMemberOfParams> {}
125
-
126
- export interface FundSettings {
127
- hide_bg_tip: boolean;
128
- donateMethods?: DonateMethodId[];
129
- }
130
-
131
- export interface FundInternal {
132
- /** uuid */
133
- id: string;
134
- env: Environment;
135
- /** fund can be closed before expiration */
136
- active: boolean;
137
- verified: boolean;
138
- /** to date received: initialized to `0` */
139
- donation_total_usd: number;
140
- /** "{number}" - endow id, "{email} - user*/
141
- creator_id: string;
142
- creator_name: string;
143
- settings: FundSettings;
144
- }
108
+ export interface IFundNew extends InferOutput<typeof fund_new> {}
109
+ export interface IFundUpdate extends InferOutput<typeof fund_update> {}
110
+ export interface IFundsSearchObj extends InferOutput<typeof funds_search> {}
111
+ export interface IFundsNpoMemberOfSearchObj
112
+ extends InferOutput<typeof funds_npo_memberof_search> {}