@vibelet/cli 0.1.38 → 1.0.0
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 +80 -0
- package/bin/cloudflared-quick-tunnel.mjs +11 -0
- package/bin/cloudflared-resolver.mjs +171 -0
- package/bin/vibelet-runtime-policy.mjs +36 -0
- package/bin/vibelet.cjs +12 -0
- package/bin/vibelet.mjs +1062 -0
- package/dist/index.cjs +126 -0
- package/package.json +24 -22
- package/app.json +0 -5
- package/dist/advertised-hosts.d.ts +0 -34
- package/dist/advertised-hosts.d.ts.map +0 -1
- package/dist/advertised-hosts.js +0 -176
- package/dist/advertised-hosts.js.map +0 -1
- package/dist/advertised-hosts.test.d.ts +0 -2
- package/dist/advertised-hosts.test.d.ts.map +0 -1
- package/dist/advertised-hosts.test.js +0 -96
- package/dist/advertised-hosts.test.js.map +0 -1
- package/dist/audit.d.ts +0 -30
- package/dist/audit.d.ts.map +0 -1
- package/dist/audit.js +0 -73
- package/dist/audit.js.map +0 -1
- package/dist/audit.test.d.ts +0 -2
- package/dist/audit.test.d.ts.map +0 -1
- package/dist/audit.test.js +0 -33
- package/dist/audit.test.js.map +0 -1
- package/dist/auth.d.ts +0 -6
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js +0 -27
- package/dist/auth.js.map +0 -1
- package/dist/claude-hooks.d.ts +0 -58
- package/dist/claude-hooks.d.ts.map +0 -1
- package/dist/claude-hooks.js +0 -129
- package/dist/claude-hooks.js.map +0 -1
- package/dist/cli-version.d.ts +0 -3
- package/dist/cli-version.d.ts.map +0 -1
- package/dist/cli-version.js +0 -35
- package/dist/cli-version.js.map +0 -1
- package/dist/cli-version.test.d.ts +0 -2
- package/dist/cli-version.test.d.ts.map +0 -1
- package/dist/cli-version.test.js +0 -38
- package/dist/cli-version.test.js.map +0 -1
- package/dist/config.d.ts +0 -30
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -327
- package/dist/config.js.map +0 -1
- package/dist/config.test.d.ts +0 -2
- package/dist/config.test.d.ts.map +0 -1
- package/dist/config.test.js +0 -184
- package/dist/config.test.js.map +0 -1
- package/dist/dev-auth.test.d.ts +0 -2
- package/dist/dev-auth.test.d.ts.map +0 -1
- package/dist/dev-auth.test.js +0 -154
- package/dist/dev-auth.test.js.map +0 -1
- package/dist/dev-script.test.d.ts +0 -2
- package/dist/dev-script.test.d.ts.map +0 -1
- package/dist/dev-script.test.js +0 -412
- package/dist/dev-script.test.js.map +0 -1
- package/dist/drivers/claude.d.ts +0 -34
- package/dist/drivers/claude.d.ts.map +0 -1
- package/dist/drivers/claude.js +0 -413
- package/dist/drivers/claude.js.map +0 -1
- package/dist/drivers/claude.test.d.ts +0 -2
- package/dist/drivers/claude.test.d.ts.map +0 -1
- package/dist/drivers/claude.test.js +0 -951
- package/dist/drivers/claude.test.js.map +0 -1
- package/dist/drivers/codex.d.ts +0 -38
- package/dist/drivers/codex.d.ts.map +0 -1
- package/dist/drivers/codex.js +0 -771
- package/dist/drivers/codex.js.map +0 -1
- package/dist/drivers/codex.test.d.ts +0 -2
- package/dist/drivers/codex.test.d.ts.map +0 -1
- package/dist/drivers/codex.test.js +0 -939
- package/dist/drivers/codex.test.js.map +0 -1
- package/dist/drivers/types.d.ts +0 -14
- package/dist/drivers/types.d.ts.map +0 -1
- package/dist/drivers/types.js +0 -2
- package/dist/drivers/types.js.map +0 -1
- package/dist/e2e.test.d.ts +0 -2
- package/dist/e2e.test.d.ts.map +0 -1
- package/dist/e2e.test.js +0 -111
- package/dist/e2e.test.js.map +0 -1
- package/dist/identity.d.ts +0 -10
- package/dist/identity.d.ts.map +0 -1
- package/dist/identity.js +0 -66
- package/dist/identity.js.map +0 -1
- package/dist/identity.test.d.ts +0 -2
- package/dist/identity.test.d.ts.map +0 -1
- package/dist/identity.test.js +0 -25
- package/dist/identity.test.js.map +0 -1
- package/dist/index-entry.test.d.ts +0 -2
- package/dist/index-entry.test.d.ts.map +0 -1
- package/dist/index-entry.test.js +0 -272
- package/dist/index-entry.test.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -707
- package/dist/index.js.map +0 -1
- package/dist/logger.d.ts +0 -31
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -75
- package/dist/logger.js.map +0 -1
- package/dist/metrics.d.ts +0 -52
- package/dist/metrics.d.ts.map +0 -1
- package/dist/metrics.js +0 -89
- package/dist/metrics.js.map +0 -1
- package/dist/pairing-store.d.ts +0 -29
- package/dist/pairing-store.d.ts.map +0 -1
- package/dist/pairing-store.js +0 -131
- package/dist/pairing-store.js.map +0 -1
- package/dist/pairing-store.test.d.ts +0 -2
- package/dist/pairing-store.test.d.ts.map +0 -1
- package/dist/pairing-store.test.js +0 -47
- package/dist/pairing-store.test.js.map +0 -1
- package/dist/paths.d.ts +0 -16
- package/dist/paths.d.ts.map +0 -1
- package/dist/paths.js +0 -18
- package/dist/paths.js.map +0 -1
- package/dist/perf-compare.d.ts +0 -13
- package/dist/perf-compare.d.ts.map +0 -1
- package/dist/perf-compare.js +0 -125
- package/dist/perf-compare.js.map +0 -1
- package/dist/port-conflict.d.ts +0 -9
- package/dist/port-conflict.d.ts.map +0 -1
- package/dist/port-conflict.js +0 -33
- package/dist/port-conflict.js.map +0 -1
- package/dist/port-conflict.test.d.ts +0 -2
- package/dist/port-conflict.test.d.ts.map +0 -1
- package/dist/port-conflict.test.js +0 -38
- package/dist/port-conflict.test.js.map +0 -1
- package/dist/process-scanner.d.ts +0 -43
- package/dist/process-scanner.d.ts.map +0 -1
- package/dist/process-scanner.js +0 -453
- package/dist/process-scanner.js.map +0 -1
- package/dist/process-scanner.perf.test.d.ts +0 -2
- package/dist/process-scanner.perf.test.d.ts.map +0 -1
- package/dist/process-scanner.perf.test.js +0 -186
- package/dist/process-scanner.perf.test.js.map +0 -1
- package/dist/process-scanner.test.d.ts +0 -2
- package/dist/process-scanner.test.d.ts.map +0 -1
- package/dist/process-scanner.test.js +0 -399
- package/dist/process-scanner.test.js.map +0 -1
- package/dist/push-protocol.d.ts +0 -15
- package/dist/push-protocol.d.ts.map +0 -1
- package/dist/push-protocol.js +0 -23
- package/dist/push-protocol.js.map +0 -1
- package/dist/push-protocol.test.d.ts +0 -2
- package/dist/push-protocol.test.d.ts.map +0 -1
- package/dist/push-protocol.test.js +0 -57
- package/dist/push-protocol.test.js.map +0 -1
- package/dist/push-store.d.ts +0 -22
- package/dist/push-store.d.ts.map +0 -1
- package/dist/push-store.js +0 -103
- package/dist/push-store.js.map +0 -1
- package/dist/push-store.test.d.ts +0 -2
- package/dist/push-store.test.d.ts.map +0 -1
- package/dist/push-store.test.js +0 -79
- package/dist/push-store.test.js.map +0 -1
- package/dist/push.d.ts +0 -65
- package/dist/push.d.ts.map +0 -1
- package/dist/push.js +0 -202
- package/dist/push.js.map +0 -1
- package/dist/push.test.d.ts +0 -2
- package/dist/push.test.d.ts.map +0 -1
- package/dist/push.test.js +0 -199
- package/dist/push.test.js.map +0 -1
- package/dist/safe-stdio.d.ts +0 -3
- package/dist/safe-stdio.d.ts.map +0 -1
- package/dist/safe-stdio.js +0 -46
- package/dist/safe-stdio.js.map +0 -1
- package/dist/scanner.d.ts +0 -30
- package/dist/scanner.d.ts.map +0 -1
- package/dist/scanner.js +0 -859
- package/dist/scanner.js.map +0 -1
- package/dist/scanner.perf.test.d.ts +0 -2
- package/dist/scanner.perf.test.d.ts.map +0 -1
- package/dist/scanner.perf.test.js +0 -320
- package/dist/scanner.perf.test.js.map +0 -1
- package/dist/scanner.test.d.ts +0 -2
- package/dist/scanner.test.d.ts.map +0 -1
- package/dist/scanner.test.js +0 -948
- package/dist/scanner.test.js.map +0 -1
- package/dist/session-inventory.d.ts +0 -63
- package/dist/session-inventory.d.ts.map +0 -1
- package/dist/session-inventory.js +0 -525
- package/dist/session-inventory.js.map +0 -1
- package/dist/session-inventory.perf.test.d.ts +0 -2
- package/dist/session-inventory.perf.test.d.ts.map +0 -1
- package/dist/session-inventory.perf.test.js +0 -220
- package/dist/session-inventory.perf.test.js.map +0 -1
- package/dist/session-inventory.test.d.ts +0 -2
- package/dist/session-inventory.test.d.ts.map +0 -1
- package/dist/session-inventory.test.js +0 -712
- package/dist/session-inventory.test.js.map +0 -1
- package/dist/session-manager.d.ts +0 -75
- package/dist/session-manager.d.ts.map +0 -1
- package/dist/session-manager.js +0 -1515
- package/dist/session-manager.js.map +0 -1
- package/dist/session-manager.test.d.ts +0 -2
- package/dist/session-manager.test.d.ts.map +0 -1
- package/dist/session-manager.test.js +0 -2861
- package/dist/session-manager.test.js.map +0 -1
- package/dist/session-store.d.ts +0 -42
- package/dist/session-store.d.ts.map +0 -1
- package/dist/session-store.js +0 -163
- package/dist/session-store.js.map +0 -1
- package/dist/session-store.test.d.ts +0 -2
- package/dist/session-store.test.d.ts.map +0 -1
- package/dist/session-store.test.js +0 -236
- package/dist/session-store.test.js.map +0 -1
- package/dist/session-title.d.ts +0 -6
- package/dist/session-title.d.ts.map +0 -1
- package/dist/session-title.js +0 -105
- package/dist/session-title.js.map +0 -1
- package/dist/session-title.perf.test.d.ts +0 -2
- package/dist/session-title.perf.test.d.ts.map +0 -1
- package/dist/session-title.perf.test.js +0 -99
- package/dist/session-title.perf.test.js.map +0 -1
- package/dist/session-title.test.d.ts +0 -2
- package/dist/session-title.test.d.ts.map +0 -1
- package/dist/session-title.test.js +0 -199
- package/dist/session-title.test.js.map +0 -1
- package/dist/shutdown-endpoint.test.d.ts +0 -2
- package/dist/shutdown-endpoint.test.d.ts.map +0 -1
- package/dist/shutdown-endpoint.test.js +0 -93
- package/dist/shutdown-endpoint.test.js.map +0 -1
- package/dist/storage-housekeeping.d.ts +0 -28
- package/dist/storage-housekeeping.d.ts.map +0 -1
- package/dist/storage-housekeeping.js +0 -76
- package/dist/storage-housekeeping.js.map +0 -1
- package/dist/storage-housekeeping.test.d.ts +0 -2
- package/dist/storage-housekeeping.test.d.ts.map +0 -1
- package/dist/storage-housekeeping.test.js +0 -65
- package/dist/storage-housekeeping.test.js.map +0 -1
- package/dist/test-daemon-harness.d.ts +0 -31
- package/dist/test-daemon-harness.d.ts.map +0 -1
- package/dist/test-daemon-harness.js +0 -337
- package/dist/test-daemon-harness.js.map +0 -1
- package/dist/token-auth.test.d.ts +0 -2
- package/dist/token-auth.test.d.ts.map +0 -1
- package/dist/token-auth.test.js +0 -52
- package/dist/token-auth.test.js.map +0 -1
- package/dist/utils.d.ts +0 -4
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -40
- package/dist/utils.js.map +0 -1
- package/dist/utils.test.d.ts +0 -2
- package/dist/utils.test.d.ts.map +0 -1
- package/dist/utils.test.js +0 -54
- package/dist/utils.test.js.map +0 -1
- package/dist/ws-data.d.ts +0 -4
- package/dist/ws-data.d.ts.map +0 -1
- package/dist/ws-data.js +0 -20
- package/dist/ws-data.js.map +0 -1
- package/dist/ws-data.test.d.ts +0 -2
- package/dist/ws-data.test.d.ts.map +0 -1
- package/dist/ws-data.test.js +0 -17
- package/dist/ws-data.test.js.map +0 -1
- package/perf-reporter.mjs +0 -138
- package/scripts/build-release.mjs +0 -41
- package/scripts/dev.mjs +0 -537
- package/src/advertised-hosts.test.ts +0 -125
- package/src/advertised-hosts.ts +0 -225
- package/src/audit.test.ts +0 -38
- package/src/audit.ts +0 -117
- package/src/auth.ts +0 -31
- package/src/claude-hooks.ts +0 -195
- package/src/cli-version.test.ts +0 -36
- package/src/cli-version.ts +0 -46
- package/src/config.test.ts +0 -254
- package/src/config.ts +0 -324
- package/src/dev-auth.test.ts +0 -183
- package/src/dev-script.test.ts +0 -511
- package/src/drivers/claude.test.ts +0 -1186
- package/src/drivers/claude.ts +0 -443
- package/src/drivers/codex.test.ts +0 -1096
- package/src/drivers/codex.ts +0 -879
- package/src/drivers/types.ts +0 -15
- package/src/e2e.test.ts +0 -139
- package/src/identity.test.ts +0 -26
- package/src/identity.ts +0 -82
- package/src/index-entry.test.ts +0 -336
- package/src/index.ts +0 -781
- package/src/logger.ts +0 -112
- package/src/metrics.ts +0 -117
- package/src/pairing-store.test.ts +0 -53
- package/src/pairing-store.ts +0 -154
- package/src/paths.ts +0 -19
- package/src/perf-compare.ts +0 -164
- package/src/port-conflict.test.ts +0 -45
- package/src/port-conflict.ts +0 -44
- package/src/process-scanner.perf.test.ts +0 -222
- package/src/process-scanner.test.ts +0 -575
- package/src/process-scanner.ts +0 -514
- package/src/push-protocol.test.ts +0 -74
- package/src/push-protocol.ts +0 -36
- package/src/push-store.test.ts +0 -89
- package/src/push-store.ts +0 -126
- package/src/push.test.ts +0 -234
- package/src/push.ts +0 -318
- package/src/safe-stdio.ts +0 -51
- package/src/scanner.perf.test.ts +0 -359
- package/src/scanner.test.ts +0 -1045
- package/src/scanner.ts +0 -924
- package/src/session-inventory.perf.test.ts +0 -250
- package/src/session-inventory.test.ts +0 -1002
- package/src/session-inventory.ts +0 -721
- package/src/session-manager.test.ts +0 -3430
- package/src/session-manager.ts +0 -1775
- package/src/session-store.test.ts +0 -276
- package/src/session-store.ts +0 -202
- package/src/session-title.perf.test.ts +0 -118
- package/src/session-title.test.ts +0 -286
- package/src/session-title.ts +0 -108
- package/src/shutdown-endpoint.test.ts +0 -95
- package/src/storage-housekeeping.test.ts +0 -78
- package/src/storage-housekeeping.ts +0 -111
- package/src/test-daemon-harness.ts +0 -410
- package/src/token-auth.test.ts +0 -67
- package/src/utils.test.ts +0 -65
- package/src/utils.ts +0 -47
- package/src/ws-data.test.ts +0 -20
- package/src/ws-data.ts +0 -26
- package/tsconfig.json +0 -12
package/src/push.ts
DELETED
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
import { PUSH_NOTIFICATION_CATEGORY_IDS, type PushNotificationData } from '@vibelet/shared';
|
|
2
|
-
import { logger as rootLogger } from './logger.js';
|
|
3
|
-
import { PushStore } from './push-store.js';
|
|
4
|
-
|
|
5
|
-
const log = rootLogger.child({ module: 'push' });
|
|
6
|
-
const EXPO_PUSH_URL = 'https://exp.host/--/api/v2/push/send';
|
|
7
|
-
const EXPO_PUSH_RECEIPTS_URL = 'https://exp.host/--/api/v2/push/getReceipts';
|
|
8
|
-
const EXPO_RECEIPT_POLL_DELAYS_MS = [0, 1000, 3000];
|
|
9
|
-
const pushStore = new PushStore();
|
|
10
|
-
|
|
11
|
-
interface FetchResponseLike {
|
|
12
|
-
ok: boolean;
|
|
13
|
-
status: number;
|
|
14
|
-
statusText: string;
|
|
15
|
-
json: () => Promise<unknown>;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
type FetchLike = (
|
|
19
|
-
input: string,
|
|
20
|
-
init?: {
|
|
21
|
-
method?: string;
|
|
22
|
-
headers?: Record<string, string>;
|
|
23
|
-
body?: string;
|
|
24
|
-
},
|
|
25
|
-
) => Promise<FetchResponseLike>;
|
|
26
|
-
|
|
27
|
-
type SleepLike = (ms: number) => Promise<void>;
|
|
28
|
-
|
|
29
|
-
interface ExpoPushTicket {
|
|
30
|
-
status?: 'ok' | 'error';
|
|
31
|
-
id?: string;
|
|
32
|
-
message?: string;
|
|
33
|
-
details?: {
|
|
34
|
-
error?: string;
|
|
35
|
-
[key: string]: unknown;
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
interface ExpoPushResponse {
|
|
40
|
-
data?: ExpoPushTicket[];
|
|
41
|
-
errors?: unknown[];
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
interface ExpoPushReceipt {
|
|
45
|
-
status?: 'ok' | 'error';
|
|
46
|
-
message?: string;
|
|
47
|
-
details?: {
|
|
48
|
-
error?: string;
|
|
49
|
-
[key: string]: unknown;
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
interface ExpoPushReceiptResponse {
|
|
54
|
-
data?: Record<string, ExpoPushReceipt>;
|
|
55
|
-
errors?: unknown[];
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function isPushNotificationData(data: unknown): data is PushNotificationData {
|
|
59
|
-
return Boolean(
|
|
60
|
-
data
|
|
61
|
-
&& typeof data === 'object'
|
|
62
|
-
&& typeof (data as PushNotificationData).daemonId === 'string'
|
|
63
|
-
&& typeof (data as PushNotificationData).canonicalHost === 'string'
|
|
64
|
-
&& typeof (data as PushNotificationData).sessionId === 'string'
|
|
65
|
-
&& (
|
|
66
|
-
(data as PushNotificationData).agent === 'claude'
|
|
67
|
-
|| (data as PushNotificationData).agent === 'codex'
|
|
68
|
-
)
|
|
69
|
-
&& (
|
|
70
|
-
(data as PushNotificationData).eventType === 'reply_ready'
|
|
71
|
-
|| (data as PushNotificationData).eventType === 'approval_request'
|
|
72
|
-
)
|
|
73
|
-
&& (
|
|
74
|
-
typeof (data as PushNotificationData).requestId === 'undefined'
|
|
75
|
-
|| typeof (data as PushNotificationData).requestId === 'string'
|
|
76
|
-
)
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function sleep(ms: number): Promise<void> {
|
|
81
|
-
return new Promise((resolve) => {
|
|
82
|
-
setTimeout(resolve, ms);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function shouldRemoveTokenForExpoError(errorCode: string | undefined): boolean {
|
|
87
|
-
return errorCode === 'DeviceNotRegistered';
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function collectSuccessfulExpoPushTokens(
|
|
91
|
-
response: ExpoPushResponse,
|
|
92
|
-
tokens: string[],
|
|
93
|
-
): { successfulTokens: string[]; ticketErrors: Array<{ token: string; ticket: ExpoPushTicket }> } {
|
|
94
|
-
if (!Array.isArray(response.data)) {
|
|
95
|
-
return { successfulTokens: [], ticketErrors: [] };
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const successfulTokens: string[] = [];
|
|
99
|
-
const ticketErrors: Array<{ token: string; ticket: ExpoPushTicket }> = [];
|
|
100
|
-
|
|
101
|
-
for (const [index, ticket] of response.data.entries()) {
|
|
102
|
-
const token = tokens[index];
|
|
103
|
-
if (!token || !ticket || typeof ticket !== 'object') continue;
|
|
104
|
-
if (ticket.status === 'ok') {
|
|
105
|
-
successfulTokens.push(token);
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
ticketErrors.push({ token, ticket });
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return { successfulTokens, ticketErrors };
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function collectExpoPushTicketIds(
|
|
115
|
-
response: ExpoPushResponse,
|
|
116
|
-
tokens: string[],
|
|
117
|
-
): Map<string, string> {
|
|
118
|
-
const ticketIds = new Map<string, string>();
|
|
119
|
-
if (!Array.isArray(response.data)) {
|
|
120
|
-
return ticketIds;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
for (const [index, ticket] of response.data.entries()) {
|
|
124
|
-
const token = tokens[index];
|
|
125
|
-
if (!token || !ticket || ticket.status !== 'ok' || typeof ticket.id !== 'string' || ticket.id.length === 0) {
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
ticketIds.set(ticket.id, token);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return ticketIds;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export function collectExpoPushReceiptResults(
|
|
135
|
-
response: ExpoPushReceiptResponse,
|
|
136
|
-
ticketIds: Map<string, string>,
|
|
137
|
-
): { pendingTicketIds: string[]; receiptErrors: Array<{ token: string; receipt: ExpoPushReceipt }> } {
|
|
138
|
-
const pendingTicketIds: string[] = [];
|
|
139
|
-
const receiptErrors: Array<{ token: string; receipt: ExpoPushReceipt }> = [];
|
|
140
|
-
const receipts = response.data;
|
|
141
|
-
|
|
142
|
-
for (const [ticketId, token] of ticketIds.entries()) {
|
|
143
|
-
const receipt = receipts?.[ticketId];
|
|
144
|
-
if (!receipt || typeof receipt !== 'object') {
|
|
145
|
-
pendingTicketIds.push(ticketId);
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
if (receipt.status === 'error') {
|
|
149
|
-
receiptErrors.push({ token, receipt });
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return { pendingTicketIds, receiptErrors };
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async function pollExpoPushReceipts(
|
|
157
|
-
ticketIds: Map<string, string>,
|
|
158
|
-
fetchImpl: FetchLike,
|
|
159
|
-
sleepImpl: SleepLike,
|
|
160
|
-
store: PushStore,
|
|
161
|
-
): Promise<void> {
|
|
162
|
-
let pendingTicketIds = new Map(ticketIds);
|
|
163
|
-
|
|
164
|
-
for (const delayMs of EXPO_RECEIPT_POLL_DELAYS_MS) {
|
|
165
|
-
if (pendingTicketIds.size === 0) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
if (delayMs > 0) {
|
|
169
|
-
await sleepImpl(delayMs);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
let response: FetchResponseLike;
|
|
173
|
-
try {
|
|
174
|
-
response = await fetchImpl(EXPO_PUSH_RECEIPTS_URL, {
|
|
175
|
-
method: 'POST',
|
|
176
|
-
headers: { 'Content-Type': 'application/json' },
|
|
177
|
-
body: JSON.stringify({ ids: [...pendingTicketIds.keys()] }),
|
|
178
|
-
});
|
|
179
|
-
} catch (error) {
|
|
180
|
-
log.error({ error: String(error), count: pendingTicketIds.size }, 'push receipt request failed');
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (!response.ok) {
|
|
185
|
-
log.error(
|
|
186
|
-
{ status: response.status, statusText: response.statusText, count: pendingTicketIds.size },
|
|
187
|
-
'push receipt request returned error status',
|
|
188
|
-
);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const payload = await response.json().catch(() => null) as ExpoPushReceiptResponse | null;
|
|
193
|
-
if (!payload) {
|
|
194
|
-
log.error({ count: pendingTicketIds.size }, 'push receipt response was unreadable');
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const { pendingTicketIds: unresolvedTicketIds, receiptErrors } = collectExpoPushReceiptResults(
|
|
199
|
-
payload,
|
|
200
|
-
pendingTicketIds,
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
for (const { token, receipt } of receiptErrors) {
|
|
204
|
-
const errorCode = receipt.details?.error;
|
|
205
|
-
log.error({
|
|
206
|
-
token,
|
|
207
|
-
message: receipt.message,
|
|
208
|
-
details: receipt.details,
|
|
209
|
-
receiptStatus: receipt.status,
|
|
210
|
-
}, 'push receipt rejected');
|
|
211
|
-
if (shouldRemoveTokenForExpoError(errorCode)) {
|
|
212
|
-
const removed = store.unregisterToken(token);
|
|
213
|
-
log.info({ token, errorCode, removed }, 'push token removed after receipt rejection');
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
pendingTicketIds = new Map(
|
|
218
|
-
unresolvedTicketIds.map((ticketId) => [ticketId, pendingTicketIds.get(ticketId)!]),
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (pendingTicketIds.size > 0) {
|
|
223
|
-
log.warn({ pendingReceipts: pendingTicketIds.size }, 'push receipts still pending after polling');
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
export function createPushSender(options?: {
|
|
228
|
-
pushStore?: PushStore;
|
|
229
|
-
fetchImpl?: FetchLike;
|
|
230
|
-
sleepImpl?: SleepLike;
|
|
231
|
-
}) {
|
|
232
|
-
const store = options?.pushStore ?? pushStore;
|
|
233
|
-
const fetchImpl = options?.fetchImpl ?? (globalThis.fetch as FetchLike);
|
|
234
|
-
const sleepImpl = options?.sleepImpl ?? sleep;
|
|
235
|
-
|
|
236
|
-
return async function sendPush(
|
|
237
|
-
title: string,
|
|
238
|
-
body: string,
|
|
239
|
-
data?: Record<string, unknown>,
|
|
240
|
-
): Promise<void> {
|
|
241
|
-
const tokens = store.listTokens();
|
|
242
|
-
if (tokens.length === 0) return;
|
|
243
|
-
|
|
244
|
-
const messages = tokens.map((token) => ({
|
|
245
|
-
to: token,
|
|
246
|
-
sound: 'default' as const,
|
|
247
|
-
title,
|
|
248
|
-
body,
|
|
249
|
-
data,
|
|
250
|
-
badge: 1,
|
|
251
|
-
...(isPushNotificationData(data) && data.eventType === 'approval_request'
|
|
252
|
-
? { categoryId: PUSH_NOTIFICATION_CATEGORY_IDS.approvalRequestV1 }
|
|
253
|
-
: {}),
|
|
254
|
-
}));
|
|
255
|
-
|
|
256
|
-
try {
|
|
257
|
-
const res = await fetchImpl(EXPO_PUSH_URL, {
|
|
258
|
-
method: 'POST',
|
|
259
|
-
headers: { 'Content-Type': 'application/json' },
|
|
260
|
-
body: JSON.stringify(messages),
|
|
261
|
-
});
|
|
262
|
-
if (!res.ok) {
|
|
263
|
-
log.error({ status: res.status, statusText: res.statusText }, 'push send failed');
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const response = await res.json().catch(() => null) as ExpoPushResponse | null;
|
|
268
|
-
if (!response) {
|
|
269
|
-
log.error({ count: messages.length }, 'push send returned unreadable response');
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const { successfulTokens, ticketErrors } = collectSuccessfulExpoPushTokens(response, tokens);
|
|
274
|
-
const ticketIds = collectExpoPushTicketIds(response, tokens);
|
|
275
|
-
|
|
276
|
-
for (const { token, ticket } of ticketErrors) {
|
|
277
|
-
const errorCode = ticket.details?.error;
|
|
278
|
-
log.error({
|
|
279
|
-
token,
|
|
280
|
-
message: ticket.message,
|
|
281
|
-
details: ticket.details,
|
|
282
|
-
ticketStatus: ticket.status,
|
|
283
|
-
}, 'push ticket rejected');
|
|
284
|
-
if (shouldRemoveTokenForExpoError(errorCode)) {
|
|
285
|
-
const removed = store.unregisterToken(token);
|
|
286
|
-
log.info({ token, errorCode, removed }, 'push token removed after ticket rejection');
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (successfulTokens.length > 0) {
|
|
291
|
-
log.debug({ count: successfulTokens.length }, 'push sent');
|
|
292
|
-
store.markSent(successfulTokens);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (ticketIds.size > 0) {
|
|
296
|
-
await pollExpoPushReceipts(ticketIds, fetchImpl, sleepImpl, store);
|
|
297
|
-
}
|
|
298
|
-
} catch (e) {
|
|
299
|
-
log.error({ error: String(e) }, 'push send error');
|
|
300
|
-
}
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
export function registerToken(deviceId: string, token: string): void {
|
|
305
|
-
pushStore.register(deviceId, token);
|
|
306
|
-
log.info({ deviceId, token, total: pushStore.count() }, 'push token registered');
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
export function unregisterToken(deviceId: string, token: string): void {
|
|
310
|
-
const removed = pushStore.unregister(deviceId, token);
|
|
311
|
-
log.info({ deviceId, token, total: pushStore.count(), removed }, 'push token unregistered');
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
export function removeAllTokens(): void {
|
|
315
|
-
pushStore.reset();
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
export const sendPush = createPushSender();
|
package/src/safe-stdio.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
type StreamName = 'stdout' | 'stderr';
|
|
2
|
-
|
|
3
|
-
const disabledStreams: Record<StreamName, boolean> = {
|
|
4
|
-
stdout: false,
|
|
5
|
-
stderr: false,
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
function isIgnorableStreamError(error: unknown): boolean {
|
|
9
|
-
if (!error || typeof error !== 'object') return false;
|
|
10
|
-
const code = typeof (error as { code?: unknown }).code === 'string'
|
|
11
|
-
? (error as { code: string }).code
|
|
12
|
-
: '';
|
|
13
|
-
return code === 'EIO' || code === 'EPIPE';
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function isWritableStream(stream: NodeJS.WriteStream): boolean {
|
|
17
|
-
return !stream.destroyed && stream.writable !== false;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function writeToStream(name: StreamName, chunk: string): boolean {
|
|
21
|
-
if (disabledStreams[name]) return false;
|
|
22
|
-
|
|
23
|
-
const stream = name === 'stderr' ? process.stderr : process.stdout;
|
|
24
|
-
if (!isWritableStream(stream)) {
|
|
25
|
-
disabledStreams[name] = true;
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
stream.write(chunk, (error?: Error | null) => {
|
|
31
|
-
if (isIgnorableStreamError(error)) {
|
|
32
|
-
disabledStreams[name] = true;
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
return true;
|
|
36
|
-
} catch (error) {
|
|
37
|
-
if (isIgnorableStreamError(error)) {
|
|
38
|
-
disabledStreams[name] = true;
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function writeStdoutSafe(chunk: string): boolean {
|
|
46
|
-
return writeToStream('stdout', chunk);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function writeStderrSafe(chunk: string): boolean {
|
|
50
|
-
return writeToStream('stderr', chunk);
|
|
51
|
-
}
|