@rei-standard/amsg-server 2.6.0-next.2 → 2.6.0-next.21

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.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +599 -24
  3. package/dist/adapters/d1.d.ts +416 -0
  4. package/dist/adapters/factory.d.ts +39 -0
  5. package/dist/adapters/interface.d.ts +306 -0
  6. package/dist/adapters/neon.d.ts +88 -0
  7. package/dist/adapters/pg-shared.d.ts +161 -0
  8. package/dist/adapters/pg.d.ts +84 -0
  9. package/dist/adapters/schema.d.ts +57 -0
  10. package/dist/adapters/schema.sqlite.d.ts +49 -0
  11. package/dist/chunk-7NMQFTDJ.cjs +148 -0
  12. package/dist/chunk-E7OWP3VL.cjs +135 -0
  13. package/dist/chunk-GN44PST5.mjs +148 -0
  14. package/dist/chunk-KOJQVOYS.mjs +5847 -0
  15. package/dist/chunk-QHVID3V2.cjs +5847 -0
  16. package/dist/chunk-ZGGF4GMA.mjs +135 -0
  17. package/dist/cloudflare/single-user-worker.d.ts +37 -0
  18. package/dist/cloudflare.cjs +39 -2
  19. package/dist/cloudflare.d.ts +10 -2
  20. package/dist/cloudflare.mjs +40 -3
  21. package/dist/handlers/cancel-message.d.ts +3 -0
  22. package/dist/handlers/capabilities.d.ts +4 -0
  23. package/dist/handlers/client-state.d.ts +7 -0
  24. package/dist/handlers/get-message.d.ts +3 -0
  25. package/dist/handlers/get-user-key.d.ts +3 -0
  26. package/dist/handlers/init-tenant.d.ts +23 -0
  27. package/dist/handlers/llm-credentials.d.ts +5 -0
  28. package/dist/handlers/messages.d.ts +3 -0
  29. package/dist/handlers/outbox.d.ts +7 -0
  30. package/dist/handlers/push-subscription.d.ts +5 -0
  31. package/dist/handlers/schedule-message.d.ts +3 -0
  32. package/dist/handlers/send-notifications.d.ts +3 -0
  33. package/dist/handlers/single-user-init.d.ts +13 -0
  34. package/dist/handlers/update-message.d.ts +3 -0
  35. package/dist/handlers/vapid-public-key.d.ts +19 -0
  36. package/dist/index.cjs +133 -44
  37. package/dist/index.d.cts +131 -766
  38. package/dist/index.d.ts +131 -766
  39. package/dist/index.mjs +125 -36
  40. package/dist/lib/agentic-fire.d.ts +108 -0
  41. package/dist/lib/client-state-store.d.ts +80 -0
  42. package/dist/lib/constant-time.d.ts +14 -0
  43. package/dist/lib/db-errors.d.ts +10 -0
  44. package/dist/lib/encryption.d.ts +48 -0
  45. package/dist/lib/errors.d.ts +215 -0
  46. package/dist/lib/llm-credentials-store.d.ts +147 -0
  47. package/dist/lib/llm.d.ts +1 -0
  48. package/dist/lib/message-processor.d.ts +73 -0
  49. package/dist/lib/outbox-store.d.ts +95 -0
  50. package/dist/lib/push-subscription-store.d.ts +94 -0
  51. package/dist/lib/recurrence.d.ts +51 -0
  52. package/dist/lib/request.d.ts +182 -0
  53. package/dist/lib/result-emitter.d.ts +54 -0
  54. package/dist/lib/run-tick.d.ts +115 -0
  55. package/dist/lib/schema-version.d.ts +50 -0
  56. package/dist/lib/state-accessors.d.ts +70 -0
  57. package/dist/lib/state-chunks.d.ts +55 -0
  58. package/dist/lib/task-projection.d.ts +92 -0
  59. package/dist/lib/validation.d.ts +97 -0
  60. package/dist/lib/version.d.ts +7 -0
  61. package/dist/lib/webcrypto-utils.d.ts +1 -0
  62. package/dist/lib/webpush-webcrypto.d.ts +78 -0
  63. package/dist/{neon-BFUS25UX.cjs → neon-KP2CPA57.cjs} +110 -10
  64. package/dist/{neon-CU5N3CSW.mjs → neon-ZIMHALYI.mjs} +106 -6
  65. package/dist/{pg-QO6NKTGL.mjs → pg-QGC2XHUT.mjs} +94 -5
  66. package/dist/{pg-IIH3M4OM.cjs → pg-RZPQGXR3.cjs} +98 -9
  67. package/dist/single-user.d.ts +95 -0
  68. package/dist/tenant/blob-store.d.ts +30 -0
  69. package/dist/tenant/context.d.ts +47 -0
  70. package/dist/tenant/single-user-context.d.ts +29 -0
  71. package/dist/tenant/token.d.ts +26 -0
  72. package/package.json +3 -3
  73. package/dist/chunk-5ENJGVZX.mjs +0 -72
  74. package/dist/chunk-GN5QTMCL.cjs +0 -1870
  75. package/dist/chunk-PVNLB6TF.mjs +0 -1870
  76. package/dist/chunk-RGECD4OH.cjs +0 -72
  77. package/dist/cloudflare-B-E51VjP.d.cts +0 -2848
  78. package/dist/cloudflare-B-E51VjP.d.ts +0 -2848
  79. package/dist/cloudflare.d.cts +0 -2
  80. package/dist/neon-CJl66EGy.d.cts +0 -251
  81. package/dist/neon-DYvGnCzx.d.ts +0 -251
  82. package/dist/pg-07S-u_H4.d.cts +0 -246
  83. package/dist/pg-Du-pN_UT.d.ts +0 -246
  84. package/dist/schema-C8OnYk6j.d.cts +0 -74
  85. package/dist/schema-C8OnYk6j.d.ts +0 -74
