ugly-app 0.1.200 → 0.1.202

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.
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.200";
1
+ export declare const CLI_VERSION = "0.1.202";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.200";
2
+ export const CLI_VERSION = "0.1.202";
3
3
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PostgresOperators.d.ts","sourceRoot":"","sources":["../../src/server/PostgresOperators.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,UAAU,QAAQ;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AA2ED,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,QAAQ,GACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CA4BzC"}
1
+ {"version":3,"file":"PostgresOperators.d.ts","sourceRoot":"","sources":["../../src/server/PostgresOperators.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,UAAU,QAAQ;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AA6ED,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,QAAQ,GACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CA4BzC"}
@@ -27,10 +27,12 @@ function buildUpdateExpression(op) {
27
27
  expr = `(${expr}) - '${field}'`;
28
28
  }
29
29
  else {
30
- // For nested: remove the last key from the parent path
30
+ // For nested: remove the last key from the parent path.
31
+ // COALESCE guards against NULL when the parent path doesn't exist,
32
+ // which would cause jsonb_set to return NULL and violate NOT NULL.
31
33
  const parentPath = toPathArray(parts.slice(0, -1).join('.'));
32
34
  const lastKey = parts[parts.length - 1];
33
- expr = `jsonb_set(${expr}, '${parentPath}', (${expr}#>'${parentPath}') - '${lastKey}')`;
35
+ expr = `jsonb_set(${expr}, '${parentPath}', COALESCE((${expr}#>'${parentPath}') - '${lastKey}', '{}'::jsonb))`;
34
36
  }
35
37
  }
36
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PostgresOperators.js","sourceRoot":"","sources":["../../src/server/PostgresOperators.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PostgresOperators.js","sourceRoot":"","sources":["../../src/server/PostgresOperators.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"WorkerQueue.d.ts","sourceRoot":"","sources":["../../src/server/WorkerQueue.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,OAAO;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,IAAI,CAAC;IACpB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAEhC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,GAAE,iBAAsB,EAE9B,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,GAChB,WAAW,GAAG;IACf,OAAO,CAAC,CAAC,EACP,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAChE,CA+OA"}
1
+ {"version":3,"file":"WorkerQueue.d.ts","sourceRoot":"","sources":["../../src/server/WorkerQueue.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,OAAO;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,IAAI,CAAC;IACpB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAEhC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,GAAE,iBAAsB,EAE9B,EAAE,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,GAChB,WAAW,GAAG;IACf,OAAO,CAAC,CAAC,EACP,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,EACV,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAChE,CA4PA"}
@@ -1,6 +1,6 @@
1
1
  import { AckPolicy, DeliverPolicy } from 'nats';
2
2
  import { BUILTIN_DEFS, dbDefaults } from '../shared/DB.js';
3
- import { ensureStream, getJetStream, getNatsConnection } from './Nats.js';
3
+ import { ensureStream, getJetStream, getNatsConnection, getNatsPrefix } from './Nats.js';
4
4
  export function createWorkerQueue(config = {},
5
5
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
6
  db) {
@@ -9,9 +9,19 @@ db) {
9
9
  let subscription = null;
10
10
  let dispatchInterval = null;
11
11
  const isClockServer = process.env['IS_CLOCK_SERVER'] === 'true';
12
+ /** Returns the prefixed stream name matching what ensureStream creates. */
13
+ function prefixedStreamName() {
14
+ const p = getNatsPrefix();
15
+ return p ? `${p}_${streamName}` : streamName;
16
+ }
17
+ /** Returns the prefixed subject for a job type. */
18
+ function prefixedSubject(type) {
19
+ const p = getNatsPrefix();
20
+ return p ? `${p}.${streamName}.${type}` : `${streamName}.${type}`;
21
+ }
12
22
  async function publishJob(job) {
13
23
  const js = await getJetStream();
14
- const subject = `${streamName}.${job.type}`;
24
+ const subject = prefixedSubject(job.type);
15
25
  await js.publish(subject, new TextEncoder().encode(JSON.stringify(job)));
16
26
  console.log('[WorkerQueue] Job enqueued', { id: job.id, type: job.type });
17
27
  }
@@ -107,23 +117,24 @@ db) {
107
117
  name: streamName,
108
118
  subjects: [`${streamName}.*`],
109
119
  });
120
+ const fullStreamName = prefixedStreamName();
110
121
  const js = await getJetStream();
