@tloncorp/openclaw 0.4.3 → 0.6.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 +130 -141
- package/dist/index.js +147 -138
- package/dist/index.js.map +1 -1
- package/dist/setup-api.js +2 -2
- package/dist/setup-entry.js +2 -2
- package/dist/setup-entry.js.map +1 -1
- package/dist/src/account-fields.js +7 -3
- package/dist/src/account-fields.js.map +1 -1
- package/dist/src/actions.js +73 -52
- package/dist/src/actions.js.map +1 -1
- package/dist/src/channel.js +51 -39
- package/dist/src/channel.js.map +1 -1
- package/dist/src/channel.runtime.js +61 -32
- package/dist/src/channel.runtime.js.map +1 -1
- package/dist/src/config-schema.js +24 -4
- package/dist/src/config-schema.js.map +1 -1
- package/dist/src/effective-owner.js.map +1 -1
- package/dist/src/gateway-status.js +55 -7
- package/dist/src/gateway-status.js.map +1 -1
- package/dist/src/monitor/approval.js +71 -62
- package/dist/src/monitor/approval.js.map +1 -1
- package/dist/src/monitor/command-auth.js +7 -7
- package/dist/src/monitor/command-auth.js.map +1 -1
- package/dist/src/monitor/command-bridge.js +3 -2
- package/dist/src/monitor/command-bridge.js.map +1 -1
- package/dist/src/monitor/computing-presence.js +76 -12
- package/dist/src/monitor/computing-presence.js.map +1 -1
- package/dist/src/monitor/discovery.js +16 -9
- package/dist/src/monitor/discovery.js.map +1 -1
- package/dist/src/monitor/history.js +58 -26
- package/dist/src/monitor/history.js.map +1 -1
- package/dist/src/monitor/index.js +2771 -2483
- package/dist/src/monitor/index.js.map +1 -1
- package/dist/src/monitor/media.js +106 -78
- package/dist/src/monitor/media.js.map +1 -1
- package/dist/src/monitor/nudge-runner.js +36 -27
- package/dist/src/monitor/nudge-runner.js.map +1 -1
- package/dist/src/monitor/nudge-state.js +7 -11
- package/dist/src/monitor/nudge-state.js.map +1 -1
- package/dist/src/monitor/owner-reply-persistence.js +27 -26
- package/dist/src/monitor/owner-reply-persistence.js.map +1 -1
- package/dist/src/monitor/processed-messages.js.map +1 -1
- package/dist/src/monitor/settings-sync.js +1 -8
- package/dist/src/monitor/settings-sync.js.map +1 -1
- package/dist/src/monitor/utils.js +77 -71
- package/dist/src/monitor/utils.js.map +1 -1
- package/dist/src/nudge-decision.js +40 -43
- package/dist/src/nudge-decision.js.map +1 -1
- package/dist/src/nudge-messages.js +9 -9
- package/dist/src/nudge-scheduler.js.map +1 -1
- package/dist/src/owner-listen-command.js +38 -28
- package/dist/src/owner-listen-command.js.map +1 -1
- package/dist/src/pending-nudge.js.map +1 -1
- package/dist/src/runtime.js +10 -6
- package/dist/src/runtime.js.map +1 -1
- package/dist/src/session-roles.js +2 -1
- package/dist/src/session-roles.js.map +1 -1
- package/dist/src/settings.js +233 -102
- package/dist/src/settings.js.map +1 -1
- package/dist/src/setup-core.js +32 -32
- package/dist/src/setup-core.js.map +1 -1
- package/dist/src/setup-surface.js +19 -19
- package/dist/src/setup-surface.js.map +1 -1
- package/dist/src/shared-state.js +46 -0
- package/dist/src/shared-state.js.map +1 -0
- package/dist/src/targets.js +17 -10
- package/dist/src/targets.js.map +1 -1
- package/dist/src/telemetry.js +17 -14
- package/dist/src/telemetry.js.map +1 -1
- package/dist/src/tlon-binary.js +20 -12
- package/dist/src/tlon-binary.js.map +1 -1
- package/dist/src/tlon-tool-guard.js +5 -5
- package/dist/src/tool-trace.js +17 -13
- package/dist/src/tool-trace.js.map +1 -1
- package/dist/src/types.js +30 -12
- package/dist/src/types.js.map +1 -1
- package/dist/src/urbit/api-client.js +16 -12
- package/dist/src/urbit/api-client.js.map +1 -1
- package/dist/src/urbit/auth.js +9 -9
- package/dist/src/urbit/auth.js.map +1 -1
- package/dist/src/urbit/base-url.js +11 -11
- package/dist/src/urbit/base-url.js.map +1 -1
- package/dist/src/urbit/channel-ops.js +25 -19
- package/dist/src/urbit/channel-ops.js.map +1 -1
- package/dist/src/urbit/context.js +8 -8
- package/dist/src/urbit/context.js.map +1 -1
- package/dist/src/urbit/errors.js +33 -7
- package/dist/src/urbit/errors.js.map +1 -1
- package/dist/src/urbit/fetch.js +3 -3
- package/dist/src/urbit/fetch.js.map +1 -1
- package/dist/src/urbit/http-poke.js +10 -10
- package/dist/src/urbit/http-poke.js.map +1 -1
- package/dist/src/urbit/send.js +27 -23
- package/dist/src/urbit/send.js.map +1 -1
- package/dist/src/urbit/sse-client.js +45 -41
- package/dist/src/urbit/sse-client.js.map +1 -1
- package/dist/src/urbit/story.js +31 -30
- package/dist/src/urbit/story.js.map +1 -1
- package/dist/src/urbit/upload.js +8 -8
- package/dist/src/urbit/upload.js.map +1 -1
- package/dist/src/version.generated.js +2 -1
- package/dist/src/version.generated.js.map +1 -1
- package/openclaw.plugin.json +37 -0
- package/package.json +35 -15
package/dist/src/urbit/errors.js
CHANGED
|
@@ -2,14 +2,14 @@ export class UrbitError extends Error {
|
|
|
2
2
|
code;
|
|
3
3
|
constructor(code, message, options) {
|
|
4
4
|
super(message, options);
|
|
5
|
-
this.name =
|
|
5
|
+
this.name = 'UrbitError';
|
|
6
6
|
this.code = code;
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
export class UrbitUrlError extends UrbitError {
|
|
10
10
|
constructor(message, options) {
|
|
11
|
-
super(
|
|
12
|
-
this.name =
|
|
11
|
+
super('invalid_url', message, options);
|
|
12
|
+
this.name = 'UrbitUrlError';
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
export class UrbitHttpError extends UrbitError {
|
|
@@ -17,11 +17,11 @@ export class UrbitHttpError extends UrbitError {
|
|
|
17
17
|
operation;
|
|
18
18
|
bodyText;
|
|
19
19
|
constructor(params) {
|
|
20
|
-
const suffix = params.bodyText ? ` - ${params.bodyText}` :
|
|
21
|
-
super(
|
|
20
|
+
const suffix = params.bodyText ? ` - ${params.bodyText}` : '';
|
|
21
|
+
super('http_error', `${params.operation} failed: ${params.status}${suffix}`, {
|
|
22
22
|
cause: params.cause,
|
|
23
23
|
});
|
|
24
|
-
this.name =
|
|
24
|
+
this.name = 'UrbitHttpError';
|
|
25
25
|
this.status = params.status;
|
|
26
26
|
this.operation = params.operation;
|
|
27
27
|
this.bodyText = params.bodyText;
|
|
@@ -30,7 +30,33 @@ export class UrbitHttpError extends UrbitError {
|
|
|
30
30
|
export class UrbitAuthError extends UrbitError {
|
|
31
31
|
constructor(code, message, options) {
|
|
32
32
|
super(code, message, options);
|
|
33
|
-
this.name =
|
|
33
|
+
this.name = 'UrbitAuthError';
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Format an error for logging, surfacing `err.cause` when present.
|
|
38
|
+
*
|
|
39
|
+
* Node/undici wraps transport failures as `TypeError: fetch failed` and hangs
|
|
40
|
+
* the real reason off `.cause` (typically with a `.code` like `ECONNRESET` /
|
|
41
|
+
* `UND_ERR_SOCKET` / `UND_ERR_CONNECT_TIMEOUT`). Plain `String(err)` drops
|
|
42
|
+
* that, leaving an undiagnosable "fetch failed". This appends the cause's
|
|
43
|
+
* `code` (preferred) or `message` so logs say which transport failure it was.
|
|
44
|
+
*/
|
|
45
|
+
export function describeError(err) {
|
|
46
|
+
if (!(err instanceof Error)) {
|
|
47
|
+
return String(err);
|
|
48
|
+
}
|
|
49
|
+
const cause = err.cause;
|
|
50
|
+
if (cause === undefined || cause === null) {
|
|
51
|
+
return err.message;
|
|
52
|
+
}
|
|
53
|
+
const causeCode = cause.code;
|
|
54
|
+
if (typeof causeCode === 'string' && causeCode.length > 0) {
|
|
55
|
+
return `${err.message} cause=${causeCode}`;
|
|
56
|
+
}
|
|
57
|
+
if (cause instanceof Error) {
|
|
58
|
+
return `${err.message} cause=${cause.message}`;
|
|
59
|
+
}
|
|
60
|
+
return `${err.message} cause=${String(cause)}`;
|
|
61
|
+
}
|
|
36
62
|
//# sourceMappingURL=errors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/urbit/errors.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,IAAI,CAAiB;IAE9B,
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/urbit/errors.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,IAAI,CAAiB;IAE9B,YACE,IAAoB,EACpB,OAAe,EACf,OAA6B;QAE7B,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,UAAU;IAC3C,YAAY,OAAe,EAAE,OAA6B;QACxD,KAAK,CAAC,aAAa,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,UAAU;IACnC,MAAM,CAAS;IACf,SAAS,CAAS;IAClB,QAAQ,CAAU;IAE3B,YAAY,MAKX;QACC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,KAAK,CACH,YAAY,EACZ,GAAG,MAAM,CAAC,SAAS,YAAY,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,EACvD;YACE,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CACF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IAClC,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,UAAU;IAC5C,YACE,IAAsC,EACtC,OAAe,EACf,OAA6B;QAE7B,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,IAAI,CAAC,CAAC,GAAG,YAAY,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IACD,MAAM,KAAK,GAAI,GAA2B,CAAC,KAAK,CAAC;IACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,GAAG,CAAC,OAAO,CAAC;IACrB,CAAC;IACD,MAAM,SAAS,GAAI,KAA4B,CAAC,IAAI,CAAC;IACrD,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,OAAO,GAAG,GAAG,CAAC,OAAO,UAAU,SAAS,EAAE,CAAC;IAC7C,CAAC;IACD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,GAAG,GAAG,CAAC,OAAO,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC;IACjD,CAAC;IACD,OAAO,GAAG,GAAG,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACjD,CAAC"}
|
package/dist/src/urbit/fetch.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { fetchWithSsrFGuard } from
|
|
2
|
-
import { validateUrbitBaseUrl } from
|
|
3
|
-
import { UrbitUrlError } from
|
|
1
|
+
import { fetchWithSsrFGuard, } from 'openclaw/plugin-sdk/ssrf-runtime';
|
|
2
|
+
import { validateUrbitBaseUrl } from './base-url.js';
|
|
3
|
+
import { UrbitUrlError } from './errors.js';
|
|
4
4
|
export async function urbitFetch(params) {
|
|
5
5
|
const validated = validateUrbitBaseUrl(params.baseUrl);
|
|
6
6
|
if (!validated.ok) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../../src/urbit/fetch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../../src/urbit/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,kBAAkB,GACnB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAyB5C,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAyB;IAEzB,MAAM,SAAS,GAAG,oBAAoB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACvD,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC/D,OAAO,MAAM,kBAAkB,CAAC;QAC9B,GAAG;QACH,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM,EAAE,MAAM,CAAC,UAAU;QACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { randomUUID } from
|
|
2
|
-
import { authenticate } from
|
|
3
|
-
import { ssrfPolicyFromAllowPrivateNetwork } from
|
|
4
|
-
import { urbitFetch } from
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { authenticate } from './auth.js';
|
|
3
|
+
import { ssrfPolicyFromAllowPrivateNetwork } from './context.js';
|
|
4
|
+
import { urbitFetch } from './fetch.js';
|
|
5
5
|
/**
|
|
6
6
|
* Simple HTTP-only poke that doesn't open an EventSource (avoids conflict with monitor's SSE)
|
|
7
7
|
*/
|
|
@@ -10,13 +10,13 @@ export async function createHttpPokeApi(params) {
|
|
|
10
10
|
const cookie = await authenticate(params.url, params.code, { ssrfPolicy });
|
|
11
11
|
const channelId = `${Math.floor(Date.now() / 1000)}-${randomUUID().slice(0, 8)}`;
|
|
12
12
|
const channelPath = `/~/channel/${channelId}`;
|
|
13
|
-
const shipName = params.ship.replace(/^~/,
|
|
13
|
+
const shipName = params.ship.replace(/^~/, '');
|
|
14
14
|
return {
|
|
15
15
|
poke: async (pokeParams) => {
|
|
16
16
|
const pokeId = Date.now();
|
|
17
17
|
const pokeData = {
|
|
18
18
|
id: pokeId,
|
|
19
|
-
action:
|
|
19
|
+
action: 'poke',
|
|
20
20
|
ship: shipName,
|
|
21
21
|
app: pokeParams.app,
|
|
22
22
|
mark: pokeParams.mark,
|
|
@@ -26,16 +26,16 @@ export async function createHttpPokeApi(params) {
|
|
|
26
26
|
baseUrl: params.url,
|
|
27
27
|
path: channelPath,
|
|
28
28
|
init: {
|
|
29
|
-
method:
|
|
29
|
+
method: 'PUT',
|
|
30
30
|
headers: {
|
|
31
|
-
|
|
32
|
-
Cookie: cookie.split(
|
|
31
|
+
'Content-Type': 'application/json',
|
|
32
|
+
Cookie: cookie.split(';')[0],
|
|
33
33
|
},
|
|
34
34
|
body: JSON.stringify([pokeData]),
|
|
35
35
|
},
|
|
36
36
|
ssrfPolicy,
|
|
37
37
|
timeoutMs: 30_000,
|
|
38
|
-
auditContext:
|
|
38
|
+
auditContext: 'tlon-http-poke',
|
|
39
39
|
});
|
|
40
40
|
try {
|
|
41
41
|
if (!response.ok && response.status !== 204) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-poke.js","sourceRoot":"","sources":["../../../src/urbit/http-poke.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"http-poke.js","sourceRoot":"","sources":["../../../src/urbit/http-poke.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,iCAAiC,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAWxC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAKvC;IACC,MAAM,UAAU,GAAG,iCAAiC,CAClD,MAAM,CAAC,mBAAmB,CAC3B,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;IAC3E,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IACjF,MAAM,WAAW,GAAG,cAAc,SAAS,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAE/C,OAAO;QACL,IAAI,EAAE,KAAK,EAAE,UAAwD,EAAE,EAAE;YACvE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG;gBACf,EAAE,EAAE,MAAM;gBACV,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,QAAQ;gBACd,GAAG,EAAE,UAAU,CAAC,GAAG;gBACnB,IAAI,EAAE,UAAU,CAAC,IAAI;gBACrB,IAAI,EAAE,UAAU,CAAC,IAAI;aACtB,CAAC;YAEF,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,UAAU,CAAC;gBAC7C,OAAO,EAAE,MAAM,CAAC,GAAG;gBACnB,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE;oBACJ,MAAM,EAAE,KAAK;oBACb,OAAO,EAAE;wBACP,cAAc,EAAE,kBAAkB;wBAClC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;qBAC7B;oBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC;iBACjC;gBACD,UAAU;gBACV,SAAS,EAAE,MAAM;gBACjB,YAAY,EAAE,gBAAgB;aAC/B,CAAC,CAAC;YAEH,IAAI,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBAC5C,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;oBACxC,MAAM,IAAI,KAAK,CAAC,gBAAgB,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,CAAC,CAAC;gBACpE,CAAC;gBACD,OAAO,MAAM,CAAC;YAChB,CAAC;oBAAS,CAAC;gBACT,MAAM,OAAO,EAAE,CAAC;YAClB,CAAC;QACH,CAAC;QACD,MAAM,EAAE,KAAK,IAAI,EAAE;YACjB,6BAA6B;QAC/B,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/src/urbit/send.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { addReaction as apiAddReaction, deletePost as apiDeletePost, removeReaction as apiRemoveReaction, sendPost as apiSendPost, sendReply as apiSendReply, } from '@tloncorp/api';
|
|
2
|
+
import { da, scot } from '@urbit/aura';
|
|
3
|
+
import { createImageBlock, isImageUrl, markdownToStory, } from './story.js';
|
|
4
4
|
// --- Helpers ---
|
|
5
5
|
/**
|
|
6
6
|
* Format a post ID as @ud (with dots) if it's a bare digit string.
|
|
@@ -9,7 +9,7 @@ import { markdownToStory, createImageBlock, isImageUrl } from "./story.js";
|
|
|
9
9
|
function formatPostId(postId) {
|
|
10
10
|
if (/^\d+$/.test(postId)) {
|
|
11
11
|
try {
|
|
12
|
-
return scot(
|
|
12
|
+
return scot('ud', BigInt(postId));
|
|
13
13
|
}
|
|
14
14
|
catch {
|
|
15
15
|
// fall through
|
|
@@ -23,17 +23,21 @@ function formatPostId(postId) {
|
|
|
23
23
|
* Returns the components for use with @tloncorp/api which expects them separately.
|
|
24
24
|
*/
|
|
25
25
|
function parseWritId(id) {
|
|
26
|
-
if (id.includes(
|
|
27
|
-
const idx = id.indexOf(
|
|
26
|
+
if (id.includes('/') && id.startsWith('~')) {
|
|
27
|
+
const idx = id.indexOf('/');
|
|
28
28
|
return { author: id.slice(0, idx), bareId: id.slice(idx + 1) };
|
|
29
29
|
}
|
|
30
|
-
return { author:
|
|
30
|
+
return { author: '', bareId: id };
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Compute a @ud-formatted timestamp for building message IDs.
|
|
34
|
+
*
|
|
35
|
+
* Exported so cross-repo fixture tests can pin the message-id encoding
|
|
36
|
+
* against this exact function — see `src/urbit/send.fixtures.test.ts` and
|
|
37
|
+
* `homestead/packages/shared/src/api/__tests__/dmTapTelemetryRoundTrip.test.ts`.
|
|
34
38
|
*/
|
|
35
|
-
function formatSentAt(sentAt) {
|
|
36
|
-
return scot(
|
|
39
|
+
export function formatSentAt(sentAt) {
|
|
40
|
+
return scot('ud', da.fromUnix(sentAt));
|
|
37
41
|
}
|
|
38
42
|
export async function sendDm(params) {
|
|
39
43
|
const story = markdownToStory(params.text);
|
|
@@ -55,7 +59,7 @@ export async function sendDmWithStory({ fromShip, toShip, story, replyToId, pare
|
|
|
55
59
|
authorId: fromShip,
|
|
56
60
|
botProfile,
|
|
57
61
|
});
|
|
58
|
-
return { channel:
|
|
62
|
+
return { channel: 'tlon', messageId, sentAt };
|
|
59
63
|
}
|
|
60
64
|
await apiSendPost({
|
|
61
65
|
channelId: toShip,
|
|
@@ -64,7 +68,7 @@ export async function sendDmWithStory({ fromShip, toShip, story, replyToId, pare
|
|
|
64
68
|
content: story,
|
|
65
69
|
botProfile,
|
|
66
70
|
});
|
|
67
|
-
return { channel:
|
|
71
|
+
return { channel: 'tlon', messageId, sentAt };
|
|
68
72
|
}
|
|
69
73
|
/**
|
|
70
74
|
* Unified function for posting to any channel type (chat, heap, diary).
|
|
@@ -77,13 +81,13 @@ export async function sendChannelPost({ fromShip, nest, story, replyToId, title,
|
|
|
77
81
|
await apiSendReply({
|
|
78
82
|
channelId: nest,
|
|
79
83
|
parentId: formattedReplyId,
|
|
80
|
-
parentAuthor:
|
|
84
|
+
parentAuthor: '', // Not used for channel replies
|
|
81
85
|
content: story,
|
|
82
86
|
sentAt,
|
|
83
87
|
authorId: fromShip,
|
|
84
88
|
botProfile,
|
|
85
89
|
});
|
|
86
|
-
return { channel:
|
|
90
|
+
return { channel: 'tlon', messageId: `${fromShip}/${sentAt}` };
|
|
87
91
|
}
|
|
88
92
|
await apiSendPost({
|
|
89
93
|
channelId: nest,
|
|
@@ -93,12 +97,12 @@ export async function sendChannelPost({ fromShip, nest, story, replyToId, title,
|
|
|
93
97
|
metadata: title ? { title } : undefined,
|
|
94
98
|
botProfile,
|
|
95
99
|
});
|
|
96
|
-
return { channel:
|
|
100
|
+
return { channel: 'tlon', messageId: `${fromShip}/${sentAt}` };
|
|
97
101
|
}
|
|
98
102
|
// --- Utilities ---
|
|
99
103
|
export function buildMediaText(text, mediaUrl) {
|
|
100
|
-
const cleanText = text?.trim() ??
|
|
101
|
-
const cleanUrl = mediaUrl?.trim() ??
|
|
104
|
+
const cleanText = text?.trim() ?? '';
|
|
105
|
+
const cleanUrl = mediaUrl?.trim() ?? '';
|
|
102
106
|
if (cleanText && cleanUrl) {
|
|
103
107
|
return `${cleanText}\n${cleanUrl}`;
|
|
104
108
|
}
|
|
@@ -112,23 +116,23 @@ export function buildMediaText(text, mediaUrl) {
|
|
|
112
116
|
*/
|
|
113
117
|
export function buildMediaStory(text, mediaUrl) {
|
|
114
118
|
const story = [];
|
|
115
|
-
const cleanText = text?.trim() ??
|
|
116
|
-
const cleanUrl = mediaUrl?.trim() ??
|
|
119
|
+
const cleanText = text?.trim() ?? '';
|
|
120
|
+
const cleanUrl = mediaUrl?.trim() ?? '';
|
|
117
121
|
// Add text content if present
|
|
118
122
|
if (cleanText) {
|
|
119
123
|
story.push(...markdownToStory(cleanText));
|
|
120
124
|
}
|
|
121
125
|
// Add image block if URL looks like an image
|
|
122
126
|
if (cleanUrl && isImageUrl(cleanUrl)) {
|
|
123
|
-
story.push(createImageBlock(cleanUrl,
|
|
127
|
+
story.push(createImageBlock(cleanUrl, ''));
|
|
124
128
|
}
|
|
125
129
|
else if (cleanUrl) {
|
|
126
130
|
// For non-image URLs, add as a link
|
|
127
131
|
story.push({ inline: [{ link: { href: cleanUrl, content: cleanUrl } }] });
|
|
128
132
|
}
|
|
129
|
-
return story.length > 0 ? story : [{ inline: [
|
|
133
|
+
return story.length > 0 ? story : [{ inline: [''] }];
|
|
130
134
|
}
|
|
131
|
-
export async function addChannelReaction({ fromShip, hostShip, channelName, postId, react, nestPrefix =
|
|
135
|
+
export async function addChannelReaction({ fromShip, hostShip, channelName, postId, react, nestPrefix = 'chat', parentId, }) {
|
|
132
136
|
const nest = `${nestPrefix}/${hostShip}/${channelName}`;
|
|
133
137
|
const formattedPostId = formatPostId(postId);
|
|
134
138
|
await apiAddReaction({
|
|
@@ -140,7 +144,7 @@ export async function addChannelReaction({ fromShip, hostShip, channelName, post
|
|
|
140
144
|
...(parentId && { parentId: formatPostId(parentId) }),
|
|
141
145
|
});
|
|
142
146
|
}
|
|
143
|
-
export async function removeChannelReaction({ fromShip, hostShip, channelName, postId, nestPrefix =
|
|
147
|
+
export async function removeChannelReaction({ fromShip, hostShip, channelName, postId, nestPrefix = 'chat', parentId, }) {
|
|
144
148
|
const nest = `${nestPrefix}/${hostShip}/${channelName}`;
|
|
145
149
|
const formattedPostId = formatPostId(postId);
|
|
146
150
|
await apiRemoveReaction({
|
|
@@ -206,7 +210,7 @@ export async function removeDmReaction({ fromShip, toShip, messageId, parentId,
|
|
|
206
210
|
export async function deleteHeapPost({ hostShip, channelName, curioId, }) {
|
|
207
211
|
const nest = `heap/${hostShip}/${channelName}`;
|
|
208
212
|
const formattedCurioId = formatPostId(curioId);
|
|
209
|
-
await apiDeletePost(nest, formattedCurioId,
|
|
213
|
+
await apiDeletePost(nest, formattedCurioId, '');
|
|
210
214
|
return { ok: true };
|
|
211
215
|
}
|
|
212
216
|
//# sourceMappingURL=send.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../../src/urbit/send.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../../src/urbit/send.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { randomUUID } from
|
|
2
|
-
import { Readable } from
|
|
3
|
-
import { ensureUrbitChannelOpen, pokeUrbitChannel, scryUrbitPath } from
|
|
4
|
-
import { getUrbitContext, normalizeUrbitCookie } from
|
|
5
|
-
import { urbitFetch } from
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { Readable } from 'node:stream';
|
|
3
|
+
import { ensureUrbitChannelOpen, pokeUrbitChannel, scryUrbitPath, } from './channel-ops.js';
|
|
4
|
+
import { getUrbitContext, normalizeUrbitCookie } from './context.js';
|
|
5
|
+
import { urbitFetch } from './fetch.js';
|
|
6
6
|
export class UrbitSSEClient {
|
|
7
7
|
url;
|
|
8
8
|
cookie;
|
|
@@ -50,13 +50,17 @@ export class UrbitSSEClient {
|
|
|
50
50
|
const subId = this.subscriptions.length + 1;
|
|
51
51
|
const subscription = {
|
|
52
52
|
id: subId,
|
|
53
|
-
action:
|
|
53
|
+
action: 'subscribe',
|
|
54
54
|
ship: this.ship,
|
|
55
55
|
app: params.app,
|
|
56
56
|
path: params.path,
|
|
57
57
|
};
|
|
58
58
|
this.subscriptions.push(subscription);
|
|
59
|
-
this.eventHandlers.set(subId, {
|
|
59
|
+
this.eventHandlers.set(subId, {
|
|
60
|
+
event: params.event,
|
|
61
|
+
err: params.err,
|
|
62
|
+
quit: params.quit,
|
|
63
|
+
});
|
|
60
64
|
if (this.isConnected) {
|
|
61
65
|
try {
|
|
62
66
|
await this.sendSubscription(subscription);
|
|
@@ -73,9 +77,9 @@ export class UrbitSSEClient {
|
|
|
73
77
|
baseUrl: this.url,
|
|
74
78
|
path: `/~/channel/${this.channelId}`,
|
|
75
79
|
init: {
|
|
76
|
-
method:
|
|
80
|
+
method: 'PUT',
|
|
77
81
|
headers: {
|
|
78
|
-
|
|
82
|
+
'Content-Type': 'application/json',
|
|
79
83
|
Cookie: this.cookie,
|
|
80
84
|
},
|
|
81
85
|
body: JSON.stringify([subscription]),
|
|
@@ -84,12 +88,12 @@ export class UrbitSSEClient {
|
|
|
84
88
|
lookupFn: this.lookupFn,
|
|
85
89
|
fetchImpl: this.fetchImpl,
|
|
86
90
|
timeoutMs: 30_000,
|
|
87
|
-
auditContext:
|
|
91
|
+
auditContext: 'tlon-urbit-subscribe',
|
|
88
92
|
});
|
|
89
93
|
try {
|
|
90
94
|
if (!response.ok && response.status !== 204) {
|
|
91
|
-
const errorText = await response.text().catch(() =>
|
|
92
|
-
throw new Error(`Subscribe failed: ${response.status}${errorText ? ` - ${errorText}` :
|
|
95
|
+
const errorText = await response.text().catch(() => '');
|
|
96
|
+
throw new Error(`Subscribe failed: ${response.status}${errorText ? ` - ${errorText}` : ''}`);
|
|
93
97
|
}
|
|
94
98
|
}
|
|
95
99
|
finally {
|
|
@@ -107,7 +111,7 @@ export class UrbitSSEClient {
|
|
|
107
111
|
fetchImpl: this.fetchImpl,
|
|
108
112
|
}, {
|
|
109
113
|
createBody: this.subscriptions,
|
|
110
|
-
createAuditContext:
|
|
114
|
+
createAuditContext: 'tlon-urbit-channel-create',
|
|
111
115
|
});
|
|
112
116
|
await this.openStream();
|
|
113
117
|
this.isConnected = true;
|
|
@@ -123,9 +127,9 @@ export class UrbitSSEClient {
|
|
|
123
127
|
baseUrl: this.url,
|
|
124
128
|
path: `/~/channel/${this.channelId}`,
|
|
125
129
|
init: {
|
|
126
|
-
method:
|
|
130
|
+
method: 'GET',
|
|
127
131
|
headers: {
|
|
128
|
-
Accept:
|
|
132
|
+
Accept: 'text/event-stream',
|
|
129
133
|
Cookie: this.cookie,
|
|
130
134
|
},
|
|
131
135
|
},
|
|
@@ -133,7 +137,7 @@ export class UrbitSSEClient {
|
|
|
133
137
|
lookupFn: this.lookupFn,
|
|
134
138
|
fetchImpl: this.fetchImpl,
|
|
135
139
|
signal: controller.signal,
|
|
136
|
-
auditContext:
|
|
140
|
+
auditContext: 'tlon-urbit-sse-stream',
|
|
137
141
|
});
|
|
138
142
|
this.streamRelease = release;
|
|
139
143
|
// Clear timeout once connection established (headers received).
|
|
@@ -160,7 +164,7 @@ export class UrbitSSEClient {
|
|
|
160
164
|
}
|
|
161
165
|
// oxlint-disable-next-line typescript/no-explicit-any
|
|
162
166
|
const stream = body instanceof ReadableStream ? Readable.fromWeb(body) : body;
|
|
163
|
-
let buffer =
|
|
167
|
+
let buffer = '';
|
|
164
168
|
try {
|
|
165
169
|
for await (const chunk of stream) {
|
|
166
170
|
if (this.aborted) {
|
|
@@ -168,7 +172,7 @@ export class UrbitSSEClient {
|
|
|
168
172
|
}
|
|
169
173
|
buffer += chunk.toString();
|
|
170
174
|
let eventEnd;
|
|
171
|
-
while ((eventEnd = buffer.indexOf(
|
|
175
|
+
while ((eventEnd = buffer.indexOf('\n\n')) !== -1) {
|
|
172
176
|
const eventData = buffer.substring(0, eventEnd);
|
|
173
177
|
buffer = buffer.substring(eventEnd + 2);
|
|
174
178
|
this.processEvent(eventData);
|
|
@@ -184,20 +188,20 @@ export class UrbitSSEClient {
|
|
|
184
188
|
this.streamController = null;
|
|
185
189
|
if (!this.aborted && this.autoReconnect) {
|
|
186
190
|
this.isConnected = false;
|
|
187
|
-
this.logger.log?.(
|
|
191
|
+
this.logger.log?.('[SSE] Stream ended, attempting reconnection...');
|
|
188
192
|
await this.attemptReconnect();
|
|
189
193
|
}
|
|
190
194
|
}
|
|
191
195
|
}
|
|
192
196
|
processEvent(eventData) {
|
|
193
|
-
const lines = eventData.split(
|
|
197
|
+
const lines = eventData.split('\n');
|
|
194
198
|
let data = null;
|
|
195
199
|
let eventId = null;
|
|
196
200
|
for (const line of lines) {
|
|
197
|
-
if (line.startsWith(
|
|
201
|
+
if (line.startsWith('id: ')) {
|
|
198
202
|
eventId = parseInt(line.substring(4), 10);
|
|
199
203
|
}
|
|
200
|
-
if (line.startsWith(
|
|
204
|
+
if (line.startsWith('data: ')) {
|
|
201
205
|
data = line.substring(6);
|
|
202
206
|
}
|
|
203
207
|
}
|
|
@@ -219,7 +223,7 @@ export class UrbitSSEClient {
|
|
|
219
223
|
try {
|
|
220
224
|
const parsed = JSON.parse(data);
|
|
221
225
|
// Log poke ack/nack responses (normally silent — critical for debugging DM delivery issues)
|
|
222
|
-
if (parsed.response ===
|
|
226
|
+
if (parsed.response === 'poke') {
|
|
223
227
|
if (parsed.err) {
|
|
224
228
|
this.logger.error?.(`[SSE] Poke NACK id=${parsed.id}: ${JSON.stringify(parsed.err)}`);
|
|
225
229
|
}
|
|
@@ -228,7 +232,7 @@ export class UrbitSSEClient {
|
|
|
228
232
|
}
|
|
229
233
|
return;
|
|
230
234
|
}
|
|
231
|
-
if (parsed.response ===
|
|
235
|
+
if (parsed.response === 'quit') {
|
|
232
236
|
if (parsed.id) {
|
|
233
237
|
const handlers = this.eventHandlers.get(parsed.id);
|
|
234
238
|
if (handlers?.quit) {
|
|
@@ -266,7 +270,7 @@ export class UrbitSSEClient {
|
|
|
266
270
|
ssrfPolicy: this.ssrfPolicy,
|
|
267
271
|
lookupFn: this.lookupFn,
|
|
268
272
|
fetchImpl: this.fetchImpl,
|
|
269
|
-
}, { ...params, auditContext:
|
|
273
|
+
}, { ...params, auditContext: 'tlon-urbit-poke' });
|
|
270
274
|
}
|
|
271
275
|
async scry(path) {
|
|
272
276
|
return await scryUrbitPath({
|
|
@@ -275,7 +279,7 @@ export class UrbitSSEClient {
|
|
|
275
279
|
ssrfPolicy: this.ssrfPolicy,
|
|
276
280
|
lookupFn: this.lookupFn,
|
|
277
281
|
fetchImpl: this.fetchImpl,
|
|
278
|
-
}, { path, auditContext:
|
|
282
|
+
}, { path, auditContext: 'tlon-urbit-scry' });
|
|
279
283
|
}
|
|
280
284
|
/**
|
|
281
285
|
* Update the cookie used for authentication.
|
|
@@ -288,16 +292,16 @@ export class UrbitSSEClient {
|
|
|
288
292
|
this.lastAcknowledgedEventId = eventId;
|
|
289
293
|
const ackData = {
|
|
290
294
|
id: Date.now(),
|
|
291
|
-
action:
|
|
292
|
-
|
|
295
|
+
action: 'ack',
|
|
296
|
+
'event-id': eventId,
|
|
293
297
|
};
|
|
294
298
|
const { response, release } = await urbitFetch({
|
|
295
299
|
baseUrl: this.url,
|
|
296
300
|
path: `/~/channel/${this.channelId}`,
|
|
297
301
|
init: {
|
|
298
|
-
method:
|
|
302
|
+
method: 'PUT',
|
|
299
303
|
headers: {
|
|
300
|
-
|
|
304
|
+
'Content-Type': 'application/json',
|
|
301
305
|
Cookie: this.cookie,
|
|
302
306
|
},
|
|
303
307
|
body: JSON.stringify([ackData]),
|
|
@@ -306,7 +310,7 @@ export class UrbitSSEClient {
|
|
|
306
310
|
lookupFn: this.lookupFn,
|
|
307
311
|
fetchImpl: this.fetchImpl,
|
|
308
312
|
timeoutMs: 10_000,
|
|
309
|
-
auditContext:
|
|
313
|
+
auditContext: 'tlon-urbit-ack',
|
|
310
314
|
});
|
|
311
315
|
try {
|
|
312
316
|
if (!response.ok) {
|
|
@@ -319,7 +323,7 @@ export class UrbitSSEClient {
|
|
|
319
323
|
}
|
|
320
324
|
async attemptReconnect() {
|
|
321
325
|
if (this.aborted || !this.autoReconnect) {
|
|
322
|
-
this.logger.log?.(
|
|
326
|
+
this.logger.log?.('[SSE] Reconnection aborted or disabled');
|
|
323
327
|
return;
|
|
324
328
|
}
|
|
325
329
|
// If we've hit max attempts, wait longer then reset and keep trying
|
|
@@ -329,7 +333,7 @@ export class UrbitSSEClient {
|
|
|
329
333
|
const extendedBackoff = 10000; // 10 seconds
|
|
330
334
|
await new Promise((resolve) => setTimeout(resolve, extendedBackoff));
|
|
331
335
|
this.reconnectAttempts = 0; // Reset counter to continue trying
|
|
332
|
-
this.logger.log?.(
|
|
336
|
+
this.logger.log?.('[SSE] Reconnection attempts reset, resuming reconnection...');
|
|
333
337
|
}
|
|
334
338
|
this.reconnectAttempts += 1;
|
|
335
339
|
const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1), this.maxReconnectDelay);
|
|
@@ -342,7 +346,7 @@ export class UrbitSSEClient {
|
|
|
342
346
|
await this.onReconnect(this);
|
|
343
347
|
}
|
|
344
348
|
await this.connect();
|
|
345
|
-
this.logger.log?.(
|
|
349
|
+
this.logger.log?.('[SSE] Reconnection successful!');
|
|
346
350
|
}
|
|
347
351
|
catch (error) {
|
|
348
352
|
this.logger.error?.(`[SSE] Reconnection failed: ${String(error)}`);
|
|
@@ -374,7 +378,7 @@ export class UrbitSSEClient {
|
|
|
374
378
|
const newSubId = this.subscriptions.length + 1;
|
|
375
379
|
const newSub = {
|
|
376
380
|
id: newSubId,
|
|
377
|
-
action:
|
|
381
|
+
action: 'subscribe',
|
|
378
382
|
ship: this.ship,
|
|
379
383
|
app: oldSub.app,
|
|
380
384
|
path: oldSub.path,
|
|
@@ -399,7 +403,7 @@ export class UrbitSSEClient {
|
|
|
399
403
|
try {
|
|
400
404
|
const unsubscribes = this.subscriptions.map((sub) => ({
|
|
401
405
|
id: sub.id,
|
|
402
|
-
action:
|
|
406
|
+
action: 'unsubscribe',
|
|
403
407
|
subscription: sub.id,
|
|
404
408
|
}));
|
|
405
409
|
{
|
|
@@ -407,9 +411,9 @@ export class UrbitSSEClient {
|
|
|
407
411
|
baseUrl: this.url,
|
|
408
412
|
path: `/~/channel/${this.channelId}`,
|
|
409
413
|
init: {
|
|
410
|
-
method:
|
|
414
|
+
method: 'PUT',
|
|
411
415
|
headers: {
|
|
412
|
-
|
|
416
|
+
'Content-Type': 'application/json',
|
|
413
417
|
Cookie: this.cookie,
|
|
414
418
|
},
|
|
415
419
|
body: JSON.stringify(unsubscribes),
|
|
@@ -418,7 +422,7 @@ export class UrbitSSEClient {
|
|
|
418
422
|
lookupFn: this.lookupFn,
|
|
419
423
|
fetchImpl: this.fetchImpl,
|
|
420
424
|
timeoutMs: 30_000,
|
|
421
|
-
auditContext:
|
|
425
|
+
auditContext: 'tlon-urbit-unsubscribe',
|
|
422
426
|
});
|
|
423
427
|
try {
|
|
424
428
|
void response.body?.cancel();
|
|
@@ -432,7 +436,7 @@ export class UrbitSSEClient {
|
|
|
432
436
|
baseUrl: this.url,
|
|
433
437
|
path: `/~/channel/${this.channelId}`,
|
|
434
438
|
init: {
|
|
435
|
-
method:
|
|
439
|
+
method: 'DELETE',
|
|
436
440
|
headers: {
|
|
437
441
|
Cookie: this.cookie,
|
|
438
442
|
},
|
|
@@ -441,7 +445,7 @@ export class UrbitSSEClient {
|
|
|
441
445
|
lookupFn: this.lookupFn,
|
|
442
446
|
fetchImpl: this.fetchImpl,
|
|
443
447
|
timeoutMs: 30_000,
|
|
444
|
-
auditContext:
|
|
448
|
+
auditContext: 'tlon-urbit-channel-close',
|
|
445
449
|
});
|
|
446
450
|
try {
|
|
447
451
|
void response.body?.cancel();
|