@milaboratories/pl-client 2.14.0 → 2.15.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"config.cjs","sources":["../../src/core/config.ts"],"sourcesContent":["import type { ProxySettings } from '@milaboratories/pl-http';\nimport type { ExponentialBackoffRetryOptions } from '@milaboratories/ts-helpers';\n\n/** Base configuration structure for PL client */\nexport interface PlClientConfig {\n /** Port and host of remote pl server */\n hostAndPort: string;\n\n /** If set, client will expose a nested object under a field with name `alternative_root_${alternativeRoot}` as a\n * client root. */\n alternativeRoot?: string;\n\n /** If true, client will establish tls connection to the server, using default\n * CA of node instance. */\n // Not implementing custom ssl validation logic for now.\n // Implementing it in a correct way is really nontrivial thing,\n // real use-cases should be considered.\n ssl: boolean;\n\n /** Default timeout in milliseconds for unary calls, like ping and login. */\n defaultRequestTimeout: number;\n\n /** Default timeout in milliseconds for read-write transaction, should be\n * adjusted for long round-trip or low bandwidth connections. */\n defaultRWTransactionTimeout: number;\n /** Default timeout in milliseconds for read-only transaction, should be\n * adjusted for long round-trip or low bandwidth connections. */\n defaultROTransactionTimeout: number;\n\n /** Controls what TTL will be requested from the server, when new JWT token\n * is requested. */\n authTTLSeconds: number;\n /** If token is older than this time, it will be refreshed regardless of its\n * expiration time. */\n authMaxRefreshSeconds: number;\n\n /** Proxy server URL to use for pl connection. */\n grpcProxy?: string;\n /** Proxy server config to use for http connections of pl drivers, like file\n * downloading. */\n httpProxy?: string | ProxySettings;\n\n /** Username extracted from pl URL. Ignored by {@link PlClient}, picked up by {@link defaultPlClient}. */\n user?: string;\n /** Password extracted from pl URL. Ignored by {@link PlClient}, picked up by {@link defaultPlClient}. */\n password?: string;\n\n /** Artificial delay introduced after write transactions completion, to\n * somewhat throttle the load on pl. Delay introduced after sync, if requested. */\n txDelay: number;\n\n /** Last resort measure to solve complicated race conditions in pl. */\n forceSync: boolean;\n\n /** Maximal number of bytes of resource state to cache */\n maxCacheBytes: number;\n\n //\n // Retry\n //\n\n /**\n * What type of backoff strategy to use in transaction retries\n * (pl uses optimistic transaction model with regular retries in write transactions)\n */\n retryBackoffAlgorithm: 'exponential' | 'linear';\n\n /** Maximal number of attempts in */\n retryMaxAttempts: number;\n\n /** Delay after first failed attempt, in ms. */\n retryInitialDelay: number;\n\n /** Each time delay will be multiplied by this number (1.5 means plus on 50% each attempt) */\n retryExponentialBackoffMultiplier: number;\n\n /** [used only for ] This value will be added to the delay from the previous step, in ms */\n retryLinearBackoffStep: number;\n\n /** Value from 0 to 1, determine level of randomness to introduce to the backoff delays sequence. (0 meaning no randomness) */\n retryJitter: number;\n}\n\nexport const DEFAULT_REQUEST_TIMEOUT = 5_000;\nexport const DEFAULT_RO_TX_TIMEOUT = 300_000;\nexport const DEFAULT_RW_TX_TIMEOUT = 60_000;\nexport const DEFAULT_TOKEN_TTL_SECONDS = 31 * 24 * 60 * 60;\nexport const DEFAULT_AUTH_MAX_REFRESH = 12 * 24 * 60 * 60;\n\nexport const DEFAULT_MAX_CACHE_BYTES = 128_000_000; // 128 Mb\n\nexport const DEFAULT_RETRY_BACKOFF_ALGORITHM = 'exponential';\nexport const DEFAULT_RETRY_MAX_ATTEMPTS = 21; // 1st attempt + 20 retries\nexport const DEFAULT_RETRY_INITIAL_DELAY = 20; // 20 ms * <jitter> of sleep after first failure\nexport const DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER = 1.5; // + 50% on each round\nexport const DEFAULT_RETRY_LINEAR_BACKOFF_STEP = 50; // + 50 ms\nexport const DEFAULT_RETRY_JITTER = 0.3; // 30%\n\nexport const DefaultRetryOptions: ExponentialBackoffRetryOptions = {\n type: 'exponentialBackoff',\n maxAttempts: DEFAULT_RETRY_MAX_ATTEMPTS,\n initialDelay: DEFAULT_RETRY_INITIAL_DELAY,\n backoffMultiplier: DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n jitter: DEFAULT_RETRY_JITTER,\n};\n\ntype PlConfigOverrides = Partial<\n Pick<\n PlClientConfig,\n | 'ssl'\n | 'defaultRequestTimeout'\n | 'defaultROTransactionTimeout'\n | 'defaultRWTransactionTimeout'\n | 'httpProxy'\n | 'grpcProxy'\n >\n>;\n\nfunction parseInt(s: string | null | undefined): number | undefined {\n if (!s) return undefined;\n const num = Number(s);\n if (Number.isNaN(num)) throw new Error(`Can't parse number: ${s}`);\n return num;\n}\n\n/** Parses pl url and creates a config object that can be passed to\n * {@link PlClient} of {@link UnauthenticatedPlClient}. */\nexport function plAddressToConfig(\n address: string,\n overrides: PlConfigOverrides = {},\n): PlClientConfig {\n if (address.indexOf('://') === -1)\n // non-url address\n return {\n hostAndPort: address,\n ssl: false,\n defaultRequestTimeout: DEFAULT_REQUEST_TIMEOUT,\n defaultROTransactionTimeout: DEFAULT_RO_TX_TIMEOUT,\n defaultRWTransactionTimeout: DEFAULT_RW_TX_TIMEOUT,\n authTTLSeconds: DEFAULT_TOKEN_TTL_SECONDS,\n authMaxRefreshSeconds: DEFAULT_AUTH_MAX_REFRESH,\n txDelay: 0,\n forceSync: false,\n\n maxCacheBytes: DEFAULT_MAX_CACHE_BYTES,\n\n retryBackoffAlgorithm: DEFAULT_RETRY_BACKOFF_ALGORITHM,\n retryMaxAttempts: DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay: DEFAULT_RETRY_INITIAL_DELAY,\n retryExponentialBackoffMultiplier: DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n retryLinearBackoffStep: DEFAULT_RETRY_LINEAR_BACKOFF_STEP,\n retryJitter: DEFAULT_RETRY_JITTER,\n\n ...overrides,\n };\n\n const url = new URL(address);\n\n if (\n url.protocol !== 'https:'\n && url.protocol !== 'http:'\n && url.protocol !== 'grpc:'\n && url.protocol !== 'tls:'\n )\n throw new Error(`Unexpected URL schema: ${url.protocol}`);\n\n if (url.pathname !== '/' && url.pathname !== '')\n throw new Error(`Unexpected URL path: ${url.pathname}`);\n\n return {\n hostAndPort: url.host, // this also includes port\n alternativeRoot: url.searchParams.get('alternative-root') ?? undefined,\n ssl: url.protocol === 'https:' || url.protocol === 'tls:',\n defaultRequestTimeout:\n parseInt(url.searchParams.get('request-timeout')) ?? DEFAULT_REQUEST_TIMEOUT,\n defaultROTransactionTimeout:\n parseInt(url.searchParams.get('ro-tx-timeout'))\n ?? parseInt(url.searchParams.get('tx-timeout'))\n ?? DEFAULT_RO_TX_TIMEOUT,\n defaultRWTransactionTimeout:\n parseInt(url.searchParams.get('rw-tx-timeout'))\n ?? parseInt(url.searchParams.get('tx-timeout'))\n ?? DEFAULT_RW_TX_TIMEOUT,\n authTTLSeconds: DEFAULT_TOKEN_TTL_SECONDS,\n authMaxRefreshSeconds: DEFAULT_AUTH_MAX_REFRESH,\n grpcProxy: url.searchParams.get('grpc-proxy') ?? undefined,\n httpProxy: url.searchParams.get('http-proxy') ?? undefined,\n user: url.username === '' ? undefined : url.username,\n password: url.password === '' ? undefined : url.password,\n txDelay: parseInt(url.searchParams.get('tx-delay')) ?? 0,\n forceSync: Boolean(url.searchParams.get('force-sync')),\n\n maxCacheBytes: parseInt(url.searchParams.get('max-cache-bytes')) ?? DEFAULT_MAX_CACHE_BYTES,\n\n retryBackoffAlgorithm: (url.searchParams.get('retry-backoff-algorithm')\n ?? DEFAULT_RETRY_BACKOFF_ALGORITHM) as any,\n retryMaxAttempts:\n parseInt(url.searchParams.get('retry-max-attempts')) ?? DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay:\n parseInt(url.searchParams.get('retry-initial-delay')) ?? DEFAULT_RETRY_INITIAL_DELAY,\n retryExponentialBackoffMultiplier:\n parseInt(url.searchParams.get('retry-exp-backoff-multiplier'))\n ?? DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n retryLinearBackoffStep:\n parseInt(url.searchParams.get('retry-linear-backoff-step'))\n ?? DEFAULT_RETRY_LINEAR_BACKOFF_STEP,\n retryJitter: parseInt(url.searchParams.get('retry-backoff-jitter')) ?? DEFAULT_RETRY_JITTER,\n\n ...overrides,\n };\n}\n\n/**\n * Authorization data / JWT Token.\n * Absent JWT Token tells the client to connect as anonymous user.\n */\nexport interface AuthInformation {\n /** Absent token means anonymous access */\n jwtToken?: string;\n}\n\nexport const AnonymousAuthInformation: AuthInformation = {};\n\n/** Authorization related settings to pass to {@link PlClient}. */\nexport interface AuthOps {\n /** Initial authorization information */\n authInformation: AuthInformation;\n /** Will be executed after successful authorization information refresh */\n readonly onUpdate?: (newInfo: AuthInformation) => void;\n /** Will be executed if auth-related error happens during normal client operation */\n readonly onAuthError?: () => void;\n /** Will be executed if error encountered during token update */\n readonly onUpdateError?: (error: unknown) => void;\n}\n\n/** Connection status. */\nexport type PlConnectionStatus = 'OK' | 'Disconnected' | 'Unauthenticated';\n\n/** Listener that will be called each time connection status changes. */\nexport type PlConnectionStatusListener = (status: PlConnectionStatus) => void;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.cjs","sources":["../../src/core/config.ts"],"sourcesContent":["import type { ProxySettings } from '@milaboratories/pl-http';\nimport type { ExponentialBackoffRetryOptions } from '@milaboratories/ts-helpers';\n\n/** Base configuration structure for PL client */\nexport interface PlClientConfig {\n /** Port and host of remote pl server */\n hostAndPort: string;\n\n /** If set, client will expose a nested object under a field with name `alternative_root_${alternativeRoot}` as a\n * client root. */\n alternativeRoot?: string;\n\n /** If true, client will establish tls connection to the server, using default\n * CA of node instance. */\n // Not implementing custom ssl validation logic for now.\n // Implementing it in a correct way is really nontrivial thing,\n // real use-cases should be considered.\n ssl: boolean;\n\n /** Default timeout in milliseconds for unary calls, like ping and login. */\n defaultRequestTimeout: number;\n\n /** Default timeout in milliseconds for read-write transaction, should be\n * adjusted for long round-trip or low bandwidth connections. */\n defaultRWTransactionTimeout: number;\n /** Default timeout in milliseconds for read-only transaction, should be\n * adjusted for long round-trip or low bandwidth connections. */\n defaultROTransactionTimeout: number;\n\n /** Controls what TTL will be requested from the server, when new JWT token\n * is requested. */\n authTTLSeconds: number;\n /** If token is older than this time, it will be refreshed regardless of its\n * expiration time. */\n authMaxRefreshSeconds: number;\n\n /** Proxy server config to use for pl connection. */\n grpcProxy?: string | ProxySettings;\n /** Proxy server config to use for http connections of pl drivers, like file\n * downloading. */\n httpProxy?: string | ProxySettings;\n\n /** Username extracted from pl URL. Ignored by {@link PlClient}, picked up by {@link defaultPlClient}. */\n user?: string;\n /** Password extracted from pl URL. Ignored by {@link PlClient}, picked up by {@link defaultPlClient}. */\n password?: string;\n\n /** Artificial delay introduced after write transactions completion, to\n * somewhat throttle the load on pl. Delay introduced after sync, if requested. */\n txDelay: number;\n\n /** Last resort measure to solve complicated race conditions in pl. */\n forceSync: boolean;\n\n /** Maximal number of bytes of resource state to cache */\n maxCacheBytes: number;\n\n //\n // Retry\n //\n\n /**\n * What type of backoff strategy to use in transaction retries\n * (pl uses optimistic transaction model with regular retries in write transactions)\n */\n retryBackoffAlgorithm: 'exponential' | 'linear';\n\n /** Maximal number of attempts in */\n retryMaxAttempts: number;\n\n /** Delay after first failed attempt, in ms. */\n retryInitialDelay: number;\n\n /** Each time delay will be multiplied by this number (1.5 means plus on 50% each attempt) */\n retryExponentialBackoffMultiplier: number;\n\n /** [used only for ] This value will be added to the delay from the previous step, in ms */\n retryLinearBackoffStep: number;\n\n /** Value from 0 to 1, determine level of randomness to introduce to the backoff delays sequence. (0 meaning no randomness) */\n retryJitter: number;\n}\n\nexport const DEFAULT_REQUEST_TIMEOUT = 5_000;\nexport const DEFAULT_RO_TX_TIMEOUT = 300_000;\nexport const DEFAULT_RW_TX_TIMEOUT = 60_000;\nexport const DEFAULT_TOKEN_TTL_SECONDS = 31 * 24 * 60 * 60;\nexport const DEFAULT_AUTH_MAX_REFRESH = 12 * 24 * 60 * 60;\n\nexport const DEFAULT_MAX_CACHE_BYTES = 128_000_000; // 128 Mb\n\nexport const DEFAULT_RETRY_BACKOFF_ALGORITHM = 'exponential';\nexport const DEFAULT_RETRY_MAX_ATTEMPTS = 21; // 1st attempt + 20 retries\nexport const DEFAULT_RETRY_INITIAL_DELAY = 20; // 20 ms * <jitter> of sleep after first failure\nexport const DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER = 1.5; // + 50% on each round\nexport const DEFAULT_RETRY_LINEAR_BACKOFF_STEP = 50; // + 50 ms\nexport const DEFAULT_RETRY_JITTER = 0.3; // 30%\n\nexport const DefaultRetryOptions: ExponentialBackoffRetryOptions = {\n type: 'exponentialBackoff',\n maxAttempts: DEFAULT_RETRY_MAX_ATTEMPTS,\n initialDelay: DEFAULT_RETRY_INITIAL_DELAY,\n backoffMultiplier: DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n jitter: DEFAULT_RETRY_JITTER,\n};\n\ntype PlConfigOverrides = Partial<\n Pick<\n PlClientConfig,\n | 'ssl'\n | 'defaultRequestTimeout'\n | 'defaultROTransactionTimeout'\n | 'defaultRWTransactionTimeout'\n | 'httpProxy'\n | 'grpcProxy'\n >\n>;\n\nfunction parseInt(s: string | null | undefined): number | undefined {\n if (!s) return undefined;\n const num = Number(s);\n if (Number.isNaN(num)) throw new Error(`Can't parse number: ${s}`);\n return num;\n}\n\n/** Parses pl url and creates a config object that can be passed to\n * {@link PlClient} of {@link UnauthenticatedPlClient}. */\nexport function plAddressToConfig(\n address: string,\n overrides: PlConfigOverrides = {},\n): PlClientConfig {\n if (address.indexOf('://') === -1)\n // non-url address\n return {\n hostAndPort: address,\n ssl: false,\n defaultRequestTimeout: DEFAULT_REQUEST_TIMEOUT,\n defaultROTransactionTimeout: DEFAULT_RO_TX_TIMEOUT,\n defaultRWTransactionTimeout: DEFAULT_RW_TX_TIMEOUT,\n authTTLSeconds: DEFAULT_TOKEN_TTL_SECONDS,\n authMaxRefreshSeconds: DEFAULT_AUTH_MAX_REFRESH,\n txDelay: 0,\n forceSync: false,\n\n maxCacheBytes: DEFAULT_MAX_CACHE_BYTES,\n\n retryBackoffAlgorithm: DEFAULT_RETRY_BACKOFF_ALGORITHM,\n retryMaxAttempts: DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay: DEFAULT_RETRY_INITIAL_DELAY,\n retryExponentialBackoffMultiplier: DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n retryLinearBackoffStep: DEFAULT_RETRY_LINEAR_BACKOFF_STEP,\n retryJitter: DEFAULT_RETRY_JITTER,\n\n ...overrides,\n };\n\n const url = new URL(address);\n\n if (\n url.protocol !== 'https:'\n && url.protocol !== 'http:'\n && url.protocol !== 'grpc:'\n && url.protocol !== 'tls:'\n )\n throw new Error(`Unexpected URL schema: ${url.protocol}`);\n\n if (url.pathname !== '/' && url.pathname !== '')\n throw new Error(`Unexpected URL path: ${url.pathname}`);\n\n return {\n hostAndPort: url.host, // this also includes port\n alternativeRoot: url.searchParams.get('alternative-root') ?? undefined,\n ssl: url.protocol === 'https:' || url.protocol === 'tls:',\n defaultRequestTimeout:\n parseInt(url.searchParams.get('request-timeout')) ?? DEFAULT_REQUEST_TIMEOUT,\n defaultROTransactionTimeout:\n parseInt(url.searchParams.get('ro-tx-timeout'))\n ?? parseInt(url.searchParams.get('tx-timeout'))\n ?? DEFAULT_RO_TX_TIMEOUT,\n defaultRWTransactionTimeout:\n parseInt(url.searchParams.get('rw-tx-timeout'))\n ?? parseInt(url.searchParams.get('tx-timeout'))\n ?? DEFAULT_RW_TX_TIMEOUT,\n authTTLSeconds: DEFAULT_TOKEN_TTL_SECONDS,\n authMaxRefreshSeconds: DEFAULT_AUTH_MAX_REFRESH,\n grpcProxy: url.searchParams.get('grpc-proxy') ?? undefined,\n httpProxy: url.searchParams.get('http-proxy') ?? undefined,\n user: url.username === '' ? undefined : url.username,\n password: url.password === '' ? undefined : url.password,\n txDelay: parseInt(url.searchParams.get('tx-delay')) ?? 0,\n forceSync: Boolean(url.searchParams.get('force-sync')),\n\n maxCacheBytes: parseInt(url.searchParams.get('max-cache-bytes')) ?? DEFAULT_MAX_CACHE_BYTES,\n\n retryBackoffAlgorithm: (url.searchParams.get('retry-backoff-algorithm')\n ?? DEFAULT_RETRY_BACKOFF_ALGORITHM) as any,\n retryMaxAttempts:\n parseInt(url.searchParams.get('retry-max-attempts')) ?? DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay:\n parseInt(url.searchParams.get('retry-initial-delay')) ?? DEFAULT_RETRY_INITIAL_DELAY,\n retryExponentialBackoffMultiplier:\n parseInt(url.searchParams.get('retry-exp-backoff-multiplier'))\n ?? DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n retryLinearBackoffStep:\n parseInt(url.searchParams.get('retry-linear-backoff-step'))\n ?? DEFAULT_RETRY_LINEAR_BACKOFF_STEP,\n retryJitter: parseInt(url.searchParams.get('retry-backoff-jitter')) ?? DEFAULT_RETRY_JITTER,\n\n ...overrides,\n };\n}\n\n/**\n * Authorization data / JWT Token.\n * Absent JWT Token tells the client to connect as anonymous user.\n */\nexport interface AuthInformation {\n /** Absent token means anonymous access */\n jwtToken?: string;\n}\n\nexport const AnonymousAuthInformation: AuthInformation = {};\n\n/** Authorization related settings to pass to {@link PlClient}. */\nexport interface AuthOps {\n /** Initial authorization information */\n authInformation: AuthInformation;\n /** Will be executed after successful authorization information refresh */\n readonly onUpdate?: (newInfo: AuthInformation) => void;\n /** Will be executed if auth-related error happens during normal client operation */\n readonly onAuthError?: () => void;\n /** Will be executed if error encountered during token update */\n readonly onUpdateError?: (error: unknown) => void;\n}\n\n/** Connection status. */\nexport type PlConnectionStatus = 'OK' | 'Disconnected' | 'Unauthenticated';\n\n/** Listener that will be called each time connection status changes. */\nexport type PlConnectionStatusListener = (status: PlConnectionStatus) => void;\n"],"names":[],"mappings":"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"}
@@ -24,8 +24,8 @@ export interface PlClientConfig {
24
24
  /** If token is older than this time, it will be refreshed regardless of its
25
25
  * expiration time. */
26
26
  authMaxRefreshSeconds: number;
27
- /** Proxy server URL to use for pl connection. */
28
- grpcProxy?: string;
27
+ /** Proxy server config to use for pl connection. */
28
+ grpcProxy?: string | ProxySettings;
29
29
  /** Proxy server config to use for http connections of pl drivers, like file
30
30
  * downloading. */
31
31
  httpProxy?: string | ProxySettings;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sources":["../../src/core/config.ts"],"sourcesContent":["import type { ProxySettings } from '@milaboratories/pl-http';\nimport type { ExponentialBackoffRetryOptions } from '@milaboratories/ts-helpers';\n\n/** Base configuration structure for PL client */\nexport interface PlClientConfig {\n /** Port and host of remote pl server */\n hostAndPort: string;\n\n /** If set, client will expose a nested object under a field with name `alternative_root_${alternativeRoot}` as a\n * client root. */\n alternativeRoot?: string;\n\n /** If true, client will establish tls connection to the server, using default\n * CA of node instance. */\n // Not implementing custom ssl validation logic for now.\n // Implementing it in a correct way is really nontrivial thing,\n // real use-cases should be considered.\n ssl: boolean;\n\n /** Default timeout in milliseconds for unary calls, like ping and login. */\n defaultRequestTimeout: number;\n\n /** Default timeout in milliseconds for read-write transaction, should be\n * adjusted for long round-trip or low bandwidth connections. */\n defaultRWTransactionTimeout: number;\n /** Default timeout in milliseconds for read-only transaction, should be\n * adjusted for long round-trip or low bandwidth connections. */\n defaultROTransactionTimeout: number;\n\n /** Controls what TTL will be requested from the server, when new JWT token\n * is requested. */\n authTTLSeconds: number;\n /** If token is older than this time, it will be refreshed regardless of its\n * expiration time. */\n authMaxRefreshSeconds: number;\n\n /** Proxy server URL to use for pl connection. */\n grpcProxy?: string;\n /** Proxy server config to use for http connections of pl drivers, like file\n * downloading. */\n httpProxy?: string | ProxySettings;\n\n /** Username extracted from pl URL. Ignored by {@link PlClient}, picked up by {@link defaultPlClient}. */\n user?: string;\n /** Password extracted from pl URL. Ignored by {@link PlClient}, picked up by {@link defaultPlClient}. */\n password?: string;\n\n /** Artificial delay introduced after write transactions completion, to\n * somewhat throttle the load on pl. Delay introduced after sync, if requested. */\n txDelay: number;\n\n /** Last resort measure to solve complicated race conditions in pl. */\n forceSync: boolean;\n\n /** Maximal number of bytes of resource state to cache */\n maxCacheBytes: number;\n\n //\n // Retry\n //\n\n /**\n * What type of backoff strategy to use in transaction retries\n * (pl uses optimistic transaction model with regular retries in write transactions)\n */\n retryBackoffAlgorithm: 'exponential' | 'linear';\n\n /** Maximal number of attempts in */\n retryMaxAttempts: number;\n\n /** Delay after first failed attempt, in ms. */\n retryInitialDelay: number;\n\n /** Each time delay will be multiplied by this number (1.5 means plus on 50% each attempt) */\n retryExponentialBackoffMultiplier: number;\n\n /** [used only for ] This value will be added to the delay from the previous step, in ms */\n retryLinearBackoffStep: number;\n\n /** Value from 0 to 1, determine level of randomness to introduce to the backoff delays sequence. (0 meaning no randomness) */\n retryJitter: number;\n}\n\nexport const DEFAULT_REQUEST_TIMEOUT = 5_000;\nexport const DEFAULT_RO_TX_TIMEOUT = 300_000;\nexport const DEFAULT_RW_TX_TIMEOUT = 60_000;\nexport const DEFAULT_TOKEN_TTL_SECONDS = 31 * 24 * 60 * 60;\nexport const DEFAULT_AUTH_MAX_REFRESH = 12 * 24 * 60 * 60;\n\nexport const DEFAULT_MAX_CACHE_BYTES = 128_000_000; // 128 Mb\n\nexport const DEFAULT_RETRY_BACKOFF_ALGORITHM = 'exponential';\nexport const DEFAULT_RETRY_MAX_ATTEMPTS = 21; // 1st attempt + 20 retries\nexport const DEFAULT_RETRY_INITIAL_DELAY = 20; // 20 ms * <jitter> of sleep after first failure\nexport const DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER = 1.5; // + 50% on each round\nexport const DEFAULT_RETRY_LINEAR_BACKOFF_STEP = 50; // + 50 ms\nexport const DEFAULT_RETRY_JITTER = 0.3; // 30%\n\nexport const DefaultRetryOptions: ExponentialBackoffRetryOptions = {\n type: 'exponentialBackoff',\n maxAttempts: DEFAULT_RETRY_MAX_ATTEMPTS,\n initialDelay: DEFAULT_RETRY_INITIAL_DELAY,\n backoffMultiplier: DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n jitter: DEFAULT_RETRY_JITTER,\n};\n\ntype PlConfigOverrides = Partial<\n Pick<\n PlClientConfig,\n | 'ssl'\n | 'defaultRequestTimeout'\n | 'defaultROTransactionTimeout'\n | 'defaultRWTransactionTimeout'\n | 'httpProxy'\n | 'grpcProxy'\n >\n>;\n\nfunction parseInt(s: string | null | undefined): number | undefined {\n if (!s) return undefined;\n const num = Number(s);\n if (Number.isNaN(num)) throw new Error(`Can't parse number: ${s}`);\n return num;\n}\n\n/** Parses pl url and creates a config object that can be passed to\n * {@link PlClient} of {@link UnauthenticatedPlClient}. */\nexport function plAddressToConfig(\n address: string,\n overrides: PlConfigOverrides = {},\n): PlClientConfig {\n if (address.indexOf('://') === -1)\n // non-url address\n return {\n hostAndPort: address,\n ssl: false,\n defaultRequestTimeout: DEFAULT_REQUEST_TIMEOUT,\n defaultROTransactionTimeout: DEFAULT_RO_TX_TIMEOUT,\n defaultRWTransactionTimeout: DEFAULT_RW_TX_TIMEOUT,\n authTTLSeconds: DEFAULT_TOKEN_TTL_SECONDS,\n authMaxRefreshSeconds: DEFAULT_AUTH_MAX_REFRESH,\n txDelay: 0,\n forceSync: false,\n\n maxCacheBytes: DEFAULT_MAX_CACHE_BYTES,\n\n retryBackoffAlgorithm: DEFAULT_RETRY_BACKOFF_ALGORITHM,\n retryMaxAttempts: DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay: DEFAULT_RETRY_INITIAL_DELAY,\n retryExponentialBackoffMultiplier: DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n retryLinearBackoffStep: DEFAULT_RETRY_LINEAR_BACKOFF_STEP,\n retryJitter: DEFAULT_RETRY_JITTER,\n\n ...overrides,\n };\n\n const url = new URL(address);\n\n if (\n url.protocol !== 'https:'\n && url.protocol !== 'http:'\n && url.protocol !== 'grpc:'\n && url.protocol !== 'tls:'\n )\n throw new Error(`Unexpected URL schema: ${url.protocol}`);\n\n if (url.pathname !== '/' && url.pathname !== '')\n throw new Error(`Unexpected URL path: ${url.pathname}`);\n\n return {\n hostAndPort: url.host, // this also includes port\n alternativeRoot: url.searchParams.get('alternative-root') ?? undefined,\n ssl: url.protocol === 'https:' || url.protocol === 'tls:',\n defaultRequestTimeout:\n parseInt(url.searchParams.get('request-timeout')) ?? DEFAULT_REQUEST_TIMEOUT,\n defaultROTransactionTimeout:\n parseInt(url.searchParams.get('ro-tx-timeout'))\n ?? parseInt(url.searchParams.get('tx-timeout'))\n ?? DEFAULT_RO_TX_TIMEOUT,\n defaultRWTransactionTimeout:\n parseInt(url.searchParams.get('rw-tx-timeout'))\n ?? parseInt(url.searchParams.get('tx-timeout'))\n ?? DEFAULT_RW_TX_TIMEOUT,\n authTTLSeconds: DEFAULT_TOKEN_TTL_SECONDS,\n authMaxRefreshSeconds: DEFAULT_AUTH_MAX_REFRESH,\n grpcProxy: url.searchParams.get('grpc-proxy') ?? undefined,\n httpProxy: url.searchParams.get('http-proxy') ?? undefined,\n user: url.username === '' ? undefined : url.username,\n password: url.password === '' ? undefined : url.password,\n txDelay: parseInt(url.searchParams.get('tx-delay')) ?? 0,\n forceSync: Boolean(url.searchParams.get('force-sync')),\n\n maxCacheBytes: parseInt(url.searchParams.get('max-cache-bytes')) ?? DEFAULT_MAX_CACHE_BYTES,\n\n retryBackoffAlgorithm: (url.searchParams.get('retry-backoff-algorithm')\n ?? DEFAULT_RETRY_BACKOFF_ALGORITHM) as any,\n retryMaxAttempts:\n parseInt(url.searchParams.get('retry-max-attempts')) ?? DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay:\n parseInt(url.searchParams.get('retry-initial-delay')) ?? DEFAULT_RETRY_INITIAL_DELAY,\n retryExponentialBackoffMultiplier:\n parseInt(url.searchParams.get('retry-exp-backoff-multiplier'))\n ?? DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n retryLinearBackoffStep:\n parseInt(url.searchParams.get('retry-linear-backoff-step'))\n ?? DEFAULT_RETRY_LINEAR_BACKOFF_STEP,\n retryJitter: parseInt(url.searchParams.get('retry-backoff-jitter')) ?? DEFAULT_RETRY_JITTER,\n\n ...overrides,\n };\n}\n\n/**\n * Authorization data / JWT Token.\n * Absent JWT Token tells the client to connect as anonymous user.\n */\nexport interface AuthInformation {\n /** Absent token means anonymous access */\n jwtToken?: string;\n}\n\nexport const AnonymousAuthInformation: AuthInformation = {};\n\n/** Authorization related settings to pass to {@link PlClient}. */\nexport interface AuthOps {\n /** Initial authorization information */\n authInformation: AuthInformation;\n /** Will be executed after successful authorization information refresh */\n readonly onUpdate?: (newInfo: AuthInformation) => void;\n /** Will be executed if auth-related error happens during normal client operation */\n readonly onAuthError?: () => void;\n /** Will be executed if error encountered during token update */\n readonly onUpdateError?: (error: unknown) => void;\n}\n\n/** Connection status. */\nexport type PlConnectionStatus = 'OK' | 'Disconnected' | 'Unauthenticated';\n\n/** Listener that will be called each time connection status changes. */\nexport type PlConnectionStatusListener = (status: PlConnectionStatus) => void;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sources":["../../src/core/config.ts"],"sourcesContent":["import type { ProxySettings } from '@milaboratories/pl-http';\nimport type { ExponentialBackoffRetryOptions } from '@milaboratories/ts-helpers';\n\n/** Base configuration structure for PL client */\nexport interface PlClientConfig {\n /** Port and host of remote pl server */\n hostAndPort: string;\n\n /** If set, client will expose a nested object under a field with name `alternative_root_${alternativeRoot}` as a\n * client root. */\n alternativeRoot?: string;\n\n /** If true, client will establish tls connection to the server, using default\n * CA of node instance. */\n // Not implementing custom ssl validation logic for now.\n // Implementing it in a correct way is really nontrivial thing,\n // real use-cases should be considered.\n ssl: boolean;\n\n /** Default timeout in milliseconds for unary calls, like ping and login. */\n defaultRequestTimeout: number;\n\n /** Default timeout in milliseconds for read-write transaction, should be\n * adjusted for long round-trip or low bandwidth connections. */\n defaultRWTransactionTimeout: number;\n /** Default timeout in milliseconds for read-only transaction, should be\n * adjusted for long round-trip or low bandwidth connections. */\n defaultROTransactionTimeout: number;\n\n /** Controls what TTL will be requested from the server, when new JWT token\n * is requested. */\n authTTLSeconds: number;\n /** If token is older than this time, it will be refreshed regardless of its\n * expiration time. */\n authMaxRefreshSeconds: number;\n\n /** Proxy server config to use for pl connection. */\n grpcProxy?: string | ProxySettings;\n /** Proxy server config to use for http connections of pl drivers, like file\n * downloading. */\n httpProxy?: string | ProxySettings;\n\n /** Username extracted from pl URL. Ignored by {@link PlClient}, picked up by {@link defaultPlClient}. */\n user?: string;\n /** Password extracted from pl URL. Ignored by {@link PlClient}, picked up by {@link defaultPlClient}. */\n password?: string;\n\n /** Artificial delay introduced after write transactions completion, to\n * somewhat throttle the load on pl. Delay introduced after sync, if requested. */\n txDelay: number;\n\n /** Last resort measure to solve complicated race conditions in pl. */\n forceSync: boolean;\n\n /** Maximal number of bytes of resource state to cache */\n maxCacheBytes: number;\n\n //\n // Retry\n //\n\n /**\n * What type of backoff strategy to use in transaction retries\n * (pl uses optimistic transaction model with regular retries in write transactions)\n */\n retryBackoffAlgorithm: 'exponential' | 'linear';\n\n /** Maximal number of attempts in */\n retryMaxAttempts: number;\n\n /** Delay after first failed attempt, in ms. */\n retryInitialDelay: number;\n\n /** Each time delay will be multiplied by this number (1.5 means plus on 50% each attempt) */\n retryExponentialBackoffMultiplier: number;\n\n /** [used only for ] This value will be added to the delay from the previous step, in ms */\n retryLinearBackoffStep: number;\n\n /** Value from 0 to 1, determine level of randomness to introduce to the backoff delays sequence. (0 meaning no randomness) */\n retryJitter: number;\n}\n\nexport const DEFAULT_REQUEST_TIMEOUT = 5_000;\nexport const DEFAULT_RO_TX_TIMEOUT = 300_000;\nexport const DEFAULT_RW_TX_TIMEOUT = 60_000;\nexport const DEFAULT_TOKEN_TTL_SECONDS = 31 * 24 * 60 * 60;\nexport const DEFAULT_AUTH_MAX_REFRESH = 12 * 24 * 60 * 60;\n\nexport const DEFAULT_MAX_CACHE_BYTES = 128_000_000; // 128 Mb\n\nexport const DEFAULT_RETRY_BACKOFF_ALGORITHM = 'exponential';\nexport const DEFAULT_RETRY_MAX_ATTEMPTS = 21; // 1st attempt + 20 retries\nexport const DEFAULT_RETRY_INITIAL_DELAY = 20; // 20 ms * <jitter> of sleep after first failure\nexport const DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER = 1.5; // + 50% on each round\nexport const DEFAULT_RETRY_LINEAR_BACKOFF_STEP = 50; // + 50 ms\nexport const DEFAULT_RETRY_JITTER = 0.3; // 30%\n\nexport const DefaultRetryOptions: ExponentialBackoffRetryOptions = {\n type: 'exponentialBackoff',\n maxAttempts: DEFAULT_RETRY_MAX_ATTEMPTS,\n initialDelay: DEFAULT_RETRY_INITIAL_DELAY,\n backoffMultiplier: DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n jitter: DEFAULT_RETRY_JITTER,\n};\n\ntype PlConfigOverrides = Partial<\n Pick<\n PlClientConfig,\n | 'ssl'\n | 'defaultRequestTimeout'\n | 'defaultROTransactionTimeout'\n | 'defaultRWTransactionTimeout'\n | 'httpProxy'\n | 'grpcProxy'\n >\n>;\n\nfunction parseInt(s: string | null | undefined): number | undefined {\n if (!s) return undefined;\n const num = Number(s);\n if (Number.isNaN(num)) throw new Error(`Can't parse number: ${s}`);\n return num;\n}\n\n/** Parses pl url and creates a config object that can be passed to\n * {@link PlClient} of {@link UnauthenticatedPlClient}. */\nexport function plAddressToConfig(\n address: string,\n overrides: PlConfigOverrides = {},\n): PlClientConfig {\n if (address.indexOf('://') === -1)\n // non-url address\n return {\n hostAndPort: address,\n ssl: false,\n defaultRequestTimeout: DEFAULT_REQUEST_TIMEOUT,\n defaultROTransactionTimeout: DEFAULT_RO_TX_TIMEOUT,\n defaultRWTransactionTimeout: DEFAULT_RW_TX_TIMEOUT,\n authTTLSeconds: DEFAULT_TOKEN_TTL_SECONDS,\n authMaxRefreshSeconds: DEFAULT_AUTH_MAX_REFRESH,\n txDelay: 0,\n forceSync: false,\n\n maxCacheBytes: DEFAULT_MAX_CACHE_BYTES,\n\n retryBackoffAlgorithm: DEFAULT_RETRY_BACKOFF_ALGORITHM,\n retryMaxAttempts: DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay: DEFAULT_RETRY_INITIAL_DELAY,\n retryExponentialBackoffMultiplier: DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n retryLinearBackoffStep: DEFAULT_RETRY_LINEAR_BACKOFF_STEP,\n retryJitter: DEFAULT_RETRY_JITTER,\n\n ...overrides,\n };\n\n const url = new URL(address);\n\n if (\n url.protocol !== 'https:'\n && url.protocol !== 'http:'\n && url.protocol !== 'grpc:'\n && url.protocol !== 'tls:'\n )\n throw new Error(`Unexpected URL schema: ${url.protocol}`);\n\n if (url.pathname !== '/' && url.pathname !== '')\n throw new Error(`Unexpected URL path: ${url.pathname}`);\n\n return {\n hostAndPort: url.host, // this also includes port\n alternativeRoot: url.searchParams.get('alternative-root') ?? undefined,\n ssl: url.protocol === 'https:' || url.protocol === 'tls:',\n defaultRequestTimeout:\n parseInt(url.searchParams.get('request-timeout')) ?? DEFAULT_REQUEST_TIMEOUT,\n defaultROTransactionTimeout:\n parseInt(url.searchParams.get('ro-tx-timeout'))\n ?? parseInt(url.searchParams.get('tx-timeout'))\n ?? DEFAULT_RO_TX_TIMEOUT,\n defaultRWTransactionTimeout:\n parseInt(url.searchParams.get('rw-tx-timeout'))\n ?? parseInt(url.searchParams.get('tx-timeout'))\n ?? DEFAULT_RW_TX_TIMEOUT,\n authTTLSeconds: DEFAULT_TOKEN_TTL_SECONDS,\n authMaxRefreshSeconds: DEFAULT_AUTH_MAX_REFRESH,\n grpcProxy: url.searchParams.get('grpc-proxy') ?? undefined,\n httpProxy: url.searchParams.get('http-proxy') ?? undefined,\n user: url.username === '' ? undefined : url.username,\n password: url.password === '' ? undefined : url.password,\n txDelay: parseInt(url.searchParams.get('tx-delay')) ?? 0,\n forceSync: Boolean(url.searchParams.get('force-sync')),\n\n maxCacheBytes: parseInt(url.searchParams.get('max-cache-bytes')) ?? DEFAULT_MAX_CACHE_BYTES,\n\n retryBackoffAlgorithm: (url.searchParams.get('retry-backoff-algorithm')\n ?? DEFAULT_RETRY_BACKOFF_ALGORITHM) as any,\n retryMaxAttempts:\n parseInt(url.searchParams.get('retry-max-attempts')) ?? DEFAULT_RETRY_MAX_ATTEMPTS,\n retryInitialDelay:\n parseInt(url.searchParams.get('retry-initial-delay')) ?? DEFAULT_RETRY_INITIAL_DELAY,\n retryExponentialBackoffMultiplier:\n parseInt(url.searchParams.get('retry-exp-backoff-multiplier'))\n ?? DEFAULT_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER,\n retryLinearBackoffStep:\n parseInt(url.searchParams.get('retry-linear-backoff-step'))\n ?? DEFAULT_RETRY_LINEAR_BACKOFF_STEP,\n retryJitter: parseInt(url.searchParams.get('retry-backoff-jitter')) ?? DEFAULT_RETRY_JITTER,\n\n ...overrides,\n };\n}\n\n/**\n * Authorization data / JWT Token.\n * Absent JWT Token tells the client to connect as anonymous user.\n */\nexport interface AuthInformation {\n /** Absent token means anonymous access */\n jwtToken?: string;\n}\n\nexport const AnonymousAuthInformation: AuthInformation = {};\n\n/** Authorization related settings to pass to {@link PlClient}. */\nexport interface AuthOps {\n /** Initial authorization information */\n authInformation: AuthInformation;\n /** Will be executed after successful authorization information refresh */\n readonly onUpdate?: (newInfo: AuthInformation) => void;\n /** Will be executed if auth-related error happens during normal client operation */\n readonly onAuthError?: () => void;\n /** Will be executed if error encountered during token update */\n readonly onUpdateError?: (error: unknown) => void;\n}\n\n/** Connection status. */\nexport type PlConnectionStatus = 'OK' | 'Disconnected' | 'Unauthenticated';\n\n/** Listener that will be called each time connection status changes. */\nexport type PlConnectionStatusListener = (status: PlConnectionStatus) => void;\n"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ var ll_transaction = require('./ll_transaction.cjs');
8
8
  var pl = require('../util/pl.cjs');
9
9
  var auth = require('./auth.cjs');
10
10
  var plHttp = require('@milaboratories/pl-http');
11
+ var plModelCommon = require('@milaboratories/pl-model-common');
11
12
 
12
13
  class GrpcClientProviderImpl {
13
14
  grpcTransport;
@@ -49,8 +50,9 @@ class LLPlClient {
49
50
  httpDispatcher;
50
51
  constructor(configOrAddress, ops = {}) {
51
52
  this.ops = ops;
52
- this.conf
53
- = typeof configOrAddress === 'string' ? config.plAddressToConfig(configOrAddress) : configOrAddress;
53
+ this.conf = typeof configOrAddress === 'string'
54
+ ? config.plAddressToConfig(configOrAddress)
55
+ : configOrAddress;
54
56
  this.grpcInterceptors = [];
55
57
  const { auth: auth$1, statusListener, shouldUseGzip } = ops;
56
58
  if (auth$1 !== undefined) {
@@ -97,10 +99,24 @@ class LLPlClient {
97
99
  : grpcJs.ChannelCredentials.createInsecure(),
98
100
  clientOptions,
99
101
  };
100
- if (this.conf.grpcProxy)
101
- process.env.grpc_proxy = this.conf.grpcProxy;
102
- else
102
+ const grpcProxy = typeof this.conf.grpcProxy === 'string'
103
+ ? { url: this.conf.grpcProxy }
104
+ : this.conf.grpcProxy;
105
+ if (grpcProxy?.url) {
106
+ const url = new URL(grpcProxy.url);
107
+ if (grpcProxy.auth) {
108
+ const parsed = plModelCommon.parseHttpAuth(grpcProxy.auth);
109
+ if (parsed.scheme !== 'Basic') {
110
+ throw new Error(`Unsupported auth scheme: ${parsed.scheme}.`);
111
+ }
112
+ url.username = parsed.username;
113
+ url.password = parsed.password;
114
+ }
115
+ process.env.grpc_proxy = url.toString();
116
+ }
117
+ else {
103
118
  delete process.env.grpc_proxy;
119
+ }
104
120
  const oldTransport = this._grpcTransport;
105
121
  this._grpcTransport = new grpcTransport.GrpcTransport(grpcOptions);
106
122
  // Reset all providers to let them reinitialize their clients
@@ -1 +1 @@
1
- {"version":3,"file":"ll_client.cjs","sources":["../../src/core/ll_client.ts"],"sourcesContent":["import { PlatformClient } from '../proto/github.com/milaboratory/pl/plapi/plapiproto/api.client';\nimport type { ClientOptions, Interceptor } from '@grpc/grpc-js';\nimport {\n ChannelCredentials,\n InterceptingCall,\n status as GrpcStatus,\n compressionAlgorithms,\n} from '@grpc/grpc-js';\nimport type {\n AuthInformation,\n AuthOps,\n PlClientConfig,\n PlConnectionStatus,\n PlConnectionStatusListener,\n} from './config';\nimport { plAddressToConfig } from './config';\nimport type { GrpcOptions } from '@protobuf-ts/grpc-transport';\nimport { GrpcTransport } from '@protobuf-ts/grpc-transport';\nimport { LLPlTransaction } from './ll_transaction';\nimport { parsePlJwt } from '../util/pl';\nimport type { Dispatcher } from 'undici';\nimport { inferAuthRefreshTime } from './auth';\nimport { defaultHttpDispatcher } from '@milaboratories/pl-http';\nimport type { GrpcClientProvider, GrpcClientProviderFactory } from './grpc';\n\nexport interface PlCallOps {\n timeout?: number;\n abortSignal?: AbortSignal;\n}\n\nclass GrpcClientProviderImpl<Client> implements GrpcClientProvider<Client> {\n private client: Client | undefined = undefined;\n\n constructor(private readonly grpcTransport: () => GrpcTransport, private readonly clientConstructor: (transport: GrpcTransport) => Client) {}\n\n public reset(): void {\n this.client = undefined;\n }\n\n public get(): Client {\n if (this.client === undefined)\n this.client = this.clientConstructor(this.grpcTransport());\n return this.client;\n }\n}\n\n/** Abstract out low level networking and authorization details */\nexport class LLPlClient implements GrpcClientProviderFactory {\n public readonly conf: PlClientConfig;\n\n /** Initial authorization information */\n private authInformation?: AuthInformation;\n /** Will be executed by the client when it is required */\n private readonly onAuthUpdate?: (newInfo: AuthInformation) => void;\n /** Will be executed if auth-related error happens during normal client operation */\n private readonly onAuthError?: () => void;\n /** Will be executed by the client when it is required */\n private readonly onAuthRefreshProblem?: (error: unknown) => void;\n /** Threshold after which auth info refresh is required */\n private refreshTimestamp?: number;\n\n private _status: PlConnectionStatus = 'OK';\n private readonly statusListener?: PlConnectionStatusListener;\n\n private readonly grpcInterceptors: Interceptor[];\n private _grpcTransport!: GrpcTransport;\n private readonly providers: WeakRef<GrpcClientProviderImpl<any>>[] = [];\n\n public readonly grpcPl: GrpcClientProvider<PlatformClient>;\n\n public readonly httpDispatcher: Dispatcher;\n\n constructor(\n configOrAddress: PlClientConfig | string,\n private readonly ops: {\n auth?: AuthOps;\n statusListener?: PlConnectionStatusListener;\n shouldUseGzip?: boolean;\n } = {},\n ) {\n this.conf\n = typeof configOrAddress === 'string' ? plAddressToConfig(configOrAddress) : configOrAddress;\n\n this.grpcInterceptors = [];\n\n const { auth, statusListener, shouldUseGzip } = ops;\n\n if (auth !== undefined) {\n this.refreshTimestamp = inferAuthRefreshTime(\n auth.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n this.grpcInterceptors.push(this.createAuthInterceptor());\n this.authInformation = auth.authInformation;\n this.onAuthUpdate = auth.onUpdate;\n this.onAuthRefreshProblem = auth.onUpdateError;\n this.onAuthError = auth.onAuthError;\n }\n\n this.grpcInterceptors.push(this.createErrorInterceptor());\n\n // initialize _grpcTransport and _grpcPl\n this.initGrpc(shouldUseGzip ?? false);\n\n this.httpDispatcher = defaultHttpDispatcher(this.conf.httpProxy);\n\n if (statusListener !== undefined) {\n this.statusListener = statusListener;\n statusListener(this._status);\n }\n\n this.grpcPl = this.createGrpcClientProvider((transport) => new PlatformClient(transport));\n }\n\n /**\n * Initializes (or reinitializes) _grpcTransport and _grpcPl\n * @param gzip - whether to enable gzip compression\n */\n private initGrpc(gzip: boolean) {\n const clientOptions: ClientOptions = {\n 'grpc.keepalive_time_ms': 30_000, // 30 seconds\n 'interceptors': this.grpcInterceptors,\n };\n\n if (gzip) clientOptions['grpc.default_compression_algorithm'] = compressionAlgorithms.gzip;\n\n //\n // Leaving it here for now\n // https://github.com/grpc/grpc-node/issues/2788\n //\n // We should implement message pooling algorithm to overcome hardcoded NO_DELAY behaviour\n // of HTTP/2 and allow our small messages to batch together.\n //\n const grpcOptions: GrpcOptions = {\n host: this.conf.hostAndPort,\n timeout: this.conf.defaultRequestTimeout,\n channelCredentials: this.conf.ssl\n ? ChannelCredentials.createSsl()\n : ChannelCredentials.createInsecure(),\n clientOptions,\n };\n\n if (this.conf.grpcProxy) process.env.grpc_proxy = this.conf.grpcProxy;\n else delete process.env.grpc_proxy;\n\n const oldTransport = this._grpcTransport;\n\n this._grpcTransport = new GrpcTransport(grpcOptions);\n\n // Reset all providers to let them reinitialize their clients\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n // at the same time we need to remove providers that are no longer valid\n this.providers.splice(i, 1);\n i--;\n } else {\n provider.reset();\n }\n }\n\n if (oldTransport !== undefined) oldTransport.close();\n }\n\n private providerCleanupCounter = 0;\n\n /**\n * Creates a provider for a grpc client. Returned provider will create fresh client whenever the underlying transport is reset.\n *\n * @param clientConstructor - a factory function that creates a grpc client\n */\n public createGrpcClientProvider<Client>(clientConstructor: (transport: GrpcTransport) => Client): GrpcClientProvider<Client> {\n // We need to cleanup providers periodically to avoid memory leaks.\n // This is a simple heuristic to avoid memory leaks.\n // We could use a more sophisticated algorithm, but this is good enough for now.\n this.providerCleanupCounter++;\n if (this.providerCleanupCounter >= 16) {\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n this.providers.splice(i, 1);\n i--;\n }\n }\n this.providerCleanupCounter = 0;\n }\n\n const provider = new GrpcClientProviderImpl<Client>(() => this._grpcTransport, clientConstructor);\n this.providers.push(new WeakRef(provider));\n return provider;\n }\n\n public get grpcTransport(): GrpcTransport {\n return this._grpcTransport;\n }\n\n /** Returns true if client is authenticated. Even with anonymous auth information\n * connection is considered authenticated. Unauthenticated clients are used for\n * login and similar tasks, see {@link UnauthenticatedPlClient}. */\n public get authenticated(): boolean {\n return this.authInformation !== undefined;\n }\n\n /** null means anonymous connection */\n public get authUser(): string | null {\n if (!this.authenticated) throw new Error('Client is not authenticated');\n if (this.authInformation?.jwtToken)\n return parsePlJwt(this.authInformation?.jwtToken).user.login;\n else return null;\n }\n\n private updateStatus(newStatus: PlConnectionStatus) {\n process.nextTick(() => {\n if (this._status !== newStatus) {\n this._status = newStatus;\n if (this.statusListener !== undefined) this.statusListener(this._status);\n if (this.onAuthError !== undefined) this.onAuthError();\n }\n });\n }\n\n public get status(): PlConnectionStatus {\n return this._status;\n }\n\n private authRefreshInProgress: boolean = false;\n\n private refreshAuthInformationIfNeeded(): void {\n if (\n this.refreshTimestamp === undefined\n || Date.now() < this.refreshTimestamp\n || this.authRefreshInProgress\n || this._status === 'Unauthenticated'\n )\n return;\n\n // Running refresh in background`\n this.authRefreshInProgress = true;\n void (async () => {\n try {\n const response = await this.grpcPl.get().getJWTToken({\n expiration: {\n seconds: BigInt(this.conf.authTTLSeconds),\n nanos: 0,\n },\n }).response;\n this.authInformation = { jwtToken: response.token };\n this.refreshTimestamp = inferAuthRefreshTime(\n this.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n if (this.onAuthUpdate) this.onAuthUpdate(this.authInformation);\n } catch (e: unknown) {\n if (this.onAuthRefreshProblem) this.onAuthRefreshProblem(e);\n } finally {\n this.authRefreshInProgress = false;\n }\n })();\n }\n\n /** Detects certain errors and update client status accordingly */\n private createErrorInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n next(metadata, {\n onReceiveStatus: (status, next) => {\n if (status.code == GrpcStatus.UNAUTHENTICATED)\n // (!!!) don't change to \"===\"\n this.updateStatus('Unauthenticated');\n if (status.code == GrpcStatus.UNAVAILABLE)\n // (!!!) don't change to \"===\"\n this.updateStatus('Disconnected');\n next(status);\n },\n });\n },\n });\n };\n }\n\n /** Injects authentication information if needed */\n private createAuthInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n if (this.authInformation?.jwtToken !== undefined) {\n metadata.set('authorization', 'Bearer ' + this.authInformation.jwtToken);\n this.refreshAuthInformationIfNeeded();\n next(metadata, listener);\n } else {\n next(metadata, listener);\n }\n },\n });\n };\n }\n\n createTx(rw: boolean, ops: PlCallOps = {}): LLPlTransaction {\n return new LLPlTransaction((abortSignal) => {\n let totalAbortSignal = abortSignal;\n if (ops.abortSignal) totalAbortSignal = AbortSignal.any([totalAbortSignal, ops.abortSignal]);\n return this.grpcPl.get().tx({\n abort: totalAbortSignal,\n timeout:\n ops.timeout\n ?? (rw ? this.conf.defaultRWTransactionTimeout : this.conf.defaultROTransactionTimeout),\n });\n });\n }\n\n /** Closes underlying transport */\n public async close() {\n this.grpcTransport.close();\n await this.httpDispatcher.destroy();\n }\n}\n"],"names":["plAddressToConfig","auth","inferAuthRefreshTime","defaultHttpDispatcher","PlatformClient","compressionAlgorithms","ChannelCredentials","GrpcTransport","parsePlJwt","InterceptingCall","GrpcStatus","LLPlTransaction"],"mappings":"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"}
1
+ {"version":3,"file":"ll_client.cjs","sources":["../../src/core/ll_client.ts"],"sourcesContent":["import { PlatformClient } from '../proto/github.com/milaboratory/pl/plapi/plapiproto/api.client';\nimport type { ClientOptions, Interceptor } from '@grpc/grpc-js';\nimport {\n ChannelCredentials,\n InterceptingCall,\n status as GrpcStatus,\n compressionAlgorithms,\n} from '@grpc/grpc-js';\nimport type {\n AuthInformation,\n AuthOps,\n PlClientConfig,\n PlConnectionStatus,\n PlConnectionStatusListener,\n} from './config';\nimport { plAddressToConfig } from './config';\nimport type { GrpcOptions } from '@protobuf-ts/grpc-transport';\nimport { GrpcTransport } from '@protobuf-ts/grpc-transport';\nimport { LLPlTransaction } from './ll_transaction';\nimport { parsePlJwt } from '../util/pl';\nimport type { Dispatcher } from 'undici';\nimport { inferAuthRefreshTime } from './auth';\nimport { defaultHttpDispatcher } from '@milaboratories/pl-http';\nimport type { GrpcClientProvider, GrpcClientProviderFactory } from './grpc';\nimport { parseHttpAuth } from '@milaboratories/pl-model-common';\n\nexport interface PlCallOps {\n timeout?: number;\n abortSignal?: AbortSignal;\n}\n\nclass GrpcClientProviderImpl<Client> implements GrpcClientProvider<Client> {\n private client: Client | undefined = undefined;\n\n constructor(private readonly grpcTransport: () => GrpcTransport, private readonly clientConstructor: (transport: GrpcTransport) => Client) {}\n\n public reset(): void {\n this.client = undefined;\n }\n\n public get(): Client {\n if (this.client === undefined)\n this.client = this.clientConstructor(this.grpcTransport());\n return this.client;\n }\n}\n\n/** Abstract out low level networking and authorization details */\nexport class LLPlClient implements GrpcClientProviderFactory {\n public readonly conf: PlClientConfig;\n\n /** Initial authorization information */\n private authInformation?: AuthInformation;\n /** Will be executed by the client when it is required */\n private readonly onAuthUpdate?: (newInfo: AuthInformation) => void;\n /** Will be executed if auth-related error happens during normal client operation */\n private readonly onAuthError?: () => void;\n /** Will be executed by the client when it is required */\n private readonly onAuthRefreshProblem?: (error: unknown) => void;\n /** Threshold after which auth info refresh is required */\n private refreshTimestamp?: number;\n\n private _status: PlConnectionStatus = 'OK';\n private readonly statusListener?: PlConnectionStatusListener;\n\n private readonly grpcInterceptors: Interceptor[];\n private _grpcTransport!: GrpcTransport;\n private readonly providers: WeakRef<GrpcClientProviderImpl<any>>[] = [];\n\n public readonly grpcPl: GrpcClientProvider<PlatformClient>;\n\n public readonly httpDispatcher: Dispatcher;\n\n constructor(\n configOrAddress: PlClientConfig | string,\n private readonly ops: {\n auth?: AuthOps;\n statusListener?: PlConnectionStatusListener;\n shouldUseGzip?: boolean;\n } = {},\n ) {\n this.conf = typeof configOrAddress === 'string'\n ? plAddressToConfig(configOrAddress)\n : configOrAddress;\n\n this.grpcInterceptors = [];\n\n const { auth, statusListener, shouldUseGzip } = ops;\n\n if (auth !== undefined) {\n this.refreshTimestamp = inferAuthRefreshTime(\n auth.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n this.grpcInterceptors.push(this.createAuthInterceptor());\n this.authInformation = auth.authInformation;\n this.onAuthUpdate = auth.onUpdate;\n this.onAuthRefreshProblem = auth.onUpdateError;\n this.onAuthError = auth.onAuthError;\n }\n\n this.grpcInterceptors.push(this.createErrorInterceptor());\n\n // initialize _grpcTransport and _grpcPl\n this.initGrpc(shouldUseGzip ?? false);\n\n this.httpDispatcher = defaultHttpDispatcher(this.conf.httpProxy);\n\n if (statusListener !== undefined) {\n this.statusListener = statusListener;\n statusListener(this._status);\n }\n\n this.grpcPl = this.createGrpcClientProvider((transport) => new PlatformClient(transport));\n }\n\n /**\n * Initializes (or reinitializes) _grpcTransport and _grpcPl\n * @param gzip - whether to enable gzip compression\n */\n private initGrpc(gzip: boolean) {\n const clientOptions: ClientOptions = {\n 'grpc.keepalive_time_ms': 30_000, // 30 seconds\n 'interceptors': this.grpcInterceptors,\n };\n\n if (gzip) clientOptions['grpc.default_compression_algorithm'] = compressionAlgorithms.gzip;\n\n //\n // Leaving it here for now\n // https://github.com/grpc/grpc-node/issues/2788\n //\n // We should implement message pooling algorithm to overcome hardcoded NO_DELAY behaviour\n // of HTTP/2 and allow our small messages to batch together.\n //\n const grpcOptions: GrpcOptions = {\n host: this.conf.hostAndPort,\n timeout: this.conf.defaultRequestTimeout,\n channelCredentials: this.conf.ssl\n ? ChannelCredentials.createSsl()\n : ChannelCredentials.createInsecure(),\n clientOptions,\n };\n\n const grpcProxy = typeof this.conf.grpcProxy === 'string'\n ? { url: this.conf.grpcProxy }\n : this.conf.grpcProxy;\n\n if (grpcProxy?.url) {\n const url = new URL(grpcProxy.url);\n if (grpcProxy.auth) {\n const parsed = parseHttpAuth(grpcProxy.auth);\n if (parsed.scheme !== 'Basic') {\n throw new Error(`Unsupported auth scheme: ${parsed.scheme as string}.`);\n }\n url.username = parsed.username;\n url.password = parsed.password;\n }\n process.env.grpc_proxy = url.toString();\n } else {\n delete process.env.grpc_proxy;\n }\n\n const oldTransport = this._grpcTransport;\n\n this._grpcTransport = new GrpcTransport(grpcOptions);\n\n // Reset all providers to let them reinitialize their clients\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n // at the same time we need to remove providers that are no longer valid\n this.providers.splice(i, 1);\n i--;\n } else {\n provider.reset();\n }\n }\n\n if (oldTransport !== undefined) oldTransport.close();\n }\n\n private providerCleanupCounter = 0;\n\n /**\n * Creates a provider for a grpc client. Returned provider will create fresh client whenever the underlying transport is reset.\n *\n * @param clientConstructor - a factory function that creates a grpc client\n */\n public createGrpcClientProvider<Client>(clientConstructor: (transport: GrpcTransport) => Client): GrpcClientProvider<Client> {\n // We need to cleanup providers periodically to avoid memory leaks.\n // This is a simple heuristic to avoid memory leaks.\n // We could use a more sophisticated algorithm, but this is good enough for now.\n this.providerCleanupCounter++;\n if (this.providerCleanupCounter >= 16) {\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n this.providers.splice(i, 1);\n i--;\n }\n }\n this.providerCleanupCounter = 0;\n }\n\n const provider = new GrpcClientProviderImpl<Client>(() => this._grpcTransport, clientConstructor);\n this.providers.push(new WeakRef(provider));\n return provider;\n }\n\n public get grpcTransport(): GrpcTransport {\n return this._grpcTransport;\n }\n\n /** Returns true if client is authenticated. Even with anonymous auth information\n * connection is considered authenticated. Unauthenticated clients are used for\n * login and similar tasks, see {@link UnauthenticatedPlClient}. */\n public get authenticated(): boolean {\n return this.authInformation !== undefined;\n }\n\n /** null means anonymous connection */\n public get authUser(): string | null {\n if (!this.authenticated) throw new Error('Client is not authenticated');\n if (this.authInformation?.jwtToken)\n return parsePlJwt(this.authInformation?.jwtToken).user.login;\n else return null;\n }\n\n private updateStatus(newStatus: PlConnectionStatus) {\n process.nextTick(() => {\n if (this._status !== newStatus) {\n this._status = newStatus;\n if (this.statusListener !== undefined) this.statusListener(this._status);\n if (this.onAuthError !== undefined) this.onAuthError();\n }\n });\n }\n\n public get status(): PlConnectionStatus {\n return this._status;\n }\n\n private authRefreshInProgress: boolean = false;\n\n private refreshAuthInformationIfNeeded(): void {\n if (\n this.refreshTimestamp === undefined\n || Date.now() < this.refreshTimestamp\n || this.authRefreshInProgress\n || this._status === 'Unauthenticated'\n )\n return;\n\n // Running refresh in background`\n this.authRefreshInProgress = true;\n void (async () => {\n try {\n const response = await this.grpcPl.get().getJWTToken({\n expiration: {\n seconds: BigInt(this.conf.authTTLSeconds),\n nanos: 0,\n },\n }).response;\n this.authInformation = { jwtToken: response.token };\n this.refreshTimestamp = inferAuthRefreshTime(\n this.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n if (this.onAuthUpdate) this.onAuthUpdate(this.authInformation);\n } catch (e: unknown) {\n if (this.onAuthRefreshProblem) this.onAuthRefreshProblem(e);\n } finally {\n this.authRefreshInProgress = false;\n }\n })();\n }\n\n /** Detects certain errors and update client status accordingly */\n private createErrorInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n next(metadata, {\n onReceiveStatus: (status, next) => {\n if (status.code == GrpcStatus.UNAUTHENTICATED)\n // (!!!) don't change to \"===\"\n this.updateStatus('Unauthenticated');\n if (status.code == GrpcStatus.UNAVAILABLE)\n // (!!!) don't change to \"===\"\n this.updateStatus('Disconnected');\n next(status);\n },\n });\n },\n });\n };\n }\n\n /** Injects authentication information if needed */\n private createAuthInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n if (this.authInformation?.jwtToken !== undefined) {\n metadata.set('authorization', 'Bearer ' + this.authInformation.jwtToken);\n this.refreshAuthInformationIfNeeded();\n next(metadata, listener);\n } else {\n next(metadata, listener);\n }\n },\n });\n };\n }\n\n createTx(rw: boolean, ops: PlCallOps = {}): LLPlTransaction {\n return new LLPlTransaction((abortSignal) => {\n let totalAbortSignal = abortSignal;\n if (ops.abortSignal) totalAbortSignal = AbortSignal.any([totalAbortSignal, ops.abortSignal]);\n return this.grpcPl.get().tx({\n abort: totalAbortSignal,\n timeout: ops.timeout\n ?? (rw ? this.conf.defaultRWTransactionTimeout : this.conf.defaultROTransactionTimeout),\n });\n });\n }\n\n /** Closes underlying transport */\n public async close() {\n this.grpcTransport.close();\n await this.httpDispatcher.destroy();\n }\n}\n"],"names":["plAddressToConfig","auth","inferAuthRefreshTime","defaultHttpDispatcher","PlatformClient","compressionAlgorithms","ChannelCredentials","parseHttpAuth","GrpcTransport","parsePlJwt","InterceptingCall","GrpcStatus","LLPlTransaction"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ll_client.d.ts","sourceRoot":"","sources":["../../src/core/ll_client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iEAAiE,CAAC;AAQjG,OAAO,KAAK,EAEV,OAAO,EACP,cAAc,EACd,kBAAkB,EAClB,0BAA0B,EAC3B,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,QAAQ,CAAC;AAE5E,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAkBD,kEAAkE;AAClE,qBAAa,UAAW,YAAW,yBAAyB;IA2BxD,OAAO,CAAC,QAAQ,CAAC,GAAG;IA1BtB,SAAgB,IAAI,EAAE,cAAc,CAAC;IAErC,wCAAwC;IACxC,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAqC;IACnE,oFAAoF;IACpF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAa;IAC1C,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAA2B;IACjE,0DAA0D;IAC1D,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAElC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAA6B;IAE7D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAgB;IACjD,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8C;IAExE,SAAgB,MAAM,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAC;IAE3D,SAAgB,cAAc,EAAE,UAAU,CAAC;gBAGzC,eAAe,EAAE,cAAc,GAAG,MAAM,EACvB,GAAG,GAAE;QACpB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,cAAc,CAAC,EAAE,0BAA0B,CAAC;QAC5C,aAAa,CAAC,EAAE,OAAO,CAAC;KACpB;IAoCR;;;OAGG;IACH,OAAO,CAAC,QAAQ;IA8ChB,OAAO,CAAC,sBAAsB,CAAK;IAEnC;;;;OAIG;IACI,wBAAwB,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,SAAS,EAAE,aAAa,KAAK,MAAM,GAAG,kBAAkB,CAAC,MAAM,CAAC;IAqB5H,IAAW,aAAa,IAAI,aAAa,CAExC;IAED;;uEAEmE;IACnE,IAAW,aAAa,IAAI,OAAO,CAElC;IAED,sCAAsC;IACtC,IAAW,QAAQ,IAAI,MAAM,GAAG,IAAI,CAKnC;IAED,OAAO,CAAC,YAAY;IAUpB,IAAW,MAAM,IAAI,kBAAkB,CAEtC;IAED,OAAO,CAAC,qBAAqB,CAAkB;IAE/C,OAAO,CAAC,8BAA8B;IAiCtC,kEAAkE;IAClE,OAAO,CAAC,sBAAsB;IAoB9B,mDAAmD;IACnD,OAAO,CAAC,qBAAqB;IAgB7B,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,GAAE,SAAc,GAAG,eAAe;IAa3D,kCAAkC;IACrB,KAAK;CAInB"}
1
+ {"version":3,"file":"ll_client.d.ts","sourceRoot":"","sources":["../../src/core/ll_client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iEAAiE,CAAC;AAQjG,OAAO,KAAK,EAEV,OAAO,EACP,cAAc,EACd,kBAAkB,EAClB,0BAA0B,EAC3B,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,QAAQ,CAAC;AAG5E,MAAM,WAAW,SAAS;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAkBD,kEAAkE;AAClE,qBAAa,UAAW,YAAW,yBAAyB;IA2BxD,OAAO,CAAC,QAAQ,CAAC,GAAG;IA1BtB,SAAgB,IAAI,EAAE,cAAc,CAAC;IAErC,wCAAwC;IACxC,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAqC;IACnE,oFAAoF;IACpF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAa;IAC1C,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAA2B;IACjE,0DAA0D;IAC1D,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAElC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAA6B;IAE7D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAgB;IACjD,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8C;IAExE,SAAgB,MAAM,EAAE,kBAAkB,CAAC,cAAc,CAAC,CAAC;IAE3D,SAAgB,cAAc,EAAE,UAAU,CAAC;gBAGzC,eAAe,EAAE,cAAc,GAAG,MAAM,EACvB,GAAG,GAAE;QACpB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,cAAc,CAAC,EAAE,0BAA0B,CAAC;QAC5C,aAAa,CAAC,EAAE,OAAO,CAAC;KACpB;IAqCR;;;OAGG;IACH,OAAO,CAAC,QAAQ;IA8DhB,OAAO,CAAC,sBAAsB,CAAK;IAEnC;;;;OAIG;IACI,wBAAwB,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,SAAS,EAAE,aAAa,KAAK,MAAM,GAAG,kBAAkB,CAAC,MAAM,CAAC;IAqB5H,IAAW,aAAa,IAAI,aAAa,CAExC;IAED;;uEAEmE;IACnE,IAAW,aAAa,IAAI,OAAO,CAElC;IAED,sCAAsC;IACtC,IAAW,QAAQ,IAAI,MAAM,GAAG,IAAI,CAKnC;IAED,OAAO,CAAC,YAAY;IAUpB,IAAW,MAAM,IAAI,kBAAkB,CAEtC;IAED,OAAO,CAAC,qBAAqB,CAAkB;IAE/C,OAAO,CAAC,8BAA8B;IAiCtC,kEAAkE;IAClE,OAAO,CAAC,sBAAsB;IAoB9B,mDAAmD;IACnD,OAAO,CAAC,qBAAqB;IAgB7B,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,GAAE,SAAc,GAAG,eAAe;IAY3D,kCAAkC;IACrB,KAAK;CAInB"}
@@ -6,6 +6,7 @@ import { LLPlTransaction } from './ll_transaction.js';
6
6
  import { parsePlJwt } from '../util/pl.js';
7
7
  import { inferAuthRefreshTime } from './auth.js';
8
8
  import { defaultHttpDispatcher } from '@milaboratories/pl-http';
9
+ import { parseHttpAuth } from '@milaboratories/pl-model-common';
9
10
 
10
11
  class GrpcClientProviderImpl {
11
12
  grpcTransport;
@@ -47,8 +48,9 @@ class LLPlClient {
47
48
  httpDispatcher;
48
49
  constructor(configOrAddress, ops = {}) {
49
50
  this.ops = ops;
50
- this.conf
51
- = typeof configOrAddress === 'string' ? plAddressToConfig(configOrAddress) : configOrAddress;
51
+ this.conf = typeof configOrAddress === 'string'
52
+ ? plAddressToConfig(configOrAddress)
53
+ : configOrAddress;
52
54
  this.grpcInterceptors = [];
53
55
  const { auth, statusListener, shouldUseGzip } = ops;
54
56
  if (auth !== undefined) {
@@ -95,10 +97,24 @@ class LLPlClient {
95
97
  : ChannelCredentials.createInsecure(),
96
98
  clientOptions,
97
99
  };
98
- if (this.conf.grpcProxy)
99
- process.env.grpc_proxy = this.conf.grpcProxy;
100
- else
100
+ const grpcProxy = typeof this.conf.grpcProxy === 'string'
101
+ ? { url: this.conf.grpcProxy }
102
+ : this.conf.grpcProxy;
103
+ if (grpcProxy?.url) {
104
+ const url = new URL(grpcProxy.url);
105
+ if (grpcProxy.auth) {
106
+ const parsed = parseHttpAuth(grpcProxy.auth);
107
+ if (parsed.scheme !== 'Basic') {
108
+ throw new Error(`Unsupported auth scheme: ${parsed.scheme}.`);
109
+ }
110
+ url.username = parsed.username;
111
+ url.password = parsed.password;
112
+ }
113
+ process.env.grpc_proxy = url.toString();
114
+ }
115
+ else {
101
116
  delete process.env.grpc_proxy;
117
+ }
102
118
  const oldTransport = this._grpcTransport;
103
119
  this._grpcTransport = new GrpcTransport(grpcOptions);
104
120
  // Reset all providers to let them reinitialize their clients
@@ -1 +1 @@
1
- {"version":3,"file":"ll_client.js","sources":["../../src/core/ll_client.ts"],"sourcesContent":["import { PlatformClient } from '../proto/github.com/milaboratory/pl/plapi/plapiproto/api.client';\nimport type { ClientOptions, Interceptor } from '@grpc/grpc-js';\nimport {\n ChannelCredentials,\n InterceptingCall,\n status as GrpcStatus,\n compressionAlgorithms,\n} from '@grpc/grpc-js';\nimport type {\n AuthInformation,\n AuthOps,\n PlClientConfig,\n PlConnectionStatus,\n PlConnectionStatusListener,\n} from './config';\nimport { plAddressToConfig } from './config';\nimport type { GrpcOptions } from '@protobuf-ts/grpc-transport';\nimport { GrpcTransport } from '@protobuf-ts/grpc-transport';\nimport { LLPlTransaction } from './ll_transaction';\nimport { parsePlJwt } from '../util/pl';\nimport type { Dispatcher } from 'undici';\nimport { inferAuthRefreshTime } from './auth';\nimport { defaultHttpDispatcher } from '@milaboratories/pl-http';\nimport type { GrpcClientProvider, GrpcClientProviderFactory } from './grpc';\n\nexport interface PlCallOps {\n timeout?: number;\n abortSignal?: AbortSignal;\n}\n\nclass GrpcClientProviderImpl<Client> implements GrpcClientProvider<Client> {\n private client: Client | undefined = undefined;\n\n constructor(private readonly grpcTransport: () => GrpcTransport, private readonly clientConstructor: (transport: GrpcTransport) => Client) {}\n\n public reset(): void {\n this.client = undefined;\n }\n\n public get(): Client {\n if (this.client === undefined)\n this.client = this.clientConstructor(this.grpcTransport());\n return this.client;\n }\n}\n\n/** Abstract out low level networking and authorization details */\nexport class LLPlClient implements GrpcClientProviderFactory {\n public readonly conf: PlClientConfig;\n\n /** Initial authorization information */\n private authInformation?: AuthInformation;\n /** Will be executed by the client when it is required */\n private readonly onAuthUpdate?: (newInfo: AuthInformation) => void;\n /** Will be executed if auth-related error happens during normal client operation */\n private readonly onAuthError?: () => void;\n /** Will be executed by the client when it is required */\n private readonly onAuthRefreshProblem?: (error: unknown) => void;\n /** Threshold after which auth info refresh is required */\n private refreshTimestamp?: number;\n\n private _status: PlConnectionStatus = 'OK';\n private readonly statusListener?: PlConnectionStatusListener;\n\n private readonly grpcInterceptors: Interceptor[];\n private _grpcTransport!: GrpcTransport;\n private readonly providers: WeakRef<GrpcClientProviderImpl<any>>[] = [];\n\n public readonly grpcPl: GrpcClientProvider<PlatformClient>;\n\n public readonly httpDispatcher: Dispatcher;\n\n constructor(\n configOrAddress: PlClientConfig | string,\n private readonly ops: {\n auth?: AuthOps;\n statusListener?: PlConnectionStatusListener;\n shouldUseGzip?: boolean;\n } = {},\n ) {\n this.conf\n = typeof configOrAddress === 'string' ? plAddressToConfig(configOrAddress) : configOrAddress;\n\n this.grpcInterceptors = [];\n\n const { auth, statusListener, shouldUseGzip } = ops;\n\n if (auth !== undefined) {\n this.refreshTimestamp = inferAuthRefreshTime(\n auth.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n this.grpcInterceptors.push(this.createAuthInterceptor());\n this.authInformation = auth.authInformation;\n this.onAuthUpdate = auth.onUpdate;\n this.onAuthRefreshProblem = auth.onUpdateError;\n this.onAuthError = auth.onAuthError;\n }\n\n this.grpcInterceptors.push(this.createErrorInterceptor());\n\n // initialize _grpcTransport and _grpcPl\n this.initGrpc(shouldUseGzip ?? false);\n\n this.httpDispatcher = defaultHttpDispatcher(this.conf.httpProxy);\n\n if (statusListener !== undefined) {\n this.statusListener = statusListener;\n statusListener(this._status);\n }\n\n this.grpcPl = this.createGrpcClientProvider((transport) => new PlatformClient(transport));\n }\n\n /**\n * Initializes (or reinitializes) _grpcTransport and _grpcPl\n * @param gzip - whether to enable gzip compression\n */\n private initGrpc(gzip: boolean) {\n const clientOptions: ClientOptions = {\n 'grpc.keepalive_time_ms': 30_000, // 30 seconds\n 'interceptors': this.grpcInterceptors,\n };\n\n if (gzip) clientOptions['grpc.default_compression_algorithm'] = compressionAlgorithms.gzip;\n\n //\n // Leaving it here for now\n // https://github.com/grpc/grpc-node/issues/2788\n //\n // We should implement message pooling algorithm to overcome hardcoded NO_DELAY behaviour\n // of HTTP/2 and allow our small messages to batch together.\n //\n const grpcOptions: GrpcOptions = {\n host: this.conf.hostAndPort,\n timeout: this.conf.defaultRequestTimeout,\n channelCredentials: this.conf.ssl\n ? ChannelCredentials.createSsl()\n : ChannelCredentials.createInsecure(),\n clientOptions,\n };\n\n if (this.conf.grpcProxy) process.env.grpc_proxy = this.conf.grpcProxy;\n else delete process.env.grpc_proxy;\n\n const oldTransport = this._grpcTransport;\n\n this._grpcTransport = new GrpcTransport(grpcOptions);\n\n // Reset all providers to let them reinitialize their clients\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n // at the same time we need to remove providers that are no longer valid\n this.providers.splice(i, 1);\n i--;\n } else {\n provider.reset();\n }\n }\n\n if (oldTransport !== undefined) oldTransport.close();\n }\n\n private providerCleanupCounter = 0;\n\n /**\n * Creates a provider for a grpc client. Returned provider will create fresh client whenever the underlying transport is reset.\n *\n * @param clientConstructor - a factory function that creates a grpc client\n */\n public createGrpcClientProvider<Client>(clientConstructor: (transport: GrpcTransport) => Client): GrpcClientProvider<Client> {\n // We need to cleanup providers periodically to avoid memory leaks.\n // This is a simple heuristic to avoid memory leaks.\n // We could use a more sophisticated algorithm, but this is good enough for now.\n this.providerCleanupCounter++;\n if (this.providerCleanupCounter >= 16) {\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n this.providers.splice(i, 1);\n i--;\n }\n }\n this.providerCleanupCounter = 0;\n }\n\n const provider = new GrpcClientProviderImpl<Client>(() => this._grpcTransport, clientConstructor);\n this.providers.push(new WeakRef(provider));\n return provider;\n }\n\n public get grpcTransport(): GrpcTransport {\n return this._grpcTransport;\n }\n\n /** Returns true if client is authenticated. Even with anonymous auth information\n * connection is considered authenticated. Unauthenticated clients are used for\n * login and similar tasks, see {@link UnauthenticatedPlClient}. */\n public get authenticated(): boolean {\n return this.authInformation !== undefined;\n }\n\n /** null means anonymous connection */\n public get authUser(): string | null {\n if (!this.authenticated) throw new Error('Client is not authenticated');\n if (this.authInformation?.jwtToken)\n return parsePlJwt(this.authInformation?.jwtToken).user.login;\n else return null;\n }\n\n private updateStatus(newStatus: PlConnectionStatus) {\n process.nextTick(() => {\n if (this._status !== newStatus) {\n this._status = newStatus;\n if (this.statusListener !== undefined) this.statusListener(this._status);\n if (this.onAuthError !== undefined) this.onAuthError();\n }\n });\n }\n\n public get status(): PlConnectionStatus {\n return this._status;\n }\n\n private authRefreshInProgress: boolean = false;\n\n private refreshAuthInformationIfNeeded(): void {\n if (\n this.refreshTimestamp === undefined\n || Date.now() < this.refreshTimestamp\n || this.authRefreshInProgress\n || this._status === 'Unauthenticated'\n )\n return;\n\n // Running refresh in background`\n this.authRefreshInProgress = true;\n void (async () => {\n try {\n const response = await this.grpcPl.get().getJWTToken({\n expiration: {\n seconds: BigInt(this.conf.authTTLSeconds),\n nanos: 0,\n },\n }).response;\n this.authInformation = { jwtToken: response.token };\n this.refreshTimestamp = inferAuthRefreshTime(\n this.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n if (this.onAuthUpdate) this.onAuthUpdate(this.authInformation);\n } catch (e: unknown) {\n if (this.onAuthRefreshProblem) this.onAuthRefreshProblem(e);\n } finally {\n this.authRefreshInProgress = false;\n }\n })();\n }\n\n /** Detects certain errors and update client status accordingly */\n private createErrorInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n next(metadata, {\n onReceiveStatus: (status, next) => {\n if (status.code == GrpcStatus.UNAUTHENTICATED)\n // (!!!) don't change to \"===\"\n this.updateStatus('Unauthenticated');\n if (status.code == GrpcStatus.UNAVAILABLE)\n // (!!!) don't change to \"===\"\n this.updateStatus('Disconnected');\n next(status);\n },\n });\n },\n });\n };\n }\n\n /** Injects authentication information if needed */\n private createAuthInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n if (this.authInformation?.jwtToken !== undefined) {\n metadata.set('authorization', 'Bearer ' + this.authInformation.jwtToken);\n this.refreshAuthInformationIfNeeded();\n next(metadata, listener);\n } else {\n next(metadata, listener);\n }\n },\n });\n };\n }\n\n createTx(rw: boolean, ops: PlCallOps = {}): LLPlTransaction {\n return new LLPlTransaction((abortSignal) => {\n let totalAbortSignal = abortSignal;\n if (ops.abortSignal) totalAbortSignal = AbortSignal.any([totalAbortSignal, ops.abortSignal]);\n return this.grpcPl.get().tx({\n abort: totalAbortSignal,\n timeout:\n ops.timeout\n ?? (rw ? this.conf.defaultRWTransactionTimeout : this.conf.defaultROTransactionTimeout),\n });\n });\n }\n\n /** Closes underlying transport */\n public async close() {\n this.grpcTransport.close();\n await this.httpDispatcher.destroy();\n }\n}\n"],"names":["status","GrpcStatus"],"mappings":"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"}
1
+ {"version":3,"file":"ll_client.js","sources":["../../src/core/ll_client.ts"],"sourcesContent":["import { PlatformClient } from '../proto/github.com/milaboratory/pl/plapi/plapiproto/api.client';\nimport type { ClientOptions, Interceptor } from '@grpc/grpc-js';\nimport {\n ChannelCredentials,\n InterceptingCall,\n status as GrpcStatus,\n compressionAlgorithms,\n} from '@grpc/grpc-js';\nimport type {\n AuthInformation,\n AuthOps,\n PlClientConfig,\n PlConnectionStatus,\n PlConnectionStatusListener,\n} from './config';\nimport { plAddressToConfig } from './config';\nimport type { GrpcOptions } from '@protobuf-ts/grpc-transport';\nimport { GrpcTransport } from '@protobuf-ts/grpc-transport';\nimport { LLPlTransaction } from './ll_transaction';\nimport { parsePlJwt } from '../util/pl';\nimport type { Dispatcher } from 'undici';\nimport { inferAuthRefreshTime } from './auth';\nimport { defaultHttpDispatcher } from '@milaboratories/pl-http';\nimport type { GrpcClientProvider, GrpcClientProviderFactory } from './grpc';\nimport { parseHttpAuth } from '@milaboratories/pl-model-common';\n\nexport interface PlCallOps {\n timeout?: number;\n abortSignal?: AbortSignal;\n}\n\nclass GrpcClientProviderImpl<Client> implements GrpcClientProvider<Client> {\n private client: Client | undefined = undefined;\n\n constructor(private readonly grpcTransport: () => GrpcTransport, private readonly clientConstructor: (transport: GrpcTransport) => Client) {}\n\n public reset(): void {\n this.client = undefined;\n }\n\n public get(): Client {\n if (this.client === undefined)\n this.client = this.clientConstructor(this.grpcTransport());\n return this.client;\n }\n}\n\n/** Abstract out low level networking and authorization details */\nexport class LLPlClient implements GrpcClientProviderFactory {\n public readonly conf: PlClientConfig;\n\n /** Initial authorization information */\n private authInformation?: AuthInformation;\n /** Will be executed by the client when it is required */\n private readonly onAuthUpdate?: (newInfo: AuthInformation) => void;\n /** Will be executed if auth-related error happens during normal client operation */\n private readonly onAuthError?: () => void;\n /** Will be executed by the client when it is required */\n private readonly onAuthRefreshProblem?: (error: unknown) => void;\n /** Threshold after which auth info refresh is required */\n private refreshTimestamp?: number;\n\n private _status: PlConnectionStatus = 'OK';\n private readonly statusListener?: PlConnectionStatusListener;\n\n private readonly grpcInterceptors: Interceptor[];\n private _grpcTransport!: GrpcTransport;\n private readonly providers: WeakRef<GrpcClientProviderImpl<any>>[] = [];\n\n public readonly grpcPl: GrpcClientProvider<PlatformClient>;\n\n public readonly httpDispatcher: Dispatcher;\n\n constructor(\n configOrAddress: PlClientConfig | string,\n private readonly ops: {\n auth?: AuthOps;\n statusListener?: PlConnectionStatusListener;\n shouldUseGzip?: boolean;\n } = {},\n ) {\n this.conf = typeof configOrAddress === 'string'\n ? plAddressToConfig(configOrAddress)\n : configOrAddress;\n\n this.grpcInterceptors = [];\n\n const { auth, statusListener, shouldUseGzip } = ops;\n\n if (auth !== undefined) {\n this.refreshTimestamp = inferAuthRefreshTime(\n auth.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n this.grpcInterceptors.push(this.createAuthInterceptor());\n this.authInformation = auth.authInformation;\n this.onAuthUpdate = auth.onUpdate;\n this.onAuthRefreshProblem = auth.onUpdateError;\n this.onAuthError = auth.onAuthError;\n }\n\n this.grpcInterceptors.push(this.createErrorInterceptor());\n\n // initialize _grpcTransport and _grpcPl\n this.initGrpc(shouldUseGzip ?? false);\n\n this.httpDispatcher = defaultHttpDispatcher(this.conf.httpProxy);\n\n if (statusListener !== undefined) {\n this.statusListener = statusListener;\n statusListener(this._status);\n }\n\n this.grpcPl = this.createGrpcClientProvider((transport) => new PlatformClient(transport));\n }\n\n /**\n * Initializes (or reinitializes) _grpcTransport and _grpcPl\n * @param gzip - whether to enable gzip compression\n */\n private initGrpc(gzip: boolean) {\n const clientOptions: ClientOptions = {\n 'grpc.keepalive_time_ms': 30_000, // 30 seconds\n 'interceptors': this.grpcInterceptors,\n };\n\n if (gzip) clientOptions['grpc.default_compression_algorithm'] = compressionAlgorithms.gzip;\n\n //\n // Leaving it here for now\n // https://github.com/grpc/grpc-node/issues/2788\n //\n // We should implement message pooling algorithm to overcome hardcoded NO_DELAY behaviour\n // of HTTP/2 and allow our small messages to batch together.\n //\n const grpcOptions: GrpcOptions = {\n host: this.conf.hostAndPort,\n timeout: this.conf.defaultRequestTimeout,\n channelCredentials: this.conf.ssl\n ? ChannelCredentials.createSsl()\n : ChannelCredentials.createInsecure(),\n clientOptions,\n };\n\n const grpcProxy = typeof this.conf.grpcProxy === 'string'\n ? { url: this.conf.grpcProxy }\n : this.conf.grpcProxy;\n\n if (grpcProxy?.url) {\n const url = new URL(grpcProxy.url);\n if (grpcProxy.auth) {\n const parsed = parseHttpAuth(grpcProxy.auth);\n if (parsed.scheme !== 'Basic') {\n throw new Error(`Unsupported auth scheme: ${parsed.scheme as string}.`);\n }\n url.username = parsed.username;\n url.password = parsed.password;\n }\n process.env.grpc_proxy = url.toString();\n } else {\n delete process.env.grpc_proxy;\n }\n\n const oldTransport = this._grpcTransport;\n\n this._grpcTransport = new GrpcTransport(grpcOptions);\n\n // Reset all providers to let them reinitialize their clients\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n // at the same time we need to remove providers that are no longer valid\n this.providers.splice(i, 1);\n i--;\n } else {\n provider.reset();\n }\n }\n\n if (oldTransport !== undefined) oldTransport.close();\n }\n\n private providerCleanupCounter = 0;\n\n /**\n * Creates a provider for a grpc client. Returned provider will create fresh client whenever the underlying transport is reset.\n *\n * @param clientConstructor - a factory function that creates a grpc client\n */\n public createGrpcClientProvider<Client>(clientConstructor: (transport: GrpcTransport) => Client): GrpcClientProvider<Client> {\n // We need to cleanup providers periodically to avoid memory leaks.\n // This is a simple heuristic to avoid memory leaks.\n // We could use a more sophisticated algorithm, but this is good enough for now.\n this.providerCleanupCounter++;\n if (this.providerCleanupCounter >= 16) {\n for (let i = 0; i < this.providers.length; i++) {\n const provider = this.providers[i].deref();\n if (provider === undefined) {\n this.providers.splice(i, 1);\n i--;\n }\n }\n this.providerCleanupCounter = 0;\n }\n\n const provider = new GrpcClientProviderImpl<Client>(() => this._grpcTransport, clientConstructor);\n this.providers.push(new WeakRef(provider));\n return provider;\n }\n\n public get grpcTransport(): GrpcTransport {\n return this._grpcTransport;\n }\n\n /** Returns true if client is authenticated. Even with anonymous auth information\n * connection is considered authenticated. Unauthenticated clients are used for\n * login and similar tasks, see {@link UnauthenticatedPlClient}. */\n public get authenticated(): boolean {\n return this.authInformation !== undefined;\n }\n\n /** null means anonymous connection */\n public get authUser(): string | null {\n if (!this.authenticated) throw new Error('Client is not authenticated');\n if (this.authInformation?.jwtToken)\n return parsePlJwt(this.authInformation?.jwtToken).user.login;\n else return null;\n }\n\n private updateStatus(newStatus: PlConnectionStatus) {\n process.nextTick(() => {\n if (this._status !== newStatus) {\n this._status = newStatus;\n if (this.statusListener !== undefined) this.statusListener(this._status);\n if (this.onAuthError !== undefined) this.onAuthError();\n }\n });\n }\n\n public get status(): PlConnectionStatus {\n return this._status;\n }\n\n private authRefreshInProgress: boolean = false;\n\n private refreshAuthInformationIfNeeded(): void {\n if (\n this.refreshTimestamp === undefined\n || Date.now() < this.refreshTimestamp\n || this.authRefreshInProgress\n || this._status === 'Unauthenticated'\n )\n return;\n\n // Running refresh in background`\n this.authRefreshInProgress = true;\n void (async () => {\n try {\n const response = await this.grpcPl.get().getJWTToken({\n expiration: {\n seconds: BigInt(this.conf.authTTLSeconds),\n nanos: 0,\n },\n }).response;\n this.authInformation = { jwtToken: response.token };\n this.refreshTimestamp = inferAuthRefreshTime(\n this.authInformation,\n this.conf.authMaxRefreshSeconds,\n );\n if (this.onAuthUpdate) this.onAuthUpdate(this.authInformation);\n } catch (e: unknown) {\n if (this.onAuthRefreshProblem) this.onAuthRefreshProblem(e);\n } finally {\n this.authRefreshInProgress = false;\n }\n })();\n }\n\n /** Detects certain errors and update client status accordingly */\n private createErrorInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n next(metadata, {\n onReceiveStatus: (status, next) => {\n if (status.code == GrpcStatus.UNAUTHENTICATED)\n // (!!!) don't change to \"===\"\n this.updateStatus('Unauthenticated');\n if (status.code == GrpcStatus.UNAVAILABLE)\n // (!!!) don't change to \"===\"\n this.updateStatus('Disconnected');\n next(status);\n },\n });\n },\n });\n };\n }\n\n /** Injects authentication information if needed */\n private createAuthInterceptor(): Interceptor {\n return (options, nextCall) => {\n return new InterceptingCall(nextCall(options), {\n start: (metadata, listener, next) => {\n if (this.authInformation?.jwtToken !== undefined) {\n metadata.set('authorization', 'Bearer ' + this.authInformation.jwtToken);\n this.refreshAuthInformationIfNeeded();\n next(metadata, listener);\n } else {\n next(metadata, listener);\n }\n },\n });\n };\n }\n\n createTx(rw: boolean, ops: PlCallOps = {}): LLPlTransaction {\n return new LLPlTransaction((abortSignal) => {\n let totalAbortSignal = abortSignal;\n if (ops.abortSignal) totalAbortSignal = AbortSignal.any([totalAbortSignal, ops.abortSignal]);\n return this.grpcPl.get().tx({\n abort: totalAbortSignal,\n timeout: ops.timeout\n ?? (rw ? this.conf.defaultRWTransactionTimeout : this.conf.defaultROTransactionTimeout),\n });\n });\n }\n\n /** Closes underlying transport */\n public async close() {\n this.grpcTransport.close();\n await this.httpDispatcher.destroy();\n }\n}\n"],"names":["status","GrpcStatus"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/pl-client",
3
- "version": "2.14.0",
3
+ "version": "2.15.0",
4
4
  "engines": {
5
5
  "node": ">=22.19.0"
6
6
  },
@@ -27,27 +27,28 @@
27
27
  "@protobuf-ts/runtime-rpc": "2.11.1",
28
28
  "canonicalize": "~2.1.0",
29
29
  "denque": "^2.1.0",
30
- "lru-cache": "^11.2.2",
31
30
  "https-proxy-agent": "^7.0.6",
32
31
  "long": "^5.3.2",
32
+ "lru-cache": "^11.2.2",
33
33
  "undici": "~7.16.0",
34
34
  "utility-types": "^3.11.0",
35
35
  "yaml": "^2.8.0",
36
- "@milaboratories/pl-http": "1.2.0",
37
- "@milaboratories/ts-helpers": "1.5.1"
36
+ "@milaboratories/pl-model-common": "1.21.2",
37
+ "@milaboratories/ts-helpers": "1.5.1",
38
+ "@milaboratories/pl-http": "1.2.0"
38
39
  },
39
40
  "devDependencies": {
40
- "typescript": "~5.6.3",
41
- "@types/node": "~24.5.2",
41
+ "@jest/globals": "^29.7.0",
42
42
  "@protobuf-ts/plugin": "2.11.1",
43
43
  "@types/http-proxy": "^1.17.16",
44
44
  "@types/jest": "^29.5.14",
45
+ "@types/node": "~24.5.2",
45
46
  "jest": "^29.7.0",
46
- "@jest/globals": "^29.7.0",
47
47
  "ts-jest": "^29.2.6",
48
- "@milaboratories/build-configs": "1.0.8",
48
+ "typescript": "~5.6.3",
49
+ "@milaboratories/ts-builder": "1.0.5",
49
50
  "@milaboratories/ts-configs": "1.0.6",
50
- "@milaboratories/ts-builder": "1.0.5"
51
+ "@milaboratories/build-configs": "1.0.8"
51
52
  },
52
53
  "scripts": {
53
54
  "type-check": "ts-builder types --target node",
@@ -34,8 +34,8 @@ export interface PlClientConfig {
34
34
  * expiration time. */
35
35
  authMaxRefreshSeconds: number;
36
36
 
37
- /** Proxy server URL to use for pl connection. */
38
- grpcProxy?: string;
37
+ /** Proxy server config to use for pl connection. */
38
+ grpcProxy?: string | ProxySettings;
39
39
  /** Proxy server config to use for http connections of pl drivers, like file
40
40
  * downloading. */
41
41
  httpProxy?: string | ProxySettings;
@@ -22,6 +22,7 @@ import type { Dispatcher } from 'undici';
22
22
  import { inferAuthRefreshTime } from './auth';
23
23
  import { defaultHttpDispatcher } from '@milaboratories/pl-http';
24
24
  import type { GrpcClientProvider, GrpcClientProviderFactory } from './grpc';
25
+ import { parseHttpAuth } from '@milaboratories/pl-model-common';
25
26
 
26
27
  export interface PlCallOps {
27
28
  timeout?: number;
@@ -78,8 +79,9 @@ export class LLPlClient implements GrpcClientProviderFactory {
78
79
  shouldUseGzip?: boolean;
79
80
  } = {},
80
81
  ) {
81
- this.conf
82
- = typeof configOrAddress === 'string' ? plAddressToConfig(configOrAddress) : configOrAddress;
82
+ this.conf = typeof configOrAddress === 'string'
83
+ ? plAddressToConfig(configOrAddress)
84
+ : configOrAddress;
83
85
 
84
86
  this.grpcInterceptors = [];
85
87
 
@@ -140,8 +142,24 @@ export class LLPlClient implements GrpcClientProviderFactory {
140
142
  clientOptions,
141
143
  };
142
144
 
143
- if (this.conf.grpcProxy) process.env.grpc_proxy = this.conf.grpcProxy;
144
- else delete process.env.grpc_proxy;
145
+ const grpcProxy = typeof this.conf.grpcProxy === 'string'
146
+ ? { url: this.conf.grpcProxy }
147
+ : this.conf.grpcProxy;
148
+
149
+ if (grpcProxy?.url) {
150
+ const url = new URL(grpcProxy.url);
151
+ if (grpcProxy.auth) {
152
+ const parsed = parseHttpAuth(grpcProxy.auth);
153
+ if (parsed.scheme !== 'Basic') {
154
+ throw new Error(`Unsupported auth scheme: ${parsed.scheme as string}.`);
155
+ }
156
+ url.username = parsed.username;
157
+ url.password = parsed.password;
158
+ }
159
+ process.env.grpc_proxy = url.toString();
160
+ } else {
161
+ delete process.env.grpc_proxy;
162
+ }
145
163
 
146
164
  const oldTransport = this._grpcTransport;
147
165
 
@@ -302,8 +320,7 @@ export class LLPlClient implements GrpcClientProviderFactory {
302
320
  if (ops.abortSignal) totalAbortSignal = AbortSignal.any([totalAbortSignal, ops.abortSignal]);
303
321
  return this.grpcPl.get().tx({
304
322
  abort: totalAbortSignal,
305
- timeout:
306
- ops.timeout
323
+ timeout: ops.timeout
307
324
  ?? (rw ? this.conf.defaultRWTransactionTimeout : this.conf.defaultROTransactionTimeout),
308
325
  });
309
326
  });