111
122
  const conn = getNatsConnection();
112
123
  const jsm = await conn.jetstreamManager();
113
124
  // Create or get durable consumer
114
125
  const consumerName = `worker-${process.env['HOSTNAME'] ?? 'local'}`;
115
126
  try {
116
- await jsm.consumers.info(streamName, consumerName);
127
+ await jsm.consumers.info(fullStreamName, consumerName);
117
128
  }
118
129
  catch {
119
- await jsm.consumers.add(streamName, {
130
+ await jsm.consumers.add(fullStreamName, {
120
131
  durable_name: consumerName,
121
132
  deliver_policy: DeliverPolicy.New,
122
133
  ack_policy: AckPolicy.Explicit,
123
134
  max_ack_pending: concurrency,
124
135
  });
125
136
  }
126
- const consumer = await js.consumers.get(streamName, consumerName);
137
+ const consumer = await js.consumers.get(fullStreamName, consumerName);
127
138
  const messages = await consumer.consume();
128
139
  subscription = messages;
129
140
  // Start delayed job dispatch interval (every 30 seconds)
@@ -1 +1 @@
1
- {"version":3,"file":"WorkerQueue.js","sourceRoot":"","sources":["../../src/server/WorkerQueue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WorkerQueue.js","sourceRoot":"","sources":["../../src/server/WorkerQueue.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"UglyBotWebSearchProvider.d.ts","sourceRoot":"","sources":["../../../../src/server/ai/providers/UglyBotWebSearchProvider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAoB,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAmDvE,eAAO,MAAM,wBAAwB,EAAE,iBAkDtC,CAAC"}
1
+ {"version":3,"file":"UglyBotWebSearchProvider.d.ts","sourceRoot":"","sources":["../../../../src/server/ai/providers/UglyBotWebSearchProvider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAoB,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAqDvE,eAAO,MAAM,wBAAwB,EAAE,iBAkDtC,CAAC"}
@@ -14,7 +14,9 @@ async function callUglyBotRequest(op, input, userId) {
14
14
  },
15
15
  body: JSON.stringify({
16
16
  op,
17
- input: userId ? { ...input, userId } : input,
17
+ input: userId
18
+ ? { ...input, context: { chargeUserIds: [userId] } }
19
+ : input,
18
20
  sessionId: 'server',
19
21
  }),
20
22
  signal: controller.signal,
@@ -1 +1 @@
1
- {"version":3,"file":"UglyBotWebSearchProvider.js","sourceRoot":"","sources":["../../../../src/server/ai/providers/UglyBotWebSearchProvider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"UglyBotWebSearchProvider.js","sourceRoot":"","sources":["../../../../src/server/ai/providers/UglyBotWebSearchProvider.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugly-app",
3
- "version": "0.1.200",
3
+ "version": "0.1.202",
4
4
  "type": "module",
5
5
  "main": "./dist/server/index.js",
6
6
  "exports": {
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.200";
2
+ export const CLI_VERSION = "0.1.202";
@@ -45,10 +45,12 @@ function buildUpdateExpression(op: UpdateOp): { expr: string; values: unknown[];
45
45
  if (parts.length === 1) {
46
46
  expr = `(${expr}) - '${field}'`;
47
47
  } else {
48
- // For nested: remove the last key from the parent path
48
+ // For nested: remove the last key from the parent path.
49
+ // COALESCE guards against NULL when the parent path doesn't exist,
50
+ // which would cause jsonb_set to return NULL and violate NOT NULL.
49
51
  const parentPath = toPathArray(parts.slice(0, -1).join('.'));
50
52
  const lastKey = parts[parts.length - 1];
51
- expr = `jsonb_set(${expr}, '${parentPath}', (${expr}#>'${parentPath}') - '${lastKey}')`;
53
+ expr = `jsonb_set(${expr}, '${parentPath}', COALESCE((${expr}#>'${parentPath}') - '${lastKey}', '{}'::jsonb))`;
52
54
  }
53
55
  }
54
56
  }
@@ -2,7 +2,7 @@ import { AckPolicy, DeliverPolicy } from 'nats';
2
2
  import type { TypedDB } from '../shared/DB.js';
3
3
  import { BUILTIN_DEFS, dbDefaults, type WorkerDelayedJobDoc } from '../shared/DB.js';
4
4
  import type { WorkerQueue } from './App.js';
5
- import { ensureStream, getJetStream, getNatsConnection } from './Nats.js';
5
+ import { ensureStream, getJetStream, getNatsConnection, getNatsPrefix } from './Nats.js';
6
6
 
7
7
  export interface Job<T = unknown> {
8
8
  id: string;
@@ -53,9 +53,21 @@ export function createWorkerQueue(
53
53
 
54
54
  const isClockServer = process.env['IS_CLOCK_SERVER'] === 'true';
55
55
 
56
+ /** Returns the prefixed stream name matching what ensureStream creates. */
57
+ function prefixedStreamName(): string {
58
+ const p = getNatsPrefix();
59
+ return p ? `${p}_${streamName}` : streamName;
60
+ }
61
+
62
+ /** Returns the prefixed subject for a job type. */
63
+ function prefixedSubject(type: string): string {
64
+ const p = getNatsPrefix();
65
+ return p ? `${p}.${streamName}.${type}` : `${streamName}.${type}`;
66
+ }
67
+
56
68
  async function publishJob<T>(job: Job<T>): Promise<void> {
57
69
  const js = await getJetStream();
58
- const subject = `${streamName}.${job.type}`;
70
+ const subject = prefixedSubject(job.type);
59
71
  await js.publish(subject, new TextEncoder().encode(JSON.stringify(job)));
60
72
  console.log('[WorkerQueue] Job enqueued', { id: job.id, type: job.type });
61
73
  }
@@ -168,6 +180,7 @@ export function createWorkerQueue(
168
180
  subjects: [`${streamName}.*`],
169
181
  });
170
182
 
183
+ const fullStreamName = prefixedStreamName();
171
184
  const js = await getJetStream();
172
185
  const conn = getNatsConnection();
173
186
  const jsm = await conn.jetstreamManager();
@@ -176,9 +189,9 @@ export function createWorkerQueue(
176
189
  const consumerName = `worker-${process.env['HOSTNAME'] ?? 'local'}`;
177
190
 
178
191
  try {
179
- await jsm.consumers.info(streamName, consumerName);
192
+ await jsm.consumers.info(fullStreamName, consumerName);
180
193
  } catch {
181
- await jsm.consumers.add(streamName, {
194
+ await jsm.consumers.add(fullStreamName, {
182
195
  durable_name: consumerName,
183
196
  deliver_policy: DeliverPolicy.New,
184
197
  ack_policy: AckPolicy.Explicit,
@@ -186,7 +199,7 @@ export function createWorkerQueue(
186
199
  });
187
200
  }
188
201
 
189
- const consumer = await js.consumers.get(streamName, consumerName);
202
+ const consumer = await js.consumers.get(fullStreamName, consumerName);
190
203
  const messages = await consumer.consume();
191
204
 
192
205
  subscription = messages;
@@ -31,7 +31,9 @@ async function callUglyBotRequest(
31
31
  },
32
32
  body: JSON.stringify({
33
33
  op,
34
- input: userId ? { ...(input as object), userId } : input,
34
+ input: userId
35
+ ? { ...(input as object), context: { chargeUserIds: [userId] } }
36
+ : input,
35
37
  sessionId: 'server',
36
38
  }),
37
39
  signal: controller.signal,
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
2
2
  import { Button, Card, PageLayout, useApp } from 'ugly-app/client';
3
3
 
4
4
  interface SentEntry {
5
- to: string;
5
+ userId: string;
6
6
  subject: string;
7
7
  id: string | null;
8
8
  sentAt: string;
@@ -20,7 +20,7 @@ function fmt(ms: number): string {
20
20
 
21
21
  export default function EmailTestPage(): React.ReactElement {
22
22
  const { socket } = useApp();
23
- const [to, setTo] = useState('');
23
+ const [userId, setUserId] = useState('');
24
24
  const [subject, setSubject] = useState('Test email from ugly-app');
25
25
  const [html, setHtml] = useState('<h1>Hello!</h1>\n<p>This is a test email sent from ugly-app.</p>');
26
26
  const [replyId, setReplyId] = useState('');
@@ -36,25 +36,25 @@ export default function EmailTestPage(): React.ReactElement {
36
36
  }
37
37
 
38
38
  async function handleSend(): Promise<void> {
39
- const trimmedTo = to.trim();
40
- if (!trimmedTo) return;
39
+ const trimmedUserId = userId.trim();
40
+ if (!trimmedUserId) return;
41
41
 
42
42
  setSending(true);
43
43
  const started = Date.now();
44
- addLog(`Sending to ${trimmedTo} — subject: "${subject.trim() || 'Test email'}"${replyId.trim() ? ` — replyId: ${replyId.trim()}` : ''}`);
44
+ addLog(`Sending to user ${trimmedUserId} — subject: "${subject.trim() || 'Test email'}"${replyId.trim() ? ` — replyId: ${replyId.trim()}` : ''}`);
45
45
  try {
46
46
  await socket.request('sendTestEmail', {
47
- to: trimmedTo,
47
+ userId: trimmedUserId,
48
48
  subject: subject.trim() || 'Test email',
49
49
  html,
50
50
  id: replyId.trim() || undefined,
51
51
  });
52
52
  addLog(`Sent in ${fmt(Date.now() - started)}`, 'ok');
53
53
  setSent((prev) => [
54
- { to: trimmedTo, subject, id: replyId.trim() || null, sentAt: new Date().toISOString() },
54
+ { userId: trimmedUserId, subject, id: replyId.trim() || null, sentAt: new Date().toISOString() },
55
55
  ...prev,
56
56
  ]);
57
- setTo('');
57
+ setUserId('');
58
58
  } catch (err) {
59
59
  addLog(`Failed: ${err instanceof Error ? err.message : String(err)}`, 'err');
60
60
  } finally {
@@ -77,12 +77,12 @@ export default function EmailTestPage(): React.ReactElement {
77
77
  <h2>Send Email</h2>
78
78
  <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
79
79
  <label>
80
- <div style={{ marginBottom: 4, fontWeight: 500 }}>To</div>
80
+ <div style={{ marginBottom: 4, fontWeight: 500 }}>User ID</div>
81
81
  <input
82
- type="email"
83
- value={to}
84
- onChange={(e) => { setTo(e.target.value); }}
85
- placeholder="recipient@example.com"
82
+ type="text"
83
+ value={userId}
84
+ onChange={(e) => { setUserId(e.target.value); }}
85
+ placeholder="user ID"
86
86
  style={{ width: '100%', padding: 8, borderRadius: 4, border: '1px solid #444' }}
87
87
  />
88
88
  </label>
@@ -118,7 +118,7 @@ export default function EmailTestPage(): React.ReactElement {
118
118
  style={{ width: '100%', padding: 8, borderRadius: 4, border: '1px solid #444', fontFamily: 'monospace', fontSize: '0.9em' }}
119
119
  />
120
120
  </label>
121
- <Button onClick={() => { void handleSend(); }} disabled={sending || !to.trim()}>
121
+ <Button onClick={() => { void handleSend(); }} disabled={sending || !userId.trim()}>
122
122
  {sending ? 'Sending…' : 'Send Email'}
123
123
  </Button>
124
124
  </div>
@@ -142,7 +142,7 @@ export default function EmailTestPage(): React.ReactElement {
142
142
  <h2>Sent Emails</h2>
143
143
  {sent.map((entry, i) => (
144
144
  <div key={i} style={{ marginBottom: 12, paddingBottom: 12, borderBottom: '1px solid #333' }}>
145
- <div><strong>To:</strong> {entry.to}</div>
145
+ <div><strong>User ID:</strong> {entry.userId}</div>
146
146
  <div><strong>Subject:</strong> {entry.subject}</div>
147
147
  {entry.id && <div><strong>Reply ID:</strong> {entry.id}</div>}
148
148
  <div style={{ fontSize: '0.8em', color: '#888' }}>{entry.sentAt}</div>
@@ -68,9 +68,22 @@ function ensureIframe(): Promise<void> {
68
68
  function postAndWait(
69
69
  msg: Record<string, unknown>,
70
70
  expectFunc: string,
71
+ timeoutMs = 10_000,
71
72
  ): Promise<Record<string, unknown>> {
72
- return new Promise((resolve) => {
73
- pendingResolvers.push({ func: expectFunc, resolve });
73
+ return new Promise((resolve, reject) => {
74
+ const timer = setTimeout(() => {
75
+ const idx = pendingResolvers.findIndex((r) => r.func === expectFunc);
76
+ if (idx >= 0) pendingResolvers.splice(idx, 1);
77
+ reject(new Error(`push-frame timeout waiting for "${expectFunc}"`));
78
+ }, timeoutMs);
79
+
80
+ pendingResolvers.push({
81
+ func: expectFunc,
82
+ resolve: (data) => {
83
+ clearTimeout(timer);
84
+ resolve(data);
85
+ },
86
+ });
74
87
  iframe!.contentWindow!.postMessage(msg, PUSH_FRAME_ORIGIN);
75
88
  });
76
89
  }
@@ -15,6 +15,7 @@ import { collections } from '../shared/collections';
15
15
  import { cronTasks } from '../shared/cron';
16
16
  import { experiments } from '../shared/experiments';
17
17
  import { pages } from '../shared/pages';
18
+ import { servePushTestPage } from './push-test-page';
18
19
 
19
20
  const userHelper = createUserHelper<User>(collections.user);
20
21
  // eslint-disable-next-line @typescript-eslint/dot-notation
@@ -61,8 +62,10 @@ const app = createApp(
61
62
  return sendPush({ targetUserId, title, body, path });
62
63
  },
63
64
 
64
- sendTestEmail: async (_userId, { to, subject, html, id }) => {
65
- await email.send({ to, subject, html, ...(id != null ? { id } : {}) });
65
+ sendTestEmail: async (_userId, { userId, subject, html, id }) => {
66
+ const user = await app.db.getDoc(collections.user, userId);
67
+ if (!user?.email) throw new Error('User not found or has no email');
68
+ await email.send({ to: user.email, subject, html, ...(id != null ? { id } : {}) });
66
69
  return { ok: true };
67
70
  },
68
71
  } satisfies RequestHandlers<typeof requests>,
@@ -77,6 +80,9 @@ const app = createApp(
77
80
  await Promise.resolve();
78
81
  console.log('[Email] Received:', { from: inbound.from, id: inbound.id, subject: inbound.subject });
79
82
  });
83
+ configurator.registerRoutes((router) => {
84
+ router.get('/push-test', servePushTestPage);
85
+ });
80
86
  configurator.setOnUserCreate(async (userId, info, db) => {
81
87
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
82
88
  await userHelper.set(db, { _id: userId, ...dbDefaults(), ...info });
@@ -0,0 +1,215 @@
1
+ import type { Request, Response } from 'express';
2
+
3
+ /**
4
+ * Lightweight standalone page for testing push notifications.
5
+ * Served as raw HTML — no React SPA bundle, no client JS framework.
6
+ */
7
+ export function servePushTestPage(req: Request, res: Response): void {
8
+ const token = req.cookies?.auth_token as string | undefined;
9
+ if (!token) {
10
+ res.status(401).send('Unauthorized — please log in first.');
11
+ return;
12
+ }
13
+
14
+ res.setHeader('Content-Type', 'text/html');
15
+ res.send(`<!DOCTYPE html>
16
+ <html lang="en">
17
+ <head>
18
+ <meta charset="utf-8">
19
+ <meta name="viewport" content="width=device-width, initial-scale=1">
20
+ <title>Push Notification Test</title>
21
+ <style>
22
+ * { box-sizing: border-box; margin: 0; padding: 0; }
23
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #111; color: #eee; padding: 24px; max-width: 480px; margin: 0 auto; }
24
+ h1 { font-size: 1.2em; margin-bottom: 16px; }
25
+ .card { background: #1a1a1a; border: 1px solid #333; border-radius: 8px; padding: 16px; margin-bottom: 12px; }
26
+ .card h2 { font-size: 0.95em; margin-bottom: 8px; color: #aaa; }
27
+ .status { font-size: 0.85em; opacity: 0.7; margin-bottom: 8px; }
28
+ button { background: #2563eb; color: #fff; border: none; border-radius: 6px; padding: 8px 16px; font-size: 0.9em; cursor: pointer; margin-right: 6px; margin-bottom: 6px; }
29
+ button:disabled { opacity: 0.4; cursor: not-allowed; }
30
+ button:hover:not(:disabled) { background: #1d4ed8; }
31
+ input { background: #222; border: 1px solid #444; color: #eee; border-radius: 6px; padding: 8px 10px; font-size: 0.9em; width: 100%; margin-bottom: 8px; }
32
+ #log { margin-top: 12px; font-size: 0.8em; font-family: monospace; max-height: 200px; overflow-y: auto; }
33
+ .log-ok { color: #4ade80; }
34
+ .log-err { color: #f87171; }
35
+ .log-info { color: #94a3b8; }
36
+ a { color: #60a5fa; }
37
+ </style>
38
+ </head>
39
+ <body>
40
+ <h1><a href="/test">&larr;</a> Push Notification Test</h1>
41
+
42
+ <div class="card">
43
+ <h2>1. Check Registration</h2>
44
+ <div class="status" id="status">Status: unknown</div>
45
+ <button id="btn-check" onclick="handleInit()">Check Status</button>
46
+ <button id="btn-register" onclick="handleRegister()" style="display:none">Register for Push</button>
47
+ </div>
48
+
49
+ <div class="card">
50
+ <h2>2. Send Test Push</h2>
51
+ <input id="target" placeholder="Target User ID" />
52
+ <input id="title" value="Test Notification" placeholder="Title" />
53
+ <input id="body" value="Hello from push test!" placeholder="Body" />
54
+ <button id="btn-send" onclick="handleSend()">Send Push</button>
55
+ </div>
56
+
57
+ <div id="log"></div>
58
+
59
+ <script>
60
+ const PUSH_FRAME_URL = 'https://ugly.bot/push-frame';
61
+ const PUSH_FRAME_ORIGIN = 'https://ugly.bot';
62
+ const AUTH_TOKEN = ${JSON.stringify(token)};
63
+
64
+ let iframe = null;
65
+ let iframeReady = false;
66
+ let pendingResolvers = [];
67
+ let loading = false;
68
+
69
+ function setLoading(v) {
70
+ loading = v;
71
+ document.querySelectorAll('button').forEach(b => b.disabled = v);
72
+ }
73
+
74
+ function addLog(msg, kind) {
75
+ const el = document.getElementById('log');
76
+ const div = document.createElement('div');
77
+ div.className = 'log-' + (kind || 'info');
78
+ div.textContent = (kind === 'err' ? '\\u2717 ' : kind === 'ok' ? '\\u2713 ' : '\\u00b7 ') + msg;
79
+ el.appendChild(div);
80
+ el.scrollTop = el.scrollHeight;
81
+ }
82
+
83
+ function ensureIframe() {
84
+ if (iframe && iframeReady) return Promise.resolve();
85
+ return new Promise(function(resolve) {
86
+ if (iframe) {
87
+ var prev = iframe.onload;
88
+ iframe.onload = function(e) { if (prev) prev.call(iframe, e); iframeReady = true; resolve(); };
89
+ return;
90
+ }
91
+ iframe = document.createElement('iframe');
92
+ iframe.src = PUSH_FRAME_URL;
93
+ iframe.style.display = 'none';
94
+ iframe.onload = function() { iframeReady = true; resolve(); };
95
+ document.body.appendChild(iframe);
96
+
97
+ window.addEventListener('message', function(event) {
98
+ if (event.origin !== PUSH_FRAME_ORIGIN) return;
99
+ var data = event.data;
100
+ var func = data.func;
101
+ var idx = pendingResolvers.findIndex(function(r) { return r.func === func; });
102
+ if (idx >= 0) {
103
+ pendingResolvers[idx].resolve(data);
104
+ pendingResolvers.splice(idx, 1);
105
+ }
106
+ });
107
+ });
108
+ }
109
+
110
+ function postAndWait(msg, expectFunc, timeoutMs) {
111
+ timeoutMs = timeoutMs || 10000;
112
+ return new Promise(function(resolve, reject) {
113
+ var timer = setTimeout(function() {
114
+ var idx = pendingResolvers.findIndex(function(r) { return r.func === expectFunc; });
115
+ if (idx >= 0) pendingResolvers.splice(idx, 1);
116
+ reject(new Error('Timeout waiting for ' + expectFunc));
117
+ }, timeoutMs);
118
+
119
+ pendingResolvers.push({
120
+ func: expectFunc,
121
+ resolve: function(data) { clearTimeout(timer); resolve(data); }
122
+ });
123
+ iframe.contentWindow.postMessage(msg, PUSH_FRAME_ORIGIN);
124
+ });
125
+ }
126
+
127
+ async function handleInit() {
128
+ setLoading(true);
129
+ var started = Date.now();
130
+ try {
131
+ addLog('Checking push registration...', 'info');
132
+ await ensureIframe();
133
+ var result = await postAndWait({ func: 'pushInit', projectToken: AUTH_TOKEN }, 'pushStatus');
134
+ var ms = Date.now() - started;
135
+ var t = ms < 1000 ? ms + 'ms' : (ms/1000).toFixed(1) + 's';
136
+ document.getElementById('status').textContent = 'Status: ' + (result.registered ? 'registered' : 'not registered');
137
+ document.getElementById('btn-register').style.display = result.registered ? 'none' : 'inline-block';
138
+ addLog(result.registered ? 'Device is registered (' + t + ')' : 'Device is NOT registered (' + t + ')', result.registered ? 'ok' : 'info');
139
+ } catch (e) {
140
+ addLog('Init failed: ' + e.message, 'err');
141
+ } finally {
142
+ setLoading(false);
143
+ }
144
+ }
145
+
146
+ async function handleRegister() {
147
+ setLoading(true);
148
+ var started = Date.now();
149
+ try {
150
+ addLog('Requesting push permission...', 'info');
151
+ await ensureIframe();
152
+
153
+ var successP = new Promise(function(resolve) {
154
+ pendingResolvers.push({ func: 'pushRegistered', resolve: function() { resolve({ success: true }); } });
155
+ });
156
+ var errorP = new Promise(function(resolve) {
157
+ pendingResolvers.push({ func: 'pushError', resolve: function(d) { resolve({ success: false, error: d.error }); } });
158
+ });
159
+ var timeoutP = new Promise(function(resolve) {
160
+ setTimeout(function() { resolve({ success: false, error: 'timeout' }); }, 15000);
161
+ });
162
+
163
+ iframe.contentWindow.postMessage({ func: 'pushRequestPermission', projectToken: AUTH_TOKEN }, PUSH_FRAME_ORIGIN);
164
+ var result = await Promise.race([successP, errorP, timeoutP]);
165
+ pendingResolvers = pendingResolvers.filter(function(r) { return r.func !== 'pushRegistered' && r.func !== 'pushError'; });
166
+
167
+ var ms = Date.now() - started;
168
+ var t = ms < 1000 ? ms + 'ms' : (ms/1000).toFixed(1) + 's';
169
+ if (result.success) {
170
+ document.getElementById('status').textContent = 'Status: registered';
171
+ document.getElementById('btn-register').style.display = 'none';
172
+ addLog('Push registered (' + t + ')', 'ok');
173
+ } else {
174
+ addLog('Registration failed (' + t + '): ' + (result.error || 'unknown'), 'err');
175
+ }
176
+ } catch (e) {
177
+ addLog('Register failed: ' + e.message, 'err');
178
+ } finally {
179
+ setLoading(false);
180
+ }
181
+ }
182
+
183
+ async function handleSend() {
184
+ var targetUserId = document.getElementById('target').value.trim();
185
+ var title = document.getElementById('title').value.trim();
186
+ var body = document.getElementById('body').value.trim();
187
+ if (!targetUserId || !title) return;
188
+
189
+ setLoading(true);
190
+ var started = Date.now();
191
+ try {
192
+ addLog('Sending push to ' + targetUserId + '...', 'info');
193
+ var resp = await fetch('/api/sendPush', {
194
+ method: 'POST',
195
+ headers: { 'Content-Type': 'application/json' },
196
+ body: JSON.stringify({ input: { targetUserId: targetUserId, title: title, body: body, path: '' } })
197
+ });
198
+ var data = await resp.json();
199
+ var ms = Date.now() - started;
200
+ var t = ms < 1000 ? ms + 'ms' : (ms/1000).toFixed(1) + 's';
201
+ if (data.result && data.result.sent) {
202
+ addLog('Push sent (' + t + ')', 'ok');
203
+ } else {
204
+ addLog('Push not delivered (' + t + ') — no devices?', 'err');
205
+ }
206
+ } catch (e) {
207
+ addLog('Send failed: ' + e.message, 'err');
208
+ } finally {
209
+ setLoading(false);
210
+ }
211
+ }
212
+ </script>
213
+ </body>
214
+ </html>`);
215
+ }
@@ -32,7 +32,7 @@ export const requests = defineRequests({
32
32
  // Email test — send an email via the app's email sender
33
33
  sendTestEmail: authReq({
34
34
  input: z.object({
35
- to: z.email(),
35
+ userId: z.string(),
36
36
  subject: z.string().min(1).max(200),
37
37
  html: z.string().min(1),
38
38
  id: z.string().max(100).optional(),