diff --git a/auth.ts b/auth.ts index f504374..6b30f84 100644 --- a/auth.ts +++ b/auth.ts @@ -303,7 +303,7 @@ export async function authedFetch( `token=${auth}; deno_auth_ghid=force`, ); - const url = new URL(endpoint, context.endpoint); + const url = new URL(`${context.endpoint}/${endpoint}`); let fallbackBody: ReadableStream | undefined; if (init.body instanceof ReadableStream) { diff --git a/lib/rs_lib.d.ts b/lib/rs_lib.d.ts new file mode 100644 index 0000000..2a36ee9 --- /dev/null +++ b/lib/rs_lib.d.ts @@ -0,0 +1,9 @@ +// @generated file from wasmbuild -- do not edit +// deno-lint-ignore-file +// deno-fmt-ignore-file + +export function resolve_config( + root_path: string, + ignore_paths: string[], + allow_node_modules: boolean, +): any; diff --git a/lib/rs_lib.internal.js b/lib/rs_lib.internal.js new file mode 100644 index 0000000..63eb5a4 --- /dev/null +++ b/lib/rs_lib.internal.js @@ -0,0 +1,441 @@ +// @generated file from wasmbuild -- do not edit +// @ts-nocheck: generated +// deno-lint-ignore-file +// deno-fmt-ignore-file + +import { copy_bytes } from "./snippets/sys_traits-4d1fdc43f822dba1/inline0.js"; + +let wasm; +export function __wbg_set_wasm(val) { + wasm = val; +} + +function addToExternrefTable0(obj) { + const idx = wasm.__externref_table_alloc(); + wasm.__wbindgen_export_2.set(idx, obj); + return idx; +} + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + const idx = addToExternrefTable0(e); + wasm.__wbindgen_exn_store(idx); + } +} + +const lTextDecoder = typeof TextDecoder === "undefined" + ? (0, module.require)("util").TextDecoder + : TextDecoder; + +let cachedTextDecoder = new lTextDecoder("utf-8", { + ignoreBOM: true, + fatal: true, +}); + +cachedTextDecoder.decode(); + +let cachedUint8ArrayMemory0 = null; + +function getUint8ArrayMemory0() { + if ( + cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0 + ) { + cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8ArrayMemory0; +} + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode( + getUint8ArrayMemory0().subarray(ptr, ptr + len), + ); +} + +function debugString(val) { + // primitive types + const type = typeof val; + if (type == "number" || type == "boolean" || val == null) { + return `${val}`; + } + if (type == "string") { + return `"${val}"`; + } + if (type == "symbol") { + const description = val.description; + if (description == null) { + return "Symbol"; + } else { + return `Symbol(${description})`; + } + } + if (type == "function") { + const name = val.name; + if (typeof name == "string" && name.length > 0) { + return `Function(${name})`; + } else { + return "Function"; + } + } + // objects + if (Array.isArray(val)) { + const length = val.length; + let debug = "["; + if (length > 0) { + debug += debugString(val[0]); + } + for (let i = 1; i < length; i++) { + debug += ", " + debugString(val[i]); + } + debug += "]"; + return debug; + } + // Test for built-in + const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); + let className; + if (builtInMatches && builtInMatches.length > 1) { + className = builtInMatches[1]; + } else { + // Failed to match the standard '[object ClassName]' + return toString.call(val); + } + if (className == "Object") { + // we're a user defined class or Object + // JSON.stringify avoids problems with cycles, and is generally much + // easier than looping through ownProperties of `val`. + try { + return "Object(" + JSON.stringify(val) + ")"; + } catch (_) { + return "Object"; + } + } + // errors + if (val instanceof Error) { + return `${val.name}: ${val.message}\n${val.stack}`; + } + // TODO we could test for more things here, like `Set`s and `Map`s. + return className; +} + +let WASM_VECTOR_LEN = 0; + +const lTextEncoder = typeof TextEncoder === "undefined" + ? (0, module.require)("util").TextEncoder + : TextEncoder; + +let cachedTextEncoder = new lTextEncoder("utf-8"); + +const encodeString = typeof cachedTextEncoder.encodeInto === "function" + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); + } + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length, + }; + }; + +function passStringToWasm0(arg, malloc, realloc) { + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8ArrayMemory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +let cachedDataViewMemory0 = null; + +function getDataViewMemory0() { + if ( + cachedDataViewMemory0 === null || + cachedDataViewMemory0.buffer.detached === true || + (cachedDataViewMemory0.buffer.detached === undefined && + cachedDataViewMemory0.buffer !== wasm.memory.buffer) + ) { + cachedDataViewMemory0 = new DataView(wasm.memory.buffer); + } + return cachedDataViewMemory0; +} + +function isLikeNone(x) { + return x === undefined || x === null; +} + +function passArrayJsValueToWasm0(array, malloc) { + const ptr = malloc(array.length * 4, 4) >>> 0; + for (let i = 0; i < array.length; i++) { + const add = addToExternrefTable0(array[i]); + getDataViewMemory0().setUint32(ptr + 4 * i, add, true); + } + WASM_VECTOR_LEN = array.length; + return ptr; +} + +function takeFromExternrefTable0(idx) { + const value = wasm.__wbindgen_export_2.get(idx); + wasm.__externref_table_dealloc(idx); + return value; +} +/** + * @param {string} root_path + * @param {string[]} ignore_paths + * @param {boolean} allow_node_modules + * @returns {any} + */ +export function resolve_config(root_path, ignore_paths, allow_node_modules) { + const ptr0 = passStringToWasm0( + root_path, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArrayJsValueToWasm0(ignore_paths, wasm.__wbindgen_malloc); + const len1 = WASM_VECTOR_LEN; + const ret = wasm.resolve_config(ptr0, len0, ptr1, len1, allow_node_modules); + if (ret[2]) { + throw takeFromExternrefTable0(ret[1]); + } + return takeFromExternrefTable0(ret[0]); +} + +const __wbindgen_enum_Os = ["windows", "darwin"]; + +export function __wbg_byteLength_e674b853d9c77e1d(arg0) { + const ret = arg0.byteLength; + return ret; +} + +export function __wbg_copybytes_912c72f9e6d5334b(arg0, arg1, arg2) { + copy_bytes(arg0, arg1, arg2 >>> 0); +} + +export function __wbg_done_769e5ede4b31c67b(arg0) { + const ret = arg0.done; + return ret; +} + +export function __wbg_getTime_46267b1c24877e30(arg0) { + const ret = arg0.getTime(); + return ret; +} + +export function __wbg_get_67b2ba62fc30de12() { + return handleError(function (arg0, arg1) { + const ret = Reflect.get(arg0, arg1); + return ret; + }, arguments); +} + +export function __wbg_instanceof_Date_e9a9be8b9cea7890(arg0) { + let result; + try { + result = arg0 instanceof Date; + } catch (_) { + result = false; + } + const ret = result; + return ret; +} + +export function __wbg_instanceof_Error_4d54113b22d20306(arg0) { + let result; + try { + result = arg0 instanceof Error; + } catch (_) { + result = false; + } + const ret = result; + return ret; +} + +export function __wbg_lstatSync_ffcaae096515e955() { + return handleError(function (arg0, arg1) { + const ret = Deno.lstatSync(getStringFromWasm0(arg0, arg1)); + return ret; + }, arguments); +} + +export function __wbg_message_97a2af9b89d693a3(arg0) { + const ret = arg0.message; + return ret; +} + +export function __wbg_name_0b327d569f00ebee(arg0) { + const ret = arg0.name; + return ret; +} + +export function __wbg_new_405e22f390576ce2() { + const ret = new Object(); + return ret; +} + +export function __wbg_new_78feb108b6472713() { + const ret = new Array(); + return ret; +} + +export function __wbg_next_6574e1a8a62d1055() { + return handleError(function (arg0) { + const ret = arg0.next(); + return ret; + }, arguments); +} + +export function __wbg_readDirSync_6627a121ad5b5202() { + return handleError(function (arg0, arg1) { + const ret = Deno.readDirSync(getStringFromWasm0(arg0, arg1)); + return ret; + }, arguments); +} + +export function __wbg_readFileSync_d8dc373cf87d2f9e() { + return handleError(function (arg0, arg1) { + const ret = Deno.readFileSync(getStringFromWasm0(arg0, arg1)); + return ret; + }, arguments); +} + +export function __wbg_set_37837023f3d740e8(arg0, arg1, arg2) { + arg0[arg1 >>> 0] = arg2; +} + +export function __wbg_set_3f1d0b984ed272ed(arg0, arg1, arg2) { + arg0[arg1] = arg2; +} + +export function __wbg_statSync_af9d1d3acb9d8325() { + return handleError(function (arg0, arg1) { + const ret = Deno.statSync(getStringFromWasm0(arg0, arg1)); + return ret; + }, arguments); +} + +export function __wbg_static_accessor_BUILD_OS_57f049863cca4b6a() { + const ret = Deno.build.os; + return (__wbindgen_enum_Os.indexOf(ret) + 1 || 3) - 1; +} + +export function __wbg_value_cd1ffa7b1ab794f1(arg0) { + const ret = arg0.value; + return ret; +} + +export function __wbindgen_boolean_get(arg0) { + const v = arg0; + const ret = typeof v === "boolean" ? (v ? 1 : 0) : 2; + return ret; +} + +export function __wbindgen_debug_string(arg0, arg1) { + const ret = debugString(arg1); + const ptr1 = passStringToWasm0( + ret, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); +} + +export function __wbindgen_error_new(arg0, arg1) { + const ret = new Error(getStringFromWasm0(arg0, arg1)); + return ret; +} + +export function __wbindgen_init_externref_table() { + const table = wasm.__wbindgen_export_2; + const offset = table.grow(4); + table.set(0, undefined); + table.set(offset + 0, undefined); + table.set(offset + 1, null); + table.set(offset + 2, true); + table.set(offset + 3, false); +} + +export function __wbindgen_is_bigint(arg0) { + const ret = typeof arg0 === "bigint"; + return ret; +} + +export function __wbindgen_is_null(arg0) { + const ret = arg0 === null; + return ret; +} + +export function __wbindgen_is_undefined(arg0) { + const ret = arg0 === undefined; + return ret; +} + +export function __wbindgen_memory() { + const ret = wasm.memory; + return ret; +} + +export function __wbindgen_number_get(arg0, arg1) { + const obj = arg1; + const ret = typeof obj === "number" ? obj : undefined; + getDataViewMemory0().setFloat64( + arg0 + 8 * 1, + isLikeNone(ret) ? 0 : ret, + true, + ); + getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true); +} + +export function __wbindgen_string_get(arg0, arg1) { + const obj = arg1; + const ret = typeof obj === "string" ? obj : undefined; + var ptr1 = isLikeNone(ret) + ? 0 + : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); +} + +export function __wbindgen_string_new(arg0, arg1) { + const ret = getStringFromWasm0(arg0, arg1); + return ret; +} + +export function __wbindgen_throw(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); +} diff --git a/lib/rs_lib.js b/lib/rs_lib.js new file mode 100644 index 0000000..3801691 --- /dev/null +++ b/lib/rs_lib.js @@ -0,0 +1,12 @@ +// @generated file from wasmbuild -- do not edit +// @ts-nocheck: generated +// deno-lint-ignore-file +// deno-fmt-ignore-file +// @ts-self-types="./rs_lib.d.ts" + +// source-hash: 68956057249f7e95a1e18a1449d2b9195b60bd6f +import * as wasm from "./rs_lib.wasm"; +export * from "./rs_lib.internal.js"; +import { __wbg_set_wasm } from "./rs_lib.internal.js"; +__wbg_set_wasm(wasm); +wasm.__wbindgen_start(); diff --git a/lib/rs_lib.wasm b/lib/rs_lib.wasm new file mode 100644 index 0000000..6bd094f Binary files /dev/null and b/lib/rs_lib.wasm differ diff --git a/lib/snippets/sys_traits-4d1fdc43f822dba1/inline0.js b/lib/snippets/sys_traits-4d1fdc43f822dba1/inline0.js new file mode 100644 index 0000000..75a0b13 --- /dev/null +++ b/lib/snippets/sys_traits-4d1fdc43f822dba1/inline0.js @@ -0,0 +1 @@ +export function copy_bytes(from, to, dst) { new Uint8Array(to.buffer).set(from, dst) } \ No newline at end of file diff --git a/tests/url_resolution.test.ts b/tests/url_resolution.test.ts new file mode 100644 index 0000000..57d86df --- /dev/null +++ b/tests/url_resolution.test.ts @@ -0,0 +1,40 @@ +import { assertEquals } from "@std/assert"; + +// Reproduces the URL resolution behavior in authedFetch. +// Before the fix: new URL(endpoint, base) drops path segments from the base. +// After the fix: string concatenation preserves the full base path. + +Deno.test("new URL() two-arg drops base path segments", () => { + // This is the OLD (broken) behavior that motivates the fix. + // When the endpoint is a proxy URL with a path, the path-based + // target host segment gets silently dropped. + const base = "https://proxy.example.com/target-host"; + const endpoint = "api/diffsync/org/app/rev123"; + + const broken = new URL(endpoint, base); + // new URL resolves relative to the parent of "target-host", losing it: + assertEquals(broken.pathname, "/api/diffsync/org/app/rev123"); + // "target-host" is gone — the proxy can no longer route the request. +}); + +Deno.test("string concatenation preserves base path segments", () => { + // This is the FIXED behavior: concatenation keeps the full base path. + const base = "https://proxy.example.com/target-host"; + const endpoint = "api/diffsync/org/app/rev123"; + + const fixed = new URL(`${base}/${endpoint}`); + assertEquals( + fixed.pathname, + "/target-host/api/diffsync/org/app/rev123", + ); +}); + +Deno.test("string concatenation works for standard endpoint too", () => { + // Ensure the fix doesn't regress the normal (non-proxy) case. + const base = "https://console.deno.com"; + const endpoint = "api/diffsync/org/app/rev123"; + + const fixed = new URL(`${base}/${endpoint}`); + assertEquals(fixed.pathname, "/api/diffsync/org/app/rev123"); + assertEquals(fixed.hostname, "console.deno.com"); +}); diff --git a/util.ts b/util.ts index 85a03b5..21cd0b8 100644 --- a/util.ts +++ b/util.ts @@ -23,7 +23,9 @@ export function error( ): never { console.error(); console.error(`${red("✗")} An error occurred:`); - console.error(` ${error.replaceAll("\n", "\n ")}`); + console.error( + ` ${String(error ?? "Unknown error").replaceAll("\n", "\n ")}`, + ); const trace = response?.headers.get("x-deno-trace-id"); if (context.debug) { console.error(` stack:\n${new Error().stack}`);