fix(ci): replace tlon git api dependency

This commit is contained in:
Vincent Koc
2026-03-19 15:01:02 -07:00
parent 2884ac13b2
commit ac850e815b
7 changed files with 341 additions and 188 deletions

View File

@@ -4,7 +4,8 @@
"description": "OpenClaw Tlon/Urbit channel plugin",
"type": "module",
"dependencies": {
"@tloncorp/api": "git+https://github.com/tloncorp/api-beta.git#7eede1c1a756977b09f96aa14a92e2b06318ae87",
"@aws-sdk/client-s3": "3.1000.0",
"@aws-sdk/s3-request-presigner": "3.1000.0",
"@tloncorp/tlon-skill": "0.2.2",
"@urbit/aura": "^3.0.0",
"zod": "^4.3.6"

View File

@@ -1,5 +1,4 @@
import crypto from "node:crypto";
import { configureClient } from "@tloncorp/api";
import type {
ChannelAccountSnapshot,
ChannelOutboundAdapter,
@@ -15,6 +14,7 @@ import {
parseTlonTarget,
resolveTlonOutboundTarget,
} from "./targets.js";
import { configureClient } from "./tlon-api.js";
import { resolveTlonAccount } from "./types.js";
import { authenticate } from "./urbit/auth.js";
import { ssrfPolicyFromAllowPrivateNetwork } from "./urbit/context.js";
@@ -169,6 +169,7 @@ export const tlonRuntimeOutbound: ChannelOutboundAdapter = {
shipName: account.ship.replace(/^~/, ""),
verbose: false,
getCode: async () => account.code,
allowPrivateNetwork: account.allowPrivateNetwork ?? undefined,
});
const uploadedUrl = mediaUrl ? await uploadImageFromUrl(mediaUrl) : undefined;

View File

@@ -0,0 +1,301 @@
import crypto from "node:crypto";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { authenticate } from "./urbit/auth.js";
import { scryUrbitPath } from "./urbit/channel-ops.js";
import { ssrfPolicyFromAllowPrivateNetwork } from "./urbit/context.js";
type ClientConfig = {
shipUrl: string;
shipName: string;
verbose: boolean;
getCode: () => Promise<string>;
allowPrivateNetwork?: boolean;
};
type StorageService = "presigned-url" | "credentials";
type StorageConfiguration = {
buckets: string[];
currentBucket: string;
region: string;
publicUrlBase: string;
presignedUrl: string;
service: StorageService;
};
type StorageCredentials = {
endpoint: string;
accessKeyId: string;
secretAccessKey: string;
};
type UploadFileParams = {
blob: Blob;
fileName?: string;
contentType?: string;
};
type UploadResult = {
url: string;
};
const MEMEX_BASE_URL = "https://memex.tlon.network";
const mimeToExt: Record<string, string> = {
"image/gif": ".gif",
"image/heic": ".heic",
"image/heif": ".heif",
"image/jpeg": ".jpg",
"image/jpg": ".jpg",
"image/png": ".png",
"image/webp": ".webp",
};
let currentClientConfig: ClientConfig | null = null;
export function configureClient(params: ClientConfig): void {
currentClientConfig = {
...params,
shipName: params.shipName.replace(/^~/, ""),
};
}
function requireClientConfig(): ClientConfig {
if (!currentClientConfig) {
throw new Error("Tlon client not configured");
}
return currentClientConfig;
}
function getExtensionFromMimeType(mimeType?: string): string {
if (!mimeType) {
return ".jpg";
}
return mimeToExt[mimeType.toLowerCase()] || ".jpg";
}
function hasCustomS3Creds(
credentials: StorageCredentials | null,
): credentials is StorageCredentials {
return Boolean(credentials?.accessKeyId && credentials?.endpoint && credentials?.secretAccessKey);
}
function isStorageCredentials(value: unknown): value is StorageCredentials {
if (!value || typeof value !== "object") {
return false;
}
const record = value as Record<string, unknown>;
return (
typeof record.endpoint === "string" &&
typeof record.accessKeyId === "string" &&
typeof record.secretAccessKey === "string"
);
}
function isHostedShipUrl(shipUrl: string): boolean {
try {
const { hostname } = new URL(shipUrl);
return hostname.endsWith("tlon.network") || hostname.endsWith(".test.tlon.systems");
} catch {
return shipUrl.endsWith("tlon.network") || shipUrl.endsWith(".test.tlon.systems");
}
}
function prefixEndpoint(endpoint: string): string {
return endpoint.match(/https?:\/\//) ? endpoint : `https://${endpoint}`;
}
function sanitizeFileName(fileName: string): string {
return fileName.split(/[/\\]/).pop() || fileName;
}
async function getAuthCookie(config: ClientConfig): Promise<string> {
return await authenticate(config.shipUrl, await config.getCode(), {
ssrfPolicy: ssrfPolicyFromAllowPrivateNetwork(config.allowPrivateNetwork),
});
}
async function scryJson<T>(config: ClientConfig, cookie: string, path: string): Promise<T> {
return (await scryUrbitPath(
{
baseUrl: config.shipUrl,
cookie,
ssrfPolicy: ssrfPolicyFromAllowPrivateNetwork(config.allowPrivateNetwork),
},
{ path, auditContext: "tlon-storage-scry" },
)) as T;
}
async function getStorageConfiguration(
config: ClientConfig,
cookie: string,
): Promise<StorageConfiguration> {
const result = await scryJson<
{ "storage-update"?: { configuration?: StorageConfiguration } } | StorageConfiguration
>(config, cookie, "/storage/configuration.json");
if ("storage-update" in result && result["storage-update"]?.configuration) {
return result["storage-update"].configuration;
}
if ("currentBucket" in result) {
return result;
}
throw new Error("Invalid storage configuration response");
}
async function getStorageCredentials(
config: ClientConfig,
cookie: string,
): Promise<StorageCredentials | null> {
const result = await scryJson<
{ "storage-update"?: { credentials?: StorageCredentials } } | StorageCredentials
>(config, cookie, "/storage/credentials.json");
if ("storage-update" in result) {
return result["storage-update"]?.credentials ?? null;
}
if (isStorageCredentials(result)) {
return result;
}
return null;
}
async function getMemexUploadUrl(params: {
config: ClientConfig;
cookie: string;
contentLength: number;
contentType: string;
fileName: string;
}): Promise<{ hostedUrl: string; uploadUrl: string }> {
const token = await scryJson<string | { secret?: string }>(
params.config,
params.cookie,
"/genuine/secret.json",
);
const resolvedToken = typeof token === "string" ? token : token.secret;
if (!resolvedToken) {
throw new Error("Missing genuine secret");
}
const endpoint = `${MEMEX_BASE_URL}/v1/${params.config.shipName}/upload`;
const response = await fetch(endpoint, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
token: resolvedToken,
contentLength: params.contentLength,
contentType: params.contentType,
fileName: params.fileName,
}),
});
if (!response.ok) {
throw new Error(`Memex upload request failed: ${response.status}`);
}
const data = (await response.json()) as { url?: string; filePath?: string } | null;
if (!data?.url || !data.filePath) {
throw new Error("Invalid response from Memex");
}
return { hostedUrl: data.filePath, uploadUrl: data.url };
}
export async function uploadFile(params: UploadFileParams): Promise<UploadResult> {
const config = requireClientConfig();
const cookie = await getAuthCookie(config);
const [storageConfig, credentials] = await Promise.all([
getStorageConfiguration(config, cookie),
getStorageCredentials(config, cookie),
]);
const contentType = params.contentType || params.blob.type || "application/octet-stream";
const extension = getExtensionFromMimeType(contentType);
const fileName = sanitizeFileName(params.fileName || `upload${extension}`);
const fileKey = `${config.shipName}/${Date.now()}-${crypto.randomUUID()}-${fileName}`;
const useMemex =
isHostedShipUrl(config.shipUrl) &&
(storageConfig.service === "presigned-url" || !hasCustomS3Creds(credentials));
if (useMemex) {
const { hostedUrl, uploadUrl } = await getMemexUploadUrl({
config,
cookie,
contentLength: params.blob.size,
contentType,
fileName: fileKey,
});
const response = await fetch(uploadUrl, {
method: "PUT",
body: params.blob,
headers: {
"Cache-Control": "public, max-age=3600",
"Content-Type": contentType,
},
});
if (!response.ok) {
throw new Error(`Upload failed: ${response.status}`);
}
return { url: hostedUrl };
}
if (!hasCustomS3Creds(credentials)) {
throw new Error("No storage credentials configured");
}
const endpoint = new URL(prefixEndpoint(credentials.endpoint));
const client = new S3Client({
endpoint: {
protocol: endpoint.protocol.slice(0, -1) as "http" | "https",
hostname: endpoint.host,
path: endpoint.pathname || "/",
},
region: storageConfig.region || "us-east-1",
credentials: {
accessKeyId: credentials.accessKeyId,
secretAccessKey: credentials.secretAccessKey,
},
forcePathStyle: true,
});
const headers: Record<string, string> = {
"Cache-Control": "public, max-age=3600",
"Content-Type": contentType,
"x-amz-acl": "public-read",
};
const command = new PutObjectCommand({
Bucket: storageConfig.currentBucket,
Key: fileKey,
ContentType: headers["Content-Type"],
CacheControl: headers["Cache-Control"],
ACL: "public-read",
});
const signedUrl = await getSignedUrl(client, command, {
expiresIn: 3600,
signableHeaders: new Set(Object.keys(headers)),
});
const response = await fetch(signedUrl, {
method: "PUT",
body: params.blob,
headers: signedUrl.includes("digitaloceanspaces.com") ? headers : undefined,
});
if (!response.ok) {
throw new Error(`Upload failed: ${response.status}`);
}
const publicUrl = storageConfig.publicUrlBase
? new URL(fileKey, storageConfig.publicUrlBase).toString()
: signedUrl.split("?")[0];
return { url: publicUrl };
}

