@agora-server/contract 0.9.2

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,85 @@
1
+ // Secure chat (end-to-end-encrypted, MLS/RFC-9420) wire contract.
2
+ //
3
+ // This is a SEPARATE surface from the Replyke-compatible plaintext chat (types.ts /
4
+ // schemas.ts) — it is NOT consumed by the forked Replyke SDK. The server is a blind MLS
5
+ // Delivery Service: every binary value (KeyPackages, Welcomes, Commits, application
6
+ // ciphertext, key-backup blobs) crosses the wire as **base64** and the server never parses
7
+ // it. MLS epochs are u64 (exceed JS safe-int) so they travel as **decimal strings**.
8
+ //
9
+ // Pure zod + TS — no hono/drizzle. Request schemas feed the server's parseBody(); the
10
+ // model interfaces are the response shapes the route shapers produce.
11
+ import { z } from "zod";
12
+ // Base64 (standard alphabet, optional padding). The server enforces the real DECODED byte
13
+ // caps (MAX_SECURE_MESSAGE_BYTES / MAX_SECURE_HANDSHAKE_BYTES); this just rejects non-base64
14
+ // and an absurd pre-decode length so a garbage body fails fast at validation.
15
+ const MAX_B64_CHARS = 16_777_216; // ~12 MiB decoded — generous upper guard, real cap is server-side
16
+ export const base64 = z
17
+ .string()
18
+ .min(1)
19
+ .max(MAX_B64_CHARS)
20
+ .regex(/^[A-Za-z0-9+/]+={0,2}$/, "must be base64");
21
+ // MLS epoch as a non-negative decimal string (u64-safe on the wire).
22
+ export const epochString = z.string().regex(/^\d+$/, "epoch must be a non-negative integer string");
23
+ const ciphersuite = z.number().int().positive();
24
+ // ─── reusable sub-objects ────────────────────────────────────────────────────
25
+ // A Welcome is targeted at the ONE device whose claimed KeyPackage was consumed.
26
+ export const welcomeSchema = z.object({
27
+ targetDeviceId: z.string().uuid(),
28
+ payload: base64,
29
+ epoch: epochString,
30
+ });
31
+ // A Commit/Proposal is broadcast to the whole group (no target device).
32
+ export const handshakeBlobSchema = z.object({
33
+ payload: base64,
34
+ epoch: epochString,
35
+ });
36
+ // ─── request schemas (server: parseBody(schema, raw, "secure-chat")) ─────────
37
+ export const registerDeviceSchema = z.object({
38
+ deviceId: z.string().min(1).max(200), // client-generated stable id (one device = one MLS leaf)
39
+ displayName: z.string().max(200).nullish(),
40
+ signaturePublicKey: base64,
41
+ credential: base64,
42
+ ciphersuite,
43
+ });
44
+ export const publishKeyPackagesSchema = z.object({
45
+ keyPackages: z
46
+ .array(z.object({
47
+ keyPackageRef: z.string().min(1).max(512),
48
+ keyPackage: base64,
49
+ ciphersuite,
50
+ expiresAt: z.string().datetime().nullish(),
51
+ }))
52
+ .min(1)
53
+ .max(100),
54
+ });
55
+ export const createSecureConversationSchema = z.object({
56
+ type: z.enum(["dm", "group", "channel"]),
57
+ mlsGroupId: base64,
58
+ spaceId: z.string().uuid().nullish(), // required when type === "channel" (enforced server-side)
59
+ name: z.string().max(300).nullish(), // optional plaintext label; prefer null (metadata concession)
60
+ memberUserIds: z.array(z.string().uuid()).max(1000).default([]),
61
+ welcomes: z.array(welcomeSchema).max(1000).default([]),
62
+ });
63
+ export const addSecureMemberSchema = z.object({
64
+ userId: z.string().uuid(),
65
+ commit: handshakeBlobSchema,
66
+ welcomes: z.array(welcomeSchema).min(1).max(50),
67
+ });
68
+ export const removeSecureMemberSchema = z.object({
69
+ commit: handshakeBlobSchema,
70
+ });
71
+ export const sendSecureMessageSchema = z.object({
72
+ ciphertext: base64,
73
+ epoch: epochString,
74
+ senderDeviceId: z.string().uuid(),
75
+ contentType: z.string().max(100).nullish(),
76
+ });
77
+ export const uploadKeyBackupSchema = z.object({
78
+ deviceId: z.string().max(200).nullish(),
79
+ blob: base64,
80
+ nonce: base64,
81
+ kdf: z.enum(["argon2id", "pbkdf2"]),
82
+ kdfParams: z.record(z.string(), z.unknown()),
83
+ cipher: z.enum(["xchacha20poly1305", "aes-256-gcm"]),
84
+ version: z.number().int().positive(),
85
+ });
@@ -0,0 +1,144 @@
1
+ import type { ReactionCounts, ReactionType } from "./reactions.js";
2
+ export interface User {
3
+ id: string;
4
+ projectId: string;
5
+ foreignId: string | null;
6
+ role: "admin" | "moderator" | "visitor";
7
+ name: string | null;
8
+ username: string | null;
9
+ avatar: string | null;
10
+ avatarFileId: string | null;
11
+ bannerFileId: string | null;
12
+ bio: string | null;
13
+ birthdate: string | null;
14
+ location: unknown | null;
15
+ metadata: Record<string, unknown>;
16
+ reputation: number;
17
+ createdAt: string;
18
+ }
19
+ export interface Entity {
20
+ id: string;
21
+ foreignId: string | null;
22
+ shortId: string;
23
+ projectId: string;
24
+ sourceId: string | null;
25
+ spaceId: string | null;
26
+ space?: unknown;
27
+ userId: string | null;
28
+ user?: User | null;
29
+ title: string | null;
30
+ content: string | null;
31
+ mentions: unknown[];
32
+ attachments: unknown[];
33
+ files?: unknown[];
34
+ keywords: string[];
35
+ upvotes: string[];
36
+ downvotes: string[];
37
+ reactionCounts: ReactionCounts;
38
+ userReaction: ReactionType | null;
39
+ repliesCount: number;
40
+ views: number;
41
+ score: number;
42
+ scoreUpdatedAt: string;
43
+ location: unknown | null;
44
+ metadata: Record<string, unknown>;
45
+ isSaved?: boolean;
46
+ createdAt: string;
47
+ updatedAt: string;
48
+ deletedAt: string | null;
49
+ isDraft: boolean;
50
+ moderationStatus: string | null;
51
+ moderatedAt: string | null;
52
+ moderatedById: string | null;
53
+ moderatedByType: string | null;
54
+ moderationReason: string | null;
55
+ }
56
+ export interface Comment {
57
+ id: string;
58
+ projectId: string;
59
+ foreignId: string | null;
60
+ entityId: string;
61
+ userId: string | null;
62
+ user?: User | null;
63
+ parentId: string | null;
64
+ parentComment?: Comment | null;
65
+ content: string | null;
66
+ gif: unknown | null;
67
+ mentions: unknown[];
68
+ upvotes: string[];
69
+ downvotes: string[];
70
+ reactionCounts: ReactionCounts;
71
+ userReaction: ReactionType | null;
72
+ repliesCount: number;
73
+ metadata: Record<string, unknown>;
74
+ createdAt: string;
75
+ updatedAt: string;
76
+ deletedAt: string | null;
77
+ userDeletedAt: string | null;
78
+ moderationStatus: string | null;
79
+ moderatedAt: string | null;
80
+ moderatedById: string | null;
81
+ moderatedByType: string | null;
82
+ moderationReason: string | null;
83
+ }
84
+ export interface AuthUser extends User {
85
+ email: string | null;
86
+ isVerified: boolean;
87
+ isActive: boolean;
88
+ lastActive: string;
89
+ updatedAt: string;
90
+ suspensions: {
91
+ reason: string | null;
92
+ startDate: string;
93
+ endDate: string | null;
94
+ }[];
95
+ authMethods: string[];
96
+ isOperator: boolean;
97
+ isSteward: boolean;
98
+ }
99
+ export type ReportTargetType = "entity" | "comment" | "message";
100
+ export interface UserSummary {
101
+ id: string;
102
+ username: string | null;
103
+ name: string | null;
104
+ reputation: number;
105
+ }
106
+ export interface Report {
107
+ id: string;
108
+ projectId: string;
109
+ reporterId: string | null;
110
+ targetType: ReportTargetType;
111
+ targetId: string;
112
+ spaceId: string | null;
113
+ reason: string;
114
+ details: string | null;
115
+ resolvedAt: string | null;
116
+ resolvedById: string | null;
117
+ createdAt: string;
118
+ author?: UserSummary | null;
119
+ reporter?: UserSummary | null;
120
+ }
121
+ export interface AuthContext {
122
+ userId: string;
123
+ role: "admin" | "moderator" | "visitor";
124
+ isOperator: boolean;
125
+ isSteward: boolean;
126
+ }
127
+ export type ModerationVerdict = "allow" | "block" | "review";
128
+ export interface ModerationAnalysis {
129
+ id: string;
130
+ projectId: string;
131
+ targetType: ReportTargetType;
132
+ targetId: string;
133
+ spaceId: string | null;
134
+ verdict: ModerationVerdict;
135
+ categories: string[];
136
+ confidence: number;
137
+ reason: string;
138
+ model: string;
139
+ autoActioned: boolean;
140
+ humanResolvedAt: string | null;
141
+ createdAt: string;
142
+ author?: UserSummary | null;
143
+ }
144
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@agora-server/contract",
3
+ "version": "0.9.2",
4
+ "type": "module",
5
+ "description": "Shared Agora API contract — response-model types + zod request schemas (no hono/drizzle).",
6
+ "license": "Apache-2.0",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/jenova-marie/agora-server.git",
10
+ "directory": "packages/contract"
11
+ },
12
+ "homepage": "https://github.com/jenova-marie/agora-server/tree/main/packages/contract",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "dependencies": {
28
+ "zod": "^3.24.1"
29
+ },
30
+ "devDependencies": {
31
+ "typescript": "^5.7.2",
32
+ "vitest": "^4.1.7"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc -p tsconfig.build.json",
36
+ "dev": "tsc -w -p tsconfig.build.json",
37
+ "typecheck": "tsc --noEmit",
38
+ "test": "vitest run",
39
+ "test:watch": "vitest"
40
+ }
41
+ }