elections-types 1.0.0

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,13 @@
1
+ import js from "@eslint/js";
2
+ import globals from "globals";
3
+ import tseslint from "typescript-eslint";
4
+ import { defineConfig } from "eslint/config";
5
+
6
+ export default defineConfig([
7
+ { files: ["**/*.{js,mjs,cjs,ts,mts,cts}"], plugins: { js }, extends: ["js/recommended"], languageOptions: { globals: globals.browser } },
8
+ {
9
+ rules: {
10
+ "@typescript-eslint/explicit-function-return-type": "error"
11
+ },
12
+ },
13
+ ]);
package/jest.config.js ADDED
@@ -0,0 +1,20 @@
1
+ import { createDefaultPreset } from "ts-jest"
2
+
3
+ const tsJestTransformCfg = createDefaultPreset().transform;
4
+
5
+ /** @type {import("jest").Config} **/
6
+ export default {
7
+ testEnvironment: "node",
8
+ transform: {
9
+ ...tsJestTransformCfg,
10
+ },
11
+ transformIgnorePatterns: ["/node_modules/(?!@smithy|@aws-sdk).+\\.js$"],
12
+ globals : {
13
+ "ts-jest" : {
14
+ useESM : true
15
+ }
16
+ },
17
+ extensionsToTreatAsEsm : [".ts"],
18
+ testTimeout : 30000,
19
+ testPathIgnorePatterns: ['dist/']
20
+ };
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "elections-types",
3
+ "version": "1.0.0",
4
+ "main": "dist/src/index.js",
5
+ "types": "dist/src/index.d.ts",
6
+ "directories": {
7
+ "test": "test"
8
+ },
9
+ "scripts": {
10
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
11
+ "build": "tsc && tsc-alias"
12
+ },
13
+ "author": "",
14
+ "license": "ISC",
15
+ "description": "",
16
+ "type": "module",
17
+ "devDependencies": {
18
+ "@eslint/js": "^9.39.2",
19
+ "@types/jest": "^30.0.0",
20
+ "eslint": "^9.39.2",
21
+ "globals": "^17.3.0",
22
+ "jest": "^30.2.0",
23
+ "jiti": "^2.6.1",
24
+ "ts-jest": "^29.4.6",
25
+ "tsc-alias": "^1.8.16",
26
+ "tsx": "^4.21.0",
27
+ "typescript": "^5.9.3",
28
+ "typescript-eslint": "^8.55.0"
29
+ }
30
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./types/APIError"
2
+ export * from "./types/Tweet"
3
+ export * from "./types/User"
@@ -0,0 +1,21 @@
1
+ const default_messages_by_status : Record<number, string> = {
2
+ 400 : "Bad Request",
3
+ 401 : "Unauthorized",
4
+ 403 : "Forbidden",
5
+ 404 : "Not Found",
6
+ 405 : "Method Not Allowed",
7
+ 500 : "Internal Server Error",
8
+ 504 : "Gateway Timeout",
9
+ 600 : "Failed to Parse Output"
10
+ }
11
+
12
+
13
+ export class APIError extends Error {
14
+ status : number
15
+ constructor(status : number, message?: string) {
16
+ const default_message = default_messages_by_status[status]
17
+ super(message !== undefined ? message : default_message !== undefined ? default_message : "Error")
18
+ this.name = "APIError"
19
+ this.status = status
20
+ }
21
+ }
@@ -0,0 +1,52 @@
1
+ // import { ElectionID, OfficeID } from "./Election"
2
+ // import { StateID } from "./State"
3
+
4
+ // export class Candidate {
5
+ // readonly candidate_id : string
6
+ // readonly fec_name : string
7
+ // readonly office_id : OfficeID
8
+ // readonly state_id : StateID
9
+ // readonly election_id : ElectionID
10
+ // readonly party_id : string
11
+ // readonly active : boolean
12
+ // readonly status : boolean
13
+
14
+ // constructor(candidate : any) {
15
+ // if (!Candidate.is(candidate)) {
16
+ // throw Error("Invalid input.")
17
+ // }
18
+ // this.office_id = candidate.office_id
19
+ // this.number = candidate.number
20
+ // this.scout_id = candidate.scout_id
21
+ // this.name = candidate.name
22
+ // this.active = candidate.active
23
+ // this.state_id = candidate.state_id
24
+ // this.district = candidate.district
25
+ // this.party_id = candidate.party_id
26
+ // this.tone_description_refresh = candidate.tone_description_refresh
27
+ // this.jurisdiction_ids = candidate.jurisdiction_ids
28
+ // this.sub_scout_ids = candidate.sub_scout_ids
29
+ // this.office_class_id = candidate.office_class_id
30
+ // this.office_name = candidate.office_name
31
+ // }
32
+
33
+ // static is(candidate : any) : candidate is Candidate {
34
+ // return (
35
+ // candidate !== undefined &&
36
+ // typeof candidate.office_id === "string" &&
37
+ // typeof candidate.number === "string" &&
38
+ // typeof candidate.scout_id === "string" &&
39
+ // typeof candidate.name === "string" &&
40
+ // typeof candidate.active === "boolean" &&
41
+ // (candidate.state_id === undefined || is_state_id(candidate.state_id)) &&
42
+ // (candidate.district === undefined || typeof candidate.district === "number") &&
43
+ // is_party_id(candidate.party_id) &&
44
+ // typeof candidate.tone_description_refresh === "boolean" &&
45
+ // Array.isArray(candidate.jurisdiction_ids) &&
46
+ // candidate.jurisdiction_ids.every((jurisdiction_id : any) => typeof jurisdiction_id === "number") &&
47
+ // (candidate.sub_scout_ids === undefined || Array.isArray(candidate.sub_scout_ids) && candidate.sub_scout_ids.every((sub_scout_id : any) => typeof sub_scout_id === "string")) &&
48
+ // is_office_class_id(candidate.office_class_id) &&
49
+ // (candidate.office_name === undefined || typeof candidate.office_name === "string")
50
+ // )
51
+ // }
52
+ // }
@@ -0,0 +1,62 @@
1
+ export const designations = ["F1", "F2", "F3", "F24"] as const
2
+
3
+ export type CommitteeDesignation = typeof designations[number]
4
+
5
+ export function is_committee_designation(designation : any) : designation is CommitteeDesignation {
6
+ return designations.includes(designation)
7
+ }
8
+
9
+ export class Committee {
10
+ readonly committee_id : string
11
+ readonly name : string
12
+ readonly url : string
13
+ readonly designation : CommitteeDesignation
14
+ readonly file_number : number
15
+ readonly principal_committee_ids? : string[]
16
+ readonly authorized_committee_ids? : string[]
17
+ readonly sponsor_committee_ids? : string[]
18
+ readonly jfp_committee_ids? : string[]
19
+ readonly jfr_committee_ids? : string[]
20
+ readonly aff_committee_ids? : string[]
21
+ readonly candidate_ids? : string[]
22
+ readonly election_ids? : string[]
23
+ readonly [x : string] : any
24
+
25
+ constructor(committee : any) {
26
+ if (!Committee.is(committee)) {
27
+ throw Error("Invalid input.")
28
+ }
29
+ this.committee_id = committee.committee_id
30
+ this.name = committee.name
31
+ this.url = committee.url
32
+ this.designation = committee.designation
33
+ this.file_number = committee.file_number
34
+ this.principal_committee_ids = committee.principal_committee_ids
35
+ this.authorized_committee_ids = committee.authorized_committee_ids
36
+ this.sponsor_committee_ids = committee.sponsor_committee_ids
37
+ this.jfp_committee_ids = committee.jfp_committee_ids
38
+ this.jfr_committee_ids = committee.jfr_committee_ids
39
+ this.aff_committee_ids = committee.aff_committee_ids
40
+ this.candidate_ids = committee.candidate_ids
41
+ this.election_ids = committee.election_ids
42
+ }
43
+
44
+ static is(committee : any) : committee is Committee {
45
+ return (
46
+ committee !== undefined &&
47
+ typeof committee.committee_id === "string" &&
48
+ typeof committee.name === "string" &&
49
+ typeof committee.url === "string" &&
50
+ is_committee_designation(committee.designation) &&
51
+ typeof committee.file_number === "number" &&
52
+ (committee.principal_committee_ids === undefined || Array.isArray(committee.principal_committee_ids) && committee.principal_committee_ids.every((committee_id : any) => typeof committee_id === "string")) &&
53
+ (committee.authorized_committee_ids === undefined || Array.isArray(committee.authorized_committee_ids) && committee.authorized_committee_ids.every((committee_id : any) => typeof committee_id === "string")) &&
54
+ (committee.sponsor_committee_ids === undefined || Array.isArray(committee.sponsor_committee_ids) && committee.sponsor_committee_ids.every((committee_id : any) => typeof committee_id === "string")) &&
55
+ (committee.jfp_committee_ids === undefined || Array.isArray(committee.jfp_committee_ids) && committee.jfp_committee_ids.every((committee_id : any) => typeof committee_id === "string")) &&
56
+ (committee.jfr_committee_ids === undefined || Array.isArray(committee.jfr_committee_ids) && committee.jfr_committee_ids.every((committee_id : any) => typeof committee_id === "string")) &&
57
+ (committee.aff_committee_ids === undefined || Array.isArray(committee.aff_committee_ids) && committee.aff_committee_ids.every((committee_id : any) => typeof committee_id === "string")) &&
58
+ (committee.candidate_ids === undefined || Array.isArray(committee.candidate_ids) && committee.candidate_ids.every((committee_id : any) => typeof committee_id === "string")) &&
59
+ (committee.election_ids === undefined || Array.isArray(committee.election_ids) && committee.election_ids.every((committee_id : any) => typeof committee_id === "string"))
60
+ )
61
+ }
62
+ }
@@ -0,0 +1,62 @@
1
+ import { is_state_id, state_ids, StateID } from "./State"
2
+
3
+ const office_ids = ["H", "S"] as const
4
+
5
+ export type OfficeID = typeof office_ids[number]
6
+
7
+ export function is_office_id(office_id : any) : office_id is OfficeID {
8
+ return office_ids.includes(office_id)
9
+ }
10
+
11
+ export type ElectionID = string
12
+
13
+ export function is_election_id(election_id : any) : election_id is ElectionID {
14
+ const parts = election_id.split("-")
15
+ const year = Number(parts[0])
16
+ const office_id = parts[1]
17
+ const state_id = parts[2]
18
+ const district = Number(parts[3])
19
+ return (
20
+ (parts.length === 4 && office_id === "H" || parts.length === 3) &&
21
+ Number.isInteger(year) && year > 1700 && year < 3000 &&
22
+ is_office_id(office_id) &&
23
+ is_state_id(state_id) &&
24
+ (office_id === "S" || Number.isInteger(district) && district < 100)
25
+ )
26
+ }
27
+
28
+ export class Election {
29
+ readonly election_id : ElectionID
30
+ readonly name : string
31
+ readonly office_id : OfficeID
32
+ readonly state_id : StateID
33
+ readonly district? : string
34
+ readonly candidate_ids? : string[]
35
+ readonly committee_ids? : string[]
36
+
37
+ constructor(election : any) {
38
+ if (!Election.is(election)) {
39
+ throw Error("Invalid input.")
40
+ }
41
+ this.election_id = election.election_id
42
+ this.name = election.name
43
+ this.office_id = election.office_id
44
+ this.state_id = election.state_id
45
+ this.district = election.district
46
+ this.candidate_ids = election.candidate_ids
47
+ this.committee_ids = election.committee_ids
48
+ }
49
+
50
+ static is(election : any) : election is Election {
51
+ return (
52
+ election !== undefined &&
53
+ is_election_id(election.election_id) &&
54
+ typeof election.name === "string" &&
55
+ is_office_id(election.office_id) &&
56
+ is_state_id(election.state_id) &&
57
+ (election.district === undefined && typeof election.district === "string") &&
58
+ (election.candidate_ids === undefined || Array.isArray(election.candidate_ids) && election.candidate_ids.every((candidate_id : any) => typeof candidate_id === "string")) &&
59
+ (election.committee_ids === undefined || Array.isArray(election.committee_ids) && election.committee_ids.every((committee_id : any) => typeof committee_id === "string"))
60
+ )
61
+ }
62
+ }
@@ -0,0 +1,23 @@
1
+ export interface ElectionsUtilsConfig {
2
+ region : string,
3
+ scraping_bee_api_key? : string,
4
+ xai_api_key? : string,
5
+ citizenportal_api_key? : string,
6
+ youtube_api_key? : string
7
+ [key : string]: any
8
+ }
9
+
10
+ export interface ElectionsConfig extends ElectionsUtilsConfig {
11
+ port : number,
12
+ api_url : string,
13
+ client_url : string,
14
+ auth_url : string,
15
+ cognito_user_pool_id : string,
16
+ cognito_client_id : string,
17
+ cognito_client_secret : string,
18
+ secret_key : string,
19
+ // admin_key : string,
20
+ dynamodb_donations : string,
21
+ s3_bucket : string,
22
+ s3vectors_bucket : string
23
+ }
@@ -0,0 +1,20 @@
1
+ export const form_type_ids = ["F1", "F2", "F3", "F24"] as const
2
+
3
+ export type FormTypeID = typeof form_type_ids[number]
4
+
5
+ export function is_form_type_id(form_type_id : any) : form_type_id is FormTypeID {
6
+ return form_type_ids.includes(form_type_id)
7
+ }
8
+
9
+ export const long_form_type_ids = [
10
+ "F1N", "F1A", "F1T",
11
+ "F2N", "F2A", "F2T",
12
+ "F3N", "F3A", "F3T",
13
+ "F24N", "F24A"
14
+ ] as const
15
+
16
+ export type LongFormTypeID = typeof long_form_type_ids[number]
17
+
18
+ export function is_long_form_type_id(long_form_type_id : any) : long_form_type_id is LongFormTypeID {
19
+ return long_form_type_ids.includes(long_form_type_id)
20
+ }
@@ -0,0 +1,215 @@
1
+ export const state_ids = ["AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY"] as const
2
+
3
+ export type StateID = typeof state_ids[number]
4
+
5
+ export function is_state_id(state_id : any) : state_id is StateID {
6
+ return state_ids.includes(state_id)
7
+ }
8
+
9
+ export interface State {
10
+ state_id : StateID,
11
+ name : string
12
+ }
13
+
14
+ export const states_by_state_id : Record<StateID, State> = {
15
+ AL : {
16
+ state_id : "AL",
17
+ name : "Alabama"
18
+ },
19
+ AK : {
20
+ state_id : "AK",
21
+ name : "Alaska"
22
+ },
23
+ AZ : {
24
+ state_id : "AZ",
25
+ name : "Arizona"
26
+ },
27
+ AR : {
28
+ state_id : "AR",
29
+ name : "Arkansas"
30
+ },
31
+ CA : {
32
+ state_id : "CA",
33
+ name : "California"
34
+ },
35
+ CO : {
36
+ state_id : "CO",
37
+ name : "Colorado"
38
+ },
39
+ CT : {
40
+ state_id : "CT",
41
+ name : "Connecticut"
42
+ },
43
+ DE : {
44
+ state_id : "DE",
45
+ name : "Delaware"
46
+ },
47
+ FL : {
48
+ state_id : "FL",
49
+ name : "Florida"
50
+ },
51
+ GA : {
52
+ state_id : "GA",
53
+ name : "Georgia"
54
+ },
55
+ HI : {
56
+ state_id : "HI",
57
+ name : "Hawaii"
58
+ },
59
+ ID : {
60
+ state_id : "ID",
61
+ name : "Idaho"
62
+ },
63
+ IL : {
64
+ state_id : "IL",
65
+ name : "Illinois"
66
+ },
67
+ IN : {
68
+ state_id : "IN",
69
+ name : "Indiana"
70
+ },
71
+ IA : {
72
+ state_id : "IA",
73
+ name : "Iowa"
74
+ },
75
+ KS : {
76
+ state_id : "KS",
77
+ name : "Kansas"
78
+ },
79
+ KY : {
80
+ state_id : "KY",
81
+ name : "Kentucky"
82
+ },
83
+ LA : {
84
+ state_id : "LA",
85
+ name : "Louisiana"
86
+ },
87
+ ME : {
88
+ state_id : "ME",
89
+ name : "Maine"
90
+ },
91
+ MD : {
92
+ state_id : "MD",
93
+ name : "Maryland"
94
+ },
95
+ MA : {
96
+ state_id : "MA",
97
+ name : "Massachusetts"
98
+ },
99
+ MI : {
100
+ state_id : "MI",
101
+ name : "Michigan"
102
+ },
103
+ MN : {
104
+ state_id : "MN",
105
+ name : "Minnesota"
106
+ },
107
+ MS : {
108
+ state_id : "MS",
109
+ name : "Mississippi"
110
+ },
111
+ MO : {
112
+ state_id : "MO",
113
+ name : "Missouri"
114
+ },
115
+ MT : {
116
+ state_id : "MT",
117
+ name : "Montana"
118
+ },
119
+ NE : {
120
+ state_id : "NE",
121
+ name : "Nebraska"
122
+ },
123
+ NV : {
124
+ state_id : "NV",
125
+ name : "Nevada"
126
+ },
127
+ NH : {
128
+ state_id : "NH",
129
+ name : "New Hampshire"
130
+ },
131
+ NJ : {
132
+ state_id : "NJ",
133
+ name : "New Jersey"
134
+ },
135
+ NM : {
136
+ state_id : "NM",
137
+ name : "New Mexico"
138
+ },
139
+ NY : {
140
+ state_id : "NY",
141
+ name : "New York"
142
+ },
143
+ NC : {
144
+ state_id : "NC",
145
+ name : "North Carolina"
146
+ },
147
+ ND : {
148
+ state_id : "ND",
149
+ name : "North Dakota"
150
+ },
151
+ OH : {
152
+ state_id : "OH",
153
+ name : "Ohio"
154
+ },
155
+ OK : {
156
+ state_id : "OK",
157
+ name : "Oklahoma"
158
+ },
159
+ OR : {
160
+ state_id : "OR",
161
+ name : "Oregon"
162
+ },
163
+ PA : {
164
+ state_id : "PA",
165
+ name : "Pennsylvania"
166
+ },
167
+ RI : {
168
+ state_id : "RI",
169
+ name : "Rhode Island"
170
+ },
171
+ SC : {
172
+ state_id : "SC",
173
+ name : "South Carolina"
174
+ },
175
+ SD : {
176
+ state_id : "SD",
177
+ name : "South Dakota"
178
+ },
179
+ TN : {
180
+ state_id : "TN",
181
+ name : "Tennessee"
182
+ },
183
+ TX : {
184
+ state_id : "TX",
185
+ name : "Texas"
186
+ },
187
+ UT : {
188
+ state_id : "UT",
189
+ name : "Utah"
190
+ },
191
+ VT : {
192
+ state_id : "VT",
193
+ name : "Vermont"
194
+ },
195
+ VA : {
196
+ state_id : "VA",
197
+ name : "Virginia"
198
+ },
199
+ WA : {
200
+ state_id : "WA",
201
+ name : "Washington"
202
+ },
203
+ WV : {
204
+ state_id : "WV",
205
+ name : "West Virginia"
206
+ },
207
+ WI : {
208
+ state_id : "WI",
209
+ name : "Wisconsin"
210
+ },
211
+ WY : {
212
+ state_id : "WY",
213
+ name : "Wyoming"
214
+ }
215
+ }
@@ -0,0 +1,38 @@
1
+ export class Tweet {
2
+ readonly tweet_id : string
3
+ readonly username : string
4
+ readonly url : string
5
+ readonly tweet_time : string
6
+ readonly tweet_content : string
7
+ readonly quote? : string
8
+ readonly html : string
9
+ readonly text : string
10
+
11
+ constructor(tweet : any) {
12
+ if (!Tweet.is(tweet)) {
13
+ throw Error("Invalid input.")
14
+ }
15
+ this.tweet_id = tweet.tweet_id
16
+ this.username = tweet.username
17
+ this.url = tweet.url
18
+ this.tweet_time = tweet.tweet_time
19
+ this.tweet_content = tweet.tweet_content
20
+ this.quote = tweet.quote
21
+ this.html = tweet.html
22
+ this.text = tweet.text
23
+ }
24
+
25
+ static is(tweet : any) : tweet is Tweet {
26
+ return (
27
+ tweet !== undefined &&
28
+ typeof tweet.tweet_id === "string" &&
29
+ typeof tweet.username === "string" &&
30
+ typeof tweet.url === "string" &&
31
+ typeof tweet.tweet_time === "string" &&
32
+ typeof tweet.tweet_content === "string" &&
33
+ (tweet.quote === undefined || typeof tweet.quote === "string") &&
34
+ (typeof tweet.html === "string") &&
35
+ (typeof tweet.text === "string")
36
+ )
37
+ }
38
+ }
@@ -0,0 +1,34 @@
1
+ import { is_long_form_type_id, LongFormTypeID } from "./FormTypeID"
2
+
3
+ export class User {
4
+ readonly user_id : string
5
+ readonly admin : boolean
6
+ readonly premium : boolean
7
+ readonly email : string
8
+ readonly email_settings : Record<LongFormTypeID, boolean>
9
+ // readonly [x : string] : any
10
+
11
+ constructor(user : any) {
12
+ if (!User.is(user)) {
13
+ throw Error("Invalid Input.")
14
+ }
15
+ this.user_id = user.user_id
16
+ this.admin = user.admin
17
+ this.premium = user.premium
18
+ this.email = user.email
19
+ this.email_settings = user.email_settings
20
+ }
21
+
22
+ static is(user : any) : user is User {
23
+ return (
24
+ user !== undefined &&
25
+ typeof user.user_id === "string" &&
26
+ typeof user.admin === "boolean" &&
27
+ typeof user.premium === "boolean" &&
28
+ typeof user.email === "string" &&
29
+ Array.isArray(user.scout_ids) &&
30
+ typeof user.email_settings === "object" &&
31
+ Object.entries(user.email_settings).every(([key, value]) => is_long_form_type_id(key) && typeof value === "boolean")
32
+ )
33
+ }
34
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "./dist",
4
+
5
+ // Treat files as modules even if it doesn't use import/export
6
+ "moduleDetection": "force",
7
+
8
+ // Ignore module structure
9
+ "module" : "esnext",
10
+ "target" : "es2022",
11
+ "noImplicitAny" : true,
12
+ "noImplicitReturns" : true,
13
+ "moduleResolution": "bundler",
14
+ "declaration": true,
15
+ // Allow JS files to be imported from TS and vice versa
16
+ "allowJs": true,
17
+ "strict" : true,
18
+ // Use correct ESM import behavior
19
+ "esModuleInterop": true,
20
+ "resolveJsonModule": true,
21
+ // Disallow features that require cross-file awareness
22
+ "isolatedModules": true,
23
+ "lib": ["es2022"],
24
+ "rootDir": "./",
25
+ "skipLibCheck": true,
26
+ "maxNodeModuleJsDepth": 0,
27
+ "types": ["jest", "node"]
28
+ },
29
+ "tsc-alias": {
30
+ "resolveFullPaths": true,
31
+ "verbose": false
32
+ },
33
+ "include" : ["src/**/*", "test/**/*"]
34
+ }