@common-grants/core 0.1.0-alpha.13 → 0.1.0-alpha.14

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,86 @@
1
+ namespace CommonGrants.Fields;
2
+
3
+ /** An mailing address. */
4
+ @example(Examples.Address.apartment)
5
+ model Address {
6
+ /** The primary street address line. */
7
+ street1: string;
8
+
9
+ /** Additional street address information (e.g., apartment number, suite, etc.). */
10
+ street2?: string;
11
+
12
+ /** The city or municipality name. */
13
+ city: string;
14
+
15
+ /** The state, province, or region name. */
16
+ stateOrProvince: string;
17
+
18
+ /** The country name or ISO country code. */
19
+ country: string;
20
+
21
+ /** The postal or ZIP code for the address. */
22
+ postalCode: string;
23
+
24
+ /** The latitude coordinate of the address location. */
25
+ latitude?: numeric;
26
+
27
+ /** The longitude coordinate of the address location. */
28
+ longitude?: numeric;
29
+
30
+ /** Additional geospatial data in GeoJSON format. */
31
+ geography?: Record<unknown>;
32
+ }
33
+
34
+ /** A collection of addresses. */
35
+ @example(Examples.Address.personalCollection)
36
+ @example(Examples.Address.orgCollection)
37
+ model AddressCollection {
38
+ /** The primary address for a person or organization. */
39
+ primary: Address;
40
+
41
+ /** Additional addresses keyed by a descriptive label (e.g., "work", "home", "international"). */
42
+ otherAddresses?: Record<Address>;
43
+ }
44
+
45
+ namespace Examples.Address {
46
+ const apartment = #{
47
+ street1: "123 Main St",
48
+ city: "Anytown",
49
+ stateOrProvince: "CA",
50
+ country: "US",
51
+ postalCode: "12345",
52
+ };
53
+
54
+ const orgAddress = #{
55
+ street1: "456 Main St",
56
+ street2: "Suite 100",
57
+ city: "Anytown",
58
+ stateOrProvince: "CA",
59
+ country: "US",
60
+ postalCode: "12345",
61
+ };
62
+
63
+ const international = #{
64
+ street1: "123 Rue Principale",
65
+ city: "Montreal",
66
+ stateOrProvince: "QC",
67
+ country: "CA",
68
+ postalCode: "H2Y 1C6",
69
+ };
70
+
71
+ const personalCollection = #{
72
+ primary: Examples.Address.apartment,
73
+ otherAddresses: #{
74
+ work: Examples.Address.apartment,
75
+ home: Examples.Address.apartment,
76
+ },
77
+ };
78
+
79
+ const orgCollection = #{
80
+ primary: Examples.Address.orgAddress,
81
+ otherAddresses: #{
82
+ satellite: Examples.Address.orgAddress,
83
+ international: Examples.Address.international,
84
+ },
85
+ };
86
+ }
@@ -0,0 +1,35 @@
1
+ import "../types.tsp";
2
+
3
+ namespace CommonGrants.Fields;
4
+
5
+ /** An email address. */
6
+ alias Email = Types.email; // Exposes Email from CommonGrants.Fields
7
+
8
+ /** A collection of email addresses. */
9
+ @example(Examples.Email.personalCollection)
10
+ model EmailCollection {
11
+ /** The primary email address for a person or organization. */
12
+ primary: Types.email;
13
+
14
+ /** Additional email addresses keyed by a descriptive label (e.g., "work", "personal", "support"). */
15
+ otherEmails?: Record<Types.email>;
16
+ }
17
+
18
+ namespace Examples.Email {
19
+ const personalCollection = #{
20
+ primary: "john.doe@example.com",
21
+ otherEmails: #{
22
+ work: "john.doe@work.com",
23
+ personal: "john.doe@gmail.com",
24
+ school: "john.doe@school.edu",
25
+ },
26
+ };
27
+
28
+ const orgCollection = #{
29
+ primary: "info@example.com",
30
+ otherEmails: #{
31
+ support: "support@example.com",
32
+ marketing: "marketing@example.com",
33
+ },
34
+ };
35
+ }
@@ -2,6 +2,11 @@ import "./custom-field.tsp";
2
2
  import "./metadata.tsp";
