@quickscores/chat 0.1.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/README.md +158 -0
- package/dist/types/api.d.ts +64 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +2 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +13 -0
- package/dist/types/message.d.ts +16 -0
- package/dist/types/message.d.ts.map +1 -0
- package/dist/types/message.js +17 -0
- package/dist/types/thread.d.ts +54 -0
- package/dist/types/thread.d.ts.map +1 -0
- package/dist/types/thread.js +38 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# QuickScores Chat Service
|
|
2
|
+
|
|
3
|
+
Supabase-backed chat for QuickScores. Consumers: React Native (Android/iOS) and web app.
|
|
4
|
+
|
|
5
|
+
## What’s in this repo
|
|
6
|
+
|
|
7
|
+
- **Supabase**: config, migrations, and Edge Functions for chat (DB, RLS, Realtime).
|
|
8
|
+
- **Shared types**: TypeScript types and Zod schemas in `src/types/` for use by RN and web clients.
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
- [Supabase CLI](https://supabase.com/docs/guides/cli) (`npm i -g supabase` or `npx supabase`)
|
|
13
|
+
- Node.js 20+
|
|
14
|
+
- A [Supabase project](https://supabase.com/dashboard) (for remote; optional for local-only)
|
|
15
|
+
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Local Supabase (optional)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx supabase start
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Use the printed URLs for local API, Studio, and DB. Link to a remote project when ready:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx supabase link --project-ref <your-project-ref>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Migrations
|
|
35
|
+
|
|
36
|
+
- Create: put SQL in `supabase/migrations/` with timestamped names (e.g. `20240202120000_create_chat_tables.sql`), or use `npm run db:diff` after changing schema locally.
|
|
37
|
+
- Apply locally: `npx supabase db reset` (reset + seed) or run migrations manually.
|
|
38
|
+
- Push to remote: `npm run db:migrate` (or `npx supabase db push`).
|
|
39
|
+
|
|
40
|
+
### Deploy to Supabase
|
|
41
|
+
|
|
42
|
+
1. **Create a project** at [supabase.com/dashboard](https://supabase.com/dashboard) if you don’t have one. Note the **Project ref** (in Settings → General).
|
|
43
|
+
|
|
44
|
+
2. **Link** the repo to that project (one-time):
|
|
45
|
+
```bash
|
|
46
|
+
npx supabase link --project-ref <your-project-ref>
|
|
47
|
+
```
|
|
48
|
+
Use your database password when prompted (from Dashboard → Settings → Database).
|
|
49
|
+
|
|
50
|
+
3. **Push migrations** (schema + RLS):
|
|
51
|
+
```bash
|
|
52
|
+
npm run db:migrate
|
|
53
|
+
```
|
|
54
|
+
or `npx supabase db push`.
|
|
55
|
+
|
|
56
|
+
4. **Deploy Edge Functions** (chat REST API):
|
|
57
|
+
```bash
|
|
58
|
+
npx supabase functions deploy
|
|
59
|
+
```
|
|
60
|
+
This deploys all functions in `supabase/functions/` (e.g. `chat-thread`, `chat-send-message`, `chat-mark-read`). To deploy a single function: `npx supabase functions deploy chat-thread`.
|
|
61
|
+
|
|
62
|
+
5. **Set secrets** (if your functions need them): in Dashboard → Edge Functions → Secrets, or:
|
|
63
|
+
```bash
|
|
64
|
+
npx supabase secrets set SUPABASE_SERVICE_ROLE_KEY=<your-service-role-key>
|
|
65
|
+
```
|
|
66
|
+
The hosted project already has `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` set by default for deployed functions; you only need to add custom secrets.
|
|
67
|
+
|
|
68
|
+
Your API base URL will be `https://<project-ref>.supabase.co/functions/v1`. Use that in clients instead of `http://127.0.0.1:54321/functions/v1`.
|
|
69
|
+
|
|
70
|
+
## Scripts
|
|
71
|
+
|
|
72
|
+
| Script | Description |
|
|
73
|
+
|-----------------|--------------------------------------|
|
|
74
|
+
| `npm run db:start` | Start local Supabase stack |
|
|
75
|
+
| `npm run db:stop` | Stop local Supabase |
|
|
76
|
+
| `npm run db:reset` | Reset DB and run migrations + seed |
|
|
77
|
+
| `npm run db:migrate`| Push migrations to linked project |
|
|
78
|
+
| `npm run db:diff` | Generate migration from schema diff |
|
|
79
|
+
| `npm run build` | Build types package to `dist/` (for publish) |
|
|
80
|
+
| `npm run types:check` | TypeScript check (no emit) |
|
|
81
|
+
| `npm run lint` | Prettier check |
|
|
82
|
+
| `npm run lint:fix` | Prettier fix |
|
|
83
|
+
|
|
84
|
+
## Using shared types in the app
|
|
85
|
+
|
|
86
|
+
From the React Native (or web) app:
|
|
87
|
+
|
|
88
|
+
1. **Workspace / link** (if in a monorepo or same parent repo):
|
|
89
|
+
- Add in the app’s `package.json`: `"@quickscores/chat": "file:../chat"` (or your path).
|
|
90
|
+
- In this repo, run `npm run build` so `dist/` is present (the package entry point is the built output).
|
|
91
|
+
- Then: `import { threadSchema, type Thread, type Message, type ThreadListRow } from "@quickscores/chat";`
|
|
92
|
+
- REST request/response types: `CreateThreadBody`, `SendMessageBody`, `ThreadResponse`, `MessageResponse`, `ErrorResponse`, etc. (see `src/types/api.ts`).
|
|
93
|
+
2. **From a registry**: Publish the types package (see below), then add `"@quickscores/chat": "^0.1.0"` and run `npm install`.
|
|
94
|
+
|
|
95
|
+
Types are aligned with the Supabase schema and [docs/api-chat.md](docs/api-chat.md): `Thread` (chat_threads), `Message` (chat_messages), `ThreadListRow` (chat_thread_list view).
|
|
96
|
+
|
|
97
|
+
### Publishing the types package to a registry
|
|
98
|
+
|
|
99
|
+
The entire `src/` tree is built to `dist/` and only `dist/` is published (`"files": ["dist"]`). Supabase config, migrations, Edge Functions, scripts, and docs are not included in the tarball.
|
|
100
|
+
|
|
101
|
+
1. **Build**: `npm run build` (or it runs automatically via `prepublishOnly` when you publish).
|
|
102
|
+
2. **Allow publishing**: In `package.json`, set `"private": false` (or remove the `"private"` field).
|
|
103
|
+
3. **Publish to npm** (see [Publishing to npm](#publishing-to-npm) below).
|
|
104
|
+
|
|
105
|
+
Consumers then install with `"@quickscores/chat": "^0.1.0"` and import as before; they get types and Zod runtime from the published tarball only.
|
|
106
|
+
|
|
107
|
+
#### Publishing to npm
|
|
108
|
+
|
|
109
|
+
1. **Create the scope** (one-time): [npmjs.com/org/create](https://www.npmjs.com/org/create) and create the `quickscores` org (or use an existing org that will own the package).
|
|
110
|
+
|
|
111
|
+
2. **Log in** (if you aren’t already):
|
|
112
|
+
```bash
|
|
113
|
+
npm login
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
3. **Allow publishing**: In `package.json`, set `"private": false` (or remove the `"private"` field).
|
|
117
|
+
|
|
118
|
+
4. **Publish** (build runs automatically via `prepublishOnly`):
|
|
119
|
+
```bash
|
|
120
|
+
npm publish --access public
|
|
121
|
+
```
|
|
122
|
+
Scoped packages (`@quickscores/chat`) are private by default; `--access public` makes them installable by anyone without a paid plan.
|
|
123
|
+
|
|
124
|
+
After that, anyone can run `npm install @quickscores/chat` with no extra config or tokens.
|
|
125
|
+
|
|
126
|
+
## Project layout
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
chat/
|
|
130
|
+
├── supabase/
|
|
131
|
+
│ ├── config.toml # Local Supabase config
|
|
132
|
+
│ ├── migrations/ # SQL migrations (chat tables, RLS)
|
|
133
|
+
│ ├── functions/ # Edge Functions (chat REST API)
|
|
134
|
+
│ └── seed.sql # Optional seed data
|
|
135
|
+
├── src/
|
|
136
|
+
│ └── types/ # Shared TypeScript + Zod (Thread, Message, ThreadListRow, REST API types)
|
|
137
|
+
├── docs/
|
|
138
|
+
│ ├── prd/ # Product requirements
|
|
139
|
+
│ └── api-chat.md # Chat REST API reference
|
|
140
|
+
├── package.json
|
|
141
|
+
├── tsconfig.json
|
|
142
|
+
└── README.md
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Chat REST API
|
|
146
|
+
|
|
147
|
+
We do **not** use Postgres RPCs for chat. The API is implemented as **REST HTTP endpoints** using Supabase Edge Functions: each action (get/create thread, send message, mark read) is a separate Edge Function. Clients use normal HTTP (e.g. `fetch` or `axios`).
|
|
148
|
+
|
|
149
|
+
- **Docs:** [docs/api-chat.md](docs/api-chat.md)
|
|
150
|
+
- **Endpoints:** `POST /functions/v1/chat-thread` (get/create thread), `chat-league-room`, `chat-team-room`, `chat-send-message`, `chat-mark-read`
|
|
151
|
+
- **Auth:** Not enforced yet; use header `X-User-Id` (or body `user_id`) to identify the caller. Add JWT auth later.
|
|
152
|
+
|
|
153
|
+
Run locally: `npx supabase start` then `npx supabase functions serve`. See [docs/api-chat.md](docs/api-chat.md#testing) for how to test (curl examples and `npm run test:api`).
|
|
154
|
+
|
|
155
|
+
## Next steps
|
|
156
|
+
|
|
157
|
+
1. Add auth: validate JWT in Edge Functions and use `auth.uid()` instead of `X-User-Id`.
|
|
158
|
+
2. In the RN/app, call the chat endpoints and use types from `@quickscores/chat` (see [docs/api-chat.md](docs/api-chat.md)).
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Message } from "./message";
|
|
2
|
+
import type { Thread } from "./thread";
|
|
3
|
+
/**
|
|
4
|
+
* Error response – all error responses use this shape.
|
|
5
|
+
*/
|
|
6
|
+
export interface ErrorResponse {
|
|
7
|
+
error: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* POST /chat-thread
|
|
11
|
+
* participant_ids are QuickScores user ids (numbers).
|
|
12
|
+
*/
|
|
13
|
+
export interface CreateThreadBody {
|
|
14
|
+
participant_ids: number[];
|
|
15
|
+
title?: string | null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* POST /chat-league-room
|
|
19
|
+
*/
|
|
20
|
+
export interface LeagueRoomBody {
|
|
21
|
+
league_id: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* POST /chat-team-room
|
|
25
|
+
*/
|
|
26
|
+
export interface TeamRoomBody {
|
|
27
|
+
team_id: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* POST /chat-send-message
|
|
31
|
+
*/
|
|
32
|
+
export interface SendMessageBody {
|
|
33
|
+
thread_id: string;
|
|
34
|
+
type: string;
|
|
35
|
+
body?: string | null;
|
|
36
|
+
payload?: Record<string, unknown>;
|
|
37
|
+
client_nonce?: string | null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* POST /chat-mark-read
|
|
41
|
+
*/
|
|
42
|
+
export interface MarkReadBody {
|
|
43
|
+
thread_id: string;
|
|
44
|
+
last_read_message_id: string | null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Response: get-or-create thread (chat-thread, chat-league-room, chat-team-room)
|
|
48
|
+
*/
|
|
49
|
+
export interface ThreadResponse {
|
|
50
|
+
thread: Thread;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Response: send message (chat-send-message)
|
|
54
|
+
*/
|
|
55
|
+
export interface MessageResponse {
|
|
56
|
+
message: Message;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Response: mark read (chat-mark-read)
|
|
60
|
+
*/
|
|
61
|
+
export interface MarkReadResponse {
|
|
62
|
+
ok: true;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/types/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,IAAI,CAAC;CACV"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared chat types and Zod schemas for QuickScores clients (RN, web).
|
|
3
|
+
* Kept in sync with Supabase migrations and docs/api-chat.md.
|
|
4
|
+
*/
|
|
5
|
+
export { threadKindSchema, threadSchema, threadListRowSchema, type Thread, type ThreadKind, type ThreadListRow, } from "./thread";
|
|
6
|
+
export { messageSchema, type Message } from "./message";
|
|
7
|
+
export type { ErrorResponse, CreateThreadBody, LeagueRoomBody, TeamRoomBody, SendMessageBody, MarkReadBody, ThreadResponse, MessageResponse, MarkReadResponse, } from "./api";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACnB,KAAK,MAAM,EACX,KAAK,UAAU,EACf,KAAK,aAAa,GACnB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AACxD,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,GACjB,MAAM,OAAO,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared chat types and Zod schemas for QuickScores clients (RN, web).
|
|
4
|
+
* Kept in sync with Supabase migrations and docs/api-chat.md.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.messageSchema = exports.threadListRowSchema = exports.threadSchema = exports.threadKindSchema = void 0;
|
|
8
|
+
var thread_1 = require("./thread");
|
|
9
|
+
Object.defineProperty(exports, "threadKindSchema", { enumerable: true, get: function () { return thread_1.threadKindSchema; } });
|
|
10
|
+
Object.defineProperty(exports, "threadSchema", { enumerable: true, get: function () { return thread_1.threadSchema; } });
|
|
11
|
+
Object.defineProperty(exports, "threadListRowSchema", { enumerable: true, get: function () { return thread_1.threadListRowSchema; } });
|
|
12
|
+
var message_1 = require("./message");
|
|
13
|
+
Object.defineProperty(exports, "messageSchema", { enumerable: true, get: function () { return message_1.messageSchema; } });
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Message – matches chat_messages table.
|
|
4
|
+
*/
|
|
5
|
+
export declare const messageSchema: z.ZodObject<{
|
|
6
|
+
id: z.ZodString;
|
|
7
|
+
thread_id: z.ZodString;
|
|
8
|
+
sender_id: z.ZodNumber;
|
|
9
|
+
type: z.ZodString;
|
|
10
|
+
body: z.ZodNullable<z.ZodString>;
|
|
11
|
+
payload: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
12
|
+
client_nonce: z.ZodNullable<z.ZodString>;
|
|
13
|
+
created_at: z.ZodString;
|
|
14
|
+
}, z.core.$strip>;
|
|
15
|
+
export type Message = z.infer<typeof messageSchema>;
|
|
16
|
+
//# sourceMappingURL=message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/types/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;;;;;iBASxB,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.messageSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Message – matches chat_messages table.
|
|
7
|
+
*/
|
|
8
|
+
exports.messageSchema = zod_1.z.object({
|
|
9
|
+
id: zod_1.z.string().uuid(),
|
|
10
|
+
thread_id: zod_1.z.string().uuid(),
|
|
11
|
+
sender_id: zod_1.z.number().int(),
|
|
12
|
+
type: zod_1.z.string(),
|
|
13
|
+
body: zod_1.z.string().nullable(),
|
|
14
|
+
payload: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
|
|
15
|
+
client_nonce: zod_1.z.string().nullable(),
|
|
16
|
+
created_at: zod_1.z.string(),
|
|
17
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Thread kind – matches chat_threads.kind.
|
|
4
|
+
*/
|
|
5
|
+
export declare const threadKindSchema: z.ZodEnum<{
|
|
6
|
+
dm: "dm";
|
|
7
|
+
group: "group";
|
|
8
|
+
league: "league";
|
|
9
|
+
team: "team";
|
|
10
|
+
}>;
|
|
11
|
+
export type ThreadKind = z.infer<typeof threadKindSchema>;
|
|
12
|
+
/**
|
|
13
|
+
* Thread – matches chat_threads table.
|
|
14
|
+
* No updated_at; schema only has created_at.
|
|
15
|
+
*/
|
|
16
|
+
export declare const threadSchema: z.ZodObject<{
|
|
17
|
+
id: z.ZodString;
|
|
18
|
+
kind: z.ZodEnum<{
|
|
19
|
+
dm: "dm";
|
|
20
|
+
group: "group";
|
|
21
|
+
league: "league";
|
|
22
|
+
team: "team";
|
|
23
|
+
}>;
|
|
24
|
+
reuse_key: z.ZodNullable<z.ZodString>;
|
|
25
|
+
title: z.ZodNullable<z.ZodString>;
|
|
26
|
+
metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
27
|
+
created_by: z.ZodNumber;
|
|
28
|
+
created_at: z.ZodString;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
export type Thread = z.infer<typeof threadSchema>;
|
|
31
|
+
/**
|
|
32
|
+
* Thread list row – one row per thread from chat_thread_list view.
|
|
33
|
+
*/
|
|
34
|
+
export declare const threadListRowSchema: z.ZodObject<{
|
|
35
|
+
thread_id: z.ZodString;
|
|
36
|
+
kind: z.ZodEnum<{
|
|
37
|
+
dm: "dm";
|
|
38
|
+
group: "group";
|
|
39
|
+
league: "league";
|
|
40
|
+
team: "team";
|
|
41
|
+
}>;
|
|
42
|
+
title: z.ZodNullable<z.ZodString>;
|
|
43
|
+
reuse_key: z.ZodNullable<z.ZodString>;
|
|
44
|
+
created_by: z.ZodNumber;
|
|
45
|
+
created_at: z.ZodString;
|
|
46
|
+
user_id: z.ZodNumber;
|
|
47
|
+
last_read_message_id: z.ZodNullable<z.ZodString>;
|
|
48
|
+
last_message_at: z.ZodNullable<z.ZodString>;
|
|
49
|
+
last_message_preview: z.ZodNullable<z.ZodString>;
|
|
50
|
+
unread_count: z.ZodNumber;
|
|
51
|
+
other_participant_ids: z.ZodNullable<z.ZodArray<z.ZodNumber>>;
|
|
52
|
+
}, z.core.$strip>;
|
|
53
|
+
export type ThreadListRow = z.infer<typeof threadListRowSchema>;
|
|
54
|
+
//# sourceMappingURL=thread.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../src/types/thread.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;EAA4C,CAAC;AAC1E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;iBAQvB,CAAC;AAEH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;iBAa9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.threadListRowSchema = exports.threadSchema = exports.threadKindSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Thread kind – matches chat_threads.kind.
|
|
7
|
+
*/
|
|
8
|
+
exports.threadKindSchema = zod_1.z.enum(["dm", "group", "league", "team"]);
|
|
9
|
+
/**
|
|
10
|
+
* Thread – matches chat_threads table.
|
|
11
|
+
* No updated_at; schema only has created_at.
|
|
12
|
+
*/
|
|
13
|
+
exports.threadSchema = zod_1.z.object({
|
|
14
|
+
id: zod_1.z.string().uuid(),
|
|
15
|
+
kind: exports.threadKindSchema,
|
|
16
|
+
reuse_key: zod_1.z.string().nullable(),
|
|
17
|
+
title: zod_1.z.string().nullable(),
|
|
18
|
+
metadata: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
|
|
19
|
+
created_by: zod_1.z.number().int(),
|
|
20
|
+
created_at: zod_1.z.string(),
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* Thread list row – one row per thread from chat_thread_list view.
|
|
24
|
+
*/
|
|
25
|
+
exports.threadListRowSchema = zod_1.z.object({
|
|
26
|
+
thread_id: zod_1.z.string().uuid(),
|
|
27
|
+
kind: exports.threadKindSchema,
|
|
28
|
+
title: zod_1.z.string().nullable(),
|
|
29
|
+
reuse_key: zod_1.z.string().nullable(),
|
|
30
|
+
created_by: zod_1.z.number().int(),
|
|
31
|
+
created_at: zod_1.z.string(),
|
|
32
|
+
user_id: zod_1.z.number().int(),
|
|
33
|
+
last_read_message_id: zod_1.z.string().uuid().nullable(),
|
|
34
|
+
last_message_at: zod_1.z.string().nullable(),
|
|
35
|
+
last_message_preview: zod_1.z.string().nullable(),
|
|
36
|
+
unread_count: zod_1.z.number().int().min(0),
|
|
37
|
+
other_participant_ids: zod_1.z.array(zod_1.z.number().int()).nullable(),
|
|
38
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@quickscores/chat",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Shared chat types and Zod schemas for QuickScores (RN, web)",
|
|
6
|
+
"main": "./dist/types/index.js",
|
|
7
|
+
"types": "./dist/types/index.d.ts",
|
|
8
|
+
"files": ["dist"],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc -p tsconfig.build.json",
|
|
11
|
+
"prepublishOnly": "npm run build",
|
|
12
|
+
"db:start": "supabase start",
|
|
13
|
+
"db:stop": "supabase stop",
|
|
14
|
+
"db:reset": "supabase db reset",
|
|
15
|
+
"db:migrate": "supabase db push",
|
|
16
|
+
"db:diff": "supabase db diff -f",
|
|
17
|
+
"types:check": "tsc --noEmit",
|
|
18
|
+
"lint": "prettier --check \"src/**/*.ts\" \"scripts/**/*.ts\" \"supabase/functions/**/*.ts\"",
|
|
19
|
+
"lint:fix": "prettier --write \"src/**/*.ts\" \"scripts/**/*.ts\" \"supabase/functions/**/*.ts\"",
|
|
20
|
+
"test:api": "tsx scripts/test-chat-api.ts",
|
|
21
|
+
"test:league-team-rooms": "tsx scripts/test-league-team-rooms.ts"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"zod": "4.3.5"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^22.10.0",
|
|
28
|
+
"dotenv": "^16.4.5",
|
|
29
|
+
"ky": "^1.8.0",
|
|
30
|
+
"prettier": "^3.8.0",
|
|
31
|
+
"supabase": "^2.75.0",
|
|
32
|
+
"tsx": "^4.19.0",
|
|
33
|
+
"typescript": "~5.9.2"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20"
|
|
37
|
+
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "github:quickscores/App2.0-Chat"
|
|
41
|
+
},
|
|
42
|
+
"exports": {
|
|
43
|
+
".": {
|
|
44
|
+
"types": "./dist/types/index.d.ts",
|
|
45
|
+
"import": "./dist/types/index.js",
|
|
46
|
+
"default": "./dist/types/index.js"
|
|
47
|
+
},
|
|
48
|
+
"./types": {
|
|
49
|
+
"types": "./dist/types/index.d.ts",
|
|
50
|
+
"import": "./dist/types/index.js",
|
|
51
|
+
"default": "./dist/types/index.js"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|