@common-grants/core 0.1.0-alpha.10

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,98 @@
1
+ import "../models/index.tsp";
2
+ import "../responses/index.tsp";
3
+ import "../pagination.tsp";
4
+
5
+ // Define the top-level namespace for CommonGrants routes
6
+ namespace CommonGrants.Routes;
7
+
8
+ // Expose the contents of the Http and Rest namespaces
9
+ // these include the decorators @route, @get, etc.
10
+ using TypeSpec.Http;
11
+
12
+ /** A re-usable interface for an Opportunities router
13
+ *
14
+ * To implement this interface, we recommend declaring a namespace,
15
+ * instantiating the router using `alias` (instead of `extends`),
16
+ * and decorating the namespace with `@route` and `@tag` since they aren't
17
+ * inherited directly from the interface.
18
+ *
19
+ * For more information, see
20
+ * [TypeSpec docs](https://typespec.io/docs/language-basics/interfaces/#templating-interface-operations)
21
+ *
22
+ * @example Using the the default type for the list operation and
23
+ * a custom model for the read operation:
24
+ * ```typespec
25
+ * using TypeSpec.Http;
26
+ *
27
+ * @tag("Opportunities")
28
+ * @route("/opportunities/")
29
+ * namespace Opportunities {
30
+ * alias Router = Routes.Opportunities
31
+ *
32
+ * op list is Router.list;
33
+ * op read is Router.read<CustomOpportunity>;
34
+ * }
35
+ * ```
36
+ */
37
+ interface Opportunities {
38
+ // ###############################
39
+ // List opportunities
40
+ // ###############################
41
+
42
+ /** `GET /opportunities/` Get a paginated list of opportunities
43
+ *
44
+ * @template T Type of the paginated response model.
45
+ * Must be an extension of Schemas.OpportunityBase. Default is Schemas.OpportunityBase.
46
+ */
47
+ @summary("List opportunities")
48
+ @doc("Get a paginated list of opportunities, sorted by `lastModifiedAt` with most recent first.")
49
+ @list
50
+ list<T extends Models.OpportunityBase = Models.OpportunityBase>(
51
+ ...Pagination.PaginatedQueryParams,
52
+ ): Responses.Paginated<T> | Responses.Unauthorized;
53
+
54
+ // ##############################
55
+ // View an opportunity
56
+ // ##############################
57
+
58
+ /** `GET /opportunities/<id>` View opportunity details
59
+ *
60
+ * @template T Type of the response model.
61
+ * Must be an extension of Schemas.OpportunityBase. Default is Schemas.OpportunityBase.
62
+ */
63
+ @summary("View opportunity")
64
+ @doc("View additional details about an opportunity")
65
+ @get
66
+ read<T extends Models.OpportunityBase = Models.OpportunityBase>(
67
+ /** The ID of the opportunity to view */
68
+ @path id: Types.uuid,
69
+ ): Responses.Ok<T> | Responses.NotFound | Responses.Unauthorized;
70
+
71
+ // ###############################
72
+ // Search opportunities
73
+ // ###############################
74
+
75
+ /** `POST /opportunities/search` Search opportunities
76
+ *
77
+ * @template T Type of the response model.
78
+ * Must be an extension of Schemas.OpportunityBase. Default is Schemas.OpportunityBase.
79
+ */
80
+ @summary("Search opportunities")
81
+ @doc("Search for opportunities based on the provided filters")
82
+ @post
83
+ @route("/search")
84
+ search<T extends Models.OpportunityBase = Models.OpportunityBase>(
85
+ /** Filters to apply to the opportunity search
86
+ *
87
+ * Multiple filter conditions will be combined with AND logic, so that
88
+ * results only include opportunities that match all of the provided filters.
89
+ */
90
+ filters?: Models.OppFilters,
91
+
92
+ /** The sort order to apply to the results */
93
+ sorting?: Models.OppSorting,
94
+
95
+ /** Pagination instructions for the results */
96
+ pagination?: Pagination.PaginatedBodyParams,
97
+ ): Responses.Filtered<T, Models.OppFilters> | Responses.Unauthorized;
98
+ }
@@ -0,0 +1,71 @@
1
+ import "@typespec/http";
2
+
3
+ using TypeSpec.Http;
4
+
5
+ /** Models for sorting
6
+ *
7
+ * @example How to use the `Sorting` namespace
8
+ * ```typespec
9
+ *
10
+ * using CommonGrants // Exposes the `Sorting` and `Responses` namespaces
11
+ * using TypeSpec.Http;
12
+ *
13
+ * @route("/foo/")
14
+ * @get
15
+ * op list(sorting: Sorting.SortQueryParams): Responses.Sorted<MyModel>;
16
+ * ```
17
+ */
18
+ namespace CommonGrants.Sorting;
19
+
20
+ enum SortOrder {
21
+ asc,
22
+ desc,
23
+ }
24
+
25
+ /** Query parameters for sorting */
26
+ model SortQueryParams {
27
+ /** The field to sort by */
28
+ @query
29
+ @example("lastModifiedAt")
30
+ sortBy: string;
31
+
32
+ /** Implementation-defined sort key */
33
+ @query
34
+ @example("customField")
35
+ customSortBy?: string;
36
+
37
+ /** The order to sort by */
38
+ @query
39
+ @example(SortOrder.asc)
40
+ sortOrder?: SortOrder;
41
+ }
42
+
43
+ /** Sorting parameters included in the request body */
44
+ model SortBodyParams {
45
+ /** The field to sort by */
46
+ @example("lastModifiedAt")
47
+ sortBy: unknown;
48
+
49
+ /** Implementation-defined sort key */
50
+ @example("customField")
51
+ customSortBy?: string;
52
+
53
+ /** The order to sort by */
54
+ @example(SortOrder.asc)
55
+ sortOrder?: SortOrder;
56
+ }
57
+
58
+ /** Information about the sort order of the items returned */
59
+ model SortInfo {
60
+ /** The field to sort by */
61
+ @example("lastModifiedAt")
62
+ sortBy: string;
63
+
64
+ /** Implementation-defined sort key */
65
+ @example("customField")
66
+ customSortBy?: string;
67
+
68
+ /** The order to sort by */
69
+ @example(SortOrder.asc)
70
+ sortOrder?: SortOrder;
71
+ }
@@ -0,0 +1,42 @@
1
+ /** A collection of base data types used throughout the CommonGrants API
2
+ *
3
+ * @example How to use the `Types` namespace
4
+ *
5
+ * ```typespec
6
+ * import "@common-grants/core";
7
+ *
8
+ * using CommonGrants; // exposes the Types namespace
9
+ *
10
+ * model MyModel {
11
+ * @example("30a12e5e-5940-4c08-921c-17a8960fcf4b")
12
+ * id: Types.uuid;
13
+ *
14
+ * @example(Types.isoDate.fromISO("2025-01-01"))
15
+ * keyDate: Types.isoDate;
16
+ * }
17
+ * ```
18
+ */
19
+ namespace CommonGrants.Types;
20
+
21
+ /** A time on a clock, without a timezone, in ISO 8601 format HH:mm:ss */
22
+ @example(isoTime.fromISO("17:00:00"))
23
+ scalar isoTime extends plainTime;
24
+
25
+ /** A date on a calendar in ISO 8601 format YYYY-MM-DD */
26
+ @example(isoDate.fromISO("2025-01-01"))
27
+ scalar isoDate extends plainDate;
28
+
29
+ /** A universally unique identifier */
30
+ @example("30a12e5e-5940-4c08-921c-17a8960fcf4b")
31
+ @format("uuid")
32
+ scalar uuid extends string;
33
+
34
+ /** A decimal number (with variable scale) encoded as a string, to avoid floating point issues */
35
+ @pattern(
36
+ "^-?[0-9]+\\.?[0-9]*$",
37
+ "Must be a valid decimal number represented as a string"
38
+ )
39
+ @example("100", #{ title: "Scale 0" })
40
+ @example("100.5", #{ title: "Scale 1" })
41
+ @example("-100.5", #{ title: "Negative, scale 2" })
42
+ scalar decimalString extends string;
package/lib/main.tsp ADDED
@@ -0,0 +1,9 @@
1
+ // Import the JS entry point for this library
2
+ // For more details see:
3
+ // https://typespec.io/docs/extending-typespec/basics/#h-add-your-main-typespec-file
4
+ import "../dist/src/index.js";
5
+
6
+ import "./core/index.tsp";
7
+ import "./api.tsp";
8
+
9
+ namespace CommonGrants;
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@common-grants/core",
3
+ "version": "0.1.0-alpha.10",
4
+ "description": "TypeSpec library for defining grant opportunity data models and APIs",
5
+ "type": "module",
6
+ "main": "dist/src/index.js",
7
+ "types": "dist/src/index.d.ts",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "typespec": "./lib/main.tsp",
14
+ "default": "./dist/src/index.js",
15
+ "types": "./dist/src/index.d.ts"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist/src/**/*.js",
20
+ "dist/src/**/*.d.ts",
21
+ "lib/**/*.tsp",
22
+ "!src/**/*.test.*"
23
+ ],
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/HHS/simpler-grants-protocol.git",
27
+ "directory": "specs"
28
+ },
29
+ "bugs": {
30
+ "url": "https://github.com/HHS/simpler-grants-protocol/issues"
31
+ },
32
+ "homepage": "https://github.com/HHS/simpler-grants-protocol/tree/main/specs#readme",
33
+ "scripts": {
34
+ "prepublishOnly": "bash scripts/prepublish-checks.sh",
35
+ "clean": "rimraf dist tsp-output",
36
+ "build": "tsc -p .",
37
+ "watch": "tsc -p . --watch",
38
+ "typespec": "tsp compile lib/main.tsp",
39
+ "prepare": "npm run build",
40
+ "lint": "eslint . --fix",
41
+ "format": "prettier --write . && tsp format lib",
42
+ "check:lint": "eslint",
43
+ "check:format": "prettier --check . && tsp format lib --check",
44
+ "checks": "npm run check:lint && npm run check:format",
45
+ "docs:build": "npx @redocly/cli build-docs tsp-output/@typespec/openapi3/openapi.yaml --output ./dist/redocly.html",
46
+ "docs:preview": "open ./dist/redocly.html",
47
+ "docs": "npm run typespec && npm run docs:build && npm run docs:preview"
48
+ },
49
+ "keywords": [
50
+ "typespec",
51
+ "api",
52
+ "grants",
53
+ "opportunities"
54
+ ],
55
+ "author": "CommonGrants",
56
+ "license": "CC0-1.0",
57
+ "peerDependencies": {
58
+ "@typespec/compiler": "^0.63.0",
59
+ "@typespec/http": "^0.63.0",
60
+ "@typespec/json-schema": "^0.63.0",
61
+ "@typespec/openapi3": "^0.63.0",
62
+ "@typespec/rest": "^0.63.0"
63
+ },
64
+ "devDependencies": {
65
+ "@types/node": "^20.10.6",
66
+ "eslint": "^9.18.0",
67
+ "prettier": "^3.4.2",
68
+ "rimraf": "^5.0.5",
69
+ "source-map-support": "^0.5.21",
70
+ "typescript": "^5.3.3",
71
+ "typescript-eslint": "^8.20.0"
72
+ }
73
+ }