@tloncorp/openclaw 0.1.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 +174 -0
- package/dist/index.js +190 -0
- package/dist/index.js.map +1 -0
- package/dist/src/account-fields.js +17 -0
- package/dist/src/account-fields.js.map +1 -0
- package/dist/src/actions.js +164 -0
- package/dist/src/actions.js.map +1 -0
- package/dist/src/channel.js +400 -0
- package/dist/src/channel.js.map +1 -0
- package/dist/src/config-schema.js +55 -0
- package/dist/src/config-schema.js.map +1 -0
- package/dist/src/monitor/approval.js +194 -0
- package/dist/src/monitor/approval.js.map +1 -0
- package/dist/src/monitor/discovery.js +64 -0
- package/dist/src/monitor/discovery.js.map +1 -0
- package/dist/src/monitor/history.js +158 -0
- package/dist/src/monitor/history.js.map +1 -0
- package/dist/src/monitor/index.js +1940 -0
- package/dist/src/monitor/index.js.map +1 -0
- package/dist/src/monitor/media.js +128 -0
- package/dist/src/monitor/media.js.map +1 -0
- package/dist/src/monitor/processed-messages.js +38 -0
- package/dist/src/monitor/processed-messages.js.map +1 -0
- package/dist/src/monitor/utils.js +283 -0
- package/dist/src/monitor/utils.js.map +1 -0
- package/dist/src/onboarding.js +178 -0
- package/dist/src/onboarding.js.map +1 -0
- package/dist/src/runtime.js +11 -0
- package/dist/src/runtime.js.map +1 -0
- package/dist/src/settings.js +305 -0
- package/dist/src/settings.js.map +1 -0
- package/dist/src/targets.js +85 -0
- package/dist/src/targets.js.map +1 -0
- package/dist/src/types.js +79 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/urbit/api-client.js +104 -0
- package/dist/src/urbit/api-client.js.map +1 -0
- package/dist/src/urbit/auth.js +35 -0
- package/dist/src/urbit/auth.js.map +1 -0
- package/dist/src/urbit/base-url.js +45 -0
- package/dist/src/urbit/base-url.js.map +1 -0
- package/dist/src/urbit/channel-ops.js +136 -0
- package/dist/src/urbit/channel-ops.js.map +1 -0
- package/dist/src/urbit/context.js +42 -0
- package/dist/src/urbit/context.js.map +1 -0
- package/dist/src/urbit/errors.js +36 -0
- package/dist/src/urbit/errors.js.map +1 -0
- package/dist/src/urbit/fetch.js +23 -0
- package/dist/src/urbit/fetch.js.map +1 -0
- package/dist/src/urbit/foreigns.js +6 -0
- package/dist/src/urbit/foreigns.js.map +1 -0
- package/dist/src/urbit/http-poke.js +56 -0
- package/dist/src/urbit/http-poke.js.map +1 -0
- package/dist/src/urbit/send.js +208 -0
- package/dist/src/urbit/send.js.map +1 -0
- package/dist/src/urbit/sse-client.js +453 -0
- package/dist/src/urbit/sse-client.js.map +1 -0
- package/dist/src/urbit/story.js +286 -0
- package/dist/src/urbit/story.js.map +1 -0
- package/dist/src/urbit/upload.js +51 -0
- package/dist/src/urbit/upload.js.map +1 -0
- package/openclaw.plugin.json +10 -0
- package/package.json +84 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export function resolveTlonAccount(cfg, accountId) {
|
|
2
|
+
const base = cfg.channels?.tlon;
|
|
3
|
+
if (!base) {
|
|
4
|
+
return {
|
|
5
|
+
accountId: accountId || "default",
|
|
6
|
+
name: null,
|
|
7
|
+
enabled: false,
|
|
8
|
+
configured: false,
|
|
9
|
+
ship: null,
|
|
10
|
+
url: null,
|
|
11
|
+
code: null,
|
|
12
|
+
allowPrivateNetwork: null,
|
|
13
|
+
groupChannels: [],
|
|
14
|
+
dmAllowlist: [],
|
|
15
|
+
groupInviteAllowlist: [],
|
|
16
|
+
autoDiscoverChannels: null,
|
|
17
|
+
showModelSignature: null,
|
|
18
|
+
autoAcceptDmInvites: null,
|
|
19
|
+
autoAcceptGroupInvites: null,
|
|
20
|
+
defaultAuthorizedShips: [],
|
|
21
|
+
ownerShip: null,
|
|
22
|
+
reactionLevel: null,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const useDefault = !accountId || accountId === "default";
|
|
26
|
+
const account = useDefault ? base : base.accounts?.[accountId];
|
|
27
|
+
const ship = (account?.ship ?? base.ship ?? null);
|
|
28
|
+
const url = (account?.url ?? base.url ?? null);
|
|
29
|
+
const code = (account?.code ?? base.code ?? null);
|
|
30
|
+
const allowPrivateNetwork = (account?.allowPrivateNetwork ?? base.allowPrivateNetwork ?? null);
|
|
31
|
+
const groupChannels = (account?.groupChannels ?? base.groupChannels ?? []);
|
|
32
|
+
const dmAllowlist = (account?.dmAllowlist ?? base.dmAllowlist ?? []);
|
|
33
|
+
const groupInviteAllowlist = (account?.groupInviteAllowlist ??
|
|
34
|
+
base.groupInviteAllowlist ??
|
|
35
|
+
[]);
|
|
36
|
+
const autoDiscoverChannels = (account?.autoDiscoverChannels ??
|
|
37
|
+
base.autoDiscoverChannels ??
|
|
38
|
+
null);
|
|
39
|
+
const showModelSignature = (account?.showModelSignature ?? base.showModelSignature ?? null);
|
|
40
|
+
const autoAcceptDmInvites = (account?.autoAcceptDmInvites ?? base.autoAcceptDmInvites ?? null);
|
|
41
|
+
const autoAcceptGroupInvites = (account?.autoAcceptGroupInvites ??
|
|
42
|
+
base.autoAcceptGroupInvites ??
|
|
43
|
+
null);
|
|
44
|
+
const ownerShip = (account?.ownerShip ?? base.ownerShip ?? null);
|
|
45
|
+
const reactionLevel = (account?.reactionLevel ?? base.reactionLevel ?? null);
|
|
46
|
+
const defaultAuthorizedShips = (account?.defaultAuthorizedShips ??
|
|
47
|
+
base?.defaultAuthorizedShips ??
|
|
48
|
+
[]);
|
|
49
|
+
const configured = Boolean(ship && url && code);
|
|
50
|
+
return {
|
|
51
|
+
accountId: accountId || "default",
|
|
52
|
+
name: (account?.name ?? base.name ?? null),
|
|
53
|
+
enabled: (account?.enabled ?? base.enabled ?? true) !== false,
|
|
54
|
+
configured,
|
|
55
|
+
ship,
|
|
56
|
+
url,
|
|
57
|
+
code,
|
|
58
|
+
allowPrivateNetwork,
|
|
59
|
+
groupChannels,
|
|
60
|
+
dmAllowlist,
|
|
61
|
+
groupInviteAllowlist,
|
|
62
|
+
autoDiscoverChannels,
|
|
63
|
+
showModelSignature,
|
|
64
|
+
autoAcceptDmInvites,
|
|
65
|
+
autoAcceptGroupInvites,
|
|
66
|
+
defaultAuthorizedShips,
|
|
67
|
+
ownerShip,
|
|
68
|
+
reactionLevel,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function listTlonAccountIds(cfg) {
|
|
72
|
+
const base = cfg.channels?.tlon;
|
|
73
|
+
if (!base) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
const accounts = base.accounts ?? {};
|
|
77
|
+
return [...(base.ship ? ["default"] : []), ...Object.keys(accounts)];
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { configureClient } from "@tloncorp/api";
|
|
2
|
+
import { createHttpPokeApi } from "./http-poke.js";
|
|
3
|
+
import { authenticate } from "./auth.js";
|
|
4
|
+
import { ssrfPolicyFromAllowPrivateNetwork } from "./context.js";
|
|
5
|
+
import { urbitFetch } from "./fetch.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create a minimal Urbit-compatible shim that delegates poke() to the given function.
|
|
8
|
+
* The @tloncorp/api configureClient accepts a `client` that looks like an Urbit instance.
|
|
9
|
+
* Includes stubs for connect/eventSource/scryWithInfo so configureClient never crashes.
|
|
10
|
+
*/
|
|
11
|
+
function createClientShim(pokeFn, scryFn) {
|
|
12
|
+
return {
|
|
13
|
+
poke: (params) => pokeFn(params),
|
|
14
|
+
on: () => ({ on: () => ({}) }),
|
|
15
|
+
// connect/eventSource are called by configureClient when code is provided.
|
|
16
|
+
// Our shim should never hit that path (we always inject the client), but
|
|
17
|
+
// if another configureClient call happens without injecting, these no-ops
|
|
18
|
+
// prevent a TypeError crash.
|
|
19
|
+
connect: async () => { },
|
|
20
|
+
eventSource: async () => { },
|
|
21
|
+
// scryWithInfo is used by @tloncorp/api for scry operations (e.g., uploadFile).
|
|
22
|
+
scryWithInfo: scryFn
|
|
23
|
+
? async (params) => {
|
|
24
|
+
const result = await scryFn(params);
|
|
25
|
+
return { result: result, responseSizeInBytes: 0, responseStatus: 200 };
|
|
26
|
+
}
|
|
27
|
+
: async () => {
|
|
28
|
+
throw new Error("Scry not supported on this client shim");
|
|
29
|
+
},
|
|
30
|
+
// Properties configureClient may access
|
|
31
|
+
verbose: false,
|
|
32
|
+
nodeId: "",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Configure @tloncorp/api's global client with an existing poke function.
|
|
37
|
+
* Use this when you already have an authenticated poke backend (e.g., SSE client in monitor).
|
|
38
|
+
*/
|
|
39
|
+
export function configureTlonApiWithPoke(pokeFn, ship, shipUrl, scryFn) {
|
|
40
|
+
const shim = createClientShim(pokeFn, scryFn);
|
|
41
|
+
configureClient({
|
|
42
|
+
shipName: ship.replace(/^~/, ""),
|
|
43
|
+
shipUrl,
|
|
44
|
+
client: shim,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create an authenticated HTTP-only client, configure @tloncorp/api, run fn, clean up.
|
|
49
|
+
* Use this for one-shot outbound operations (channel.ts, actions.ts).
|
|
50
|
+
* Supports both poke and scry (needed for uploadFile).
|
|
51
|
+
*/
|
|
52
|
+
export async function withAuthenticatedTlonApi(params, fn) {
|
|
53
|
+
const ssrfPolicy = ssrfPolicyFromAllowPrivateNetwork(params.allowPrivateNetwork);
|
|
54
|
+
const cookie = await authenticate(params.url, params.code, { ssrfPolicy });
|
|
55
|
+
const api = await createHttpPokeApi({
|
|
56
|
+
url: params.url,
|
|
57
|
+
code: params.code,
|
|
58
|
+
ship: params.ship,
|
|
59
|
+
allowPrivateNetwork: params.allowPrivateNetwork,
|
|
60
|
+
});
|
|
61
|
+
// Build a scry function using the authenticated cookie
|
|
62
|
+
const scryFn = async ({ app, path }) => {
|
|
63
|
+
const scryPath = `/~/scry/${app}${path}.json`;
|
|
64
|
+
const { response, release } = await urbitFetch({
|
|
65
|
+
baseUrl: params.url,
|
|
66
|
+
path: scryPath,
|
|
67
|
+
init: {
|
|
68
|
+
method: "GET",
|
|
69
|
+
headers: { Cookie: cookie },
|
|
70
|
+
},
|
|
71
|
+
ssrfPolicy,
|
|
72
|
+
timeoutMs: 30_000,
|
|
73
|
+
auditContext: "tlon-api-scry",
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
throw new Error(`Scry failed: ${response.status} ${scryPath}`);
|
|
78
|
+
}
|
|
79
|
+
return await response.json();
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
await release();
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const shim = createClientShim(api.poke, scryFn);
|
|
86
|
+
configureClient({
|
|
87
|
+
shipName: params.ship.replace(/^~/, ""),
|
|
88
|
+
shipUrl: params.url,
|
|
89
|
+
client: shim,
|
|
90
|
+
getCode: async () => params.code,
|
|
91
|
+
});
|
|
92
|
+
try {
|
|
93
|
+
return await fn();
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
try {
|
|
97
|
+
await api.delete();
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// ignore cleanup errors
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../../src/urbit/api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { UrbitAuthError } from "./errors.js";
|
|
2
|
+
import { urbitFetch } from "./fetch.js";
|
|
3
|
+
export async function authenticate(url, code, options = {}) {
|
|
4
|
+
const { response, release } = await urbitFetch({
|
|
5
|
+
baseUrl: url,
|
|
6
|
+
path: "/~/login",
|
|
7
|
+
init: {
|
|
8
|
+
method: "POST",
|
|
9
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
10
|
+
body: new URLSearchParams({ password: code }).toString(),
|
|
11
|
+
},
|
|
12
|
+
ssrfPolicy: options.ssrfPolicy,
|
|
13
|
+
lookupFn: options.lookupFn,
|
|
14
|
+
fetchImpl: options.fetchImpl,
|
|
15
|
+
timeoutMs: options.timeoutMs ?? 15_000,
|
|
16
|
+
maxRedirects: 3,
|
|
17
|
+
auditContext: "tlon-urbit-login",
|
|
18
|
+
});
|
|
19
|
+
try {
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
throw new UrbitAuthError("auth_failed", `Login failed with status ${response.status}`);
|
|
22
|
+
}
|
|
23
|
+
// Some Urbit setups require the response body to be read before cookie headers finalize.
|
|
24
|
+
await response.text().catch(() => { });
|
|
25
|
+
const cookie = response.headers.get("set-cookie");
|
|
26
|
+
if (!cookie) {
|
|
27
|
+
throw new UrbitAuthError("missing_cookie", "No authentication cookie received");
|
|
28
|
+
}
|
|
29
|
+
return cookie;
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
await release();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/urbit/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AASxC,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAW,EACX,IAAY,EACZ,UAAoC,EAAE;IAEtC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,UAAU,CAAC;QAC7C,OAAO,EAAE,GAAG;QACZ,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE;YACJ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,IAAI,eAAe,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;SACzD;QACD,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,MAAM;QACtC,YAAY,EAAE,CAAC;QACf,YAAY,EAAE,kBAAkB;KACjC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,cAAc,CAAC,aAAa,EAAE,4BAA4B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACzF,CAAC;QAED,yFAAyF;QACzF,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,cAAc,CAAC,gBAAgB,EAAE,mCAAmC,CAAC,CAAC;QAClF,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { isBlockedHostname, isPrivateIpAddress } from "openclaw/plugin-sdk";
|
|
2
|
+
function hasScheme(value) {
|
|
3
|
+
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
|
4
|
+
}
|
|
5
|
+
export function validateUrbitBaseUrl(raw) {
|
|
6
|
+
const trimmed = String(raw ?? "").trim();
|
|
7
|
+
if (!trimmed) {
|
|
8
|
+
return { ok: false, error: "Required" };
|
|
9
|
+
}
|
|
10
|
+
const candidate = hasScheme(trimmed) ? trimmed : `https://${trimmed}`;
|
|
11
|
+
let parsed;
|
|
12
|
+
try {
|
|
13
|
+
parsed = new URL(candidate);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return { ok: false, error: "Invalid URL" };
|
|
17
|
+
}
|
|
18
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
19
|
+
return { ok: false, error: "URL must use http:// or https://" };
|
|
20
|
+
}
|
|
21
|
+
if (parsed.username || parsed.password) {
|
|
22
|
+
return { ok: false, error: "URL must not include credentials" };
|
|
23
|
+
}
|
|
24
|
+
const hostname = parsed.hostname.trim().toLowerCase().replace(/\.$/, "");
|
|
25
|
+
if (!hostname) {
|
|
26
|
+
return { ok: false, error: "Invalid hostname" };
|
|
27
|
+
}
|
|
28
|
+
// Normalize to origin so callers can't smuggle paths/query fragments into the base URL,
|
|
29
|
+
// and strip a trailing dot from the hostname (DNS root label).
|
|
30
|
+
const isIpv6 = hostname.includes(":");
|
|
31
|
+
const host = parsed.port
|
|
32
|
+
? `${isIpv6 ? `[${hostname}]` : hostname}:${parsed.port}`
|
|
33
|
+
: isIpv6
|
|
34
|
+
? `[${hostname}]`
|
|
35
|
+
: hostname;
|
|
36
|
+
return { ok: true, baseUrl: `${parsed.protocol}//${host}`, hostname };
|
|
37
|
+
}
|
|
38
|
+
export function isBlockedUrbitHostname(hostname) {
|
|
39
|
+
const normalized = hostname.trim().toLowerCase().replace(/\.$/, "");
|
|
40
|
+
if (!normalized) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return isBlockedHostname(normalized) || isPrivateIpAddress(normalized);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=base-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-url.js","sourceRoot":"","sources":["../../../src/urbit/base-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAM5E,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAC1C,CAAC;IAED,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,OAAO,EAAE,CAAC;IAEtE,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;IAC7C,CAAC;IAED,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC;IAClE,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACvC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC;IAClE,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACzE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAClD,CAAC;IAED,wFAAwF;IACxF,+DAA+D;IAC/D,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI;QACtB,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE;QACzD,CAAC,CAAC,MAAM;YACN,CAAC,CAAC,IAAI,QAAQ,GAAG;YACjB,CAAC,CAAC,QAAQ,CAAC;IAEf,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,QAAgB;IACrD,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACpE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,iBAAiB,CAAC,UAAU,CAAC,IAAI,kBAAkB,CAAC,UAAU,CAAC,CAAC;AACzE,CAAC"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { UrbitHttpError } from "./errors.js";
|
|
2
|
+
import { urbitFetch } from "./fetch.js";
|
|
3
|
+
export async function pokeUrbitChannel(deps, params) {
|
|
4
|
+
const pokeId = Date.now();
|
|
5
|
+
const pokeData = {
|
|
6
|
+
id: pokeId,
|
|
7
|
+
action: "poke",
|
|
8
|
+
ship: deps.ship,
|
|
9
|
+
app: params.app,
|
|
10
|
+
mark: params.mark,
|
|
11
|
+
json: params.json,
|
|
12
|
+
};
|
|
13
|
+
const { response, release } = await urbitFetch({
|
|
14
|
+
baseUrl: deps.baseUrl,
|
|
15
|
+
path: `/~/channel/${deps.channelId}`,
|
|
16
|
+
init: {
|
|
17
|
+
method: "PUT",
|
|
18
|
+
headers: {
|
|
19
|
+
"Content-Type": "application/json",
|
|
20
|
+
Cookie: deps.cookie,
|
|
21
|
+
},
|
|
22
|
+
body: JSON.stringify([pokeData]),
|
|
23
|
+
},
|
|
24
|
+
ssrfPolicy: deps.ssrfPolicy,
|
|
25
|
+
lookupFn: deps.lookupFn,
|
|
26
|
+
fetchImpl: deps.fetchImpl,
|
|
27
|
+
timeoutMs: 30_000,
|
|
28
|
+
auditContext: params.auditContext,
|
|
29
|
+
});
|
|
30
|
+
try {
|
|
31
|
+
if (!response.ok && response.status !== 204) {
|
|
32
|
+
const errorText = await response.text().catch(() => "");
|
|
33
|
+
throw new Error(`Poke failed: ${response.status}${errorText ? ` - ${errorText}` : ""}`);
|
|
34
|
+
}
|
|
35
|
+
return pokeId;
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
await release();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export async function scryUrbitPath(deps, params) {
|
|
42
|
+
const scryPath = `/~/scry${params.path}`;
|
|
43
|
+
const { response, release } = await urbitFetch({
|
|
44
|
+
baseUrl: deps.baseUrl,
|
|
45
|
+
path: scryPath,
|
|
46
|
+
init: {
|
|
47
|
+
method: "GET",
|
|
48
|
+
headers: { Cookie: deps.cookie },
|
|
49
|
+
},
|
|
50
|
+
ssrfPolicy: deps.ssrfPolicy,
|
|
51
|
+
lookupFn: deps.lookupFn,
|
|
52
|
+
fetchImpl: deps.fetchImpl,
|
|
53
|
+
timeoutMs: 30_000,
|
|
54
|
+
auditContext: params.auditContext,
|
|
55
|
+
});
|
|
56
|
+
try {
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
throw new Error(`Scry failed: ${response.status} for path ${params.path}`);
|
|
59
|
+
}
|
|
60
|
+
return await response.json();
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
await release();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export async function createUrbitChannel(deps, params) {
|
|
67
|
+
const { response, release } = await urbitFetch({
|
|
68
|
+
baseUrl: deps.baseUrl,
|
|
69
|
+
path: `/~/channel/${deps.channelId}`,
|
|
70
|
+
init: {
|
|
71
|
+
method: "PUT",
|
|
72
|
+
headers: {
|
|
73
|
+
"Content-Type": "application/json",
|
|
74
|
+
Cookie: deps.cookie,
|
|
75
|
+
},
|
|
76
|
+
body: JSON.stringify(params.body),
|
|
77
|
+
},
|
|
78
|
+
ssrfPolicy: deps.ssrfPolicy,
|
|
79
|
+
lookupFn: deps.lookupFn,
|
|
80
|
+
fetchImpl: deps.fetchImpl,
|
|
81
|
+
timeoutMs: 30_000,
|
|
82
|
+
auditContext: params.auditContext,
|
|
83
|
+
});
|
|
84
|
+
try {
|
|
85
|
+
if (!response.ok && response.status !== 204) {
|
|
86
|
+
throw new UrbitHttpError({ operation: "Channel creation", status: response.status });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
await release();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export async function wakeUrbitChannel(deps) {
|
|
94
|
+
const { response, release } = await urbitFetch({
|
|
95
|
+
baseUrl: deps.baseUrl,
|
|
96
|
+
path: `/~/channel/${deps.channelId}`,
|
|
97
|
+
init: {
|
|
98
|
+
method: "PUT",
|
|
99
|
+
headers: {
|
|
100
|
+
"Content-Type": "application/json",
|
|
101
|
+
Cookie: deps.cookie,
|
|
102
|
+
},
|
|
103
|
+
body: JSON.stringify([
|
|
104
|
+
{
|
|
105
|
+
id: Date.now(),
|
|
106
|
+
action: "poke",
|
|
107
|
+
ship: deps.ship,
|
|
108
|
+
app: "hood",
|
|
109
|
+
mark: "helm-hi",
|
|
110
|
+
json: "Opening API channel",
|
|
111
|
+
},
|
|
112
|
+
]),
|
|
113
|
+
},
|
|
114
|
+
ssrfPolicy: deps.ssrfPolicy,
|
|
115
|
+
lookupFn: deps.lookupFn,
|
|
116
|
+
fetchImpl: deps.fetchImpl,
|
|
117
|
+
timeoutMs: 30_000,
|
|
118
|
+
auditContext: "tlon-urbit-channel-wake",
|
|
119
|
+
});
|
|
120
|
+
try {
|
|
121
|
+
if (!response.ok && response.status !== 204) {
|
|
122
|
+
throw new UrbitHttpError({ operation: "Channel activation", status: response.status });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
await release();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
export async function ensureUrbitChannelOpen(deps, params) {
|
|
130
|
+
await createUrbitChannel(deps, {
|
|
131
|
+
body: params.createBody,
|
|
132
|
+
auditContext: params.createAuditContext,
|
|
133
|
+
});
|
|
134
|
+
await wakeUrbitChannel(deps);
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=channel-ops.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-ops.js","sourceRoot":"","sources":["../../../src/urbit/channel-ops.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAYxC,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAsB,EACtB,MAA0E;IAE1E,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG;QACf,EAAE,EAAE,MAAM;QACV,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,MAAM,CAAC,IAAI;KAClB,CAAC;IAEF,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,UAAU,CAAC;QAC7C,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,cAAc,IAAI,CAAC,SAAS,EAAE;QACpC,IAAI,EAAE;YACJ,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC;SACjC;QACD,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,MAAM;QACjB,YAAY,EAAE,MAAM,CAAC,YAAY;KAClC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5C,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,gBAAgB,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1F,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAA4F,EAC5F,MAA8C;IAE9C,MAAM,QAAQ,GAAG,UAAU,MAAM,CAAC,IAAI,EAAE,CAAC;IACzC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,UAAU,CAAC;QAC7C,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE;YACJ,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE;SACjC;QACD,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,MAAM;QACjB,YAAY,EAAE,MAAM,CAAC,YAAY;KAClC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,gBAAgB,QAAQ,CAAC,MAAM,aAAa,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAsB,EACtB,MAA+C;IAE/C,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,UAAU,CAAC;QAC7C,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,cAAc,IAAI,CAAC,SAAS,EAAE;QACpC,IAAI,EAAE;YACJ,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;SAClC;QACD,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,MAAM;QACjB,YAAY,EAAE,MAAM,CAAC,YAAY;KAClC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5C,MAAM,IAAI,cAAc,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAsB;IAC3D,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,UAAU,CAAC;QAC7C,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,cAAc,IAAI,CAAC,SAAS,EAAE;QACpC,IAAI,EAAE;YACJ,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB;oBACE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;oBACd,MAAM,EAAE,MAAM;oBACd,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,GAAG,EAAE,MAAM;oBACX,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,qBAAqB;iBAC5B;aACF,CAAC;SACH;QACD,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,SAAS,EAAE,MAAM;QACjB,YAAY,EAAE,yBAAyB;KACxC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5C,MAAM,IAAI,cAAc,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,IAAsB,EACtB,MAA2D;IAE3D,MAAM,kBAAkB,CAAC,IAAI,EAAE;QAC7B,IAAI,EAAE,MAAM,CAAC,UAAU;QACvB,YAAY,EAAE,MAAM,CAAC,kBAAkB;KACxC,CAAC,CAAC;IACH,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { validateUrbitBaseUrl } from "./base-url.js";
|
|
2
|
+
import { UrbitUrlError } from "./errors.js";
|
|
3
|
+
export function resolveShipFromHostname(hostname) {
|
|
4
|
+
const trimmed = hostname.trim().toLowerCase().replace(/\.$/, "");
|
|
5
|
+
if (!trimmed) {
|
|
6
|
+
return "";
|
|
7
|
+
}
|
|
8
|
+
if (trimmed.includes(".")) {
|
|
9
|
+
return trimmed.split(".")[0] ?? trimmed;
|
|
10
|
+
}
|
|
11
|
+
return trimmed;
|
|
12
|
+
}
|
|
13
|
+
export function normalizeUrbitShip(ship, hostname) {
|
|
14
|
+
const raw = ship?.replace(/^~/, "") ?? resolveShipFromHostname(hostname);
|
|
15
|
+
return raw.trim();
|
|
16
|
+
}
|
|
17
|
+
export function normalizeUrbitCookie(cookie) {
|
|
18
|
+
return cookie.split(";")[0] ?? cookie;
|
|
19
|
+
}
|
|
20
|
+
export function getUrbitContext(url, ship) {
|
|
21
|
+
const validated = validateUrbitBaseUrl(url);
|
|
22
|
+
if (!validated.ok) {
|
|
23
|
+
throw new UrbitUrlError(validated.error);
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
baseUrl: validated.baseUrl,
|
|
27
|
+
hostname: validated.hostname,
|
|
28
|
+
ship: normalizeUrbitShip(ship, validated.hostname),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function ssrfPolicyFromAllowPrivateNetwork(allowPrivateNetwork) {
|
|
32
|
+
return allowPrivateNetwork ? { allowPrivateNetwork: true } : undefined;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get the default SSRF policy for image uploads.
|
|
36
|
+
* Uses a restrictive policy that blocks private networks by default.
|
|
37
|
+
*/
|
|
38
|
+
export function getDefaultSsrFPolicy() {
|
|
39
|
+
// Default: block private networks for image uploads (safer default)
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/urbit/context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQ5C,MAAM,UAAU,uBAAuB,CAAC,QAAgB;IACtD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;IAC1C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAwB,EAAE,QAAgB;IAC3E,MAAM,GAAG,GAAG,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IACzE,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,IAAa;IACxD,MAAM,SAAS,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO;QACL,OAAO,EAAE,SAAS,CAAC,OAAO;QAC1B,QAAQ,EAAE,SAAS,CAAC,QAAQ;QAC5B,IAAI,EAAE,kBAAkB,CAAC,IAAI,EAAE,SAAS,CAAC,QAAQ,CAAC;KACnD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iCAAiC,CAC/C,mBAA+C;IAE/C,OAAO,mBAAmB,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACzE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,oEAAoE;IACpE,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export class UrbitError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
constructor(code, message, options) {
|
|
4
|
+
super(message, options);
|
|
5
|
+
this.name = "UrbitError";
|
|
6
|
+
this.code = code;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export class UrbitUrlError extends UrbitError {
|
|
10
|
+
constructor(message, options) {
|
|
11
|
+
super("invalid_url", message, options);
|
|
12
|
+
this.name = "UrbitUrlError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class UrbitHttpError extends UrbitError {
|
|
16
|
+
status;
|
|
17
|
+
operation;
|
|
18
|
+
bodyText;
|
|
19
|
+
constructor(params) {
|
|
20
|
+
const suffix = params.bodyText ? ` - ${params.bodyText}` : "";
|
|
21
|
+
super("http_error", `${params.operation} failed: ${params.status}${suffix}`, {
|
|
22
|
+
cause: params.cause,
|
|
23
|
+
});
|
|
24
|
+
this.name = "UrbitHttpError";
|
|
25
|
+
this.status = params.status;
|
|
26
|
+
this.operation = params.operation;
|
|
27
|
+
this.bodyText = params.bodyText;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class UrbitAuthError extends UrbitError {
|
|
31
|
+
constructor(code, message, options) {
|
|
32
|
+
super(code, message, options);
|
|
33
|
+
this.name = "UrbitAuthError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +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,YAAY,IAAoB,EAAE,OAAe,EAAE,OAA6B;QAC9E,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,MAAiF;QAC3F,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,KAAK,CAAC,YAAY,EAAE,GAAG,MAAM,CAAC,SAAS,YAAY,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,EAAE;YAC3E,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC;QACH,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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk";
|
|
2
|
+
import { validateUrbitBaseUrl } from "./base-url.js";
|
|
3
|
+
import { UrbitUrlError } from "./errors.js";
|
|
4
|
+
export async function urbitFetch(params) {
|
|
5
|
+
const validated = validateUrbitBaseUrl(params.baseUrl);
|
|
6
|
+
if (!validated.ok) {
|
|
7
|
+
throw new UrbitUrlError(validated.error);
|
|
8
|
+
}
|
|
9
|
+
const url = new URL(params.path, validated.baseUrl).toString();
|
|
10
|
+
return await fetchWithSsrFGuard({
|
|
11
|
+
url,
|
|
12
|
+
fetchImpl: params.fetchImpl,
|
|
13
|
+
init: params.init,
|
|
14
|
+
timeoutMs: params.timeoutMs,
|
|
15
|
+
maxRedirects: params.maxRedirects,
|
|
16
|
+
signal: params.signal,
|
|
17
|
+
policy: params.ssrfPolicy,
|
|
18
|
+
lookupFn: params.lookupFn,
|
|
19
|
+
auditContext: params.auditContext,
|
|
20
|
+
pinDns: params.pinDns,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../../src/urbit/fetch.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAsB5C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAyB;IACxD,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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foreigns.js","sourceRoot":"","sources":["../../../src/urbit/foreigns.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
/**
|
|
6
|
+
* Simple HTTP-only poke that doesn't open an EventSource (avoids conflict with monitor's SSE)
|
|
7
|
+
*/
|
|
8
|
+
export async function createHttpPokeApi(params) {
|
|
9
|
+
const ssrfPolicy = ssrfPolicyFromAllowPrivateNetwork(params.allowPrivateNetwork);
|
|
10
|
+
const cookie = await authenticate(params.url, params.code, { ssrfPolicy });
|
|
11
|
+
const channelId = `${Math.floor(Date.now() / 1000)}-${randomUUID().slice(0, 8)}`;
|
|
12
|
+
const channelPath = `/~/channel/${channelId}`;
|
|
13
|
+
const shipName = params.ship.replace(/^~/, "");
|
|
14
|
+
return {
|
|
15
|
+
poke: async (pokeParams) => {
|
|
16
|
+
const pokeId = Date.now();
|
|
17
|
+
const pokeData = {
|
|
18
|
+
id: pokeId,
|
|
19
|
+
action: "poke",
|
|
20
|
+
ship: shipName,
|
|
21
|
+
app: pokeParams.app,
|
|
22
|
+
mark: pokeParams.mark,
|
|
23
|
+
json: pokeParams.json,
|
|
24
|
+
};
|
|
25
|
+
const { response, release } = await urbitFetch({
|
|
26
|
+
baseUrl: params.url,
|
|
27
|
+
path: channelPath,
|
|
28
|
+
init: {
|
|
29
|
+
method: "PUT",
|
|
30
|
+
headers: {
|
|
31
|
+
"Content-Type": "application/json",
|
|
32
|
+
Cookie: cookie.split(";")[0],
|
|
33
|
+
},
|
|
34
|
+
body: JSON.stringify([pokeData]),
|
|
35
|
+
},
|
|
36
|
+
ssrfPolicy,
|
|
37
|
+
timeoutMs: 30_000,
|
|
38
|
+
auditContext: "tlon-http-poke",
|
|
39
|
+
});
|
|
40
|
+
try {
|
|
41
|
+
if (!response.ok && response.status !== 204) {
|
|
42
|
+
const errorText = await response.text();
|
|
43
|
+
throw new Error(`Poke failed: ${response.status} - ${errorText}`);
|
|
44
|
+
}
|
|
45
|
+
return pokeId;
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
await release();
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
delete: async () => {
|
|
52
|
+
// No-op for HTTP-only client
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=http-poke.js.map
|
|
@@ -0,0 +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;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,iCAAiC,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAOxC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAKvC;IACC,MAAM,UAAU,GAAG,iCAAiC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACjF,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"}
|