View File

@@ -1,14 +0,0 @@
declare module "@tloncorp/api" {
export function configureClient(params: {
shipUrl: string;
shipName: string;
verbose: boolean;
getCode: () => Promise<string>;
}): void;
export function uploadFile(params: {
blob: Blob;
fileName: string;
contentType: string;
}): Promise<{ url: string }>;
}

View File

@@ -9,15 +9,15 @@ vi.mock("openclaw/plugin-sdk/infra-runtime", async (importOriginal) => {
};
});
// Mock @tloncorp/api
vi.mock("@tloncorp/api", () => ({
// Mock the local Tlon upload seam.
vi.mock("../tlon-api.js", () => ({
uploadFile: vi.fn(),
}));
describe("uploadImageFromUrl", () => {
async function loadUploadMocks() {
const { fetchWithSsrFGuard } = await import("openclaw/plugin-sdk/infra-runtime");
const { uploadFile } = await import("@tloncorp/api");
const { uploadFile } = await import("../tlon-api.js");
const { uploadImageFromUrl } = await import("./upload.js");
return {
mockFetch: vi.mocked(fetchWithSsrFGuard),

View File

@@ -1,8 +1,8 @@
/**
* Upload an image from a URL to Tlon storage.
*/
import { uploadFile } from "@tloncorp/api";
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/infra-runtime";
import { uploadFile } from "../tlon-api.js";
import { getDefaultSsrFPolicy } from "./context.js";
/**

200
pnpm-lock.yaml generated
View File

@@ -533,9 +533,12 @@ importers:
extensions/tlon:
dependencies:
'@tloncorp/api':
specifier: git+https://github.com/tloncorp/api-beta.git#7eede1c1a756977b09f96aa14a92e2b06318ae87
version: git+https://github.com/tloncorp/api-beta.git#7eede1c1a756977b09f96aa14a92e2b06318ae87
'@aws-sdk/client-s3':
specifier: 3.1000.0
version: 3.1000.0
'@aws-sdk/s3-request-presigner':
specifier: 3.1000.0
version: 3.1000.0
'@tloncorp/tlon-skill':
specifier: 0.2.2
version: 0.2.2
@@ -2896,34 +2899,18 @@ packages:
resolution: {integrity: sha512-FE3bZdEl62ojmy8x4FHqxq2+BuOHlcxiH5vaZ6aqHJr3AIZzwF5jfx8dEiU/X0a8RboyNDjmXjlbr8AdEyLgiA==}
engines: {node: '>=18.0.0'}
'@smithy/eventstream-serde-browser@4.2.11':
resolution: {integrity: sha512-3rEpo3G6f/nRS7fQDsZmxw/ius6rnlIpz4UX6FlALEzz8JoSxFmdBt0SZnthis+km7sQo6q5/3e+UJcuQivoXA==}
engines: {node: '>=18.0.0'}
'@smithy/eventstream-serde-browser@4.2.12':
resolution: {integrity: sha512-XUSuMxlTxV5pp4VpqZf6Sa3vT/Q75FVkLSpSSE3KkWBvAQWeuWt1msTv8fJfgA4/jcJhrbrbMzN1AC/hvPmm5A==}
engines: {node: '>=18.0.0'}
'@smithy/eventstream-serde-config-resolver@4.3.11':
resolution: {integrity: sha512-XeNIA8tcP/GDWnnKkO7qEm/bg0B/bP9lvIXZBXcGZwZ+VYM8h8k9wuDvUODtdQ2Wcp2RcBkPTCSMmaniVHrMlA==}
engines: {node: '>=18.0.0'}
'@smithy/eventstream-serde-config-resolver@4.3.12':
resolution: {integrity: sha512-7epsAZ3QvfHkngz6RXQYseyZYHlmWXSTPOfPmXkiS+zA6TBNo1awUaMFL9vxyXlGdoELmCZyZe1nQE+imbmV+Q==}
engines: {node: '>=18.0.0'}
'@smithy/eventstream-serde-node@4.2.11':
resolution: {integrity: sha512-fzbCh18rscBDTQSCrsp1fGcclLNF//nJyhjldsEl/5wCYmgpHblv5JSppQAyQI24lClsFT0wV06N1Porn0IsEw==}
engines: {node: '>=18.0.0'}
'@smithy/eventstream-serde-node@4.2.12':
resolution: {integrity: sha512-D1pFuExo31854eAvg89KMn9Oab/wEeJR6Buy32B49A9Ogdtx5fwZPqBHUlDzaCDpycTFk2+fSQgX689Qsk7UGA==}
engines: {node: '>=18.0.0'}
'@smithy/eventstream-serde-universal@4.2.11':
resolution: {integrity: sha512-MJ7HcI+jEkqoWT5vp+uoVaAjBrmxBtKhZTeynDRG/seEjJfqyg3SiqMMqyPnAMzmIfLaeJ/uiuSDP/l9AnMy/Q==}
engines: {node: '>=18.0.0'}
'@smithy/eventstream-serde-universal@4.2.12':
resolution: {integrity: sha512-+yNuTiyBACxOJUTvbsNsSOfH9G9oKbaJE1lNL3YHpGcuucl6rPZMi3nrpehpVOVR2E07YqFFmtwpImtpzlouHQ==}
engines: {node: '>=18.0.0'}
@@ -3104,10 +3091,6 @@ packages:
resolution: {integrity: sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ==}
engines: {node: '>=18.0.0'}
'@smithy/util-stream@4.5.19':
resolution: {integrity: sha512-v4sa+3xTweL1CLO2UP0p7tvIMH/Rq1X4KKOxd568mpe6LSLMQCnDHs4uv7m3ukpl3HvcN2JH6jiCS0SNRXKP/w==}
engines: {node: '>=18.0.0'}
'@smithy/util-stream@4.5.20':
resolution: {integrity: sha512-4yXLm5n/B5SRBR2p8cZ90Sbv4zL4NKsgxdzCzp/83cXw2KxLEumt5p+GAVyRNZgQOSrzXn9ARpO0lUe8XSlSDw==}
engines: {node: '>=18.0.0'}
@@ -3237,10 +3220,6 @@ packages:
resolution: {integrity: sha512-5Kc5CM2Ysn3vTTArBs2vESUt0AQiWZA86yc1TI3B+lxXmtEq133C1nxXNOgnzhrivdPZIh3zLj5gDnZjoLL5GA==}
engines: {node: '>=12.17.0'}
'@tloncorp/api@git+https://github.com/tloncorp/api-beta.git#7eede1c1a756977b09f96aa14a92e2b06318ae87':
resolution: {commit: 7eede1c1a756977b09f96aa14a92e2b06318ae87, repo: https://github.com/tloncorp/api-beta.git, type: git}
version: 0.0.2
'@tloncorp/tlon-skill-darwin-arm64@0.2.2':
resolution: {integrity: sha512-R6RPBZKwOlhJm8BkPCbnhLJ9XKPCCp0a3nq1QUCT2bN4orp/IbKFaqGK2mjZsxzKT8aPPPnRqviqpGioDdItuA==}
cpu: [arm64]
@@ -3468,9 +3447,6 @@ packages:
resolution: {integrity: sha512-N8/FHc/lmlMDCumMuTXyRHCxlov5KZY6unmJ9QR2GOw+OpROZMBsXYGwE+ZMtvN21ql9+Xb8KhGNBj08IrG3Wg==}
engines: {node: '>=16', npm: '>=8'}
'@urbit/nockjs@1.6.0':
resolution: {integrity: sha512-f2xCIxoYQh+bp/p6qztvgxnhGsnUwcrSSvW2CUKX7BPPVkDNppQCzCVPWo38TbqgChE7wh6rC1pm6YNCOyFlQA==}
'@vitest/browser-playwright@4.1.0':
resolution: {integrity: sha512-2RU7pZELY9/aVMLmABNy1HeZ4FX23FXGY1jRuHLHgWa2zaAE49aNW2GLzebW+BmbTZIKKyFF1QXvk7DEWViUCQ==}
peerDependencies:
@@ -3548,8 +3524,8 @@ packages:
link-preview-js:
optional: true
'@whiskeysockets/libsignal-node@git+https://github.com/whiskeysockets/libsignal-node.git#1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67':
resolution: {commit: 1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67, repo: https://github.com/whiskeysockets/libsignal-node.git, type: git}
'@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67':
resolution: {tarball: https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67}
version: 2.0.1
abbrev@1.1.1:
@@ -3633,10 +3609,6 @@ packages:
resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==}
engines: {node: '>=14'}
any-ascii@0.3.3:
resolution: {integrity: sha512-8hm+zPrc1VnlxD5eRgMo9F9k2wEMZhbZVLKwA/sPKIt6ywuz7bI9uV/yb27uvc8fv8q6Wl2piJT51q1saKX0Jw==}
engines: {node: '>=12.20'}
any-base@1.1.0:
resolution: {integrity: sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==}
@@ -3793,10 +3765,6 @@ packages:
bidi-js@1.0.3:
resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
big-integer@1.6.52:
resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
engines: {node: '>=0.6'}
bignumber.js@9.3.1:
resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==}
@@ -3831,9 +3799,6 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
browser-or-node@3.0.0:
resolution: {integrity: sha512-iczIdVJzGEYhP5DqQxYM9Hh7Ztpqqi+CXZpSmX8ALFs9ecXkQIeqRyM6TfxEfMVpwhl3dSuDvxdzzo9sUOIVBQ==}
bs58@6.0.0:
resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==}
@@ -3846,9 +3811,6 @@ packages:
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
bun-types@1.3.9:
resolution: {integrity: sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg==}
@@ -4067,9 +4029,6 @@ packages:
resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
date-fns@3.6.0:
resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'}
@@ -4298,9 +4257,6 @@ packages:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
exponential-backoff@3.1.3:
resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==}
express-rate-limit@8.3.1:
resolution: {integrity: sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==}
engines: {node: '>= 16'}
@@ -4872,9 +4828,6 @@ packages:
koffi@2.15.2:
resolution: {integrity: sha512-r9tjJLVRSOhCRWdVyQlF3/Ugzeg13jlzS4czS82MAgLff4W+BcYOW7g8Y62t9O5JYjYOLAjAovAZDNlDfZNu+g==}
libphonenumber-js@1.12.38:
resolution: {integrity: sha512-vwzxmasAy9hZigxtqTbFEwp8ZdZ975TiqVDwj5bKx5sR+zi5ucUQy9mbVTkKM9GzqdLdxux/hTw2nmN5J7POMA==}
lie@3.3.0:
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
@@ -5017,9 +4970,6 @@ packages:
lodash.pickby@4.6.0:
resolution: {integrity: sha512-AZV+GsS/6ckvPOVQPXSiFFacKvKB4kOQu6ynt9wz0F3LO4R9Ij4K1ddYsIytDpSgLz88JHd9P+oaLeej5/Sl7Q==}
lodash@4.17.23:
resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==}
log-symbols@7.0.1:
resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==}
engines: {node: '>=18'}
@@ -6025,9 +5975,6 @@ packages:
sonic-boom@4.2.1:
resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==}
sorted-btree@1.8.1:
resolution: {integrity: sha512-395+XIP+wqNn3USkFSrNz7G3Ss/MXlZEqesxvzCRFwL14h6e8LukDHdLBePn5pwbm5OQ9vGu8mDyz2lLDIqamQ==}
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
@@ -6454,10 +6401,6 @@ packages:
resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==}
engines: {node: ^20.17.0 || >=22.9.0}
validator@13.15.26:
resolution: {integrity: sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==}
engines: {node: '>= 0.10'}
vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
@@ -6805,33 +6748,33 @@ snapshots:
'@aws-sdk/util-user-agent-browser': 3.972.8
'@aws-sdk/util-user-agent-node': 3.973.7
'@smithy/config-resolver': 4.4.11
'@smithy/core': 3.23.11
'@smithy/eventstream-serde-browser': 4.2.11
'@smithy/eventstream-serde-config-resolver': 4.3.11
'@smithy/eventstream-serde-node': 4.2.11
'@smithy/core': 3.23.12
'@smithy/eventstream-serde-browser': 4.2.12
'@smithy/eventstream-serde-config-resolver': 4.3.12
'@smithy/eventstream-serde-node': 4.2.12
'@smithy/fetch-http-handler': 5.3.15
'@smithy/hash-node': 4.2.12
'@smithy/invalid-dependency': 4.2.12
'@smithy/middleware-content-length': 4.2.12
'@smithy/middleware-endpoint': 4.4.25
'@smithy/middleware-retry': 4.4.42
'@smithy/middleware-serde': 4.2.14
'@smithy/middleware-endpoint': 4.4.26
'@smithy/middleware-retry': 4.4.43
'@smithy/middleware-serde': 4.2.15
'@smithy/middleware-stack': 4.2.12
'@smithy/node-config-provider': 4.3.12
'@smithy/node-http-handler': 4.4.16
'@smithy/node-http-handler': 4.5.0
'@smithy/protocol-http': 5.3.12
'@smithy/smithy-client': 4.12.5
'@smithy/smithy-client': 4.12.6
'@smithy/types': 4.13.1
'@smithy/url-parser': 4.2.12
'@smithy/util-base64': 4.3.2
'@smithy/util-body-length-browser': 4.2.2
'@smithy/util-body-length-node': 4.2.3
'@smithy/util-defaults-mode-browser': 4.3.41
'@smithy/util-defaults-mode-node': 4.2.44
'@smithy/util-defaults-mode-browser': 4.3.42
'@smithy/util-defaults-mode-node': 4.2.45
'@smithy/util-endpoints': 3.3.3
'@smithy/util-middleware': 4.2.12
'@smithy/util-retry': 4.2.12
'@smithy/util-stream': 4.5.19
'@smithy/util-stream': 4.5.20
'@smithy/util-utf8': 4.2.2
tslib: 2.8.1
transitivePeerDependencies:
@@ -9620,7 +9563,7 @@ snapshots:
'@smithy/util-base64': 4.3.2
'@smithy/util-body-length-browser': 4.2.2
'@smithy/util-middleware': 4.2.12
'@smithy/util-stream': 4.5.19
'@smithy/util-stream': 4.5.20
'@smithy/util-utf8': 4.2.2
'@smithy/uuid': 1.1.2
tslib: 2.8.1
@@ -9660,46 +9603,23 @@ snapshots:
'@smithy/util-hex-encoding': 4.2.2
tslib: 2.8.1
'@smithy/eventstream-serde-browser@4.2.11':
dependencies:
'@smithy/eventstream-serde-universal': 4.2.11
'@smithy/types': 4.13.1
tslib: 2.8.1
'@smithy/eventstream-serde-browser@4.2.12':
dependencies:
'@smithy/eventstream-serde-universal': 4.2.12
'@smithy/types': 4.13.1
tslib: 2.8.1
'@smithy/eventstream-serde-config-resolver@4.3.11':
dependencies:
'@smithy/types': 4.13.1
tslib: 2.8.1
'@smithy/eventstream-serde-config-resolver@4.3.12':
dependencies:
'@smithy/types': 4.13.1
tslib: 2.8.1
'@smithy/eventstream-serde-node@4.2.11':
dependencies:
'@smithy/eventstream-serde-universal': 4.2.11
'@smithy/types': 4.13.1
tslib: 2.8.1
'@smithy/eventstream-serde-node@4.2.12':
dependencies:
'@smithy/eventstream-serde-universal': 4.2.12
'@smithy/types': 4.13.1
tslib: 2.8.1
'@smithy/eventstream-serde-universal@4.2.11':
dependencies:
'@smithy/eventstream-codec': 4.2.11
'@smithy/types': 4.13.1
tslib: 2.8.1
'@smithy/eventstream-serde-universal@4.2.12':
dependencies:
'@smithy/eventstream-codec': 4.2.12
@@ -9761,8 +9681,8 @@ snapshots:
'@smithy/middleware-endpoint@4.4.25':
dependencies:
'@smithy/core': 3.23.11
'@smithy/middleware-serde': 4.2.14
'@smithy/core': 3.23.12
'@smithy/middleware-serde': 4.2.15
'@smithy/node-config-provider': 4.3.12
'@smithy/shared-ini-file-loader': 4.4.7
'@smithy/types': 4.13.1
@@ -9786,7 +9706,7 @@ snapshots:
'@smithy/node-config-provider': 4.3.12
'@smithy/protocol-http': 5.3.12
'@smithy/service-error-classification': 4.2.12
'@smithy/smithy-client': 4.12.5
'@smithy/smithy-client': 4.12.6
'@smithy/types': 4.13.1
'@smithy/util-middleware': 4.2.12
'@smithy/util-retry': 4.2.12
@@ -9807,7 +9727,7 @@ snapshots:
'@smithy/middleware-serde@4.2.14':
dependencies:
'@smithy/core': 3.23.11
'@smithy/core': 3.23.12
'@smithy/protocol-http': 5.3.12
'@smithy/types': 4.13.1
tslib: 2.8.1
@@ -9890,12 +9810,12 @@ snapshots:
'@smithy/smithy-client@4.12.5':
dependencies:
'@smithy/core': 3.23.11
'@smithy/middleware-endpoint': 4.4.25
'@smithy/core': 3.23.12
'@smithy/middleware-endpoint': 4.4.26
'@smithy/middleware-stack': 4.2.12
'@smithy/protocol-http': 5.3.12
'@smithy/types': 4.13.1
'@smithy/util-stream': 4.5.19
'@smithy/util-stream': 4.5.20
tslib: 2.8.1
'@smithy/smithy-client@4.12.6':
@@ -9949,7 +9869,7 @@ snapshots:
'@smithy/util-defaults-mode-browser@4.3.41':
dependencies:
'@smithy/property-provider': 4.2.12
'@smithy/smithy-client': 4.12.5
'@smithy/smithy-client': 4.12.6
'@smithy/types': 4.13.1
tslib: 2.8.1
@@ -9966,7 +9886,7 @@ snapshots:
'@smithy/credential-provider-imds': 4.2.12
'@smithy/node-config-provider': 4.3.12
'@smithy/property-provider': 4.2.12
'@smithy/smithy-client': 4.12.5
'@smithy/smithy-client': 4.12.6
'@smithy/types': 4.13.1
tslib: 2.8.1
@@ -10001,17 +9921,6 @@ snapshots:
'@smithy/types': 4.13.1
tslib: 2.8.1
'@smithy/util-stream@4.5.19':
dependencies:
'@smithy/fetch-http-handler': 5.3.15
'@smithy/node-http-handler': 4.5.0
'@smithy/types': 4.13.1
'@smithy/util-base64': 4.3.2
'@smithy/util-buffer-from': 4.2.2
'@smithy/util-hex-encoding': 4.2.2
'@smithy/util-utf8': 4.2.2
tslib: 2.8.1
'@smithy/util-stream@4.5.20':
dependencies:
'@smithy/fetch-http-handler': 5.3.15
@@ -10124,26 +10033,6 @@ snapshots:
'@tinyhttp/content-disposition@2.2.4': {}
'@tloncorp/api@git+https://github.com/tloncorp/api-beta.git#7eede1c1a756977b09f96aa14a92e2b06318ae87':
dependencies:
'@aws-sdk/client-s3': 3.1000.0
'@aws-sdk/s3-request-presigner': 3.1000.0
'@urbit/aura': 3.0.0
'@urbit/nockjs': 1.6.0
any-ascii: 0.3.3
big-integer: 1.6.52
browser-or-node: 3.0.0
buffer: 6.0.3
date-fns: 3.6.0
emoji-regex: 10.6.0
exponential-backoff: 3.1.3
libphonenumber-js: 1.12.38
lodash: 4.17.23
sorted-btree: 1.8.1
validator: 13.15.26
transitivePeerDependencies:
- aws-crt
'@tloncorp/tlon-skill-darwin-arm64@0.2.2':
optional: true
@@ -10398,8 +10287,6 @@ snapshots:
'@urbit/aura@3.0.0': {}
'@urbit/nockjs@1.6.0': {}
'@vitest/browser-playwright@4.1.0(playwright@1.58.2)(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0)':
dependencies:
'@vitest/browser': 4.1.0(vite@8.0.0(@types/node@25.5.0)(esbuild@0.27.3)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.1.0)
@@ -10515,7 +10402,7 @@ snapshots:
'@cacheable/node-cache': 1.7.6
'@hapi/boom': 9.1.4
async-mutex: 0.5.0
libsignal: '@whiskeysockets/libsignal-node@git+https://github.com/whiskeysockets/libsignal-node.git#1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67'
libsignal: '@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67'
lru-cache: 11.2.7
music-metadata: 11.12.3
p-queue: 9.1.0
@@ -10531,7 +10418,7 @@ snapshots:
- supports-color
- utf-8-validate
'@whiskeysockets/libsignal-node@git+https://github.com/whiskeysockets/libsignal-node.git#1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67':
'@whiskeysockets/libsignal-node@https://codeload.github.com/whiskeysockets/libsignal-node/tar.gz/1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67':
dependencies:
curve25519-js: 0.0.4
protobufjs: 6.8.8
@@ -10605,8 +10492,6 @@ snapshots:
ansis@4.2.0: {}
any-ascii@0.3.3: {}
any-base@1.1.0:
optional: true
@@ -10765,8 +10650,6 @@ snapshots:
dependencies:
require-from-string: 2.0.2
big-integer@1.6.52: {}
bignumber.js@9.3.1: {}
birpc@4.0.0: {}
@@ -10807,8 +10690,6 @@ snapshots:
dependencies:
fill-range: 7.1.1
browser-or-node@3.0.0: {}
bs58@6.0.0:
dependencies:
base-x: 5.0.1
@@ -10819,11 +10700,6 @@ snapshots:
buffer-from@1.1.2: {}
buffer@6.0.3:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
bun-types@1.3.9:
dependencies:
'@types/node': 25.5.0
@@ -11040,8 +10916,6 @@ snapshots:
transitivePeerDependencies:
- '@noble/hashes'
date-fns@3.6.0: {}
debug@4.4.3:
dependencies:
ms: 2.1.3
@@ -11250,8 +11124,6 @@ snapshots:
expect-type@1.3.0: {}
exponential-backoff@3.1.3: {}
express-rate-limit@8.3.1(express@5.2.1):
dependencies:
express: 5.2.1
@@ -12012,8 +11884,6 @@ snapshots:
koffi@2.15.2:
optional: true
libphonenumber-js@1.12.38: {}
lie@3.3.0:
dependencies:
immediate: 3.0.6
@@ -12127,8 +11997,6 @@ snapshots:
lodash.pickby@4.6.0: {}
lodash@4.17.23: {}
log-symbols@7.0.1:
dependencies:
is-unicode-supported: 2.1.0
@@ -13406,8 +13274,6 @@ snapshots:
dependencies:
atomic-sleep: 1.0.0
sorted-btree@1.8.1: {}
source-map-js@1.2.1: {}
source-map-support@0.5.21:
@@ -13798,8 +13664,6 @@ snapshots:
validate-npm-package-name@7.0.2: {}
validator@13.15.26: {}
vary@1.1.2: {}
vfile-message@4.0.3: