@better-giving/fundraiser 3.0.5 → 3.0.7

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 { Db, UpdateBuilder } from "@better-giving/db";
2
+ import { QueryCommand, UpdateCommand, } from "@aws-sdk/lib-dynamodb";
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,3 @@
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";
17
3
  export declare const MAX_EXPIRATION = "9999-12-31T23:59:59Z";
@@ -0,0 +1,28 @@
1
+ import type { DonateMethodId, Environment } from "@better-giving/schemas";
2
+ import type { IFundNew } from "./schema.mjs";
3
+ import type { IPageNumbered } from "@better-giving/types/api";
4
+ import type { CloudsearchFund } from "./cloudsearch.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,14 +1,13 @@
1
- import type { DonateMethodId } from "@better-giving/schemas";
2
- import type { Environment } from "@better-giving/types/list";
3
- export type { Environment } from "@better-giving/types/list";
4
1
  import { type InferOutput } from "valibot";
5
- export declare const fundId: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").UuidAction<string, undefined>]>;
2
+ export { type DonateMethodId, slug } from "@better-giving/schemas";
3
+ export type { Environment } from "@better-giving/types/list";
4
+ export declare const fund_id: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").UuidAction<string, undefined>]>;
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 declare const npo_owner: import("valibot").SchemaWithPipe<[import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 0, undefined>]>;
11
- export declare const newFund: import("valibot").ObjectSchema<{
10
+ export declare const fund_new: import("valibot").ObjectSchema<{
12
11
  readonly name: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").NonEmptyAction<string, "required">]>;
13
12
  readonly description: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").NonEmptyAction<string, "required">]>;
14
13
  readonly banner: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").UrlAction<string, undefined>]>;
@@ -23,7 +22,7 @@ export declare const newFund: import("valibot").ObjectSchema<{
23
22
  readonly npo_owner: import("valibot").SchemaWithPipe<[import("valibot").NumberSchema<undefined>, import("valibot").IntegerAction<number, undefined>, import("valibot").MinValueAction<number, 0, undefined>]>;
24
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>;
25
24
  }, undefined>;
26
- export declare const fundUpdate: Omit<Omit<import("valibot").ObjectSchema<{
25
+ export declare const fund_update: Omit<Omit<import("valibot").ObjectSchema<{
27
26
  readonly name: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").NonEmptyAction<string, "required">]>;
28
27
  readonly description: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").NonEmptyAction<string, "required">]>;
29
28
  readonly banner: import("valibot").SchemaWithPipe<[import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, import("valibot").UrlAction<string, undefined>]>;
@@ -131,38 +130,20 @@ export declare const fundUpdate: Omit<Omit<import("valibot").ObjectSchema<{
131
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;
132
131
  } | undefined;
133
132
  };
134
- export declare const fundsParams: import("valibot").ObjectSchema<{
133
+ export declare const funds_search: import("valibot").ObjectSchema<{
135
134
  /** search text */
136
135
  readonly query: import("valibot").OptionalSchema<import("valibot").SchemaWithPipe<[import("valibot").StringSchema<undefined>, import("valibot").TrimAction]>, never>;
137
136
  /** input str: from url */
138
- 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>]>]>;
139
138
  }, undefined>;
140
- export declare const fundsEndowMemberOfParams: import("valibot").ObjectSchema<{
141
- 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>;
142
141
  }, undefined>;
143
- export interface NewFund extends InferOutput<typeof newFund> {
144
- }
145
- export interface FundUpdate extends InferOutput<typeof fundUpdate> {
146
- }
147
- export interface FundsParams extends InferOutput<typeof fundsParams> {
142
+ export interface IFundNew extends InferOutput<typeof fund_new> {
148
143
  }
149
- export interface FundsEndowMemberOfParams extends InferOutput<typeof fundsEndowMemberOfParams> {
144
+ export interface IFundUpdate extends InferOutput<typeof fund_update> {
150
145
  }
151
- export interface FundSettings {
152
- hide_bg_tip: boolean;
153
- donateMethods?: DonateMethodId[];
146
+ export interface IFundsSearchObj extends InferOutput<typeof funds_search> {
154
147
  }
155
- export interface FundInternal {
156
- /** uuid */
157
- id: string;
158
- env: Environment;
159
- /** fund can be closed before expiration */
160
- active: boolean;
161
- verified: boolean;
162
- /** to date received: initialized to `0` */
163
- donation_total_usd: number;
164
- /** "{number}" - endow id, "{email} - user*/
165
- creator_id: string;
166
- creator_name: string;
167
- settings: FundSettings;
148
+ export interface IFundsNpoMemberOfSearchObj extends InferOutput<typeof funds_npo_memberof_search> {
168
149
  }
package/dist/schema.mjs CHANGED
@@ -1,32 +1,32 @@
1
- import { slug } from "@better-giving/endowment/schema";
2
- import { url, array, boolean, integer, isoTimestamp, literal, maxLength, minValue, nonEmpty, number, object, optional, partial, pick, pipe, string, transform, trim, union, uuid, } from "valibot";
3
- const str = pipe(string(), trim());
4
- export const fundId = pipe(str, uuid());
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
+ export { slug } from "@better-giving/schemas";
4
+ export const fund_id = pipe($, uuid());
5
5
  /**
6
6
  * when fundraiser is created in the context of an NPO, all members of that NPO can edit the fundraiser
7
7
  * 0 - none
8
8
  */
9
9
  export const npo_owner = pipe(number(), integer(), minValue(0));
10
- export const newFund = object({
11
- name: pipe(str, nonEmpty("required")),
12
- description: pipe(str, nonEmpty("required")),
13
- banner: pipe(str, url()),
14
- 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()),
15
15
  /** endowment ids */
16
16
  members: pipe(array(pipe(number(), integer(), minValue(1))), nonEmpty(), maxLength(10)),
17
17
  featured: boolean(),
18
- 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
19
19
  )),
20
20
  /** `"0"` - none, {"number"} = fixed */
21
21
  target: union([
22
22
  literal("smart"),
23
23
  pipe(string(), transform((v) => +v), number(), minValue(0), transform((v) => v.toString())),
24
24
  ]),
25
- videos: array(pipe(str, url())),
25
+ videos: array(pipe($, url())),
26
26
  npo_owner,
27
27
  slug: optional(slug),
28
28
  });
29
- export const fundUpdate = partial(pick(newFund, [
29
+ export const fund_update = partial(pick(fund_new, [
30
30
  "name",
31
31
  "description",
32
32
  "banner",
@@ -36,13 +36,13 @@ export const fundUpdate = partial(pick(newFund, [
36
36
  "videos",
37
37
  "slug",
38
38
  ]));
39
- export const fundsParams = object({
39
+ export const funds_search = object({
40
40
  /** search text */
41
- query: optional(str),
41
+ query: optional($),
42
42
  /** input str: from url */
43
- page: optional(pipe(str, transform((x) => +x), number(), integer(), minValue(1))),
43
+ page: $int_gte1,
44
44
  });
45
- export const fundsEndowMemberOfParams = object({
45
+ export const funds_npo_memberof_search = object({
46
46
  /*
47
47
  * this endow is the only member (not an index fund),
48
48
  * and is approved:
@@ -51,5 +51,5 @@ export const fundsEndowMemberOfParams = object({
51
51
  *
52
52
  * input str: from url
53
53
  */
54
- npoProfileFeatured: optional(pipe(str, transform((x) => x === "true"), boolean())),
54
+ npo_profile_featured: optional(pipe($, transform((x) => x === "true"), boolean())),
55
55
  });
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@better-giving/fundraiser",
3
- "version": "3.0.5",
3
+ "version": "3.0.7",
4
4
  "peerDependencies": {
5
5
  "valibot": "0.42.0",
6
- "@better-giving/endowment": "4.0.5",
7
6
  "@better-giving/schemas": "2.0.0",
8
- "@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"
9
10
  },
10
11
  "devDependencies": {
11
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 { Db, UpdateBuilder, type TxType } from "@better-giving/db";
2
+ import type { IFund } from "./interfaces.mjs";
3
+ import {
4
+ QueryCommand,
5
+ UpdateCommand,
6
+ type QueryCommandInput,
7
+ } from "@aws-sdk/lib-dynamodb";
8
+ import { UUID_REGEX } from "valibot";
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,11 @@
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> {}
26
10
 
27
11
  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 { IFundNew } from "./schema.mjs";
3
+ import type { IPageNumbered } from "@better-giving/types/api";
4
+ import type { CloudsearchFund } from "./cloudsearch.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,7 +1,4 @@
1
- import { slug } from "@better-giving/endowment/schema";
2
- import type { DonateMethodId } from "@better-giving/schemas";
3
- import type { Environment } from "@better-giving/types/list";
4
- export type { Environment } from "@better-giving/types/list";
1
+ import { $, $int_gte1, slug } from "@better-giving/schemas";
5
2
  import {
6
3
  url,
7
4
  type InferOutput,
@@ -21,25 +18,25 @@ import {
21
18
  pipe,
22
19
  string,
23
20
  transform,
24
- trim,
25
21
  union,
26
22
  uuid,
27
23
  } from "valibot";
28
24
 
29
- const str = pipe(string(), trim());
25
+ export { type DonateMethodId, slug } from "@better-giving/schemas";
26
+ export type { Environment } from "@better-giving/types/list";
30
27
 
31
- export const fundId = pipe(str, uuid());
28
+ export const fund_id = pipe($, uuid());
32
29
  /**
33
30
  * when fundraiser is created in the context of an NPO, all members of that NPO can edit the fundraiser
34
31
  * 0 - none
35
32
  */
36
33
  export const npo_owner = pipe(number(), integer(), minValue(0));
37
34
 
38
- export const newFund = object({
39
- name: pipe(str, nonEmpty("required")),
40
- description: pipe(str, nonEmpty("required")),
41
- banner: pipe(str, url()),
42
- 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()),
43
40
  /** endowment ids */
44
41
  members: pipe(
45
42
  array(pipe(number(), integer(), minValue(1))),
@@ -49,7 +46,7 @@ export const newFund = object({
49
46
  featured: boolean(),
50
47
  expiration: optional(
51
48
  pipe(
52
- str,
49
+ $,
53
50
  isoTimestamp("invalid date"),
54
51
  minValue(new Date().toISOString()) //created each parsing
55
52
  )
@@ -65,13 +62,13 @@ export const newFund = object({
65
62
  transform((v) => v.toString())
66
63
  ),
67
64
  ]),
68
- videos: array(pipe(str, url())),
65
+ videos: array(pipe($, url())),
69
66
  npo_owner,
70
67
  slug: optional(slug),
71
68
  });
72
69
 
73
- export const fundUpdate = partial(
74
- pick(newFund, [
70
+ export const fund_update = partial(
71
+ pick(fund_new, [
75
72
  "name",
76
73
  "description",
77
74
  "banner",
@@ -83,22 +80,14 @@ export const fundUpdate = partial(
83
80
  ])
84
81
  );
85
82
 
86
- export const fundsParams = object({
83
+ export const funds_search = object({
87
84
  /** search text */
88
- query: optional(str),
85
+ query: optional($),
89
86
  /** input str: from url */
90
- page: optional(
91
- pipe(
92
- str,
93
- transform((x) => +x),
94
- number(),
95
- integer(),
96
- minValue(1)
97
- )
98
- ),
87
+ page: $int_gte1,
99
88
  });
100
89
 
101
- export const fundsEndowMemberOfParams = object({
90
+ export const funds_npo_memberof_search = object({
102
91
  /*
103
92
  * this endow is the only member (not an index fund),
104
93
  * and is approved:
@@ -107,37 +96,17 @@ export const fundsEndowMemberOfParams = object({
107
96
  *
108
97
  * input str: from url
109
98
  */
110
- npoProfileFeatured: optional(
99
+ npo_profile_featured: optional(
111
100
  pipe(
112
- str,
101
+ $,
113
102
  transform((x) => x === "true"),
114
103
  boolean()
115
104
  )
116
105
  ),
117
106
  });
118
107
 
119
- export interface NewFund extends InferOutput<typeof newFund> {}
120
- export interface FundUpdate extends InferOutput<typeof fundUpdate> {}
121
- export interface FundsParams extends InferOutput<typeof fundsParams> {}
122
- export interface FundsEndowMemberOfParams
123
- extends InferOutput<typeof fundsEndowMemberOfParams> {}
124
-
125
- export interface FundSettings {
126
- hide_bg_tip: boolean;
127
- donateMethods?: DonateMethodId[];
128
- }
129
-
130
- export interface FundInternal {
131
- /** uuid */
132
- id: string;
133
- env: Environment;
134
- /** fund can be closed before expiration */
135
- active: boolean;
136
- verified: boolean;
137
- /** to date received: initialized to `0` */
138
- donation_total_usd: number;
139
- /** "{number}" - endow id, "{email} - user*/
140
- creator_id: string;
141
- creator_name: string;
142
- settings: FundSettings;
143
- }
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> {}