diff --git a/packages/b2c-cli/bin/dev.cmd b/packages/b2c-cli/bin/dev.cmd index 96feba51..6553fad9 100644 --- a/packages/b2c-cli/bin/dev.cmd +++ b/packages/b2c-cli/bin/dev.cmd @@ -1,3 +1,6 @@ @echo off +@REM Disable telemetry in development mode to avoid polluting production data +if not defined SFCC_DISABLE_TELEMETRY set SFCC_DISABLE_TELEMETRY=true + node --import tsx "%~dp0\dev" %* diff --git a/packages/b2c-cli/bin/dev.js b/packages/b2c-cli/bin/dev.js index e383e090..754d515b 100755 --- a/packages/b2c-cli/bin/dev.js +++ b/packages/b2c-cli/bin/dev.js @@ -5,6 +5,9 @@ * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 */ +// Disable telemetry in development mode to avoid polluting production data +process.env.SFCC_DISABLE_TELEMETRY = process.env.SFCC_DISABLE_TELEMETRY || 'true'; + // Load .env file if present (Node.js native support) try { process.loadEnvFile(); diff --git a/packages/b2c-cli/package.json b/packages/b2c-cli/package.json index 24a94a1a..0e42d7aa 100644 --- a/packages/b2c-cli/package.json +++ b/packages/b2c-cli/package.json @@ -77,6 +77,9 @@ "bin": "b2c", "dirname": "b2c", "commands": "./dist/commands", + "telemetry": { + "connectionString": "InstrumentationKey=6fcc215f-0b11-4864-ad5c-3945ae19e2f3;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/;ApplicationId=a60f17ec-265a-4dfc-b8df-03a64695697d" + }, "plugins": [ "@oclif/plugin-help", "@oclif/plugin-plugins", diff --git a/packages/b2c-cli/test/commands/ecdn/security/get.test.ts b/packages/b2c-cli/test/commands/ecdn/security/get.test.ts index 12f30002..e0fc3e8f 100644 --- a/packages/b2c-cli/test/commands/ecdn/security/get.test.ts +++ b/packages/b2c-cli/test/commands/ecdn/security/get.test.ts @@ -98,7 +98,9 @@ describe('ecdn security get', () => { }), }); - const result = (await runSilent(() => command.run())) as {settings: {securityLevel: string; wafEnabled: boolean}}; + const result = (await runSilent(() => command.run())) as { + settings: {securityLevel: string; wafEnabled: boolean}; + }; expect(result.settings.securityLevel).to.equal('high'); expect(result.settings.wafEnabled).to.be.true; diff --git a/packages/b2c-cli/test/commands/ecdn/zones/list.test.ts b/packages/b2c-cli/test/commands/ecdn/zones/list.test.ts index befc4047..e8a4ad8f 100644 --- a/packages/b2c-cli/test/commands/ecdn/zones/list.test.ts +++ b/packages/b2c-cli/test/commands/ecdn/zones/list.test.ts @@ -129,7 +129,10 @@ describe('ecdn zones list', () => { }), }); - const result = (await runSilent(() => command.run())) as {total: number; zones: Array<{name: string}>}; + const result = (await runSilent(() => command.run())) as { + total: number; + zones: Array<{name: string}>; + }; expect(result).to.have.property('total', 1); expect(result.zones).to.have.lengthOf(1); diff --git a/packages/b2c-dx-mcp/README.md b/packages/b2c-dx-mcp/README.md index 45b1d0be..9b258ccf 100644 --- a/packages/b2c-dx-mcp/README.md +++ b/packages/b2c-dx-mcp/README.md @@ -218,6 +218,43 @@ Storefront Next development tools for building modern storefronts. > **Note:** Some tools appear in multiple toolsets (e.g., `mrt_bundle_push`, `scapi_discovery`). When using multiple toolsets, tools are automatically deduplicated. +## Telemetry + +The MCP server collects anonymous usage telemetry to help improve the developer experience. Telemetry is enabled by default. + +**Development mode**: Telemetry is automatically disabled when using `bin/dev.js`, so local development and testing won't pollute production data. + +### Disabling Telemetry + +Set one of these environment variables to disable telemetry: + +```bash +# Salesforce CLI standard (recommended) +SF_DISABLE_TELEMETRY=true + +# Or SFCC-specific +SFCC_DISABLE_TELEMETRY=true +``` + +You can also override the telemetry connection string for testing: + +```bash +SFCC_APP_INSIGHTS_KEY=your-connection-string +``` + +### What We Collect + +- **Server lifecycle events**: When the server starts, stops, or encounters errors +- **Tool usage**: Which tools are called and their execution time (not the arguments or results) +- **Command metrics**: Command duration and success/failure status +- **Environment info**: Platform, architecture, Node.js version, and package version + +### What We Don't Collect + +- **No credentials**: No API keys, passwords, or secrets +- **No business data**: No product data, customer information, or site content +- **No tool arguments**: No input parameters or output results from tool calls +- **No file contents**: No source code, configuration files, or project data ## Development diff --git a/packages/b2c-dx-mcp/bin/dev.cmd b/packages/b2c-dx-mcp/bin/dev.cmd index 2372b246..534e3dd4 100644 --- a/packages/b2c-dx-mcp/bin/dev.cmd +++ b/packages/b2c-dx-mcp/bin/dev.cmd @@ -1,4 +1,7 @@ @echo off +@REM Disable telemetry in development mode to avoid polluting production data +if not defined SFCC_DISABLE_TELEMETRY set SFCC_DISABLE_TELEMETRY=true + node --conditions development --import tsx "%~dp0\dev" %* diff --git a/packages/b2c-dx-mcp/bin/dev.js b/packages/b2c-dx-mcp/bin/dev.js index e383e090..754d515b 100755 --- a/packages/b2c-dx-mcp/bin/dev.js +++ b/packages/b2c-dx-mcp/bin/dev.js @@ -5,6 +5,9 @@ * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 */ +// Disable telemetry in development mode to avoid polluting production data +process.env.SFCC_DISABLE_TELEMETRY = process.env.SFCC_DISABLE_TELEMETRY || 'true'; + // Load .env file if present (Node.js native support) try { process.loadEnvFile(); diff --git a/packages/b2c-dx-mcp/package.json b/packages/b2c-dx-mcp/package.json index 9ebb2020..afe8d900 100644 --- a/packages/b2c-dx-mcp/package.json +++ b/packages/b2c-dx-mcp/package.json @@ -34,7 +34,10 @@ "strategy": "single", "target": "./dist/commands/mcp.js" }, - "topicSeparator": " " + "topicSeparator": " ", + "telemetry": { + "connectionString": "InstrumentationKey=6fcc215f-0b11-4864-ad5c-3945ae19e2f3;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/;ApplicationId=a60f17ec-265a-4dfc-b8df-03a64695697d" + } }, "files": [ "bin", @@ -99,6 +102,7 @@ "@types/chai": "^4", "@types/mocha": "^10", "@types/node": "^22.16.5", + "@types/sinon": "^21.0.0", "chai": "^4", "eslint": "^9", "eslint-config-oclif": "^6", @@ -109,6 +113,7 @@ "oclif": "^4", "prettier": "^3.6.2", "shx": "^0.3.3", + "sinon": "^21.0.1", "tsx": "^4", "typescript": "^5", "typescript-eslint": "^8" diff --git a/packages/b2c-dx-mcp/src/commands/mcp.ts b/packages/b2c-dx-mcp/src/commands/mcp.ts index 07ee4072..582683bd 100644 --- a/packages/b2c-dx-mcp/src/commands/mcp.ts +++ b/packages/b2c-dx-mcp/src/commands/mcp.ts @@ -20,6 +20,13 @@ * | `--tools` | `SFCC_TOOLS` | Comma-separated individual tools to enable (case-insensitive) | * | `--allow-non-ga-tools` | `SFCC_ALLOW_NON_GA_TOOLS` | Enable experimental/non-GA tools | * + * ### Environment Variables for Telemetry + * | Env Variable | Description | + * |--------------|-------------| + * | `SF_DISABLE_TELEMETRY` | Set to `true` to disable telemetry (sf CLI standard) | + * | `SFCC_DISABLE_TELEMETRY` | Set to `true` to disable telemetry | + * | `SFCC_APP_INSIGHTS_KEY` | Override connection string from package.json | + * * ### MRT Flags (from MrtCommand.baseFlags) * | Flag | Env Variable | Description | * |------|--------------|-------------| @@ -152,6 +159,7 @@ import {TOOLSETS, type StartupFlags} from '../utils/index.js'; * - Global flags for config, logging, and debugging * - Structured pino logging via `this.logger` * - Automatic dw.json loading via `this.resolvedConfig` + * - Automatic telemetry initialization via `this.telemetry` * - `this.config` - package.json metadata and standard config paths */ export default class McpServerCommand extends BaseCommand { @@ -247,9 +255,9 @@ export default class McpServerCommand extends BaseCommand { - // telemetry?.sendEvent(err ? "SERVER_STOPPED_ERROR" : "SERVER_STOPPED_SUCCESS"); - // telemetry?.stop(); - // }); - // } + // Add toolsets to telemetry attributes + if (this.telemetry && startupFlags.toolsets) { + this.telemetry.addAttributes({toolsets: startupFlags.toolsets.join(', ')}); + } - // Create MCP server + // Create MCP server with telemetry from BaseCommand const server = new B2CDxMcpServer( { name: this.config.name, @@ -306,6 +306,7 @@ export default class McpServerCommand extends BaseCommand { + this.telemetry?.sendEvent('SERVER_STOPPED'); + // Don't call stop() here - let finally() handle telemetry cleanup + }); + // Log startup message using the structured logger this.logger.info({version: this.config.version}, 'MCP Server running on stdio'); } diff --git a/packages/b2c-dx-mcp/src/server.ts b/packages/b2c-dx-mcp/src/server.ts index 1503a0dc..4249f44a 100644 --- a/packages/b2c-dx-mcp/src/server.ts +++ b/packages/b2c-dx-mcp/src/server.ts @@ -15,19 +15,27 @@ import type {ServerOptions} from '@modelcontextprotocol/sdk/server/index.js'; import type {RequestHandlerExtra} from '@modelcontextprotocol/sdk/shared/protocol.js'; import type {Transport} from '@modelcontextprotocol/sdk/shared/transport.js'; import type {ZodRawShape} from 'zod'; +import type {Telemetry} from '@salesforce/b2c-tooling-sdk/telemetry'; /** * Extended server options. */ -export type B2CDxMcpServerOptions = ServerOptions; +export interface B2CDxMcpServerOptions extends ServerOptions { + /** + * Telemetry instance for tracking server and tool events. + * If not provided, telemetry is disabled. + */ + telemetry?: Telemetry; +} /** * A server implementation that extends the base MCP server. * - * * @augments {McpServer} */ export class B2CDxMcpServer extends McpServer { + private telemetry?: Telemetry; + /** * Creates a new B2CDxMcpServer instance * @@ -36,15 +44,17 @@ export class B2CDxMcpServer extends McpServer { */ public constructor(serverInfo: Implementation, options?: B2CDxMcpServerOptions) { super(serverInfo, options); + this.telemetry = options?.telemetry; // Set up oninitialized handler this.server.oninitialized = (): void => { const clientInfo = this.server.getClientVersion(); if (clientInfo) { - // TODO: Telemetry - Add client info attributes - // telemetry.addAttributes({ clientName: clientInfo.name, clientVersion: clientInfo.version }); + this.telemetry?.addAttributes({ + clientName: clientInfo.name, + clientVersion: clientInfo.version, + }); } - // TODO: Telemetry - Send SERVER_START_SUCCESS event }; } @@ -68,13 +78,29 @@ export class B2CDxMcpServer extends McpServer { args: Record, _extra: RequestHandlerExtra, ): Promise => { - // TODO: Telemetry - Track timing and send TOOL_CALLED event - // const startTime = Date.now(); - const result = await handler(args); - // const runtimeMs = Date.now() - startTime; - // telemetry.sendEvent('TOOL_CALLED', { name, runtimeMs, isError: result.isError }); + const startTime = Date.now(); + try { + const result = await handler(args); + const runTimeMs = Date.now() - startTime; - return result; + this.telemetry?.sendEvent('TOOL_CALLED', { + toolName: name, + runTimeMs, + isError: result.isError ?? false, + }); + + return result; + } catch (error) { + const runTimeMs = Date.now() - startTime; + + this.telemetry?.sendEvent('TOOL_CALLED', { + toolName: name, + runTimeMs, + isError: true, + }); + + throw error; + } }; // Use the new registerTool API (tool() is deprecated) @@ -85,10 +111,22 @@ export class B2CDxMcpServer extends McpServer { * Connect to a transport. */ public override async connect(transport: Transport): Promise { - await super.connect(transport); - if (!this.isConnected()) { - // TODO: Telemetry - Send SERVER_START_ERROR event with "Server not connected" + try { + await super.connect(transport); + if (this.isConnected()) { + this.telemetry?.sendEvent('SERVER_STATUS', {status: 'started'}); + } else { + this.telemetry?.sendEvent('SERVER_STATUS', { + status: 'error', + errorMessage: 'Server not connected after connect() call', + }); + } + } catch (error) { + this.telemetry?.sendEvent('SERVER_STATUS', { + status: 'error', + errorMessage: error instanceof Error ? error.message : String(error), + }); + throw error; } - // TODO: Telemetry - wrap with try/catch to send SERVER_START_ERROR event with error details } } diff --git a/packages/b2c-dx-mcp/test/commands/mcp.test.ts b/packages/b2c-dx-mcp/test/commands/mcp.test.ts index a273e730..701b8039 100644 --- a/packages/b2c-dx-mcp/test/commands/mcp.test.ts +++ b/packages/b2c-dx-mcp/test/commands/mcp.test.ts @@ -5,7 +5,10 @@ */ import {expect} from 'chai'; +import sinon from 'sinon'; +import {Telemetry} from '@salesforce/b2c-tooling-sdk/telemetry'; import McpServerCommand from '../../src/commands/mcp.js'; +import {B2CDxMcpServer} from '../../src/server.js'; describe('McpServerCommand', () => { describe('static properties', () => { @@ -35,6 +38,13 @@ describe('McpServerCommand', () => { expect(flag.default).to.equal(false); }); + it('should not have a no-telemetry flag (telemetry controlled via env vars only)', () => { + // Telemetry is disabled via SF_DISABLE_TELEMETRY=true or SFCC_DISABLE_TELEMETRY=true + // This keeps the CLI cleaner and prevents accidental disabling + const flags = McpServerCommand.flags as Record; + expect(flags['no-telemetry']).to.be.undefined; + }); + it('should inherit config flag from BaseCommand', () => { // config flag is inherited from BaseCommand.baseFlags const flag = McpServerCommand.baseFlags.config; @@ -89,4 +99,351 @@ describe('McpServerCommand', () => { } }); }); + + describe('telemetry initialization', () => { + let sandbox: sinon.SinonSandbox; + let serverConnectStub: sinon.SinonStub; + let addAttributesStub: sinon.SinonStub; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + + // Stub Telemetry prototype methods - this works because BaseCommand creates + // telemetry instances with `new Telemetry()`, so all instances use these stubs + sandbox.stub(Telemetry.prototype, 'start').resolves(); + sandbox.stub(Telemetry.prototype, 'stop'); + sandbox.stub(Telemetry.prototype, 'sendEvent'); + sandbox.stub(Telemetry.prototype, 'sendException'); + addAttributesStub = sandbox.stub(Telemetry.prototype, 'addAttributes'); + + // Stub server.connect to prevent actual stdio transport + serverConnectStub = sandbox.stub(B2CDxMcpServer.prototype, 'connect').resolves(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it('should pass telemetry to server when telemetry is initialized', async () => { + // Create a real Telemetry instance (will use our stubbed prototype methods) + const telemetryInstance = new Telemetry({ + project: 'test', + appInsightsKey: 'test-key', + }); + + // Create command instance - cast config to avoid oclif type complexity + const command = new McpServerCommand([], { + name: 'test', + version: '1.0.0', + root: process.cwd(), + dataDir: '/tmp/test-data', + } as never); + + // Stub init to set up flags + sandbox.stub(command, 'init').resolves(); + (command as unknown as {flags: Record}).flags = { + 'allow-non-ga-tools': false, + 'log-level': 'silent', + }; + + // Simulate BaseCommand.init() having set up telemetry + (command as unknown as {telemetry: Telemetry}).telemetry = telemetryInstance; + + // Stub resolvedConfig with required methods (cast to bypass protected accessor) + sandbox.stub(command as unknown as Record, 'resolvedConfig').get(() => ({ + values: {}, + hasMrtConfig: () => false, + hasB2CInstanceConfig: () => false, + hasOAuth: () => false, + hasBasicAuth: () => false, + })); + + // Stub logger (cast to bypass protected accessor) + sandbox.stub(command as unknown as Record, 'logger').get(() => ({info: sandbox.stub()})); + + // Run the command + await command.run(); + + // Verify server.connect was called (server started successfully) + expect(serverConnectStub.calledOnce).to.be.true; + }); + + it('should start server without telemetry when telemetry is not configured', async () => { + // Create command instance without telemetry set + const command = new McpServerCommand([], { + name: 'test', + version: '1.0.0', + root: process.cwd(), + dataDir: '/tmp/test-data', + } as never); + + // Stub init to set up flags + sandbox.stub(command, 'init').resolves(); + (command as unknown as {flags: Record}).flags = { + 'allow-non-ga-tools': false, + 'log-level': 'silent', + }; + + // Don't set this.telemetry - simulates when telemetry is disabled + + // Stub resolvedConfig with required methods (cast to bypass protected accessor) + sandbox.stub(command as unknown as Record, 'resolvedConfig').get(() => ({ + values: {}, + hasMrtConfig: () => false, + hasB2CInstanceConfig: () => false, + hasOAuth: () => false, + hasBasicAuth: () => false, + })); + + // Stub logger (cast to bypass protected accessor) + sandbox.stub(command as unknown as Record, 'logger').get(() => ({info: sandbox.stub()})); + + // Run the command + await command.run(); + + // Verify server.connect was called (server started successfully even without telemetry) + expect(serverConnectStub.calledOnce).to.be.true; + }); + + it('should add toolsets to telemetry attributes when toolsets are specified', async () => { + // Create a real Telemetry instance + const telemetryInstance = new Telemetry({ + project: 'test', + appInsightsKey: 'test-key', + }); + + // Create command instance + const command = new McpServerCommand([], { + name: 'test', + version: '1.0.0', + root: process.cwd(), + dataDir: '/tmp/test-data', + } as never); + + // Stub init to set up flags with toolsets + sandbox.stub(command, 'init').resolves(); + (command as unknown as {flags: Record}).flags = { + 'allow-non-ga-tools': false, + 'log-level': 'silent', + toolsets: 'MRT,CARTRIDGES', + }; + + // Simulate BaseCommand.init() having set up telemetry + (command as unknown as {telemetry: Telemetry}).telemetry = telemetryInstance; + + // Stub resolvedConfig + sandbox.stub(command as unknown as Record, 'resolvedConfig').get(() => ({ + values: {}, + hasMrtConfig: () => false, + hasB2CInstanceConfig: () => false, + hasOAuth: () => false, + hasBasicAuth: () => false, + })); + + // Stub logger + sandbox.stub(command as unknown as Record, 'logger').get(() => ({info: sandbox.stub()})); + + // Run the command + await command.run(); + + // Verify addAttributes was called with toolsets + expect(addAttributesStub.called).to.be.true; + const attributesCall = addAttributesStub.firstCall.args[0]; + expect(attributesCall.toolsets).to.equal('MRT, CARTRIDGES'); + }); + }); + + describe('telemetry env var configuration', () => { + describe('Telemetry.isDisabled()', () => { + it('returns false when no disable env vars are set', () => { + const originalSf = process.env.SF_DISABLE_TELEMETRY; + const originalSfcc = process.env.SFCC_DISABLE_TELEMETRY; + try { + delete process.env.SF_DISABLE_TELEMETRY; + delete process.env.SFCC_DISABLE_TELEMETRY; + expect(Telemetry.isDisabled()).to.be.false; + } finally { + if (originalSf !== undefined) process.env.SF_DISABLE_TELEMETRY = originalSf; + if (originalSfcc !== undefined) process.env.SFCC_DISABLE_TELEMETRY = originalSfcc; + } + }); + + it('returns true when SF_DISABLE_TELEMETRY=true', () => { + const original = process.env.SF_DISABLE_TELEMETRY; + try { + process.env.SF_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.isDisabled()).to.be.true; + } finally { + if (original === undefined) { + delete process.env.SF_DISABLE_TELEMETRY; + } else { + process.env.SF_DISABLE_TELEMETRY = original; + } + } + }); + + it('returns true when SFCC_DISABLE_TELEMETRY=true', () => { + const original = process.env.SFCC_DISABLE_TELEMETRY; + try { + process.env.SFCC_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.isDisabled()).to.be.true; + } finally { + if (original === undefined) { + delete process.env.SFCC_DISABLE_TELEMETRY; + } else { + process.env.SFCC_DISABLE_TELEMETRY = original; + } + } + }); + + it('returns false when SF_DISABLE_TELEMETRY=false', () => { + const original = process.env.SF_DISABLE_TELEMETRY; + const originalSfcc = process.env.SFCC_DISABLE_TELEMETRY; + try { + process.env.SF_DISABLE_TELEMETRY = 'false'; + delete process.env.SFCC_DISABLE_TELEMETRY; + expect(Telemetry.isDisabled()).to.be.false; + } finally { + if (original === undefined) { + delete process.env.SF_DISABLE_TELEMETRY; + } else { + process.env.SF_DISABLE_TELEMETRY = original; + } + if (originalSfcc !== undefined) process.env.SFCC_DISABLE_TELEMETRY = originalSfcc; + } + }); + }); + + describe('Telemetry.getConnectionString()', () => { + it('returns undefined when telemetry is disabled', () => { + const originalDisable = process.env.SF_DISABLE_TELEMETRY; + try { + process.env.SF_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.getConnectionString('default-key')).to.be.undefined; + } finally { + if (originalDisable === undefined) { + delete process.env.SF_DISABLE_TELEMETRY; + } else { + process.env.SF_DISABLE_TELEMETRY = originalDisable; + } + } + }); + + it('returns project default when no env override', () => { + const originalDisable = process.env.SFCC_DISABLE_TELEMETRY; + const originalKey = process.env.SFCC_APP_INSIGHTS_KEY; + try { + delete process.env.SFCC_DISABLE_TELEMETRY; + delete process.env.SFCC_APP_INSIGHTS_KEY; + expect(Telemetry.getConnectionString('default-key')).to.equal('default-key'); + } finally { + if (originalDisable !== undefined) process.env.SFCC_DISABLE_TELEMETRY = originalDisable; + if (originalKey !== undefined) process.env.SFCC_APP_INSIGHTS_KEY = originalKey; + } + }); + + it('returns env override when SFCC_APP_INSIGHTS_KEY is set', () => { + const originalDisable = process.env.SFCC_DISABLE_TELEMETRY; + const originalKey = process.env.SFCC_APP_INSIGHTS_KEY; + try { + delete process.env.SFCC_DISABLE_TELEMETRY; + process.env.SFCC_APP_INSIGHTS_KEY = 'env-override-key'; + expect(Telemetry.getConnectionString('default-key')).to.equal('env-override-key'); + } finally { + if (originalDisable !== undefined) process.env.SFCC_DISABLE_TELEMETRY = originalDisable; + if (originalKey === undefined) { + delete process.env.SFCC_APP_INSIGHTS_KEY; + } else { + process.env.SFCC_APP_INSIGHTS_KEY = originalKey; + } + } + }); + + it('returns undefined when no default and no env override', () => { + const originalDisable = process.env.SFCC_DISABLE_TELEMETRY; + const originalKey = process.env.SFCC_APP_INSIGHTS_KEY; + try { + delete process.env.SFCC_DISABLE_TELEMETRY; + delete process.env.SFCC_APP_INSIGHTS_KEY; + expect(Telemetry.getConnectionString()).to.be.undefined; + } finally { + if (originalDisable !== undefined) process.env.SFCC_DISABLE_TELEMETRY = originalDisable; + if (originalKey !== undefined) process.env.SFCC_APP_INSIGHTS_KEY = originalKey; + } + }); + + it('returns env override even without project default', () => { + const originalDisable = process.env.SFCC_DISABLE_TELEMETRY; + const originalKey = process.env.SFCC_APP_INSIGHTS_KEY; + try { + delete process.env.SFCC_DISABLE_TELEMETRY; + process.env.SFCC_APP_INSIGHTS_KEY = 'env-only-key'; + expect(Telemetry.getConnectionString()).to.equal('env-only-key'); + } finally { + if (originalDisable !== undefined) process.env.SFCC_DISABLE_TELEMETRY = originalDisable; + if (originalKey === undefined) { + delete process.env.SFCC_APP_INSIGHTS_KEY; + } else { + process.env.SFCC_APP_INSIGHTS_KEY = originalKey; + } + } + }); + }); + }); + + describe('telemetry lifecycle', () => { + let sandbox: sinon.SinonSandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + it('should create Telemetry instance with correct options', () => { + const telemetry = new Telemetry({ + project: 'b2c-dx-mcp', + appInsightsKey: 'test-key', + version: '1.0.0', + dataDir: '/tmp/test-data', + initialAttributes: {toolsets: 'MRT, CARTRIDGES'}, + }); + + expect(telemetry).to.be.instanceOf(Telemetry); + }); + + it('should support sendEvent for SERVER_STOPPED', () => { + sandbox.stub(Telemetry.prototype, 'start').resolves(); + const sendEventStub = sandbox.stub(Telemetry.prototype, 'sendEvent'); + + const telemetry = new Telemetry({ + project: 'b2c-dx-mcp', + appInsightsKey: 'test-key', + }); + + telemetry.sendEvent('SERVER_STOPPED'); + + expect(sendEventStub.calledWith('SERVER_STOPPED')).to.be.true; + }); + + it('should support sendException for errors', () => { + sandbox.stub(Telemetry.prototype, 'start').resolves(); + const sendExceptionStub = sandbox.stub(Telemetry.prototype, 'sendException'); + + const telemetry = new Telemetry({ + project: 'b2c-dx-mcp', + appInsightsKey: 'test-key', + }); + + const error = new Error('Test error'); + telemetry.sendException(error, {context: 'server shutdown'}); + + expect(sendExceptionStub.calledOnce).to.be.true; + const [sentError, attributes] = sendExceptionStub.firstCall.args as [Error, Record]; + expect(sentError).to.equal(error); + expect(attributes.context).to.equal('server shutdown'); + }); + }); }); diff --git a/packages/b2c-dx-mcp/test/server.test.ts b/packages/b2c-dx-mcp/test/server.test.ts index 4db512a8..d0df9a3f 100644 --- a/packages/b2c-dx-mcp/test/server.test.ts +++ b/packages/b2c-dx-mcp/test/server.test.ts @@ -7,6 +7,33 @@ import {expect} from 'chai'; import {z} from 'zod'; import {B2CDxMcpServer} from '../src/server.js'; +import type {Telemetry} from '@salesforce/b2c-tooling-sdk/telemetry'; + +/** + * Mock telemetry for testing. + */ +class MockTelemetry { + public attributes: Record = {}; + public events: Array<{name: string; attributes: Record}> = []; + public started = false; + public stopped = false; + + addAttributes(attrs: Record): void { + this.attributes = {...this.attributes, ...attrs}; + } + + sendEvent(name: string, attributes: Record = {}): void { + this.events.push({name, attributes}); + } + + async start(): Promise { + this.started = true; + } + + stop(): void { + this.stopped = true; + } +} // Handlers extracted to module scope to reduce callback nesting depth const simpleHandler = async () => ({content: [{type: 'text' as const, text: 'ok'}]}); @@ -16,6 +43,23 @@ const paramHandler = async (args: Record) => ({ content: [{type: 'text' as const, text: `Hello ${args.name}`}], }); +// Telemetry test handlers +const successHandler = async () => ({content: [{type: 'text' as const, text: 'success'}]}); +const errorResultHandler = async () => ({ + content: [{type: 'text' as const, text: 'error occurred'}], + isError: true, +}); +const throwingHandler = async (): Promise<{content: Array<{type: 'text'; text: string}>}> => { + throw new Error('Tool execution failed'); +}; +const delayMs = 50; +const slowHandler = async () => { + await new Promise((resolve) => { + setTimeout(resolve, delayMs); + }); + return {content: [{type: 'text' as const, text: 'done'}]}; +}; + describe('B2CDxMcpServer', () => { describe('constructor', () => { it('should create server with name and version', () => { @@ -79,4 +123,171 @@ describe('B2CDxMcpServer', () => { expect(server.isConnected()).to.be.false; }); }); + + describe('telemetry integration', () => { + it('should accept telemetry in options', () => { + const mockTelemetry = new MockTelemetry(); + + const server = new B2CDxMcpServer( + {name: 'test-server', version: '1.0.0'}, + {telemetry: mockTelemetry as unknown as Telemetry}, + ); + + expect(server).to.be.instanceOf(B2CDxMcpServer); + }); + + it('should work without telemetry (telemetry disabled)', () => { + // When telemetry is undefined, server should still work + const server = new B2CDxMcpServer({name: 'test-server', version: '1.0.0'}, {telemetry: undefined}); + + expect(server).to.be.instanceOf(B2CDxMcpServer); + }); + + it('should call telemetry.start() before passing to server (simulated lifecycle)', async () => { + // This test verifies the expected telemetry lifecycle: + // 1. Create telemetry instance + // 2. Call telemetry.start() to initialize the reporter + // 3. Pass started telemetry to server + const mockTelemetry = new MockTelemetry(); + + // Verify telemetry is not started initially + expect(mockTelemetry.started).to.be.false; + + // Simulate what mcp.ts does: start telemetry before creating server + await mockTelemetry.start(); + expect(mockTelemetry.started).to.be.true; + + // Now pass to server (as mcp.ts does) + const server = new B2CDxMcpServer( + {name: 'test-server', version: '1.0.0'}, + {telemetry: mockTelemetry as unknown as Telemetry}, + ); + + expect(server).to.be.instanceOf(B2CDxMcpServer); + expect(mockTelemetry.started).to.be.true; + }); + + it('should create server without options (no telemetry)', () => { + const server = new B2CDxMcpServer({name: 'test-server', version: '1.0.0'}); + + expect(server).to.be.instanceOf(B2CDxMcpServer); + }); + }); + + describe('TOOL_CALLED telemetry', () => { + let mockTelemetry: MockTelemetry; + let capturedHandler: ((args: Record, extra: unknown) => Promise) | null; + + beforeEach(() => { + mockTelemetry = new MockTelemetry(); + capturedHandler = null; + }); + + /** + * Creates a server that captures the wrapped handler for testing. + * This allows us to test the telemetry wrapper logic without going through + * the full MCP protocol. + */ + function createServerWithHandlerCapture(): B2CDxMcpServer { + const server = new B2CDxMcpServer( + {name: 'test-server', version: '1.0.0'}, + {telemetry: mockTelemetry as unknown as Telemetry}, + ); + + // Override registerTool to capture the wrapped handler + const originalRegisterTool = server.registerTool.bind(server); + server.registerTool = (name, config, handler) => { + capturedHandler = handler as (args: Record, extra: unknown) => Promise; + return originalRegisterTool(name, config, handler); + }; + + return server; + } + + it('should send TOOL_CALLED event on successful tool execution', async () => { + const server = createServerWithHandlerCapture(); + + server.addTool('test_tool', 'Test tool', {}, successHandler); + + // Call the captured wrapped handler + expect(capturedHandler).to.not.be.null; + await capturedHandler!({}, {}); + + // Verify telemetry event + expect(mockTelemetry.events).to.have.lengthOf(1); + expect(mockTelemetry.events[0].name).to.equal('TOOL_CALLED'); + expect(mockTelemetry.events[0].attributes.toolName).to.equal('test_tool'); + expect(mockTelemetry.events[0].attributes.isError).to.equal(false); + expect(mockTelemetry.events[0].attributes.runTimeMs).to.be.a('number'); + }); + + it('should send TOOL_CALLED event with isError=true when tool returns error', async () => { + const server = createServerWithHandlerCapture(); + + server.addTool('error_tool', 'Error tool', {}, errorResultHandler); + + await capturedHandler!({}, {}); + + expect(mockTelemetry.events).to.have.lengthOf(1); + expect(mockTelemetry.events[0].name).to.equal('TOOL_CALLED'); + expect(mockTelemetry.events[0].attributes.toolName).to.equal('error_tool'); + expect(mockTelemetry.events[0].attributes.isError).to.equal(true); + }); + + it('should send TOOL_CALLED event with isError=true when tool throws', async () => { + const server = createServerWithHandlerCapture(); + + server.addTool('throwing_tool', 'Throwing tool', {}, throwingHandler); + + try { + await capturedHandler!({}, {}); + expect.fail('Should have thrown'); + } catch { + // Expected + } + + expect(mockTelemetry.events).to.have.lengthOf(1); + expect(mockTelemetry.events[0].name).to.equal('TOOL_CALLED'); + expect(mockTelemetry.events[0].attributes.toolName).to.equal('throwing_tool'); + expect(mockTelemetry.events[0].attributes.isError).to.equal(true); + }); + + it('should measure runTimeMs accurately', async () => { + const server = createServerWithHandlerCapture(); + + server.addTool('slow_tool', 'Slow tool', {}, slowHandler); + + await capturedHandler!({}, {}); + + const runTimeMs = mockTelemetry.events[0].attributes.runTimeMs as number; + // Allow some tolerance for timing + expect(runTimeMs).to.be.at.least(delayMs - 10); + expect(runTimeMs).to.be.at.most(delayMs + 50); + }); + + it('should not send events when telemetry is disabled', async () => { + // Create server without telemetry + const server = new B2CDxMcpServer({name: 'test-server', version: '1.0.0'}); + + let handlerCalled = false; + const handler = async () => { + handlerCalled = true; + return {content: [{type: 'text' as const, text: 'ok'}]}; + }; + + // Override registerTool to capture handler + let noTelemetryHandler: ((args: Record, extra: unknown) => Promise) | null = null; + const originalRegisterTool = server.registerTool.bind(server); + server.registerTool = (name, config, h) => { + noTelemetryHandler = h as (args: Record, extra: unknown) => Promise; + return originalRegisterTool(name, config, h); + }; + + server.addTool('no_telemetry_tool', 'No telemetry', {}, handler); + + // Should not throw even without telemetry + await noTelemetryHandler!({}, {}); + expect(handlerCalled).to.be.true; + }); + }); }); diff --git a/packages/b2c-tooling-sdk/package.json b/packages/b2c-tooling-sdk/package.json index ce728b56..84f6ccb4 100644 --- a/packages/b2c-tooling-sdk/package.json +++ b/packages/b2c-tooling-sdk/package.json @@ -210,6 +210,17 @@ "types": "./dist/cjs/test-utils/index.d.ts", "default": "./dist/cjs/test-utils/index.js" } + }, + "./telemetry": { + "development": "./src/telemetry/index.ts", + "import": { + "types": "./dist/esm/telemetry/index.d.ts", + "default": "./dist/esm/telemetry/index.js" + }, + "require": { + "types": "./dist/cjs/telemetry/index.d.ts", + "default": "./dist/cjs/telemetry/index.js" + } } }, "main": "./dist/cjs/index.js", @@ -281,6 +292,7 @@ "node": ">=22.16.0" }, "dependencies": { + "@salesforce/telemetry": "^6.1.0", "archiver": "^7.0.1", "chokidar": "^5.0.0", "cliui": "^9.0.1", diff --git a/packages/b2c-tooling-sdk/src/cli/base-command.ts b/packages/b2c-tooling-sdk/src/cli/base-command.ts index f7d83d2d..20a3ee63 100644 --- a/packages/b2c-tooling-sdk/src/cli/base-command.ts +++ b/packages/b2c-tooling-sdk/src/cli/base-command.ts @@ -22,12 +22,20 @@ import type {ConfigSource} from '../config/types.js'; import {globalMiddlewareRegistry} from '../clients/middleware-registry.js'; import {globalAuthMiddlewareRegistry} from '../auth/middleware.js'; import {setUserAgent} from '../clients/user-agent.js'; +import {createTelemetry, Telemetry, type TelemetryAttributes} from '../telemetry/index.js'; export type Flags = Interfaces.InferredFlags<(typeof BaseCommand)['baseFlags'] & T['flags']>; export type Args = Interfaces.InferredArgs; const LOG_LEVELS = ['trace', 'debug', 'info', 'warn', 'error', 'silent'] as const; +/** + * Type for oclif pjson custom telemetry config. + */ +interface TelemetryConfig { + connectionString?: string; +} + /** * Base command class for B2C CLI tools. * @@ -36,6 +44,11 @@ const LOG_LEVELS = ['trace', 'debug', 'info', 'warn', 'error', 'silent'] as cons * - SFCC_LOG_COLORIZE: Force colors on/off (default: auto-detect TTY) * - SFCC_REDACT_SECRETS: Set to 'false' to disable secret redaction * - NO_COLOR: Industry standard to disable colors + * + * Environment variables for telemetry: + * - SF_DISABLE_TELEMETRY: Set to 'true' to disable telemetry (sf CLI standard) + * - SFCC_DISABLE_TELEMETRY: Set to 'true' to disable telemetry + * - SFCC_APP_INSIGHTS_KEY: Override connection string from package.json */ export abstract class BaseCommand extends Command { static baseFlags = { @@ -103,11 +116,17 @@ export abstract class BaseCommand extends Command { protected resolvedConfig!: ResolvedB2CConfig; protected logger!: Logger; + /** Telemetry instance for tracking command events */ + protected telemetry?: Telemetry; + /** High-priority config sources from plugins (inserted before defaults) */ protected pluginSourcesBefore: ConfigSource[] = []; /** Low-priority config sources from plugins (inserted after defaults) */ protected pluginSourcesAfter: ConfigSource[] = []; + /** Start time for command duration tracking */ + private commandStartTime?: number; + public async init(): Promise { await super.init(); @@ -144,9 +163,71 @@ export abstract class BaseCommand extends Command { // Collect config sources from plugins before loading configuration await this.collectPluginConfigSources(); + // Auto-initialize telemetry from oclif pjson config + await this.initTelemetryFromConfig(); + this.resolvedConfig = this.loadConfiguration(); } + /** + * Auto-initialize telemetry from package.json oclif.telemetry config. + * Called during init() to enable automatic telemetry for all commands. + */ + private async initTelemetryFromConfig(): Promise { + const pjsonTelemetry = (this.config.pjson.oclif as {telemetry?: TelemetryConfig} | undefined)?.telemetry; + const connectionString = Telemetry.getConnectionString(pjsonTelemetry?.connectionString); + + if (!connectionString) return; + + this.telemetry = createTelemetry({ + project: this.config.name, + appInsightsKey: connectionString, + version: this.config.version, + dataDir: this.config.dataDir, + initialAttributes: {command: this.id}, + }); + await this.telemetry.start(); + + // Track command start + this.commandStartTime = Date.now(); + this.telemetry.sendEvent('COMMAND_START', {command: this.id}); + } + + /** + * Manual telemetry initialization for non-pjson usage (e.g., MCP server with additional attributes). + * Use this when you need to pass custom initial attributes or use a different connection string. + * + * @param options - Telemetry options + * @returns The telemetry instance, or undefined if telemetry is disabled + */ + protected async initTelemetry(options: { + appInsightsKey?: string; + initialAttributes?: TelemetryAttributes; + }): Promise { + // If telemetry was already initialized by initTelemetryFromConfig, stop it first + if (this.telemetry) { + this.telemetry.stop(); + } + + const connectionString = Telemetry.getConnectionString(options.appInsightsKey); + if (!connectionString) return undefined; + + this.telemetry = createTelemetry({ + project: this.config.name, + appInsightsKey: connectionString, + version: this.config.version, + dataDir: this.config.dataDir, + initialAttributes: {command: this.id, ...options.initialAttributes}, + }); + await this.telemetry.start(); + + // Track command start + this.commandStartTime = Date.now(); + this.telemetry.sendEvent('COMMAND_START', {command: this.id}); + + return this.telemetry; + } + /** * Determine colorize setting based on env vars and TTY. * Priority: NO_COLOR > SFCC_LOG_COLORIZE > TTY detection @@ -385,9 +466,15 @@ export abstract class BaseCommand extends Command { * * Logs the error using the structured logger (including cause if available). * In JSON mode, outputs a JSON error object to stdout instead of oclif's default format. + * Sends exception to telemetry if initialized. */ protected async catch(err: Error & {exitCode?: number}): Promise { const exitCode = err.exitCode ?? 1; + const duration = this.commandStartTime ? Date.now() - this.commandStartTime : undefined; + + // Send exception to telemetry if initialized + this.telemetry?.sendException(err, {command: this.id, exitCode, duration}); + this.telemetry?.stop(); // Log if logger is available (may not be if error during init) if (this.logger) { @@ -411,6 +498,20 @@ export abstract class BaseCommand extends Command { this.error(err.message, {exit: exitCode}); } + /** + * Called after run() completes (whether successfully or via catch()). + * Tracks COMMAND_SUCCESS and stops telemetry. + */ + protected async finally(err: Error | undefined): Promise { + // Only track success if no error occurred + if (!err && this.telemetry) { + const duration = this.commandStartTime ? Date.now() - this.commandStartTime : undefined; + this.telemetry.sendEvent('COMMAND_SUCCESS', {command: this.id, duration}); + this.telemetry.stop(); + } + await super.finally(err); + } + public baseCommandTest(): void { this.logger.info('BaseCommand initialized'); } diff --git a/packages/b2c-tooling-sdk/src/telemetry/index.ts b/packages/b2c-tooling-sdk/src/telemetry/index.ts new file mode 100644 index 00000000..91897d3d --- /dev/null +++ b/packages/b2c-tooling-sdk/src/telemetry/index.ts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ + +export type {TelemetryAttributes, TelemetryEventProperties, TelemetryOptions} from './types.js'; +export {Telemetry} from './telemetry.js'; + +import {Telemetry} from './telemetry.js'; +import type {TelemetryOptions} from './types.js'; + +/** + * Factory function to create a Telemetry instance. + * + * @param options - Telemetry configuration options + * @returns A new Telemetry instance + * + * @example + * ```typescript + * import { createTelemetry } from '@salesforce/b2c-tooling-sdk/telemetry'; + * + * const telemetry = createTelemetry({ + * project: 'my-mcp-server', + * appInsightsKey: process.env.APP_INSIGHTS_KEY, + * version: '1.0.0', + * initialAttributes: { environment: 'production' }, + * }); + * + * await telemetry.start(); + * telemetry.sendEvent('SERVER_STATUS', { status: 'started' }); + * ``` + */ +export function createTelemetry(options: TelemetryOptions): Telemetry { + return new Telemetry(options); +} diff --git a/packages/b2c-tooling-sdk/src/telemetry/telemetry.ts b/packages/b2c-tooling-sdk/src/telemetry/telemetry.ts new file mode 100644 index 00000000..dba2f5ff --- /dev/null +++ b/packages/b2c-tooling-sdk/src/telemetry/telemetry.ts @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ + +import {randomBytes} from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; +import {TelemetryReporter} from '@salesforce/telemetry'; +import type {TelemetryAttributes, TelemetryEventProperties, TelemetryOptions} from './types.js'; + +const generateRandomId = (): string => randomBytes(20).toString('hex'); + +/** + * Get the path to the persistent CLI ID file. + * @param dataDir - oclif dataDir for persistent storage + */ +const getCliIdPath = (dataDir?: string): string | null => { + if (!dataDir) return null; + return path.join(dataDir, 'cliid'); +}; + +/** + * Read or create a persistent CLI ID. + * @param dataDir - oclif dataDir for persistent storage + */ +const readOrCreateCliId = (dataDir?: string): string => { + const filePath = getCliIdPath(dataDir); + if (!filePath) return generateRandomId(); + + // Try to read existing ID + try { + if (fs.existsSync(filePath)) { + const value = fs.readFileSync(filePath, 'utf8'); + const trimmed = value?.trim(); + if (trimmed) return trimmed; + } + } catch { + // Fall through to create new + } + + // Create new ID + const newId = generateRandomId(); + try { + const dir = path.dirname(filePath); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, {recursive: true, mode: 0o700}); + } + fs.writeFileSync(filePath, newId, {encoding: 'utf8', mode: 0o600}); + } catch { + // If we can't persist, still return the generated id + } + return newId; +}; + +/** + * Custom TelemetryReporter that always enables telemetry. + * Gating is handled at the instantiation site. + */ +class ConfigurableTelemetryReporter extends TelemetryReporter { + override isSfdxTelemetryEnabled(): boolean { + return true; + } +} + +/** + * Telemetry client for sending events to Application Insights. + * + * @example + * ```typescript + * const telemetry = new Telemetry({ + * project: 'my-app', + * appInsightsKey: 'InstrumentationKey=...', + * version: '1.0.0', + * dataDir: '/path/to/data', + * }); + * + * await telemetry.start(); + * telemetry.sendEvent('USER_ACTION', { action: 'click' }); + * telemetry.stop(); + * ``` + */ +export class Telemetry { + private attributes: TelemetryAttributes; + private cliId: string; + private project: string; + private reporter: TelemetryReporter | undefined; + private sessionId: string; + private started: boolean; + private version: string; + private appInsightsKey: string | undefined; + + /** + * Check if telemetry is disabled via environment variables. + * Supports both SF_DISABLE_TELEMETRY (sf CLI standard) and SFCC_DISABLE_TELEMETRY. + */ + static isDisabled(): boolean { + return process.env.SF_DISABLE_TELEMETRY === 'true' || process.env.SFCC_DISABLE_TELEMETRY === 'true'; + } + + /** + * Get the connection string for telemetry, respecting disable flags and env overrides. + * @param projectDefault - Default connection string from project config (e.g., package.json) + * @returns Connection string to use, or undefined if telemetry should be disabled + */ + static getConnectionString(projectDefault?: string): string | undefined { + if (Telemetry.isDisabled()) return undefined; + return process.env.SFCC_APP_INSIGHTS_KEY ?? projectDefault; + } + + constructor(options: TelemetryOptions) { + this.project = options.project; + this.appInsightsKey = options.appInsightsKey; + this.attributes = {...(options.initialAttributes ?? {})}; + this.cliId = readOrCreateCliId(options.dataDir); + this.reporter = undefined; + this.sessionId = generateRandomId(); + this.started = false; + this.version = options.version ?? '0.0.0'; + } + + /** + * Add additional attributes to include with all future events. + */ + addAttributes(attributes: TelemetryAttributes): void { + this.attributes = {...this.attributes, ...attributes}; + } + + /** + * Send a telemetry event. + * + * @param eventName - Name of the event (e.g., 'SERVER_STATUS', 'TOOL_CALLED') + * @param attributes - Event-specific attributes + */ + sendEvent(eventName: string, attributes: TelemetryAttributes = {}): void { + try { + const eventProperties = this.buildEventProperties(attributes); + this.reporter?.sendTelemetryEvent(eventName, eventProperties); + } catch { + // ignore send errors + } + } + + /** + * Send an exception to telemetry. + * + * @param error - The error to report + * @param attributes - Additional attributes to include with the exception + */ + sendException(error: Error, attributes: TelemetryAttributes = {}): void { + try { + const properties = this.buildEventProperties(attributes); + this.reporter?.sendTelemetryException(error, properties); + } catch { + // ignore send errors + } + } + + /** + * Start the telemetry reporter. + * Must be called before sending events. + */ + async start(): Promise { + if (this.started) return; + this.started = true; + + // If no key provided, telemetry is disabled + if (!this.appInsightsKey) return; + + try { + await this.createReporter(); + } catch { + // Best-effort retry after ~1s: first runs can hit transient failures + // establishing the Application Insights connection (DNS/proxy/VPN warm-up, + // brief network blips, or backend cold start). One short delay usually fixes it. + // If the retry still fails, ignore it to avoid impacting the application. + try { + await this.createReporter(); + } catch { + // ignore + } + } + } + + /** + * Stop the telemetry reporter and flush any pending events. + */ + stop(): void { + if (!this.started) return; + this.started = false; + this.reporter?.stop(); + } + + private buildEventProperties(attributes: TelemetryAttributes = {}): TelemetryEventProperties { + return { + ...this.attributes, + ...attributes, + sessionId: this.sessionId, + cliId: this.cliId, + version: this.version, + platform: process.platform, + arch: process.arch, + nodeVersion: process.version, + nodeEnv: process.env.NODE_ENV, + origin: this.project, + date: new Date().toUTCString(), + timestamp: String(Date.now()), + processUptime: process.uptime() * 1000, + }; + } + + private async createReporter(): Promise { + this.reporter = await ConfigurableTelemetryReporter.create({ + project: this.project, + key: this.appInsightsKey ?? '', + userId: this.cliId, + waitForConnection: true, + }); + this.reporter.start(); + } +} diff --git a/packages/b2c-tooling-sdk/src/telemetry/types.ts b/packages/b2c-tooling-sdk/src/telemetry/types.ts new file mode 100644 index 00000000..de724b1f --- /dev/null +++ b/packages/b2c-tooling-sdk/src/telemetry/types.ts @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ + +/** + * Telemetry event attributes - key-value pairs sent with each event. + */ +export interface TelemetryAttributes { + [key: string]: boolean | number | string | undefined; +} + +/** + * Core properties automatically included with every telemetry event. + */ +export interface TelemetryEventProperties extends TelemetryAttributes { + /** Unique session identifier (generated per Telemetry instance) */ + sessionId: string; + /** Persistent CLI identifier (stored in {dataDir}/cliid) */ + cliId: string; + /** Package version */ + version: string; + /** Operating system platform (e.g., 'darwin', 'linux', 'win32') */ + platform: string; + /** CPU architecture (e.g., 'x64', 'arm64') */ + arch: string; + /** Node.js version */ + nodeVersion: string; + /** NODE_ENV environment variable value */ + nodeEnv: string | undefined; + /** Project name / origin of the event */ + origin: string; + /** Human-readable UTC date string */ + date: string; + /** Unix timestamp in milliseconds */ + timestamp: string; + /** Process uptime in milliseconds */ + processUptime: number; +} + +/** + * Options for creating a Telemetry instance. + */ +export interface TelemetryOptions { + /** + * Project identifier used for telemetry reporting. + * This is used as the project name in Application Insights. + */ + project: string; + + /** + * Application Insights connection string or instrumentation key. + * If not provided, telemetry will be disabled. + */ + appInsightsKey?: string; + + /** + * Initial attributes to include with every telemetry event. + */ + initialAttributes?: TelemetryAttributes; + + /** + * Package version to include in telemetry events. + */ + version?: string; + + /** + * oclif dataDir for persistent CLI ID storage. + * If provided, CLI ID is stored in {dataDir}/cliid. + * If not provided or non-writable, falls back to random ID. + */ + dataDir?: string; +} diff --git a/packages/b2c-tooling-sdk/test/cli/base-command.test.ts b/packages/b2c-tooling-sdk/test/cli/base-command.test.ts index c3476729..34211ef4 100644 --- a/packages/b2c-tooling-sdk/test/cli/base-command.test.ts +++ b/packages/b2c-tooling-sdk/test/cli/base-command.test.ts @@ -8,6 +8,7 @@ import sinon from 'sinon'; import {Config} from '@oclif/core'; import {BaseCommand} from '@salesforce/b2c-tooling-sdk/cli'; import {globalMiddlewareRegistry} from '@salesforce/b2c-tooling-sdk/clients'; +import {Telemetry} from '@salesforce/b2c-tooling-sdk/telemetry'; import {isolateConfig, restoreConfig} from '@salesforce/b2c-tooling-sdk/test-utils'; import {stubParse} from '../helpers/stub-parse.js'; @@ -28,6 +29,14 @@ class TestBaseCommand extends BaseCommand { public testCatch(err: Error & {exitCode?: number}) { return this.catch(err); } + + public testFinally(err: Error | undefined) { + return this.finally(err); + } + + public getTelemetry() { + return this.telemetry; + } } describe('cli/base-command', () => { @@ -204,4 +213,283 @@ describe('cli/base-command', () => { // Cleanup handled by sinon.restore() in afterEach }); }); + + describe('telemetry', () => { + let telemetryStartStub: sinon.SinonStub; + let telemetryStopStub: sinon.SinonStub; + let telemetrySendEventStub: sinon.SinonStub; + let telemetrySendExceptionStub: sinon.SinonStub; + + beforeEach(() => { + // Stub Telemetry prototype methods + telemetryStartStub = sinon.stub(Telemetry.prototype, 'start').resolves(); + telemetryStopStub = sinon.stub(Telemetry.prototype, 'stop'); + telemetrySendEventStub = sinon.stub(Telemetry.prototype, 'sendEvent'); + telemetrySendExceptionStub = sinon.stub(Telemetry.prototype, 'sendException'); + }); + + describe('Telemetry.isDisabled()', () => { + let originalSfDisable: string | undefined; + let originalSfccDisable: string | undefined; + + beforeEach(() => { + originalSfDisable = process.env.SF_DISABLE_TELEMETRY; + originalSfccDisable = process.env.SFCC_DISABLE_TELEMETRY; + delete process.env.SF_DISABLE_TELEMETRY; + delete process.env.SFCC_DISABLE_TELEMETRY; + }); + + afterEach(() => { + if (originalSfDisable !== undefined) { + process.env.SF_DISABLE_TELEMETRY = originalSfDisable; + } else { + delete process.env.SF_DISABLE_TELEMETRY; + } + if (originalSfccDisable !== undefined) { + process.env.SFCC_DISABLE_TELEMETRY = originalSfccDisable; + } else { + delete process.env.SFCC_DISABLE_TELEMETRY; + } + }); + + it('returns false when no disable env vars are set', () => { + expect(Telemetry.isDisabled()).to.be.false; + }); + + it('returns true when SF_DISABLE_TELEMETRY=true', () => { + process.env.SF_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.isDisabled()).to.be.true; + }); + + it('returns true when SFCC_DISABLE_TELEMETRY=true', () => { + process.env.SFCC_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.isDisabled()).to.be.true; + }); + + it('returns false when SF_DISABLE_TELEMETRY=false', () => { + process.env.SF_DISABLE_TELEMETRY = 'false'; + expect(Telemetry.isDisabled()).to.be.false; + }); + }); + + describe('Telemetry.getConnectionString()', () => { + let originalSfDisable: string | undefined; + let originalAppInsightsKey: string | undefined; + + beforeEach(() => { + originalSfDisable = process.env.SF_DISABLE_TELEMETRY; + originalAppInsightsKey = process.env.SFCC_APP_INSIGHTS_KEY; + delete process.env.SF_DISABLE_TELEMETRY; + delete process.env.SFCC_APP_INSIGHTS_KEY; + }); + + afterEach(() => { + if (originalSfDisable !== undefined) { + process.env.SF_DISABLE_TELEMETRY = originalSfDisable; + } else { + delete process.env.SF_DISABLE_TELEMETRY; + } + if (originalAppInsightsKey !== undefined) { + process.env.SFCC_APP_INSIGHTS_KEY = originalAppInsightsKey; + } else { + delete process.env.SFCC_APP_INSIGHTS_KEY; + } + }); + + it('returns undefined when telemetry is disabled', () => { + process.env.SF_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.getConnectionString('default-key')).to.be.undefined; + }); + + it('returns project default when no env override', () => { + expect(Telemetry.getConnectionString('default-key')).to.equal('default-key'); + }); + + it('returns env override when SFCC_APP_INSIGHTS_KEY is set', () => { + process.env.SFCC_APP_INSIGHTS_KEY = 'env-override'; + expect(Telemetry.getConnectionString('default-key')).to.equal('env-override'); + }); + + it('returns undefined when no project default and no env override', () => { + expect(Telemetry.getConnectionString()).to.be.undefined; + }); + }); + + describe('auto-initialization from pjson', () => { + let originalSfDisable: string | undefined; + let originalSfccDisable: string | undefined; + + beforeEach(() => { + originalSfDisable = process.env.SF_DISABLE_TELEMETRY; + originalSfccDisable = process.env.SFCC_DISABLE_TELEMETRY; + delete process.env.SF_DISABLE_TELEMETRY; + delete process.env.SFCC_DISABLE_TELEMETRY; + }); + + afterEach(() => { + if (originalSfDisable !== undefined) { + process.env.SF_DISABLE_TELEMETRY = originalSfDisable; + } else { + delete process.env.SF_DISABLE_TELEMETRY; + } + if (originalSfccDisable !== undefined) { + process.env.SFCC_DISABLE_TELEMETRY = originalSfccDisable; + } else { + delete process.env.SFCC_DISABLE_TELEMETRY; + } + }); + + it('initializes telemetry when pjson has connectionString', async () => { + // Mock the pjson to include telemetry config + sinon.stub(config, 'pjson').value({ + ...config.pjson, + oclif: { + ...(config.pjson.oclif || {}), + telemetry: {connectionString: 'test-key'}, + }, + }); + + const cmd = new TestBaseCommand([], config); + stubParse(cmd); + + await cmd.init(); + + expect(telemetryStartStub.called).to.be.true; + expect(telemetrySendEventStub.calledWith('COMMAND_START')).to.be.true; + expect(cmd.getTelemetry()).to.not.be.undefined; + }); + + it('does not initialize telemetry when pjson has no connectionString', async () => { + // Use default config without telemetry + stubParse(command); + + await command.init(); + + // With no connectionString in pjson, telemetry should not be initialized + // (unless there's an env override, which we've cleared) + expect(command.getTelemetry()).to.be.undefined; + }); + + it('does not initialize telemetry when SF_DISABLE_TELEMETRY=true', async () => { + process.env.SF_DISABLE_TELEMETRY = 'true'; + + // Mock the pjson to include telemetry config + sinon.stub(config, 'pjson').value({ + ...config.pjson, + oclif: { + ...(config.pjson.oclif || {}), + telemetry: {connectionString: 'test-key'}, + }, + }); + + const cmd = new TestBaseCommand([], config); + stubParse(cmd); + + await cmd.init(); + + expect(cmd.getTelemetry()).to.be.undefined; + }); + }); + + describe('catch() exception tracking', () => { + it('sends exception to telemetry when telemetry is initialized', async () => { + // Create a telemetry instance and attach it to the command + const telemetry = new Telemetry({project: 'test', appInsightsKey: 'test-key'}); + (command as unknown as {telemetry: Telemetry}).telemetry = telemetry; + + stubParse(command, {json: false}); + await command.init(); + + const errorStub = sinon.stub(command, 'error').throws(new Error('Expected error')); + + const error = new Error('Test error') as Error & {exitCode?: number}; + error.exitCode = 2; + + try { + await command.testCatch(error); + } catch { + // Expected + } + + expect(telemetrySendExceptionStub.called).to.be.true; + expect(telemetryStopStub.called).to.be.true; + expect(errorStub.called).to.be.true; + }); + + it('includes exitCode and command in exception attributes', async () => { + const telemetry = new Telemetry({project: 'test', appInsightsKey: 'test-key'}); + (command as unknown as {telemetry: Telemetry}).telemetry = telemetry; + + stubParse(command, {json: false}); + await command.init(); + + sinon.stub(command, 'error').throws(new Error('Expected error')); + + const error = new Error('Test error') as Error & {exitCode?: number}; + error.exitCode = 42; + + try { + await command.testCatch(error); + } catch { + // Expected + } + + expect(telemetrySendExceptionStub.called).to.be.true; + const [sentError, attributes] = telemetrySendExceptionStub.firstCall.args; + expect(sentError).to.equal(error); + expect(attributes.exitCode).to.equal(42); + expect(attributes.command).to.equal('test:base'); + }); + }); + + describe('finally() success tracking', () => { + it('sends COMMAND_SUCCESS when no error occurred', async () => { + const telemetry = new Telemetry({project: 'test', appInsightsKey: 'test-key'}); + (command as unknown as {telemetry: Telemetry}).telemetry = telemetry; + + stubParse(command); + await command.init(); + + await command.testFinally(undefined); + + expect(telemetrySendEventStub.calledWith('COMMAND_SUCCESS')).to.be.true; + expect(telemetryStopStub.called).to.be.true; + }); + + it('does not send COMMAND_SUCCESS when error occurred', async () => { + const telemetry = new Telemetry({project: 'test', appInsightsKey: 'test-key'}); + (command as unknown as {telemetry: Telemetry}).telemetry = telemetry; + + stubParse(command); + await command.init(); + + // Reset the stubs to clear any calls from init + telemetrySendEventStub.resetHistory(); + + await command.testFinally(new Error('Some error')); + + expect(telemetrySendEventStub.calledWith('COMMAND_SUCCESS')).to.be.false; + }); + + it('includes duration in COMMAND_SUCCESS attributes', async () => { + const telemetry = new Telemetry({project: 'test', appInsightsKey: 'test-key'}); + (command as unknown as {telemetry: Telemetry}).telemetry = telemetry; + // Simulate that command started 100ms ago + (command as unknown as {commandStartTime: number}).commandStartTime = Date.now() - 100; + + stubParse(command); + await command.init(); + + // Reset after init to check only finally's sendEvent call + telemetrySendEventStub.resetHistory(); + + await command.testFinally(undefined); + + expect(telemetrySendEventStub.calledWith('COMMAND_SUCCESS')).to.be.true; + const [, attributes] = telemetrySendEventStub.firstCall.args; + expect(attributes.duration).to.be.a('number'); + expect(attributes.duration).to.be.at.least(100); + }); + }); + }); }); diff --git a/packages/b2c-tooling-sdk/test/telemetry/telemetry.test.ts b/packages/b2c-tooling-sdk/test/telemetry/telemetry.test.ts new file mode 100644 index 00000000..33db7fbb --- /dev/null +++ b/packages/b2c-tooling-sdk/test/telemetry/telemetry.test.ts @@ -0,0 +1,979 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {expect} from 'chai'; +import sinon from 'sinon'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import type {TelemetryReporter} from '@salesforce/telemetry'; +import * as telemetryModule from '@salesforce/telemetry'; +import {Telemetry, createTelemetry} from '@salesforce/b2c-tooling-sdk/telemetry'; + +/** Type for TelemetryReporter.create options */ +interface ReporterCreateOptions { + project: string; + key: string; + userId: string; + waitForConnection: boolean; +} + +/** Partial mock of TelemetryReporter for testing */ +interface MockReporter { + sendTelemetryEvent: sinon.SinonStub; + sendTelemetryException: sinon.SinonStub; + start: sinon.SinonStub; + stop: sinon.SinonStub; +} + +function createMockReporter(sandbox: sinon.SinonSandbox): MockReporter { + return { + sendTelemetryEvent: sandbox.stub(), + sendTelemetryException: sandbox.stub(), + start: sandbox.stub(), + stop: sandbox.stub(), + }; +} + +/** Cast mock reporter to TelemetryReporter for stub resolution */ +function asTelemetryReporter(mock: MockReporter): TelemetryReporter { + return mock as unknown as TelemetryReporter; +} + +describe('telemetry/telemetry', () => { + let sandbox: sinon.SinonSandbox; + + beforeEach(() => { + sandbox = sinon.createSandbox(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('Telemetry.isDisabled()', () => { + let originalSfDisable: string | undefined; + let originalSfccDisable: string | undefined; + + beforeEach(() => { + originalSfDisable = process.env.SF_DISABLE_TELEMETRY; + originalSfccDisable = process.env.SFCC_DISABLE_TELEMETRY; + delete process.env.SF_DISABLE_TELEMETRY; + delete process.env.SFCC_DISABLE_TELEMETRY; + }); + + afterEach(() => { + if (originalSfDisable !== undefined) { + process.env.SF_DISABLE_TELEMETRY = originalSfDisable; + } else { + delete process.env.SF_DISABLE_TELEMETRY; + } + if (originalSfccDisable !== undefined) { + process.env.SFCC_DISABLE_TELEMETRY = originalSfccDisable; + } else { + delete process.env.SFCC_DISABLE_TELEMETRY; + } + }); + + it('returns false when no disable env vars are set', () => { + expect(Telemetry.isDisabled()).to.be.false; + }); + + it('returns true when SF_DISABLE_TELEMETRY=true', () => { + process.env.SF_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.isDisabled()).to.be.true; + }); + + it('returns true when SFCC_DISABLE_TELEMETRY=true', () => { + process.env.SFCC_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.isDisabled()).to.be.true; + }); + + it('returns false when SF_DISABLE_TELEMETRY=false', () => { + process.env.SF_DISABLE_TELEMETRY = 'false'; + expect(Telemetry.isDisabled()).to.be.false; + }); + + it('returns false when SFCC_DISABLE_TELEMETRY=false', () => { + process.env.SFCC_DISABLE_TELEMETRY = 'false'; + expect(Telemetry.isDisabled()).to.be.false; + }); + + it('returns true when both disable vars are set to true', () => { + process.env.SF_DISABLE_TELEMETRY = 'true'; + process.env.SFCC_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.isDisabled()).to.be.true; + }); + + it('returns true when SF is true and SFCC is false', () => { + process.env.SF_DISABLE_TELEMETRY = 'true'; + process.env.SFCC_DISABLE_TELEMETRY = 'false'; + expect(Telemetry.isDisabled()).to.be.true; + }); + + it('returns true when SF is false and SFCC is true', () => { + process.env.SF_DISABLE_TELEMETRY = 'false'; + process.env.SFCC_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.isDisabled()).to.be.true; + }); + }); + + describe('Telemetry.getConnectionString()', () => { + let originalSfDisable: string | undefined; + let originalSfccDisable: string | undefined; + let originalAppInsightsKey: string | undefined; + + beforeEach(() => { + originalSfDisable = process.env.SF_DISABLE_TELEMETRY; + originalSfccDisable = process.env.SFCC_DISABLE_TELEMETRY; + originalAppInsightsKey = process.env.SFCC_APP_INSIGHTS_KEY; + delete process.env.SF_DISABLE_TELEMETRY; + delete process.env.SFCC_DISABLE_TELEMETRY; + delete process.env.SFCC_APP_INSIGHTS_KEY; + }); + + afterEach(() => { + if (originalSfDisable !== undefined) { + process.env.SF_DISABLE_TELEMETRY = originalSfDisable; + } else { + delete process.env.SF_DISABLE_TELEMETRY; + } + if (originalSfccDisable !== undefined) { + process.env.SFCC_DISABLE_TELEMETRY = originalSfccDisable; + } else { + delete process.env.SFCC_DISABLE_TELEMETRY; + } + if (originalAppInsightsKey !== undefined) { + process.env.SFCC_APP_INSIGHTS_KEY = originalAppInsightsKey; + } else { + delete process.env.SFCC_APP_INSIGHTS_KEY; + } + }); + + it('returns undefined when telemetry is disabled via SF_DISABLE_TELEMETRY', () => { + process.env.SF_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.getConnectionString('project-default')).to.be.undefined; + }); + + it('returns undefined when telemetry is disabled via SFCC_DISABLE_TELEMETRY', () => { + process.env.SFCC_DISABLE_TELEMETRY = 'true'; + expect(Telemetry.getConnectionString('project-default')).to.be.undefined; + }); + + it('returns project default when no env override', () => { + expect(Telemetry.getConnectionString('project-default')).to.equal('project-default'); + }); + + it('returns env override when SFCC_APP_INSIGHTS_KEY is set', () => { + process.env.SFCC_APP_INSIGHTS_KEY = 'env-override'; + expect(Telemetry.getConnectionString('project-default')).to.equal('env-override'); + }); + + it('returns undefined when no project default and no env override', () => { + expect(Telemetry.getConnectionString()).to.be.undefined; + }); + + it('returns env override even without project default', () => { + process.env.SFCC_APP_INSIGHTS_KEY = 'env-override'; + expect(Telemetry.getConnectionString()).to.equal('env-override'); + }); + + it('returns undefined when disabled even with env override set', () => { + process.env.SF_DISABLE_TELEMETRY = 'true'; + process.env.SFCC_APP_INSIGHTS_KEY = 'env-override'; + expect(Telemetry.getConnectionString('project-default')).to.be.undefined; + }); + }); + + describe('Telemetry constructor', () => { + it('creates instance with minimal options', () => { + const telemetry = new Telemetry({project: 'test-project'}); + expect(telemetry).to.be.instanceOf(Telemetry); + }); + + it('creates instance with all options', () => { + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + version: '1.2.3', + initialAttributes: {env: 'test'}, + dataDir: '/tmp/test-data', + }); + expect(telemetry).to.be.instanceOf(Telemetry); + }); + + it('defaults version to 0.0.0 when not provided', () => { + const telemetry = new Telemetry({project: 'test-project'}); + expect(telemetry).to.be.instanceOf(Telemetry); + }); + + it('initializes with empty attributes when not provided', () => { + const telemetry = new Telemetry({project: 'test-project'}); + expect(telemetry).to.be.instanceOf(Telemetry); + }); + }); + + describe('addAttributes', () => { + it('adds single attribute', () => { + const telemetry = new Telemetry({project: 'test-project'}); + telemetry.addAttributes({key: 'value'}); + expect(telemetry).to.be.instanceOf(Telemetry); + }); + + it('adds multiple attributes', () => { + const telemetry = new Telemetry({project: 'test-project'}); + telemetry.addAttributes({key1: 'value1', key2: 'value2'}); + expect(telemetry).to.be.instanceOf(Telemetry); + }); + + it('merges with existing attributes', () => { + const telemetry = new Telemetry({ + project: 'test-project', + initialAttributes: {initial: 'value'}, + }); + telemetry.addAttributes({added: 'new'}); + expect(telemetry).to.be.instanceOf(Telemetry); + }); + + it('overwrites existing attributes with same key', () => { + const telemetry = new Telemetry({ + project: 'test-project', + initialAttributes: {key: 'old'}, + }); + telemetry.addAttributes({key: 'new'}); + expect(telemetry).to.be.instanceOf(Telemetry); + }); + + it('verifies overwritten attributes are sent in events', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + initialAttributes: {key: 'old'}, + }); + + await telemetry.start(); + telemetry.addAttributes({key: 'new'}); + telemetry.sendEvent('TEST_EVENT'); + + const [, eventProps] = mockReporter.sendTelemetryEvent.firstCall.args; + expect(eventProps.key).to.equal('new'); + }); + }); + + describe('sendEvent', () => { + it('does not throw when reporter is not initialized', () => { + const telemetry = new Telemetry({project: 'test-project'}); + expect(() => telemetry.sendEvent('TEST_EVENT')).not.to.throw(); + }); + + it('does not throw with event attributes', () => { + const telemetry = new Telemetry({project: 'test-project'}); + expect(() => telemetry.sendEvent('TEST_EVENT', {action: 'click'})).not.to.throw(); + }); + + it('sends event when reporter is available', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + version: '1.0.0', + }); + + await telemetry.start(); + telemetry.sendEvent('TEST_EVENT', {action: 'click'}); + + expect(mockReporter.sendTelemetryEvent.calledOnce).to.be.true; + const [eventName, eventProps] = mockReporter.sendTelemetryEvent.firstCall.args; + expect(eventName).to.equal('TEST_EVENT'); + expect(eventProps).to.include({ + action: 'click', + version: '1.0.0', + origin: 'test-project', + platform: process.platform, + arch: process.arch, + nodeVersion: process.version, + }); + expect(eventProps.sessionId).to.be.a('string'); + expect(eventProps.cliId).to.be.a('string'); + expect(eventProps.date).to.be.a('string'); + expect(eventProps.timestamp).to.be.a('string'); + expect(eventProps.processUptime).to.be.a('number'); + }); + + it('includes initial attributes in events', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + initialAttributes: {environment: 'test'}, + }); + + await telemetry.start(); + telemetry.sendEvent('TEST_EVENT'); + + const [, eventProps] = mockReporter.sendTelemetryEvent.firstCall.args; + expect(eventProps.environment).to.equal('test'); + }); + + it('includes added attributes in events', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + }); + + await telemetry.start(); + telemetry.addAttributes({customAttr: 'value'}); + telemetry.sendEvent('TEST_EVENT'); + + const [, eventProps] = mockReporter.sendTelemetryEvent.firstCall.args; + expect(eventProps.customAttr).to.equal('value'); + }); + + it('event attributes override instance attributes', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + initialAttributes: {key: 'initial'}, + }); + + await telemetry.start(); + telemetry.sendEvent('TEST_EVENT', {key: 'event'}); + + const [, eventProps] = mockReporter.sendTelemetryEvent.firstCall.args; + expect(eventProps.key).to.equal('event'); + }); + + it('silently catches errors during send', async () => { + const mockReporter = createMockReporter(sandbox); + mockReporter.sendTelemetryEvent.throws(new Error('Send failed')); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + }); + + await telemetry.start(); + expect(() => telemetry.sendEvent('TEST_EVENT')).not.to.throw(); + }); + + it('supports COMMAND_START event type', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + initialAttributes: {command: 'test:command'}, + }); + + await telemetry.start(); + telemetry.sendEvent('COMMAND_START', {command: 'test:command'}); + + const [eventName] = mockReporter.sendTelemetryEvent.firstCall.args; + expect(eventName).to.equal('COMMAND_START'); + }); + + it('supports COMMAND_SUCCESS event type with duration', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + }); + + await telemetry.start(); + telemetry.sendEvent('COMMAND_SUCCESS', {command: 'test:command', duration: 1234}); + + const [eventName, eventProps] = mockReporter.sendTelemetryEvent.firstCall.args; + expect(eventName).to.equal('COMMAND_SUCCESS'); + expect(eventProps.duration).to.equal(1234); + }); + + it('supports SERVER_STOPPED event type', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'b2c-dx-mcp', + appInsightsKey: 'test-key', + }); + + await telemetry.start(); + telemetry.sendEvent('SERVER_STOPPED'); + + const [eventName] = mockReporter.sendTelemetryEvent.firstCall.args; + expect(eventName).to.equal('SERVER_STOPPED'); + }); + + it('supports TOOL_CALLED event type', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'b2c-dx-mcp', + appInsightsKey: 'test-key', + }); + + await telemetry.start(); + telemetry.sendEvent('TOOL_CALLED', { + toolName: 'cartridge_deploy', + runTimeMs: 500, + isError: false, + }); + + const [eventName, eventProps] = mockReporter.sendTelemetryEvent.firstCall.args; + expect(eventName).to.equal('TOOL_CALLED'); + expect(eventProps.toolName).to.equal('cartridge_deploy'); + expect(eventProps.runTimeMs).to.equal(500); + expect(eventProps.isError).to.equal(false); + }); + }); + + describe('sendException', () => { + it('does not throw when reporter is not initialized', () => { + const telemetry = new Telemetry({project: 'test-project'}); + expect(() => telemetry.sendException(new Error('test error'))).not.to.throw(); + }); + + it('sends exception when reporter is available', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + version: '1.0.0', + }); + + await telemetry.start(); + const error = new Error('test error'); + telemetry.sendException(error, {context: 'test-context'}); + + expect(mockReporter.sendTelemetryException.calledOnce).to.be.true; + const [sentError, properties] = mockReporter.sendTelemetryException.firstCall.args; + expect(sentError).to.equal(error); + expect(properties).to.include({ + context: 'test-context', + version: '1.0.0', + origin: 'test-project', + }); + }); + + it('includes initial attributes in exception', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + initialAttributes: {command: 'test-command'}, + }); + + await telemetry.start(); + telemetry.sendException(new Error('test error')); + + const [, properties] = mockReporter.sendTelemetryException.firstCall.args; + expect(properties.command).to.equal('test-command'); + }); + + it('silently catches errors during send', async () => { + const mockReporter = createMockReporter(sandbox); + mockReporter.sendTelemetryException.throws(new Error('Send failed')); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + }); + + await telemetry.start(); + expect(() => telemetry.sendException(new Error('test error'))).not.to.throw(); + }); + + it('includes exitCode and command in exception attributes', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + initialAttributes: {command: 'test:command'}, + }); + + await telemetry.start(); + telemetry.sendException(new Error('test error'), {exitCode: 1, duration: 500}); + + const [, properties] = mockReporter.sendTelemetryException.firstCall.args; + expect(properties.exitCode).to.equal(1); + expect(properties.duration).to.equal(500); + expect(properties.command).to.equal('test:command'); + }); + }); + + describe('start', () => { + it('does nothing when already started', async () => { + const mockReporter = createMockReporter(sandbox); + const createStub = sandbox + .stub(telemetryModule.TelemetryReporter, 'create') + .resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + }); + + await telemetry.start(); + await telemetry.start(); + + expect(createStub.calledOnce).to.be.true; + }); + + it('does not create reporter when appInsightsKey is not provided', async () => { + const createStub = sandbox.stub(telemetryModule.TelemetryReporter, 'create'); + + const telemetry = new Telemetry({project: 'test-project'}); + await telemetry.start(); + + expect(createStub.called).to.be.false; + }); + + it('retries once on initial failure', async () => { + const mockReporter = createMockReporter(sandbox); + + const createStub = sandbox + .stub(telemetryModule.TelemetryReporter, 'create') + .onFirstCall() + .rejects(new Error('Connection failed')) + .onSecondCall() + .resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + }); + + await telemetry.start(); + + expect(createStub.calledTwice).to.be.true; + }); + + it('ignores failure after retry', async () => { + const createStub = sandbox + .stub(telemetryModule.TelemetryReporter, 'create') + .rejects(new Error('Connection failed')); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + }); + + await telemetry.start(); + + expect(createStub.calledTwice).to.be.true; + }); + + it('creates reporter with correct options', async () => { + const mockReporter = createMockReporter(sandbox); + const createStub = sandbox + .stub(telemetryModule.TelemetryReporter, 'create') + .resolves(asTelemetryReporter(mockReporter)); + + // Mock fs to return a known CLI ID + sandbox.stub(fs, 'existsSync').returns(true); + sandbox.stub(fs, 'readFileSync').returns('known-cli-id'); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key-123', + dataDir: '/tmp/test-data', + }); + + await telemetry.start(); + + expect(createStub.calledOnce).to.be.true; + const createOptions = createStub.firstCall.args[0] as ReporterCreateOptions; + expect(createOptions.project).to.equal('test-project'); + expect(createOptions.key).to.equal('test-key-123'); + expect(createOptions.userId).to.equal('known-cli-id'); + expect(createOptions.waitForConnection).to.be.true; + }); + }); + + describe('stop', () => { + it('does nothing when not started', () => { + const telemetry = new Telemetry({project: 'test-project'}); + expect(() => telemetry.stop()).not.to.throw(); + }); + + it('stops the reporter', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + }); + + await telemetry.start(); + telemetry.stop(); + + expect(mockReporter.stop.calledOnce).to.be.true; + }); + + it('can be called multiple times', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + }); + + await telemetry.start(); + telemetry.stop(); + telemetry.stop(); + + // Only called once because second stop() returns early (started is false) + expect(mockReporter.stop.calledOnce).to.be.true; + }); + }); + + describe('CLI ID persistence with dataDir', () => { + let tempDir: string; + + beforeEach(() => { + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'telemetry-test-')); + }); + + afterEach(() => { + fs.rmSync(tempDir, {recursive: true, force: true}); + }); + + it('generates random ID when dataDir is not provided', () => { + const telemetry1 = new Telemetry({project: 'test-project'}); + const telemetry2 = new Telemetry({project: 'test-project'}); + + // Each instance should get a unique ID since it can't persist + expect(telemetry1).to.be.instanceOf(Telemetry); + expect(telemetry2).to.be.instanceOf(Telemetry); + }); + + it('reads existing CLI ID from dataDir', async () => { + const cliIdFile = path.join(tempDir, 'cliid'); + fs.writeFileSync(cliIdFile, 'existing-cli-id'); + + const mockReporter = createMockReporter(sandbox); + const createStub = sandbox + .stub(telemetryModule.TelemetryReporter, 'create') + .resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + dataDir: tempDir, + }); + + await telemetry.start(); + + const createOptions = createStub.firstCall.args[0] as ReporterCreateOptions; + expect(createOptions.userId).to.equal('existing-cli-id'); + }); + + it('creates new CLI ID and persists it to dataDir', async () => { + const mockReporter = createMockReporter(sandbox); + const createStub = sandbox + .stub(telemetryModule.TelemetryReporter, 'create') + .resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + dataDir: tempDir, + }); + + await telemetry.start(); + + // Verify ID was created + const createOptions = createStub.firstCall.args[0] as ReporterCreateOptions; + expect(createOptions.userId).to.be.a('string'); + expect(createOptions.userId).to.have.lengthOf(40); // 20 bytes as hex + + // Verify ID was persisted + const persistedId = fs.readFileSync(path.join(tempDir, 'cliid'), 'utf8'); + expect(persistedId).to.equal(createOptions.userId); + }); + + it('handles empty CLI ID file by creating new one', async () => { + const cliIdFile = path.join(tempDir, 'cliid'); + fs.writeFileSync(cliIdFile, ' '); // whitespace-only file + + const mockReporter = createMockReporter(sandbox); + const createStub = sandbox + .stub(telemetryModule.TelemetryReporter, 'create') + .resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + dataDir: tempDir, + }); + + await telemetry.start(); + + const createOptions = createStub.firstCall.args[0] as ReporterCreateOptions; + expect(createOptions.userId).to.have.lengthOf(40); + }); + + it('handles read errors by creating new ID', async () => { + const cliIdFile = path.join(tempDir, 'cliid'); + // Create a directory with the same name as the file to cause read error + fs.mkdirSync(cliIdFile); + + const mockReporter = createMockReporter(sandbox); + const createStub = sandbox + .stub(telemetryModule.TelemetryReporter, 'create') + .resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + dataDir: tempDir, + }); + + await telemetry.start(); + + // Should still get a valid ID despite read error + const createOptions = createStub.firstCall.args[0] as ReporterCreateOptions; + expect(createOptions.userId).to.be.a('string'); + }); + + it('handles write errors gracefully', async () => { + // Make the temp directory read-only to simulate write failure + const readOnlyDir = path.join(tempDir, 'readonly'); + fs.mkdirSync(readOnlyDir, {mode: 0o444}); + + const mockReporter = createMockReporter(sandbox); + const createStub = sandbox + .stub(telemetryModule.TelemetryReporter, 'create') + .resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + dataDir: readOnlyDir, + }); + + await telemetry.start(); + + // Should still have a valid ID even if persistence failed + const createOptions = createStub.firstCall.args[0] as ReporterCreateOptions; + expect(createOptions.userId).to.be.a('string'); + + // Clean up permissions for removal + fs.chmodSync(readOnlyDir, 0o755); + }); + + it('creates dataDir if it does not exist', async () => { + const nestedDir = path.join(tempDir, 'nested', 'data'); + + const mockReporter = createMockReporter(sandbox); + const createStub = sandbox + .stub(telemetryModule.TelemetryReporter, 'create') + .resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + dataDir: nestedDir, + }); + + await telemetry.start(); + + // Verify ID was created and persisted + const createOptions = createStub.firstCall.args[0] as ReporterCreateOptions; + expect(createOptions.userId).to.be.a('string'); + expect(fs.existsSync(path.join(nestedDir, 'cliid'))).to.be.true; + }); + + it('uses same CLI ID across multiple telemetry instances with same dataDir', async () => { + const mockReporter = createMockReporter(sandbox); + const createStub = sandbox + .stub(telemetryModule.TelemetryReporter, 'create') + .resolves(asTelemetryReporter(mockReporter)); + + const telemetry1 = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + dataDir: tempDir, + }); + + await telemetry1.start(); + const userId1 = (createStub.firstCall.args[0] as ReporterCreateOptions).userId; + + const telemetry2 = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + dataDir: tempDir, + }); + + await telemetry2.start(); + const userId2 = (createStub.secondCall.args[0] as ReporterCreateOptions).userId; + + expect(userId1).to.equal(userId2); + }); + }); + + describe('createTelemetry factory', () => { + it('creates Telemetry instance with options', () => { + const telemetry = createTelemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + version: '1.0.0', + }); + expect(telemetry).to.be.instanceOf(Telemetry); + }); + + it('creates Telemetry instance with minimal options', () => { + const telemetry = createTelemetry({project: 'test-project'}); + expect(telemetry).to.be.instanceOf(Telemetry); + }); + + it('creates Telemetry instance with dataDir', () => { + const telemetry = createTelemetry({ + project: 'test-project', + dataDir: '/tmp/test-data', + }); + expect(telemetry).to.be.instanceOf(Telemetry); + }); + }); + + describe('session ID uniqueness', () => { + it('generates unique session IDs per instance', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry1 = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + }); + const telemetry2 = new Telemetry({ + project: 'test-project', + appInsightsKey: 'test-key', + }); + + await telemetry1.start(); + await telemetry2.start(); + + telemetry1.sendEvent('EVENT1'); + telemetry2.sendEvent('EVENT2'); + + const stub = mockReporter.sendTelemetryEvent as sinon.SinonStub; + const sessionId1 = stub.firstCall.args[1].sessionId; + const sessionId2 = stub.secondCall.args[1].sessionId; + + expect(sessionId1).to.be.a('string'); + expect(sessionId2).to.be.a('string'); + expect(sessionId1).to.not.equal(sessionId2); + }); + }); + + describe('integration scenarios', () => { + it('supports full CLI command lifecycle', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'b2c-cli', + appInsightsKey: 'test-key', + version: '1.0.0', + initialAttributes: {command: 'code deploy'}, + }); + + await telemetry.start(); + + // Simulate command lifecycle + telemetry.sendEvent('COMMAND_START', {command: 'code deploy'}); + + // Simulate successful completion + telemetry.sendEvent('COMMAND_SUCCESS', {command: 'code deploy', duration: 5000}); + + telemetry.stop(); + + expect(mockReporter.sendTelemetryEvent.calledTwice).to.be.true; + expect(mockReporter.stop.calledOnce).to.be.true; + }); + + it('supports MCP server lifecycle', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'b2c-dx-mcp', + appInsightsKey: 'test-key', + version: '1.0.0', + initialAttributes: {toolsets: 'MRT, CARTRIDGES'}, + }); + + await telemetry.start(); + + // Simulate server lifecycle + telemetry.sendEvent('COMMAND_START', {command: 'mcp'}); + telemetry.sendEvent('SERVER_STATUS', {status: 'started'}); + + // Simulate tool calls + telemetry.sendEvent('TOOL_CALLED', {toolName: 'cartridge_deploy', runTimeMs: 500, isError: false}); + telemetry.sendEvent('TOOL_CALLED', {toolName: 'mrt_bundle_push', runTimeMs: 3000, isError: false}); + + // Simulate shutdown + telemetry.sendEvent('SERVER_STOPPED'); + telemetry.stop(); + + expect(mockReporter.sendTelemetryEvent.callCount).to.equal(5); + expect(mockReporter.stop.calledOnce).to.be.true; + }); + + it('supports error handling in CLI command', async () => { + const mockReporter = createMockReporter(sandbox); + sandbox.stub(telemetryModule.TelemetryReporter, 'create').resolves(asTelemetryReporter(mockReporter)); + + const telemetry = new Telemetry({ + project: 'b2c-cli', + appInsightsKey: 'test-key', + version: '1.0.0', + initialAttributes: {command: 'code deploy'}, + }); + + await telemetry.start(); + + // Simulate command start + telemetry.sendEvent('COMMAND_START', {command: 'code deploy'}); + + // Simulate error + const error = new Error('Connection refused'); + telemetry.sendException(error, {exitCode: 1, duration: 1000}); + + telemetry.stop(); + + expect(mockReporter.sendTelemetryEvent.calledOnce).to.be.true; + expect(mockReporter.sendTelemetryException.calledOnce).to.be.true; + expect(mockReporter.stop.calledOnce).to.be.true; + }); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ea4db83..9a2418b4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -181,6 +181,9 @@ importers: '@types/node': specifier: ^22.16.5 version: 22.19.0 + '@types/sinon': + specifier: ^21.0.0 + version: 21.0.0 chai: specifier: ^4 version: 4.5.0 @@ -211,6 +214,9 @@ importers: shx: specifier: ^0.3.3 version: 0.3.4 + sinon: + specifier: ^21.0.1 + version: 21.0.1 tsx: specifier: ^4 version: 4.20.6 @@ -263,6 +269,9 @@ importers: packages/b2c-tooling-sdk: dependencies: + '@salesforce/telemetry': + specifier: ^6.1.0 + version: 6.4.6(tslib@2.8.1) archiver: specifier: ^7.0.1 version: 7.0.1 @@ -619,6 +628,38 @@ packages: resolution: {integrity: sha512-RcLam17LdlbSOSp9VxmUu1eI6Mwxp+OwhD2QhiSNmNCzoDb0EeUXTD2n/WbcnrAYMGlmf05th6QYq23VqvJqpA==} engines: {node: '>=18.0.0'} + '@azure/abort-controller@2.1.2': + resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} + engines: {node: '>=18.0.0'} + + '@azure/core-auth@1.10.1': + resolution: {integrity: sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==} + engines: {node: '>=20.0.0'} + + '@azure/core-auth@1.7.2': + resolution: {integrity: sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==} + engines: {node: '>=18.0.0'} + + '@azure/core-rest-pipeline@1.16.3': + resolution: {integrity: sha512-VxLk4AHLyqcHsfKe4MZ6IQ+D+ShuByy+RfStKfSjxJoL3WBWq17VNmrz8aT8etKzqc2nAeIyLxScjpzsS4fz8w==} + engines: {node: '>=18.0.0'} + + '@azure/core-tracing@1.3.1': + resolution: {integrity: sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==} + engines: {node: '>=20.0.0'} + + '@azure/core-util@1.13.1': + resolution: {integrity: sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==} + engines: {node: '>=20.0.0'} + + '@azure/logger@1.3.0': + resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} + engines: {node: '>=20.0.0'} + + '@azure/opentelemetry-instrumentation-azure-sdk@1.0.0-beta.9': + resolution: {integrity: sha512-gNCFokEoQQEkhu2T8i1i+1iW2o9wODn2slu5tpqJmjV1W7qf9dxVv6GNXW1P1WC8wMga8BCc2t/oMhOK3iwRQg==} + engines: {node: '>=18.0.0'} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -1489,12 +1530,139 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@jsforce/jsforce-node@3.10.13': + resolution: {integrity: sha512-Ft42/lp3WaVxijcX88Rb3yIxujk/u3LwL3913OTcB4WCpwjB9xTqP6jkVTKt2riXg+ZlNiS62SMpQeC3U1Efkw==} + engines: {node: '>=18'} + + '@jsonjoy.com/base64@1.1.2': + resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/base64@17.65.0': + resolution: {integrity: sha512-Xrh7Fm/M0QAYpekSgmskdZYnFdSGnsxJ/tHaolA4bNwWdG9i65S8m83Meh7FOxyJyQAdo4d4J97NOomBLEfkDQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/buffers@1.2.1': + resolution: {integrity: sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/buffers@17.65.0': + resolution: {integrity: sha512-eBrIXd0/Ld3p9lpDDlMaMn6IEfWqtHMD+z61u0JrIiPzsV1r7m6xDZFRxJyvIFTEO+SWdYF9EiQbXZGd8BzPfA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/codegen@1.0.0': + resolution: {integrity: sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/codegen@17.65.0': + resolution: {integrity: sha512-7MXcRYe7n3BG+fo3jicvjB0+6ypl2Y/bQp79Sp7KeSiiCgLqw4Oled6chVv07/xLVTdo3qa1CD0VCCnPaw+RGA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-core@4.56.4': + resolution: {integrity: sha512-mgiAa7w0N0mlr7G3PUY/iRSYuJwyZmHBt+y7D9veiXfAqsIhEi9+FCu47tU+y/3KPqaTNJMsfgAGwUnLPnRdqA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-fsa@4.56.4': + resolution: {integrity: sha512-D6tHSr8xMiZnV9pQcX0ysoEg1kTsTFK6fRV+TX+1uFcEiNKJR7hooGBq8iKnkZCXRxY8S4nZJ+rErpVF1XJ4vw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-builtins@4.56.4': + resolution: {integrity: sha512-/HMj267Ygg/fa3kHuZL+L7rVXvZ7HT2Bm7d8CpKs6l7QpT4mzTnN4f2/E0u+LsrrJVbT+R34/nsBr2dIZSYIgg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-to-fsa@4.56.4': + resolution: {integrity: sha512-Wewg2JlMkFpUt2Z+RrhdxLrbG6o4XAZB9UdGbpcQS+acvwytmhEjUCCodD3kqY5wPSNpnIbD614VeTA/5jPzvg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-utils@4.56.4': + resolution: {integrity: sha512-7yvPBX+YUPvoljJ5ELmHrK7sLYzEVdLnILoNXLtsztN4Ag8UbS7DteWRiW3BFAUIvI4kDBJ8OymdxwLLCkX+AQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node@4.56.4': + resolution: {integrity: sha512-4G7KBypcWy2BGPnuDCmUQWHasbNZnEqcb3DLODuH22J8fre7YK8MiyciIohkUTFMqR9qem84LK22T1FmUwiTSQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-print@4.56.4': + resolution: {integrity: sha512-GtTDri9Ot1l7XPe3ft+ViTqxFOqtKcM4RLyXEXWDvQEoqgmU/6bCNNjfSze9VlpfC8KfuUYAixuDLD1quzHdow==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-snapshot@4.56.4': + resolution: {integrity: sha512-qQxl+GVp9gzT21/Ot8qa+pcNurpfTL/ruMODYmshpcTLXy6x06aP4/xdhBOJpBclhqbnQcMTVDCny98CtGvyzQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pack@1.21.0': + resolution: {integrity: sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pack@17.65.0': + resolution: {integrity: sha512-e0SG/6qUCnVhHa0rjDJHgnXnbsacooHVqQHxspjvlYQSkHm+66wkHw6Gql+3u/WxI/b1VsOdUi0M+fOtkgKGdQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pointer@1.0.2': + resolution: {integrity: sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pointer@17.65.0': + resolution: {integrity: sha512-uhTe+XhlIZpWOxgPcnO+iSCDgKKBpwkDVTyYiXX9VayGV8HSFVJM67M6pUE71zdnXF1W0Da21AvnhlmdwYPpow==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/util@1.9.0': + resolution: {integrity: sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/util@17.65.0': + resolution: {integrity: sha512-cWiEHZccQORf96q2y6zU3wDeIVPeidmGqd9cNKJRYoVHTV0S1eHPy5JTbHpMnGfDvtvujQwQozOqgO9ABu6h0w==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + '@manypkg/find-root@1.1.0': resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + '@microsoft/applicationinsights-web-snippet@1.0.1': + resolution: {integrity: sha512-2IHAOaLauc8qaAitvWS+U931T+ze+7MNWrDHY47IENP5y2UA0vqJDu67kWZDdpCN1fFC77sfgfB+HV7SrKshnQ==} + '@modelcontextprotocol/inspector-cli@0.18.0': resolution: {integrity: sha512-QMPjKx8zKmX17S1LF2gWuwbYglKexkdgB0HhKZFXzGrQ0MYoKUsIgokMyV48xr4LipaLS3b2v3ut3nV/jhWeSg==} hasBin: true @@ -1591,6 +1759,70 @@ packages: '@open-draft/until@2.1.0': resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@opentelemetry/api-logs@0.200.0': + resolution: {integrity: sha512-IKJBQxh91qJ+3ssRly5hYEJ8NDHu9oY/B1PXVSCWf7zytmYO9RNLB0Ox9XQ/fJ8m6gY6Q6NtBWlmXfaXt5Uc4Q==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/core@1.30.1': + resolution: {integrity: sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@2.4.0': + resolution: {integrity: sha512-KtcyFHssTn5ZgDu6SXmUznS80OFs/wN7y6MyFRRcKU6TOw8hNcGxKvt8hsdaLJfhzUszNSjURetq5Qpkad14Gw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/instrumentation@0.200.0': + resolution: {integrity: sha512-pmPlzfJd+vvgaZd/reMsC8RWgTXn2WY1OWT5RT42m3aOn5532TozwXNDhg1vzqJ+jnvmkREcdLr27ebJEQt0Jg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/resources@1.30.1': + resolution: {integrity: sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/resources@2.4.0': + resolution: {integrity: sha512-RWvGLj2lMDZd7M/5tjkI/2VHMpXebLgPKvBUd9LRasEWR2xAynDwEYZuLvY9P2NGG73HF07jbbgWX2C9oavcQg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@1.30.1': + resolution: {integrity: sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@2.4.0': + resolution: {integrity: sha512-WH0xXkz/OHORDLKqaxcUZS0X+t1s7gGlumr2ebiEgNZQl2b0upK2cdoD0tatf7l8iP74woGJ/Kmxe82jdvcWRw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-web@2.4.0': + resolution: {integrity: sha512-1FYg7qnrgTugPev51SehxCp0v9J4P97MJn2MaXQ8QK//psfyLDorKAAC3LmSIhq7XaC726WSZ/Wm69r8NdjIsA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/semantic-conventions@1.28.0': + resolution: {integrity: sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==} + engines: {node: '>=14'} + + '@opentelemetry/semantic-conventions@1.39.0': + resolution: {integrity: sha512-R5R9tb2AXs2IRLNKLBJDynhkfmx7mX0vi8NkhZb3gUkPWHn6HXk5J8iQ/dql0U3ApfWym4kXXmBDRGO+oeOfjg==} + engines: {node: '>=14'} + '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} @@ -1614,6 +1846,36 @@ packages: resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} engines: {node: '>=12'} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@radix-ui/number@1.1.1': resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} @@ -2157,9 +2419,28 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@salesforce/core@8.24.3': + resolution: {integrity: sha512-E9k4G3S8svS6QtsPVhUvxr0VHWyzg7KxH8sYM0o5pk7QEUXZCKQEQE5VjQOa+Gl3jRyX6zv/8Cp4UpQ2ZszOVg==} + engines: {node: '>=18.0.0'} + '@salesforce/dev-config@4.3.2': resolution: {integrity: sha512-mxhsWV1rzHfhGMVSFQRLOHZTGfB1R2FtqbuIb3hrgDFsW1NLjEDS2U+eZWBJiCYod1JeGpJxnETNq587lem1Gg==} + '@salesforce/kit@3.2.4': + resolution: {integrity: sha512-9buqZ2puIGWqjUFWYNroSeNih4d1s9kdQAzZfutr/Re/JMl6xBct0ATO5LVb1ty5UhdBruJrVaiTg03PqVKU+Q==} + + '@salesforce/o11y-reporter@1.7.0': + resolution: {integrity: sha512-K4kY3yf2RD2T/RYIID3Ucrlbi9cdR57Lak58o1KLhl4gO+LHMatuk5FJbYpEIuaOqE83G5/pIJ1dOps0BVBcVA==} + engines: {node: '>=20'} + + '@salesforce/telemetry@6.4.6': + resolution: {integrity: sha512-/TJZC62lHvlP2PF5vJqpZQAPwA8s/ML8ZNUY4EUFvH6uMLa0qNy+k4pV2N4/s0LqXO2rcdNvz8TO0Nk4QTHzDw==} + engines: {node: '>=18.0.0'} + + '@salesforce/ts-types@2.0.12': + resolution: {integrity: sha512-BIJyduJC18Kc8z+arUm5AZ9VkPRyw1KKAm+Tk+9LT99eOzhNilyfKzhZ4t+tG2lIGgnJpmytZfVDZ0e2kFul8g==} + engines: {node: '>=18.0.0'} + '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} @@ -2449,6 +2730,10 @@ packages: peerDependencies: eslint: '>=9.0.0' + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + '@szmarczak/http-timer@5.0.1': resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} engines: {node: '>=14.16'} @@ -2458,6 +2743,9 @@ packages: peerDependencies: eslint: '>=7.7.0' + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@tsconfig/node10@1.0.12': resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} @@ -2476,6 +2764,9 @@ packages: '@types/archiver@7.0.0': resolution: {integrity: sha512-/3vwGwx9n+mCQdYZ2IKGGHEFL30I96UgBlk8EtRDDFQ9uxM1l4O5Ci6r00EMAkiDaTqD9DQ6nVrWRICnBPtzzg==} + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + '@types/chai@4.3.20': resolution: {integrity: sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==} @@ -2497,6 +2788,9 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + '@types/linkify-it@5.0.0': resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} @@ -2530,6 +2824,12 @@ packages: '@types/readdir-glob@1.1.5': resolution: {integrity: sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==} + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + + '@types/shimmer@1.2.0': + resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==} + '@types/sinon@21.0.0': resolution: {integrity: sha512-+oHKZ0lTI+WVLxx1IbJDNmReQaIsQJjN2e7UUrJHEeByG7bFeKJYsv1E75JxTQ9QKJDp21bAa/0W2Xo4srsDnw==} @@ -2610,6 +2910,10 @@ packages: resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typespec/ts-http-runtime@0.3.2': + resolution: {integrity: sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg==} + engines: {node: '>=20.0.0'} + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} @@ -2819,6 +3123,11 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -2833,6 +3142,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -2894,6 +3207,15 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + applicationinsights@2.9.8: + resolution: {integrity: sha512-eB/EtAXJ6mDLLvHrtZj/7h31qUfnC2Npr2pHGqds5+1OP7BFLsn5us+HCkwTj7Q+1sHXujLphE5Cyvq5grtV6g==} + engines: {node: '>=8.0.0'} + peerDependencies: + applicationinsights-native-metrics: '*' + peerDependenciesMeta: + applicationinsights-native-metrics: + optional: true + archiver-utils@5.0.2: resolution: {integrity: sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==} engines: {node: '>= 14'} @@ -2947,19 +3269,37 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} + async-hook-jl@1.7.6: + resolution: {integrity: sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg==} + engines: {node: ^4.7 || >=6.9 || >=7.3} + + async-listener@0.6.10: + resolution: {integrity: sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==} + engines: {node: <=0.11.8 || >0.11.10} + async-retry@1.3.3: resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + atomic-sleep@1.0.0: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} @@ -2990,6 +3330,10 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + base64url@3.0.1: + resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==} + engines: {node: '>=6.0.0'} + baseline-browser-mapping@2.8.26: resolution: {integrity: sha512-73lC1ugzwoaWCLJ1LvOgrR5xsMLTqSKIEoMHVtL9E/HNk0PXtTM76ZIm84856/SF7Nv8mPZxKoBsgpm0tR1u1Q==} hasBin: true @@ -2998,6 +3342,10 @@ packages: resolution: {integrity: sha512-kX8h7K2srmDyYnXRIppo4AH/wYgzWVCs+eKr3RusRSQ5PvRYoEFmR/I0PbdTjKFAoKqp5+kbxnNTFO9jOfSVJg==} hasBin: true + basic-ftp@5.1.0: + resolution: {integrity: sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==} + engines: {node: '>=10.0.0'} + better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} @@ -3038,6 +3386,9 @@ packages: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} engines: {node: '>=8.0.0'} + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -3070,6 +3421,10 @@ packages: monocart-coverage-reports: optional: true + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + cacheable-lookup@7.0.0: resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} engines: {node: '>=14.16'} @@ -3078,6 +3433,10 @@ packages: resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} engines: {node: '>=14.16'} + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -3160,6 +3519,9 @@ packages: resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} engines: {node: '>=8'} + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -3199,6 +3561,13 @@ packages: resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} engines: {node: '>=20'} + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + + cls-hooked@4.2.2: + resolution: {integrity: sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw==} + engines: {node: ^4.7 || >=6.9 || >=7.3 || >=8.2.1} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -3222,6 +3591,10 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -3266,6 +3639,9 @@ packages: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + continuation-local-storage@3.2.1: + resolution: {integrity: sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -3311,13 +3687,27 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + csprng@0.1.2: + resolution: {integrity: sha512-D3WAbvvgUVIqSxUfdvLeGjuotsB32bvfVPd+AaaTWMtyUeC9zgCnw5xs94no89yFLVsafvY9dMZEhTwsY/ZecA==} + engines: {node: '>=0.6.0'} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + csv-parse@5.6.0: + resolution: {integrity: sha512-l3nz3euub2QMg5ouu5U09Ew9Wf6/wQ8I++ch1loQ0ljmzhmfZYrH9fflS22i/PQEvsPvxCwxgz5q7UB8K1JO4Q==} + + csv-stringify@6.6.0: + resolution: {integrity: sha512-YW32lKOmIBgbxtu3g5SaiqWNwa/9ISQt2EcgOq0+RAIFufFp9is6tqNnKahqE5kuKvrnYAzs28r+s6pXJR8Vcw==} + data-uri-to-buffer@4.0.1: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -3392,6 +3782,14 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -3418,6 +3816,14 @@ packages: devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + diagnostic-channel-publishers@1.0.8: + resolution: {integrity: sha512-HmSm9hXxSPxA9BaLGY98QU1zsdjeCk113KjAYGPCen1ZP6mhVaTPzHd6UYv5r21DnWANi+f+NyPOHruGT9jpqQ==} + peerDependencies: + diagnostic-channel: '*' + + diagnostic-channel@1.1.1: + resolution: {integrity: sha512-r2HV5qFkUICyoaKlBEpLKHjxMXATUf/l+h8UZPGBHGLy4DDiY2sOLcIctax4eRnTw5wH2jTMExLntGPJ8eOJxw==} + diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} @@ -3452,6 +3858,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -3463,6 +3872,9 @@ packages: electron-to-chromium@1.5.250: resolution: {integrity: sha512-/5UMj9IiGDMOFBnN4i7/Ry5onJrAGSbOGo3s9FEKmwobGq6xw832ccET0CE3CkkMBZ8GJSlUIesZofpyurqDXw==} + emitter-listener@1.1.2: + resolution: {integrity: sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==} + emoji-regex-xs@1.0.0: resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} @@ -3557,6 +3969,11 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + eslint-compat-utils@0.5.1: resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} engines: {node: '>=12'} @@ -3865,6 +4282,14 @@ packages: fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + faye-websocket@0.11.4: + resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} + engines: {node: '>=0.8.0'} + + faye@1.4.1: + resolution: {integrity: sha512-Cg/khikhqlvumHO3efwx2tps2ZgQRjUMrO24G0quz7MMzRYYaEjU224YFXOeuPIvanRegIchVxj6pmHK1W0ikA==} + engines: {node: '>=0.8.0'} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -3934,6 +4359,10 @@ packages: resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} engines: {node: '>= 14.17'} + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} @@ -4011,6 +4440,10 @@ packages: resolution: {integrity: sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==} engines: {node: '>=12'} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -4026,6 +4459,10 @@ packages: get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-uri@6.0.5: + resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} + engines: {node: '>= 14'} + git-hooks-list@3.2.0: resolution: {integrity: sha512-ZHG9a1gEhUMX1TvGrLdyWb9kDopCBbTnI8z4JgRMYxsijWipgjSEYoPWqBuIB0DnRnvqlQSEeVmzpeuPm7NdFQ==} @@ -4040,6 +4477,12 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob-to-regex.js@1.2.0: + resolution: {integrity: sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} hasBin: true @@ -4088,6 +4531,10 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + got@13.0.0: resolution: {integrity: sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==} engines: {node: '>=16'} @@ -4185,10 +4632,25 @@ packages: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} + http-parser-js@0.5.10: + resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + http2-wrapper@2.2.1: resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} engines: {node: '>=10.19.0'} + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} @@ -4201,6 +4663,10 @@ packages: resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} engines: {node: '>=18.18.0'} + hyperdyperid@1.2.0: + resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==} + engines: {node: '>=10.18'} + i18next@25.6.3: resolution: {integrity: sha512-AEQvoPDljhp67a1+NsnG/Wb1Nh6YoSvtrmeEd24sfGn3uujCtXCF3cXpr7ulhMywKNFF7p3TX1u2j7y+caLOJg==} peerDependencies: @@ -4235,6 +4701,9 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} + import-in-the-middle@1.15.0: + resolution: {integrity: sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -4265,6 +4734,10 @@ packages: resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} engines: {node: '>= 0.10'} + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -4519,6 +4992,9 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + js2xmlparser@4.0.2: + resolution: {integrity: sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==} + jsdoc-type-pratt-parser@4.1.0: resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} engines: {node: '>=12.0.0'} @@ -4560,9 +5036,19 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonwebtoken@9.0.3: + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} + engines: {node: '>=12', npm: '>=6'} + jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -4595,9 +5081,30 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} @@ -4608,6 +5115,9 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -4618,6 +5128,10 @@ packages: lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + lowercase-keys@3.0.0: resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -4629,6 +5143,10 @@ packages: resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} engines: {node: 20 || >=22} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + lucide-react@0.523.0: resolution: {integrity: sha512-rUjQoy7egZT9XYVXBK1je9ckBnNp7qzRZOhLQx5RcEp2dCGlXo+mv6vf7Am4LimEcFBJIIZzSGfgTqc9QCrPSw==} peerDependencies: @@ -4682,6 +5200,11 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} + memfs@4.56.4: + resolution: {integrity: sha512-GKqmHEFyFwccco9NmTEY38AemzpNLs5tKKxGfNpnLI/5D92NAr7STItdzTMeUlKdd3FjkE5w18TPLyKTb6MDVA==} + peerDependencies: + tslib: '2' + merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} @@ -4725,6 +5248,10 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} @@ -4770,6 +5297,9 @@ packages: engines: {node: '>= 14.0.0'} hasBin: true + module-details-from-path@1.0.4: + resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -4787,6 +5317,9 @@ packages: typescript: optional: true + multistream@3.1.0: + resolution: {integrity: sha512-zBgD3kn8izQAN/TaL1PCMv15vYpf+Vcrsfub06njuYVYlzUldzpopTlrEZ53pZVEbfn3Shtv7vRFoOv6LOV87Q==} + mute-stream@1.0.0: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -4819,6 +5352,10 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} + netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} @@ -4858,6 +5395,10 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + normalize-url@8.1.0: resolution: {integrity: sha512-X06Mfd/5aKsRHc0O0J5CUedwnPmnDtLF2+nq+KN9KSDlJHkPuh0JUviWjEWMe0SW/9TDdSLVPuk7L5gGTIA1/w==} engines: {node: '>=14.16'} @@ -4948,6 +5489,15 @@ packages: - which - write-file-atomic + o11y@258.22.0: + resolution: {integrity: sha512-HVWyrTgv1Tx0mk7XtZp2IE/ZaiBxcL07g62ptMDLFaTwAbvKnemveX8llcF4PmK66kZdZwD8E5Jd4fQvkNJBSw==} + + o11y_schema@254.44.0: + resolution: {integrity: sha512-qcwaZsTyl/NFRoyjXk5ZObfjb773wYM5wxDbHSJNkQDBxX96RjUS/Df0M1rSbsmJWPOuYiV4EkvIOEPMm8V86g==} + + o11y_schema@256.154.0: + resolution: {integrity: sha512-czvU/9cibyZptbr0gLJSM70U7zLlhWC2D2L5e9nOG84Wnqmn4F5YzVjrH1ZQzAzDbBbtbeU6WTS3F/SHqtMQ5g==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -5033,6 +5583,10 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + p-cancelable@3.0.0: resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} engines: {node: '>=12.20'} @@ -5065,6 +5619,14 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + pac-proxy-agent@7.2.0: + resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} + engines: {node: '>= 14'} + + pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -5186,9 +5748,16 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + pino-abstract-transport@1.2.0: + resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==} + pino-abstract-transport@2.0.0: resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + pino-pretty@11.3.0: + resolution: {integrity: sha512-oXwn7ICywaZPHmu3epHGU2oJX4nPmKvHvB/bwrJHlGcbEWaVcotkpyVHMKLKmiVryWYByNp0jpgAcXpFJDXJzA==} + hasBin: true + pino-pretty@13.1.2: resolution: {integrity: sha512-3cN0tCakkT4f3zo9RXDIhy6GTvtYD6bK4CRBLN9j3E/ePqN1tugAXD5rGVfoChW6s0hiek+eyYlLNqc/BG7vBQ==} hasBin: true @@ -5200,6 +5769,10 @@ packages: resolution: {integrity: sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==} hasBin: true + pino@9.14.0: + resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} + hasBin: true + pkce-challenge@4.1.0: resolution: {integrity: sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==} engines: {node: '>=16.20.0'} @@ -5267,16 +5840,30 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + protobufjs@7.2.6: + resolution: {integrity: sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==} + engines: {node: '>=12.0.0'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + proxy-agent@6.5.0: + resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} + engines: {node: '>= 14'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + pump@3.0.3: resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} @@ -5383,6 +5970,10 @@ packages: readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readable-stream@4.7.0: resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -5447,6 +6038,10 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-in-the-middle@7.5.2: + resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==} + engines: {node: '>=8.6.0'} + resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} @@ -5466,10 +6061,17 @@ packages: engines: {node: '>= 0.4'} hasBin: true + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + responselike@3.0.0: resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} engines: {node: '>=14.16'} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} @@ -5537,6 +6139,9 @@ packages: search-insights@2.17.3: resolution: {integrity: sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==} + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + secure-json-parse@4.1.0: resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} @@ -5560,6 +6165,10 @@ packages: sentence-case@3.0.4: resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} + sequin@0.1.1: + resolution: {integrity: sha512-hJWMZRwP75ocoBM+1/YaCsvS0j5MTPeBHJkS2/wruehl9xwtX30HlDF1Gt6UZ8HHHY8SJa2/IL+jo+JJCd59rA==} + engines: {node: '>=0.4.0'} + serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -5608,6 +6217,9 @@ packages: shiki@2.5.0: resolution: {integrity: sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==} + shimmer@1.2.1: + resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} + shx@0.3.4: resolution: {integrity: sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==} engines: {node: '>=6'} @@ -5629,6 +6241,9 @@ packages: resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -5644,9 +6259,21 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} + + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + sonic-boom@4.2.0: resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} @@ -5661,6 +6288,10 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -5699,6 +6330,9 @@ packages: stable-hash@0.0.5: resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + stack-chain@1.3.7: + resolution: {integrity: sha512-D8cWtWVdIe/jBA7v5p5Hwl5yOSOrmZPWDPe2KxQ5UAGD+nxbxU0lKXA4h85Ta6+qgdKVL3vUxsbIZjc1kBG7ug==} + statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} @@ -5840,6 +6474,12 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + thingies@2.5.0: + resolution: {integrity: sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw==} + engines: {node: '>=10.18'} + peerDependencies: + tslib: ^2 + thread-stream@3.1.0: resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} @@ -5872,6 +6512,12 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tree-dump@1.1.0: + resolution: {integrity: sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -5904,6 +6550,10 @@ packages: '@swc/wasm': optional: true + ts-retry-promise@0.8.1: + resolution: {integrity: sha512-+AHPUmAhr5bSRRK5CurE9kNH8gZlEHnCgusZ0zy2bjfatUBDX0h6vGQjiT0YrGwSDwRZmU+bapeX6mj55FOPvg==} + engines: {node: '>=6'} + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -6171,9 +6821,20 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} + web-vitals@3.5.2: + resolution: {integrity: sha512-c0rhqNcHXRkY/ogGDJQxZ9Im9D19hDihbzSQJrsioex+KnFgmMzBiy57Z1EjkhX/+OjyBpclDCzz2ITtjokFmg==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + websocket-driver@0.7.4: + resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} + engines: {node: '>=0.8.0'} + + websocket-extensions@0.1.4: + resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} + engines: {node: '>=0.8.0'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -6264,6 +6925,9 @@ packages: resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} engines: {node: '>=4.0'} + xmlcreate@2.0.4: + resolution: {integrity: sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -6329,6 +6993,9 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.3.5: + resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -6960,6 +7627,70 @@ snapshots: '@aws/lambda-invoke-store@0.1.1': {} + '@azure/abort-controller@2.1.2': + dependencies: + tslib: 2.8.1 + + '@azure/core-auth@1.10.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-auth@1.7.2': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-rest-pipeline@1.16.3': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-tracing@1.3.1': + dependencies: + tslib: 2.8.1 + + '@azure/core-util@1.13.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@typespec/ts-http-runtime': 0.3.2 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/logger@1.3.0': + dependencies: + '@typespec/ts-http-runtime': 0.3.2 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/opentelemetry-instrumentation-azure-sdk@1.0.0-beta.9': + dependencies: + '@azure/core-tracing': 1.3.1 + '@azure/logger': 1.3.0 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation': 0.200.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-web': 2.4.0(@opentelemetry/api@1.9.0) + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -7914,6 +8645,148 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@jsforce/jsforce-node@3.10.13': + dependencies: + '@sindresorhus/is': 4.6.0 + base64url: 3.0.1 + csv-parse: 5.6.0 + csv-stringify: 6.6.0 + faye: 1.4.1 + form-data: 4.0.5 + https-proxy-agent: 5.0.1 + multistream: 3.1.0 + node-fetch: 2.7.0 + xml2js: 0.6.2 + transitivePeerDependencies: + - encoding + - supports-color + + '@jsonjoy.com/base64@1.1.2(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/base64@17.65.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/buffers@1.2.1(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/buffers@17.65.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/codegen@1.0.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/codegen@17.65.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/fs-core@4.56.4(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-node-builtins': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.4(tslib@2.8.1) + thingies: 2.5.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-fsa@4.56.4(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-core': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.4(tslib@2.8.1) + thingies: 2.5.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-node-builtins@4.56.4(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/fs-node-to-fsa@4.56.4(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-fsa': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.4(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-node-utils@4.56.4(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-node-builtins': 4.56.4(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-node@4.56.4(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-core': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-print': 4.56.4(tslib@2.8.1) + glob-to-regex.js: 1.2.0(tslib@2.8.1) + thingies: 2.5.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-print@4.56.4(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-node-utils': 4.56.4(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-snapshot@4.56.4(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/buffers': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/json-pack': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/util': 17.65.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/json-pack@1.21.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/base64': 1.1.2(tslib@2.8.1) + '@jsonjoy.com/buffers': 1.2.1(tslib@2.8.1) + '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) + '@jsonjoy.com/json-pointer': 1.0.2(tslib@2.8.1) + '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) + hyperdyperid: 1.2.0 + thingies: 2.5.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/json-pack@17.65.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/base64': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/buffers': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/codegen': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/json-pointer': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/util': 17.65.0(tslib@2.8.1) + hyperdyperid: 1.2.0 + thingies: 2.5.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/json-pointer@1.0.2(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) + '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/json-pointer@17.65.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/util': 17.65.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/util@1.9.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/buffers': 1.2.1(tslib@2.8.1) + '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/util@17.65.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/buffers': 17.65.0(tslib@2.8.1) + '@jsonjoy.com/codegen': 17.65.0(tslib@2.8.1) + tslib: 2.8.1 + '@manypkg/find-root@1.1.0': dependencies: '@babel/runtime': 7.28.4 @@ -7930,6 +8803,8 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 + '@microsoft/applicationinsights-web-snippet@1.0.1': {} + '@modelcontextprotocol/inspector-cli@0.18.0(hono@4.11.1)(zod@3.25.76)': dependencies: '@modelcontextprotocol/sdk': 1.25.1(hono@4.11.1)(zod@3.25.76) @@ -8172,6 +9047,69 @@ snapshots: '@open-draft/until@2.1.0': {} + '@opentelemetry/api-logs@0.200.0': + dependencies: + '@opentelemetry/api': 1.9.0 + + '@opentelemetry/api@1.9.0': {} + + '@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.28.0 + + '@opentelemetry/core@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.39.0 + + '@opentelemetry/instrumentation@0.200.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.200.0 + '@types/shimmer': 1.2.0 + import-in-the-middle: 1.15.0 + require-in-the-middle: 7.5.2 + shimmer: 1.2.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.28.0 + + '@opentelemetry/resources@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.39.0 + + '@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.28.0 + + '@opentelemetry/sdk-trace-base@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.39.0 + + '@opentelemetry/sdk-trace-web@2.4.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.4.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.4.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/semantic-conventions@1.28.0': {} + + '@opentelemetry/semantic-conventions@1.39.0': {} + '@pinojs/redact@0.4.0': {} '@pkgjs/parseargs@0.11.0': @@ -8191,6 +9129,29 @@ snapshots: '@pnpm/network.ca-file': 1.0.2 config-chain: 1.1.13 + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + '@radix-ui/number@1.1.1': {} '@radix-ui/primitive@1.1.3': {} @@ -8598,8 +9559,59 @@ snapshots: '@rtsao/scc@1.1.0': {} + '@salesforce/core@8.24.3(tslib@2.8.1)': + dependencies: + '@jsforce/jsforce-node': 3.10.13 + '@salesforce/kit': 3.2.4 + '@salesforce/ts-types': 2.0.12 + ajv: 8.17.1 + change-case: 4.1.2 + fast-levenshtein: 3.0.0 + faye: 1.4.1 + form-data: 4.0.5 + js2xmlparser: 4.0.2 + jsonwebtoken: 9.0.3 + jszip: 3.10.1 + memfs: 4.56.4(tslib@2.8.1) + pino: 9.14.0 + pino-abstract-transport: 1.2.0 + pino-pretty: 11.3.0 + proper-lockfile: 4.1.2 + semver: 7.7.3 + ts-retry-promise: 0.8.1 + zod: 4.3.5 + transitivePeerDependencies: + - encoding + - supports-color + - tslib + '@salesforce/dev-config@4.3.2': {} + '@salesforce/kit@3.2.4': + dependencies: + '@salesforce/ts-types': 2.0.12 + + '@salesforce/o11y-reporter@1.7.0': + dependencies: + o11y: 258.22.0 + o11y_schema: 256.154.0 + + '@salesforce/telemetry@6.4.6(tslib@2.8.1)': + dependencies: + '@salesforce/core': 8.24.3(tslib@2.8.1) + '@salesforce/kit': 3.2.4 + '@salesforce/o11y-reporter': 1.7.0 + applicationinsights: 2.9.8 + got: 11.8.6 + proxy-agent: 6.5.0 + transitivePeerDependencies: + - applicationinsights-native-metrics + - encoding + - supports-color + - tslib + + '@salesforce/ts-types@2.0.12': {} + '@sec-ant/readable-stream@0.4.1': {} '@shikijs/core@2.5.0': @@ -9039,6 +10051,10 @@ snapshots: estraverse: 5.3.0 picomatch: 4.0.3 + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + '@szmarczak/http-timer@5.0.1': dependencies: defer-to-connect: 2.0.1 @@ -9047,6 +10063,8 @@ snapshots: dependencies: eslint: 9.39.1 + '@tootallnate/quickjs-emscripten@0.23.0': {} + '@tsconfig/node10@1.0.12': {} '@tsconfig/node12@1.0.11': {} @@ -9064,6 +10082,13 @@ snapshots: dependencies: '@types/readdir-glob': 1.1.5 + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.0.4 + '@types/keyv': 3.1.4 + '@types/node': 18.19.130 + '@types/responselike': 1.0.3 + '@types/chai@4.3.20': {} '@types/estree@1.0.8': {} @@ -9080,6 +10105,10 @@ snapshots: '@types/json5@0.0.29': {} + '@types/keyv@3.1.4': + dependencies: + '@types/node': 18.19.130 + '@types/linkify-it@5.0.0': {} '@types/markdown-it@14.1.2': @@ -9115,6 +10144,12 @@ snapshots: dependencies: '@types/node': 18.19.130 + '@types/responselike@1.0.3': + dependencies: + '@types/node': 18.19.130 + + '@types/shimmer@1.2.0': {} + '@types/sinon@21.0.0': dependencies: '@types/sinonjs__fake-timers': 15.0.1 @@ -9226,6 +10261,14 @@ snapshots: '@typescript-eslint/types': 8.46.4 eslint-visitor-keys: 4.2.1 + '@typespec/ts-http-runtime@0.3.2': + dependencies: + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + '@ungap/structured-clone@1.3.0': {} '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -9402,6 +10445,10 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -9412,6 +10459,12 @@ snapshots: acorn@8.15.0: {} + agent-base@6.0.2: + dependencies: + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + agent-base@7.1.4: {} ajv-formats@3.0.1(ajv@8.17.1): @@ -9478,6 +10531,23 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + applicationinsights@2.9.8: + dependencies: + '@azure/core-auth': 1.7.2 + '@azure/core-rest-pipeline': 1.16.3 + '@azure/opentelemetry-instrumentation-azure-sdk': 1.0.0-beta.9 + '@microsoft/applicationinsights-web-snippet': 1.0.1 + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.39.0 + cls-hooked: 4.2.2 + continuation-local-storage: 3.2.1 + diagnostic-channel: 1.1.1 + diagnostic-channel-publishers: 1.0.8(diagnostic-channel@1.1.1) + transitivePeerDependencies: + - supports-color + archiver-utils@5.0.2: dependencies: glob: 10.5.0 @@ -9567,16 +10637,33 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + asap@2.0.6: {} + assertion-error@1.1.0: {} + ast-types@0.13.4: + dependencies: + tslib: 2.8.1 + async-function@1.0.0: {} + async-hook-jl@1.7.6: + dependencies: + stack-chain: 1.3.7 + + async-listener@0.6.10: + dependencies: + semver: 5.7.2 + shimmer: 1.2.1 + async-retry@1.3.3: dependencies: retry: 0.13.1 async@3.2.6: {} + asynckit@0.4.0: {} + atomic-sleep@1.0.0: {} available-typed-arrays@1.0.7: @@ -9591,10 +10678,14 @@ snapshots: base64-js@1.5.1: {} + base64url@3.0.1: {} + baseline-browser-mapping@2.8.26: {} baseline-browser-mapping@2.9.15: {} + basic-ftp@5.1.0: {} + better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 @@ -9644,6 +10735,8 @@ snapshots: buffer-crc32@1.0.0: {} + buffer-equal-constant-time@1.0.1: {} + buffer@6.0.3: dependencies: base64-js: 1.5.1 @@ -9677,6 +10770,8 @@ snapshots: yargs: 17.7.2 yargs-parser: 21.1.1 + cacheable-lookup@5.0.4: {} + cacheable-lookup@7.0.0: {} cacheable-request@10.2.14: @@ -9689,6 +10784,16 @@ snapshots: normalize-url: 8.1.0 responselike: 3.0.0 + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.2.0 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -9791,6 +10896,8 @@ snapshots: ci-info@4.3.1: {} + cjs-module-lexer@1.4.3: {} + class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 @@ -9840,6 +10947,16 @@ snapshots: strip-ansi: 7.1.2 wrap-ansi: 9.0.2 + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + + cls-hooked@4.2.2: + dependencies: + async-hook-jl: 1.7.6 + emitter-listener: 1.1.2 + semver: 5.7.2 + clsx@2.1.1: {} cmdk@1.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): @@ -9864,6 +10981,10 @@ snapshots: colorette@2.0.20: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} commander@13.1.0: {} @@ -9908,6 +11029,11 @@ snapshots: content-type@1.0.5: {} + continuation-local-storage@3.2.1: + dependencies: + async-listener: 0.6.10 + emitter-listener: 1.1.2 + convert-source-map@2.0.0: {} cookie-signature@1.2.2: {} @@ -9946,10 +11072,20 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + csprng@0.1.2: + dependencies: + sequin: 0.1.1 + csstype@3.2.3: {} + csv-parse@5.6.0: {} + + csv-stringify@6.6.0: {} + data-uri-to-buffer@4.0.1: {} + data-uri-to-buffer@6.0.2: {} + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -10023,6 +11159,14 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + degenerator@5.0.1: + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + + delayed-stream@1.0.0: {} + depd@2.0.0: {} dequal@2.0.3: {} @@ -10039,6 +11183,14 @@ snapshots: dependencies: dequal: 2.0.3 + diagnostic-channel-publishers@1.0.8(diagnostic-channel@1.1.1): + dependencies: + diagnostic-channel: 1.1.1 + + diagnostic-channel@1.1.1: + dependencies: + semver: 7.7.3 + diff@4.0.2: {} diff@5.2.0: {} @@ -10068,6 +11220,10 @@ snapshots: eastasianwidth@0.2.0: {} + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + ee-first@1.1.1: {} ejs@3.1.10: @@ -10076,6 +11232,10 @@ snapshots: electron-to-chromium@1.5.250: {} + emitter-listener@1.1.2: + dependencies: + shimmer: 1.2.1 + emoji-regex-xs@1.0.0: {} emoji-regex@10.6.0: {} @@ -10255,6 +11415,14 @@ snapshots: escape-string-regexp@4.0.0: {} + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + eslint-compat-utils@0.5.1(eslint@9.39.1): dependencies: eslint: 9.39.1 @@ -10699,6 +11867,19 @@ snapshots: dependencies: reusify: 1.1.0 + faye-websocket@0.11.4: + dependencies: + websocket-driver: 0.7.4 + + faye@1.4.1: + dependencies: + asap: 2.0.6 + csprng: 0.1.2 + faye-websocket: 0.11.4 + safe-buffer: 5.2.1 + tough-cookie: 6.0.0 + tunnel-agent: 0.6.0 + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -10773,6 +11954,14 @@ snapshots: form-data-encoder@2.1.4: {} + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.18 + formdata-polyfill@4.0.10: dependencies: fetch-blob: 3.2.0 @@ -10845,6 +12034,10 @@ snapshots: get-stdin@9.0.0: {} + get-stream@5.2.0: + dependencies: + pump: 3.0.3 + get-stream@6.0.1: {} get-stream@9.0.1: @@ -10862,6 +12055,14 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-uri@6.0.5: + dependencies: + basic-ftp: 5.1.0 + data-uri-to-buffer: 6.0.2 + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + git-hooks-list@3.2.0: {} github-slugger@2.0.0: {} @@ -10874,6 +12075,10 @@ snapshots: dependencies: is-glob: 4.0.3 + glob-to-regex.js@1.2.0(tslib@2.8.1): + dependencies: + tslib: 2.8.1 + glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -10934,6 +12139,20 @@ snapshots: gopd@1.2.0: {} + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + got@13.0.0: dependencies: '@sindresorhus/is': 5.6.0 @@ -11044,11 +12263,32 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 + http-parser-js@0.5.10: {} + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + http2-wrapper@2.2.1: dependencies: quick-lru: 5.1.1 resolve-alpn: 1.2.1 + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + https-proxy-agent@7.0.6(supports-color@10.2.2): dependencies: agent-base: 7.1.4 @@ -11060,6 +12300,8 @@ snapshots: human-signals@8.0.1: {} + hyperdyperid@1.2.0: {} + i18next@25.6.3(typescript@5.9.3): dependencies: '@babel/runtime': 7.28.4 @@ -11087,6 +12329,13 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + import-in-the-middle@1.15.0: + dependencies: + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) + cjs-module-lexer: 1.4.3 + module-details-from-path: 1.0.4 + imurmurhash@0.1.4: {} indent-string@4.0.0: {} @@ -11110,6 +12359,8 @@ snapshots: interpret@1.4.0: {} + ip-address@10.1.0: {} + ipaddr.js@1.9.1: {} is-array-buffer@3.0.5: @@ -11334,6 +12585,10 @@ snapshots: dependencies: argparse: 2.0.1 + js2xmlparser@4.0.2: + dependencies: + xmlcreate: 2.0.4 + jsdoc-type-pratt-parser@4.1.0: {} jsesc@0.5.0: {} @@ -11362,6 +12617,19 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonwebtoken@9.0.3: + dependencies: + jws: 4.0.1 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.7.3 + jszip@3.10.1: dependencies: lie: 3.3.0 @@ -11369,6 +12637,17 @@ snapshots: readable-stream: 2.3.8 setimmediate: 1.0.5 + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -11402,8 +12681,22 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.includes@4.3.0: {} + + lodash.isboolean@3.0.3: {} + + lodash.isinteger@4.0.4: {} + + lodash.isnumber@3.0.3: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + lodash.merge@4.6.2: {} + lodash.once@4.1.1: {} + lodash.startcase@4.4.0: {} lodash@4.17.21: {} @@ -11413,6 +12706,8 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + long@5.3.2: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -11425,12 +12720,16 @@ snapshots: dependencies: tslib: 2.8.1 + lowercase-keys@2.0.0: {} + lowercase-keys@3.0.0: {} lru-cache@10.4.3: {} lru-cache@11.2.2: {} + lru-cache@7.18.3: {} + lucide-react@0.523.0(react@18.3.1): dependencies: react: 18.3.1 @@ -11491,6 +12790,23 @@ snapshots: media-typer@1.1.0: {} + memfs@4.56.4(tslib@2.8.1): + dependencies: + '@jsonjoy.com/fs-core': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-fsa': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-node': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-node-to-fsa': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-print': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/fs-snapshot': 4.56.4(tslib@2.8.1) + '@jsonjoy.com/json-pack': 1.21.0(tslib@2.8.1) + '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) + glob-to-regex.js: 1.2.0(tslib@2.8.1) + thingies: 2.5.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 + merge-descriptors@2.0.0: {} merge2@1.4.1: {} @@ -11529,6 +12845,8 @@ snapshots: dependencies: mime-db: 1.54.0 + mimic-response@1.0.1: {} + mimic-response@3.1.0: {} mimic-response@4.0.0: {} @@ -11582,6 +12900,8 @@ snapshots: yargs-parser: 20.2.9 yargs-unparser: 2.0.0 + module-details-from-path@1.0.4: {} + mri@1.2.0: {} ms@2.1.3: {} @@ -11611,6 +12931,11 @@ snapshots: transitivePeerDependencies: - '@types/node' + multistream@3.1.0: + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + mute-stream@1.0.0: {} mute-stream@3.0.0: {} @@ -11631,6 +12956,8 @@ snapshots: negotiator@1.0.0: {} + netmask@2.0.2: {} + no-case@3.0.4: dependencies: lower-case: 2.0.2 @@ -11672,6 +12999,8 @@ snapshots: normalize-path@3.0.0: {} + normalize-url@6.1.0: {} + normalize-url@8.1.0: {} npm-package-arg@11.0.3: @@ -11692,6 +13021,16 @@ snapshots: npm@10.9.4: {} + o11y@258.22.0: + dependencies: + o11y_schema: 254.44.0 + protobufjs: 7.2.6 + web-vitals: 3.5.2 + + o11y_schema@254.44.0: {} + + o11y_schema@256.154.0: {} + object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -11858,6 +13197,8 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 + p-cancelable@2.1.1: {} + p-cancelable@3.0.0: {} p-filter@2.1.0: @@ -11884,6 +13225,24 @@ snapshots: p-try@2.2.0: {} + pac-proxy-agent@7.2.0: + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.4 + debug: 4.4.3(supports-color@10.2.2) + get-uri: 6.0.5 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + pac-resolver@7.0.1: + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + package-json-from-dist@1.0.1: {} package-manager-detector@0.2.11: @@ -11989,10 +13348,32 @@ snapshots: pify@4.0.1: {} + pino-abstract-transport@1.2.0: + dependencies: + readable-stream: 4.7.0 + split2: 4.2.0 + pino-abstract-transport@2.0.0: dependencies: split2: 4.2.0 + pino-pretty@11.3.0: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pump: 3.0.3 + readable-stream: 4.7.0 + secure-json-parse: 2.7.0 + sonic-boom: 4.2.0 + strip-json-comments: 3.1.1 + pino-pretty@13.1.2: dependencies: colorette: 2.0.20 @@ -12025,6 +13406,20 @@ snapshots: sonic-boom: 4.2.0 thread-stream: 3.1.0 + pino@9.14.0: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + pkce-challenge@4.1.0: {} pkce-challenge@5.0.1: {} @@ -12067,15 +13462,51 @@ snapshots: process@0.11.10: {} + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + property-information@7.1.0: {} proto-list@1.2.4: {} + protobufjs@7.2.6: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 18.19.130 + long: 5.3.2 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-agent@6.5.0: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3(supports-color@10.2.2) + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + lru-cache: 7.18.3 + pac-proxy-agent: 7.2.0 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + proxy-from-env@1.1.0: {} + pump@3.0.3: dependencies: end-of-stream: 1.4.5 @@ -12180,6 +13611,12 @@ snapshots: string_decoder: 1.1.1 util-deprecate: 1.0.2 + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + readable-stream@4.7.0: dependencies: abort-controller: 3.0.0 @@ -12250,6 +13687,14 @@ snapshots: require-from-string@2.0.2: {} + require-in-the-middle@7.5.2: + dependencies: + debug: 4.4.3(supports-color@10.2.2) + module-details-from-path: 1.0.4 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + resolve-alpn@1.2.1: {} resolve-from@4.0.0: {} @@ -12264,10 +13709,16 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + responselike@3.0.0: dependencies: lowercase-keys: 3.0.0 + retry@0.12.0: {} + retry@0.13.1: {} rettime@0.7.0: {} @@ -12359,6 +13810,8 @@ snapshots: search-insights@2.17.3: {} + secure-json-parse@2.7.0: {} + secure-json-parse@4.1.0: {} semver@5.7.2: {} @@ -12389,6 +13842,8 @@ snapshots: tslib: 2.8.1 upper-case-first: 2.0.2 + sequin@0.1.1: {} + serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 @@ -12463,6 +13918,8 @@ snapshots: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 + shimmer@1.2.1: {} + shx@0.3.4: dependencies: minimist: 1.2.8 @@ -12496,6 +13953,8 @@ snapshots: side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 + signal-exit@3.0.7: {} + signal-exit@4.1.0: {} sinon@21.0.1: @@ -12512,11 +13971,26 @@ snapshots: slash@3.0.0: {} + smart-buffer@4.2.0: {} + snake-case@3.0.4: dependencies: dot-case: 3.0.4 tslib: 2.8.1 + socks-proxy-agent@8.0.5: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3(supports-color@10.2.2) + socks: 2.8.7 + transitivePeerDependencies: + - supports-color + + socks@2.8.7: + dependencies: + ip-address: 10.1.0 + smart-buffer: 4.2.0 + sonic-boom@4.2.0: dependencies: atomic-sleep: 1.0.0 @@ -12536,6 +14010,9 @@ snapshots: source-map-js@1.2.1: {} + source-map@0.6.1: + optional: true + space-separated-tokens@2.0.2: {} spawn-rx@5.1.2: @@ -12577,6 +14054,8 @@ snapshots: stable-hash@0.0.5: {} + stack-chain@1.3.7: {} + statuses@2.0.2: {} stop-iteration-iterator@1.1.0: @@ -12735,6 +14214,10 @@ snapshots: dependencies: any-promise: 1.3.0 + thingies@2.5.0(tslib@2.8.1): + dependencies: + tslib: 2.8.1 + thread-stream@3.1.0: dependencies: real-require: 0.2.0 @@ -12764,6 +14247,10 @@ snapshots: tr46@0.0.3: {} + tree-dump@1.1.0(tslib@2.8.1): + dependencies: + tslib: 2.8.1 + tree-kill@1.2.2: {} trim-lines@3.0.1: {} @@ -12795,6 +14282,8 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + ts-retry-promise@0.8.1: {} + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -13104,8 +14593,18 @@ snapshots: web-streams-polyfill@3.3.3: {} + web-vitals@3.5.2: {} + webidl-conversions@3.0.1: {} + websocket-driver@0.7.4: + dependencies: + http-parser-js: 0.5.10 + safe-buffer: 5.2.1 + websocket-extensions: 0.1.4 + + websocket-extensions@0.1.4: {} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -13214,6 +14713,8 @@ snapshots: xmlbuilder@11.0.1: {} + xmlcreate@2.0.4: {} + y18n@5.0.8: {} yaml-ast-parser@0.0.43: {} @@ -13273,4 +14774,6 @@ snapshots: zod@3.25.76: {} + zod@4.3.5: {} + zwitch@2.0.4: {}