doers-comms-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,32 @@
1
+ {
2
+ "name": "doers-comms-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
+ "dependencies": {
18
+ },
19
+ "devDependencies": {
20
+ "@eslint/js": "^9.39.2",
21
+ "@types/jest": "^30.0.0",
22
+ "eslint": "^9.39.2",
23
+ "globals": "^17.3.0",
24
+ "jest": "^30.2.0",
25
+ "jiti": "^2.6.1",
26
+ "ts-jest": "^29.4.6",
27
+ "tsc-alias": "^1.8.16",
28
+ "tsx": "^4.21.0",
29
+ "typescript": "^5.9.3",
30
+ "typescript-eslint": "^8.55.0"
31
+ }
32
+ }
package/src/Bot.ts ADDED
@@ -0,0 +1,84 @@
1
+ import { is_office_class_id, OfficeClassID } from "./OfficeClass"
2
+ import { Jurisdiction } from "./Jurisdiction"
3
+ import { is_state_id, StateID } from "./State"
4
+ import { is_party_id, PartyID } from "./Party"
5
+
6
+ export class Bot {
7
+ readonly office_id : string
8
+ readonly number : string
9
+ readonly bot_id : string
10
+ readonly name : string
11
+ readonly active : boolean
12
+ readonly state_id : StateID
13
+ readonly district? : number
14
+ readonly party_id : PartyID
15
+ readonly guidelines : string
16
+ readonly topics : string[]
17
+ readonly jurisdiction_ids : number[]
18
+ readonly office_class_id : OfficeClassID
19
+ readonly office_name? : string
20
+ readonly [x : string] : any
21
+
22
+ constructor(bot : any) {
23
+ if (!Bot.is(bot)) {
24
+ throw Error("Invalid input.")
25
+ }
26
+ this.office_id = bot.office_id
27
+ this.number = bot.number
28
+ this.bot_id = bot.bot_id
29
+ this.name = bot.name
30
+ this.active = bot.active
31
+ this.state_id = bot.state_id
32
+ this.district = bot.district
33
+ this.party_id = bot.party_id
34
+ this.guidelines = bot.guidelines
35
+ this.topics = bot.topics
36
+ this.jurisdiction_ids = bot.jurisdiction_ids
37
+ this.office_class_id = bot.office_class_id
38
+ this.office_name = bot.office_name
39
+ }
40
+
41
+ static is(bot : any) : bot is Bot {
42
+ return (
43
+ bot !== undefined &&
44
+ typeof bot.office_id === "string" &&
45
+ typeof bot.number === "string" &&
46
+ typeof bot.bot_id === "string" &&
47
+ typeof bot.name === "string" &&
48
+ typeof bot.active === "boolean" &&
49
+ is_state_id(bot.state_id) &&
50
+ (bot.district === undefined || typeof bot.district === "number") &&
51
+ is_party_id(bot.party_id) &&
52
+ typeof bot.guidelines === "string" &&
53
+ Array.isArray(bot.topics) &&
54
+ bot.topics.every((topic : any) => typeof topic === "string") &&
55
+ Array.isArray(bot.jurisdiction_ids) &&
56
+ bot.jurisdiction_ids.every((jurisdiction_id : any) => typeof jurisdiction_id === "number") &&
57
+ is_office_class_id(bot.office_class_id) &&
58
+ (bot.office_name === undefined || typeof bot.office_name === "string")
59
+ )
60
+ }
61
+ }
62
+
63
+ export class BotAux extends Bot {
64
+ readonly jurisdictions : Jurisdiction[]
65
+ readonly photo_download_url? : string
66
+
67
+ constructor(bot : any) {
68
+ if (!BotAux.is(bot)) {
69
+ throw Error("Invalid input.")
70
+ }
71
+ super(bot)
72
+ this.jurisdictions = bot.jurisdictions
73
+ this.photo_download_url = bot.photo_download_url
74
+ }
75
+
76
+ static is(bot : any) : bot is BotAux {
77
+ return (
78
+ Bot.is(bot) &&
79
+ Array.isArray(bot.jurisdictions) &&
80
+ bot.jurisdictions.every(Jurisdiction.is) &&
81
+ (bot.photo_download_url === undefined || typeof bot.photo_download_url === "string")
82
+ )
83
+ }
84
+ }
@@ -0,0 +1,43 @@
1
+ import { Tweet } from "./Tweet"
2
+
3
+ export class BotDocument {
4
+ readonly bot_id : string
5
+ readonly document_id : string
6
+ readonly type : "URL" | "TWEET" | "TWITTER"
7
+ readonly s3_filename? : string
8
+ readonly url? : string
9
+ readonly username? : string
10
+ readonly vector_keys? : string[]
11
+ readonly tweet? : Tweet
12
+ readonly text? : string
13
+
14
+ constructor(bot_document : any) {
15
+ if (!BotDocument.is(bot_document)) {
16
+ throw Error("Invalid input.")
17
+ }
18
+ this.bot_id = bot_document.bot_id
19
+ this.document_id = bot_document.document_id
20
+ this.type = bot_document.type
21
+ this.s3_filename = bot_document.s3_filename
22
+ this.url = bot_document.url
23
+ this.username = bot_document.username
24
+ this.vector_keys = bot_document.vector_keys
25
+ this.tweet = bot_document.tweet
26
+ this.text = bot_document.text
27
+ }
28
+
29
+ static is(bot_document : any) : bot_document is BotDocument {
30
+ return (
31
+ bot_document !== undefined &&
32
+ typeof bot_document.bot_id === "string" &&
33
+ typeof bot_document.document_id === "string" &&
34
+ typeof bot_document.type === "string" &&
35
+ (bot_document.s3_filename === undefined || typeof bot_document.s3_filename === "string") &&
36
+ (bot_document.url === undefined || typeof bot_document.url === "string") &&
37
+ (bot_document.username === undefined || typeof bot_document.username === "string") &&
38
+ (bot_document.vector_keys === undefined || Array.isArray(bot_document.vector_keys) && bot_document.vector_keys.every((vector_key : any) => typeof vector_key === "string")) &&
39
+ (bot_document.tweet === undefined || Tweet.is(bot_document.tweet)) &&
40
+ (bot_document.text === undefined || typeof bot_document.text === "string")
41
+ )
42
+ }
43
+ }
@@ -0,0 +1,53 @@
1
+ import { Message } from "./Message"
2
+
3
+ export class Conversation {
4
+ readonly user_id : string
5
+ readonly conversation_id : string
6
+ readonly bot_id : string
7
+ readonly mode : "email" | "general"
8
+ readonly topics? : string[]
9
+ readonly [x : string] : any
10
+
11
+ constructor(conversation : any) {
12
+ if (!Conversation.is(conversation)) {
13
+ throw Error("Invalid input.")
14
+ }
15
+ this.user_id = conversation.user_id
16
+ this.conversation_id = conversation.conversation_id
17
+ this.bot_id = conversation.bot_id
18
+ this.mode = conversation.mode
19
+ this.topics = conversation.topics
20
+ }
21
+
22
+ static is(conversation : any) : conversation is Conversation {
23
+ return (
24
+ conversation !== undefined &&
25
+ typeof conversation.user_id === "string" &&
26
+ typeof conversation.conversation_id === "string" &&
27
+ typeof conversation.bot_id === "string" &&
28
+ ["email", "general"].includes(conversation.mode) &&
29
+ (conversation.topics === undefined || Array.isArray(conversation.topics) &&
30
+ conversation.topics.every((topic : any) => typeof topic === "string"))
31
+ )
32
+ }
33
+ }
34
+
35
+ export class ConversationAux extends Conversation {
36
+ readonly messages : Message[]
37
+
38
+ constructor(conversation : any) {
39
+ if (!ConversationAux.is(conversation)) {
40
+ throw Error("Invalid input.")
41
+ }
42
+ super(conversation)
43
+ this.messages = conversation.messages
44
+ }
45
+
46
+ static is(conversation : any) : conversation is ConversationAux {
47
+ return (
48
+ Conversation.is(conversation) &&
49
+ Array.isArray(conversation.messages) &&
50
+ conversation.messages.every(Message.is)
51
+ )
52
+ }
53
+ }
@@ -0,0 +1,20 @@
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
+ 600 : "Failed to Parse Output"
9
+ }
10
+
11
+
12
+ export class DoersAPIError extends Error {
13
+ status : number
14
+ constructor(status : number, message?: string) {
15
+ const default_message = default_messages_by_status[status]
16
+ super(message !== undefined ? message : default_message !== undefined ? default_message : "Error")
17
+ this.name = "DoersAPIError"
18
+ this.status = status
19
+ }
20
+ }
@@ -0,0 +1,7 @@
1
+ export interface DoersCommsUtilsConfig {
2
+ region : string,
3
+ scraping_bee_api_key? : string,
4
+ xai_api_key? : string,
5
+ citizenportal_api_key? : string,
6
+ [key : string]: any
7
+ }
@@ -0,0 +1,58 @@
1
+ export enum JurisdictionLevel {
2
+ SCHOOL = 0,
3
+ NATION = 1,
4
+ STATE = 2,
5
+ COUNTY = 3,
6
+ CITY = 4
7
+ }
8
+
9
+ export function is_jurisdiction_level(jurisdiction_level : any) : jurisdiction_level is JurisdictionLevel {
10
+ return [0, 1, 2, 3, 4].includes(jurisdiction_level)
11
+ }
12
+
13
+ export class Jurisdiction {
14
+ readonly jurisdiction_id : number
15
+ readonly name : string
16
+ readonly path : number[]
17
+ readonly sub_jurisdiction_ids : number[]
18
+ readonly super_jurisdiction_id? : number
19
+ readonly level : JurisdictionLevel
20
+ readonly state_jurisdiction_id? : number
21
+ readonly county_jurisdiction_id? : number
22
+ readonly city_jurisdiction_id? : number
23
+ readonly geographic : boolean
24
+
25
+ constructor(jurisdiction : any) {
26
+ if (!Jurisdiction.is(jurisdiction)) {
27
+ throw Error("Invalid input.")
28
+ }
29
+ this.jurisdiction_id = jurisdiction.jurisdiction_id
30
+ this.name = jurisdiction.name
31
+ this.path = jurisdiction.path
32
+ this.sub_jurisdiction_ids = jurisdiction.sub_jurisdiction_ids
33
+ this.super_jurisdiction_id = jurisdiction.super_jurisdiction_id
34
+ this.level = jurisdiction.level
35
+ this.state_jurisdiction_id = jurisdiction.state_jurisdiction_id
36
+ this.county_jurisdiction_id = jurisdiction.county_jurisdiction_id
37
+ this.city_jurisdiction_id = jurisdiction.city_jurisdiction_id
38
+ this.geographic = jurisdiction.geographic
39
+ }
40
+
41
+ static is(jurisdiction : any) : jurisdiction is Jurisdiction {
42
+ return (
43
+ jurisdiction !== undefined &&
44
+ typeof jurisdiction.jurisdiction_id === "number" &&
45
+ typeof jurisdiction.name === "string" &&
46
+ Array.isArray(jurisdiction.path) &&
47
+ jurisdiction.path.every((jurisdiction_id : any) => typeof jurisdiction_id === "number") &&
48
+ Array.isArray(jurisdiction.sub_jurisdiction_ids) &&
49
+ jurisdiction.sub_jurisdiction_ids.every((jurisdiction_id : any) => typeof jurisdiction_id === "number") &&
50
+ is_jurisdiction_level(jurisdiction.level) &&
51
+ typeof jurisdiction.geographic === "boolean" &&
52
+ (jurisdiction.super_jurisdiction_id === undefined || typeof jurisdiction.super_jurisdiction_id === "number") &&
53
+ (jurisdiction.state_jurisdiction_id === undefined || typeof jurisdiction.state_jurisdiction_id === "number") &&
54
+ (jurisdiction.county_jurisdiction_id === undefined || typeof jurisdiction.county_jurisdiction_id === "number") &&
55
+ (jurisdiction.city_jurisdiction_id === undefined || typeof jurisdiction.city_jurisdiction_id === "number")
56
+ )
57
+ }
58
+ }
@@ -0,0 +1,48 @@
1
+ export class JurisdictionDocument {
2
+ readonly jurisdiction_id : number
3
+ readonly document_id : string
4
+ readonly media_id : string
5
+ readonly origin : string
6
+ readonly s3_filename? : string
7
+ readonly time? : string
8
+ readonly title : string
9
+ readonly type : string
10
+ readonly url : string
11
+ readonly vector_keys? : string[]
12
+ readonly location? : string
13
+
14
+ constructor(jurisdiction_document : any) {
15
+ if (!JurisdictionDocument.is(jurisdiction_document)) {
16
+ throw Error("Invalid input.")
17
+ }
18
+ this.jurisdiction_id = jurisdiction_document.jurisdiction_id
19
+ this.document_id = jurisdiction_document.document_id
20
+ this.media_id = jurisdiction_document.media_id
21
+ this.origin = jurisdiction_document.origin
22
+ this.s3_filename = jurisdiction_document.s3_filename
23
+ this.time = jurisdiction_document.time
24
+ this.title = jurisdiction_document.title
25
+ this.type = jurisdiction_document.type
26
+ this.url = jurisdiction_document.url
27
+ this.vector_keys = jurisdiction_document.vector_keys
28
+ this.location = jurisdiction_document.location
29
+ }
30
+
31
+ static is(jurisdiction_document : any) : jurisdiction_document is JurisdictionDocument {
32
+ return (
33
+ jurisdiction_document !== undefined &&
34
+ typeof jurisdiction_document.jurisdiction_id === "number" &&
35
+ typeof jurisdiction_document.document_id === "string" &&
36
+ typeof jurisdiction_document.media_id === "string" &&
37
+ typeof jurisdiction_document.origin === "string" &&
38
+ (jurisdiction_document.s3_filename === undefined || typeof jurisdiction_document.s3_filename === "string") &&
39
+ (jurisdiction_document.time === undefined || typeof jurisdiction_document.time === "string") &&
40
+ typeof jurisdiction_document.title === "string" &&
41
+ typeof jurisdiction_document.type === "string" &&
42
+ typeof jurisdiction_document.url === "string" &&
43
+ (jurisdiction_document.vector_keys === undefined || Array.isArray(jurisdiction_document.vector_keys)) &&
44
+ jurisdiction_document.vector_keys.every((vector_key : any) => typeof vector_key === "string") &&
45
+ (jurisdiction_document.location === undefined || typeof jurisdiction_document.location === "string")
46
+ )
47
+ }
48
+ }
package/src/Message.ts ADDED
@@ -0,0 +1,94 @@
1
+ import { Sources } from "./Sources"
2
+
3
+ export class Fragment {
4
+ readonly text : string
5
+ readonly sources : Sources
6
+
7
+ constructor(fragment : any) {
8
+ if (!Fragment.is(fragment)) {
9
+ throw Error("Invalid input.")
10
+ }
11
+ this.text = fragment.text
12
+ this.sources = fragment.sources
13
+ }
14
+
15
+ static is(fragment : any) : fragment is Fragment {
16
+ return (
17
+ fragment !== undefined &&
18
+ typeof fragment.text === "string" &&
19
+ Sources.is(fragment.sources)
20
+ )
21
+ }
22
+ }
23
+
24
+ export class Post {
25
+ text : string
26
+ s3_image_filename? : string
27
+ s3_image_url? : string
28
+
29
+ constructor(post : any) {
30
+ if (!Post.is(post)) {
31
+ throw Error("Invalid input.")
32
+ }
33
+ this.text = post.text
34
+ this.s3_image_filename = post.s3_image_filename
35
+ this.s3_image_url = post.s3_image_url
36
+ }
37
+
38
+ static is(post : any) : post is Post {
39
+ return (
40
+ post !== undefined &&
41
+ typeof post.text === "string" &&
42
+ (post.s3_image_filename === undefined || typeof post.s3_image_filename === "string") &&
43
+ (post.s3_image_url === undefined || typeof post.s3_image_url === "string")
44
+ )
45
+ }
46
+ }
47
+
48
+ export class Message {
49
+ readonly user_id : string
50
+ readonly message_id : string
51
+ readonly conversation_id : string
52
+ readonly mode : "email" | "general"
53
+ readonly role : "user" | "bot"
54
+ readonly system_prompt? : string
55
+ readonly grok_text? : string
56
+ readonly fragments? : Fragment[]
57
+ readonly sources? : Sources
58
+ readonly text : string
59
+ readonly posts? : Post[]
60
+
61
+ constructor(message : any) {
62
+ if (!Message.is(message)) {
63
+ throw Error("Invalid input.")
64
+ }
65
+ this.user_id = message.user_id
66
+ this.message_id = message.message_id
67
+ this.conversation_id = message.conversation_id
68
+ this.mode = message.mode
69
+ this.role = message.role
70
+ this.system_prompt = message.system_prompt
71
+ this.grok_text = message.grok_text
72
+ this.fragments = message.fragments
73
+ this.sources = message.sources
74
+ this.text = message.text
75
+ this.posts = message.posts
76
+ }
77
+
78
+ static is(message : any) : message is Message {
79
+ return (
80
+ message !== undefined &&
81
+ typeof message.user_id === "string" &&
82
+ typeof message.message_id === "string" &&
83
+ typeof message.conversation_id === "string" &&
84
+ ["email", "general"].includes(message.mode) &&
85
+ ["user", "bot"].includes(message.role) &&
86
+ (message.system_prompt === undefined || typeof message.system_prompt === "string") &&
87
+ (message.grok_text === undefined || typeof message.grok_text === "string") &&
88
+ (message.fragments === undefined || Array.isArray(message.fragments) && message.fragments.every(Fragment.is)) &&
89
+ (message.sources === undefined || Sources.is(message.sources)) &&
90
+ typeof message.text === "string" &&
91
+ (message.posts === undefined || Array.isArray(message.posts) && message.posts.every(Post.is))
92
+ )
93
+ }
94
+ }
@@ -0,0 +1,149 @@
1
+ import { JurisdictionLevel } from "./Jurisdiction"
2
+
3
+ const office_class_ids = ["ORG", "USH", "USS", "STG", "STH", "STS", "STB", "COG", "CIG", "LOB"] as const
4
+
5
+ export type OfficeClassID = typeof office_class_ids[number]
6
+
7
+ export function is_office_class_id(office_class_id : any) : office_class_id is OfficeClassID {
8
+ return office_class_ids.includes(office_class_id)
9
+ }
10
+
11
+ export interface OfficeClass {
12
+ office_class_id : OfficeClassID,
13
+ name : string,
14
+ type : "candidate" | "organization",
15
+ office_id_template : string,
16
+ jurisdiction_level? : JurisdictionLevel,
17
+ jurisdictions_mutable : Boolean,
18
+ require_district : Boolean,
19
+ require_initial_jurisdiction : Boolean,
20
+ office_names? : string[]
21
+
22
+ }
23
+
24
+ export const office_classes_by_office_class_id : Record<OfficeClassID, OfficeClass> = {
25
+ "ORG" : {
26
+ office_class_id : "ORG",
27
+ name : "Organization",
28
+ type : "organization",
29
+ office_id_template : "O-[state_id]",
30
+ jurisdictions_mutable : true,
31
+ require_district : false,
32
+ require_initial_jurisdiction : false
33
+ },
34
+ "USH" : {
35
+ office_class_id : "USH",
36
+ name : "U.S. House",
37
+ type : "candidate",
38
+ office_id_template : "H-[state_id]",
39
+ jurisdictions_mutable : true,
40
+ require_district : true,
41
+ require_initial_jurisdiction : false
42
+ },
43
+ "USS" : {
44
+ office_class_id : "USS",
45
+ name : "U.S. Senate",
46
+ type : "candidate",
47
+ office_id_template : "S-[state_id]",
48
+ jurisdiction_level : JurisdictionLevel.STATE,
49
+ jurisdictions_mutable : false,
50
+ require_district : false,
51
+ require_initial_jurisdiction : false
52
+ },
53
+ "STG" : {
54
+ office_class_id : "STG",
55
+ name : "State (Executive) Government",
56
+ type : "candidate",
57
+ office_id_template : "[state_id]-G",
58
+ jurisdiction_level : JurisdictionLevel.STATE,
59
+ jurisdictions_mutable : false,
60
+ require_district : false,
61
+ require_initial_jurisdiction : false,
62
+ office_names : [
63
+ "Governor",
64
+ "Lieutenant Governor",
65
+ "Secretary of State",
66
+ "Treasurer",
67
+ "Auditor",
68
+ "Attorney General"
69
+ ]
70
+ },
71
+ "STH" : {
72
+ office_class_id : "STH",
73
+ name : "State House",
74
+ type : "candidate",
75
+ office_id_template : "[state_id]-H",
76
+ jurisdictions_mutable : true,
77
+ require_district : true,
78
+ require_initial_jurisdiction : false
79
+ },
80
+ "STS" : {
81
+ office_class_id : "STS",
82
+ name : "State Senate",
83
+ type : "candidate",
84
+ office_id_template : "[state_id]-S",
85
+ jurisdictions_mutable : true,
86
+ require_district : true,
87
+ require_initial_jurisdiction : false
88
+ },
89
+ "STB" : {
90
+ office_class_id : "STB",
91
+ name : "State School Board",
92
+ type : "candidate",
93
+ office_id_template : "[state_id]-B",
94
+ jurisdictions_mutable : true,
95
+ require_district : true,
96
+ require_initial_jurisdiction : false,
97
+ office_names : [
98
+ "Board Member"
99
+ ]
100
+ },
101
+ "COG" : {
102
+ office_class_id : "COG",
103
+ name : "County Government",
104
+ type : "candidate",
105
+ office_id_template : "[state_id]-C",
106
+ jurisdiction_level : JurisdictionLevel.COUNTY,
107
+ jurisdictions_mutable : true,
108
+ require_district : false,
109
+ require_initial_jurisdiction : true,
110
+ office_names : [
111
+ "Mayor",
112
+ "Councillor",
113
+ "Commissioner",
114
+ "Clerk",
115
+ "Recorder",
116
+ "Auditor",
117
+ "Surveyor",
118
+ "Recorder",
119
+ "District Attorney",
120
+ "Sheriff"
121
+ ]
122
+ },
123
+ "CIG" : {
124
+ office_class_id : "CIG",
125
+ name : "City Government",
126
+ type : "candidate",
127
+ office_id_template : "[state_id]-M",
128
+ jurisdiction_level : JurisdictionLevel.CITY,
129
+ jurisdictions_mutable : true,
130
+ require_district : false,
131
+ require_initial_jurisdiction : true,
132
+ office_names : [
133
+ "Mayor",
134
+ "Councillor"
135
+ ]
136
+ },
137
+ "LOB" : {
138
+ office_class_id : "LOB",
139
+ name : "Local School Board",
140
+ type : "candidate",
141
+ office_id_template : "[state_id]-E",
142
+ jurisdictions_mutable : true,
143
+ require_district : false,
144
+ require_initial_jurisdiction : false,
145
+ office_names : [
146
+ "Board Member"
147
+ ]
148
+ }
149
+ }
package/src/Party.ts ADDED
@@ -0,0 +1,36 @@
1
+ const party_ids = ["DEM", "REP", "NON", "ETC"] as const
2
+
3
+ export type PartyID = typeof party_ids[number]
4
+
5
+ export function is_party_id(party_id : any) : party_id is PartyID {
6
+ return party_ids.includes(party_id)
7
+ }
8
+
9
+ export interface Party {
10
+ party_id : PartyID,
11
+ name : string,
12
+ adjective : string
13
+ }
14
+
15
+ export const parties_by_party_id : Record<PartyID, Party> = {
16
+ DEM : {
17
+ party_id : "DEM",
18
+ name : "Democratic Party",
19
+ adjective : "Democratic"
20
+ },
21
+ REP : {
22
+ party_id : "REP",
23
+ name : "Republican Party",
24
+ adjective : "Republican"
25
+ },
26
+ ETC : {
27
+ party_id : "ETC",
28
+ name : "Other Party",
29
+ adjective : "Third-Party"
30
+ },
31
+ NON : {
32
+ party_id : "NON",
33
+ name : "Nonpartisan",
34
+ adjective : "Nonpartisan"
35
+ }
36
+ }
package/src/Sources.ts ADDED
@@ -0,0 +1,125 @@
1
+ import { BotDocument } from "./BotDocument"
2
+ import { JurisdictionDocument } from "./JurisdictionDocument"
3
+
4
+ export class BotDocumentSource {
5
+ readonly chunk_text : string
6
+ readonly description : string
7
+ readonly label : string
8
+ readonly type : string
9
+ readonly vector_key : string
10
+ readonly document : BotDocument
11
+
12
+ constructor(bot_document_source : any) {
13
+ if (!BotDocumentSource.is(bot_document_source)) {
14
+ throw Error("Invalid input.")
15
+ }
16
+ this.chunk_text = bot_document_source.chunk_text
17
+ this.description = bot_document_source.description
18
+ this.label = bot_document_source.label
19
+ this.type = bot_document_source.type
20
+ this.vector_key = bot_document_source.vector_key
21
+ this.document = bot_document_source.document
22
+ }
23
+
24
+ static is(bot_document_source : any) : bot_document_source is BotDocumentSource {
25
+ return (
26
+ bot_document_source !== undefined &&
27
+ typeof bot_document_source.chunk_text === "string" &&
28
+ typeof bot_document_source.description === "string" &&
29
+ typeof bot_document_source.label === "string" &&
30
+ typeof bot_document_source.type === "string" &&
31
+ typeof bot_document_source.vector_key === "string" &&
32
+ BotDocument.is(bot_document_source.document)
33
+ )
34
+ }
35
+ }
36
+
37
+ export class JurisdictionDocumentSource {
38
+ readonly chunk_text : string
39
+ readonly description : string
40
+ readonly label : string
41
+ readonly type : string
42
+ readonly vector_key : string
43
+ readonly document : JurisdictionDocument
44
+
45
+ constructor(jurisdiction_document_source : any) {
46
+ if (!JurisdictionDocumentSource.is(jurisdiction_document_source)) {
47
+ throw Error("Invalid input.")
48
+ }
49
+ this.chunk_text = jurisdiction_document_source.chunk_text
50
+ this.description = jurisdiction_document_source.description
51
+ this.label = jurisdiction_document_source.label
52
+ this.type = jurisdiction_document_source.type
53
+ this.vector_key = jurisdiction_document_source.vector_key
54
+ this.document = jurisdiction_document_source.document
55
+ }
56
+
57
+ static is(jurisdiction_document_source : any) : jurisdiction_document_source is JurisdictionDocumentSource {
58
+ return (
59
+ jurisdiction_document_source !== undefined &&
60
+ typeof jurisdiction_document_source.chunk_text === "string" &&
61
+ typeof jurisdiction_document_source.description === "string" &&
62
+ typeof jurisdiction_document_source.label === "string" &&
63
+ typeof jurisdiction_document_source.type === "string" &&
64
+ typeof jurisdiction_document_source.vector_key === "string" &&
65
+ JurisdictionDocument.is(jurisdiction_document_source.document)
66
+ )
67
+ }
68
+ }
69
+
70
+ export class GrokSource {
71
+ readonly title : string
72
+ readonly url : string
73
+ readonly start_index : number
74
+ readonly end_index : number
75
+ readonly type : string
76
+
77
+ constructor(grok_source : any) {
78
+ if (!GrokSource.is(grok_source)) {
79
+ throw Error("Invalid input.")
80
+ }
81
+ this.title = grok_source.title
82
+ this.url = grok_source.url
83
+ this.start_index = grok_source.start_index
84
+ this.end_index = grok_source.end_index
85
+ this.type = grok_source.type
86
+ }
87
+
88
+ static is(grok_source : any) : grok_source is GrokSource {
89
+ return (
90
+ grok_source !== undefined &&
91
+ typeof grok_source.title === "string" &&
92
+ typeof grok_source.url === "string" &&
93
+ typeof grok_source.start_index === "number" &&
94
+ typeof grok_source.end_index === "number" &&
95
+ typeof grok_source.type === "string"
96
+ )
97
+ }
98
+ }
99
+
100
+ export class Sources {
101
+ readonly B : BotDocumentSource[]
102
+ readonly J : JurisdictionDocumentSource[]
103
+ readonly G : GrokSource[]
104
+
105
+ constructor(sources : any) {
106
+ if (!Sources.is(sources)) {
107
+ throw Error("Invalid input.")
108
+ }
109
+ this.B = sources.B
110
+ this.J = sources.J
111
+ this.G = sources.G
112
+ }
113
+
114
+ static is(sources : any) : sources is Sources {
115
+ return (
116
+ sources !== undefined &&
117
+ Array.isArray(sources.B) &&
118
+ sources.B.every(BotDocumentSource.is) &&
119
+ Array.isArray(sources.J) &&
120
+ sources.J.every(JurisdictionDocumentSource.is) &&
121
+ Array.isArray(sources.G) &&
122
+ sources.G.every(GrokSource.is)
123
+ )
124
+ }
125
+ }
package/src/State.ts ADDED
@@ -0,0 +1,266 @@
1
+ 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
+ jurisdiction_id : number
13
+ }
14
+
15
+ export const states_by_state_id : Record<StateID, State> = {
16
+ AL : {
17
+ state_id : "AL",
18
+ name : "Alabama",
19
+ jurisdiction_id : 2280
20
+ },
21
+ AK : {
22
+ state_id : "AK",
23
+ name : "Alaska",
24
+ jurisdiction_id : 2281
25
+ },
26
+ AZ : {
27
+ state_id : "AZ",
28
+ name : "Arizona",
29
+ jurisdiction_id : 2148
30
+ },
31
+ AR : {
32
+ state_id : "AR",
33
+ name : "Arkansas",
34
+ jurisdiction_id : 2282
35
+ },
36
+ CA : {
37
+ state_id : "CA",
38
+ name : "California",
39
+ jurisdiction_id : 2283
40
+ },
41
+ CO : {
42
+ state_id : "CO",
43
+ name : "Colorado",
44
+ jurisdiction_id : 2284
45
+ },
46
+ CT : {
47
+ state_id : "CT",
48
+ name : "Connecticut",
49
+ jurisdiction_id : 2314
50
+ },
51
+ DE : {
52
+ state_id : "DE",
53
+ name : "Delaware",
54
+ jurisdiction_id : 2315
55
+ },
56
+ FL : {
57
+ state_id : "FL",
58
+ name : "Florida",
59
+ jurisdiction_id : 2316
60
+ },
61
+ GA : {
62
+ state_id : "GA",
63
+ name : "Georgia",
64
+ jurisdiction_id : 2317
65
+ },
66
+ HI : {
67
+ state_id : "HI",
68
+ name : "Hawaii",
69
+ jurisdiction_id : 2156
70
+ },
71
+ ID : {
72
+ state_id : "ID",
73
+ name : "Idaho",
74
+ jurisdiction_id : 2318
75
+ },
76
+ IL : {
77
+ state_id : "IL",
78
+ name : "Illinois",
79
+ jurisdiction_id : 2319
80
+ },
81
+ IN : {
82
+ state_id : "IN",
83
+ name : "Indiana",
84
+ jurisdiction_id : 2159
85
+ },
86
+ IA : {
87
+ state_id : "IA",
88
+ name : "Iowa",
89
+ jurisdiction_id : 2320
90
+ },
91
+ KS : {
92
+ state_id : "KS",
93
+ name : "Kansas",
94
+ jurisdiction_id : 2161
95
+ },
96
+ KY : {
97
+ state_id : "KY",
98
+ name : "Kentucky",
99
+ jurisdiction_id : 2162
100
+ },
101
+ LA : {
102
+ state_id : "LA",
103
+ name : "Louisiana",
104
+ jurisdiction_id : 2163
105
+ },
106
+ ME : {
107
+ state_id : "ME",
108
+ name : "Maine",
109
+ jurisdiction_id : 2164
110
+ },
111
+ MD : {
112
+ state_id : "MD",
113
+ name : "Maryland",
114
+ jurisdiction_id : 2165
115
+ },
116
+ MA : {
117
+ state_id : "MA",
118
+ name : "Massachusetts",
119
+ jurisdiction_id : 2166
120
+ },
121
+ MI : {
122
+ state_id : "MI",
123
+ name : "Michigan",
124
+ jurisdiction_id : 2167
125
+ },
126
+ MN : {
127
+ state_id : "MN",
128
+ name : "Minnesota",
129
+ jurisdiction_id : 2286
130
+ },
131
+ MS : {
132
+ state_id : "MS",
133
+ name : "Mississippi",
134
+ jurisdiction_id : 2287
135
+ },
136
+ MO : {
137
+ state_id : "MO",
138
+ name : "Missouri",
139
+ jurisdiction_id : 2288
140
+ },
141
+ MT : {
142
+ state_id : "MT",
143
+ name : "Montana",
144
+ jurisdiction_id : 2289
145
+ },
146
+ NE : {
147
+ state_id : "NE",
148
+ name : "Nebraska",
149
+ jurisdiction_id : 2290
150
+ },
151
+ NV : {
152
+ state_id : "NV",
153
+ name : "Nevada",
154
+ jurisdiction_id : 2291
155
+ },
156
+ NH : {
157
+ state_id : "NH",
158
+ name : "New Hampshire",
159
+ jurisdiction_id : 2292
160
+ },
161
+ NJ : {
162
+ state_id : "NJ",
163
+ name : "New Jersey",
164
+ jurisdiction_id : 2293
165
+ },
166
+ NM : {
167
+ state_id : "NM",
168
+ name : "New Mexico",
169
+ jurisdiction_id : 2294
170
+ },
171
+ NY : {
172
+ state_id : "NY",
173
+ name : "New York",
174
+ jurisdiction_id : 2295
175
+ },
176
+ NC : {
177
+ state_id : "NC",
178
+ name : "North Carolina",
179
+ jurisdiction_id : 2296
180
+ },
181
+ ND : {
182
+ state_id : "ND",
183
+ name : "North Dakota",
184
+ jurisdiction_id : 2297
185
+ },
186
+ OH : {
187
+ state_id : "OH",
188
+ name : "Ohio",
189
+ jurisdiction_id : 2298
190
+ },
191
+ OK : {
192
+ state_id : "OK",
193
+ name : "Oklahoma",
194
+ jurisdiction_id : 2299
195
+ },
196
+ OR : {
197
+ state_id : "OR",
198
+ name : "Oregon",
199
+ jurisdiction_id : 2300
200
+ },
201
+ PA : {
202
+ state_id : "PA",
203
+ name : "Pennsylvania",
204
+ jurisdiction_id : 2301
205
+ },
206
+ RI : {
207
+ state_id : "RI",
208
+ name : "Rhode Island",
209
+ jurisdiction_id : 2302
210
+ },
211
+ SC : {
212
+ state_id : "SC",
213
+ name : "South Carolina",
214
+ jurisdiction_id : 2303
215
+ },
216
+ SD : {
217
+ state_id : "SD",
218
+ name : "South Dakota",
219
+ jurisdiction_id : 2304
220
+ },
221
+ TN : {
222
+ state_id : "TN",
223
+ name : "Tennessee",
224
+ jurisdiction_id : 2305
225
+ },
226
+ TX : {
227
+ state_id : "TX",
228
+ name : "Texas",
229
+ jurisdiction_id : 2306
230
+ },
231
+ UT : {
232
+ state_id : "UT",
233
+ name : "Utah",
234
+ jurisdiction_id : 2307
235
+ },
236
+ VT : {
237
+ state_id : "VT",
238
+ name : "Vermont",
239
+ jurisdiction_id : 2308
240
+ },
241
+ VA : {
242
+ state_id : "VA",
243
+ name : "Virginia",
244
+ jurisdiction_id : 2309
245
+ },
246
+ WA : {
247
+ state_id : "WA",
248
+ name : "Washington",
249
+ jurisdiction_id : 2310
250
+ },
251
+ WV : {
252
+ state_id : "WV",
253
+ name : "West Virginia",
254
+ jurisdiction_id : 2311
255
+ },
256
+ WI : {
257
+ state_id : "WI",
258
+ name : "Wisconsin",
259
+ jurisdiction_id : 2312
260
+ },
261
+ WY : {
262
+ state_id : "WY",
263
+ name : "Wyoming",
264
+ jurisdiction_id : 2313
265
+ }
266
+ }
package/src/Tweet.ts ADDED
@@ -0,0 +1,36 @@
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 replying_to : string[]
8
+ readonly quote? : string
9
+
10
+ constructor(tweet : any) {
11
+ if (!Tweet.is(tweet)) {
12
+ throw Error("Invalid input.")
13
+ }
14
+ this.tweet_id = tweet.tweet_id
15
+ this.username = tweet.username
16
+ this.url = tweet.url
17
+ this.tweet_time = tweet.tweet_time
18
+ this.tweet_content = tweet.tweet_content
19
+ this.replying_to = tweet.replying_to
20
+ this.quote = tweet.quote
21
+ }
22
+
23
+ static is(tweet : any) : tweet is Tweet {
24
+ return (
25
+ tweet !== undefined &&
26
+ typeof tweet.tweet_id === "string" &&
27
+ typeof tweet.username === "string" &&
28
+ typeof tweet.url === "string" &&
29
+ typeof tweet.tweet_time === "string" &&
30
+ typeof tweet.tweet_content === "string" &&
31
+ Array.isArray(tweet.replying_to) &&
32
+ tweet.replying_to.every((username : any) => typeof username === "string") &&
33
+ (tweet.quote === undefined || typeof tweet.quote === "string")
34
+ )
35
+ }
36
+ }
package/src/User.ts ADDED
@@ -0,0 +1,50 @@
1
+ import { BotAux } from "./Bot"
2
+
3
+ export class User {
4
+ readonly user_id : string
5
+ readonly admin : boolean
6
+ readonly bot_ids : string[]
7
+ readonly email : string
8
+ readonly [x : string] : any
9
+
10
+ constructor(user : any) {
11
+ if (!User.is(user)) {
12
+ throw Error("Invalid Input.")
13
+ }
14
+ this.user_id = user.user_id
15
+ this.admin = user.admin
16
+ this.bot_ids = user.bot_ids
17
+ this.email = user.email
18
+ }
19
+
20
+ static is(user : any) : user is User {
21
+ return (
22
+ user !== undefined &&
23
+ typeof user.user_id === "string" &&
24
+ typeof user.admin === "boolean" &&
25
+ typeof user.email === "string" &&
26
+ Array.isArray(user.bot_ids) &&
27
+ user.bot_ids.every((bot_id : any) => typeof bot_id === "string")
28
+ )
29
+ }
30
+ }
31
+
32
+ export class UserAux extends User {
33
+ readonly bots : BotAux[]
34
+
35
+ constructor(user : any) {
36
+ if (!UserAux.is(user)) {
37
+ throw Error("Invalid Input.")
38
+ }
39
+ super(user)
40
+ this.bots = user.bots
41
+ }
42
+
43
+ static is(user : any) : user is UserAux {
44
+ return (
45
+ User.is(user) &&
46
+ Array.isArray(user.bots) &&
47
+ user.bots.every(BotAux.is)
48
+ )
49
+ }
50
+ }
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ export * from "./Bot"
2
+ export * from "./BotDocument"
3
+ export * from "./Conversation"
4
+ export * from "./DoersAPIError"
5
+ export * from "./DoersCommsUtilsConfig"
6
+ export * from "./Jurisdiction"
7
+ export * from "./JurisdictionDocument"
8
+ export * from "./Message"
9
+ export * from "./OfficeClass"
10
+ export * from "./Party"
11
+ export * from "./Sources"
12
+ export * from "./State"
13
+ export * from "./User"
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": "node",
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
+ }