@common-grants/core 0.2.3 → 0.3.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/api.tsp CHANGED
@@ -31,9 +31,17 @@ using Versioning;
31
31
  }
32
32
  )
33
33
  @tagMetadata("Forms", #{ description: "Endpoints related to forms" })
34
+ @tagMetadata(
35
+ "Application Reviews",
36
+ #{
37
+ description: "Endpoints related to reviewing applications for a given competition",
38
+ }
39
+ )
34
40
  @tagMetadata(
35
41
  "Applications",
36
- #{ description: "Endpoints related to applications for a given competition" }
42
+ #{
43
+ description: "Endpoints related to submitting applications for a given competition",
44
+ }
37
45
  )
38
46
  @tagMetadata(
39
47
  "Competitions",
@@ -122,6 +130,14 @@ namespace Applications {
122
130
 
123
131
  @added(Versions.v0_2)
124
132
  op submitApplication is ApplicationRouter.submitApplication;
133
+
134
+ // ################################
135
+ // Search applications
136
+ // ################################
137
+
138
+ @added(Versions.v0_3)
139
+ @tag("Application Reviews")
140
+ op searchApplications is ApplicationRouter.searchApplications;
125
141
  }
126
142
 
127
143
  // #########################################################
@@ -47,4 +47,24 @@ namespace Examples.File {
47
47
  createdAt: utcDateTime.fromISO("2025-01-01T17:01:01"),
48
48
  lastModifiedAt: utcDateTime.fromISO("2025-01-02T17:30:00"),
49
49
  };
50
+
51
+ const excelFile = #{
52
+ downloadUrl: "https://example.com/excel.xlsx",
53
+ name: "excel.xlsx",
54
+ description: "The excel file for the application",
55
+ sizeInBytes: 1000,
56
+ mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
57
+ createdAt: utcDateTime.fromISO("2025-01-01T17:01:01"),
58
+ lastModifiedAt: utcDateTime.fromISO("2025-01-02T17:30:00"),
59
+ };
60
+
61
+ const zipFile = #{
62
+ downloadUrl: "https://example.com/application.zip",
63
+ name: "application.zip",
64
+ description: "The zip file for the application",
65
+ sizeInBytes: 50000,
66
+ mimeType: "application/zip",
67
+ createdAt: utcDateTime.fromISO("2025-01-01T17:01:01"),
68
+ lastModifiedAt: utcDateTime.fromISO("2025-01-02T17:30:00"),
69
+ };
50
70
  }
