@massalabs/gossip-sdk 0.0.2-dev.20260220142001 → 0.0.2-dev.20260223065033
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 +26 -3
- package/dist/core/SdkEventEmitter.d.ts +2 -0
- package/dist/core/SdkEventEmitter.js +2 -0
- package/dist/{db.d.ts → db/db.d.ts} +14 -3
- package/dist/{db.js → db/db.js} +17 -8
- package/dist/db/exec-utils.d.ts +19 -0
- package/dist/db/exec-utils.js +48 -0
- package/dist/db/generated-ddl.d.ts +1 -0
- package/dist/db/generated-ddl.js +31 -0
- package/dist/db/index.d.ts +3 -0
- package/dist/db/index.js +3 -0
- package/dist/db/queries/activeSeekers.d.ts +1 -0
- package/dist/{queries → db/queries}/activeSeekers.js +0 -5
- package/dist/{queries → db/queries}/messages.d.ts +2 -2
- package/dist/{queries → db/queries}/messages.js +3 -3
- package/dist/{queries → db/queries}/userProfile.d.ts +1 -1
- package/dist/{queries → db/queries}/userProfile.js +1 -1
- package/dist/db/schema/_helpers.d.ts +26 -0
- package/dist/db/schema/_helpers.js +15 -0
- package/dist/db/schema/activeSeekers.d.ts +43 -0
- package/dist/db/schema/activeSeekers.js +6 -0
- package/dist/db/schema/announcementCursors.d.ts +45 -0
- package/dist/db/schema/announcementCursors.js +5 -0
- package/dist/db/schema/contacts.d.ts +170 -0
- package/dist/db/schema/contacts.js +16 -0
- package/dist/db/schema/discussions.d.ts +336 -0
- package/dist/db/schema/discussions.js +31 -0
- package/dist/db/schema/index.d.ts +8 -0
- package/dist/db/schema/index.js +8 -0
- package/dist/db/schema/messages.d.ts +309 -0
- package/dist/db/schema/messages.js +29 -0
- package/dist/db/schema/pendingAnnouncements.d.ts +79 -0
- package/dist/db/schema/pendingAnnouncements.js +11 -0
- package/dist/db/schema/pendingEncryptedMessages.d.ts +79 -0
- package/dist/db/schema/pendingEncryptedMessages.js +11 -0
- package/dist/db/schema/userProfile.d.ts +208 -0
- package/dist/db/schema/userProfile.js +20 -0
- package/dist/{sqlite-worker.js → db/sqlite-worker.js} +2 -30
- package/dist/db/sqlite.d.ts +77 -0
- package/dist/db/sqlite.js +254 -0
- package/dist/gossip.d.ts +1 -41
- package/dist/gossip.js +8 -10
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/services/announcement.js +1 -1
- package/dist/services/discussion.js +1 -1
- package/dist/services/message.d.ts +1 -1
- package/dist/services/message.js +2 -3
- package/dist/services/refresh.js +1 -1
- package/dist/utils/contacts.d.ts +11 -0
- package/dist/utils/contacts.js +30 -2
- package/dist/utils/discussions.d.ts +1 -1
- package/dist/utils/discussions.js +1 -1
- package/dist/utils/validation.js +1 -1
- package/package.json +2 -1
- package/dist/contacts.d.ts +0 -120
- package/dist/contacts.js +0 -160
- package/dist/queries/activeSeekers.d.ts +0 -2
- package/dist/schema.d.ts +0 -1280
- package/dist/schema.js +0 -164
- package/dist/sqlite.d.ts +0 -79
- package/dist/sqlite.js +0 -448
- /package/dist/{queries → db/queries}/announcementCursors.d.ts +0 -0
- /package/dist/{queries → db/queries}/announcementCursors.js +0 -0
- /package/dist/{queries → db/queries}/contacts.d.ts +0 -0
- /package/dist/{queries → db/queries}/contacts.js +0 -0
- /package/dist/{queries → db/queries}/discussions.d.ts +0 -0
- /package/dist/{queries → db/queries}/discussions.js +0 -0
- /package/dist/{queries → db/queries}/index.d.ts +0 -0
- /package/dist/{queries → db/queries}/index.js +0 -0
- /package/dist/{queries → db/queries}/pendingAnnouncements.d.ts +0 -0
- /package/dist/{queries → db/queries}/pendingAnnouncements.js +0 -0
- /package/dist/{sqlite-worker.d.ts → db/sqlite-worker.d.ts} +0 -0
package/dist/schema.js
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Drizzle ORM schema for the Gossip SDK database.
|
|
3
|
-
*
|
|
4
|
-
* IMPORTANT: The raw DDL in sqlite.ts must stay in sync with these definitions.
|
|
5
|
-
* When adding/removing/renaming columns, tables, or indexes, update BOTH files.
|
|
6
|
-
*
|
|
7
|
-
* Type mappings from SQLite:
|
|
8
|
-
* Date → integer (epoch milliseconds)
|
|
9
|
-
* boolean → integer (0/1)
|
|
10
|
-
* Uint8Array → blob (wa-sqlite handles natively)
|
|
11
|
-
* JSON → text (JSON.stringify/parse in service layer)
|
|
12
|
-
*/
|
|
13
|
-
import { sqliteTable, text, integer, index, uniqueIndex, customType, } from 'drizzle-orm/sqlite-core';
|
|
14
|
-
// Custom blob type — wa-sqlite returns Uint8Array natively for BLOB columns.
|
|
15
|
-
// Drizzle's built-in blob mode converts to/from hex strings, which breaks
|
|
16
|
-
// with wa-sqlite's direct Uint8Array handling. This custom type passes through.
|
|
17
|
-
const bytes = customType({
|
|
18
|
-
dataType() {
|
|
19
|
-
return 'blob';
|
|
20
|
-
},
|
|
21
|
-
fromDriver(value) {
|
|
22
|
-
return value;
|
|
23
|
-
},
|
|
24
|
-
toDriver(value) {
|
|
25
|
-
return value;
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
// contacts
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
export const contacts = sqliteTable('contacts', {
|
|
32
|
-
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
33
|
-
ownerUserId: text('ownerUserId').notNull(),
|
|
34
|
-
userId: text('userId').notNull(),
|
|
35
|
-
name: text('name').notNull(),
|
|
36
|
-
avatar: text('avatar'),
|
|
37
|
-
publicKeys: bytes('publicKeys').notNull(),
|
|
38
|
-
isOnline: integer('isOnline', { mode: 'boolean' }).notNull(),
|
|
39
|
-
lastSeen: integer('lastSeen', { mode: 'timestamp_ms' }).notNull(),
|
|
40
|
-
createdAt: integer('createdAt', { mode: 'timestamp_ms' }).notNull(),
|
|
41
|
-
}, table => [
|
|
42
|
-
index('contacts_owner_user_idx').on(table.ownerUserId, table.userId),
|
|
43
|
-
index('contacts_owner_name_idx').on(table.ownerUserId, table.name),
|
|
44
|
-
]);
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
|
-
// messages
|
|
47
|
-
// ---------------------------------------------------------------------------
|
|
48
|
-
export const messages = sqliteTable('messages', {
|
|
49
|
-
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
50
|
-
ownerUserId: text('ownerUserId').notNull(),
|
|
51
|
-
contactUserId: text('contactUserId').notNull(),
|
|
52
|
-
messageId: bytes('messageId'), // 12-byte random ID for deduplication
|
|
53
|
-
content: text('content').notNull(),
|
|
54
|
-
serializedContent: bytes('serializedContent'),
|
|
55
|
-
type: text('type').$type().notNull(),
|
|
56
|
-
direction: text('direction').$type().notNull(),
|
|
57
|
-
status: text('status').$type().notNull(),
|
|
58
|
-
timestamp: integer('timestamp', { mode: 'timestamp_ms' }).notNull(),
|
|
59
|
-
metadata: text('metadata'), // JSON — service layer handles stringify/parse
|
|
60
|
-
seeker: bytes('seeker'),
|
|
61
|
-
replyTo: text('replyTo'), // JSON — contains Uint8Array fields (base64 encoded)
|
|
62
|
-
forwardOf: text('forwardOf'), // JSON — contains Uint8Array fields (base64 encoded)
|
|
63
|
-
encryptedMessage: bytes('encryptedMessage'),
|
|
64
|
-
whenToSend: integer('whenToSend', { mode: 'timestamp_ms' }),
|
|
65
|
-
}, table => [
|
|
66
|
-
index('messages_owner_contact_idx').on(table.ownerUserId, table.contactUserId),
|
|
67
|
-
index('messages_owner_status_idx').on(table.ownerUserId, table.status),
|
|
68
|
-
index('messages_owner_contact_status_idx').on(table.ownerUserId, table.contactUserId, table.status),
|
|
69
|
-
index('messages_owner_seeker_idx').on(table.ownerUserId, table.seeker),
|
|
70
|
-
index('messages_owner_contact_dir_idx').on(table.ownerUserId, table.contactUserId, table.direction),
|
|
71
|
-
index('messages_owner_dir_status_idx').on(table.ownerUserId, table.direction, table.status),
|
|
72
|
-
index('messages_timestamp_idx').on(table.timestamp),
|
|
73
|
-
]);
|
|
74
|
-
// ---------------------------------------------------------------------------
|
|
75
|
-
// userProfile
|
|
76
|
-
// ---------------------------------------------------------------------------
|
|
77
|
-
export const userProfile = sqliteTable('userProfile', {
|
|
78
|
-
userId: text('userId').primaryKey(),
|
|
79
|
-
username: text('username').notNull(),
|
|
80
|
-
avatar: text('avatar'),
|
|
81
|
-
bio: text('bio'),
|
|
82
|
-
status: text('status').notNull(),
|
|
83
|
-
lastSeen: integer('lastSeen', { mode: 'timestamp_ms' }).notNull(),
|
|
84
|
-
createdAt: integer('createdAt', { mode: 'timestamp_ms' }).notNull(),
|
|
85
|
-
updatedAt: integer('updatedAt', { mode: 'timestamp_ms' }).notNull(),
|
|
86
|
-
lastPublicKeyPush: integer('lastPublicKeyPush', {
|
|
87
|
-
mode: 'timestamp_ms',
|
|
88
|
-
}),
|
|
89
|
-
security: text('security').notNull(), // JSON — contains Uint8Array fields (base64 encoded)
|
|
90
|
-
session: bytes('session').notNull(),
|
|
91
|
-
}, table => [
|
|
92
|
-
index('userProfile_username_idx').on(table.username),
|
|
93
|
-
index('userProfile_status_idx').on(table.status),
|
|
94
|
-
]);
|
|
95
|
-
// ---------------------------------------------------------------------------
|
|
96
|
-
// discussions
|
|
97
|
-
// ---------------------------------------------------------------------------
|
|
98
|
-
export const discussions = sqliteTable('discussions', {
|
|
99
|
-
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
100
|
-
ownerUserId: text('ownerUserId').notNull(),
|
|
101
|
-
contactUserId: text('contactUserId').notNull(),
|
|
102
|
-
weAccepted: integer('weAccepted', { mode: 'boolean' })
|
|
103
|
-
.notNull()
|
|
104
|
-
.default(false),
|
|
105
|
-
sendAnnouncement: text('sendAnnouncement'), // JSON — nullable
|
|
106
|
-
direction: text('direction').$type().notNull(),
|
|
107
|
-
status: text('status').$type().notNull(),
|
|
108
|
-
nextSeeker: bytes('nextSeeker'),
|
|
109
|
-
initiationAnnouncement: bytes('initiationAnnouncement'),
|
|
110
|
-
announcementMessage: text('announcementMessage'),
|
|
111
|
-
lastSyncTimestamp: integer('lastSyncTimestamp', {
|
|
112
|
-
mode: 'timestamp_ms',
|
|
113
|
-
}),
|
|
114
|
-
customName: text('customName'),
|
|
115
|
-
lastMessageId: integer('lastMessageId'),
|
|
116
|
-
lastMessageContent: text('lastMessageContent'),
|
|
117
|
-
lastMessageTimestamp: integer('lastMessageTimestamp', {
|
|
118
|
-
mode: 'timestamp_ms',
|
|
119
|
-
}),
|
|
120
|
-
unreadCount: integer('unreadCount').notNull().default(0),
|
|
121
|
-
createdAt: integer('createdAt', { mode: 'timestamp_ms' }).notNull(),
|
|
122
|
-
updatedAt: integer('updatedAt', { mode: 'timestamp_ms' }).notNull(),
|
|
123
|
-
}, table => [
|
|
124
|
-
uniqueIndex('discussions_owner_contact_idx').on(table.ownerUserId, table.contactUserId),
|
|
125
|
-
index('discussions_owner_status_idx').on(table.ownerUserId, table.status),
|
|
126
|
-
]);
|
|
127
|
-
// ---------------------------------------------------------------------------
|
|
128
|
-
// pendingEncryptedMessages
|
|
129
|
-
// ---------------------------------------------------------------------------
|
|
130
|
-
export const pendingEncryptedMessages = sqliteTable('pendingEncryptedMessages', {
|
|
131
|
-
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
132
|
-
seeker: bytes('seeker').notNull(),
|
|
133
|
-
ciphertext: bytes('ciphertext').notNull(),
|
|
134
|
-
fetchedAt: integer('fetchedAt', { mode: 'timestamp_ms' }).notNull(),
|
|
135
|
-
}, table => [
|
|
136
|
-
index('pending_encrypted_seeker_idx').on(table.seeker),
|
|
137
|
-
index('pending_encrypted_fetchedAt_idx').on(table.fetchedAt),
|
|
138
|
-
]);
|
|
139
|
-
// ---------------------------------------------------------------------------
|
|
140
|
-
// pendingAnnouncements
|
|
141
|
-
// ---------------------------------------------------------------------------
|
|
142
|
-
export const pendingAnnouncements = sqliteTable('pendingAnnouncements', {
|
|
143
|
-
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
144
|
-
announcement: bytes('announcement').notNull(),
|
|
145
|
-
fetchedAt: integer('fetchedAt', { mode: 'timestamp_ms' }).notNull(),
|
|
146
|
-
counter: text('counter'),
|
|
147
|
-
}, table => [
|
|
148
|
-
uniqueIndex('pending_announcements_announcement_idx').on(table.announcement),
|
|
149
|
-
index('pending_announcements_fetchedAt_idx').on(table.fetchedAt),
|
|
150
|
-
]);
|
|
151
|
-
// ---------------------------------------------------------------------------
|
|
152
|
-
// activeSeekers
|
|
153
|
-
// ---------------------------------------------------------------------------
|
|
154
|
-
export const activeSeekers = sqliteTable('activeSeekers', {
|
|
155
|
-
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
156
|
-
seeker: bytes('seeker').notNull(),
|
|
157
|
-
}, table => [index('active_seekers_seeker_idx').on(table.seeker)]);
|
|
158
|
-
// ---------------------------------------------------------------------------
|
|
159
|
-
// announcementCursors
|
|
160
|
-
// ---------------------------------------------------------------------------
|
|
161
|
-
export const announcementCursors = sqliteTable('announcementCursors', {
|
|
162
|
-
userId: text('userId').primaryKey(),
|
|
163
|
-
counter: text('counter').notNull(),
|
|
164
|
-
});
|
package/dist/sqlite.d.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SQLite initialization module for the Gossip SDK.
|
|
3
|
-
*
|
|
4
|
-
* Uses wa-sqlite (WASM) with Drizzle ORM's sqlite-proxy driver.
|
|
5
|
-
* Two execution paths:
|
|
6
|
-
* - Browser (opfsPath set): Web Worker + AccessHandlePoolVFS — OPFS persistence,
|
|
7
|
-
* off the main thread. Uses the sync WASM build (wa-sqlite).
|
|
8
|
-
* - In-memory (tests): :memory: in-process — no persistence, fast, isolated.
|
|
9
|
-
* Uses the sync WASM build with wasmBinary passed directly.
|
|
10
|
-
*
|
|
11
|
-
* In Phase C the VFS will be swapped for the encrypted PlausibleDeniableVFS.
|
|
12
|
-
*/
|
|
13
|
-
import { type SqliteRemoteDatabase } from 'drizzle-orm/sqlite-proxy';
|
|
14
|
-
import * as schema from './schema.js';
|
|
15
|
-
export type GossipDatabase = SqliteRemoteDatabase<typeof schema>;
|
|
16
|
-
export interface InitDbOptions {
|
|
17
|
-
/**
|
|
18
|
-
* OPFS directory path for persistent storage.
|
|
19
|
-
* When set, spawns a Web Worker with AccessHandlePoolVFS for OPFS persistence.
|
|
20
|
-
* When omitted, uses an in-memory database (for tests).
|
|
21
|
-
*/
|
|
22
|
-
opfsPath?: string;
|
|
23
|
-
/**
|
|
24
|
-
* Pre-loaded WASM binary for environments where fetch() is unavailable
|
|
25
|
-
* (e.g. Node.js tests). When omitted, the factory uses fetch() to load
|
|
26
|
-
* the .wasm file (browser default).
|
|
27
|
-
*/
|
|
28
|
-
wasmBinary?: ArrayBuffer;
|
|
29
|
-
/**
|
|
30
|
-
* URL to the wa-sqlite WASM file. Used in browser to tell the Emscripten
|
|
31
|
-
* factory where to fetch the WASM binary (needed when bundlers like Vite
|
|
32
|
-
* rewrite asset paths). When omitted, the factory uses its default path.
|
|
33
|
-
*/
|
|
34
|
-
wasmUrl?: string;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Initialize wa-sqlite and create the Drizzle ORM instance.
|
|
38
|
-
* Idempotent — subsequent calls are no-ops.
|
|
39
|
-
*
|
|
40
|
-
* @param options.opfsPath - Set to persist via OPFS Worker (production).
|
|
41
|
-
* Omit for in-memory database (tests).
|
|
42
|
-
*/
|
|
43
|
-
export declare function initDb(options?: InitDbOptions): Promise<void>;
|
|
44
|
-
/**
|
|
45
|
-
* Get the Drizzle ORM database instance.
|
|
46
|
-
* Throws if initDb() has not been called.
|
|
47
|
-
*/
|
|
48
|
-
export declare function getSqliteDb(): GossipDatabase;
|
|
49
|
-
export declare function isSqliteOpen(): boolean;
|
|
50
|
-
/**
|
|
51
|
-
* Run a callback inside a SQLite transaction (BEGIN / COMMIT / ROLLBACK).
|
|
52
|
-
* All Drizzle operations inside the callback share the same transaction
|
|
53
|
-
* and the same dbLock hold, so they cannot interleave with outside queries.
|
|
54
|
-
*/
|
|
55
|
-
export declare function withTransaction<T>(fn: () => Promise<T>): Promise<T>;
|
|
56
|
-
export declare function clearAllTables(): Promise<void>;
|
|
57
|
-
/**
|
|
58
|
-
* Clear only conversation-related tables (contacts, discussions, messages).
|
|
59
|
-
* Preserves user profiles and other data.
|
|
60
|
-
*/
|
|
61
|
-
export declare function clearConversationTables(): Promise<void>;
|
|
62
|
-
/**
|
|
63
|
-
* Get the last auto-increment row ID inserted via this connection.
|
|
64
|
-
* Used after INSERT into tables with INTEGER PRIMARY KEY AUTOINCREMENT.
|
|
65
|
-
*
|
|
66
|
-
* Browser path: returns the cached value from the last Worker exec response
|
|
67
|
-
* (returned atomically with every exec — no race condition).
|
|
68
|
-
* Test path: queries directly (same connection, serialized by dbLock).
|
|
69
|
-
*/
|
|
70
|
-
export declare function getLastInsertRowId(): Promise<number>;
|
|
71
|
-
/**
|
|
72
|
-
* Close the database and release all resources.
|
|
73
|
-
* Browser path: sends close to Worker, then terminates it.
|
|
74
|
-
* Test path: closes in-process database handle.
|
|
75
|
-
* Atomically resets all state by replacing with a fresh default.
|
|
76
|
-
*/
|
|
77
|
-
export declare function closeSqlite(): Promise<void>;
|
|
78
|
-
/** Exported for testing — the raw DDL string used to create tables. */
|
|
79
|
-
export declare const _DDL_FOR_TESTING = "\n CREATE TABLE IF NOT EXISTS contacts (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n ownerUserId TEXT NOT NULL,\n userId TEXT NOT NULL,\n name TEXT NOT NULL,\n avatar TEXT,\n publicKeys BLOB NOT NULL,\n isOnline INTEGER NOT NULL DEFAULT 0,\n lastSeen INTEGER NOT NULL,\n createdAt INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS messages (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n ownerUserId TEXT NOT NULL,\n contactUserId TEXT NOT NULL,\n messageId BLOB,\n content TEXT NOT NULL,\n serializedContent BLOB,\n type TEXT NOT NULL,\n direction TEXT NOT NULL,\n status TEXT NOT NULL,\n timestamp INTEGER NOT NULL,\n metadata TEXT,\n seeker BLOB,\n replyTo TEXT,\n forwardOf TEXT,\n encryptedMessage BLOB,\n whenToSend INTEGER\n );\n\n CREATE TABLE IF NOT EXISTS userProfile (\n userId TEXT PRIMARY KEY,\n username TEXT NOT NULL,\n avatar TEXT,\n bio TEXT,\n status TEXT NOT NULL,\n lastSeen INTEGER NOT NULL,\n createdAt INTEGER NOT NULL,\n updatedAt INTEGER NOT NULL,\n lastPublicKeyPush INTEGER,\n security TEXT NOT NULL,\n session BLOB NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS discussions (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n ownerUserId TEXT NOT NULL,\n contactUserId TEXT NOT NULL,\n direction TEXT NOT NULL,\n status TEXT NOT NULL,\n weAccepted INTEGER NOT NULL DEFAULT 0,\n sendAnnouncement TEXT,\n nextSeeker BLOB,\n initiationAnnouncement BLOB,\n announcementMessage TEXT,\n lastSyncTimestamp INTEGER,\n customName TEXT,\n lastMessageId INTEGER,\n lastMessageContent TEXT,\n lastMessageTimestamp INTEGER,\n unreadCount INTEGER NOT NULL DEFAULT 0,\n createdAt INTEGER NOT NULL,\n updatedAt INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS pendingEncryptedMessages (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n seeker BLOB NOT NULL,\n ciphertext BLOB NOT NULL,\n fetchedAt INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS pendingAnnouncements (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n announcement BLOB NOT NULL,\n fetchedAt INTEGER NOT NULL,\n counter TEXT\n );\n\n CREATE TABLE IF NOT EXISTS activeSeekers (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n seeker BLOB NOT NULL\n );\n\n -- Indexes: contacts\n CREATE INDEX IF NOT EXISTS contacts_owner_user_idx ON contacts(ownerUserId, userId);\n CREATE INDEX IF NOT EXISTS contacts_owner_name_idx ON contacts(ownerUserId, name);\n\n -- Indexes: messages\n CREATE INDEX IF NOT EXISTS messages_owner_contact_idx ON messages(ownerUserId, contactUserId);\n CREATE INDEX IF NOT EXISTS messages_owner_status_idx ON messages(ownerUserId, status);\n CREATE INDEX IF NOT EXISTS messages_owner_contact_status_idx ON messages(ownerUserId, contactUserId, status);\n CREATE INDEX IF NOT EXISTS messages_owner_seeker_idx ON messages(ownerUserId, seeker);\n CREATE INDEX IF NOT EXISTS messages_owner_contact_dir_idx ON messages(ownerUserId, contactUserId, direction);\n CREATE INDEX IF NOT EXISTS messages_owner_dir_status_idx ON messages(ownerUserId, direction, status);\n CREATE INDEX IF NOT EXISTS messages_timestamp_idx ON messages(timestamp);\n\n -- Indexes: userProfile\n CREATE INDEX IF NOT EXISTS userProfile_username_idx ON userProfile(username);\n CREATE INDEX IF NOT EXISTS userProfile_status_idx ON userProfile(status);\n\n -- Indexes: discussions\n CREATE UNIQUE INDEX IF NOT EXISTS discussions_owner_contact_idx ON discussions(ownerUserId, contactUserId);\n CREATE INDEX IF NOT EXISTS discussions_owner_status_idx ON discussions(ownerUserId, status);\n\n -- Indexes: pendingEncryptedMessages\n CREATE INDEX IF NOT EXISTS pending_encrypted_seeker_idx ON pendingEncryptedMessages(seeker);\n CREATE INDEX IF NOT EXISTS pending_encrypted_fetchedAt_idx ON pendingEncryptedMessages(fetchedAt);\n\n -- Indexes: pendingAnnouncements\n CREATE UNIQUE INDEX IF NOT EXISTS pending_announcements_announcement_idx ON pendingAnnouncements(announcement);\n CREATE INDEX IF NOT EXISTS pending_announcements_fetchedAt_idx ON pendingAnnouncements(fetchedAt);\n\n -- Indexes: activeSeekers\n CREATE INDEX IF NOT EXISTS active_seekers_seeker_idx ON activeSeekers(seeker);\n\n CREATE TABLE IF NOT EXISTS announcementCursors (\n userId TEXT PRIMARY KEY,\n counter TEXT NOT NULL\n );\n";
|