3
3
  import "./money.tsp";
4
4
  import "./event.tsp";
5
+ import "./address.tsp";
6
+ import "./name.tsp";
7
+ import "./phone.tsp";
8
+ import "./pcs.tsp";
9
+ import "./email.tsp";
5
10
 
6
11
  using TypeSpec.JsonSchema;
7
12
 
@@ -0,0 +1,30 @@
1
+ namespace CommonGrants.Fields;
2
+
3
+ /** A person's name. */
4
+ @example(Examples.Name.janeDoe)
5
+ model Name {
6
+ /** Honorific prefix (e.g., Mr., Mrs., Dr., Prof.). */
7
+ prefix?: string;
8
+
9
+ /** The person's first or given name. */
10
+ firstName: string;
11
+
12
+ /** The person's middle name or names. */
13
+ middleName?: string;
14
+
15
+ /** The person's last name or family name. */
16
+ lastName: string;
17
+
18
+ /** Name suffix (e.g., Jr., Sr., III, Ph.D.). */
19
+ suffix?: string;
20
+ }
21
+
22
+ namespace Examples.Name {
23
+ const janeDoe = #{
24
+ prefix: "Dr.",
25
+ firstName: "Jane",
26
+ middleName: "Edward",
27
+ lastName: "Doe",
28
+ suffix: "Jr.",
29
+ };
30
+ }
@@ -0,0 +1,112 @@
1
+ namespace CommonGrants.Fields;
2
+
3
+ /** A Philanthropy Classification System (PCS) term.
4
+ *
5
+ * The PCS is a hierarchical classification system for categorizing data related to
6
+ * philanthropic activities. It supports the following classes:
7
+ * - Organization types
8
+ * - Subjects
9
+ * - Population groups
10
+ * - Transaction types
11
+ * - Support strategies
12
+ *
13
+ * See https://taxonomy.candid.org/ for more information.
14
+ */
15
+ @example(Examples.PCS.orgTypeTerm)
16
+ model PCSTerm {
17
+ /** The plain language PCS term. */
18
+ term: string;
19
+
20
+ /** The class to which the PCS term belongs. */
21
+ class: PCSClass;
22
+
23
+ /** The code for this PCS term. */
24
+ @pattern("[A-Z]{2}[0-9]{6}")
25
+ @example("UC0")
26
+ code: string;
27
+
28
+ /** Description of the PCS term */
29
+ description?: string;
30
+ }
31
+
32
+ // #########################################################
33
+ // PCSClass
34
+ // #########################################################
35
+
36
+ /** The class to which the PCS term belongs. */
37
+ enum PCSClass {
38
+ orgTypes: "Organization types",
39
+ subjects: "Subjects",
40
+ populationGroups: "Population groups",
41
+ transactionTypes: "Transaction types",
42
+ supportStrategies: "Support strategies",
43
+ }
44
+
45
+ // #########################################################
46
+ // PCS class types
47
+ // #########################################################
48
+
49
+ /** A Philanthropy Classification System (PCS) term for organization types.
50
+ *
51
+ * See https://taxonomy.candid.org/organization-type for more information.
52
+ */
53
+ model PCSOrgType extends PCSTerm {
54
+ /** The PCS term for the organization type. */
55
+ class: PCSClass.orgTypes;
56
+ }
57
+
58
+ /** A Philanthropy Classification System (PCS) term for the subject of the grant.
59
+ *
60
+ * See https://taxonomy.candid.org/subjects for more information.
61
+ */
62
+ model PCSSubject extends PCSTerm {
63
+ /** The PCS term for the subject. */
64
+ class: PCSClass.subjects;
65
+ }
66
+
67
+ /** A Philanthropy Classification System (PCS) term for populations served.
68
+ *
69
+ * See https://taxonomy.candid.org/populations for more information.
70
+ */
71
+ model PCSPopulation extends PCSTerm {
72
+ /** The PCS term for the population. */
73
+ class: PCSClass.populationGroups;
74
+ }
75
+
76
+ /** A Philanthropy Classification System (PCS) term for support strategies.
77
+ *
78
+ * See https://taxonomy.candid.org/support-strategies for more information.
79
+ */
80
+ model PCSSupportStrategy extends PCSTerm {
81
+ /** The PCS term for the support strategy. */
82
+ class: PCSClass.supportStrategies;
83
+ }
84
+
85
+ /** A Philanthropy Classification System (PCS) term for transaction types.
86
+ *
87
+ * See https://taxonomy.candid.org/transaction-types for more information.
88
+ */
89
+ model PCSTransactionType extends PCSTerm {
90
+ /** The PCS term for the transaction type. */
91
+ class: PCSClass.transactionTypes;
92
+ }
93
+
94
+ // #########################################################
95
+ // Examples
96
+ // #########################################################
97
+
98
+ namespace Examples.PCS {
99
+ const orgTypeTerm = #{
100
+ term: "Hospital",
101
+ class: PCSClass.orgTypes,
102
+ description: "Institutions with the primary purpose of providing in-patient physical and mental health services...",
103
+ code: "EO000000",
104
+ };
105
+
106
+ const subjectTerm = #{
107
+ term: "Education",
108
+ class: PCSClass.subjects,
109
+ description: "All formally constituted educational institutions (except art and performing art schools) and projects or activities...",
110
+ code: "SB000000",
111
+ };
112
+ }
@@ -0,0 +1,65 @@
1
+ namespace CommonGrants.Fields;
2
+
3
+ /** A phone number. */
4
+ @example(Examples.Phone.mobile)
5
+ @example(Examples.Phone.withExtension)
6
+ model Phone {
7
+ /** The international country code (e.g., "+1" for US/Canada). */
8
+ @pattern("^\\+[1-9][0-9]{1,3}$")
9
+ countryCode: string;
10
+
11
+ /** The local phone number without the country code. */
12
+ number: string;
13
+
14
+ /** Optional extension number for the phone line. */
15
+ extension?: string;
16
+
17
+ /** Indicates whether this is a mobile/cell phone number. */
18
+ isMobile?: boolean = false;
19
+ }
20
+
21
+ // #########################################################
22
+ // Phone Collection
23
+ // #########################################################
24
+
25
+ /** A collection of phone numbers for a person. */
26
+ @example(Examples.Phone.personalCollection)
27
+ @example(Examples.Phone.orgCollection)
28
+ model PhoneCollection {
29
+ /** The person's primary phone number. */
30
+ primary: Fields.Phone;
31
+
32
+ /** The person's fax number, if applicable. */
33
+ fax?: Fields.Phone;
34
+
35
+ /** Additional phone numbers not covered by the standard fields. */
36
+ otherPhones?: Record<Fields.Phone>;
37
+ }
38
+
39
+ // #########################################################
40
+ // Examples
41
+ // #########################################################
42
+
43
+ namespace Examples.Phone {
44
+ const mobile = #{ countryCode: "+1", number: "444-456-1230", isMobile: true };
45
+
46
+ const home = #{ countryCode: "+1", number: "333-456-1230", isMobile: false };
47
+
48
+ const withExtension = #{
49
+ countryCode: "+1",
50
+ number: "555-123-4567",
51
+ extension: "123",
52
+ isMobile: false,
53
+ };
54
+
55
+ const personalCollection = #{ primary: mobile, otherPhones: #{ home: home } };
56
+
57
+ const orgCollection = #{
58
+ primary: mobile,
59
+ fax: withExtension,
60
+ otherPhones: #{
61
+ support: #{ countryCode: "+1", number: "333-456-1230", isMobile: false },
62
+ marketing: #{ countryCode: "+1", number: "444-456-1230", isMobile: true },
63
+ },
64
+ };
65
+ }
@@ -0,0 +1,142 @@
1
+ import "../index.tsp";
2
+
3
+ namespace CommonGrants.Models;
4
+
5
+ /** The base model for an application. */
6
+ @example(Examples.Application.exampleApplication)
7
+ model ApplicationBase {
8
+ /** The application's unique identifier. */
9
+ id: Types.uuid;
10
+
11
+ /** The application's status. */
12
+ status?: AppStatus;
13
+
14
+ /** The application's date of submission. */
15
+ dateSubmitted?: Types.isoDate;
16
+
17
+ /** The organization that is applying for the grant. */
18
+ organization?: OrganizationBase;
19
+
20
+ /** The person who is applying for the grant. */
21
+ pointOfContact?: PersonBase;
22
+
23
+ /** The application's proposal for funding. */
24
+ proposal?: AppProposal;
25
+
26
+ /** The opportunity being applied to. */
27
+ opportunity?: AppOpportunity;
28
+
29
+ /** The application's custom fields. */
30
+ customFields?: Record<Fields.CustomField>;
31
+ }
32
+
33
+ // #########################################################
34
+ // AppStatus
35
+ // #########################################################
36
+
37
+ /** The status of the application. */
38
+ @example(Examples.Application.submittedStatus)
39
+ model AppStatus {
40
+ /** The status of the application. */
41
+ value: AppStatusOptions;
42
+
43
+ /** A custom value for the status. */
44
+ customValue?: string;
45
+
46
+ /** A description of the status. */
47
+ description?: string;
48
+ }
49
+
50
+ // #########################################################
51
+ // AppStatusOptions
52
+ // #########################################################
53
+
54
+ /** The default set of values accepted for application status. */
55
+ enum AppStatusOptions {
56
+ submitted,
57
+ approved,
58
+ rejected,
59
+ custom,
60
+ }
61
+
62
+ // #########################################################
63
+ // AppProject
64
+ // #########################################################
65
+
66
+ /** The project for which funding is requested. */
67
+ @example(Examples.Application.exampleProposal)
68
+ model AppProposal {
69
+ /** The title of the proposal and/or the project requesting funding. */
70
+ title: string;
71
+
72
+ /** The description of the proposal and/or the project requesting funding. */
73
+ description: string;
74
+
75
+ /** The amount of money requested. */
76
+ amountRequested?: Fields.Money;
77
+
78
+ /** The start date of the period for which the funding is requested. */
79
+ periodStartDate?: Types.isoDate;
80
+
81
+ /** The end date of the period for which the funding is requested. */
82
+ periodEndDate?: Types.isoDate;
83
+
84
+ /** The project's custom fields. */
85
+ customFields?: Record<Fields.CustomField>;
86
+ }
87
+
88
+ // #########################################################
89
+ // AppOpportunity
90
+ // #########################################################
91
+
92
+ /** The opportunity to which this application is related */
93
+ model AppOpportunity {
94
+ /** The opportunity's unique identifier. */
95
+ id: Types.uuid;
96
+
97
+ /** The opportunity's name. */
98
+ title?: string;
99
+
100
+ /** The opportunity's custom fields. */
101
+ customFields?: Record<Fields.CustomField>;
102
+ }
103
+
104
+ // #########################################################
105
+ // Examples
106
+ // #########################################################
107
+
108
+ namespace Examples.Application {
109
+ const exampleApplication = #{
110
+ id: "083b4567-e89d-42c8-a439-6c1234567890",
111
+ status: submittedStatus,
112
+ dateSubmitted: Types.isoDate.fromISO("2024-01-01"),
113
+ organization: Examples.Organization.exampleOrg,
114
+ pointOfContact: Examples.Person.examplePerson,
115
+ proposal: exampleProposal,
116
+ opportunity: exampleOpportunity,
117
+ };
118
+
119
+ const submittedStatus = #{
120
+ value: AppStatusOptions.submitted,
121
+ description: "Application has been submitted.",
122
+ };
123
+
124
+ const customStatus = #{
125
+ value: AppStatusOptions.custom,
126
+ customValue: "draft",
127
+ description: "Application is started but not yet submitted.",
128
+ };
129
+
130
+ const exampleProposal = #{
131
+ title: "Example Project",
132
+ description: "Example project to serve community needs.",
133
+ amountRequested: #{ amount: "100000", currency: "USD" },
134
+ periodStartDate: Types.isoDate.fromISO("2024-01-01"),
135
+ periodEndDate: Types.isoDate.fromISO("2024-12-31"),
136
+ };
137
+
138
+ const exampleOpportunity = #{
139
+ id: "083b4567-e89d-42c8-a439-6c1234567890",
140
+ title: "Example Opportunity",
141
+ };
142
+ }
@@ -3,6 +3,9 @@ import "@typespec/json-schema";
3
3
  // Import individual schemas to provide a consistent interface
