@takodotid/azure-rest 1.0.1 → 1.0.2
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/dist/index.cjs +8 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -113,13 +113,18 @@ var AzureClient = class _AzureClient {
|
|
|
113
113
|
* @throws If token refresh fails after max retries
|
|
114
114
|
*/
|
|
115
115
|
async request(path, options) {
|
|
116
|
+
let lastError;
|
|
116
117
|
for (let i = 0; i <= _AzureClient.MAX_TOKEN_RETRIES; i++) {
|
|
117
118
|
if (this.token && this.token.expiresAt > /* @__PURE__ */ new Date()) break;
|
|
118
119
|
if (i === _AzureClient.MAX_TOKEN_RETRIES) {
|
|
119
|
-
throw new Error(
|
|
120
|
+
throw new Error(`Failed to refresh token after ${_AzureClient.MAX_TOKEN_RETRIES} attempts: ${lastError?.message ?? "unknown error"}`);
|
|
120
121
|
}
|
|
121
|
-
await this.refreshToken();
|
|
122
122
|
if (i > 0) await new Promise((res) => setTimeout(res, 100 * i));
|
|
123
|
+
try {
|
|
124
|
+
await this.refreshToken();
|
|
125
|
+
} catch (error) {
|
|
126
|
+
lastError = error;
|
|
127
|
+
}
|
|
123
128
|
}
|
|
124
129
|
if (!this.token) throw new Error("Token is unexpectedly null after refresh attempts");
|
|
125
130
|
const baseUrl = this.options.baseUrl.replace(/\/+$/, "");
|
|
@@ -407,7 +412,7 @@ var ServicePrincipalCredential = class _ServicePrincipalCredential {
|
|
|
407
412
|
tokenType: data.token_type
|
|
408
413
|
};
|
|
409
414
|
} catch (error) {
|
|
410
|
-
throw new Error(`Failed to get token: ${error.
|
|
415
|
+
throw new Error(`ServicePrincipalCredential: Failed to get token: ${error.message}`);
|
|
411
416
|
}
|
|
412
417
|
}
|
|
413
418
|
/**
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/AzureClient.ts","../src/credentials/AzureCliCredential.ts","../src/credentials/AzureCredential.ts","../src/credentials/ManagedIdentityCredential.ts","../src/credentials/ServicePrincipalCredential.ts","../src/credentials/WorkloadIdentityCredential.ts","../src/credentials/ChainedCredential.ts"],"sourcesContent":["export * from \"./AzureClient.js\";\nexport * from \"./credentials/AzureCliCredential.js\";\nexport * from \"./credentials/AzureCredential.js\";\nexport * from \"./credentials/ChainedCredential.js\";\nexport * from \"./credentials/ManagedIdentityCredential.js\";\nexport * from \"./credentials/ServicePrincipalCredential.js\";\nexport * from \"./credentials/WorkloadIdentityCredential.js\";\n","import type { AzureCredential, Credential } from \"./credentials/AzureCredential.js\";\n\n/**\n * Options for configuring the AzureClient instance.\n *\n * @property baseUrl - The base URL for Azure REST API endpoints (e.g. https://management.azure.com)\n * @property credential - Credential configuration for authenticating requests\n * @property helper - An AzureCredential implementation for acquiring tokens\n * @property scope - The Azure resource scope for the token (e.g. https://management.azure.com/.default)\n * @property builder - (Optional) Function to build request headers from a token. If not provided, an Authorization header is set by default.\n */\nexport type AzureClientOptions = {\n\tbaseUrl: string;\n\tcredential: {\n\t\thelper: AzureCredential;\n\t\tscope: string;\n\t\tbuilder?: (token: Credential) => Record<string, string>;\n\t};\n};\n\n/**\n * Azure REST API client with credential refresh and HTTP verb helpers.\n */\nexport class AzureClient {\n\tprivate static readonly MAX_TOKEN_RETRIES = 3;\n\tprivate token: Credential | null = null;\n\n\t/**\n\t * @param options Azure client configuration (baseUrl, credential, etc)\n\t */\n\tconstructor(public options: AzureClientOptions) {\n\t\tObject.defineProperty(this, \"token\", { enumerable: false });\n\t}\n\n\t/**\n\t * Sends a GET request to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including headers\n\t * @returns The fetch Response object\n\t */\n\tpublic get(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, { ...options, method: \"GET\" });\n\t}\n\n\t/**\n\t * Sends a POST request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic post(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"POST\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a PUT request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic put(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"PUT\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a PATCH request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic patch(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"PATCH\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a DELETE request to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic delete(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, { ...options, method: \"DELETE\" });\n\t}\n\n\t/**\n\t * Sends a request to the Azure REST API, handling token refresh and retries.\n\t * @param path The API path (relative to baseUrl)\n\t * @param options Optional fetch options\n\t * @returns The fetch Response object\n\t * @throws If token refresh fails after max retries\n\t */\n\tpublic async request(path: string, options?: RequestInit): Promise<Response> {\n\t\tfor (let i = 0; i <= AzureClient.MAX_TOKEN_RETRIES; i++) {\n\t\t\tif (this.token && this.token.expiresAt > new Date()) break;\n\t\t\tif (i === AzureClient.MAX_TOKEN_RETRIES) {\n\t\t\t\tthrow new Error(\"Failed to refresh token after multiple attempts\");\n\t\t\t}\n\t\t\tawait this.refreshToken();\n\t\t\tif (i > 0) await new Promise(res => setTimeout(res, 100 * i));\n\t\t}\n\n\t\tif (!this.token) throw new Error(\"Token is unexpectedly null after refresh attempts\");\n\n\t\t// Normalize baseUrl and path to avoid double or missing slashes\n\t\tconst baseUrl = this.options.baseUrl.replace(/\\/+$/, \"\");\n\t\tconst relPath = path.replace(/^\\/+/, \"\");\n\t\tconst url = `${baseUrl}/${relPath}`;\n\n\t\treturn fetch(url, {\n\t\t\t...options,\n\t\t\theaders: {\n\t\t\t\t...(this.options.credential.builder ? this.options.credential.builder(this.token) : { Authorization: `Bearer ${this.token.accessToken}` }),\n\t\t\t\t...options?.headers\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Refreshes the Azure access token using the provided credential helper.\n\t * @private\n\t */\n\tprivate async refreshToken(): Promise<void> {\n\t\tthis.token = await this.options.credential.helper.getToken(this.options.credential.scope);\n\t}\n}\n","import { execFile } from \"node:child_process\";\nimport process from \"node:process\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\n\n/**\n * The raw response returned by Azure CLI when requesting an access token.\n *\n * @property accessToken - The access token string\n * @property expiresOn - Expiry date in RFC3339 format (legacy)\n * @property expires_on - Expiry as seconds since epoch (preferred)\n * @property subscription - (Optional) Subscription ID, may not be present\n * @property tenant - Tenant ID\n * @property tokenType - Token type (usually 'Bearer')\n */\nexport type CLITokenResponse = {\n\taccessToken: string;\n\texpiresOn: string;\n\texpires_on: string;\n\tsubscription?: string;\n\ttenant: string;\n\ttokenType: string;\n};\n\n/**\n * Options for AzureCliCredential.\n *\n * @property tenantId - (Optional) The Azure tenant ID to use for authentication. If not provided, will use the current Azure CLI context.\n */\nexport type AzureCLICredentialOptions = {\n\ttenantId?: string;\n};\n\n/**\n * AzureCliCredential authenticates using the Azure CLI (`az`).\n *\n * - If `tenantId` is provided, uses it for token requests.\n * - If not, will try `AZURE_TENANT_ID` env var, then fall back to the current Azure CLI context.\n *\n * Throws clear errors if the CLI is not installed or not logged in.\n */\nexport class AzureCliCredential implements AzureCredential {\n\tpublic constructor(public options: AzureCLICredentialOptions) {}\n\n\t/**\n\t * Instantiates AzureCliCredential using the AZURE_TENANT_ID environment variable (if set),\n\t * or falls back to the current Azure CLI context.\n\t * @returns AzureCliCredential instance\n\t */\n\tpublic static fromEnv(): AzureCliCredential {\n\t\tconst tenantId = process.env.AZURE_TENANT_ID;\n\t\treturn new AzureCliCredential(tenantId ? { tenantId } : {});\n\t}\n\n\t/**\n\t * Gets an Azure access token using the Azure CLI.\n\t * @param scope The resource scope for the token (e.g. 'https://management.azure.com/.default')\n\t * @returns An object with accessToken, expiresAt, and tokenType\n\t * @throws If CLI is not installed or not logged in\n\t */\n\tpublic async getToken(scope: string): Promise<{ accessToken: string; expiresAt: Date; tokenType: string }> {\n\t\ttry {\n\t\t\tconst tenantId = this.options.tenantId ?? (await AzureCliCredential.getCurrentTenantId());\n\t\t\tconst result = await this.getCliToken(scope, tenantId);\n\t\t\treturn this.parseRawOutput(result.stdout);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Failed to get token: ${(error as Error).message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Runs the Azure CLI to get an access token for the given scope and tenant.\n\t * @param scope The resource scope\n\t * @param tenantId The Azure tenant ID\n\t * @returns Promise resolving to CLI stdout and stderr\n\t * @private\n\t */\n\tprivate async getCliToken(scope: string, tenantId: string): Promise<{ stderr: string; stdout: string }> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\texecFile(\n\t\t\t\t\t\"az\",\n\t\t\t\t\t[\"account\", \"get-access-token\", \"--output\", \"json\", \"--resource\", scope.replace(\".default\", \"\"), \"--tenant\", tenantId],\n\t\t\t\t\t{ cwd: process.cwd(), shell: true, timeout: 30_000 },\n\t\t\t\t\t(error, stdout, stderr) => {\n\t\t\t\t\t\tconst { isLoginError, isNotInstallError } = AzureCliCredential.parseCliLoginError(stderr);\n\t\t\t\t\t\tif (isNotInstallError) {\n\t\t\t\t\t\t\treject(new Error(\"Azure CLI not found. Please install\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (isLoginError) {\n\t\t\t\t\t\t\treject(new Error(\"Please login to Azure CLI\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\treject(new Error(`Failed to get token: ${error.message}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve({ stdout, stderr });\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treject(error as Error);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Gets the current tenant ID from Azure CLI context.\n\t * @returns Promise resolving to the current tenant ID string\n\t * @throws If CLI is not installed or not logged in\n\t */\n\tprivate static async getCurrentTenantId(): Promise<string> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\texecFile(\"az\", [\"account\", \"show\", \"--query\", \"tenantId\", \"--output\", \"tsv\"], { cwd: process.cwd(), shell: true, timeout: 10_000 }, (error, stdout, stderr) => {\n\t\t\t\tconst { isLoginError, isNotInstallError } = AzureCliCredential.parseCliLoginError(stderr);\n\t\t\t\tif (isNotInstallError) {\n\t\t\t\t\treject(new Error(\"Azure CLI not found. Please install\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (isLoginError) {\n\t\t\t\t\treject(new Error(\"Please login to Azure CLI\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (error) {\n\t\t\t\t\treject(new Error(`Failed to detect tenantId from Azure CLI context: ${stderr}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst tenantId = stdout.trim();\n\t\t\t\tif (!tenantId) {\n\t\t\t\t\treject(new Error(\"Could not detect tenantId from Azure CLI context.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tresolve(tenantId);\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Parses the raw CLI output and returns a token + expiry object.\n\t * @param output The stdout from Azure CLI\n\t * @returns An object with accessToken, expiresAt, and tokenType\n\t * @private\n\t */\n\tprivate parseRawOutput(output: string): { accessToken: string; expiresAt: Date; tokenType: string } {\n\t\tconst response = JSON.parse(output) as CLITokenResponse;\n\t\tconst token = response.accessToken;\n\t\tconst expiresOnTimestamp = Number.parseInt(response.expires_on, 10) * 1_000;\n\t\tif (!Number.isNaN(expiresOnTimestamp)) {\n\t\t\treturn {\n\t\t\t\taccessToken: token,\n\t\t\t\texpiresAt: new Date(expiresOnTimestamp),\n\t\t\t\ttokenType: response.tokenType\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\taccessToken: token,\n\t\t\texpiresAt: new Date(response.expiresOn),\n\t\t\ttokenType: response.tokenType\n\t\t};\n\t}\n\n\t/**\n\t * Checks stderr for common Azure CLI login errors.\n\t * @param stderr The stderr string from CLI\n\t * @returns Object with isLoginError and isNotInstallError booleans\n\t * @private\n\t */\n\tprivate static parseCliLoginError(stderr: string): { isLoginError: boolean; isNotInstallError: boolean } {\n\t\tconst specificScope = stderr.match(\"(.*)az login --scope(.*)\");\n\t\tconst isLoginError = stderr.match(\"(.*)az login(.*)\") && !specificScope;\n\t\tconst isNotInstallError = stderr.match(\"az:(.*)not found\") ?? stderr.startsWith(\"'az' is not recognized\");\n\t\treturn {\n\t\t\tisLoginError: Boolean(isLoginError),\n\t\t\tisNotInstallError: Boolean(isNotInstallError)\n\t\t};\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_TENANT_ID: string;\n\t\t}\n\t}\n}\n","/**\n * Represents an Azure access token and its expiration.\n */\nexport type Credential = { accessToken: string; clientId?: string; expiresAt: Date; tokenType: string };\n\n/**\n * Abstract credential class for acquiring Azure tokens.\n * Implement this to provide custom authentication logic.\n */\nexport abstract class AzureCredential {\n\t/**\n\t * Gets an Azure access token for the given scope.\n\t * @param scope The resource or scope for which the token is requested\n\t * @returns A promise resolving to an AzureToken\n\t */\n\tpublic abstract getToken(scope: string): Promise<Credential>;\n}\n","import type { AzureCredential } from \"./AzureCredential.js\";\nimport type { OAuth2TokenResponse } from \"./ServicePrincipalCredential.js\";\n\n/**\n * Options for configuring ManagedIdentityCredential.\n *\n * @property clientId - (Optional) The user-assigned managed identity client ID.\n * @property timeoutMs - (Optional) Timeout in milliseconds for metadata endpoint fetch. Default: 300ms.\n */\nexport type ManagedIdentityCredentialOptions = {\n\tidentityEndpoint?: string; // Optional: custom endpoint, defaults to Azure's default metadata endpoint\n\tclientId?: string;\n\ttimeoutMs?: number; // Optional: custom timeout for fetch\n};\n\n/**\n * AzureCredential implementation for Azure Managed Identity (MSI).\n *\n * Supports both system-assigned and user-assigned managed identities.\n * Works on Azure VM, App Service, Container Apps, etc.\n */\nexport class ManagedIdentityCredential implements AzureCredential {\n\t/**\n\t * @param options Managed identity credential options\n\t */\n\tpublic constructor(public options: ManagedIdentityCredentialOptions = {}) {}\n\n\t/**\n\t * Gets an Azure access token using the managed identity endpoint.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If the endpoint is unavailable or token request fails\n\t */\n\tpublic async getToken(scope: string) {\n\t\tconst endpoint = this.options.identityEndpoint || \"http://169.254.169.254/metadata/identity/oauth2/token\";\n\t\tconst apiVersion = \"2018-02-01\";\n\t\tconst params = new URLSearchParams();\n\t\tparams.set(\"api-version\", apiVersion);\n\t\tparams.set(\"resource\", scope.replace(\".default\", \"\"));\n\t\tif (this.options.clientId) {\n\t\t\tparams.set(\"client_id\", this.options.clientId);\n\t\t}\n\n\t\tconst url = `${endpoint}?${params.toString()}`;\n\t\tconst headers = { Metadata: \"true\" };\n\n\t\t// Add timeout to fetch (default 500ms, can override via options)\n\t\tconst timeoutMs = this.options.timeoutMs ?? 300;\n\t\tconst controller = new AbortController();\n\n\t\t// Manual timeout fallback: Promise.race to guarantee timeout even if fetch/AbortController fails (e.g., network hang)\n\t\tconst timeoutPromise = new Promise<never>((_, reject) => {\n\t\t\tsetTimeout(() => {\n\t\t\t\tcontroller.abort(); // still try to abort fetch\n\t\t\t\treject(new Error(`ManagedIdentityCredential: Timed out after ${timeoutMs}ms waiting for metadata endpoint (${url})`));\n\t\t\t}, timeoutMs);\n\t\t});\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await Promise.race([fetch(url, { headers, signal: controller.signal }), timeoutPromise]);\n\t\t} catch (err: any) {\n\t\t\tif (err.name === \"AbortError\" || /Timed out/.test(err.message)) {\n\t\t\t\tthrow new Error(`ManagedIdentityCredential: Timed out after ${timeoutMs}ms waiting for metadata endpoint (${url})`);\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`ManagedIdentityCredential: Failed to get token: ${await response.text()}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as OAuth2TokenResponse;\n\t\treturn {\n\t\t\taccessToken: data.access_token,\n\t\t\tclientId: data.client_id,\n\t\t\texpiresAt: new Date(data.expires_on ? Number(data.expires_on) * 1000 : Date.now() + 60 * 60 * 1000), // fallback 1h\n\t\t\ttokenType: data.token_type\n\t\t};\n\t}\n\n\t/**\n\t * Instantiates ManagedIdentityCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_CLIENT_ID: The user-assigned managed identity client ID. This is optional for system-assigned identities.\n\t * - AZURE_MANAGED_IDENTITY_ENDPOINT or IDENTITY_ENDPOINT: The managed identity endpoint (optional, defaults to http://169.254.169.254/metadata/identity/oauth2/token)\n\t * - AZURE_MANAGED_IDENTITY_TIMEOUT_MS: Custom timeout for metadata endpoint fetch in milliseconds (optional).\n\t * @returns ManagedIdentityCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new ManagedIdentityCredential({\n\t\t\tidentityEndpoint: process.env.AZURE_MANAGED_IDENTITY_ENDPOINT || process.env.IDENTITY_ENDPOINT,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\ttimeoutMs: process.env.AZURE_MANAGED_IDENTITY_TIMEOUT_MS ? Number.parseInt(process.env.AZURE_MANAGED_IDENTITY_TIMEOUT_MS) : undefined\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_MANAGED_IDENTITY_ENDPOINT?: string;\n\t\t\tAZURE_MANAGED_IDENTITY_TIMEOUT_MS?: string; // Optional: custom timeout for fetch\n\t\t\tIDENTITY_ENDPOINT?: string;\n\t\t}\n\t}\n}\n","import { URLSearchParams } from \"node:url\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\n\n/**\n * The OAuth2 token response returned by Azure AD and Managed Identity endpoints.\n *\n * @property access_token - The access token string\n * @property client_id - The client/application ID (optional, present in MSI)\n * @property expires_in - Seconds until token expiry\n * @property expires_on - Expiry time (epoch seconds, as string)\n * @property ext_expires_in - Extended expiry in seconds\n * @property not_before - Not before time (epoch seconds, as string)\n * @property resource - The resource for which the token is issued\n * @property token_type - The type of token (usually 'Bearer')\n */\nexport type OAuth2TokenResponse = {\n\taccess_token: string;\n\tclient_id?: string;\n\texpires_in: number;\n\texpires_on: string;\n\text_expires_in: number;\n\tnot_before: string;\n\tresource: string;\n\ttoken_type: string;\n};\n\n/**\n * Options for configuring ServicePrincipalCredential.\n *\n * @property clientId - The Azure AD application (client) ID.\n * @property clientSecret - The client secret or JWT assertion (for federated).\n * @property tenantId - The Azure AD tenant ID.\n * @property authorityHost - (Optional) The Azure AD authority host. Defaults to \"https://login.microsoftonline.com\".\n * @property federated - Whether to use federated (JWT) auth. If true, clientSecret is treated as a JWT assertion.\n */\nexport type ServicePrincipalCredentialOption = {\n\tclientId: string;\n\tclientSecret?: string;\n\ttenantId: string;\n\tauthorityHost?: string;\n\tfederated: boolean;\n};\n\n/**\n * AzureCredential implementation for authenticating with a Service Principal (client secret or federated/JWT).\n */\nexport class ServicePrincipalCredential implements AzureCredential {\n\t/**\n\t * @param options Service principal credential options\n\t */\n\tpublic constructor(public options: ServicePrincipalCredentialOption) {}\n\n\t/**\n\t * Gets an Azure access token using the service principal credentials.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If client secret is missing or token request fails\n\t */\n\tpublic async getToken(scope: string) {\n\t\tif (!this.options.clientSecret) throw new Error(\"ServicePrincipalCredential: The client secret is not provided.\");\n\n\t\t// Remove trailing slash from identityAuthorityHost\n\t\tconst url = [this.options.authorityHost?.replace(/\\/$/, \"\") ?? \"https://login.microsoftonline.com\", `${this.options.tenantId}/oauth2/v2.0/token`].join(\"/\");\n\n\t\ttry {\n\t\t\tconst searchParams = {\n\t\t\t\tclient_id: this.options.clientId,\n\t\t\t\tgrant_type: \"client_credentials\",\n\t\t\t\tscope\n\t\t\t};\n\n\t\t\t// If federated, use client_assertion and client_assertion_type\n\t\t\t// Otherwise, use client_secret\n\t\t\tif (this.options.federated) {\n\t\t\t\tObject.assign(searchParams, {\n\t\t\t\t\tclient_assertion: this.options.clientSecret,\n\t\t\t\t\tclient_assertion_type: \"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\"\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tObject.assign(searchParams, {\n\t\t\t\t\tclient_secret: this.options.clientSecret\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst response = await fetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\"\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams(searchParams)\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(`Failed to get token: ${await response.text()}`);\n\t\t\t}\n\n\t\t\tconst data = (await response.json()) as OAuth2TokenResponse;\n\n\t\t\treturn {\n\t\t\t\taccessToken: data.access_token,\n\t\t\t\tclientId: data.client_id ?? this.options.clientId,\n\t\t\t\texpiresAt: new Date(Date.now() + data.expires_in * 1_000),\n\t\t\t\ttokenType: data.token_type\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Failed to get token: ${(error as Error).stack}`);\n\t\t}\n\t}\n\n\t/**\n\t * Instantiates ServicePrincipalCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_CLIENT_ID: The Azure AD application (client) ID\n\t * - AZURE_CLIENT_SECRET: The client secret\n\t * - AZURE_TENANT_ID: The Azure AD tenant ID\n\t * - AZURE_USE_FEDERATED_AUTH: Optional, if set to \"true\", uses federated authentication (JWT assertion).\n\t * @returns ServicePrincipalCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new ServicePrincipalCredential({\n\t\t\tauthorityHost: process.env.AZURE_AUTHORITY_HOST,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\tclientSecret: process.env.AZURE_CLIENT_SECRET,\n\t\t\ttenantId: process.env.AZURE_TENANT_ID,\n\t\t\tfederated: process.env.AZURE_USE_FEDERATED_AUTH === \"true\"\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_CLIENT_ID: string;\n\t\t\tAZURE_CLIENT_SECRET: string;\n\t\t\tAZURE_TENANT_ID: string;\n\t\t\tAZURE_USE_FEDERATED_AUTH: \"true\" | \"false\"; // Optional, defaults to \"false\"\n\t\t}\n\t}\n}\n","import { readFile } from \"node:fs/promises\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\nimport { ServicePrincipalCredential } from \"./ServicePrincipalCredential.js\";\n\n/**\n * Options for configuring WorkloadIdentityCredential.\n *\n * @property clientId - The Azure AD application (client) ID\n * @property federatedTokenFile - Path to the federated token file (OIDC/JWT)\n * @property tenantId - The Azure AD tenant ID\n * @property authorityHost - (Optional) The Azure AD authority host\n */\nexport type WorkloadIdentityCredentialOption = {\n\tclientId: string;\n\tfederatedTokenFile: string;\n\ttenantId: string;\n\tauthorityHost?: string;\n};\n\n/**\n * AzureCredential implementation for Azure Workload Identity (OIDC federated token).\n *\n * Reads a federated token from file and authenticates as a service principal using JWT assertion.\n */\nexport class WorkloadIdentityCredential implements AzureCredential {\n\t/**\n\t * @param options Workload identity credential options\n\t */\n\tpublic constructor(public options: WorkloadIdentityCredentialOption) {}\n\n\t/**\n\t * Gets an Azure access token using the federated token file.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If the federated token file does not exist\n\t */\n\tpublic async getToken(scope: string) {\n\t\ttry {\n\t\t\tconst token = await readFile(this.options.federatedTokenFile, \"utf-8\");\n\t\t\tconst servicePrincipal = new ServicePrincipalCredential({ ...this.options, clientSecret: token, federated: true });\n\n\t\t\treturn servicePrincipal.getToken(scope);\n\t\t} catch (err) {\n\t\t\tif ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\t\tthrow new Error(`WorkloadIdentityCredential: Federated token file not found at ${this.options.federatedTokenFile}`);\n\t\t\t}\n\t\t\tthrow new Error(`WorkloadIdentityCredential: Failed to get token: ${(err as Error).message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Instantiates WorkloadIdentityCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_AUTHORITY_HOST: The Azure AD authority host (optional)\n\t * - AZURE_CLIENT_ID: The Azure AD application (client) ID\n\t * - AZURE_FEDERATED_TOKEN_FILE: Path to the federated token file\n\t * - AZURE_TENANT_ID: The Azure AD tenant ID\n\t * @returns WorkloadIdentityCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new WorkloadIdentityCredential({\n\t\t\tauthorityHost: process.env.AZURE_AUTHORITY_HOST,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\tfederatedTokenFile: process.env.AZURE_FEDERATED_TOKEN_FILE,\n\t\t\ttenantId: process.env.AZURE_TENANT_ID\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_AUTHORITY_HOST: string;\n\t\t\tAZURE_CLIENT_ID: string;\n\t\t\tAZURE_FEDERATED_TOKEN_FILE: string;\n\t\t\tAZURE_TENANT_ID: string;\n\t\t}\n\t}\n}\n","import { AzureCliCredential } from \"./AzureCliCredential.js\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\nimport { ManagedIdentityCredential } from \"./ManagedIdentityCredential.js\";\nimport { ServicePrincipalCredential } from \"./ServicePrincipalCredential.js\";\nimport { WorkloadIdentityCredential } from \"./WorkloadIdentityCredential.js\";\n\nconst credentialChain = [WorkloadIdentityCredential, ManagedIdentityCredential, ServicePrincipalCredential, AzureCliCredential];\n\n/**\n * ChainedCredential tries multiple credential providers in order until one succeeds.\n *\n * The chain is: WorkloadIdentityCredential → ManagedIdentityCredential → ServicePrincipalCredential → AzureCliCredential.\n * Useful for local dev, CI, and cloud environments with minimal config.\n */\nexport class ChainedCredential implements AzureCredential {\n\t/**\n\t * Attempts to get an Azure access token using the first available credential in the chain.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If all credential providers fail\n\t */\n\tpublic async getToken(scope: string) {\n\t\tconst errors: { name: string; error: Error }[] = [];\n\t\tconst debug = process.env.DEBUG?.includes(\"tako-azure-rest:credentials\") || process.env.DEBUG?.includes(\"tako-azure-rest:*\");\n\t\tfor (const Credential of credentialChain) {\n\t\t\tconst label = `[ChainedCredential] ${Credential.name}`;\n\t\t\tlet start: number | undefined;\n\t\t\tif (debug) {\n\t\t\t\tstart = Date.now();\n\t\t\t\tconsole.log(`${label} - trying...`);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await Credential.fromEnv().getToken(scope);\n\t\t\t\tif (debug && start !== undefined) {\n\t\t\t\t\tconst ms = Date.now() - start;\n\t\t\t\t\tconsole.log(`${label} - success in ${ms}ms`);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t} catch (error) {\n\t\t\t\tif (debug && start !== undefined) {\n\t\t\t\t\tconst ms = Date.now() - start;\n\t\t\t\t\tconsole.log(`${label} - failed in ${ms}ms: ${(error as Error).message}`);\n\t\t\t\t}\n\t\t\t\terrors.push({ error: error as Error, name: Credential.name });\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error(`Failed to get token, errors:\\n${errors.map(err => `[${err.name}] ${err.error.message}`).join(\"\\n\")}`);\n\t}\n}\n"],"mappings":"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","names":["process"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/AzureClient.ts","../src/credentials/AzureCliCredential.ts","../src/credentials/AzureCredential.ts","../src/credentials/ManagedIdentityCredential.ts","../src/credentials/ServicePrincipalCredential.ts","../src/credentials/WorkloadIdentityCredential.ts","../src/credentials/ChainedCredential.ts"],"sourcesContent":["export * from \"./AzureClient.js\";\nexport * from \"./credentials/AzureCliCredential.js\";\nexport * from \"./credentials/AzureCredential.js\";\nexport * from \"./credentials/ChainedCredential.js\";\nexport * from \"./credentials/ManagedIdentityCredential.js\";\nexport * from \"./credentials/ServicePrincipalCredential.js\";\nexport * from \"./credentials/WorkloadIdentityCredential.js\";\n","import type { AzureCredential, Credential } from \"./credentials/AzureCredential.js\";\n\n/**\n * Options for configuring the AzureClient instance.\n *\n * @property baseUrl - The base URL for Azure REST API endpoints (e.g. https://management.azure.com)\n * @property credential - Credential configuration for authenticating requests\n * @property helper - An AzureCredential implementation for acquiring tokens\n * @property scope - The Azure resource scope for the token (e.g. https://management.azure.com/.default)\n * @property builder - (Optional) Function to build request headers from a token. If not provided, an Authorization header is set by default.\n */\nexport type AzureClientOptions = {\n\tbaseUrl: string;\n\tcredential: {\n\t\thelper: AzureCredential;\n\t\tscope: string;\n\t\tbuilder?: (token: Credential) => Record<string, string>;\n\t};\n};\n\n/**\n * Azure REST API client with credential refresh and HTTP verb helpers.\n */\nexport class AzureClient {\n\tprivate static readonly MAX_TOKEN_RETRIES = 3;\n\tprivate token: Credential | null = null;\n\n\t/**\n\t * @param options Azure client configuration (baseUrl, credential, etc)\n\t */\n\tconstructor(public options: AzureClientOptions) {\n\t\tObject.defineProperty(this, \"token\", { enumerable: false });\n\t}\n\n\t/**\n\t * Sends a GET request to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including headers\n\t * @returns The fetch Response object\n\t */\n\tpublic get(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, { ...options, method: \"GET\" });\n\t}\n\n\t/**\n\t * Sends a POST request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic post(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"POST\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a PUT request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic put(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"PUT\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a PATCH request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic patch(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"PATCH\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a DELETE request to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic delete(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, { ...options, method: \"DELETE\" });\n\t}\n\n\t/**\n\t * Sends a request to the Azure REST API, handling token refresh and retries.\n\t * @param path The API path (relative to baseUrl)\n\t * @param options Optional fetch options\n\t * @returns The fetch Response object\n\t * @throws If token refresh fails after max retries\n\t */\n\tpublic async request(path: string, options?: RequestInit): Promise<Response> {\n\t\tlet lastError: unknown;\n\t\tfor (let i = 0; i <= AzureClient.MAX_TOKEN_RETRIES; i++) {\n\t\t\tif (this.token && this.token.expiresAt > new Date()) break;\n\t\t\tif (i === AzureClient.MAX_TOKEN_RETRIES) {\n\t\t\t\tthrow new Error(`Failed to refresh token after ${AzureClient.MAX_TOKEN_RETRIES} attempts: ${(lastError as Error)?.message ?? \"unknown error\"}`);\n\t\t\t}\n\t\t\t// Back off before retrying (skip the wait on the first attempt).\n\t\t\tif (i > 0) await new Promise(res => setTimeout(res, 100 * i));\n\t\t\ttry {\n\t\t\t\tawait this.refreshToken();\n\t\t\t} catch (error) {\n\t\t\t\tlastError = error;\n\t\t\t}\n\t\t}\n\n\t\tif (!this.token) throw new Error(\"Token is unexpectedly null after refresh attempts\");\n\n\t\t// Normalize baseUrl and path to avoid double or missing slashes\n\t\tconst baseUrl = this.options.baseUrl.replace(/\\/+$/, \"\");\n\t\tconst relPath = path.replace(/^\\/+/, \"\");\n\t\tconst url = `${baseUrl}/${relPath}`;\n\n\t\treturn fetch(url, {\n\t\t\t...options,\n\t\t\theaders: {\n\t\t\t\t...(this.options.credential.builder ? this.options.credential.builder(this.token) : { Authorization: `Bearer ${this.token.accessToken}` }),\n\t\t\t\t...options?.headers\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Refreshes the Azure access token using the provided credential helper.\n\t * @private\n\t */\n\tprivate async refreshToken(): Promise<void> {\n\t\tthis.token = await this.options.credential.helper.getToken(this.options.credential.scope);\n\t}\n}\n","import { execFile } from \"node:child_process\";\nimport process from \"node:process\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\n\n/**\n * The raw response returned by Azure CLI when requesting an access token.\n *\n * @property accessToken - The access token string\n * @property expiresOn - Expiry date in RFC3339 format (legacy)\n * @property expires_on - Expiry as seconds since epoch (preferred)\n * @property subscription - (Optional) Subscription ID, may not be present\n * @property tenant - Tenant ID\n * @property tokenType - Token type (usually 'Bearer')\n */\nexport type CLITokenResponse = {\n\taccessToken: string;\n\texpiresOn: string;\n\texpires_on: string;\n\tsubscription?: string;\n\ttenant: string;\n\ttokenType: string;\n};\n\n/**\n * Options for AzureCliCredential.\n *\n * @property tenantId - (Optional) The Azure tenant ID to use for authentication. If not provided, will use the current Azure CLI context.\n */\nexport type AzureCLICredentialOptions = {\n\ttenantId?: string;\n};\n\n/**\n * AzureCliCredential authenticates using the Azure CLI (`az`).\n *\n * - If `tenantId` is provided, uses it for token requests.\n * - If not, will try `AZURE_TENANT_ID` env var, then fall back to the current Azure CLI context.\n *\n * Throws clear errors if the CLI is not installed or not logged in.\n */\nexport class AzureCliCredential implements AzureCredential {\n\tpublic constructor(public options: AzureCLICredentialOptions) {}\n\n\t/**\n\t * Instantiates AzureCliCredential using the AZURE_TENANT_ID environment variable (if set),\n\t * or falls back to the current Azure CLI context.\n\t * @returns AzureCliCredential instance\n\t */\n\tpublic static fromEnv(): AzureCliCredential {\n\t\tconst tenantId = process.env.AZURE_TENANT_ID;\n\t\treturn new AzureCliCredential(tenantId ? { tenantId } : {});\n\t}\n\n\t/**\n\t * Gets an Azure access token using the Azure CLI.\n\t * @param scope The resource scope for the token (e.g. 'https://management.azure.com/.default')\n\t * @returns An object with accessToken, expiresAt, and tokenType\n\t * @throws If CLI is not installed or not logged in\n\t */\n\tpublic async getToken(scope: string): Promise<{ accessToken: string; expiresAt: Date; tokenType: string }> {\n\t\ttry {\n\t\t\tconst tenantId = this.options.tenantId ?? (await AzureCliCredential.getCurrentTenantId());\n\t\t\tconst result = await this.getCliToken(scope, tenantId);\n\t\t\treturn this.parseRawOutput(result.stdout);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Failed to get token: ${(error as Error).message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Runs the Azure CLI to get an access token for the given scope and tenant.\n\t * @param scope The resource scope\n\t * @param tenantId The Azure tenant ID\n\t * @returns Promise resolving to CLI stdout and stderr\n\t * @private\n\t */\n\tprivate async getCliToken(scope: string, tenantId: string): Promise<{ stderr: string; stdout: string }> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\texecFile(\n\t\t\t\t\t\"az\",\n\t\t\t\t\t[\"account\", \"get-access-token\", \"--output\", \"json\", \"--resource\", scope.replace(\".default\", \"\"), \"--tenant\", tenantId],\n\t\t\t\t\t{ cwd: process.cwd(), shell: true, timeout: 30_000 },\n\t\t\t\t\t(error, stdout, stderr) => {\n\t\t\t\t\t\tconst { isLoginError, isNotInstallError } = AzureCliCredential.parseCliLoginError(stderr);\n\t\t\t\t\t\tif (isNotInstallError) {\n\t\t\t\t\t\t\treject(new Error(\"Azure CLI not found. Please install\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (isLoginError) {\n\t\t\t\t\t\t\treject(new Error(\"Please login to Azure CLI\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\treject(new Error(`Failed to get token: ${error.message}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve({ stdout, stderr });\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treject(error as Error);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Gets the current tenant ID from Azure CLI context.\n\t * @returns Promise resolving to the current tenant ID string\n\t * @throws If CLI is not installed or not logged in\n\t */\n\tprivate static async getCurrentTenantId(): Promise<string> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\texecFile(\"az\", [\"account\", \"show\", \"--query\", \"tenantId\", \"--output\", \"tsv\"], { cwd: process.cwd(), shell: true, timeout: 10_000 }, (error, stdout, stderr) => {\n\t\t\t\tconst { isLoginError, isNotInstallError } = AzureCliCredential.parseCliLoginError(stderr);\n\t\t\t\tif (isNotInstallError) {\n\t\t\t\t\treject(new Error(\"Azure CLI not found. Please install\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (isLoginError) {\n\t\t\t\t\treject(new Error(\"Please login to Azure CLI\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (error) {\n\t\t\t\t\treject(new Error(`Failed to detect tenantId from Azure CLI context: ${stderr}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst tenantId = stdout.trim();\n\t\t\t\tif (!tenantId) {\n\t\t\t\t\treject(new Error(\"Could not detect tenantId from Azure CLI context.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tresolve(tenantId);\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Parses the raw CLI output and returns a token + expiry object.\n\t * @param output The stdout from Azure CLI\n\t * @returns An object with accessToken, expiresAt, and tokenType\n\t * @private\n\t */\n\tprivate parseRawOutput(output: string): { accessToken: string; expiresAt: Date; tokenType: string } {\n\t\tconst response = JSON.parse(output) as CLITokenResponse;\n\t\tconst token = response.accessToken;\n\t\tconst expiresOnTimestamp = Number.parseInt(response.expires_on, 10) * 1_000;\n\t\tif (!Number.isNaN(expiresOnTimestamp)) {\n\t\t\treturn {\n\t\t\t\taccessToken: token,\n\t\t\t\texpiresAt: new Date(expiresOnTimestamp),\n\t\t\t\ttokenType: response.tokenType\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\taccessToken: token,\n\t\t\texpiresAt: new Date(response.expiresOn),\n\t\t\ttokenType: response.tokenType\n\t\t};\n\t}\n\n\t/**\n\t * Checks stderr for common Azure CLI login errors.\n\t * @param stderr The stderr string from CLI\n\t * @returns Object with isLoginError and isNotInstallError booleans\n\t * @private\n\t */\n\tprivate static parseCliLoginError(stderr: string): { isLoginError: boolean; isNotInstallError: boolean } {\n\t\tconst specificScope = stderr.match(\"(.*)az login --scope(.*)\");\n\t\tconst isLoginError = stderr.match(\"(.*)az login(.*)\") && !specificScope;\n\t\tconst isNotInstallError = stderr.match(\"az:(.*)not found\") ?? stderr.startsWith(\"'az' is not recognized\");\n\t\treturn {\n\t\t\tisLoginError: Boolean(isLoginError),\n\t\t\tisNotInstallError: Boolean(isNotInstallError)\n\t\t};\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_TENANT_ID: string;\n\t\t}\n\t}\n}\n","/**\n * Represents an Azure access token and its expiration.\n */\nexport type Credential = { accessToken: string; clientId?: string; expiresAt: Date; tokenType: string };\n\n/**\n * Abstract credential class for acquiring Azure tokens.\n * Implement this to provide custom authentication logic.\n */\nexport abstract class AzureCredential {\n\t/**\n\t * Gets an Azure access token for the given scope.\n\t * @param scope The resource or scope for which the token is requested\n\t * @returns A promise resolving to an AzureToken\n\t */\n\tpublic abstract getToken(scope: string): Promise<Credential>;\n}\n","import type { AzureCredential } from \"./AzureCredential.js\";\nimport type { OAuth2TokenResponse } from \"./ServicePrincipalCredential.js\";\n\n/**\n * Options for configuring ManagedIdentityCredential.\n *\n * @property clientId - (Optional) The user-assigned managed identity client ID.\n * @property timeoutMs - (Optional) Timeout in milliseconds for metadata endpoint fetch. Default: 300ms.\n */\nexport type ManagedIdentityCredentialOptions = {\n\tidentityEndpoint?: string; // Optional: custom endpoint, defaults to Azure's default metadata endpoint\n\tclientId?: string;\n\ttimeoutMs?: number; // Optional: custom timeout for fetch\n};\n\n/**\n * AzureCredential implementation for Azure Managed Identity (MSI).\n *\n * Supports both system-assigned and user-assigned managed identities.\n * Works on Azure VM, App Service, Container Apps, etc.\n */\nexport class ManagedIdentityCredential implements AzureCredential {\n\t/**\n\t * @param options Managed identity credential options\n\t */\n\tpublic constructor(public options: ManagedIdentityCredentialOptions = {}) {}\n\n\t/**\n\t * Gets an Azure access token using the managed identity endpoint.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If the endpoint is unavailable or token request fails\n\t */\n\tpublic async getToken(scope: string) {\n\t\tconst endpoint = this.options.identityEndpoint || \"http://169.254.169.254/metadata/identity/oauth2/token\";\n\t\tconst apiVersion = \"2018-02-01\";\n\t\tconst params = new URLSearchParams();\n\t\tparams.set(\"api-version\", apiVersion);\n\t\tparams.set(\"resource\", scope.replace(\".default\", \"\"));\n\t\tif (this.options.clientId) {\n\t\t\tparams.set(\"client_id\", this.options.clientId);\n\t\t}\n\n\t\tconst url = `${endpoint}?${params.toString()}`;\n\t\tconst headers = { Metadata: \"true\" };\n\n\t\t// Add timeout to fetch (default 500ms, can override via options)\n\t\tconst timeoutMs = this.options.timeoutMs ?? 300;\n\t\tconst controller = new AbortController();\n\n\t\t// Manual timeout fallback: Promise.race to guarantee timeout even if fetch/AbortController fails (e.g., network hang)\n\t\tconst timeoutPromise = new Promise<never>((_, reject) => {\n\t\t\tsetTimeout(() => {\n\t\t\t\tcontroller.abort(); // still try to abort fetch\n\t\t\t\treject(new Error(`ManagedIdentityCredential: Timed out after ${timeoutMs}ms waiting for metadata endpoint (${url})`));\n\t\t\t}, timeoutMs);\n\t\t});\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await Promise.race([fetch(url, { headers, signal: controller.signal }), timeoutPromise]);\n\t\t} catch (err: any) {\n\t\t\tif (err.name === \"AbortError\" || /Timed out/.test(err.message)) {\n\t\t\t\tthrow new Error(`ManagedIdentityCredential: Timed out after ${timeoutMs}ms waiting for metadata endpoint (${url})`);\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`ManagedIdentityCredential: Failed to get token: ${await response.text()}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as OAuth2TokenResponse;\n\t\treturn {\n\t\t\taccessToken: data.access_token,\n\t\t\tclientId: data.client_id,\n\t\t\texpiresAt: new Date(data.expires_on ? Number(data.expires_on) * 1000 : Date.now() + 60 * 60 * 1000), // fallback 1h\n\t\t\ttokenType: data.token_type\n\t\t};\n\t}\n\n\t/**\n\t * Instantiates ManagedIdentityCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_CLIENT_ID: The user-assigned managed identity client ID. This is optional for system-assigned identities.\n\t * - AZURE_MANAGED_IDENTITY_ENDPOINT or IDENTITY_ENDPOINT: The managed identity endpoint (optional, defaults to http://169.254.169.254/metadata/identity/oauth2/token)\n\t * - AZURE_MANAGED_IDENTITY_TIMEOUT_MS: Custom timeout for metadata endpoint fetch in milliseconds (optional).\n\t * @returns ManagedIdentityCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new ManagedIdentityCredential({\n\t\t\tidentityEndpoint: process.env.AZURE_MANAGED_IDENTITY_ENDPOINT || process.env.IDENTITY_ENDPOINT,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\ttimeoutMs: process.env.AZURE_MANAGED_IDENTITY_TIMEOUT_MS ? Number.parseInt(process.env.AZURE_MANAGED_IDENTITY_TIMEOUT_MS) : undefined\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_MANAGED_IDENTITY_ENDPOINT?: string;\n\t\t\tAZURE_MANAGED_IDENTITY_TIMEOUT_MS?: string; // Optional: custom timeout for fetch\n\t\t\tIDENTITY_ENDPOINT?: string;\n\t\t}\n\t}\n}\n","import { URLSearchParams } from \"node:url\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\n\n/**\n * The OAuth2 token response returned by Azure AD and Managed Identity endpoints.\n *\n * @property access_token - The access token string\n * @property client_id - The client/application ID (optional, present in MSI)\n * @property expires_in - Seconds until token expiry\n * @property expires_on - Expiry time (epoch seconds, as string)\n * @property ext_expires_in - Extended expiry in seconds\n * @property not_before - Not before time (epoch seconds, as string)\n * @property resource - The resource for which the token is issued\n * @property token_type - The type of token (usually 'Bearer')\n */\nexport type OAuth2TokenResponse = {\n\taccess_token: string;\n\tclient_id?: string;\n\texpires_in: number;\n\texpires_on: string;\n\text_expires_in: number;\n\tnot_before: string;\n\tresource: string;\n\ttoken_type: string;\n};\n\n/**\n * Options for configuring ServicePrincipalCredential.\n *\n * @property clientId - The Azure AD application (client) ID.\n * @property clientSecret - The client secret or JWT assertion (for federated).\n * @property tenantId - The Azure AD tenant ID.\n * @property authorityHost - (Optional) The Azure AD authority host. Defaults to \"https://login.microsoftonline.com\".\n * @property federated - Whether to use federated (JWT) auth. If true, clientSecret is treated as a JWT assertion.\n */\nexport type ServicePrincipalCredentialOption = {\n\tclientId: string;\n\tclientSecret?: string;\n\ttenantId: string;\n\tauthorityHost?: string;\n\tfederated: boolean;\n};\n\n/**\n * AzureCredential implementation for authenticating with a Service Principal (client secret or federated/JWT).\n */\nexport class ServicePrincipalCredential implements AzureCredential {\n\t/**\n\t * @param options Service principal credential options\n\t */\n\tpublic constructor(public options: ServicePrincipalCredentialOption) {}\n\n\t/**\n\t * Gets an Azure access token using the service principal credentials.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If client secret is missing or token request fails\n\t */\n\tpublic async getToken(scope: string) {\n\t\tif (!this.options.clientSecret) throw new Error(\"ServicePrincipalCredential: The client secret is not provided.\");\n\n\t\t// Remove trailing slash from identityAuthorityHost\n\t\tconst url = [this.options.authorityHost?.replace(/\\/$/, \"\") ?? \"https://login.microsoftonline.com\", `${this.options.tenantId}/oauth2/v2.0/token`].join(\"/\");\n\n\t\ttry {\n\t\t\tconst searchParams = {\n\t\t\t\tclient_id: this.options.clientId,\n\t\t\t\tgrant_type: \"client_credentials\",\n\t\t\t\tscope\n\t\t\t};\n\n\t\t\t// If federated, use client_assertion and client_assertion_type\n\t\t\t// Otherwise, use client_secret\n\t\t\tif (this.options.federated) {\n\t\t\t\tObject.assign(searchParams, {\n\t\t\t\t\tclient_assertion: this.options.clientSecret,\n\t\t\t\t\tclient_assertion_type: \"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\"\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tObject.assign(searchParams, {\n\t\t\t\t\tclient_secret: this.options.clientSecret\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst response = await fetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\"\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams(searchParams)\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(`Failed to get token: ${await response.text()}`);\n\t\t\t}\n\n\t\t\tconst data = (await response.json()) as OAuth2TokenResponse;\n\n\t\t\treturn {\n\t\t\t\taccessToken: data.access_token,\n\t\t\t\tclientId: data.client_id ?? this.options.clientId,\n\t\t\t\texpiresAt: new Date(Date.now() + data.expires_in * 1_000),\n\t\t\t\ttokenType: data.token_type\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new Error(`ServicePrincipalCredential: Failed to get token: ${(error as Error).message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Instantiates ServicePrincipalCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_CLIENT_ID: The Azure AD application (client) ID\n\t * - AZURE_CLIENT_SECRET: The client secret\n\t * - AZURE_TENANT_ID: The Azure AD tenant ID\n\t * - AZURE_USE_FEDERATED_AUTH: Optional, if set to \"true\", uses federated authentication (JWT assertion).\n\t * @returns ServicePrincipalCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new ServicePrincipalCredential({\n\t\t\tauthorityHost: process.env.AZURE_AUTHORITY_HOST,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\tclientSecret: process.env.AZURE_CLIENT_SECRET,\n\t\t\ttenantId: process.env.AZURE_TENANT_ID,\n\t\t\tfederated: process.env.AZURE_USE_FEDERATED_AUTH === \"true\"\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_CLIENT_ID: string;\n\t\t\tAZURE_CLIENT_SECRET: string;\n\t\t\tAZURE_TENANT_ID: string;\n\t\t\tAZURE_USE_FEDERATED_AUTH: \"true\" | \"false\"; // Optional, defaults to \"false\"\n\t\t}\n\t}\n}\n","import { readFile } from \"node:fs/promises\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\nimport { ServicePrincipalCredential } from \"./ServicePrincipalCredential.js\";\n\n/**\n * Options for configuring WorkloadIdentityCredential.\n *\n * @property clientId - The Azure AD application (client) ID\n * @property federatedTokenFile - Path to the federated token file (OIDC/JWT)\n * @property tenantId - The Azure AD tenant ID\n * @property authorityHost - (Optional) The Azure AD authority host\n */\nexport type WorkloadIdentityCredentialOption = {\n\tclientId: string;\n\tfederatedTokenFile: string;\n\ttenantId: string;\n\tauthorityHost?: string;\n};\n\n/**\n * AzureCredential implementation for Azure Workload Identity (OIDC federated token).\n *\n * Reads a federated token from file and authenticates as a service principal using JWT assertion.\n */\nexport class WorkloadIdentityCredential implements AzureCredential {\n\t/**\n\t * @param options Workload identity credential options\n\t */\n\tpublic constructor(public options: WorkloadIdentityCredentialOption) {}\n\n\t/**\n\t * Gets an Azure access token using the federated token file.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If the federated token file does not exist\n\t */\n\tpublic async getToken(scope: string) {\n\t\ttry {\n\t\t\tconst token = await readFile(this.options.federatedTokenFile, \"utf-8\");\n\t\t\tconst servicePrincipal = new ServicePrincipalCredential({ ...this.options, clientSecret: token, federated: true });\n\n\t\t\treturn servicePrincipal.getToken(scope);\n\t\t} catch (err) {\n\t\t\tif ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\t\tthrow new Error(`WorkloadIdentityCredential: Federated token file not found at ${this.options.federatedTokenFile}`);\n\t\t\t}\n\t\t\tthrow new Error(`WorkloadIdentityCredential: Failed to get token: ${(err as Error).message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Instantiates WorkloadIdentityCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_AUTHORITY_HOST: The Azure AD authority host (optional)\n\t * - AZURE_CLIENT_ID: The Azure AD application (client) ID\n\t * - AZURE_FEDERATED_TOKEN_FILE: Path to the federated token file\n\t * - AZURE_TENANT_ID: The Azure AD tenant ID\n\t * @returns WorkloadIdentityCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new WorkloadIdentityCredential({\n\t\t\tauthorityHost: process.env.AZURE_AUTHORITY_HOST,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\tfederatedTokenFile: process.env.AZURE_FEDERATED_TOKEN_FILE,\n\t\t\ttenantId: process.env.AZURE_TENANT_ID\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_AUTHORITY_HOST: string;\n\t\t\tAZURE_CLIENT_ID: string;\n\t\t\tAZURE_FEDERATED_TOKEN_FILE: string;\n\t\t\tAZURE_TENANT_ID: string;\n\t\t}\n\t}\n}\n","import { AzureCliCredential } from \"./AzureCliCredential.js\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\nimport { ManagedIdentityCredential } from \"./ManagedIdentityCredential.js\";\nimport { ServicePrincipalCredential } from \"./ServicePrincipalCredential.js\";\nimport { WorkloadIdentityCredential } from \"./WorkloadIdentityCredential.js\";\n\nconst credentialChain = [WorkloadIdentityCredential, ManagedIdentityCredential, ServicePrincipalCredential, AzureCliCredential];\n\n/**\n * ChainedCredential tries multiple credential providers in order until one succeeds.\n *\n * The chain is: WorkloadIdentityCredential → ManagedIdentityCredential → ServicePrincipalCredential → AzureCliCredential.\n * Useful for local dev, CI, and cloud environments with minimal config.\n */\nexport class ChainedCredential implements AzureCredential {\n\t/**\n\t * Attempts to get an Azure access token using the first available credential in the chain.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If all credential providers fail\n\t */\n\tpublic async getToken(scope: string) {\n\t\tconst errors: { name: string; error: Error }[] = [];\n\t\tconst debug = process.env.DEBUG?.includes(\"tako-azure-rest:credentials\") || process.env.DEBUG?.includes(\"tako-azure-rest:*\");\n\t\tfor (const Credential of credentialChain) {\n\t\t\tconst label = `[ChainedCredential] ${Credential.name}`;\n\t\t\tlet start: number | undefined;\n\t\t\tif (debug) {\n\t\t\t\tstart = Date.now();\n\t\t\t\tconsole.log(`${label} - trying...`);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await Credential.fromEnv().getToken(scope);\n\t\t\t\tif (debug && start !== undefined) {\n\t\t\t\t\tconst ms = Date.now() - start;\n\t\t\t\t\tconsole.log(`${label} - success in ${ms}ms`);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t} catch (error) {\n\t\t\t\tif (debug && start !== undefined) {\n\t\t\t\t\tconst ms = Date.now() - start;\n\t\t\t\t\tconsole.log(`${label} - failed in ${ms}ms: ${(error as Error).message}`);\n\t\t\t\t}\n\t\t\t\terrors.push({ error: error as Error, name: Credential.name });\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error(`Failed to get token, errors:\\n${errors.map(err => `[${err.name}] ${err.error.message}`).join(\"\\n\")}`);\n\t}\n}\n"],"mappings":"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","names":["process"]}
|
package/dist/index.js
CHANGED
|
@@ -71,13 +71,18 @@ var AzureClient = class _AzureClient {
|
|
|
71
71
|
* @throws If token refresh fails after max retries
|
|
72
72
|
*/
|
|
73
73
|
async request(path, options) {
|
|
74
|
+
let lastError;
|
|
74
75
|
for (let i = 0; i <= _AzureClient.MAX_TOKEN_RETRIES; i++) {
|
|
75
76
|
if (this.token && this.token.expiresAt > /* @__PURE__ */ new Date()) break;
|
|
76
77
|
if (i === _AzureClient.MAX_TOKEN_RETRIES) {
|
|
77
|
-
throw new Error(
|
|
78
|
+
throw new Error(`Failed to refresh token after ${_AzureClient.MAX_TOKEN_RETRIES} attempts: ${lastError?.message ?? "unknown error"}`);
|
|
78
79
|
}
|
|
79
|
-
await this.refreshToken();
|
|
80
80
|
if (i > 0) await new Promise((res) => setTimeout(res, 100 * i));
|
|
81
|
+
try {
|
|
82
|
+
await this.refreshToken();
|
|
83
|
+
} catch (error) {
|
|
84
|
+
lastError = error;
|
|
85
|
+
}
|
|
81
86
|
}
|
|
82
87
|
if (!this.token) throw new Error("Token is unexpectedly null after refresh attempts");
|
|
83
88
|
const baseUrl = this.options.baseUrl.replace(/\/+$/, "");
|
|
@@ -365,7 +370,7 @@ var ServicePrincipalCredential = class _ServicePrincipalCredential {
|
|
|
365
370
|
tokenType: data.token_type
|
|
366
371
|
};
|
|
367
372
|
} catch (error) {
|
|
368
|
-
throw new Error(`Failed to get token: ${error.
|
|
373
|
+
throw new Error(`ServicePrincipalCredential: Failed to get token: ${error.message}`);
|
|
369
374
|
}
|
|
370
375
|
}
|
|
371
376
|
/**
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/AzureClient.ts","../src/credentials/AzureCliCredential.ts","../src/credentials/AzureCredential.ts","../src/credentials/ManagedIdentityCredential.ts","../src/credentials/ServicePrincipalCredential.ts","../src/credentials/WorkloadIdentityCredential.ts","../src/credentials/ChainedCredential.ts"],"sourcesContent":["import type { AzureCredential, Credential } from \"./credentials/AzureCredential.js\";\n\n/**\n * Options for configuring the AzureClient instance.\n *\n * @property baseUrl - The base URL for Azure REST API endpoints (e.g. https://management.azure.com)\n * @property credential - Credential configuration for authenticating requests\n * @property helper - An AzureCredential implementation for acquiring tokens\n * @property scope - The Azure resource scope for the token (e.g. https://management.azure.com/.default)\n * @property builder - (Optional) Function to build request headers from a token. If not provided, an Authorization header is set by default.\n */\nexport type AzureClientOptions = {\n\tbaseUrl: string;\n\tcredential: {\n\t\thelper: AzureCredential;\n\t\tscope: string;\n\t\tbuilder?: (token: Credential) => Record<string, string>;\n\t};\n};\n\n/**\n * Azure REST API client with credential refresh and HTTP verb helpers.\n */\nexport class AzureClient {\n\tprivate static readonly MAX_TOKEN_RETRIES = 3;\n\tprivate token: Credential | null = null;\n\n\t/**\n\t * @param options Azure client configuration (baseUrl, credential, etc)\n\t */\n\tconstructor(public options: AzureClientOptions) {\n\t\tObject.defineProperty(this, \"token\", { enumerable: false });\n\t}\n\n\t/**\n\t * Sends a GET request to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including headers\n\t * @returns The fetch Response object\n\t */\n\tpublic get(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, { ...options, method: \"GET\" });\n\t}\n\n\t/**\n\t * Sends a POST request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic post(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"POST\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a PUT request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic put(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"PUT\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a PATCH request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic patch(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"PATCH\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a DELETE request to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic delete(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, { ...options, method: \"DELETE\" });\n\t}\n\n\t/**\n\t * Sends a request to the Azure REST API, handling token refresh and retries.\n\t * @param path The API path (relative to baseUrl)\n\t * @param options Optional fetch options\n\t * @returns The fetch Response object\n\t * @throws If token refresh fails after max retries\n\t */\n\tpublic async request(path: string, options?: RequestInit): Promise<Response> {\n\t\tfor (let i = 0; i <= AzureClient.MAX_TOKEN_RETRIES; i++) {\n\t\t\tif (this.token && this.token.expiresAt > new Date()) break;\n\t\t\tif (i === AzureClient.MAX_TOKEN_RETRIES) {\n\t\t\t\tthrow new Error(\"Failed to refresh token after multiple attempts\");\n\t\t\t}\n\t\t\tawait this.refreshToken();\n\t\t\tif (i > 0) await new Promise(res => setTimeout(res, 100 * i));\n\t\t}\n\n\t\tif (!this.token) throw new Error(\"Token is unexpectedly null after refresh attempts\");\n\n\t\t// Normalize baseUrl and path to avoid double or missing slashes\n\t\tconst baseUrl = this.options.baseUrl.replace(/\\/+$/, \"\");\n\t\tconst relPath = path.replace(/^\\/+/, \"\");\n\t\tconst url = `${baseUrl}/${relPath}`;\n\n\t\treturn fetch(url, {\n\t\t\t...options,\n\t\t\theaders: {\n\t\t\t\t...(this.options.credential.builder ? this.options.credential.builder(this.token) : { Authorization: `Bearer ${this.token.accessToken}` }),\n\t\t\t\t...options?.headers\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Refreshes the Azure access token using the provided credential helper.\n\t * @private\n\t */\n\tprivate async refreshToken(): Promise<void> {\n\t\tthis.token = await this.options.credential.helper.getToken(this.options.credential.scope);\n\t}\n}\n","import { execFile } from \"node:child_process\";\nimport process from \"node:process\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\n\n/**\n * The raw response returned by Azure CLI when requesting an access token.\n *\n * @property accessToken - The access token string\n * @property expiresOn - Expiry date in RFC3339 format (legacy)\n * @property expires_on - Expiry as seconds since epoch (preferred)\n * @property subscription - (Optional) Subscription ID, may not be present\n * @property tenant - Tenant ID\n * @property tokenType - Token type (usually 'Bearer')\n */\nexport type CLITokenResponse = {\n\taccessToken: string;\n\texpiresOn: string;\n\texpires_on: string;\n\tsubscription?: string;\n\ttenant: string;\n\ttokenType: string;\n};\n\n/**\n * Options for AzureCliCredential.\n *\n * @property tenantId - (Optional) The Azure tenant ID to use for authentication. If not provided, will use the current Azure CLI context.\n */\nexport type AzureCLICredentialOptions = {\n\ttenantId?: string;\n};\n\n/**\n * AzureCliCredential authenticates using the Azure CLI (`az`).\n *\n * - If `tenantId` is provided, uses it for token requests.\n * - If not, will try `AZURE_TENANT_ID` env var, then fall back to the current Azure CLI context.\n *\n * Throws clear errors if the CLI is not installed or not logged in.\n */\nexport class AzureCliCredential implements AzureCredential {\n\tpublic constructor(public options: AzureCLICredentialOptions) {}\n\n\t/**\n\t * Instantiates AzureCliCredential using the AZURE_TENANT_ID environment variable (if set),\n\t * or falls back to the current Azure CLI context.\n\t * @returns AzureCliCredential instance\n\t */\n\tpublic static fromEnv(): AzureCliCredential {\n\t\tconst tenantId = process.env.AZURE_TENANT_ID;\n\t\treturn new AzureCliCredential(tenantId ? { tenantId } : {});\n\t}\n\n\t/**\n\t * Gets an Azure access token using the Azure CLI.\n\t * @param scope The resource scope for the token (e.g. 'https://management.azure.com/.default')\n\t * @returns An object with accessToken, expiresAt, and tokenType\n\t * @throws If CLI is not installed or not logged in\n\t */\n\tpublic async getToken(scope: string): Promise<{ accessToken: string; expiresAt: Date; tokenType: string }> {\n\t\ttry {\n\t\t\tconst tenantId = this.options.tenantId ?? (await AzureCliCredential.getCurrentTenantId());\n\t\t\tconst result = await this.getCliToken(scope, tenantId);\n\t\t\treturn this.parseRawOutput(result.stdout);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Failed to get token: ${(error as Error).message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Runs the Azure CLI to get an access token for the given scope and tenant.\n\t * @param scope The resource scope\n\t * @param tenantId The Azure tenant ID\n\t * @returns Promise resolving to CLI stdout and stderr\n\t * @private\n\t */\n\tprivate async getCliToken(scope: string, tenantId: string): Promise<{ stderr: string; stdout: string }> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\texecFile(\n\t\t\t\t\t\"az\",\n\t\t\t\t\t[\"account\", \"get-access-token\", \"--output\", \"json\", \"--resource\", scope.replace(\".default\", \"\"), \"--tenant\", tenantId],\n\t\t\t\t\t{ cwd: process.cwd(), shell: true, timeout: 30_000 },\n\t\t\t\t\t(error, stdout, stderr) => {\n\t\t\t\t\t\tconst { isLoginError, isNotInstallError } = AzureCliCredential.parseCliLoginError(stderr);\n\t\t\t\t\t\tif (isNotInstallError) {\n\t\t\t\t\t\t\treject(new Error(\"Azure CLI not found. Please install\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (isLoginError) {\n\t\t\t\t\t\t\treject(new Error(\"Please login to Azure CLI\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\treject(new Error(`Failed to get token: ${error.message}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve({ stdout, stderr });\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treject(error as Error);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Gets the current tenant ID from Azure CLI context.\n\t * @returns Promise resolving to the current tenant ID string\n\t * @throws If CLI is not installed or not logged in\n\t */\n\tprivate static async getCurrentTenantId(): Promise<string> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\texecFile(\"az\", [\"account\", \"show\", \"--query\", \"tenantId\", \"--output\", \"tsv\"], { cwd: process.cwd(), shell: true, timeout: 10_000 }, (error, stdout, stderr) => {\n\t\t\t\tconst { isLoginError, isNotInstallError } = AzureCliCredential.parseCliLoginError(stderr);\n\t\t\t\tif (isNotInstallError) {\n\t\t\t\t\treject(new Error(\"Azure CLI not found. Please install\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (isLoginError) {\n\t\t\t\t\treject(new Error(\"Please login to Azure CLI\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (error) {\n\t\t\t\t\treject(new Error(`Failed to detect tenantId from Azure CLI context: ${stderr}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst tenantId = stdout.trim();\n\t\t\t\tif (!tenantId) {\n\t\t\t\t\treject(new Error(\"Could not detect tenantId from Azure CLI context.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tresolve(tenantId);\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Parses the raw CLI output and returns a token + expiry object.\n\t * @param output The stdout from Azure CLI\n\t * @returns An object with accessToken, expiresAt, and tokenType\n\t * @private\n\t */\n\tprivate parseRawOutput(output: string): { accessToken: string; expiresAt: Date; tokenType: string } {\n\t\tconst response = JSON.parse(output) as CLITokenResponse;\n\t\tconst token = response.accessToken;\n\t\tconst expiresOnTimestamp = Number.parseInt(response.expires_on, 10) * 1_000;\n\t\tif (!Number.isNaN(expiresOnTimestamp)) {\n\t\t\treturn {\n\t\t\t\taccessToken: token,\n\t\t\t\texpiresAt: new Date(expiresOnTimestamp),\n\t\t\t\ttokenType: response.tokenType\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\taccessToken: token,\n\t\t\texpiresAt: new Date(response.expiresOn),\n\t\t\ttokenType: response.tokenType\n\t\t};\n\t}\n\n\t/**\n\t * Checks stderr for common Azure CLI login errors.\n\t * @param stderr The stderr string from CLI\n\t * @returns Object with isLoginError and isNotInstallError booleans\n\t * @private\n\t */\n\tprivate static parseCliLoginError(stderr: string): { isLoginError: boolean; isNotInstallError: boolean } {\n\t\tconst specificScope = stderr.match(\"(.*)az login --scope(.*)\");\n\t\tconst isLoginError = stderr.match(\"(.*)az login(.*)\") && !specificScope;\n\t\tconst isNotInstallError = stderr.match(\"az:(.*)not found\") ?? stderr.startsWith(\"'az' is not recognized\");\n\t\treturn {\n\t\t\tisLoginError: Boolean(isLoginError),\n\t\t\tisNotInstallError: Boolean(isNotInstallError)\n\t\t};\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_TENANT_ID: string;\n\t\t}\n\t}\n}\n","/**\n * Represents an Azure access token and its expiration.\n */\nexport type Credential = { accessToken: string; clientId?: string; expiresAt: Date; tokenType: string };\n\n/**\n * Abstract credential class for acquiring Azure tokens.\n * Implement this to provide custom authentication logic.\n */\nexport abstract class AzureCredential {\n\t/**\n\t * Gets an Azure access token for the given scope.\n\t * @param scope The resource or scope for which the token is requested\n\t * @returns A promise resolving to an AzureToken\n\t */\n\tpublic abstract getToken(scope: string): Promise<Credential>;\n}\n","import type { AzureCredential } from \"./AzureCredential.js\";\nimport type { OAuth2TokenResponse } from \"./ServicePrincipalCredential.js\";\n\n/**\n * Options for configuring ManagedIdentityCredential.\n *\n * @property clientId - (Optional) The user-assigned managed identity client ID.\n * @property timeoutMs - (Optional) Timeout in milliseconds for metadata endpoint fetch. Default: 300ms.\n */\nexport type ManagedIdentityCredentialOptions = {\n\tidentityEndpoint?: string; // Optional: custom endpoint, defaults to Azure's default metadata endpoint\n\tclientId?: string;\n\ttimeoutMs?: number; // Optional: custom timeout for fetch\n};\n\n/**\n * AzureCredential implementation for Azure Managed Identity (MSI).\n *\n * Supports both system-assigned and user-assigned managed identities.\n * Works on Azure VM, App Service, Container Apps, etc.\n */\nexport class ManagedIdentityCredential implements AzureCredential {\n\t/**\n\t * @param options Managed identity credential options\n\t */\n\tpublic constructor(public options: ManagedIdentityCredentialOptions = {}) {}\n\n\t/**\n\t * Gets an Azure access token using the managed identity endpoint.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If the endpoint is unavailable or token request fails\n\t */\n\tpublic async getToken(scope: string) {\n\t\tconst endpoint = this.options.identityEndpoint || \"http://169.254.169.254/metadata/identity/oauth2/token\";\n\t\tconst apiVersion = \"2018-02-01\";\n\t\tconst params = new URLSearchParams();\n\t\tparams.set(\"api-version\", apiVersion);\n\t\tparams.set(\"resource\", scope.replace(\".default\", \"\"));\n\t\tif (this.options.clientId) {\n\t\t\tparams.set(\"client_id\", this.options.clientId);\n\t\t}\n\n\t\tconst url = `${endpoint}?${params.toString()}`;\n\t\tconst headers = { Metadata: \"true\" };\n\n\t\t// Add timeout to fetch (default 500ms, can override via options)\n\t\tconst timeoutMs = this.options.timeoutMs ?? 300;\n\t\tconst controller = new AbortController();\n\n\t\t// Manual timeout fallback: Promise.race to guarantee timeout even if fetch/AbortController fails (e.g., network hang)\n\t\tconst timeoutPromise = new Promise<never>((_, reject) => {\n\t\t\tsetTimeout(() => {\n\t\t\t\tcontroller.abort(); // still try to abort fetch\n\t\t\t\treject(new Error(`ManagedIdentityCredential: Timed out after ${timeoutMs}ms waiting for metadata endpoint (${url})`));\n\t\t\t}, timeoutMs);\n\t\t});\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await Promise.race([fetch(url, { headers, signal: controller.signal }), timeoutPromise]);\n\t\t} catch (err: any) {\n\t\t\tif (err.name === \"AbortError\" || /Timed out/.test(err.message)) {\n\t\t\t\tthrow new Error(`ManagedIdentityCredential: Timed out after ${timeoutMs}ms waiting for metadata endpoint (${url})`);\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`ManagedIdentityCredential: Failed to get token: ${await response.text()}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as OAuth2TokenResponse;\n\t\treturn {\n\t\t\taccessToken: data.access_token,\n\t\t\tclientId: data.client_id,\n\t\t\texpiresAt: new Date(data.expires_on ? Number(data.expires_on) * 1000 : Date.now() + 60 * 60 * 1000), // fallback 1h\n\t\t\ttokenType: data.token_type\n\t\t};\n\t}\n\n\t/**\n\t * Instantiates ManagedIdentityCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_CLIENT_ID: The user-assigned managed identity client ID. This is optional for system-assigned identities.\n\t * - AZURE_MANAGED_IDENTITY_ENDPOINT or IDENTITY_ENDPOINT: The managed identity endpoint (optional, defaults to http://169.254.169.254/metadata/identity/oauth2/token)\n\t * - AZURE_MANAGED_IDENTITY_TIMEOUT_MS: Custom timeout for metadata endpoint fetch in milliseconds (optional).\n\t * @returns ManagedIdentityCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new ManagedIdentityCredential({\n\t\t\tidentityEndpoint: process.env.AZURE_MANAGED_IDENTITY_ENDPOINT || process.env.IDENTITY_ENDPOINT,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\ttimeoutMs: process.env.AZURE_MANAGED_IDENTITY_TIMEOUT_MS ? Number.parseInt(process.env.AZURE_MANAGED_IDENTITY_TIMEOUT_MS) : undefined\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_MANAGED_IDENTITY_ENDPOINT?: string;\n\t\t\tAZURE_MANAGED_IDENTITY_TIMEOUT_MS?: string; // Optional: custom timeout for fetch\n\t\t\tIDENTITY_ENDPOINT?: string;\n\t\t}\n\t}\n}\n","import { URLSearchParams } from \"node:url\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\n\n/**\n * The OAuth2 token response returned by Azure AD and Managed Identity endpoints.\n *\n * @property access_token - The access token string\n * @property client_id - The client/application ID (optional, present in MSI)\n * @property expires_in - Seconds until token expiry\n * @property expires_on - Expiry time (epoch seconds, as string)\n * @property ext_expires_in - Extended expiry in seconds\n * @property not_before - Not before time (epoch seconds, as string)\n * @property resource - The resource for which the token is issued\n * @property token_type - The type of token (usually 'Bearer')\n */\nexport type OAuth2TokenResponse = {\n\taccess_token: string;\n\tclient_id?: string;\n\texpires_in: number;\n\texpires_on: string;\n\text_expires_in: number;\n\tnot_before: string;\n\tresource: string;\n\ttoken_type: string;\n};\n\n/**\n * Options for configuring ServicePrincipalCredential.\n *\n * @property clientId - The Azure AD application (client) ID.\n * @property clientSecret - The client secret or JWT assertion (for federated).\n * @property tenantId - The Azure AD tenant ID.\n * @property authorityHost - (Optional) The Azure AD authority host. Defaults to \"https://login.microsoftonline.com\".\n * @property federated - Whether to use federated (JWT) auth. If true, clientSecret is treated as a JWT assertion.\n */\nexport type ServicePrincipalCredentialOption = {\n\tclientId: string;\n\tclientSecret?: string;\n\ttenantId: string;\n\tauthorityHost?: string;\n\tfederated: boolean;\n};\n\n/**\n * AzureCredential implementation for authenticating with a Service Principal (client secret or federated/JWT).\n */\nexport class ServicePrincipalCredential implements AzureCredential {\n\t/**\n\t * @param options Service principal credential options\n\t */\n\tpublic constructor(public options: ServicePrincipalCredentialOption) {}\n\n\t/**\n\t * Gets an Azure access token using the service principal credentials.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If client secret is missing or token request fails\n\t */\n\tpublic async getToken(scope: string) {\n\t\tif (!this.options.clientSecret) throw new Error(\"ServicePrincipalCredential: The client secret is not provided.\");\n\n\t\t// Remove trailing slash from identityAuthorityHost\n\t\tconst url = [this.options.authorityHost?.replace(/\\/$/, \"\") ?? \"https://login.microsoftonline.com\", `${this.options.tenantId}/oauth2/v2.0/token`].join(\"/\");\n\n\t\ttry {\n\t\t\tconst searchParams = {\n\t\t\t\tclient_id: this.options.clientId,\n\t\t\t\tgrant_type: \"client_credentials\",\n\t\t\t\tscope\n\t\t\t};\n\n\t\t\t// If federated, use client_assertion and client_assertion_type\n\t\t\t// Otherwise, use client_secret\n\t\t\tif (this.options.federated) {\n\t\t\t\tObject.assign(searchParams, {\n\t\t\t\t\tclient_assertion: this.options.clientSecret,\n\t\t\t\t\tclient_assertion_type: \"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\"\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tObject.assign(searchParams, {\n\t\t\t\t\tclient_secret: this.options.clientSecret\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst response = await fetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\"\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams(searchParams)\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(`Failed to get token: ${await response.text()}`);\n\t\t\t}\n\n\t\t\tconst data = (await response.json()) as OAuth2TokenResponse;\n\n\t\t\treturn {\n\t\t\t\taccessToken: data.access_token,\n\t\t\t\tclientId: data.client_id ?? this.options.clientId,\n\t\t\t\texpiresAt: new Date(Date.now() + data.expires_in * 1_000),\n\t\t\t\ttokenType: data.token_type\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Failed to get token: ${(error as Error).stack}`);\n\t\t}\n\t}\n\n\t/**\n\t * Instantiates ServicePrincipalCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_CLIENT_ID: The Azure AD application (client) ID\n\t * - AZURE_CLIENT_SECRET: The client secret\n\t * - AZURE_TENANT_ID: The Azure AD tenant ID\n\t * - AZURE_USE_FEDERATED_AUTH: Optional, if set to \"true\", uses federated authentication (JWT assertion).\n\t * @returns ServicePrincipalCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new ServicePrincipalCredential({\n\t\t\tauthorityHost: process.env.AZURE_AUTHORITY_HOST,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\tclientSecret: process.env.AZURE_CLIENT_SECRET,\n\t\t\ttenantId: process.env.AZURE_TENANT_ID,\n\t\t\tfederated: process.env.AZURE_USE_FEDERATED_AUTH === \"true\"\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_CLIENT_ID: string;\n\t\t\tAZURE_CLIENT_SECRET: string;\n\t\t\tAZURE_TENANT_ID: string;\n\t\t\tAZURE_USE_FEDERATED_AUTH: \"true\" | \"false\"; // Optional, defaults to \"false\"\n\t\t}\n\t}\n}\n","import { readFile } from \"node:fs/promises\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\nimport { ServicePrincipalCredential } from \"./ServicePrincipalCredential.js\";\n\n/**\n * Options for configuring WorkloadIdentityCredential.\n *\n * @property clientId - The Azure AD application (client) ID\n * @property federatedTokenFile - Path to the federated token file (OIDC/JWT)\n * @property tenantId - The Azure AD tenant ID\n * @property authorityHost - (Optional) The Azure AD authority host\n */\nexport type WorkloadIdentityCredentialOption = {\n\tclientId: string;\n\tfederatedTokenFile: string;\n\ttenantId: string;\n\tauthorityHost?: string;\n};\n\n/**\n * AzureCredential implementation for Azure Workload Identity (OIDC federated token).\n *\n * Reads a federated token from file and authenticates as a service principal using JWT assertion.\n */\nexport class WorkloadIdentityCredential implements AzureCredential {\n\t/**\n\t * @param options Workload identity credential options\n\t */\n\tpublic constructor(public options: WorkloadIdentityCredentialOption) {}\n\n\t/**\n\t * Gets an Azure access token using the federated token file.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If the federated token file does not exist\n\t */\n\tpublic async getToken(scope: string) {\n\t\ttry {\n\t\t\tconst token = await readFile(this.options.federatedTokenFile, \"utf-8\");\n\t\t\tconst servicePrincipal = new ServicePrincipalCredential({ ...this.options, clientSecret: token, federated: true });\n\n\t\t\treturn servicePrincipal.getToken(scope);\n\t\t} catch (err) {\n\t\t\tif ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\t\tthrow new Error(`WorkloadIdentityCredential: Federated token file not found at ${this.options.federatedTokenFile}`);\n\t\t\t}\n\t\t\tthrow new Error(`WorkloadIdentityCredential: Failed to get token: ${(err as Error).message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Instantiates WorkloadIdentityCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_AUTHORITY_HOST: The Azure AD authority host (optional)\n\t * - AZURE_CLIENT_ID: The Azure AD application (client) ID\n\t * - AZURE_FEDERATED_TOKEN_FILE: Path to the federated token file\n\t * - AZURE_TENANT_ID: The Azure AD tenant ID\n\t * @returns WorkloadIdentityCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new WorkloadIdentityCredential({\n\t\t\tauthorityHost: process.env.AZURE_AUTHORITY_HOST,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\tfederatedTokenFile: process.env.AZURE_FEDERATED_TOKEN_FILE,\n\t\t\ttenantId: process.env.AZURE_TENANT_ID\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_AUTHORITY_HOST: string;\n\t\t\tAZURE_CLIENT_ID: string;\n\t\t\tAZURE_FEDERATED_TOKEN_FILE: string;\n\t\t\tAZURE_TENANT_ID: string;\n\t\t}\n\t}\n}\n","import { AzureCliCredential } from \"./AzureCliCredential.js\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\nimport { ManagedIdentityCredential } from \"./ManagedIdentityCredential.js\";\nimport { ServicePrincipalCredential } from \"./ServicePrincipalCredential.js\";\nimport { WorkloadIdentityCredential } from \"./WorkloadIdentityCredential.js\";\n\nconst credentialChain = [WorkloadIdentityCredential, ManagedIdentityCredential, ServicePrincipalCredential, AzureCliCredential];\n\n/**\n * ChainedCredential tries multiple credential providers in order until one succeeds.\n *\n * The chain is: WorkloadIdentityCredential → ManagedIdentityCredential → ServicePrincipalCredential → AzureCliCredential.\n * Useful for local dev, CI, and cloud environments with minimal config.\n */\nexport class ChainedCredential implements AzureCredential {\n\t/**\n\t * Attempts to get an Azure access token using the first available credential in the chain.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If all credential providers fail\n\t */\n\tpublic async getToken(scope: string) {\n\t\tconst errors: { name: string; error: Error }[] = [];\n\t\tconst debug = process.env.DEBUG?.includes(\"tako-azure-rest:credentials\") || process.env.DEBUG?.includes(\"tako-azure-rest:*\");\n\t\tfor (const Credential of credentialChain) {\n\t\t\tconst label = `[ChainedCredential] ${Credential.name}`;\n\t\t\tlet start: number | undefined;\n\t\t\tif (debug) {\n\t\t\t\tstart = Date.now();\n\t\t\t\tconsole.log(`${label} - trying...`);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await Credential.fromEnv().getToken(scope);\n\t\t\t\tif (debug && start !== undefined) {\n\t\t\t\t\tconst ms = Date.now() - start;\n\t\t\t\t\tconsole.log(`${label} - success in ${ms}ms`);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t} catch (error) {\n\t\t\t\tif (debug && start !== undefined) {\n\t\t\t\t\tconst ms = Date.now() - start;\n\t\t\t\t\tconsole.log(`${label} - failed in ${ms}ms: ${(error as Error).message}`);\n\t\t\t\t}\n\t\t\t\terrors.push({ error: error as Error, name: Credential.name });\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error(`Failed to get token, errors:\\n${errors.map(err => `[${err.name}] ${err.error.message}`).join(\"\\n\")}`);\n\t}\n}\n"],"mappings":"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","names":["process","URLSearchParams"]}
|
|
1
|
+
{"version":3,"sources":["../src/AzureClient.ts","../src/credentials/AzureCliCredential.ts","../src/credentials/AzureCredential.ts","../src/credentials/ManagedIdentityCredential.ts","../src/credentials/ServicePrincipalCredential.ts","../src/credentials/WorkloadIdentityCredential.ts","../src/credentials/ChainedCredential.ts"],"sourcesContent":["import type { AzureCredential, Credential } from \"./credentials/AzureCredential.js\";\n\n/**\n * Options for configuring the AzureClient instance.\n *\n * @property baseUrl - The base URL for Azure REST API endpoints (e.g. https://management.azure.com)\n * @property credential - Credential configuration for authenticating requests\n * @property helper - An AzureCredential implementation for acquiring tokens\n * @property scope - The Azure resource scope for the token (e.g. https://management.azure.com/.default)\n * @property builder - (Optional) Function to build request headers from a token. If not provided, an Authorization header is set by default.\n */\nexport type AzureClientOptions = {\n\tbaseUrl: string;\n\tcredential: {\n\t\thelper: AzureCredential;\n\t\tscope: string;\n\t\tbuilder?: (token: Credential) => Record<string, string>;\n\t};\n};\n\n/**\n * Azure REST API client with credential refresh and HTTP verb helpers.\n */\nexport class AzureClient {\n\tprivate static readonly MAX_TOKEN_RETRIES = 3;\n\tprivate token: Credential | null = null;\n\n\t/**\n\t * @param options Azure client configuration (baseUrl, credential, etc)\n\t */\n\tconstructor(public options: AzureClientOptions) {\n\t\tObject.defineProperty(this, \"token\", { enumerable: false });\n\t}\n\n\t/**\n\t * Sends a GET request to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including headers\n\t * @returns The fetch Response object\n\t */\n\tpublic get(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, { ...options, method: \"GET\" });\n\t}\n\n\t/**\n\t * Sends a POST request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic post(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"POST\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a PUT request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic put(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"PUT\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a PATCH request with a JSON body to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic patch(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, {\n\t\t\t...options,\n\t\t\tmethod: \"PATCH\"\n\t\t});\n\t}\n\n\t/**\n\t * Sends a DELETE request to the Azure REST API.\n\t * @param path The API path\n\t * @param options Fetch options, including body and headers\n\t * @returns The fetch Response object\n\t */\n\tpublic delete(path: string, options?: Exclude<RequestInit, \"method\">) {\n\t\treturn this.request(path, { ...options, method: \"DELETE\" });\n\t}\n\n\t/**\n\t * Sends a request to the Azure REST API, handling token refresh and retries.\n\t * @param path The API path (relative to baseUrl)\n\t * @param options Optional fetch options\n\t * @returns The fetch Response object\n\t * @throws If token refresh fails after max retries\n\t */\n\tpublic async request(path: string, options?: RequestInit): Promise<Response> {\n\t\tlet lastError: unknown;\n\t\tfor (let i = 0; i <= AzureClient.MAX_TOKEN_RETRIES; i++) {\n\t\t\tif (this.token && this.token.expiresAt > new Date()) break;\n\t\t\tif (i === AzureClient.MAX_TOKEN_RETRIES) {\n\t\t\t\tthrow new Error(`Failed to refresh token after ${AzureClient.MAX_TOKEN_RETRIES} attempts: ${(lastError as Error)?.message ?? \"unknown error\"}`);\n\t\t\t}\n\t\t\t// Back off before retrying (skip the wait on the first attempt).\n\t\t\tif (i > 0) await new Promise(res => setTimeout(res, 100 * i));\n\t\t\ttry {\n\t\t\t\tawait this.refreshToken();\n\t\t\t} catch (error) {\n\t\t\t\tlastError = error;\n\t\t\t}\n\t\t}\n\n\t\tif (!this.token) throw new Error(\"Token is unexpectedly null after refresh attempts\");\n\n\t\t// Normalize baseUrl and path to avoid double or missing slashes\n\t\tconst baseUrl = this.options.baseUrl.replace(/\\/+$/, \"\");\n\t\tconst relPath = path.replace(/^\\/+/, \"\");\n\t\tconst url = `${baseUrl}/${relPath}`;\n\n\t\treturn fetch(url, {\n\t\t\t...options,\n\t\t\theaders: {\n\t\t\t\t...(this.options.credential.builder ? this.options.credential.builder(this.token) : { Authorization: `Bearer ${this.token.accessToken}` }),\n\t\t\t\t...options?.headers\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Refreshes the Azure access token using the provided credential helper.\n\t * @private\n\t */\n\tprivate async refreshToken(): Promise<void> {\n\t\tthis.token = await this.options.credential.helper.getToken(this.options.credential.scope);\n\t}\n}\n","import { execFile } from \"node:child_process\";\nimport process from \"node:process\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\n\n/**\n * The raw response returned by Azure CLI when requesting an access token.\n *\n * @property accessToken - The access token string\n * @property expiresOn - Expiry date in RFC3339 format (legacy)\n * @property expires_on - Expiry as seconds since epoch (preferred)\n * @property subscription - (Optional) Subscription ID, may not be present\n * @property tenant - Tenant ID\n * @property tokenType - Token type (usually 'Bearer')\n */\nexport type CLITokenResponse = {\n\taccessToken: string;\n\texpiresOn: string;\n\texpires_on: string;\n\tsubscription?: string;\n\ttenant: string;\n\ttokenType: string;\n};\n\n/**\n * Options for AzureCliCredential.\n *\n * @property tenantId - (Optional) The Azure tenant ID to use for authentication. If not provided, will use the current Azure CLI context.\n */\nexport type AzureCLICredentialOptions = {\n\ttenantId?: string;\n};\n\n/**\n * AzureCliCredential authenticates using the Azure CLI (`az`).\n *\n * - If `tenantId` is provided, uses it for token requests.\n * - If not, will try `AZURE_TENANT_ID` env var, then fall back to the current Azure CLI context.\n *\n * Throws clear errors if the CLI is not installed or not logged in.\n */\nexport class AzureCliCredential implements AzureCredential {\n\tpublic constructor(public options: AzureCLICredentialOptions) {}\n\n\t/**\n\t * Instantiates AzureCliCredential using the AZURE_TENANT_ID environment variable (if set),\n\t * or falls back to the current Azure CLI context.\n\t * @returns AzureCliCredential instance\n\t */\n\tpublic static fromEnv(): AzureCliCredential {\n\t\tconst tenantId = process.env.AZURE_TENANT_ID;\n\t\treturn new AzureCliCredential(tenantId ? { tenantId } : {});\n\t}\n\n\t/**\n\t * Gets an Azure access token using the Azure CLI.\n\t * @param scope The resource scope for the token (e.g. 'https://management.azure.com/.default')\n\t * @returns An object with accessToken, expiresAt, and tokenType\n\t * @throws If CLI is not installed or not logged in\n\t */\n\tpublic async getToken(scope: string): Promise<{ accessToken: string; expiresAt: Date; tokenType: string }> {\n\t\ttry {\n\t\t\tconst tenantId = this.options.tenantId ?? (await AzureCliCredential.getCurrentTenantId());\n\t\t\tconst result = await this.getCliToken(scope, tenantId);\n\t\t\treturn this.parseRawOutput(result.stdout);\n\t\t} catch (error) {\n\t\t\tthrow new Error(`Failed to get token: ${(error as Error).message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Runs the Azure CLI to get an access token for the given scope and tenant.\n\t * @param scope The resource scope\n\t * @param tenantId The Azure tenant ID\n\t * @returns Promise resolving to CLI stdout and stderr\n\t * @private\n\t */\n\tprivate async getCliToken(scope: string, tenantId: string): Promise<{ stderr: string; stdout: string }> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\ttry {\n\t\t\t\texecFile(\n\t\t\t\t\t\"az\",\n\t\t\t\t\t[\"account\", \"get-access-token\", \"--output\", \"json\", \"--resource\", scope.replace(\".default\", \"\"), \"--tenant\", tenantId],\n\t\t\t\t\t{ cwd: process.cwd(), shell: true, timeout: 30_000 },\n\t\t\t\t\t(error, stdout, stderr) => {\n\t\t\t\t\t\tconst { isLoginError, isNotInstallError } = AzureCliCredential.parseCliLoginError(stderr);\n\t\t\t\t\t\tif (isNotInstallError) {\n\t\t\t\t\t\t\treject(new Error(\"Azure CLI not found. Please install\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (isLoginError) {\n\t\t\t\t\t\t\treject(new Error(\"Please login to Azure CLI\"));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\treject(new Error(`Failed to get token: ${error.message}`));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tresolve({ stdout, stderr });\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treject(error as Error);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Gets the current tenant ID from Azure CLI context.\n\t * @returns Promise resolving to the current tenant ID string\n\t * @throws If CLI is not installed or not logged in\n\t */\n\tprivate static async getCurrentTenantId(): Promise<string> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\texecFile(\"az\", [\"account\", \"show\", \"--query\", \"tenantId\", \"--output\", \"tsv\"], { cwd: process.cwd(), shell: true, timeout: 10_000 }, (error, stdout, stderr) => {\n\t\t\t\tconst { isLoginError, isNotInstallError } = AzureCliCredential.parseCliLoginError(stderr);\n\t\t\t\tif (isNotInstallError) {\n\t\t\t\t\treject(new Error(\"Azure CLI not found. Please install\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (isLoginError) {\n\t\t\t\t\treject(new Error(\"Please login to Azure CLI\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (error) {\n\t\t\t\t\treject(new Error(`Failed to detect tenantId from Azure CLI context: ${stderr}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst tenantId = stdout.trim();\n\t\t\t\tif (!tenantId) {\n\t\t\t\t\treject(new Error(\"Could not detect tenantId from Azure CLI context.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tresolve(tenantId);\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Parses the raw CLI output and returns a token + expiry object.\n\t * @param output The stdout from Azure CLI\n\t * @returns An object with accessToken, expiresAt, and tokenType\n\t * @private\n\t */\n\tprivate parseRawOutput(output: string): { accessToken: string; expiresAt: Date; tokenType: string } {\n\t\tconst response = JSON.parse(output) as CLITokenResponse;\n\t\tconst token = response.accessToken;\n\t\tconst expiresOnTimestamp = Number.parseInt(response.expires_on, 10) * 1_000;\n\t\tif (!Number.isNaN(expiresOnTimestamp)) {\n\t\t\treturn {\n\t\t\t\taccessToken: token,\n\t\t\t\texpiresAt: new Date(expiresOnTimestamp),\n\t\t\t\ttokenType: response.tokenType\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\taccessToken: token,\n\t\t\texpiresAt: new Date(response.expiresOn),\n\t\t\ttokenType: response.tokenType\n\t\t};\n\t}\n\n\t/**\n\t * Checks stderr for common Azure CLI login errors.\n\t * @param stderr The stderr string from CLI\n\t * @returns Object with isLoginError and isNotInstallError booleans\n\t * @private\n\t */\n\tprivate static parseCliLoginError(stderr: string): { isLoginError: boolean; isNotInstallError: boolean } {\n\t\tconst specificScope = stderr.match(\"(.*)az login --scope(.*)\");\n\t\tconst isLoginError = stderr.match(\"(.*)az login(.*)\") && !specificScope;\n\t\tconst isNotInstallError = stderr.match(\"az:(.*)not found\") ?? stderr.startsWith(\"'az' is not recognized\");\n\t\treturn {\n\t\t\tisLoginError: Boolean(isLoginError),\n\t\t\tisNotInstallError: Boolean(isNotInstallError)\n\t\t};\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_TENANT_ID: string;\n\t\t}\n\t}\n}\n","/**\n * Represents an Azure access token and its expiration.\n */\nexport type Credential = { accessToken: string; clientId?: string; expiresAt: Date; tokenType: string };\n\n/**\n * Abstract credential class for acquiring Azure tokens.\n * Implement this to provide custom authentication logic.\n */\nexport abstract class AzureCredential {\n\t/**\n\t * Gets an Azure access token for the given scope.\n\t * @param scope The resource or scope for which the token is requested\n\t * @returns A promise resolving to an AzureToken\n\t */\n\tpublic abstract getToken(scope: string): Promise<Credential>;\n}\n","import type { AzureCredential } from \"./AzureCredential.js\";\nimport type { OAuth2TokenResponse } from \"./ServicePrincipalCredential.js\";\n\n/**\n * Options for configuring ManagedIdentityCredential.\n *\n * @property clientId - (Optional) The user-assigned managed identity client ID.\n * @property timeoutMs - (Optional) Timeout in milliseconds for metadata endpoint fetch. Default: 300ms.\n */\nexport type ManagedIdentityCredentialOptions = {\n\tidentityEndpoint?: string; // Optional: custom endpoint, defaults to Azure's default metadata endpoint\n\tclientId?: string;\n\ttimeoutMs?: number; // Optional: custom timeout for fetch\n};\n\n/**\n * AzureCredential implementation for Azure Managed Identity (MSI).\n *\n * Supports both system-assigned and user-assigned managed identities.\n * Works on Azure VM, App Service, Container Apps, etc.\n */\nexport class ManagedIdentityCredential implements AzureCredential {\n\t/**\n\t * @param options Managed identity credential options\n\t */\n\tpublic constructor(public options: ManagedIdentityCredentialOptions = {}) {}\n\n\t/**\n\t * Gets an Azure access token using the managed identity endpoint.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If the endpoint is unavailable or token request fails\n\t */\n\tpublic async getToken(scope: string) {\n\t\tconst endpoint = this.options.identityEndpoint || \"http://169.254.169.254/metadata/identity/oauth2/token\";\n\t\tconst apiVersion = \"2018-02-01\";\n\t\tconst params = new URLSearchParams();\n\t\tparams.set(\"api-version\", apiVersion);\n\t\tparams.set(\"resource\", scope.replace(\".default\", \"\"));\n\t\tif (this.options.clientId) {\n\t\t\tparams.set(\"client_id\", this.options.clientId);\n\t\t}\n\n\t\tconst url = `${endpoint}?${params.toString()}`;\n\t\tconst headers = { Metadata: \"true\" };\n\n\t\t// Add timeout to fetch (default 500ms, can override via options)\n\t\tconst timeoutMs = this.options.timeoutMs ?? 300;\n\t\tconst controller = new AbortController();\n\n\t\t// Manual timeout fallback: Promise.race to guarantee timeout even if fetch/AbortController fails (e.g., network hang)\n\t\tconst timeoutPromise = new Promise<never>((_, reject) => {\n\t\t\tsetTimeout(() => {\n\t\t\t\tcontroller.abort(); // still try to abort fetch\n\t\t\t\treject(new Error(`ManagedIdentityCredential: Timed out after ${timeoutMs}ms waiting for metadata endpoint (${url})`));\n\t\t\t}, timeoutMs);\n\t\t});\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await Promise.race([fetch(url, { headers, signal: controller.signal }), timeoutPromise]);\n\t\t} catch (err: any) {\n\t\t\tif (err.name === \"AbortError\" || /Timed out/.test(err.message)) {\n\t\t\t\tthrow new Error(`ManagedIdentityCredential: Timed out after ${timeoutMs}ms waiting for metadata endpoint (${url})`);\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`ManagedIdentityCredential: Failed to get token: ${await response.text()}`);\n\t\t}\n\n\t\tconst data = (await response.json()) as OAuth2TokenResponse;\n\t\treturn {\n\t\t\taccessToken: data.access_token,\n\t\t\tclientId: data.client_id,\n\t\t\texpiresAt: new Date(data.expires_on ? Number(data.expires_on) * 1000 : Date.now() + 60 * 60 * 1000), // fallback 1h\n\t\t\ttokenType: data.token_type\n\t\t};\n\t}\n\n\t/**\n\t * Instantiates ManagedIdentityCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_CLIENT_ID: The user-assigned managed identity client ID. This is optional for system-assigned identities.\n\t * - AZURE_MANAGED_IDENTITY_ENDPOINT or IDENTITY_ENDPOINT: The managed identity endpoint (optional, defaults to http://169.254.169.254/metadata/identity/oauth2/token)\n\t * - AZURE_MANAGED_IDENTITY_TIMEOUT_MS: Custom timeout for metadata endpoint fetch in milliseconds (optional).\n\t * @returns ManagedIdentityCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new ManagedIdentityCredential({\n\t\t\tidentityEndpoint: process.env.AZURE_MANAGED_IDENTITY_ENDPOINT || process.env.IDENTITY_ENDPOINT,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\ttimeoutMs: process.env.AZURE_MANAGED_IDENTITY_TIMEOUT_MS ? Number.parseInt(process.env.AZURE_MANAGED_IDENTITY_TIMEOUT_MS) : undefined\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_MANAGED_IDENTITY_ENDPOINT?: string;\n\t\t\tAZURE_MANAGED_IDENTITY_TIMEOUT_MS?: string; // Optional: custom timeout for fetch\n\t\t\tIDENTITY_ENDPOINT?: string;\n\t\t}\n\t}\n}\n","import { URLSearchParams } from \"node:url\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\n\n/**\n * The OAuth2 token response returned by Azure AD and Managed Identity endpoints.\n *\n * @property access_token - The access token string\n * @property client_id - The client/application ID (optional, present in MSI)\n * @property expires_in - Seconds until token expiry\n * @property expires_on - Expiry time (epoch seconds, as string)\n * @property ext_expires_in - Extended expiry in seconds\n * @property not_before - Not before time (epoch seconds, as string)\n * @property resource - The resource for which the token is issued\n * @property token_type - The type of token (usually 'Bearer')\n */\nexport type OAuth2TokenResponse = {\n\taccess_token: string;\n\tclient_id?: string;\n\texpires_in: number;\n\texpires_on: string;\n\text_expires_in: number;\n\tnot_before: string;\n\tresource: string;\n\ttoken_type: string;\n};\n\n/**\n * Options for configuring ServicePrincipalCredential.\n *\n * @property clientId - The Azure AD application (client) ID.\n * @property clientSecret - The client secret or JWT assertion (for federated).\n * @property tenantId - The Azure AD tenant ID.\n * @property authorityHost - (Optional) The Azure AD authority host. Defaults to \"https://login.microsoftonline.com\".\n * @property federated - Whether to use federated (JWT) auth. If true, clientSecret is treated as a JWT assertion.\n */\nexport type ServicePrincipalCredentialOption = {\n\tclientId: string;\n\tclientSecret?: string;\n\ttenantId: string;\n\tauthorityHost?: string;\n\tfederated: boolean;\n};\n\n/**\n * AzureCredential implementation for authenticating with a Service Principal (client secret or federated/JWT).\n */\nexport class ServicePrincipalCredential implements AzureCredential {\n\t/**\n\t * @param options Service principal credential options\n\t */\n\tpublic constructor(public options: ServicePrincipalCredentialOption) {}\n\n\t/**\n\t * Gets an Azure access token using the service principal credentials.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If client secret is missing or token request fails\n\t */\n\tpublic async getToken(scope: string) {\n\t\tif (!this.options.clientSecret) throw new Error(\"ServicePrincipalCredential: The client secret is not provided.\");\n\n\t\t// Remove trailing slash from identityAuthorityHost\n\t\tconst url = [this.options.authorityHost?.replace(/\\/$/, \"\") ?? \"https://login.microsoftonline.com\", `${this.options.tenantId}/oauth2/v2.0/token`].join(\"/\");\n\n\t\ttry {\n\t\t\tconst searchParams = {\n\t\t\t\tclient_id: this.options.clientId,\n\t\t\t\tgrant_type: \"client_credentials\",\n\t\t\t\tscope\n\t\t\t};\n\n\t\t\t// If federated, use client_assertion and client_assertion_type\n\t\t\t// Otherwise, use client_secret\n\t\t\tif (this.options.federated) {\n\t\t\t\tObject.assign(searchParams, {\n\t\t\t\t\tclient_assertion: this.options.clientSecret,\n\t\t\t\t\tclient_assertion_type: \"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\"\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tObject.assign(searchParams, {\n\t\t\t\t\tclient_secret: this.options.clientSecret\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst response = await fetch(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\"\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams(searchParams)\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(`Failed to get token: ${await response.text()}`);\n\t\t\t}\n\n\t\t\tconst data = (await response.json()) as OAuth2TokenResponse;\n\n\t\t\treturn {\n\t\t\t\taccessToken: data.access_token,\n\t\t\t\tclientId: data.client_id ?? this.options.clientId,\n\t\t\t\texpiresAt: new Date(Date.now() + data.expires_in * 1_000),\n\t\t\t\ttokenType: data.token_type\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tthrow new Error(`ServicePrincipalCredential: Failed to get token: ${(error as Error).message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Instantiates ServicePrincipalCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_CLIENT_ID: The Azure AD application (client) ID\n\t * - AZURE_CLIENT_SECRET: The client secret\n\t * - AZURE_TENANT_ID: The Azure AD tenant ID\n\t * - AZURE_USE_FEDERATED_AUTH: Optional, if set to \"true\", uses federated authentication (JWT assertion).\n\t * @returns ServicePrincipalCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new ServicePrincipalCredential({\n\t\t\tauthorityHost: process.env.AZURE_AUTHORITY_HOST,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\tclientSecret: process.env.AZURE_CLIENT_SECRET,\n\t\t\ttenantId: process.env.AZURE_TENANT_ID,\n\t\t\tfederated: process.env.AZURE_USE_FEDERATED_AUTH === \"true\"\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_CLIENT_ID: string;\n\t\t\tAZURE_CLIENT_SECRET: string;\n\t\t\tAZURE_TENANT_ID: string;\n\t\t\tAZURE_USE_FEDERATED_AUTH: \"true\" | \"false\"; // Optional, defaults to \"false\"\n\t\t}\n\t}\n}\n","import { readFile } from \"node:fs/promises\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\nimport { ServicePrincipalCredential } from \"./ServicePrincipalCredential.js\";\n\n/**\n * Options for configuring WorkloadIdentityCredential.\n *\n * @property clientId - The Azure AD application (client) ID\n * @property federatedTokenFile - Path to the federated token file (OIDC/JWT)\n * @property tenantId - The Azure AD tenant ID\n * @property authorityHost - (Optional) The Azure AD authority host\n */\nexport type WorkloadIdentityCredentialOption = {\n\tclientId: string;\n\tfederatedTokenFile: string;\n\ttenantId: string;\n\tauthorityHost?: string;\n};\n\n/**\n * AzureCredential implementation for Azure Workload Identity (OIDC federated token).\n *\n * Reads a federated token from file and authenticates as a service principal using JWT assertion.\n */\nexport class WorkloadIdentityCredential implements AzureCredential {\n\t/**\n\t * @param options Workload identity credential options\n\t */\n\tpublic constructor(public options: WorkloadIdentityCredentialOption) {}\n\n\t/**\n\t * Gets an Azure access token using the federated token file.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If the federated token file does not exist\n\t */\n\tpublic async getToken(scope: string) {\n\t\ttry {\n\t\t\tconst token = await readFile(this.options.federatedTokenFile, \"utf-8\");\n\t\t\tconst servicePrincipal = new ServicePrincipalCredential({ ...this.options, clientSecret: token, federated: true });\n\n\t\t\treturn servicePrincipal.getToken(scope);\n\t\t} catch (err) {\n\t\t\tif ((err as NodeJS.ErrnoException).code === \"ENOENT\") {\n\t\t\t\tthrow new Error(`WorkloadIdentityCredential: Federated token file not found at ${this.options.federatedTokenFile}`);\n\t\t\t}\n\t\t\tthrow new Error(`WorkloadIdentityCredential: Failed to get token: ${(err as Error).message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Instantiates WorkloadIdentityCredential using environment variables.\n\t * This expects the following environment variables to be set:\n\t * - AZURE_AUTHORITY_HOST: The Azure AD authority host (optional)\n\t * - AZURE_CLIENT_ID: The Azure AD application (client) ID\n\t * - AZURE_FEDERATED_TOKEN_FILE: Path to the federated token file\n\t * - AZURE_TENANT_ID: The Azure AD tenant ID\n\t * @returns WorkloadIdentityCredential instance\n\t */\n\tpublic static fromEnv() {\n\t\treturn new WorkloadIdentityCredential({\n\t\t\tauthorityHost: process.env.AZURE_AUTHORITY_HOST,\n\t\t\tclientId: process.env.AZURE_CLIENT_ID,\n\t\t\tfederatedTokenFile: process.env.AZURE_FEDERATED_TOKEN_FILE,\n\t\t\ttenantId: process.env.AZURE_TENANT_ID\n\t\t});\n\t}\n}\n\ndeclare global {\n\tnamespace NodeJS {\n\t\tinterface ProcessEnv {\n\t\t\tAZURE_AUTHORITY_HOST: string;\n\t\t\tAZURE_CLIENT_ID: string;\n\t\t\tAZURE_FEDERATED_TOKEN_FILE: string;\n\t\t\tAZURE_TENANT_ID: string;\n\t\t}\n\t}\n}\n","import { AzureCliCredential } from \"./AzureCliCredential.js\";\nimport type { AzureCredential } from \"./AzureCredential.js\";\nimport { ManagedIdentityCredential } from \"./ManagedIdentityCredential.js\";\nimport { ServicePrincipalCredential } from \"./ServicePrincipalCredential.js\";\nimport { WorkloadIdentityCredential } from \"./WorkloadIdentityCredential.js\";\n\nconst credentialChain = [WorkloadIdentityCredential, ManagedIdentityCredential, ServicePrincipalCredential, AzureCliCredential];\n\n/**\n * ChainedCredential tries multiple credential providers in order until one succeeds.\n *\n * The chain is: WorkloadIdentityCredential → ManagedIdentityCredential → ServicePrincipalCredential → AzureCliCredential.\n * Useful for local dev, CI, and cloud environments with minimal config.\n */\nexport class ChainedCredential implements AzureCredential {\n\t/**\n\t * Attempts to get an Azure access token using the first available credential in the chain.\n\t * @param scope The resource scope for the token\n\t * @returns An object with token and expiresAt\n\t * @throws If all credential providers fail\n\t */\n\tpublic async getToken(scope: string) {\n\t\tconst errors: { name: string; error: Error }[] = [];\n\t\tconst debug = process.env.DEBUG?.includes(\"tako-azure-rest:credentials\") || process.env.DEBUG?.includes(\"tako-azure-rest:*\");\n\t\tfor (const Credential of credentialChain) {\n\t\t\tconst label = `[ChainedCredential] ${Credential.name}`;\n\t\t\tlet start: number | undefined;\n\t\t\tif (debug) {\n\t\t\t\tstart = Date.now();\n\t\t\t\tconsole.log(`${label} - trying...`);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await Credential.fromEnv().getToken(scope);\n\t\t\t\tif (debug && start !== undefined) {\n\t\t\t\t\tconst ms = Date.now() - start;\n\t\t\t\t\tconsole.log(`${label} - success in ${ms}ms`);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t} catch (error) {\n\t\t\t\tif (debug && start !== undefined) {\n\t\t\t\t\tconst ms = Date.now() - start;\n\t\t\t\t\tconsole.log(`${label} - failed in ${ms}ms: ${(error as Error).message}`);\n\t\t\t\t}\n\t\t\t\terrors.push({ error: error as Error, name: Credential.name });\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error(`Failed to get token, errors:\\n${errors.map(err => `[${err.name}] ${err.error.message}`).join(\"\\n\")}`);\n\t}\n}\n"],"mappings":";AAuBO,IAAM,cAAN,MAAM,aAAY;AAAA;AAAA;AAAA;AAAA,EAOxB,YAAmB,SAA6B;AAA7B;AAClB,WAAO,eAAe,MAAM,SAAS,EAAE,YAAY,MAAM,CAAC;AAAA,EAC3D;AAAA,EARA,OAAwB,oBAAoB;AAAA,EACpC,QAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAe5B,IAAI,MAAc,SAA0C;AAClE,WAAO,KAAK,QAAQ,MAAM,EAAE,GAAG,SAAS,QAAQ,MAAM,CAAC;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,KAAK,MAAc,SAA0C;AACnE,WAAO,KAAK,QAAQ,MAAM;AAAA,MACzB,GAAG;AAAA,MACH,QAAQ;AAAA,IACT,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,IAAI,MAAc,SAA0C;AAClE,WAAO,KAAK,QAAQ,MAAM;AAAA,MACzB,GAAG;AAAA,MACH,QAAQ;AAAA,IACT,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,MAAM,MAAc,SAA0C;AACpE,WAAO,KAAK,QAAQ,MAAM;AAAA,MACzB,GAAG;AAAA,MACH,QAAQ;AAAA,IACT,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,OAAO,MAAc,SAA0C;AACrE,WAAO,KAAK,QAAQ,MAAM,EAAE,GAAG,SAAS,QAAQ,SAAS,CAAC;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAa,QAAQ,MAAc,SAA0C;AAC5E,QAAI;AACJ,aAAS,IAAI,GAAG,KAAK,aAAY,mBAAmB,KAAK;AACxD,UAAI,KAAK,SAAS,KAAK,MAAM,YAAY,oBAAI,KAAK,EAAG;AACrD,UAAI,MAAM,aAAY,mBAAmB;AACxC,cAAM,IAAI,MAAM,iCAAiC,aAAY,iBAAiB,cAAe,WAAqB,WAAW,eAAe,EAAE;AAAA,MAC/I;AAEA,UAAI,IAAI,EAAG,OAAM,IAAI,QAAQ,SAAO,WAAW,KAAK,MAAM,CAAC,CAAC;AAC5D,UAAI;AACH,cAAM,KAAK,aAAa;AAAA,MACzB,SAAS,OAAO;AACf,oBAAY;AAAA,MACb;AAAA,IACD;AAEA,QAAI,CAAC,KAAK,MAAO,OAAM,IAAI,MAAM,mDAAmD;AAGpF,UAAM,UAAU,KAAK,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;AACvD,UAAM,UAAU,KAAK,QAAQ,QAAQ,EAAE;AACvC,UAAM,MAAM,GAAG,OAAO,IAAI,OAAO;AAEjC,WAAO,MAAM,KAAK;AAAA,MACjB,GAAG;AAAA,MACH,SAAS;AAAA,QACR,GAAI,KAAK,QAAQ,WAAW,UAAU,KAAK,QAAQ,WAAW,QAAQ,KAAK,KAAK,IAAI,EAAE,eAAe,UAAU,KAAK,MAAM,WAAW,GAAG;AAAA,QACxI,GAAG,SAAS;AAAA,MACb;AAAA,IACD,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,eAA8B;AAC3C,SAAK,QAAQ,MAAM,KAAK,QAAQ,WAAW,OAAO,SAAS,KAAK,QAAQ,WAAW,KAAK;AAAA,EACzF;AACD;;;AC3IA,SAAS,gBAAgB;AACzB,OAAOA,cAAa;AAuCb,IAAM,qBAAN,MAAM,oBAA8C;AAAA,EACnD,YAAmB,SAAoC;AAApC;AAAA,EAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/D,OAAc,UAA8B;AAC3C,UAAM,WAAWA,SAAQ,IAAI;AAC7B,WAAO,IAAI,oBAAmB,WAAW,EAAE,SAAS,IAAI,CAAC,CAAC;AAAA,EAC3D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAa,SAAS,OAAqF;AAC1G,QAAI;AACH,YAAM,WAAW,KAAK,QAAQ,YAAa,MAAM,oBAAmB,mBAAmB;AACvF,YAAM,SAAS,MAAM,KAAK,YAAY,OAAO,QAAQ;AACrD,aAAO,KAAK,eAAe,OAAO,MAAM;AAAA,IACzC,SAAS,OAAO;AACf,YAAM,IAAI,MAAM,wBAAyB,MAAgB,OAAO,EAAE;AAAA,IACnE;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,YAAY,OAAe,UAA+D;AACvG,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACvC,UAAI;AACH;AAAA,UACC;AAAA,UACA,CAAC,WAAW,oBAAoB,YAAY,QAAQ,cAAc,MAAM,QAAQ,YAAY,EAAE,GAAG,YAAY,QAAQ;AAAA,UACrH,EAAE,KAAKA,SAAQ,IAAI,GAAG,OAAO,MAAM,SAAS,IAAO;AAAA,UACnD,CAAC,OAAO,QAAQ,WAAW;AAC1B,kBAAM,EAAE,cAAc,kBAAkB,IAAI,oBAAmB,mBAAmB,MAAM;AACxF,gBAAI,mBAAmB;AACtB,qBAAO,IAAI,MAAM,qCAAqC,CAAC;AACvD;AAAA,YACD;AACA,gBAAI,cAAc;AACjB,qBAAO,IAAI,MAAM,2BAA2B,CAAC;AAC7C;AAAA,YACD;AACA,gBAAI,OAAO;AACV,qBAAO,IAAI,MAAM,wBAAwB,MAAM,OAAO,EAAE,CAAC;AACzD;AAAA,YACD;AACA,oBAAQ,EAAE,QAAQ,OAAO,CAAC;AAAA,UAC3B;AAAA,QACD;AAAA,MACD,SAAS,OAAO;AACf,eAAO,KAAc;AAAA,MACtB;AAAA,IACD,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAqB,qBAAsC;AAC1D,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACvC,eAAS,MAAM,CAAC,WAAW,QAAQ,WAAW,YAAY,YAAY,KAAK,GAAG,EAAE,KAAKA,SAAQ,IAAI,GAAG,OAAO,MAAM,SAAS,IAAO,GAAG,CAAC,OAAO,QAAQ,WAAW;AAC9J,cAAM,EAAE,cAAc,kBAAkB,IAAI,oBAAmB,mBAAmB,MAAM;AACxF,YAAI,mBAAmB;AACtB,iBAAO,IAAI,MAAM,qCAAqC,CAAC;AACvD;AAAA,QACD;AACA,YAAI,cAAc;AACjB,iBAAO,IAAI,MAAM,2BAA2B,CAAC;AAC7C;AAAA,QACD;AACA,YAAI,OAAO;AACV,iBAAO,IAAI,MAAM,qDAAqD,MAAM,EAAE,CAAC;AAC/E;AAAA,QACD;AACA,cAAM,WAAW,OAAO,KAAK;AAC7B,YAAI,CAAC,UAAU;AACd,iBAAO,IAAI,MAAM,mDAAmD,CAAC;AACrE;AAAA,QACD;AACA,gBAAQ,QAAQ;AAAA,MACjB,CAAC;AAAA,IACF,CAAC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,eAAe,QAA6E;AACnG,UAAM,WAAW,KAAK,MAAM,MAAM;AAClC,UAAM,QAAQ,SAAS;AACvB,UAAM,qBAAqB,OAAO,SAAS,SAAS,YAAY,EAAE,IAAI;AACtE,QAAI,CAAC,OAAO,MAAM,kBAAkB,GAAG;AACtC,aAAO;AAAA,QACN,aAAa;AAAA,QACb,WAAW,IAAI,KAAK,kBAAkB;AAAA,QACtC,WAAW,SAAS;AAAA,MACrB;AAAA,IACD;AACA,WAAO;AAAA,MACN,aAAa;AAAA,MACb,WAAW,IAAI,KAAK,SAAS,SAAS;AAAA,MACtC,WAAW,SAAS;AAAA,IACrB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAe,mBAAmB,QAAuE;AACxG,UAAM,gBAAgB,OAAO,MAAM,0BAA0B;AAC7D,UAAM,eAAe,OAAO,MAAM,kBAAkB,KAAK,CAAC;AAC1D,UAAM,oBAAoB,OAAO,MAAM,kBAAkB,KAAK,OAAO,WAAW,wBAAwB;AACxG,WAAO;AAAA,MACN,cAAc,QAAQ,YAAY;AAAA,MAClC,mBAAmB,QAAQ,iBAAiB;AAAA,IAC7C;AAAA,EACD;AACD;;;ACvKO,IAAe,kBAAf,MAA+B;AAOtC;;;ACKO,IAAM,4BAAN,MAAM,2BAAqD;AAAA;AAAA;AAAA;AAAA,EAI1D,YAAmB,UAA4C,CAAC,GAAG;AAAhD;AAAA,EAAiD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ3E,MAAa,SAAS,OAAe;AACpC,UAAM,WAAW,KAAK,QAAQ,oBAAoB;AAClD,UAAM,aAAa;AACnB,UAAM,SAAS,IAAI,gBAAgB;AACnC,WAAO,IAAI,eAAe,UAAU;AACpC,WAAO,IAAI,YAAY,MAAM,QAAQ,YAAY,EAAE,CAAC;AACpD,QAAI,KAAK,QAAQ,UAAU;AAC1B,aAAO,IAAI,aAAa,KAAK,QAAQ,QAAQ;AAAA,IAC9C;AAEA,UAAM,MAAM,GAAG,QAAQ,IAAI,OAAO,SAAS,CAAC;AAC5C,UAAM,UAAU,EAAE,UAAU,OAAO;AAGnC,UAAM,YAAY,KAAK,QAAQ,aAAa;AAC5C,UAAM,aAAa,IAAI,gBAAgB;AAGvC,UAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACxD,iBAAW,MAAM;AAChB,mBAAW,MAAM;AACjB,eAAO,IAAI,MAAM,8CAA8C,SAAS,qCAAqC,GAAG,GAAG,CAAC;AAAA,MACrH,GAAG,SAAS;AAAA,IACb,CAAC;AAED,QAAI;AACJ,QAAI;AACH,iBAAW,MAAM,QAAQ,KAAK,CAAC,MAAM,KAAK,EAAE,SAAS,QAAQ,WAAW,OAAO,CAAC,GAAG,cAAc,CAAC;AAAA,IACnG,SAAS,KAAU;AAClB,UAAI,IAAI,SAAS,gBAAgB,YAAY,KAAK,IAAI,OAAO,GAAG;AAC/D,cAAM,IAAI,MAAM,8CAA8C,SAAS,qCAAqC,GAAG,GAAG;AAAA,MACnH;AACA,YAAM;AAAA,IACP;AAEA,QAAI,CAAC,SAAS,IAAI;AACjB,YAAM,IAAI,MAAM,mDAAmD,MAAM,SAAS,KAAK,CAAC,EAAE;AAAA,IAC3F;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,WAAO;AAAA,MACN,aAAa,KAAK;AAAA,MAClB,UAAU,KAAK;AAAA,MACf,WAAW,IAAI,KAAK,KAAK,aAAa,OAAO,KAAK,UAAU,IAAI,MAAO,KAAK,IAAI,IAAI,KAAK,KAAK,GAAI;AAAA;AAAA,MAClG,WAAW,KAAK;AAAA,IACjB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,OAAc,UAAU;AACvB,WAAO,IAAI,2BAA0B;AAAA,MACpC,kBAAkB,QAAQ,IAAI,mCAAmC,QAAQ,IAAI;AAAA,MAC7E,UAAU,QAAQ,IAAI;AAAA,MACtB,WAAW,QAAQ,IAAI,oCAAoC,OAAO,SAAS,QAAQ,IAAI,iCAAiC,IAAI;AAAA,IAC7H,CAAC;AAAA,EACF;AACD;;;AChGA,SAAS,mBAAAC,wBAAuB;AA8CzB,IAAM,6BAAN,MAAM,4BAAsD;AAAA;AAAA;AAAA;AAAA,EAI3D,YAAmB,SAA2C;AAA3C;AAAA,EAA4C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQtE,MAAa,SAAS,OAAe;AACpC,QAAI,CAAC,KAAK,QAAQ,aAAc,OAAM,IAAI,MAAM,gEAAgE;AAGhH,UAAM,MAAM,CAAC,KAAK,QAAQ,eAAe,QAAQ,OAAO,EAAE,KAAK,qCAAqC,GAAG,KAAK,QAAQ,QAAQ,oBAAoB,EAAE,KAAK,GAAG;AAE1J,QAAI;AACH,YAAM,eAAe;AAAA,QACpB,WAAW,KAAK,QAAQ;AAAA,QACxB,YAAY;AAAA,QACZ;AAAA,MACD;AAIA,UAAI,KAAK,QAAQ,WAAW;AAC3B,eAAO,OAAO,cAAc;AAAA,UAC3B,kBAAkB,KAAK,QAAQ;AAAA,UAC/B,uBAAuB;AAAA,QACxB,CAAC;AAAA,MACF,OAAO;AACN,eAAO,OAAO,cAAc;AAAA,UAC3B,eAAe,KAAK,QAAQ;AAAA,QAC7B,CAAC;AAAA,MACF;AACA,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QACjC,QAAQ;AAAA,QACR,SAAS;AAAA,UACR,QAAQ;AAAA,UACR,gBAAgB;AAAA,QACjB;AAAA,QACA,MAAM,IAAIA,iBAAgB,YAAY;AAAA,MACvC,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AACjB,cAAM,IAAI,MAAM,wBAAwB,MAAM,SAAS,KAAK,CAAC,EAAE;AAAA,MAChE;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAElC,aAAO;AAAA,QACN,aAAa,KAAK;AAAA,QAClB,UAAU,KAAK,aAAa,KAAK,QAAQ;AAAA,QACzC,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,aAAa,GAAK;AAAA,QACxD,WAAW,KAAK;AAAA,MACjB;AAAA,IACD,SAAS,OAAO;AACf,YAAM,IAAI,MAAM,oDAAqD,MAAgB,OAAO,EAAE;AAAA,IAC/F;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAc,UAAU;AACvB,WAAO,IAAI,4BAA2B;AAAA,MACrC,eAAe,QAAQ,IAAI;AAAA,MAC3B,UAAU,QAAQ,IAAI;AAAA,MACtB,cAAc,QAAQ,IAAI;AAAA,MAC1B,UAAU,QAAQ,IAAI;AAAA,MACtB,WAAW,QAAQ,IAAI,6BAA6B;AAAA,IACrD,CAAC;AAAA,EACF;AACD;;;AC/HA,SAAS,gBAAgB;AAwBlB,IAAM,6BAAN,MAAM,4BAAsD;AAAA;AAAA;AAAA;AAAA,EAI3D,YAAmB,SAA2C;AAA3C;AAAA,EAA4C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQtE,MAAa,SAAS,OAAe;AACpC,QAAI;AACH,YAAM,QAAQ,MAAM,SAAS,KAAK,QAAQ,oBAAoB,OAAO;AACrE,YAAM,mBAAmB,IAAI,2BAA2B,EAAE,GAAG,KAAK,SAAS,cAAc,OAAO,WAAW,KAAK,CAAC;AAEjH,aAAO,iBAAiB,SAAS,KAAK;AAAA,IACvC,SAAS,KAAK;AACb,UAAK,IAA8B,SAAS,UAAU;AACrD,cAAM,IAAI,MAAM,iEAAiE,KAAK,QAAQ,kBAAkB,EAAE;AAAA,MACnH;AACA,YAAM,IAAI,MAAM,oDAAqD,IAAc,OAAO,EAAE;AAAA,IAC7F;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAc,UAAU;AACvB,WAAO,IAAI,4BAA2B;AAAA,MACrC,eAAe,QAAQ,IAAI;AAAA,MAC3B,UAAU,QAAQ,IAAI;AAAA,MACtB,oBAAoB,QAAQ,IAAI;AAAA,MAChC,UAAU,QAAQ,IAAI;AAAA,IACvB,CAAC;AAAA,EACF;AACD;;;AC7DA,IAAM,kBAAkB,CAAC,4BAA4B,2BAA2B,4BAA4B,kBAAkB;AAQvH,IAAM,oBAAN,MAAmD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOzD,MAAa,SAAS,OAAe;AACpC,UAAM,SAA2C,CAAC;AAClD,UAAM,QAAQ,QAAQ,IAAI,OAAO,SAAS,6BAA6B,KAAK,QAAQ,IAAI,OAAO,SAAS,mBAAmB;AAC3H,eAAW,cAAc,iBAAiB;AACzC,YAAM,QAAQ,uBAAuB,WAAW,IAAI;AACpD,UAAI;AACJ,UAAI,OAAO;AACV,gBAAQ,KAAK,IAAI;AACjB,gBAAQ,IAAI,GAAG,KAAK,cAAc;AAAA,MACnC;AACA,UAAI;AACH,cAAM,SAAS,MAAM,WAAW,QAAQ,EAAE,SAAS,KAAK;AACxD,YAAI,SAAS,UAAU,QAAW;AACjC,gBAAM,KAAK,KAAK,IAAI,IAAI;AACxB,kBAAQ,IAAI,GAAG,KAAK,iBAAiB,EAAE,IAAI;AAAA,QAC5C;AACA,eAAO;AAAA,MACR,SAAS,OAAO;AACf,YAAI,SAAS,UAAU,QAAW;AACjC,gBAAM,KAAK,KAAK,IAAI,IAAI;AACxB,kBAAQ,IAAI,GAAG,KAAK,gBAAgB,EAAE,OAAQ,MAAgB,OAAO,EAAE;AAAA,QACxE;AACA,eAAO,KAAK,EAAE,OAAuB,MAAM,WAAW,KAAK,CAAC;AAAA,MAC7D;AAAA,IACD;AAEA,UAAM,IAAI,MAAM;AAAA,EAAiC,OAAO,IAAI,SAAO,IAAI,IAAI,IAAI,KAAK,IAAI,MAAM,OAAO,EAAE,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,EACtH;AACD;","names":["process","URLSearchParams"]}
|