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