4
4
  // and make them available throughout the namespace
5
5
  import "./opportunity/index.tsp";
6
+ import "./organization.tsp";
7
+ import "./person.tsp";
8
+ import "./application.tsp";
6
9
 
7
10
  using TypeSpec.JsonSchema;
8
11
 
@@ -0,0 +1,105 @@
1
+ import "../fields/index.tsp";
2
+
3
+ namespace CommonGrants.Models;
4
+
5
+ /** An organization that can apply for grants. */
6
+ @example(Examples.Organization.exampleOrg)
7
+ model OrganizationBase {
8
+ /** The organization's unique identifier. */
9
+ id: Types.uuid;
10
+
11
+ /** The organization's legal name as registered with relevant authorities. */
12
+ name: string;
13
+
14
+ /** The organization's type within the Philanthropy Classification System (PCS). */
15
+ type?: Fields.PCSOrgType;
16
+
17
+ /** The organization's Employer Identification Number (EIN), a unique identifier assigned by the IRS. */
18
+ ein?: Types.employerTaxId;
19
+
20
+ /** The organization's Unique Entity Identifier (UEI) from SAM.gov, used for federal contracting. */
21
+ uei?: Types.samUEI;
22
+
23
+ /** The organization's Data Universal Numbering System (DUNS) number, a unique identifier for businesses. */
24
+ duns?: Types.duns;
25
+
26
+ /** Collection of physical addresses associated with the organization. */
27
+ addresses?: Fields.AddressCollection;
28
+
29
+ /** Collection of phone numbers associated with the organization. */
30
+ phones?: Fields.PhoneCollection;
31
+
32
+ /** Collection of email addresses associated with the organization. */
33
+ emails?: Fields.EmailCollection;
34
+
35
+ /** The organization's mission statement. */
36
+ mission?: string;
37
+
38
+ /** The calendar year the organization was founded. */
39
+ yearFounded?: Types.calendarYear;
40
+
41
+ /** Collection of the organization's social media and web presence links. */
42
+ socials?: OrgSocialLinks;
43
+
44
+ /** Custom fields for the organization. */
45
+ customFields?: Record<Fields.CustomField>;
46
+ }
47
+
48
+ // #########################################################
49
+ // OrgSocialLinks
50
+ // #########################################################
51
+
52
+ /** A collection of social media and web presence links for an organization. */
53
+ @example(Examples.Organization.exampleSocials)
54
+ model OrgSocialLinks {
55
+ /** The organization's primary website URL. */
56
+ website?: url;
57
+
58
+ /** The organization's Facebook profile URL. */
59
+ facebook?: url;
60
+
61
+ /** The organization's Twitter/X profile URL. */
62
+ twitterOrX?: url;
63
+
64
+ /** The organization's BlueSky profile URL. */
65
+ bluesky?: url;
66
+
67
+ /** The organization's Instagram profile URL. */
68
+ instagram?: url;
69
+
70
+ /** The organization's LinkedIn profile URL. */
71
+ linkedin?: url;
72
+
73
+ /** Additional social media profiles not covered by the standard fields. */
74
+ otherSocials?: Record<url>;
75
+ }
76
+
77
+ // #########################################################
78
+ // Examples
79
+ // #########################################################
80
+
81
+ namespace Examples.Organization {
82
+ const exampleOrg = #{
83
+ id: "083b4567-e89d-42c8-a439-6c1234567890",
84
+ name: "Example Organization",
85
+ type: Fields.Examples.PCS.orgTypeTerm,
86
+ ein: "12-3456789",
87
+ uei: "ABC1234567890",
88
+ duns: "123456789012",
89
+ addresses: Fields.Examples.Address.orgCollection,
90
+ phones: Fields.Examples.Phone.orgCollection,
91
+ emails: Fields.Examples.Email.orgCollection,
92
+ mission: "To provide support and resources to the community.",
93
+ yearFounded: "2024",
94
+ socials: exampleSocials,
95
+ };
96
+
97
+ const exampleSocials = #{
98
+ website: "https://www.example.com",
99
+ facebook: "https://www.facebook.com/example",
100
+ twitterOrX: "https://x.com/example",
101
+ instagram: "https://www.instagram.com/example",
102
+ linkedin: "https://www.linkedin.com/company/example",
103
+ otherSocials: #{ youtube: "https://www.youtube.com/example" },
104
+ };
105
+ }
@@ -0,0 +1,43 @@
1
+ import "../fields/index.tsp";
2
+ import "../types.tsp";
3
+
4
+ namespace CommonGrants.Models;
5
+
6
+ /** A person affiliated with an organization or grant application. */
7
+ @example(Examples.Person.examplePerson)
8
+ model PersonBase {
9
+ /** The person's full name, including all relevant components (first, middle, last, etc.). */
10
+ name: Fields.Name;
11
+
12
+ /** The person's title, if applicable. */
13
+ title?: string;
14
+
15
+ /** Collection of physical addresses associated with the person. */
16
+ addresses?: Fields.AddressCollection;
17
+
18
+ /** Collection of phone numbers associated with the person. */
19
+ phones?: Fields.PhoneCollection;
20
+
21
+ /** Collection of email addresses associated with the person. */
22
+ emails?: Fields.EmailCollection;
23
+
24
+ /** The person's date of birth. */
25
+ dateOfBirth?: Types.isoDate;
26
+
27
+ /** Custom fields for the person. */
28
+ customFields?: Record<Fields.CustomField>;
29
+ }
30
+
31
+ // #########################################################
32
+ // Examples
33
+ // #########################################################
34
+
35
+ namespace Examples.Person {
36
+ const examplePerson = #{
37
+ name: Fields.Examples.Name.janeDoe,
38
+ title: "Chief Executive Officer",
39
+ addresses: Fields.Examples.Address.personalCollection,
40
+ phones: Fields.Examples.Phone.personalCollection,
41
+ emails: Fields.Examples.Email.personalCollection,
42
+ };
43
+ }
@@ -29,6 +29,11 @@ scalar isoTime extends plainTime;
29
29
  @example(isoDate.fromISO("2025-01-01"))