@@ -1,246 +0,0 @@
1
- import { Pool } from 'pg';
2
- import { T as TABLE_SQL, I as INDEXES, V as VERIFY_TABLE_SQL, C as COLUMNS_SQL } from './schema-C8OnYk6j.cjs';
3
-
4
- /**
5
- * PostgreSQL (pg) Database Adapter
6
- * ReiStandard SDK v2.0.1
7
- *
8
- * Uses the standard 'pg' npm package.
9
- *
10
- * @implements {import('./interface.js').DbAdapter}
11
- */
12
-
13
-
14
- class PgAdapter {
15
- /** @param {string} connectionString */
16
- constructor(connectionString) {
17
- /** @private */
18
- this._connectionString = connectionString;
19
- /** @private */
20
- this._pool = null;
21
- }
22
-
23
- /** @private */
24
- _getPool() {
25
- if (!this._pool) {
26
- this._pool = new Pool({ connectionString: this._connectionString });
27
- }
28
- return this._pool;
29
- }
30
-
31
- /** @private */
32
- async _query(text, params) {
33
- const pool = this._getPool();
34
- const result = await pool.query(text, params);
35
- return result.rows;
36
- }
37
-
38
- async initSchema() {
39
- await this._query(TABLE_SQL);
40
- const indexResults = [];
41
- for (const index of INDEXES) {
42
- try {
43
- await this._query(index.sql);
44
- indexResults.push({
45
- name: index.name,
46
- status: 'success',
47
- description: index.description,
48
- critical: !!index.critical
49
- });
50
- } catch (error) {
51
- indexResults.push({
52
- name: index.name,
53
- status: 'failed',
54
- description: index.description,
55
- critical: !!index.critical,
56
- error: error.message
57
- });
58
- }
59
- }
60
-
61
- const criticalFailures = indexResults.filter((index) => index.critical && index.status === 'failed');
62
- if (criticalFailures.length > 0) {
63
- const failedNames = criticalFailures.map((index) => index.name).join(', ');
64
- throw new Error(
65
- `Critical index creation failed (${failedNames}). ` +
66
- 'Please remove duplicate UUID rows and run initSchema again.'
67
- );
68
- }
69
-
70
- const tableCheck = await this._query(VERIFY_TABLE_SQL);
71
- if (tableCheck.length === 0) {
72
- throw new Error('Table creation verification failed');
73
- }
74
- const columns = await this._query(COLUMNS_SQL);
75
- return {
76
- columnsCreated: columns.length,
77
- indexesCreated: indexResults.filter(r => r.status === 'success').length,
78
- indexesFailed: indexResults.filter(r => r.status === 'failed').length,
79
- columns: [
80
- ...columns.map(c => ({ table: 'scheduled_messages', name: c.column_name, type: c.data_type, nullable: c.is_nullable === 'YES' }))
81
- ],
82
- indexes: indexResults
83
- };
84
- }
85
-
86
- async dropSchema() {
87
- await this._query('DROP TABLE IF EXISTS scheduled_messages CASCADE');
88
- }
89
-
90
- async createTask(params) {
91
- const rows = await this._query(
92
- `INSERT INTO scheduled_messages
93
- (user_id, uuid, encrypted_payload, next_send_at, message_type, status, retry_count, created_at, updated_at)
94
- VALUES ($1, $2, $3, $4, $5, 'pending', 0, NOW(), NOW())
95
- RETURNING id, uuid, next_send_at, status, created_at`,
96
- [params.user_id, params.uuid, params.encrypted_payload, params.next_send_at, params.message_type]
97
- );
98
- return rows[0] || null;
99
- }
100
-
101
- async getTaskByUuid(uuid, userId) {
102
- const rows = await this._query(
103
- `SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count
104
- FROM scheduled_messages
105
- WHERE uuid = $1 AND user_id = $2 AND status = 'pending'
106
- LIMIT 1`,
107
- [uuid, userId]
108
- );
109
- return rows[0] || null;
110
- }
111
-
112
- async getTaskByUuidOnly(uuid) {
113
- const rows = await this._query(
114
- `SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count
115
- FROM scheduled_messages
116
- WHERE uuid = $1 AND status = 'pending'
117
- LIMIT 1`,
118
- [uuid]
119
- );
120
- return rows[0] || null;
121
- }
122
-
123
- async updateTaskById(taskId, updates) {
124
- const sets = [];
125
- const values = [];
126
- let idx = 1;
127
-
128
- for (const [key, value] of Object.entries(updates)) {
129
- sets.push(`${key} = $${idx}`);
130
- values.push(value);
131
- idx++;
132
- }
133
-
134
- sets.push('updated_at = NOW()');
135
- values.push(taskId);
136
-
137
- const rows = await this._query(
138
- `UPDATE scheduled_messages SET ${sets.join(', ')} WHERE id = $${idx} RETURNING *`,
139
- values
140
- );
141
- return rows[0] || null;
142
- }
143
-
144
- async updateTaskByUuid(uuid, userId, encryptedPayload, extraFields) {
145
- const sets = ['encrypted_payload = $1', 'updated_at = NOW()'];
146
- const values = [encryptedPayload];
147
- let idx = 2;
148
-
149
- if (extraFields) {
150
- for (const [key, value] of Object.entries(extraFields)) {
151
- sets.push(`${key} = $${idx}`);
152
- values.push(value);
153
- idx++;
154
- }
155
- }
156
-
157
- values.push(uuid, userId);
158
- const rows = await this._query(
159
- `UPDATE scheduled_messages SET ${sets.join(', ')}
160
- WHERE uuid = $${idx} AND user_id = $${idx + 1} AND status = 'pending'
161
- RETURNING uuid, updated_at`,
162
- values
163
- );
164
- return rows[0] || null;
165
- }
166
-
167
- async deleteTaskById(taskId) {
168
- const rows = await this._query('DELETE FROM scheduled_messages WHERE id = $1 RETURNING id', [taskId]);
169
- return rows.length > 0;
170
- }
171
-
172
- async deleteTaskByUuid(uuid, userId) {
173
- const rows = await this._query(
174
- 'DELETE FROM scheduled_messages WHERE uuid = $1 AND user_id = $2 RETURNING id',
175
- [uuid, userId]
176
- );
177
- return rows.length > 0;
178
- }
179
-
180
- async getPendingTasks(limit = 50) {
181
- return this._query(
182
- `SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count
183
- FROM scheduled_messages
184
- WHERE status = 'pending' AND next_send_at <= NOW()
185
- ORDER BY next_send_at ASC
186
- LIMIT $1`,
187
- [limit]
188
- );
189
- }
190
-
191
- async listTasks(userId, opts = {}) {
192
- const { status = 'all', limit = 20, offset = 0 } = opts;
193
-
194
- const conditions = ['user_id = $1'];
195
- const params = [userId];
196
- let idx = 2;
197
-
198
- if (status !== 'all') {
199
- conditions.push(`status = $${idx}`);
200
- params.push(status);
201
- idx++;
202
- }
203
-
204
- const where = conditions.join(' AND ');
205
-
206
- const countRows = await this._query(
207
- `SELECT COUNT(*) as count FROM scheduled_messages WHERE ${where}`,
208
- params
209
- );
210
- const total = parseInt(countRows[0].count, 10);
211
-
212
- const taskParams = [...params, limit, offset];
213
- const tasks = await this._query(
214
- `SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count, created_at, updated_at
215
- FROM scheduled_messages
216
- WHERE ${where}
217
- ORDER BY next_send_at ASC
218
- LIMIT $${idx} OFFSET $${idx + 1}`,
219
- taskParams
220
- );
221
-
222
- return { tasks, total };
223
- }
224
-
225
- async cleanupOldTasks(days = 7) {
226
- const safeDays = Math.max(1, Math.floor(Number(days)));
227
- const rows = await this._query(
228
- `DELETE FROM scheduled_messages
229
- WHERE status IN ('sent', 'failed')
230
- AND updated_at < NOW() - make_interval(days => $1)
231
- RETURNING id`,
232
- [safeDays]
233
- );
234
- return rows.length;
235
- }
236
-
237
- async getTaskStatus(uuid, userId) {
238
- const rows = await this._query(
239
- 'SELECT status FROM scheduled_messages WHERE uuid = $1 AND user_id = $2 LIMIT 1',
240
- [uuid, userId]
241
- );
242
- return rows.length > 0 ? rows[0].status : null;
243
- }
244
- }
245
-
246
- export { PgAdapter };
@@ -1,246 +0,0 @@
1
- import { Pool } from 'pg';
2
- import { T as TABLE_SQL, I as INDEXES, V as VERIFY_TABLE_SQL, C as COLUMNS_SQL } from './schema-C8OnYk6j.js';
3
-
4
- /**
5
- * PostgreSQL (pg) Database Adapter
6
- * ReiStandard SDK v2.0.1
7
- *
8
- * Uses the standard 'pg' npm package.
9
- *
10
- * @implements {import('./interface.js').DbAdapter}
11
- */
12
-
13
-
14
- class PgAdapter {
15
- /** @param {string} connectionString */
16
- constructor(connectionString) {
17
- /** @private */
18
- this._connectionString = connectionString;
19
- /** @private */
20
- this._pool = null;
21
- }
22
-
23
- /** @private */
24
- _getPool() {
25
- if (!this._pool) {
26
- this._pool = new Pool({ connectionString: this._connectionString });
27
- }
28
- return this._pool;
29
- }
30
-
31
- /** @private */
32
- async _query(text, params) {
33
- const pool = this._getPool();
34
- const result = await pool.query(text, params);
35
- return result.rows;
36
- }
37
-
38
- async initSchema() {
39
- await this._query(TABLE_SQL);
40
- const indexResults = [];
41
- for (const index of INDEXES) {
42
- try {
43
- await this._query(index.sql);
44
- indexResults.push({
45
- name: index.name,
46
- status: 'success',
47
- description: index.description,
48
- critical: !!index.critical
49
- });
50
- } catch (error) {
51
- indexResults.push({
52
- name: index.name,
53
- status: 'failed',
54
- description: index.description,
55
- critical: !!index.critical,
56
- error: error.message
57
- });
58
- }
59
- }
60
-
61
- const criticalFailures = indexResults.filter((index) => index.critical && index.status === 'failed');
62
- if (criticalFailures.length > 0) {
63
- const failedNames = criticalFailures.map((index) => index.name).join(', ');
64
- throw new Error(
65
- `Critical index creation failed (${failedNames}). ` +
66
- 'Please remove duplicate UUID rows and run initSchema again.'
67
- );
68
- }
69
-
70
- const tableCheck = await this._query(VERIFY_TABLE_SQL);
71
- if (tableCheck.length === 0) {
72
- throw new Error('Table creation verification failed');
73
- }
74
- const columns = await this._query(COLUMNS_SQL);
75
- return {
76
- columnsCreated: columns.length,
77
- indexesCreated: indexResults.filter(r => r.status === 'success').length,
78
- indexesFailed: indexResults.filter(r => r.status === 'failed').length,
79
- columns: [
80
- ...columns.map(c => ({ table: 'scheduled_messages', name: c.column_name, type: c.data_type, nullable: c.is_nullable === 'YES' }))
81
- ],
82
- indexes: indexResults
83
- };
84
- }
85
-
86
- async dropSchema() {
87
- await this._query('DROP TABLE IF EXISTS scheduled_messages CASCADE');
88
- }
89
-
90
- async createTask(params) {
91
- const rows = await this._query(
92
- `INSERT INTO scheduled_messages
93
- (user_id, uuid, encrypted_payload, next_send_at, message_type, status, retry_count, created_at, updated_at)
94
- VALUES ($1, $2, $3, $4, $5, 'pending', 0, NOW(), NOW())
95
- RETURNING id, uuid, next_send_at, status, created_at`,
96
- [params.user_id, params.uuid, params.encrypted_payload, params.next_send_at, params.message_type]
97
- );
98
- return rows[0] || null;
99
- }
100
-
101
- async getTaskByUuid(uuid, userId) {
102
- const rows = await this._query(
103
- `SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count
104
- FROM scheduled_messages
105
- WHERE uuid = $1 AND user_id = $2 AND status = 'pending'
106
- LIMIT 1`,
107
- [uuid, userId]
108
- );
109
- return rows[0] || null;
110
- }
111
-
112
- async getTaskByUuidOnly(uuid) {
113
- const rows = await this._query(
114
- `SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count
115
- FROM scheduled_messages
116
- WHERE uuid = $1 AND status = 'pending'
117
- LIMIT 1`,
118
- [uuid]
119
- );
120
- return rows[0] || null;
121
- }
122
-
123
- async updateTaskById(taskId, updates) {
124
- const sets = [];
125
- const values = [];
126
- let idx = 1;
127
-
128
- for (const [key, value] of Object.entries(updates)) {
129
- sets.push(`${key} = $${idx}`);
130
- values.push(value);
131
- idx++;
132
- }
133
-
134
- sets.push('updated_at = NOW()');
135
- values.push(taskId);
136
-
137
- const rows = await this._query(
138
- `UPDATE scheduled_messages SET ${sets.join(', ')} WHERE id = $${idx} RETURNING *`,
139
- values
140
- );
141
- return rows[0] || null;
142
- }
143
-
144
- async updateTaskByUuid(uuid, userId, encryptedPayload, extraFields) {
145
- const sets = ['encrypted_payload = $1', 'updated_at = NOW()'];
146
- const values = [encryptedPayload];
147
- let idx = 2;
148
-
149
- if (extraFields) {
150
- for (const [key, value] of Object.entries(extraFields)) {
151
- sets.push(`${key} = $${idx}`);
152
- values.push(value);
153
- idx++;
154
- }
155
- }
156
-
157
- values.push(uuid, userId);
158
- const rows = await this._query(
159
- `UPDATE scheduled_messages SET ${sets.join(', ')}
160
- WHERE uuid = $${idx} AND user_id = $${idx + 1} AND status = 'pending'
161
- RETURNING uuid, updated_at`,
162
- values
163
- );
164
- return rows[0] || null;
165
- }
166
-
167
- async deleteTaskById(taskId) {
168
- const rows = await this._query('DELETE FROM scheduled_messages WHERE id = $1 RETURNING id', [taskId]);
169
- return rows.length > 0;
170
- }
171
-
172
- async deleteTaskByUuid(uuid, userId) {
173
- const rows = await this._query(
174
- 'DELETE FROM scheduled_messages WHERE uuid = $1 AND user_id = $2 RETURNING id',
175
- [uuid, userId]
176
- );
177
- return rows.length > 0;
178
- }
179
-
180
- async getPendingTasks(limit = 50) {
181
- return this._query(
182
- `SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count
183
- FROM scheduled_messages
184
- WHERE status = 'pending' AND next_send_at <= NOW()
185
- ORDER BY next_send_at ASC
186
- LIMIT $1`,
187
- [limit]
188
- );
189
- }
190
-
191
- async listTasks(userId, opts = {}) {
192
- const { status = 'all', limit = 20, offset = 0 } = opts;
193
-
194
- const conditions = ['user_id = $1'];
195
- const params = [userId];
196
- let idx = 2;
197
-
198
- if (status !== 'all') {
199
- conditions.push(`status = $${idx}`);
200
- params.push(status);
201
- idx++;
202
- }
203
-
204
- const where = conditions.join(' AND ');
205
-
206
- const countRows = await this._query(
207
- `SELECT COUNT(*) as count FROM scheduled_messages WHERE ${where}`,
208
- params
209
- );
210
- const total = parseInt(countRows[0].count, 10);
211
-
212
- const taskParams = [...params, limit, offset];
213
- const tasks = await this._query(
214
- `SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count, created_at, updated_at
215
- FROM scheduled_messages
216
- WHERE ${where}
217
- ORDER BY next_send_at ASC
218
- LIMIT $${idx} OFFSET $${idx + 1}`,
219
- taskParams
220
- );
221
-
222
- return { tasks, total };
223
- }
224
-
225
- async cleanupOldTasks(days = 7) {
226
- const safeDays = Math.max(1, Math.floor(Number(days)));
227
- const rows = await this._query(
228
- `DELETE FROM scheduled_messages
229
- WHERE status IN ('sent', 'failed')
230
- AND updated_at < NOW() - make_interval(days => $1)
231
- RETURNING id`,
232
- [safeDays]
233
- );
234
- return rows.length;
235
- }
236
-
237
- async getTaskStatus(uuid, userId) {
238
- const rows = await this._query(
239
- 'SELECT status FROM scheduled_messages WHERE uuid = $1 AND user_id = $2 LIMIT 1',
240
- [uuid, userId]
241
- );
242
- return rows.length > 0 ? rows[0].status : null;
243
- }
244
- }
245
-
246
- export { PgAdapter };
@@ -1,74 +0,0 @@
1
- /**
2
- * Shared SQL schema constants
3
- * ReiStandard SDK v2.0.1
4
- */
5
-
6
- const TABLE_SQL = `
7
- CREATE TABLE IF NOT EXISTS scheduled_messages (
8
- id SERIAL PRIMARY KEY,
9
- user_id VARCHAR(255) NOT NULL,
10
- uuid VARCHAR(36),
11
- encrypted_payload TEXT NOT NULL,
12
- message_type VARCHAR(50) NOT NULL CHECK (message_type IN ('fixed', 'prompted', 'auto', 'instant')),
13
- next_send_at TIMESTAMP WITH TIME ZONE NOT NULL,
14
- status VARCHAR(50) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'sent', 'failed')),
15
- retry_count INTEGER DEFAULT 0,
16
- created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
17
- updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
18
- )
19
- `;
20
-
21
- const INDEXES = [
22
- {
23
- name: 'idx_pending_tasks_optimized',
24
- sql: `CREATE INDEX IF NOT EXISTS idx_pending_tasks_optimized
25
- ON scheduled_messages (status, next_send_at, id, retry_count)
26
- WHERE status = 'pending'`,
27
- description: 'Main query index (Cron Job finds pending tasks)'
28
- },
29
- {
30
- name: 'idx_cleanup_completed',
31
- sql: `CREATE INDEX IF NOT EXISTS idx_cleanup_completed
32
- ON scheduled_messages (status, updated_at)
33
- WHERE status IN ('sent', 'failed')`,
34
- description: 'Cleanup query index'
35
- },
36
- {
37
- name: 'idx_failed_retry',
38
- sql: `CREATE INDEX IF NOT EXISTS idx_failed_retry
39
- ON scheduled_messages (status, retry_count, next_send_at)
40
- WHERE status = 'failed' AND retry_count < 3`,
41
- description: 'Failed retry index'
42
- },
43
- {
44
- name: 'idx_user_id',
45
- sql: `CREATE INDEX IF NOT EXISTS idx_user_id
46
- ON scheduled_messages (user_id)`,
47
- description: 'User task query index'
48
- },
49
- {
50
- name: 'uidx_uuid',
51
- sql: `CREATE UNIQUE INDEX IF NOT EXISTS uidx_uuid
52
- ON scheduled_messages (uuid)
53
- WHERE uuid IS NOT NULL`,
54
- description: 'UUID uniqueness guard',
55
- critical: true
56
- }
57
- ];
58
-
59
- const VERIFY_TABLE_SQL = `
60
- SELECT table_name
61
- FROM information_schema.tables
62
- WHERE table_schema = 'public'
63
- AND table_name = 'scheduled_messages'
64
- `;
65
-
66
- const COLUMNS_SQL = `
67
- SELECT column_name, data_type, is_nullable
68
- FROM information_schema.columns
69
- WHERE table_schema = 'public'
70
- AND table_name = 'scheduled_messages'
71
- ORDER BY ordinal_position
72
- `;
73
-
74
- export { COLUMNS_SQL as C, INDEXES as I, TABLE_SQL as T, VERIFY_TABLE_SQL as V };
@@ -1,74 +0,0 @@
1
- /**
2
- * Shared SQL schema constants
3
- * ReiStandard SDK v2.0.1
4
- */
5
-
6
- const TABLE_SQL = `
7
- CREATE TABLE IF NOT EXISTS scheduled_messages (
8
- id SERIAL PRIMARY KEY,
9
- user_id VARCHAR(255) NOT NULL,
10
- uuid VARCHAR(36),
11
- encrypted_payload TEXT NOT NULL,
12
- message_type VARCHAR(50) NOT NULL CHECK (message_type IN ('fixed', 'prompted', 'auto', 'instant')),
13
- next_send_at TIMESTAMP WITH TIME ZONE NOT NULL,
14
- status VARCHAR(50) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'sent', 'failed')),
15
- retry_count INTEGER DEFAULT 0,
16
- created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
17
- updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
18
- )
19
- `;
20
-
21
- const INDEXES = [
22
- {
23
- name: 'idx_pending_tasks_optimized',
24
- sql: `CREATE INDEX IF NOT EXISTS idx_pending_tasks_optimized
25
- ON scheduled_messages (status, next_send_at, id, retry_count)
26
- WHERE status = 'pending'`,
27
- description: 'Main query index (Cron Job finds pending tasks)'
28
- },
29
- {
30
- name: 'idx_cleanup_completed',
31
- sql: `CREATE INDEX IF NOT EXISTS idx_cleanup_completed
32
- ON scheduled_messages (status, updated_at)
33
- WHERE status IN ('sent', 'failed')`,
34
- description: 'Cleanup query index'
35
- },
36
- {
37
- name: 'idx_failed_retry',
38
- sql: `CREATE INDEX IF NOT EXISTS idx_failed_retry
39
- ON scheduled_messages (status, retry_count, next_send_at)
40
- WHERE status = 'failed' AND retry_count < 3`,
41
- description: 'Failed retry index'
42
- },
43
- {
44
- name: 'idx_user_id',
45
- sql: `CREATE INDEX IF NOT EXISTS idx_user_id
46
- ON scheduled_messages (user_id)`,
47
- description: 'User task query index'
48
- },
49
- {
50
- name: 'uidx_uuid',
51
- sql: `CREATE UNIQUE INDEX IF NOT EXISTS uidx_uuid
52
- ON scheduled_messages (uuid)
53
- WHERE uuid IS NOT NULL`,
54
- description: 'UUID uniqueness guard',
55
- critical: true
56
- }
57
- ];
58
-
59
- const VERIFY_TABLE_SQL = `
60
- SELECT table_name
61
- FROM information_schema.tables
62
- WHERE table_schema = 'public'
63
- AND table_name = 'scheduled_messages'
64
- `;
65
-
66
- const COLUMNS_SQL = `
67
- SELECT column_name, data_type, is_nullable
68
- FROM information_schema.columns
69
- WHERE table_schema = 'public'
70
- AND table_name = 'scheduled_messages'
71
- ORDER BY ordinal_position
72
- `;
73
-
74
- export { COLUMNS_SQL as C, INDEXES as I, TABLE_SQL as T, VERIFY_TABLE_SQL as V };