one-shared 0.0.0-stage → 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.
package/package.json CHANGED
@@ -1,6 +1,35 @@
1
1
  {
2
2
  "name": "one-shared",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "homepage": "https://github.com/eightseventeen/one-shared#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/eightseventeen/one-shared/issues"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/eightseventeen/one-shared.git"
12
+ },
13
+ "license": "ISC",
14
+ "author": "",
15
+ "type": "commonjs",
16
+ "scripts": {
17
+ "build": "tsdown",
18
+ "test": "echo \"Error: no test specified\" && exit 1"
19
+ },
20
+ "devDependencies": {
21
+ "@neondatabase/serverless": "^1.2.0",
22
+ "drizzle-orm": "^1.0.0-rc.4",
23
+ "tsdown": "^0.23.0",
24
+ "typescript": "^7.0.2",
25
+ "zod": "^4.6.5"
26
+ },
27
+ "peerDependencies": {
28
+ "drizzle-orm": "^1.0.0-rc.4",
29
+ "@neondatabase/serverless": "^1.2.0",
30
+ "zod": "^4.6.5"
31
+ },
32
+ "main": "dist/index.js",
33
+ "module": "dist/index.mjs",
34
+ "types": "dist/index.d.ts"
35
+ }
package/schema.ts ADDED
@@ -0,0 +1,211 @@
1
+ import { defineRelations, type Json } from "drizzle-orm";
2
+ import {
3
+ pgEnum,
4
+ pgTable,
5
+ uuid,
6
+ text,
7
+ timestamp,
8
+ jsonb,
9
+ index,
10
+ integer,
11
+ boolean,
12
+ varchar,
13
+ } from "drizzle-orm/pg-core";
14
+
15
+ export const statusSignalEnum = pgEnum("status_signal", [
16
+ "recovery",
17
+ "failure",
18
+ ]);
19
+
20
+ export const teamsTable = pgTable("teams", {
21
+ id: uuid().primaryKey().defaultRandom(),
22
+ slackTeamId: text().notNull(),
23
+ installerId: text().notNull(),
24
+ installerToken: text(),
25
+ scopes: text().array(),
26
+ teamName: text(),
27
+ botToken: text().notNull(),
28
+ botScopes: text().array().notNull(),
29
+ botUserId: text().notNull(),
30
+ botId: text().notNull(),
31
+ });
32
+
33
+ export const eventsTable = pgTable(
34
+ "events",
35
+ {
36
+ id: uuid().primaryKey().defaultRandom(),
37
+ channelId: uuid()
38
+ .notNull()
39
+ .references(() => channelsTable.id),
40
+ slackAuthorId: text().notNull(),
41
+ slackChannelId: text().notNull(),
42
+ slackTeamId: text().notNull(),
43
+ ts: timestamp().notNull().defaultNow(),
44
+ textRaw: text(),
45
+ textNorm: text(),
46
+ payload: jsonb("payload").$type<Json>().notNull(),
47
+ mlClassification: integer().notNull(),
48
+ permalink: text().notNull(),
49
+ },
50
+ (t) => [
51
+ index("events_stream_ts_idx").on(t.channelId, t.ts),
52
+ index("events_stream_ts_event_idx").on(
53
+ t.channelId,
54
+ t.ts,
55
+ t.id,
56
+ ),
57
+ index("events_stream_idx").on(t.channelId),
58
+ ],
59
+ );
60
+
61
+ export const channelsTable = pgTable("channels", {
62
+ id: uuid().primaryKey().defaultRandom(),
63
+ slackChannelId: text().notNull(),
64
+ slackName: text().notNull(),
65
+ });
66
+
67
+ export const prewatchResultsTable = pgTable("prewatchResults", {
68
+ id: uuid().primaryKey().defaultRandom(),
69
+ triggerEventId: uuid()
70
+ .notNull()
71
+ .references(() => eventsTable.id),
72
+ channelId: uuid()
73
+ .notNull()
74
+ .references(() => channelsTable.id),
75
+ suspicious: boolean().notNull(),
76
+ reasoning: text().notNull(),
77
+ title: text(),
78
+ incidentId: uuid().references(() => incidentsTable.id),
79
+ });
80
+
81
+ export const prewatchPromptEventsTable = pgTable("prewatchPromptEvents", {
82
+ id: uuid().primaryKey().defaultRandom(),
83
+ prewatchResultId: uuid()
84
+ .notNull()
85
+ .references(() => prewatchResultsTable.id),
86
+ eventId: uuid()
87
+ .notNull()
88
+ .references(() => eventsTable.id),
89
+ });
90
+
91
+ export const prewatchEvidenceEventsTable = pgTable("prewatchEvidenceIds", {
92
+ id: uuid().primaryKey().defaultRandom(),
93
+ prewatchResultId: uuid()
94
+ .notNull()
95
+ .references(() => prewatchResultsTable.id),
96
+ eventId: uuid()
97
+ .notNull()
98
+ .references(() => eventsTable.id),
99
+ });
100
+
101
+ export const watchResultsTable = pgTable("watchResults", {
102
+ id: uuid().primaryKey().defaultRandom(),
103
+ incidentId: uuid()
104
+ .notNull()
105
+ .references(() => incidentsTable.id),
106
+ triggerEventId: uuid()
107
+ .notNull()
108
+ .references(() => eventsTable.id),
109
+ channelId: uuid()
110
+ .notNull()
111
+ .references(() => channelsTable.id),
112
+ statusSignal: statusSignalEnum(),
113
+ important: boolean().notNull(),
114
+ description: text(),
115
+ summary: text(),
116
+ });
117
+
118
+ export const incidentsTable = pgTable("incidents", {
119
+ id: uuid().primaryKey().defaultRandom(),
120
+ channelId: uuid()
121
+ .notNull()
122
+ .references(() => channelsTable.id),
123
+ ts: timestamp().notNull().defaultNow(),
124
+ });
125
+
126
+ export const incidentCommentsTable = pgTable("incidentComments", {
127
+ id: uuid().primaryKey().defaultRandom(),
128
+ incidentId: uuid().notNull().references(() => incidentsTable.id),
129
+ content: varchar({ length: 10000 }).notNull(),
130
+ ts: timestamp().notNull().defaultNow()
131
+ })
132
+
133
+ export const incidentEventsTable = pgTable("incidentEvents", {
134
+ id: uuid().primaryKey().defaultRandom(),
135
+ eventId: uuid()
136
+ .notNull()
137
+ .references(() => eventsTable.id),
138
+ incidentId: uuid()
139
+ .notNull()
140
+ .references(() => incidentsTable.id),
141
+ });
142
+
143
+ export const tables = {
144
+ teams: teamsTable,
145
+ events: eventsTable,
146
+ channels: channelsTable,
147
+ prewatchResults: prewatchResultsTable,
148
+ prewatchPromptEvents: prewatchPromptEventsTable,
149
+ prewatchEvidenceEvents: prewatchEvidenceEventsTable,
150
+ watchResults: watchResultsTable,
151
+ incidents: incidentsTable,
152
+ incidentEvents: incidentEventsTable,
153
+ incidentComments: incidentCommentsTable
154
+ };
155
+
156
+ /*
157
+ const comment = db.query.incidentComments.findFirst({
158
+ with: {
159
+ incident: true
160
+ }
161
+ })
162
+
163
+ console.log('The comment was made on this incident:', comment.incident) // GOOD
164
+ console.log('The comment was made on this incident:', comment.incidents) // BAD
165
+ */
166
+
167
+ export const relations = defineRelations(tables, (props) => {
168
+ return {
169
+ incidents: {
170
+ incidentEvents: props.many.incidentEvents(),
171
+ incidentComments: props.many.incidentComments(),
172
+ channel: props.one.channels({
173
+ from: props.incidents.channelId,
174
+ to: props.channels.id,
175
+ optional: false,
176
+ }),
177
+ },
178
+ incidentComments: {
179
+ incident: props.one.incidents({
180
+ from: props.incidentComments.incidentId,
181
+ to: props.incidents.id,
182
+ optional: false
183
+ })
184
+ },
185
+ incidentEvents: {
186
+ incident: props.one.incidents({
187
+ from: props.incidentEvents.incidentId,
188
+ to: props.incidents.id,
189
+ optional: false,
190
+ }),
191
+ event: props.one.events({
192
+ from: props.incidentEvents.eventId,
193
+ to: props.events.id,
194
+ optional: false,
195
+ }),
196
+ },
197
+ events: {
198
+ prewatchResult: props.one.prewatchResults({
199
+ from: props.events.id,
200
+ to: props.prewatchResults.triggerEventId,
201
+ optional: true,
202
+ }),
203
+ watchResult: props.one.watchResults({
204
+ from: props.events.id,
205
+ to: props.watchResults.triggerEventId,
206
+ optional: true,
207
+ }),
208
+ },
209
+ };
210
+ });
211
+
package/tsconfig.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "strict": true,
7
+ "skipLibCheck": true,
8
+ "noEmit": true
9
+ },
10
+ "include": ["*.ts"],
11
+ "exclude": ["dist", "node_modules"]
12
+ }
@@ -0,0 +1,17 @@
1
+ ///
2
+
3
+ import { defineConfig } from 'tsdown'
4
+
5
+ export default defineConfig({
6
+ entry: ['index.ts'],
7
+ format: ['cjs', 'esm'], // Build for commonJS and ESmodules
8
+ dts: true, // Generate declaration file (.d.ts)
9
+ target: 'node16',
10
+ sourcemap: true,
11
+ clean: true,
12
+ deps: { neverBundle: true },
13
+ outExtensions: ({ format }) => ({
14
+ js: format === 'cjs' ? '.js' : '.mjs',
15
+ dts: format === 'cjs' ? '.d.ts' : '.d.mts',
16
+ }),
17
+ })
package/types.ts ADDED
@@ -0,0 +1,229 @@
1
+ import db from "./db";
2
+ import { z } from "zod";
3
+ import {
4
+ channelsTable,
5
+ eventsTable,
6
+ prewatchEvidenceEventsTable,
7
+ prewatchPromptEventsTable,
8
+ prewatchResultsTable,
9
+ teamsTable,
10
+ incidentEventsTable,
11
+ incidentsTable,
12
+ watchResultsTable,
13
+ statusSignalEnum,
14
+ incidentCommentsTable,
15
+ } from "./schema";
16
+
17
+ export type Db = typeof db;
18
+
19
+ import { createSchemaFactory } from "drizzle-orm/zod";
20
+
21
+ const { createSelectSchema, createInsertSchema } = createSchemaFactory({
22
+ coerce: {
23
+ date: true,
24
+ },
25
+ });
26
+
27
+ // Enums
28
+ export const statusSignalSchema = createSelectSchema(statusSignalEnum);
29
+ export type StatusSignal = z.infer<typeof statusSignalSchema>;
30
+
31
+ // Tables
32
+ export const eventSchema = createSelectSchema(eventsTable);
33
+ export type Event = z.infer<typeof eventSchema>;
34
+
35
+ export const eventInsertSchema = createInsertSchema(eventsTable);
36
+ export type EventInsert = z.infer<typeof eventInsertSchema>;
37
+
38
+ export const channelSchema = createSelectSchema(channelsTable);
39
+ export type Channel = z.infer<typeof channelSchema>;
40
+
41
+ export const teamSchema = createSelectSchema(teamsTable);
42
+ export type Team = z.infer<typeof teamSchema>;
43
+
44
+ export const teamInsertSchema = createInsertSchema(teamsTable);
45
+ export type TeamInsert = z.infer<typeof teamInsertSchema>;
46
+
47
+ export const prewatchResultSchema = createSelectSchema(prewatchResultsTable);
48
+ export type PrewatchResult = z.infer<typeof prewatchResultSchema>;
49
+ export const prewatchResultInsertSchema =
50
+ createInsertSchema(prewatchResultsTable);
51
+ export type PrewatchResultInsert = z.infer<typeof prewatchResultInsertSchema>;
52
+
53
+ export const prewatchPromptEventSchema = createSelectSchema(
54
+ prewatchPromptEventsTable,
55
+ );
56
+ export type PrewatchPromptEvent = z.infer<typeof prewatchPromptEventSchema>;
57
+ export const prewatchPromptEventInsertSchema = createInsertSchema(
58
+ prewatchPromptEventsTable,
59
+ );
60
+ export type PrewatchPromptEventInsert = z.infer<
61
+ typeof prewatchPromptEventInsertSchema
62
+ >;
63
+
64
+ export const watchResultSchema = createSelectSchema(watchResultsTable);
65
+ export type WatchResult = z.infer<typeof watchResultSchema>;
66
+ export const watchResultInsertSchema = createInsertSchema(watchResultsTable);
67
+ export type WatchResultInsert = z.infer<typeof watchResultInsertSchema>;
68
+
69
+ export const incidentSchema = createSelectSchema(incidentsTable);
70
+ export type Incident = z.infer<typeof incidentSchema>;
71
+ export const incidentInsertSchema = createInsertSchema(incidentsTable);
72
+ export type IncidentInsert = z.infer<typeof incidentInsertSchema>;
73
+
74
+ export const incidentCommentsSchema = createSelectSchema(incidentCommentsTable);
75
+ export type IncidentComments = z.infer<typeof incidentCommentsSchema>;
76
+ export const incidentCommentsInsertSchema = createInsertSchema(
77
+ incidentCommentsTable,
78
+ );
79
+ export type IncidentCommentsInsert = z.infer<
80
+ typeof incidentCommentsInsertSchema
81
+ >;
82
+
83
+ export const incidentEventSchema = createSelectSchema(incidentEventsTable);
84
+ export type IncidentEvent = z.infer<typeof incidentEventSchema>;
85
+ export const incidentEventInsertSchema =
86
+ createInsertSchema(incidentEventsTable);
87
+ export type IncidentEventInsert = z.infer<typeof incidentEventInsertSchema>;
88
+
89
+ export const prewatchEvidenceEventSchema = createSelectSchema(
90
+ prewatchEvidenceEventsTable,
91
+ );
92
+ export type PrewatchEvidenceEvent = z.infer<typeof prewatchEvidenceEventSchema>;
93
+ export const prewatchEvidenceEventInsertSchema = createInsertSchema(
94
+ prewatchEvidenceEventsTable,
95
+ );
96
+ export type PrewatchEvidenceEventInsert = z.infer<
97
+ typeof prewatchEvidenceEventInsertSchema
98
+ >;
99
+
100
+ const relatedEventSchema = eventSchema.extend({
101
+ prewatchResult: prewatchResultSchema.nullish(),
102
+ watchResult: watchResultSchema.nullish(),
103
+ });
104
+
105
+ const relatedIncidentEventSchema = incidentEventSchema.extend({
106
+ event: relatedEventSchema,
107
+ });
108
+
109
+ export interface PromptEvent {
110
+ id: string;
111
+ ts: string;
112
+ slackAuthorId: string;
113
+ textRaw: string | null;
114
+ textNorm: string | null;
115
+ }
116
+
117
+ export const unsuspiciousPrewatchGenerationSchema = z.object({
118
+ suspicious: z.literal(false),
119
+ reasoning: z.string(),
120
+ });
121
+
122
+ export const suspiciousPrewatchGenerationSchema = z.object({
123
+ suspicious: z.literal(true),
124
+ reasoning: z.string(),
125
+ title: z.string(),
126
+ evidenceEventIds: z.string().array(),
127
+ });
128
+ export type SuspiciousPrewatchGeneration = z.infer<
129
+ typeof suspiciousPrewatchGenerationSchema
130
+ >;
131
+
132
+ export const importantGenerationSchema = z
133
+ .object({
134
+ important: z.literal(true),
135
+ statusSignal: statusSignalSchema,
136
+ description: z.string(),
137
+ summary: z.string(),
138
+ })
139
+ .strict();
140
+
141
+ export const unimportantGenerationSchema = z
142
+ .object({
143
+ important: z.literal(false),
144
+ })
145
+ .strict();
146
+
147
+ export const watchGenerationSchema = z.union([
148
+ importantGenerationSchema,
149
+ unimportantGenerationSchema,
150
+ ]);
151
+ export type WatchGeneration = z.infer<typeof watchGenerationSchema>;
152
+
153
+ export const prewatchGenerationSchema = z.union([
154
+ suspiciousPrewatchGenerationSchema,
155
+ unsuspiciousPrewatchGenerationSchema,
156
+ ]);
157
+ export type PrewatchGeneration = z.infer<typeof prewatchGenerationSchema>;
158
+
159
+ // API
160
+
161
+ export const emptyParamsSchema = z.tuple([]).readonly();
162
+ export type EmptyParams = z.infer<typeof emptyParamsSchema>;
163
+
164
+ export const singleParamSchema = z.tuple([z.string()]).readonly();
165
+ export type SingleParam = z.infer<typeof singleParamSchema>;
166
+
167
+ export type OptionalParams<S, K extends PropertyKey> = S extends {
168
+ [P in K]: infer T extends z.ZodType;
169
+ }
170
+ ? { [P in K]: z.infer<T> }
171
+ : { [P in K]?: never };
172
+
173
+ export const incidentWithChannelSchema = incidentSchema.extend({
174
+ channel: channelSchema,
175
+ });
176
+
177
+ // GET /health
178
+ export const getHealthOutputSchema = z.object({
179
+ startupTime: z.string(),
180
+ memoryLoad: z.number(),
181
+ });
182
+
183
+ // GET /incidents
184
+ export const getIncidentsOutputSchema = incidentWithChannelSchema.array();
185
+
186
+ // GET /incidents/:incidentId
187
+ export const getIncidentOutputSchema = incidentSchema.extend({
188
+ incidentEvents: relatedIncidentEventSchema.array(),
189
+ channel: channelSchema,
190
+ });
191
+
192
+ export const postIncidentCommentInputSchema = incidentCommentsInsertSchema.pick(
193
+ {
194
+ incidentId: true,
195
+ content: true,
196
+ },
197
+ );
198
+
199
+ export const postIncidentCommentOutputSchema = incidentCommentsSchema;
200
+
201
+ export const apiSchemas = {
202
+ getHealth: {
203
+ method: "GET",
204
+ path: "health",
205
+ output: getHealthOutputSchema,
206
+ },
207
+ getIncidents: {
208
+ method: "GET",
209
+ path: "incidents",
210
+ output: getIncidentsOutputSchema,
211
+ },
212
+ getIncident: {
213
+ method: "GET",
214
+ path: "incidents",
215
+ output: getIncidentOutputSchema,
216
+ params: singleParamSchema,
217
+ },
218
+ postIncidentComment: {
219
+ method: "POST",
220
+ path: "incidents",
221
+ output: postIncidentCommentOutputSchema,
222
+ input: postIncidentCommentInputSchema,
223
+ },
224
+ };
225
+
226
+ export type ApiSchemas = typeof apiSchemas;
227
+
228
+ export type ProcedureName = keyof ApiSchemas;
229
+ // 'getHealth' | 'getIncidents' | 'getIncident' ...
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.