30
30
  scalar isoDate extends plainDate;
31
31
 
32
+ /** A calendar year */
33
+ @example("2025")
34
+ @pattern("^[0-9]{4}$")
35
+ scalar calendarYear extends string;
36
+
32
37
  /** A universally unique identifier */
33
38
  @example("30a12e5e-5940-4c08-921c-17a8960fcf4b")
34
39
  @format("uuid")
@@ -43,3 +48,23 @@ scalar uuid extends string;
43
48
  @example("100.5", #{ title: "Scale 1" })
44
49
  @example("-100.5", #{ title: "Negative, scale 2" })
45
50
  scalar decimalString extends string;
51
+
52
+ /** An email address */
53
+ @example("test@example.com")
54
+ @format("email")
55
+ scalar email extends string;
56
+
57
+ /** An Employer Identification Number (EIN) */
58
+ @example("123456789")
59
+ @pattern("^[0-9]{2}-[0-9]{7}$")
60
+ scalar employerTaxId extends string;
61
+
62
+ /** A Unique Entity Identifier (UEI) */
63
+ @example("ABC1234567890")
64
+ @pattern("^[A-z0-9]{12}$")
65
+ scalar samUEI extends string;
66
+
67
+ /** A Data Universal Numbering System (DUNS) number */
68
+ @example("123456789012")
69
+ @pattern("^[0-9]{9}$")
70
+ scalar duns extends string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@common-grants/core",
3
- "version": "0.1.0-alpha.13",
3
+ "version": "0.1.0-alpha.14",
4
4
  "description": "TypeSpec library for defining grant opportunity data models and APIs",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",