Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ jobs:
matrix:
node-version:
- 18
- '*'
- 25 # Node.js 25 support Uint8Array.fromBase64()
- 'lts/*'
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
Expand Down
61 changes: 61 additions & 0 deletions globals.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Adapted from file://./node_modules/typescript/lib/lib.dom.d.ts so we don't have to include the entire DOM lib
// Ref: https://github.com/microsoft/TypeScript/issues/31535, https://github.com/microsoft/TypeScript/issues/41727, https://github.com/microsoft/TypeScript-DOM-lib-generator/issues/1685

/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/atob) */
declare function atob(data: string): string;
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/btoa) */
declare function btoa(data: string): string;

type AllowSharedBufferSource =
| ArrayBufferLike
| ArrayBufferView<ArrayBufferLike>;

interface TextDecodeOptions {
stream?: boolean;
}

interface TextDecoderOptions {
fatal?: boolean;
ignoreBOM?: boolean;
}

/**
* The **`TextDecoder`** interface represents a decoder for a specific text encoding, such as `UTF-8`, `ISO-8859-2`, `KOI8-R`, `GBK`, etc.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder)
*/
interface TextDecoder extends TextDecoderCommon {
/**
* The **`TextDecoder.decode()`** method returns a string containing text decoded from the buffer passed as a parameter.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder/decode)
*/
decode(input?: AllowSharedBufferSource, options?: TextDecodeOptions): string;
}

// eslint-disable-next-line no-var
declare var TextDecoder: {
prototype: TextDecoder;
new (label?: string, options?: TextDecoderOptions): TextDecoder;
};

interface TextDecoderCommon {
/**
* Returns encoding's name, lowercased.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder/encoding)
*/
readonly encoding: string;
/**
* Returns true if error mode is "fatal", otherwise false.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder/fatal)
*/
readonly fatal: boolean;
/**
* Returns the value of ignore BOM.
*
* [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextDecoder/ignoreBOM)
*/
readonly ignoreBOM: boolean;
}
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
},
"devDependencies": {
"@borderless/ts-scripts": "^0.15.0",
"@types/node": "^20.19.35",
"@vitest/coverage-v8": "^3.2.4",
"typescript": "^5.9.3",
"vitest": "^3.2.4"
Expand Down
39 changes: 34 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
* MIT Licensed
*/

import { Buffer } from 'node:buffer';

export = auth;

/**
Expand Down Expand Up @@ -101,14 +99,45 @@ const CREDENTIALS_REGEXP =

const USER_PASS_REGEXP = /^([^:]*):(.*)$/;

type Uint8ArrayWithBase64 = typeof Uint8Array & {
fromBase64?: (str: string) => Uint8Array;
};

type BufferLike = {
from(
input: string,
encoding: 'base64',
): { toString(encoding: 'utf-8'): string };
};

const NodeBuffer = (globalThis as any).Buffer as BufferLike | undefined;

const textDecoder = new TextDecoder('utf-8');

/**
* Decode base64 string.
* @private
*/
const decodeBase64: (str: string) => string = (() => {
// 1) Modern Web / some runtimes
if (typeof (Uint8Array as Uint8ArrayWithBase64).fromBase64 === 'function') {
return (str: string) =>
textDecoder.decode((Uint8Array as Uint8ArrayWithBase64).fromBase64!(str));
}

function decodeBase64(str: string): string {
return Buffer.from(str, 'base64').toString();
}
// 2) Node.js (fast path)
if (typeof NodeBuffer?.from === 'function') {
return (str: string) => NodeBuffer.from(str, 'base64').toString('utf-8');
}

// 3) Browser fallback
return (str: string) => {
const binary = atob(str);
return textDecoder.decode(
Uint8Array.from(binary, (char) => char.charCodeAt(0)),
);
};
})();

/**
* Get the Authorization header from request object.
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"outDir": "dist",
"module": "nodenext",
"moduleResolution": "nodenext",
"types": ["node"]
"types": ["./globals.d.ts"]
},
"include": ["src/**/*"]
}
Loading