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.
- package/dist/cli/version.d.ts +1 -1
- package/dist/cli/version.js +1 -1
- package/dist/server/PostgresOperators.d.ts.map +1 -1
- package/dist/server/PostgresOperators.js +4 -2
- package/dist/server/PostgresOperators.js.map +1 -1
- package/dist/server/WorkerQueue.d.ts.map +1 -1
- package/dist/server/WorkerQueue.js +16 -5
- package/dist/server/WorkerQueue.js.map +1 -1
- package/dist/server/ai/providers/UglyBotWebSearchProvider.d.ts.map +1 -1
- package/dist/server/ai/providers/UglyBotWebSearchProvider.js +3 -1
- package/dist/server/ai/providers/UglyBotWebSearchProvider.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/version.ts +1 -1
- package/src/server/PostgresOperators.ts +4 -2
- package/src/server/WorkerQueue.ts +18 -5
- package/src/server/ai/providers/UglyBotWebSearchProvider.ts +3 -1
- package/templates/client/pages/EmailTestPage.tsx +15 -15
- package/templates/client/push.ts +15 -2
- package/templates/server/index.ts +8 -2
- package/templates/server/push-test-page.ts +215 -0
- package/templates/shared/api.ts +1 -1
package/dist/cli/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.1.
|
|
1
|
+
export declare const CLI_VERSION = "0.1.202";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/cli/version.js
CHANGED
|
@@ -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;
|
|
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":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAiBtC,kFAAkF;AAClF,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAC3C,CAAC;AAED;;;GAGG;AACH,SAAS,qBAAqB,CAAC,EAAY;IACzC,IAAI,IAAI,GAAG,MAAM,CAAC;IAClB,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC,uBAAuB;IAEzC,iCAAiC;IACjC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;QACZ,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACrD,IAAI,GAAG,aAAa,IAAI,MAAM,WAAW,CAAC,KAAK,CAAC,OAAO,QAAQ,UAAU,CAAC;YAC1E,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;YACnC,QAAQ,EAAE,CAAC;QACb,CAAC;IACH,CAAC;IAED,sBAAsB;IACtB,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC;QACd,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,GAAG,CAAC;YAClC,CAAC;iBAAM,CAAC;gBACN,
|
|
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,
|
|
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 =
|
|
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(
|
|
127
|
+
await jsm.consumers.info(fullStreamName, consumerName);
|
|
117
128
|
}
|
|
118
129
|
catch {
|
|
119
|
-
await jsm.consumers.add(
|
|
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(
|
|
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":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAEhD,OAAO,EAAE,YAAY,EAAE,UAAU,EAA4B,MAAM,iBAAiB,CAAC;AAErF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;
|
|
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;
|
|
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
|
|
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":"AASA,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAExC,KAAK,UAAU,kBAAkB,CAC/B,EAAU,EACV,KAAc,EACd,MAAe;IAEf,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC5C,IAAI,CAAC,QAAQ;QACX,MAAM,IAAI,KAAK,CACb,4DAA4D,CAC7D,CAAC;IAEJ,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,YAAY,UAAU,EAAE;YACjD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,QAAQ,EAAE;gBACrC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,EAAE;gBACF,KAAK,EAAE,MAAM,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"UglyBotWebSearchProvider.js","sourceRoot":"","sources":["../../../../src/server/ai/providers/UglyBotWebSearchProvider.ts"],"names":[],"mappings":"AASA,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAExC,KAAK,UAAU,kBAAkB,CAC/B,EAAU,EACV,KAAc,EACd,MAAe;IAEf,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC5C,IAAI,CAAC,QAAQ;QACX,MAAM,IAAI,KAAK,CACb,4DAA4D,CAC7D,CAAC;IAEJ,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,YAAY,UAAU,EAAE;YACjD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,QAAQ,EAAE;gBACrC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,EAAE;gBACF,KAAK,EAAE,MAAM;oBACX,CAAC,CAAC,EAAE,GAAI,KAAgB,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE;oBAChE,CAAC,CAAC,KAAK;gBACT,SAAS,EAAE,QAAQ;aACpB,CAAC;YACF,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACvB,OAAO,CAAC,KAAK,CACX,iCAAiC,EAAE,uCAAuC;oBACxE,6BAA6B;oBAC7B,WAAW,IAAI,EAAE,CACpB,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,GAAG,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;YACjE,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAwB,CAAC;QACvD,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,wBAAwB,GAAsB;IACzD,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,gBAAgB;IAE3B,KAAK,CAAC,MAAM,CACV,MAAuB,EACvB,OAA0B;QAE1B,OAAO,kBAAkB,CACvB,YAAY,EACZ,EAAE,MAAM,EAAE,EACV,OAAO,EAAE,MAAM,CACY,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,SAAS,CACb,MAA0B,EAC1B,OAA0B;QAE1B,MAAM,MAAM,GAAG,CAAC,MAAM,kBAAkB,CACtC,eAAe,EACf,EAAE,MAAM,EAAE,EACV,OAAO,EAAE,MAAM,CAChB,CAAW,CAAC;QACb,6DAA6D;QAC7D,mEAAmE;QACnE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,SAAS,CACb,MAAuB,EACvB,OAA0B;QAE1B,OAAO,kBAAkB,CACvB,eAAe,EACf,EAAE,MAAM,EAAE,EACV,OAAO,EAAE,MAAM,CACY,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,UAAU,CACd,MAAuB,EACvB,OAA0B;QAE1B,OAAO,kBAAkB,CACvB,gBAAgB,EAChB,EAAE,MAAM,EAAE,EACV,OAAO,EAAE,MAAM,CACY,CAAC;IAChC,CAAC;CACF,CAAC"}
|
package/package.json
CHANGED
package/src/cli/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by prebuild — do not edit manually
|
|
2
|
-
export const CLI_VERSION = "0.1.
|
|
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 =
|
|
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(
|
|
192
|
+
await jsm.consumers.info(fullStreamName, consumerName);
|
|
180
193
|
} catch {
|
|
181
|
-
await jsm.consumers.add(
|
|
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(
|
|
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
|
|
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
|
-
|
|
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 [
|
|
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
|
|
40
|
-
if (!
|
|
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 ${
|
|
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
|
-
|
|
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
|
-
{
|
|
54
|
+
{ userId: trimmedUserId, subject, id: replyId.trim() || null, sentAt: new Date().toISOString() },
|
|
55
55
|
...prev,
|
|
56
56
|
]);
|
|
57
|
-
|
|
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 }}>
|
|
80
|
+
<div style={{ marginBottom: 4, fontWeight: 500 }}>User ID</div>
|
|
81
81
|
<input
|
|
82
|
-
type="
|
|
83
|
-
value={
|
|
84
|
-
onChange={(e) => {
|
|
85
|
-
placeholder="
|
|
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 || !
|
|
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>
|
|
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>
|
package/templates/client/push.ts
CHANGED
|
@@ -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
|
-
|
|
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, {
|
|
65
|
-
await
|
|
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">←</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
|
+
}
|
package/templates/shared/api.ts
CHANGED
|
@@ -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
|
-
|
|
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(),
|