@adaptic/utils 0.1.47 → 0.1.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -17307,6 +17307,198 @@ var index = /*#__PURE__*/Object.freeze({
17307
17307
  getUtilsTunedTradingPolicy: getUtilsTunedTradingPolicy
17308
17308
  });
17309
17309
 
17310
+ /**
17311
+ * API credential validation utilities
17312
+ * Provides fast, synchronous validation of API credentials before making requests
17313
+ */
17314
+ /**
17315
+ * Validates Alpaca API credentials
17316
+ * @param auth - Authentication object containing API key and secret
17317
+ * @param options - Validation options
17318
+ * @param options.throwOnMissing - If false, missing credentials will log a warning instead of throwing (default: true)
17319
+ * @throws {Error} If credentials are invalid (when throwOnMissing is true)
17320
+ * @returns {boolean} True if credentials are valid, false if missing (when throwOnMissing is false)
17321
+ */
17322
+ function validateAlpacaCredentials(auth, options = { throwOnMissing: true }) {
17323
+ const { throwOnMissing = true } = options;
17324
+ // Check for missing or empty API key
17325
+ if (!auth.apiKey ||
17326
+ typeof auth.apiKey !== "string" ||
17327
+ auth.apiKey.trim().length === 0) {
17328
+ if (throwOnMissing) {
17329
+ throw new Error("Invalid Alpaca API key: must be a non-empty string");
17330
+ }
17331
+ console.warn("[AlpacaAPI] API key not configured. Market data features will be unavailable.");
17332
+ return false;
17333
+ }
17334
+ // Check for missing or empty API secret
17335
+ if (!auth.apiSecret ||
17336
+ typeof auth.apiSecret !== "string" ||
17337
+ auth.apiSecret.trim().length === 0) {
17338
+ if (throwOnMissing) {
17339
+ throw new Error("Invalid Alpaca API secret: must be a non-empty string");
17340
+ }
17341
+ console.warn("[AlpacaAPI] API secret not configured. Market data features will be unavailable.");
17342
+ return false;
17343
+ }
17344
+ // Alpaca keys are typically 20+ characters
17345
+ if (auth.apiKey.length < 10) {
17346
+ if (throwOnMissing) {
17347
+ throw new Error("Alpaca API key appears to be too short");
17348
+ }
17349
+ console.warn("[AlpacaAPI] API key appears to be too short.");
17350
+ return false;
17351
+ }
17352
+ return true;
17353
+ }
17354
+ /**
17355
+ * Validates Massive API key
17356
+ * @param apiKey - Massive API key
17357
+ * @throws {Error} If API key is invalid or missing
17358
+ */
17359
+ function validateMassiveApiKey(apiKey) {
17360
+ if (!apiKey || typeof apiKey !== "string" || apiKey.trim().length === 0) {
17361
+ throw new Error("Invalid Massive API key: must be a non-empty string");
17362
+ }
17363
+ }
17364
+ /**
17365
+ * Validates Alpha Vantage API key
17366
+ * @param apiKey - Alpha Vantage API key
17367
+ * @throws {Error} If API key is invalid or missing
17368
+ */
17369
+ function validateAlphaVantageApiKey(apiKey) {
17370
+ if (!apiKey || typeof apiKey !== "string" || apiKey.trim().length === 0) {
17371
+ throw new Error("Invalid Alpha Vantage API key: must be a non-empty string");
17372
+ }
17373
+ }
17374
+
17375
+ /**
17376
+ * HTTP connection pooling and keep-alive configuration.
17377
+ *
17378
+ * Node.js (>=20) uses undici as its built-in fetch implementation, which
17379
+ * automatically maintains an internal connection pool with keep-alive enabled
17380
+ * by default. This module provides:
17381
+ *
17382
+ * 1. Explicit documentation of the connection pooling behavior
17383
+ * 2. A configured HTTP Agent for use with node:http/node:https if needed
17384
+ * 3. Verification utilities to confirm keep-alive is active
17385
+ *
17386
+ * ## Connection Pooling Behavior
17387
+ *
17388
+ * **Native fetch (undici):** The global `fetch()` used throughout this package
17389
+ * uses Node.js built-in undici which maintains persistent connections by default.
17390
+ * Connections are kept alive and reused across requests to the same origin.
17391
+ * No additional configuration is needed for fetch-based API calls.
17392
+ *
17393
+ * **Alpaca SDK (@alpacahq/alpaca-trade-api):** The SDK uses its own internal
17394
+ * HTTP client with connection reuse. The SDK is configured through `AlpacaClient`
17395
+ * in `src/alpaca/client.ts` via the `createAlpacaClient()` factory which caches
17396
+ * client instances by API key + account type.
17397
+ *
17398
+ * **WebSocket connections:** Trading API and market data WebSocket connections
17399
+ * are long-lived persistent connections managed by `AlpacaTradingAPI` and
17400
+ * `AlpacaMarketDataAPI` respectively.
17401
+ *
17402
+ * ## API Client Summary
17403
+ *
17404
+ * | API Client | Transport | Keep-Alive | Connection Reuse |
17405
+ * |------------|-----------|------------|------------------|
17406
+ * | Alpaca Trading (direct) | fetch() | Built-in | Undici pool |
17407
+ * | Alpaca Market Data | fetch() | Built-in | Undici pool |
17408
+ * | Alpaca SDK | internal | Built-in | SDK managed |
17409
+ * | Massive.com | fetch() via fetchWithRetry | Built-in | Undici pool |
17410
+ * | Alpha Vantage | fetch() | Built-in | Undici pool |
17411
+ * | WebSocket (Trading) | ws | Persistent | Long-lived |
17412
+ * | WebSocket (Market Data) | ws | Persistent | Long-lived |
17413
+ */
17414
+ /**
17415
+ * Default keep-alive configuration values.
17416
+ * These are applied when creating explicit HTTP agents for non-fetch use cases.
17417
+ */
17418
+ const KEEP_ALIVE_DEFAULTS = {
17419
+ /** Enable keep-alive connections */
17420
+ keepAlive: true,
17421
+ /** Initial delay before sending keep-alive probes (in milliseconds) */
17422
+ keepAliveMsecs: 60000,
17423
+ /** Maximum number of sockets per host */
17424
+ maxSockets: 50,
17425
+ /** Maximum total number of sockets */
17426
+ maxTotalSockets: 256,
17427
+ /** Maximum number of free (idle) sockets per host */
17428
+ maxFreeSockets: 10,
17429
+ /** Socket timeout for idle connections (in milliseconds) */
17430
+ timeout: 60000,
17431
+ };
17432
+ /**
17433
+ * Pre-configured HTTP agent with keep-alive enabled.
17434
+ * Use this when making requests through node:http (not needed for fetch).
17435
+ */
17436
+ const httpAgent = new require$$2.Agent({
17437
+ keepAlive: KEEP_ALIVE_DEFAULTS.keepAlive,
17438
+ keepAliveMsecs: KEEP_ALIVE_DEFAULTS.keepAliveMsecs,
17439
+ maxSockets: KEEP_ALIVE_DEFAULTS.maxSockets,
17440
+ maxTotalSockets: KEEP_ALIVE_DEFAULTS.maxTotalSockets,
17441
+ maxFreeSockets: KEEP_ALIVE_DEFAULTS.maxFreeSockets,
17442
+ timeout: KEEP_ALIVE_DEFAULTS.timeout,
17443
+ });
17444
+ /**
17445
+ * Pre-configured HTTPS agent with keep-alive enabled.
17446
+ * Use this when making requests through node:https (not needed for fetch).
17447
+ */
17448
+ const httpsAgent = new require$$1$1.Agent({
17449
+ keepAlive: KEEP_ALIVE_DEFAULTS.keepAlive,
17450
+ keepAliveMsecs: KEEP_ALIVE_DEFAULTS.keepAliveMsecs,
17451
+ maxSockets: KEEP_ALIVE_DEFAULTS.maxSockets,
17452
+ maxTotalSockets: KEEP_ALIVE_DEFAULTS.maxTotalSockets,
17453
+ maxFreeSockets: KEEP_ALIVE_DEFAULTS.maxFreeSockets,
17454
+ timeout: KEEP_ALIVE_DEFAULTS.timeout,
17455
+ });
17456
+ /**
17457
+ * Get the connection pool status for an HTTP/HTTPS agent.
17458
+ * Useful for monitoring and debugging connection reuse.
17459
+ *
17460
+ * @param agent - The HTTP/HTTPS agent to inspect
17461
+ * @param name - A human-readable name for the agent
17462
+ * @returns Connection pool status information
17463
+ */
17464
+ function getAgentPoolStatus(agent, name = "default") {
17465
+ const sockets = agent.sockets || {};
17466
+ const freeSockets = agent.freeSockets || {};
17467
+ const requests = agent.requests || {};
17468
+ const activeSockets = Object.values(sockets).reduce((sum, arr) => sum + (arr ? arr.length : 0), 0);
17469
+ const freeSocketCount = Object.values(freeSockets).reduce((sum, arr) => sum + (arr ? arr.length : 0), 0);
17470
+ const pendingRequests = Object.values(requests).reduce((sum, arr) => sum + (arr ? arr.length : 0), 0);
17471
+ return {
17472
+ name,
17473
+ keepAlive: agent.keepAlive ?? false,
17474
+ activeSockets,
17475
+ freeSockets: freeSocketCount,
17476
+ pendingRequests,
17477
+ maxSockets: agent.maxSockets,
17478
+ maxFreeSockets: agent.maxFreeSockets,
17479
+ };
17480
+ }
17481
+ /**
17482
+ * Verifies that keep-alive is properly configured for the Node.js built-in fetch.
17483
+ * Node.js >= 20 uses undici internally, which has keep-alive enabled by default.
17484
+ *
17485
+ * @returns Object indicating whether keep-alive is expected to be active
17486
+ */
17487
+ function verifyFetchKeepAlive() {
17488
+ const nodeVersion = process.version;
17489
+ const majorVersion = parseInt(nodeVersion.slice(1).split(".")[0], 10);
17490
+ // Node.js >= 18 has built-in fetch via undici
17491
+ // Node.js >= 20 has mature undici with connection pooling
17492
+ const undiciBuiltIn = majorVersion >= 18;
17493
+ const keepAliveExpected = majorVersion >= 18;
17494
+ return {
17495
+ supported: true,
17496
+ nodeVersion,
17497
+ undiciBuiltIn,
17498
+ keepAliveExpected,
17499
+ };
17500
+ }
17501
+
17310
17502
  // Export factory functions for easier instantiation