@@ -13,6 +13,10 @@ model ApplicationBase {
13
13
  /** The unique identifier for the competition */
14
14
  competitionId: Types.uuid;
15
15
 
16
+ /** The unique identifier for the opportunity being applied to */
17
+ @Versioning.added(CommonGrants.Versions.v0_3)
18
+ opportunityId: Types.uuid;
19
+
16
20
  /** The form responses for the application */
17
21
  formResponses: Record<AppFormResponse>;
18
22
 
@@ -84,6 +88,79 @@ model AppFormResponse {
84
88
  ...FormResponseBase;
85
89
  }
86
90
 
91
+ // #########################################################
92
+ // AppFilters
93
+ // #########################################################
94
+
95
+ /** Filters to apply when searching for applications */
96
+ @Versioning.added(CommonGrants.Versions.v0_3)
97
+ model AppFilters {
98
+ /** The default filters to apply to the search */
99
+ ...AppDefaultFilters;
100
+
101
+ /** Additional implementation-defined filters to apply to the search */
102
+ customFilters?: Record<Filters.DefaultFilter>;
103
+ }
104
+
105
+ /** The standard set of filters supported for application searches */
106
+ @Versioning.added(CommonGrants.Versions.v0_3)
107
+ model AppDefaultFilters extends Record<Filters.DefaultFilter> {
108
+ /** `opportunityId` matches one of the following values */
109
+ @example(#{
110
+ operator: Filters.ArrayOperators.in,
111
+ value: #["ad3b469a-d89a-42d3-c439-6c1234567890"],
112
+ })
113
+ opportunityId?: Filters.StringArrayFilter;
114
+
115
+ /** `competitionId` matches one of the following values */
116
+ @example(#{
117
+ operator: Filters.ArrayOperators.in,
118
+ value: #["123e4567-e89b-12d3-a456-426614174000"],
119
+ })
120
+ competitionId?: Filters.StringArrayFilter;
121
+
122
+ /** `submittedAt` is between the given range */
123
+ @example(#{
124
+ operator: Filters.RangeOperators.between,
125
+ value: #{
126
+ min: Types.isoDate.fromISO("2025-01-01"),
127
+ max: Types.isoDate.fromISO("2025-01-30"),
128
+ },
129
+ })
130
+ submittedAtRange?: Filters.DateRangeFilter;
131
+
132
+ /** `status.value` matches one of the following values */
133
+ @example(#{
134
+ operator: Filters.ArrayOperators.in,
135
+ value: #["submitted", "accepted"],
136
+ })
137
+ status?: Filters.StringArrayFilter;
138
+ }
139
+
140
+ // #########################################################
141
+ // AppSorting
142
+ // #########################################################
143
+
144
+ /** The fields that can be used to sort applications */
145
+ @Versioning.added(CommonGrants.Versions.v0_3)
146
+ enum AppSortBy {
147
+ lastModifiedAt,
148
+ createdAt,
149
+ submittedAt,
150
+ status: "status.value",
151
+ opportunityId,
152
+ competitionId,
153
+ custom,
154
+ }
155
+
156
+ /** Sorting parameters for applications */
157
+ @Versioning.added(CommonGrants.Versions.v0_3)
158
+ model AppSorting extends Sorting.SortBodyParams {
159
+ /** The field to sort by */
160
+ @example(AppSortBy.opportunityId)
161
+ sortBy: AppSortBy;
162
+ }
163
+
87
164
  // #########################################################
88
165
  // Examples
89
166
  // #########################################################
@@ -110,14 +187,36 @@ namespace Examples.Application {
110
187
  ...Examples.FormResponse.formResponse,
111
188
  };
112
189
 
190
+ const attachmentsCustomField = #{
191
+ name: "attachments",
192
+ fieldType: Fields.CustomFieldType.object,
193
+ value: #{
194
+ contacts: Fields.Examples.File.pdfFile,
195
+ budget: Fields.Examples.File.excelFile,
196
+ },
197
+ description: "The attachments for the application",
198
+ };
199
+
200
+ const applicationZipFileCustomField = #{
201
+ name: "applicationZipFile",
202
+ fieldType: Fields.CustomFieldType.object,
203
+ value: Fields.Examples.File.zipFile,
204
+ description: "The zip file for the application",
205
+ };
206
+
113
207
  const applicationBase = #{
114
208
  id: "123e4567-e89b-12d3-a456-426614174000",
115
209
  name: "My Application",
116
210
  competitionId: "123e4567-e89b-12d3-a456-426614174000",
211
+ opportunityId: "ad3b469a-d89a-42d3-c439-6c1234567890",
117
212
  formResponses: #{ formA: formResponse },
118
213
  status: inProgressStatus,
119
214
  submittedAt: null,
120
215
  createdAt: utcDateTime.fromISO("2021-01-01T00:00:00Z"),
121
216
  lastModifiedAt: utcDateTime.fromISO("2021-01-01T00:00:00Z"),
217
+ customFields: #{
218
+ attachments: attachmentsCustomField,
219
+ applicationZipFile: applicationZipFileCustomField,
220
+ },
122
221
  };
123
222
  }