17311
17503
  const createAlpacaTradingAPI = (credentials) => {
17312
17504
  return new AlpacaTradingAPI(credentials);
@@ -17455,5 +17647,5 @@ const adaptic = {
17455
17647
  };
17456
17648
  const adptc = adaptic;
17457
17649
 
17458
- export { AlpacaMarketDataAPI, AlpacaTradingAPI, AssetAllocationEngine, DEFAULT_CACHE_OPTIONS, DEFAULT_TRADING_POLICY_UTILS_TUNED, StampedeProtectedCache, adaptic, adptc, createAlpacaMarketDataAPI, createAlpacaTradingAPI, createStampedeProtectedCache, generateOptimalAllocation, getDefaultRiskProfile, getUtilsTunedTradingPolicy, index as tradingPolicy };
17650
+ export { AlpacaMarketDataAPI, AlpacaTradingAPI, AssetAllocationEngine, DEFAULT_CACHE_OPTIONS, DEFAULT_TRADING_POLICY_UTILS_TUNED, KEEP_ALIVE_DEFAULTS, StampedeProtectedCache, adaptic, adptc, createAlpacaMarketDataAPI, createAlpacaTradingAPI, createStampedeProtectedCache, generateOptimalAllocation, getAgentPoolStatus, getDefaultRiskProfile, getUtilsTunedTradingPolicy, httpAgent, httpsAgent, index as tradingPolicy, validateAlpacaCredentials, validateAlphaVantageApiKey, validateMassiveApiKey, verifyFetchKeepAlive };
17459
17651
  //# sourceMappingURL=index.mjs.map