@@ -83,7 +83,7 @@ enum CompetitionStatusOptions {
83
83
  @example(Examples.Competition.forms)
84
84
  model CompetitionForms {
85
85
  /** The forms for the competition */
86
- forms: Record<Models.Form>;
86
+ forms: Record<Models.FormBase>;
87
87
 
88
88
  /** The validation rules for the competition forms */
89
89
  validation?: Record<unknown>;
@@ -9,7 +9,8 @@ namespace CommonGrants.Models;
9
9
  /** A form for collecting data from a user. */
10
10
  @example(Examples.Form.form)
11
11
  @Versioning.added(CommonGrants.Versions.v0_2)
12
- model Form {
12
+ @Versioning.renamedFrom(CommonGrants.Versions.v0_3, "Form")
13
+ model FormBase {
13
14
  /** The form's unique identifier. */
14
15
  id: Types.uuid;
15
16
 
@@ -19,6 +20,9 @@ model Form {
19
20
  /** The form's description. */
20
21
  description?: string;
21
22
 
23
+ @Versioning.added(CommonGrants.Versions.v0_3)
24
+ version?: string;
25
+
22
26
  /** The form's instructions. */
23
27
  instructions?: string | Fields.File[];
24
28
 
@@ -36,6 +40,9 @@ model Form {
36
40
 
37
41
  /** Custom attributes about the form itself, not custom fields within the form. */
38
42
  customFields?: Record<Fields.CustomField>;
43
+
44
+ /** The system metadata for the form. */
45
+ ...Fields.SystemMetadata;
39
46
  }
40
47
 
41
48
  // #########################################################
@@ -74,6 +81,8 @@ namespace Examples.Form {
74
81
  uiSchema: uiSchema,
75
82
  mappingToCommonGrants: mappingToCommonGrants,
76
83
  mappingFromCommonGrants: mappingFromCommonGrants,
84
+ createdAt: utcDateTime.fromISO("2025-01-01T17:01:01"),
85
+ lastModifiedAt: utcDateTime.fromISO("2025-01-02T17:30:00"),
77
86
  };
78
87
 
79
88
  const formSchema = #{
@@ -63,4 +63,20 @@ interface Applications {
63
63
  | Responses.ApplicationSubmissionError
64
64
  | Responses.NotFound
65
65
  | Responses.Unauthorized;
66
+
67
+ // ###############################
68
+ // Search applications
69
+ // ###############################
70
+
71
+ @summary("Search applications")
72
+ @doc("Search for applications. Note: The search results for a given query will depend on the scopes attached to the API token used to make the request.")
73
+ @get
74
+ @route("/search")
75
+ searchApplications(
76
+ /** The filters to apply to the search */
77
+ @query filters: Models.AppFilters,
78
+
79
+ /** The sorting to apply to the search */
80
+ @query sorting: Models.AppSorting,
81
+ ): Responses.Filtered<Models.ApplicationBase, Models.AppFilters>;
66
82
  }
@@ -22,7 +22,9 @@ interface Forms {
22
22
  @summary("List forms")
23
23
  @doc("Get a paginated list of forms, sorted by `lastModifiedAt` with most recent first.")
24
24
  @get
25
- list(...Pagination.PaginatedQueryParams): Responses.Paginated<Models.Form>;
25
+ list(
26
+ ...Pagination.PaginatedQueryParams,
27
+ ): Responses.Paginated<Models.FormBase>;
26
28
 
27
29
  // ###############################
28
30
  // View form details
@@ -34,5 +36,5 @@ interface Forms {
34
36
  read(
35
37
  /** The ID of the form to view */
36
38
  @path formId: Types.uuid,
37
- ): Responses.Ok<Models.Form>;
39
+ ): Responses.Ok<Models.FormBase>;
38
40
  }
package/lib/main.tsp CHANGED
@@ -18,4 +18,5 @@ namespace CommonGrants;
18
18
  enum Versions {
19
19
  v0_1: "0.1.0",
20
20
  v0_2: "0.2.0",
21
+ v0_3: "0.3.0",
21
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@common-grants/core",
3
- "version": "0.2.3",
3
+ "version": "0.3.0-alpha.1",
4
4
  "description": "TypeSpec library for defining grant opportunity data models and APIs",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -30,6 +30,18 @@
30
30
  "url": "https://github.com/HHS/simpler-grants-protocol/issues"
31
31
  },
32
32
  "homepage": "https://github.com/HHS/simpler-grants-protocol/tree/main/lib/core/#readme",
33
+ "scripts": {
34
+ "clean": "rimraf dist tsp-output",
35
+ "build": "tsc -p .",
36
+ "watch": "tsc -p . --watch",
37
+ "typespec": "tsp compile lib/main.tsp",
38
+ "prepare": "npm run build",
39
+ "lint": "eslint . --fix",
40
+ "format": "prettier --write . && tsp format lib",
41
+ "check:lint": "eslint",
42
+ "check:format": "prettier --check . && tsp format lib --check",
43
+ "checks": "npm run check:lint && npm run check:format"
44
+ },
33
45
  "keywords": [
34
46
  "typespec",
35
47
  "api",
@@ -39,34 +51,20 @@
39
51
  "author": "CommonGrants",
40
52
  "license": "CC0-1.0",
41
53
  "peerDependencies": {
42
- "@typespec/compiler": "^1.5.0",
43
- "@typespec/http": "^1.5.0",
44
- "@typespec/json-schema": "^1.5.0",
45
- "@typespec/openapi3": "^1.5.0",
46
- "@typespec/openapi": "^1.5.0",
47
- "@typespec/rest": "^0.75.0",
48
- "@typespec/versioning": "^0.75.0"
54
+ "@typespec/compiler": "^1.1.0",
55
+ "@typespec/http": "^1.1.0",
56
+ "@typespec/json-schema": "1.0.0",
57
+ "@typespec/openapi3": "1.0.0",
58
+ "@typespec/rest": "0.70.0",
59
+ "@typespec/versioning": "^0.70.0"
49
60
  },
50
61
  "devDependencies": {
51
- "@eslint/js": "^9.18.0",
52
62
  "@types/node": "^20.10.6",
53
63
  "eslint": "^9.18.0",
54
- "globals": "^15.14.0",
55
64
  "prettier": "^3.4.2",
56
65
  "rimraf": "^5.0.5",
57
66
  "source-map-support": "^0.5.21",
58
67
  "typescript": "^5.3.3",
59
68
  "typescript-eslint": "^8.20.0"
60
- },
61
- "scripts": {
62
- "clean": "rimraf dist tsp-output",
63
- "build": "tsc -p .",
64
- "watch": "tsc -p . --watch",
65
- "typespec": "tsp compile lib/main.tsp",
66
- "lint": "eslint . --fix",
67
- "format": "prettier --write . && tsp format lib",
68
- "check:lint": "eslint",
69
- "check:format": "prettier --check . && tsp format lib --check",
70
- "checks": "npm run check:lint && npm run check:format"
71
69
  }
72
- }
70
+ }
package/LICENSE.md DELETED
@@ -1,34 +0,0 @@
1
- # License
2
-
3
- As a work of the [United States government](https://www.usa.gov/), this project
4
- is in the public domain within the United States of America.
5
-
6
- Additionally, we waive copyright and related rights in the work worldwide
7
- through the CC0 1.0 Universal public domain dedication.
8
-
9
- ## CC0 1.0 Universal Summary
10
-
11
- This is a human-readable summary of the [Legal Code (read the full
12
- text)](https://creativecommons.org/publicdomain/zero/1.0/legalcode).
13
-
14
- ### No Copyright
15
-
16
- The person who associated a work with this deed has dedicated the work to the
17
- public domain by waiving all of their rights to the work worldwide under
18
- copyright law, including all related and neighboring rights, to the extent
19
- allowed by law.
20
-
21
- You can copy, modify, distribute, and perform the work, even for commercial
22
- purposes, all without asking permission.
23
-
24
- ### Other Information
25
-
26
- In no way are the patent or trademark rights of any person affected by CC0, nor
27
- are the rights that other persons may have in the work or in how the work is
28
- used, such as publicity or privacy rights.
29
-
30
- Unless expressly stated otherwise, the person who associated a work with this
31
- deed makes no warranties about the work, and disclaims liability for all uses
32
- of the work, to the fullest extent permitted by applicable law. When using or
33
- citing the work, you should not imply endorsement by the author or the
34
- affirmer.