@whaly/connector-sdk 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +5 -6
- package/dist/index.d.ts +5 -6
- package/dist/index.js +15 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sdk/utils.ts","../src/sdk/service/logger.ts","../src/sdk/service/network.ts","../src/sdk/service/metric.ts","../src/sdk/service/memory.ts","../src/sdk/service/exit.ts","../src/sdk/service/error.ts","../src/sdk/models/replication.ts","../src/sdk/models/messages.ts","../src/sdk/models/state.ts","../src/sdk/constants/date.ts","../src/sdk/models/tap/authenticator.ts","../src/sdk/models/tap/restStream.ts","../src/sdk/models/tap/stream.ts","../src/sdk/helpers/typing.ts","../src/sdk/models/tap/tap.ts","../src/sdk/helpers/qs-logger.ts","../src/sdk/models/target/dbSync.ts","../src/sdk/models/target/error.ts","../src/sdk/models/target/record.ts","../src/sdk/models/target/renameColumnStore.ts","../src/sdk/models/target/schema.ts","../src/sdk/models/target/target.ts","../src/sdk/models/target/streamDbState.ts","../src/sdk/models/target/temporaryFile.ts","../src/sdk/file-processing/types.ts","../src/sdk/file-processing/schema-utils.ts","../src/sdk/file-processing/excel/reader.ts","../src/sdk/file-processing/excel/config-builder.ts","../src/sdk/file-processing/csv/reader.ts","../src/sdk/file-processing/csv/writer.ts","../src/sdk/file-processing/file-stream.ts","../src/sdk/file-processing/csv/config-builder.ts","../src/sdk/file-processing/file-tap.ts","../src/sdk/file-processing/file-patterns.ts","../src/services/sftp.ts","../src/services/cloud-storage.ts","../src/services/zip.ts","../src/targets/bigquery/helpers.ts","../src/targets/bigquery/service/record.ts","../src/targets/bigquery/service/dbSync.ts","../src/targets/bigquery/service/bigquery.ts","../src/targets/bigquery/main.ts","../src/state-providers/gcs/main.ts"],"sourcesContent":["import { readFileSync } from \"fs\";\nimport { logger } from \"./service/logger.js\";\n\nfunction readFile(fileName: string, filePath: string) {\n try {\n return readFileSync(filePath);\n } catch (err) {\n logger.error(`Can't open file: \\`${fileName}\\` at path: \\`${filePath}\\`. Is it at the proper place?`)\n throw err;\n }\n}\n\nfunction parseFileContent(fileName: string, fileContent: Buffer) {\n try {\n return JSON.parse(fileContent.toString());\n } catch (err) {\n logger.error(`Can't parse file: \\`${fileName}\\` as JSON. Is it properly formatted?`)\n throw err;\n }\n}\n\nexport const loadJson = (fileName: string): any => {\n const filePath = process.cwd() + `/` + fileName\n const fileContent = readFile(fileName, filePath);\n return parseFileContent(fileName, fileContent);\n}\n\nexport const loadSchema = (streamId: string) => {\n const schema = loadJson(`schemas/${streamId}.json`)\n return schema;\n}","import * as winston from \"winston\";\nexport const BATCH_INTERVAL_MS = 100;\n\nconst transports = {\n console: new winston.transports.Console({\n stderrLevels: [],\n level: 'info'\n })\n};\n\nconst getTransports = (): winston.transport[] => {\n return [\n transports.console\n ]\n}\n\nconst { combine, prettyPrint, timestamp, errors, splat } = winston.format;\n\nconst winstonLogger = winston.createLogger({\n format: combine(\n timestamp(),\n errors({ stack: true }),\n splat(),\n prettyPrint()\n ),\n transports: getTransports(),\n});\n\nlet isWinstonOpen = true;\nconst closeWinston = (cb: () => void) => {\n isWinstonOpen = false;\n winstonLogger.end();\n winstonLogger.on('finish', () => {\n setTimeout(() => {\n return cb()\n }, BATCH_INTERVAL_MS * 2)\n });\n}\n\ntype LogLevel = 'info' | 'error' | 'debug' | 'warn';\n\nconst log = (\n level: LogLevel,\n message: string | any,\n ...args: any[]\n): void => {\n if (isWinstonOpen) {\n winstonLogger[level](message, ...args);\n } else {\n console[level](message, ...args);\n }\n};\n\nexport const logger = {\n info: (message: string | any, ...args: any[]): void => log('info', message, ...args),\n error: (message: string | any, ...args: any[]): void => log('error', message, ...args),\n debug: (message: string | any, ...args: any[]): void => log('debug', message, ...args),\n warn: (message: string | any, ...args: any[]): void => log('warn', message, ...args),\n closeWinston\n}","import axios, { AxiosError, AxiosInstance, AxiosResponse, AxiosRequestConfig, AxiosRequestHeaders } from \"axios\";\nimport { URLSearchParams } from \"url\";\nimport * as fs from 'fs';\nimport * as qs from 'qs';\nimport axiosRetry, { isNetworkOrIdempotentRequestError } from 'axios-retry';\nimport { logger } from \"./logger\";\n\n// This retry regardless of whether the call is idempotent or not. \n// e.g. this will retry POST and PUT.\n// Hence, this service and all its function SHOULD not be used to create things as it is not safe. \n// This service should be only used for extracting data.\nconst shouldRetry = (error: AxiosError): boolean => {\n\n const statusCode = error.response ? error.response.status : 0;\n\n return error.code !== 'ECONNABORTED' // Triggered if there is not enough local socket. In those case, retrying will only make things worse\n && (\n !error.response\n || statusCode === 429\n || statusCode === 409\n || statusCode === 400\n || (statusCode >= 500 && statusCode < 599)\n );\n}\n\nexport const getAxiosInstance = (retryCount?: number): AxiosInstance => {\n const instance = axios.create({\n timeout: 120_000\n });\n axiosRetry(instance,\n {\n retries: retryCount || 24,\n retryDelay: (retryCount, error) => {\n logger.info(`🔁 Retrying for the ${retryCount}th time the call for \n method=${error.config?.method}\n url=${error.config?.url}\n params=%j\n body=%j`,\n error.config?.params,\n error.config?.data\n )\n if (retryCount > 6) {\n return 10000\n }\n return axiosRetry.exponentialDelay(retryCount)\n },\n retryCondition: (error: AxiosError): boolean => {\n logger.debug(`😱 Got an error for ${error.config?.method} ${error.config?.url}\n \n Status: ${error?.response?.status}\n Error code ${error.code}\n Error config method ${error}`)\n\n return isNetworkOrIdempotentRequestError(error)\n || shouldRetry(error)\n }\n });\n return instance;\n}\n\nexport interface GetConfig {\n qs?: { [key: string]: any },\n headers?: AxiosRequestHeaders,\n retryCount?: number\n}\n\nexport const getRawJSONApiCall = async <T>(\n endpoint: string,\n config: GetConfig,\n privateLogging?: boolean\n): Promise<AxiosResponse<T>> => {\n\n const instance = getAxiosInstance(config.retryCount);\n\n // Repeat the key/value pair multiple time when having arrays to be passed in the QS\n const paramsSerializer = (params: any) => {\n return qs.stringify(params, { arrayFormat: 'repeat' })\n }\n\n try {\n logger.info(`🤖 GET ${endpoint}`, { private: privateLogging })\n const requestConfig: AxiosRequestConfig = {\n params: config.qs,\n paramsSerializer: { serialize: (params) => qs.stringify(params, { arrayFormat: 'repeat' }) }\n };\n if (config.headers) {\n requestConfig.headers = config.headers;\n }\n const response = await instance.get(\n endpoint,\n requestConfig\n );\n return response;\n } catch (err: any) {\n if (err.response.status > 400) {\n throw new Error(`We got a \\`${err.response.status}\\` status code from endpoint: \\`${endpoint}\\`. \n\n headers response: ${JSON.stringify(err.response.headers)}\n\n Response body from the server: ${JSON.stringify(err.response.data)}`);\n }\n throw err;\n }\n}\n\nexport const getJSONApiCallWithFullResponse = async <T>(\n endpoint: string,\n config: GetConfig,\n privateLogging?: boolean\n) => {\n const instance = getAxiosInstance(config.retryCount);\n\n // Repeat the key/value pair multiple time when having arrays to be passed in the QS\n const paramsSerializer = (params: any) => {\n return qs.stringify(params, { arrayFormat: 'repeat' })\n }\n\n try {\n logger.info(`🤖 GET ${endpoint} with params: %s`, config.qs, { private: privateLogging })\n const requestConfig: AxiosRequestConfig = {\n params: config.qs,\n paramsSerializer: { serialize: (params) => qs.stringify(params, { arrayFormat: 'repeat' }) }\n };\n if (config.headers) {\n requestConfig.headers = config.headers;\n }\n const response = await instance.get(endpoint, requestConfig);\n return response;\n } catch (err) {\n if (err instanceof Error) {\n if (axios.isAxiosError(err)) {\n if ((err.response?.status || 0) > 400) {\n logger.warn(`We got a \\`${err.response?.status}\\` status code from endpoint: \\`${endpoint}\\`. \n\n Headers response: ${JSON.stringify(err.response?.headers)}\n\n Response body from the server: ${JSON.stringify(err.response?.data)}`);\n }\n }\n }\n throw err;\n }\n}\n\nexport const getJSONApiCall = async <T>(\n endpoint: string,\n config: GetConfig,\n privateLogging?: boolean\n): Promise<T> => {\n const fullResponse = await getJSONApiCallWithFullResponse(\n endpoint,\n config,\n privateLogging\n );\n return fullResponse.data;\n}\n\nexport const getDownloadFileApiCall = async <T>(\n endpoint: string,\n config: GetConfig,\n output: string,\n privateLogging?: boolean\n): Promise<{ outputDir: string }> => {\n\n const instance = getAxiosInstance(config.retryCount);\n\n const writer = fs.createWriteStream(output)\n\n const paramsSerializer = (params: any) => {\n return qs.stringify(params, { arrayFormat: 'repeat' })\n }\n\n logger.info(`🤖 GET ${endpoint}`, { private: privateLogging })\n\n return instance({\n method: \"GET\",\n url: endpoint,\n responseType: 'stream',\n params: config.qs,\n ...(config.headers ? { headers: config.headers } : {}),\n paramsSerializer: { serialize: (params) => qs.stringify(params, { arrayFormat: 'repeat' }) }\n }).then(response => {\n return new Promise<{ outputDir: string }>((resolve, reject) => {\n response.data.pipe(writer);\n let error: any = null;\n writer.on('error', err => {\n error = err;\n writer.close();\n reject(err);\n });\n writer.on('close', () => {\n if (!error) {\n resolve({ outputDir: output });\n }\n //no need to call the reject here, as it will have been called in the\n //'error' stream;\n });\n });\n });\n}\n\nexport interface PostConfig {\n qs?: { [key: string]: any },\n headers?: AxiosRequestHeaders,\n retryCount?: number\n}\n\nexport const postJSONApiCall = async <T>(\n endpoint: string,\n config: PostConfig,\n payload: any\n): Promise<T> => {\n\n const instance = getAxiosInstance(config.retryCount);\n try {\n const requestConfig: AxiosRequestConfig = { params: config.qs };\n if (config.headers) {\n requestConfig.headers = config.headers;\n }\n const response = await instance.post(\n endpoint,\n payload,\n requestConfig\n );\n return response.data;\n } catch (err: any) {\n if (err?.response?.status >= 400) {\n throw new Error(`We got a \\`${err.response.status}\\` status code from endpoint: \\`${endpoint}\\`. \n \n Response body from the server: ${JSON.stringify(err.response.data)}`);\n }\n throw err;\n }\n}\n\nexport const postFormDataApiCall = async <T>(endpoint: string, config: PostConfig, payload: any): Promise<T> => {\n\n const instance = getAxiosInstance(config.retryCount);\n\n try {\n const response = await instance({\n method: 'post',\n url: endpoint,\n headers: {\n ...(payload as any).getHeaders()\n },\n data: payload\n });\n return response.data;\n } catch (err: any) {\n if (err.response.status > 400) {\n throw new Error(`We got a \\`${err.response.status}\\` status code from endpoint: \\`${endpoint}\\`. \n \n Response body from the server: ${JSON.stringify(err.response.data)}`);\n }\n throw err;\n }\n}\n\nexport const postUrlEncodedApiCall = async (endpoint: string, config: PostConfig, payload: any) => {\n\n const instance = getAxiosInstance(config.retryCount);\n\n try {\n\n const params = new URLSearchParams(payload as any);\n\n const response = await instance.post(\n endpoint,\n params.toString(),\n {\n ...(config.headers ? { headers: config.headers } : {})\n });\n return response.data;\n } catch (err: any) {\n if (err.response.status > 400) {\n throw new Error(`We got a \\`${err.response.status}\\` status code from endpoint: \\`${endpoint}\\`. \n \n Response body from the server: ${JSON.stringify(err.response.data)}`);\n }\n throw err;\n }\n}","const metricStore: {\n [streamId: string]: {\n [metricName: string]: CounterMetric\n }\n} = {};\n\nexport const ALL_STREAM_ID_KEYWORD = \"all\";\nexport const ROWS_SYNCED_METRIC_NAME = \"rows_synced_count\";\nexport const API_CALLS_METRIC_NAME = \"api_calls_count\";\nexport const EXECUTION_TIME_METRIC_NAME = \"execution_time_ms\";\n\n// We're using functions here so that the call is done lazily\n// when the stream is initialized and the proper isSilent + streamId is configured\n// otherwise we have the default streamId value here\nexport interface MetricConfiguration {\n isEnabled: () => boolean;\n getStreamIds?: () => string[];\n}\n\nexport const getCounterMetrics = (\n name: string,\n streamIds: string[]\n): CounterMetric[] => {\n return streamIds.map(streamId => {\n return getCounterMetric(name, streamId)\n })\n}\n\nexport const getCounterMetric = (\n name: string,\n streamId: string = ALL_STREAM_ID_KEYWORD\n): CounterMetric => {\n if (!metricStore[streamId]) {\n metricStore[streamId] = {};\n }\n const streamMetricStore = metricStore[streamId];\n\n if (!streamMetricStore[name]) {\n streamMetricStore[name] = new CounterMetric(name, streamId);\n }\n return streamMetricStore[name];\n}\n\nexport const getAllMetrics = (): CounterMetric[] => {\n return Object.keys(metricStore)\n .flatMap(streamId => {\n const streamMetricStore = metricStore[streamId];\n if (!streamMetricStore) {\n return [] as CounterMetric[];\n }\n return Object.keys(streamMetricStore)\n .map(metricName => streamMetricStore[metricName])\n .filter((m): m is CounterMetric => m !== undefined)\n })\n}\n\nexport class CounterMetric {\n private value: number = 0;\n name: string;\n streamId: string;\n\n constructor(\n name: string,\n streamId: string\n ) {\n this.name = name;\n this.streamId = streamId;\n }\n\n increment(inc: number = 1): void {\n this.value = this.value + inc;\n }\n\n getStreamId(): string {\n return this.streamId\n }\n\n getName(): string {\n return this.name\n }\n\n getValue(): number {\n return this.value\n }\n}","import { logger } from \"./logger\";\n\nconst formatMemoryUsage = (data: number) => `${Math.round(data / 1024 / 1024 * 100) / 100} MB`;\n\nexport const printMemoryFootprint = (prefix: string) => {\n const memoryData = process.memoryUsage();\n\n const memoryUsage = {\n rss: `${formatMemoryUsage(memoryData.rss)} -> Resident Set Size - total memory allocated for the process execution`,\n heapTotal: `${formatMemoryUsage(memoryData.heapTotal)} -> total size of the allocated heap`,\n heapUsed: `${formatMemoryUsage(memoryData.heapUsed)} -> actual memory used during the execution`,\n external: `${formatMemoryUsage(memoryData.external)} -> V8 external memory`,\n };\n\n logger.info(`${prefix}: %j`, memoryUsage);\n}","import { logger } from \"./logger\";\n\nexport async function gracefulExit(exitCode: number) {\n // Wait for winston to have logged all messages\n // Required as we are using HTTP transport\n const loggerFinish = new Promise<void>((resolve, reject) => {\n logger.closeWinston(resolve)\n })\n await loggerFinish;\n process.exit(exitCode);\n}","import { gracefulExit } from \"./exit\";\nimport { logger } from \"./logger\";\nimport { ErrorType } from \"../models/error\";\n\nexport const haltAndCatchFire = async (\n errorType: ErrorType,\n errorText: string,\n errorDebugText: string\n): Promise<void> => {\n\n logger.error(\n `💥 Got a fatal error that will reported to the end user. Process will stop.\n errorType=%s\n errorText=%s\n errorDebugText=%s\n `,\n errorType,\n errorText,\n errorDebugText\n )\n // we return sucess but we let the sucess job pass the error params\n await gracefulExit(0);\n}","export enum ReplicationMethod {\n INCREMENTAL = \"INCREMENTAL\",\n FULL_TABLE = \"FULL_TABLE\",\n APPEND = \"APPEND\"\n}","import { StreamId } from \"./metadata\";\nimport { ReplicationMethod } from \"./replication\";\nimport { PropertiesMetadata } from \"./schema\";\n\nexport type MessageType = \"RECORD\" | \"STATE\" | \"SCHEMA\" | \"ACTIVATE_VERSION\" | \"REPLICATION_METHOD\";\n\nexport interface Message {\n type: MessageType;\n toString(): string;\n}\n\nexport class RecordMessage implements Message {\n\n type: MessageType = \"RECORD\"\n stream: StreamId;\n record: any;\n\n constructor(record: any, stream: StreamId) {\n this.record = record;\n this.stream = stream;\n }\n\n toString() {\n const result = {\n type: \"RECORD\",\n record: this.record,\n stream: this.stream\n }\n return JSON.stringify(result);\n }\n}\n\nexport class StateMessage implements Message {\n\n type: MessageType = \"STATE\"\n value: any\n\n constructor(value: any) {\n this.value = value\n }\n\n toString() {\n const result = {\n type: \"STATE\",\n value: this.value\n }\n return JSON.stringify(result);\n }\n}\n\nexport class ReplicationMethodMessage implements Message {\n\n type: MessageType = \"REPLICATION_METHOD\";\n stream: string;\n replication: ReplicationMethod;\n\n constructor(stream: string, version: ReplicationMethod) {\n this.stream = stream;\n this.replication = version;\n }\n\n toString() {\n const result = {\n type: \"REPLICATION_METHOD\",\n replication: this.replication,\n stream: this.stream\n }\n return JSON.stringify(result);\n }\n}\n\nexport class SchemaMessage implements Message {\n\n type: MessageType = \"SCHEMA\";\n stream: StreamId;\n schema: any;\n keyProperties: string[];\n bookmarkProperties: string[] | undefined;\n displayLabel: string | undefined;\n description: string | undefined;\n propertiesMetadata: PropertiesMetadata | undefined\n\n constructor(opts: {\n stream: StreamId,\n schema: any,\n keyProperties: string[],\n bookmarkProperties?: string[],\n displayLabel?: string,\n description?: string,\n propertiesMetadata?: PropertiesMetadata | undefined\n }) {\n const {\n stream,\n schema,\n keyProperties,\n bookmarkProperties,\n displayLabel,\n description,\n propertiesMetadata\n } = opts;\n\n this.stream = stream;\n this.schema = schema;\n this.keyProperties = keyProperties;\n this.bookmarkProperties = bookmarkProperties;\n this.displayLabel = displayLabel;\n this.description = description;\n this.propertiesMetadata = propertiesMetadata;\n }\n\n toString() {\n const result: any = {\n type: \"SCHEMA\",\n stream: this.stream,\n schema: this.schema,\n key_properties: this.keyProperties,\n label: this.displayLabel,\n description: this.description,\n }\n\n if (this.bookmarkProperties) {\n result[\"bookmark_properties\"] = this.bookmarkProperties\n }\n\n return JSON.stringify(result);\n }\n}","import { StreamId } from \"./metadata\";\nimport { StateMessage } from \"./messages\";\nimport dayjs, { Dayjs } from \"dayjs\";\nimport { ITarget } from \"./target/target\";\nimport { defaultDateTimeFormat } from \"../constants/date\";\nimport { format } from \"util\";\n\nexport interface InputTapState {\n bookmarks?: {\n [streamId: string]: StreamState\n }\n}\n\nexport interface TapState {\n bookmarks: {\n [streamId: string]: StreamState\n }\n}\n\nexport interface Bookmark {\n replicationKey?: string;\n replicationKeyValue?: string; // Contains ISO 8601 string\n}\n\nexport interface StreamState extends Bookmark {\n progressMarkers?: ProgressMarkers\n replicationKeySignpost?: string\n}\n\nexport interface ProgressMarkers extends Bookmark {\n Note?: string;\n}\n\n// To deprecate\nexport interface State {\n bookmarks: Bookmarks;\n}\n\n// To deprecate\nexport interface Bookmarks {\n [streamId: string]: any;\n}\n\nconst PROGRESS_MARKERS = \"progressMarkers\"\nconst PROGRESS_MARKER_NOTE = \"Note\"\nconst SIGNPOST_MARKER = \"replicationKeySignpost\"\n\nexport const incrementStreamState = (\n state: StreamState,\n replicationKey: string,\n latestRecord: any,\n isSorted: boolean\n): StreamState => {\n\n let newRkValue = latestRecord[replicationKey] as string;\n if (!newRkValue) {\n throw new Error(format(`No value for replicationKey: ${replicationKey} in record with keys: %j`, Object.keys(latestRecord)))\n }\n let newRkValueMoment = dayjs(newRkValue);\n\n let prevRkValue: string | undefined;\n let prevRkValueMoment: Dayjs | undefined;\n\n if (isSorted) {\n prevRkValue = state[\"replicationKeyValue\"];\n prevRkValueMoment = dayjs(prevRkValue);\n if (prevRkValue && prevRkValueMoment.isAfter(newRkValueMoment)) {\n throw new Error(\n `Unsorted data detected in stream. Latest value '${newRkValue}' is\n smaller than previous max '${prevRkValue}'.`\n )\n }\n }\n\n // For unsorted streams, we have to make sure that the \"new\" replication key is newer or equal than the previous one\n if (!isSorted) {\n\n // Progress markers are living only during the current sync\n // They are erased at the end of the sync and the stored value is used to write the new state\n if (!state[PROGRESS_MARKERS]) {\n const marker: ProgressMarkers = {};\n marker[PROGRESS_MARKER_NOTE] = \"Progress is not resumable if interrupted.\"\n state[PROGRESS_MARKERS] = marker;\n }\n prevRkValue = (state[PROGRESS_MARKERS] as any)[\"replicationKeyValue\"];\n\n // In case we don't have any previous value in the PROGRESS_MARKERS, \n // which happens for the first record of the current sync, we take the last state value\n prevRkValueMoment = dayjs(prevRkValue || state[\"replicationKeyValue\"]);\n\n // If we just got an \"old\" record, we keep the previous state as the max ts\n if (prevRkValue && prevRkValueMoment.isAfter(newRkValueMoment)) {\n newRkValueMoment = prevRkValueMoment;\n newRkValue = prevRkValue;\n }\n }\n\n // Signpost is the moment we start the current sync,\n // we make sure that our replication value can't be greater than the signpost\n const signpostMarker = state[SIGNPOST_MARKER];\n const replicationKeySignpostMoment = dayjs(signpostMarker);\n\n if (replicationKeySignpostMoment && replicationKeySignpostMoment.isBefore(newRkValueMoment)) {\n // Overflowed max bookmark threshold, reset to the max for this key:\n newRkValueMoment = replicationKeySignpostMoment\n newRkValue = replicationKeySignpostMoment.format(defaultDateTimeFormat);\n }\n\n if (isSorted === false) {\n (state[PROGRESS_MARKERS] as ProgressMarkers)['replicationKey'] = replicationKey;\n (state[PROGRESS_MARKERS] as ProgressMarkers)['replicationKeyValue'] = dayjs(newRkValueMoment).format(defaultDateTimeFormat);\n } else {\n state['replicationKey'] = replicationKey;\n state['replicationKeyValue'] = dayjs(newRkValueMoment).format(defaultDateTimeFormat);\n }\n\n return state;\n}\n\n/**\n * Promote or wipe progress markers once sync is complete.\"\"\"\n\n * @param state \n * @returns \n */\nexport const finalizeStateProgressMarkers = (state: StreamState): StreamState => {\n\n const signpostValue = state[SIGNPOST_MARKER];\n const progressMarkers = state[PROGRESS_MARKERS];\n if (progressMarkers && progressMarkers[\"replicationKey\"] && progressMarkers[\"replicationKeyValue\"]) {\n // Replication keys valid (only) after sync is complete\n state[\"replicationKey\"] = progressMarkers[\"replicationKey\"]\n let newRkValue = progressMarkers[\"replicationKeyValue\"]\n\n // Reset to signpost if needed\n if (signpostValue && _greaterThan(newRkValue, signpostValue)) {\n newRkValue = signpostValue\n }\n\n const previousReplicationValue = state[\"replicationKeyValue\"];\n if (!previousReplicationValue || (previousReplicationValue && _greaterThan(newRkValue, previousReplicationValue))) {\n state[\"replicationKeyValue\"] = newRkValue\n }\n }\n // Wipe any markers that have not been promoted\n delete state[PROGRESS_MARKERS];\n\n return state;\n}\n\nexport const _greaterThan = (aValue: string, bValue: string): boolean => {\n return dayjs(aValue).isAfter(dayjs(bValue));\n}\n\nexport const extractStateForStream = (state: InputTapState, streamId: StreamId) => {\n if (!state.bookmarks) {\n state.bookmarks = {}\n }\n if (!state.bookmarks[streamId]) {\n state.bookmarks[streamId] = {}\n }\n return state.bookmarks[streamId];\n}\n\nexport class StateService {\n\n private static instance: StateService;\n\n bookmarks: Bookmarks;\n\n constructor() {\n this.bookmarks = {}\n }\n\n static getInstance(): StateService {\n if (!this.instance) {\n this.instance = new this();\n }\n\n return this.instance;\n }\n\n setBookmark(streamId: StreamId, streamState: StreamState) {\n this.bookmarks[streamId] = streamState;\n }\n\n setBookmarkSignpost(streamId: StreamId, signpostValue: string) {\n if (!this.bookmarks[streamId]) {\n this.bookmarks[streamId] = {}\n }\n this.bookmarks[streamId][SIGNPOST_MARKER] = signpostValue;\n }\n\n getBookmark(streamId: StreamId): StreamState {\n if (this.bookmarks[streamId]) {\n return this.bookmarks[streamId];\n } else {\n return {}\n }\n }\n\n clearState() {\n this.bookmarks = {};\n }\n\n get(): State {\n const state: State = {\n bookmarks: this.bookmarks\n }\n return state\n }\n\n async forwardStateToTarget(target: ITarget) {\n const state: State = {\n bookmarks: this.bookmarks\n }\n\n const message = new StateMessage(state);\n await target.state(message);\n }\n}","export const defaultDateTimeFormat = \"YYYY-MM-DDTHH:mm:ss.SSSSSSZ\"","import { HTTPHeaders, URLParams } from \"../http\";\n\n/**\n * C: The type of the tap config\n */\nexport class Authenticator<C> {\n\n getAuthHeaders(config: C): Promise<HTTPHeaders> {\n return Promise.resolve({})\n }\n\n getAuthQS(config: C): Promise<URLParams> {\n return Promise.resolve({})\n }\n\n}","import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from \"axios\";\nimport { Authenticator } from \"./authenticator\";\nimport { HTTPHeaders, HTTPMethod, URLParams } from \"../http\";\nimport * as qs from 'qs';\nimport { logger } from \"../../service/logger\";\nimport { Stream } from \"./stream\";\nimport { InputTapState } from \"../state\";\nimport { ITarget } from \"../target/target\";\nimport { getAxiosInstance } from \"../../service/network\";\nimport { DEFAULT_MAX_CONCURRENT_STREAMS } from \"./tap\";\nimport { API_CALLS_METRIC_NAME, CounterMetric, getCounterMetrics, MetricConfiguration } from \"../../service/metric\";\nimport { getTruncatedParamsForLog } from \"../../helpers/qs-logger\";\nimport cloneDeep from \"lodash/cloneDeep.js\";\nimport isEqual from \"lodash/isEqual.js\";\n\n/**\n * R: Type of the API result\n * NPT: Type of the \"nextPageToken\"\n */\nexport abstract class RESTStream<R, O, NPT, C, P = undefined>\n extends Stream<O, C, P> {\n\n axiosInstance: AxiosInstance | undefined;\n\n constructor(\n config: C,\n state: InputTapState,\n target: ITarget,\n childConcurrency: number = DEFAULT_MAX_CONCURRENT_STREAMS\n ) {\n super(config, state, target, childConcurrency);\n this.apiCallsMetricsConf = {\n isEnabled: () => !this.isSilent,\n getStreamIds: () => [this.streamId]\n }\n }\n\n // Internal\n // Those functions shouldn't be overriden (or it means that we fuck'ed up the SDK during the design phase)\n\n /**\n * Prepare an Axios request object.\n * Pagination information can be parsed from `nextPageToken` if `nextPageToken` is not undefined.\n * @param nextPageToken \n * @returns \n */\n _prepareRequest = async (nextPageToken: NPT | undefined, parent?: P)\n : Promise<AxiosRequestConfig> => {\n\n const method = this.httpMethod;\n const url = this.getNextUrl(nextPageToken, parent);\n if (!url) {\n throw new Error(`StreamId: ${this.streamId} - URL is undefined. Did your properly define the URL for this stream?`)\n }\n\n const authenticator = this.authenticator\n\n // If getNextUrl returns a URL that already contains query string parameters,\n // extract them and merge into params. We remove the query part from the URL\n // to avoid duplication with axios params handling.\n let finalUrl = url;\n let urlQueryParams: Record<string, any> = {};\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex !== -1) {\n finalUrl = url.substring(0, queryIndex);\n const rawQueryString = url.substring(queryIndex + 1);\n urlQueryParams = qs.parse(rawQueryString) as Record<string, any>;\n }\n\n const params = {\n ...this.getNextUrlParams(nextPageToken, parent),\n // Query params embedded in URL should override computed pagination params\n // but should not override auth params which are appended last\n ...urlQueryParams,\n ...(await authenticator?.getAuthQS(this.config))\n }\n\n const requestBody = this.getRequestBodyForNextCall(nextPageToken, parent)\n let headers = this.getCustomHTTPHeaders(parent);\n if (!headers) {\n headers = {};\n }\n\n if (authenticator) {\n const authHeaders = await authenticator.getAuthHeaders(this.config)\n headers = {\n ...headers,\n ...authHeaders\n }\n }\n\n const paramsSerializer = (params: any) => {\n return qs.stringify(params, { arrayFormat: 'repeat' })\n }\n\n const request: AxiosRequestConfig = {\n url: finalUrl,\n method,\n data: requestBody,\n params,\n paramsSerializer,\n headers\n }\n return request\n }\n\n async _requestWithRetry(request: AxiosRequestConfig, privateLogging?: boolean): Promise<R | \"STOP_SYNC\"> {\n try {\n logger.debug(`🤖 ${request.method} ${request.url} with params: %j | body: %j`,\n request.params,\n request.data,\n { private: privateLogging });\n logger.info(`🤖 ${request.method} ${request.url} qs: %j`,\n getTruncatedParamsForLog(request.params),\n { private: privateLogging });\n const axiosInstance = this.axiosInstance;\n if (!axiosInstance) {\n throw new Error(`Axios Instance is not initialized!`)\n }\n const response = await axiosInstance.request<R>(request);\n return response.data;\n } catch (err) {\n if (axios.isAxiosError(err)) {\n logger.error(`🤖 Error on ${request.method} ${request.url} with params %j | body: %j | headers: %j - getting error %s - response body: %j`,\n request.params,\n request.data,\n request.headers,\n err.message,\n err.response?.data\n )\n const recoveredValue = await this.httpErrorHandler(request.url, err);\n if (recoveredValue === undefined) {\n return \"STOP_SYNC\"\n } else {\n return recoveredValue;\n }\n } else {\n throw err;\n }\n }\n }\n\n async *_requestRecords(parent?: P): AsyncIterable<O> {\n let nextPageToken: NPT | undefined = undefined;\n let finished = false;\n\n let apiCallsMetrics: CounterMetric[] = [];\n if (this.apiCallsMetricsConf.isEnabled() === true) {\n apiCallsMetrics = getCounterMetrics(\n API_CALLS_METRIC_NAME,\n this.apiCallsMetricsConf.getStreamIds\n ? this.apiCallsMetricsConf.getStreamIds()\n : []\n )\n }\n\n // We reset the axios instance here to use the value of `httpRetryCount` after the initialization of custom values defined in the Streams impl.\n // Doing it in the constructor is givingf us access only to the default value of `httpRetryCount`\n this.axiosInstance = getAxiosInstance(this.httpRetryCount);\n\n while (!finished) {\n const preparedRequest = await this._prepareRequest(nextPageToken, parent);\n const resp = await this._requestWithRetry(preparedRequest);\n\n apiCallsMetrics.forEach(metric => {\n metric.increment();\n })\n\n // We stop the sync for this stream\n if (resp === \"STOP_SYNC\") {\n return;\n }\n const rows = this.parseResponse(resp, parent, nextPageToken);\n for await (const row of rows) {\n yield row\n }\n\n const previousToken = cloneDeep(nextPageToken);\n nextPageToken = this.getNextPageToken(resp, previousToken);\n\n if (nextPageToken && isEqual(nextPageToken, previousToken)) {\n throw new Error(\n `${this.streamId} - Loop detected in pagination. \"\n Pagination token: \\`${JSON.stringify(nextPageToken)}\\` is identical to prior token \\`${JSON.stringify(previousToken)}\\`.`\n )\n }\n // Cycle until getNextPageToken() no longer returns a value\n finished = !nextPageToken\n }\n }\n\n async *_getRecords(parent?: P): AsyncIterable<O> {\n for await (const row of this._requestRecords(parent)) {\n yield row\n }\n }\n\n // Overridable\n // Even if the default impl. of some function can be used as-is, those functions\n // are meant to be overriden when necessary to match the API needs.\n httpMethod: HTTPMethod = \"GET\";\n baseUrl: string = \"\";\n path: string = \"\";\n httpRetryCount = 24;\n authenticator?: Authenticator<C>;\n\n apiCallsMetricsConf: MetricConfiguration\n\n // When undefined is returned, we should stop the sync without any error\n async httpErrorHandler(url: string | undefined, err: AxiosError): Promise<R | undefined> {\n if ((err.response?.status || 0) > 400) {\n throw new Error(`We got a \\`${err.response?.status}\\` status code from endpoint: \\`${url}\\`. \n\n Response body from the server: ${JSON.stringify(err.response?.data)}`);\n }\n throw err;\n }\n\n /** \n * Return a dictionary of values to be used in URL parameterization.\n * If paging is supported, developers may override with specific paging logic.\n * \n * By default, no params are passed.\n */\n getNextUrlParams(nextPageToken: NPT | undefined, parent?: P): URLParams {\n return {}\n }\n\n /** \n * Prepare the data payload for the REST API request.\n * Useful when working with POST APIs.\n * \n * By default, no payload will be sent (return undefined).\n */\n getRequestBodyForNextCall(nextPageToken: NPT | undefined, parent?: P): any {\n return undefined\n }\n\n /**\n * Return token identifying next page or undefined if all records have been read.\n * \n * By default, no token will be returned and a single API call will be made.\n * \n * @param response \n * @param previousToken \n * @returns \n */\n getNextPageToken(response: R, previousToken?: NPT): NPT | undefined {\n return undefined;\n }\n\n /**\n * Return custom headers to be used for HTTP requests.\n * \n * By default, no additional header will be added\n */\n getCustomHTTPHeaders(parent?: P): HTTPHeaders | undefined {\n return undefined;\n }\n\n /**\n * Return a URL, optionally targeted to a specific partition.\n * This can be overriden to perform dynamic URL generation.\n * \n * TODO: Make URL + Path templatisable and replace those with Extractor (or Tap) config\n * @returns \n */\n getNextUrl(previousToken?: NPT,parent?: P): string {\n const urlPattern = [this.baseUrl, this.path].join(\"\")\n return urlPattern;\n }\n\n /**\n * Parse the response and return an iterator of result rows.\n * \n * Default impl assume that R = O or R = O[]\n * @param response\n */\n async *parseResponse(\n response: R,\n parent?: P,\n nextPageToken?: NPT\n ): AsyncIterable<O> {\n if (Array.isArray(response)) {\n for (const row of response) {\n yield row as any as O\n }\n } else {\n yield response as any as O\n }\n }\n\n}","import dayjs, { Dayjs } from \"dayjs\";\nimport { defaultDateTimeFormat } from \"../../constants/date\";\nimport { isDatetimeType } from \"../../helpers/typing\";\nimport { logger } from \"../../service/logger\";\nimport { loadJson } from \"../../utils\";\nimport { StreamId } from \"../metadata\";\nimport { RecordMessage, ReplicationMethodMessage, SchemaMessage, StateMessage } from \"../messages\";\nimport { ReplicationMethod } from \"../replication\";\nimport { extractStateForStream, finalizeStateProgressMarkers, incrementStreamState, InputTapState, StateService } from \"../state\";\nimport { ITarget } from \"../target/target\";\nimport cloneDeep from \"lodash/cloneDeep.js\";\nimport { Schema } from \"../schema\";\nimport Bluebird from \"bluebird\";\nimport { DEFAULT_MAX_CONCURRENT_STREAMS } from \"./tap\";\nimport { CounterMetric, EXECUTION_TIME_METRIC_NAME, getCounterMetrics, MetricConfiguration, ROWS_SYNCED_METRIC_NAME } from \"../../service/metric\";\nimport { format } from \"util\";\n\n/**\n * TODO: Handle non timestamp based replication key\n *\n * O: Type of a resulted row after post processing\n * C: Type of the tap configuration\n * P: For children Streams, this is the type of the parent\n */\nexport abstract class Stream<O = any, C = any, P = undefined> {\n\n // Runtime values, can't be overriden\n config: C;\n tapState: InputTapState;\n target: ITarget;\n\n replicationMethod: ReplicationMethod | undefined = undefined;\n selectedByDefault: boolean = true;\n STATE_MSG_FREQUENCY: number = 10;\n streamId: StreamId = \"default\";\n schemaPath: string | undefined = undefined;\n displayLabel: string | undefined = undefined;\n description: string | undefined = undefined;\n primaryKey: string[] = [];\n replicationKey: string | undefined = undefined;\n // When set, use the state from another stream for this stream\n useStateFromStreamId: string | undefined = undefined;\n\n children: Stream<any, any, O | O[]>[] = [];\n // If true, it means that the records in this stream are sorted by replicationKey.\n // If false, then the records are coming in an unsorted manner.\n isSorted: boolean = false;\n // If true, then no SCHEMA / RECORD messages will be sent for this Stream.\n // However, a STATE will still be emitted if the Stream is using an incremental sync type.\n isSilent: boolean = false;\n\n childConcurrency: number;\n\n // Optional total row count for percentage progress logging\n totalRows?: number;\n\n // Metrics configuration\n rowsSyncedMetricsConf: MetricConfiguration\n executionTimeMetricsConf: MetricConfiguration\n\n constructor(\n config: C,\n tapState: InputTapState,\n target: ITarget,\n childConcurrency: number = DEFAULT_MAX_CONCURRENT_STREAMS\n ) {\n this.config = config;\n this.tapState = cloneDeep(tapState);\n this.target = target;\n this.childConcurrency = childConcurrency;\n\n // Default metric configuration\n this.rowsSyncedMetricsConf = {\n isEnabled: () => !this.isSilent,\n getStreamIds: () => [this.streamId]\n }\n this.executionTimeMetricsConf = {\n isEnabled: () => !this.isSilent,\n getStreamIds: () => [this.streamId]\n }\n }\n\n // No root metadata: replication config is derived from stream defaults only\n\n /**\n * Sync this stream\n * Called only for streams with no parents, aka. \"root tap streams\"\n * @returns \n */\n sync = async (): Promise<void> => {\n try {\n const replicationMethod = this.configuredReplicationConfig().replicationMethod;\n logger.info(\n `🎬 Beginning ${replicationMethod} sync of stream '${this.streamId}'...`\n )\n\n await this.asyncInit();\n\n // Send a SCHEMA message to the downstream target\n await this._writeSchemaMessage();\n\n await this._writeReplicationMethodMessage();\n\n // Write the signpost\n await this._writeSignpostInState();\n\n // Sync the records themselves\n await this._syncRecords();\n\n // Flush the stream\n return this.flush();\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(`got an error while syncing streamId=%s, err: %s`, this.streamId, err.message))\n }\n throw err;\n }\n }\n\n flush = async (): Promise<void> => {\n const replicationMethod = this.configuredReplicationConfig().replicationMethod;\n logger.info(\n `🚽 Flushing ${replicationMethod} sync of stream '${this.streamId}' + all of its children...`\n )\n\n await this._flush();\n\n await Bluebird.map(this.children, child => {\n return child.flush();\n }, { concurrency: 3 });\n }\n\n // Private message authoring methods:\n\n /**\n * Write out a STATE message with the latest state.\n */\n _writeStateMessage = (): Promise<void> => {\n const message = new StateMessage(StateService.getInstance().get());\n return this.target.state(message);\n }\n\n /**\n * Write out a ACTIVATE_VERSION message.\n */\n _writeReplicationMethodMessage = async (): Promise<void> => {\n const method = this.configuredReplicationConfig().replicationMethod;\n const message = new ReplicationMethodMessage(this.streamId, method);\n\n await Bluebird.map(this.children, async c => {\n return c._writeReplicationMethodMessage()\n }, { concurrency: 3 })\n await this.target.replicationMethod(message);\n }\n\n /**\n * Write out a SCHEMA message with the stream schema.\n */\n _writeSchemaMessage = async (skipChildrenSchema?: boolean): Promise<void> => {\n\n if (!this.isSilent) {\n const schema = await this.getSchema();\n if (schema !== undefined) {\n const replicationConfig = this.configuredReplicationConfig();\n\n const message = new SchemaMessage({\n keyProperties: this.primaryKey,\n stream: this.streamId,\n schema: schema.jsonSchema,\n ...(replicationConfig.replicationKey ? { bookmarkProperties: [replicationConfig.replicationKey] } : {}),\n ...(this.displayLabel ? { displayLabel: this.displayLabel } : {}),\n ...(this.description ? { description: this.description } : {}),\n ...(schema.propertiesMetadata ? { propertiesMetadata: schema.propertiesMetadata } : {})\n })\n await this.target.schema(message);\n }\n }\n\n if (skipChildrenSchema !== true) {\n await Bluebird.map(this.children, async (child) => {\n await child._writeSchemaMessage();\n }, { concurrency: 3 });\n }\n }\n\n // Private bookmarking methods\n\n _writeSignpostInState = async () => {\n const signpostMoment = await this.getReplicationKeySignpost();\n const signpostValue = signpostMoment?.format(defaultDateTimeFormat);\n\n if (signpostValue) {\n StateService.getInstance().setBookmarkSignpost(this.streamId, signpostValue);\n }\n }\n\n /**\n * Update state of stream with data from the provided record. \n */\n _incrementStreamState = (latestRecord: O): void => {\n\n if (latestRecord) {\n const replicationConfig = this.configuredReplicationConfig()\n if ([\n \"INCREMENTAL\",\n \"LOG_BASED\",\n ].includes(replicationConfig.replicationMethod)) {\n // If the stream is using another stream state, it doesn't own the state and can't increment it\n if (this.useStateFromStreamId) {\n return;\n }\n // If the replication method was forced, it can be that the stream is the child of anohter stream that is managing the state (ex. a paginated stream). \n // The state is not owned by the current stream then.\n if (this.replicationMethod && !this.replicationKey) {\n return;\n }\n\n // If the stream has been detected as being incremental and has no excuses for not owning its state, it should have the replicationKey\n if (!replicationConfig.replicationKey) {\n throw new Error(`Could not detect replication key for '${this.streamId}' stream\"\n replication method=${replicationConfig.replicationMethod})`\n )\n }\n\n const stateServiceInst = StateService.getInstance();\n const state = stateServiceInst.getBookmark(this.streamId);\n\n const newState = incrementStreamState(\n state,\n replicationConfig.replicationKey,\n latestRecord,\n this.isSorted\n )\n\n StateService.getInstance().setBookmark(this.streamId, newState)\n }\n }\n }\n\n /**\n * Return True if the stream uses a timestamp-based replication key.\n * \n * Developers can override with `is_timestamp_replication_key = True` in\n order to force this value.\n */\n isTimestampReplicationKey = async (): Promise<boolean> => {\n\n const replicationConfig = this.configuredReplicationConfig()\n\n if (!replicationConfig.replicationKey) {\n return false;\n }\n\n const schema = await this.getSchema();\n if (!schema || !schema.jsonSchema || !schema.jsonSchema.properties) {\n return false;\n }\n\n const typeFromSchema = schema.jsonSchema[\"properties\"][replicationConfig.replicationKey]\n if (!typeFromSchema) {\n return false;\n }\n\n return isDatetimeType(typeFromSchema);\n }\n\n /**\n * Return state timestamp if set for the stream, \n * or `start_date` config if set, \n * or the UNIX Epoch\n **/\n getStartingTimestamp(): Dayjs {\n const streamIdToReadFrom = this.useStateFromStreamId\n ? this.useStateFromStreamId\n : this.streamId;\n const state = extractStateForStream(this.tapState, streamIdToReadFrom);\n\n const startDate = (this.config as any).start_date as string | undefined;\n const replicationConfig = this.configuredReplicationConfig();\n\n logger.debug(`${this.streamId}: state.replicationKeyValue: ${state.replicationKeyValue}, \n state.replicationKey: ${state.replicationKey},\n this.replicationKey: ${replicationConfig.replicationKey}`)\n\n if (state.replicationKeyValue) {\n logger.debug(`${this.streamId} - getStartingTimestamp -> Returning replication key value: ${state.replicationKeyValue}`)\n return dayjs(state.replicationKeyValue);\n } else if (startDate) {\n logger.debug(`${this.streamId} - getStartingTimestamp -> Returning config start date: ${startDate}`)\n return dayjs(startDate)\n } else {\n logger.debug(`${this.streamId} - getStartingTimestamp -> Returning EPOCH (1970)`)\n return dayjs(0);\n }\n }\n\n /**\n * Return the max allowable bookmark value for this stream's replication key.\n * \n * For timestamp-based replication keys, this defaults to `dayjs()`. For\n * non-timestamp replication keys, default to `undefined`.\n * \n * Override this value to prevent bookmarks from being advanced in cases where we\n * may only have a partial set of records.\n */\n getReplicationKeySignpost = async (): Promise<Dayjs | undefined> => {\n\n if (await this.isTimestampReplicationKey()) {\n return dayjs()\n }\n\n return undefined\n }\n\n /**\n * Return the default replication method for the stream that will be used to write the catalog.\n */\n defaultReplicationConfig = (): {\n replicationMethod: ReplicationMethod,\n replicationKey: string | undefined,\n // When replication method is forced, it means that end user can't override it.\n isForced: boolean\n } => {\n if (this.replicationMethod) {\n return {\n replicationMethod: this.replicationMethod,\n replicationKey: this.replicationKey,\n isForced: true\n }\n }\n if (this.replicationKey || this.useStateFromStreamId) {\n return {\n replicationMethod: ReplicationMethod.INCREMENTAL,\n replicationKey: this.replicationKey,\n isForced: true\n }\n }\n\n return {\n replicationMethod: ReplicationMethod.FULL_TABLE,\n replicationKey: undefined,\n isForced: false\n }\n }\n\n /**\n * Return the configured replication method that will be used for the sync.\n */\n configuredReplicationConfig = (): {\n replicationMethod: ReplicationMethod,\n replicationKey: string | undefined\n } => {\n const defaults = this.defaultReplicationConfig();\n return {\n replicationMethod: defaults.replicationMethod,\n replicationKey: defaults.replicationKey\n }\n }\n\n // Private sync methods:\n async _syncRecords(parent?: P): Promise<void> {\n let rowsSent = 0;\n\n let recordSyncedMetrics: CounterMetric[] = [];\n if (this.rowsSyncedMetricsConf.isEnabled() === true) {\n recordSyncedMetrics = getCounterMetrics(\n ROWS_SYNCED_METRIC_NAME,\n this.rowsSyncedMetricsConf.getStreamIds\n ? this.rowsSyncedMetricsConf.getStreamIds()\n : []\n )\n }\n\n let executionTimeMetrics: CounterMetric[] = [];\n if (this.executionTimeMetricsConf.isEnabled() === true) {\n executionTimeMetrics = getCounterMetrics(\n EXECUTION_TIME_METRIC_NAME,\n this.executionTimeMetricsConf.getStreamIds\n ? this.executionTimeMetricsConf.getStreamIds()\n : []\n )\n }\n\n const startTime = new Date().getTime();\n\n for await (const row of this._getRecords(parent)) {\n\n if ((rowsSent - 1) % this.STATE_MSG_FREQUENCY == 0) {\n await this._writeStateMessage()\n }\n\n const recordMessage = new RecordMessage(\n { ...row },\n this.streamId\n )\n\n if (!this.isSilent) {\n await this.target.record(recordMessage);\n }\n\n await Bluebird.map(this.children, async (child) => {\n await child.asyncInit(row);\n return child._syncRecords(row);\n },\n {\n concurrency: this.childConcurrency\n });\n this._incrementStreamState(row);\n recordSyncedMetrics.forEach((metric) => {\n metric.increment();\n })\n rowsSent += 1;\n\n if (rowsSent % 1000 === 0) {\n const percentStr = this.totalRows\n ? ` (${Math.round((rowsSent / this.totalRows) * 100)}%)`\n : \"\";\n logger.info(`⏳ Stream: ${this.streamId} - ${rowsSent} records synced so far...${percentStr}`);\n }\n }\n\n const stateServiceInst = StateService.getInstance();\n const state = stateServiceInst.getBookmark(this.streamId);\n const newState = finalizeStateProgressMarkers(state);\n stateServiceInst.setBookmark(this.streamId, newState);\n\n if (!parent) {\n logger.info(`✅ Completed sync for stream: ${this.streamId} (${rowsSent} records)`);\n } else {\n logger.debug(`✅ Completed sync for sub-stream: ${this.streamId} (${rowsSent} records)`);\n }\n\n await this._writeStateMessage();\n const endTime = new Date().getTime();\n const executionTimeMs = endTime - startTime;\n executionTimeMetrics.forEach(metric => {\n metric.increment(executionTimeMs);\n })\n\n }\n\n // Overridable Methods\n\n asyncInit(parent?: P): Promise<void> {\n return Promise.resolve()\n }\n\n /**\n * Return the stream schema.\n * \n * Can be overriden to return a dynamic schema\n */\n getSchema(): Promise<Schema | undefined> {\n logger.debug(`stream: ${this.streamId} - getSchema() is called`)\n if (this.schemaPath) {\n const schema = loadJson(`schemas/${this.schemaPath}`)\n return Promise.resolve({ jsonSchema: schema });\n } else {\n if (this.isSilent) {\n return Promise.resolve(undefined);\n }\n throw new Error(`Stream=${this.streamId} - No schema path was passed.\n Either you forgot to fill the the \\`schemaPath\\` property,\n or to override the getSchema() method.`)\n }\n }\n\n getRowCount(): Promise<number | undefined> {\n return Promise.resolve(undefined)\n }\n\n /**\n * Abstract row generator function. Must be overridden by the child class.\n */\n _getRecords(parent?: P): AsyncIterable<O> {\n throw new Error(`Stream._getRecords() - Should be implemented by child class`);\n }\n\n /**\n * Return the list of keys that can be configured in the UI by the end user as the replication key\n * @returns \n */\n getValidReplicationKeys(): Promise<string[]> {\n return Promise.resolve([]);\n }\n\n /**\n * Called at the end of the sync. Use to flush all records before closing the Stream.\n * @returns \n */\n async _flush(): Promise<void> {\n await Promise.resolve();\n }\n}","\ninterface TypeDef {\n anyOf?: TypeDef[]\n type: string | string[]\n format?: \"date-time\"\n}\n/**\n * Return True if JSON Schema type definition is a 'date-time' type.\n * \n * Also returns True if 'date-time' is nested within an 'anyOf' type Array.\n\n * @param typeDef \n * @returns \n */\nexport const isDatetimeType = (typeDef: TypeDef): boolean => {\n\n if (!typeDef) {\n throw new Error(\"Could not detect type from empty typeDef param.\")\n }\n\n if (typeDef[\"anyOf\"] !== undefined) {\n for (const subTypeDef of typeDef[\"anyOf\"]) {\n if (isDatetimeType(subTypeDef)) {\n return true\n }\n }\n return false\n }\n\n else if (typeDef[\"type\"] !== undefined) {\n return typeDef[\"format\"] === \"date-time\"\n }\n\n throw new Error(\n `Could not detect type of key using schema '${typeDef}'`\n )\n\n}","import cloneDeep from \"lodash/cloneDeep.js\";\nimport { logger } from \"../../service/logger\";\nimport { InputTapState, StateService } from \"../state\";\nimport { StateProvider } from \"../state-provider/types\";\nimport { ITarget } from \"../target/target\";\nimport { Stream } from \"./stream\";\nimport Bluebird from \"bluebird\";\n\nexport const DEFAULT_MAX_CONCURRENT_STREAMS = 5;\n\nexport type SyncOptions = { include?: string[]; exclude?: string[] };\n\nexport abstract class Tap<C> {\n target: ITarget;\n config: C;\n streams: Stream[];\n concurrency: number = DEFAULT_MAX_CONCURRENT_STREAMS;\n stateProvider: StateProvider;\n tapState: InputTapState;\n\n // To be implemented by the concrete tap implementation\n abstract init(): Promise<void>;\n\n constructor(\n target: ITarget,\n config: C,\n stateProvider: StateProvider\n ) {\n this.streams = [];\n this.target = target;\n this.config = config\n this.stateProvider = stateProvider;\n this.tapState = { bookmarks: {} };\n }\n sync = async (options?: SyncOptions): Promise<void> => {\n\n // Set the initial state from the state provider\n const initialState = await this.stateProvider.getState();\n if(initialState.state && initialState.state.bookmarks) {\n this.tapState = cloneDeep(initialState.state);\n }\n\n await this.init();\n logger.info(`🚀 Start syncing`)\n\n const state = StateService.getInstance().get();\n logger.info(`📍 Received state: %j`, state)\n\n const envInclude = process.env.TAP_STREAMS\n ? process.env.TAP_STREAMS.split(',').map(s => s.trim()).filter(s => s.length > 0)\n : undefined;\n\n const include = options?.include && options.include.length > 0\n ? options.include\n : envInclude;\n const exclude = new Set((options?.exclude || []).map(s => s.trim()))\n\n let streamsToRun = this.streams.filter(s => !s.isSilent);\n if (include && include.length > 0) {\n const includeSet = new Set(include);\n streamsToRun = streamsToRun.filter(s => includeSet.has(s.streamId));\n }\n if (exclude.size > 0) {\n streamsToRun = streamsToRun.filter(s => !exclude.has(s.streamId));\n }\n\n const selectedStreamIds = streamsToRun.map(s => s.streamId);\n logger.info(`🥳 Syncing streams: %s`, selectedStreamIds.join(\",\"))\n\n await Bluebird.map(streamsToRun, (stream) => {\n return stream.sync();\n }, { concurrency: this.concurrency });\n\n logger.debug(`[TAP] All streams have finished syncing. We send the [complete] signal to the target.`)\n await this.target.complete();\n return Promise.resolve();\n };\n\n // Used to clean up any ressource before exit\n end(): Promise<void> {\n return Promise.resolve()\n }\n}","import isPlainObject from \"lodash/isPlainObject.js\";\n\n// Truncate potentially large query params for logging efficiency\nconst MAX_QS_KEYS = 10;\nconst MAX_QS_STRING_LENGTH = 200;\nconst MAX_QS_ARRAY_ITEMS = 5;\nconst MAX_QS_DEPTH = 2;\n\nfunction truncateQueryParams(value: any, depth: number = 0): any {\n if (value == null) return value;\n if (depth >= MAX_QS_DEPTH) return \"[…]\";\n\n if (typeof value === \"string\") {\n if (value.length <= MAX_QS_STRING_LENGTH) return value;\n const truncated = value.slice(0, MAX_QS_STRING_LENGTH);\n return `${truncated}…(+${value.length - MAX_QS_STRING_LENGTH} chars)`;\n }\n\n if (Array.isArray(value)) {\n const items = value\n .slice(0, MAX_QS_ARRAY_ITEMS)\n .map((v) => truncateQueryParams(v, depth + 1));\n const omittedCount = Math.max(0, value.length - MAX_QS_ARRAY_ITEMS);\n if (omittedCount > 0) {\n items.push(`[… ${omittedCount} more items]`);\n }\n return items;\n }\n\n if (isPlainObject(value)) {\n const keys = Object.keys(value);\n const result: Record<string, any> = {};\n for (const key of keys.slice(0, MAX_QS_KEYS)) {\n result[key] = truncateQueryParams((value as any)[key], depth + 1);\n }\n const omittedCount = Math.max(0, keys.length - MAX_QS_KEYS);\n if (omittedCount > 0) {\n (result as any)[\"__omittedKeys\"] = omittedCount;\n }\n return result;\n }\n\n return value;\n}\n\nexport function getTruncatedParamsForLog(params: any): any {\n try {\n return truncateQueryParams(params);\n } catch {\n return \"[unserializable params]\";\n }\n}","import { logger } from \"../../service/logger\";\nimport { StreamId } from \"../metadata\";\nimport { ReplicationMethod } from \"../replication\";\nimport { FlattenedSchema, InternalTableField, JSONSchemaFieldDefinition, WarehouseTableField } from \"./models\";\nimport { RenameColumnStore } from \"./renameColumnStore\";\nimport retry from 'async-retry';\n\n// This class is a Stateless interface with the APIs of a Warehouse when it comes to dealing with\n// loading a stream into a table.\n\n// TODO: Move flattenedSchema + renamedColumnStore into the StreamDbState class.\nexport abstract class StreamWarehouseSyncService {\n\n streamId: StreamId;\n database: string;\n schema: string;\n table: string;\n\n flattenedSchema: FlattenedSchema;\n primaryKeys: string[];\n maxRetryCount = 5;\n\n renamedColumnStore: RenameColumnStore;\n\n constructor(\n streamId: StreamId,\n database: string,\n schema: string,\n table: string,\n renameColumnStore: RenameColumnStore\n ) {\n this.streamId = streamId;\n this.database = database;\n this.schema = schema;\n this.table = table;\n\n this.primaryKeys = [];\n this.flattenedSchema = {};\n this.renamedColumnStore = renameColumnStore;\n }\n\n /////////////////////////////////////////////////////////////////\n ///////// Functions to be implented for each Warehouse //////////\n /////////////////////////////////////////////////////////////////\n\n // Function to adapt to the Warehouse SQL dialect\n abstract safeColumnName: (unsafe: string) => string;\n abstract getWarehouseTypeFromJSONSchema: (definition: JSONSchemaFieldDefinition) => string | undefined;\n getcolumnNameWithTypeSuffix(colName: string, warehouseType: string | undefined): string {\n return `${colName}__${warehouseType}`\n }\n // In order to not overload Warehouse, we update the destination table by chunks of columns as updating all the columns at once is generating a too complex query\n abstract getMergeQueries: () => string[]\n abstract getReplaceQueries: () => string[]\n abstract getAppendQueries: () => string[]\n\n // Functions to provision the tables, columns, etc.\n abstract createDatabaseAndSchemaIfNotExists: (retryCount: number) => Promise<void>;\n abstract createTable: () => Promise<void>;\n abstract addColumns: (fields: InternalTableField[]) => Promise<void>;\n\n // Functions to deal with the staging area that will be used to load data in the Warehouse\n abstract createStagingArea: () => Promise<void>;\n abstract loadStreamInStagingArea: (localFilePath: string) => Promise<void>;\n abstract deleteStagingArea: () => Promise<void>;\n\n // Function to read from the Warehouse\n abstract getTablesInSchema: () => Promise<{ tableName: string }[]>;\n abstract getTableColumnsFromWarehouse: () => Promise<WarehouseTableField[]>;\n\n // Function to execute queries on the warehouse\n abstract runQueries: (queries: string[]) => Promise<void>;\n\n // Function to serialize the record\n abstract getSerializedRecord: (record: any) => string;\n\n // Orchestration functions\n updateSchemaInWarehouse = async (\n flattenedSchema: FlattenedSchema,\n primaryKeys: string[]\n ) => {\n await this.createDatabaseAndSchemaIfNotExists(0);\n\n this.flattenedSchema = flattenedSchema;\n\n this.renamedColumnStore.computeColumnNameForStream(\n this.streamId,\n flattenedSchema\n )\n\n this.primaryKeys = primaryKeys.map(pk => {\n return this.renamedColumnStore.getColumnTranslation(this.streamId, pk)!;\n });\n\n await this.syncTableSchemaWithWarehouse();\n }\n\n renameColumns(record: any): any {\n const renamedColsRecord: any = {}\n\n Object.keys(record).forEach(originalColName => {\n renamedColsRecord[this.renamedColumnStore.getColumnTranslation(this.streamId, originalColName)!] = record[originalColName]\n })\n return renamedColsRecord;\n }\n\n // Function to execute queries on the warehouse\n protected runQueriesWithRetry = async (queries: string[]): Promise<void> => {\n await retry(\n async () => {\n await this.runQueries(queries);\n },\n {\n retries: 5,\n }\n );\n };\n\n private syncTableSchemaWithWarehouse = async () => {\n\n const tables = await this.getTablesInSchema();\n const foundTables = tables.filter(table => this.table === table.tableName);\n\n if (foundTables.length === 0) {\n logger.info(`🐣 Database: \\`${this.database}\\`, Schema: \\`${this.schema}\\`, Table: \\`${this.table}\\` does not exist in Warehouse. Creating it...`)\n await this.createTable();\n } else if (foundTables.length === 1) {\n logger.info(`👋 Database: \\`${this.database}\\`, Schema: \\`${this.schema}\\`, Table: \\`${this.table}\\` already exists. Updating the columns if needed.`);\n await this.updateTableColumns();\n }\n }\n\n /**\n * When there is a conflict between the synced data type and the data type of an\n * already existing column in the Warehouse, this create a new column in Warehouse with the new\n * datatype as suffix.\n * \n * This refer the fact that data should now be synced with the new column.\n * \n * @param tableFields \n */\n private addVersionedColumns = async (tableFields: InternalTableField[]) => {\n\n if (tableFields.length > 0) {\n logger.info(`🛂 Stream: ${this.streamId} - Versionning following columns in Warehouse schema: ${JSON.stringify(tableFields)}`)\n\n const columnsFromWarehouse = await this.getTableColumnsFromWarehouse();\n const columnNamesFromWarehouse = columnsFromWarehouse.map(col => col.name);\n\n let columnsToBeAddedInWarehouse: InternalTableField[] = [];\n tableFields.forEach(tblField => {\n const safeName = tblField.name as string;\n const warehouseTypeToBeUsed = this.getWarehouseTypeFromJSONSchema(tblField.definition)\n const columnNameWithTypeSuffix = this.getcolumnNameWithTypeSuffix(safeName, warehouseTypeToBeUsed)\n\n // Rewrite the safe mapping of the column to the versionned column\n this.renamedColumnStore.getUnsafeToSafeColumnMapping(this.streamId)[tblField.unsafeName] = columnNameWithTypeSuffix;\n\n if (!columnNamesFromWarehouse.includes(columnNameWithTypeSuffix)) {\n columnsToBeAddedInWarehouse.push({\n unsafeName: columnNameWithTypeSuffix,\n name: columnNameWithTypeSuffix,\n definition: tblField.definition\n })\n }\n })\n\n if (columnsToBeAddedInWarehouse.length > 0) {\n await this.addColumns(columnsToBeAddedInWarehouse);\n }\n }\n }\n\n private updateTableColumns = async () => {\n\n const columnsFromWarehouse = await this.getTableColumnsFromWarehouse();\n const columnNamesFromWarehouse = columnsFromWarehouse.map(col => col.name);\n\n const columnsMappingStore = this.renamedColumnStore.getUnsafeToSafeColumnMapping(this.streamId);\n const columnsToAdd: InternalTableField[] = Object.keys(columnsMappingStore)\n .filter(unsafeColumnKey => {\n const safeColumnName = columnsMappingStore[unsafeColumnKey];\n if (!safeColumnName) {\n return false;\n }\n return !columnNamesFromWarehouse.includes(safeColumnName);\n })\n .map(unsafeColumnKey => {\n const safeColumnName = columnsMappingStore[unsafeColumnKey];\n const definition = this.flattenedSchema[unsafeColumnKey];\n if (!safeColumnName || !definition) {\n return undefined as unknown as InternalTableField;\n }\n return {\n unsafeName: unsafeColumnKey,\n name: safeColumnName,\n definition\n }\n })\n .filter((item): item is InternalTableField => !!item)\n\n await this.addColumns(columnsToAdd);\n\n const columnsToVersion: InternalTableField[] = Object.keys(this.flattenedSchema)\n // We keep only the columns already declared in Warehouse but with a different type\n .filter(unsafeColumnKey => {\n const definition = this.flattenedSchema[unsafeColumnKey];\n if (!definition) {\n return false;\n }\n const warehouseTypeToBeUsed = this.getWarehouseTypeFromJSONSchema(definition)\n if (warehouseTypeToBeUsed) {\n const safeName = this.safeColumnName(unsafeColumnKey);\n if (columnNamesFromWarehouse.includes(safeName)) {\n const columnFromWarehouse = columnsFromWarehouse.find(col => col.name === safeName);\n\n if (!columnFromWarehouse) {\n throw new Error(`We can't find in Warehouse schema any column definition for colName: ${safeName}`);\n }\n\n const { type } = columnFromWarehouse;\n\n if (warehouseTypeToBeUsed !== type) {\n return true;\n }\n }\n }\n return false;\n })\n .map(unsafeColumnKey => {\n const definition = this.flattenedSchema[unsafeColumnKey];\n if (!definition) {\n return undefined as unknown as InternalTableField;\n }\n return {\n unsafeName: unsafeColumnKey,\n name: this.safeColumnName(unsafeColumnKey),\n definition\n }\n })\n .filter((tableField): tableField is InternalTableField => !!tableField);\n\n await this.addVersionedColumns(columnsToVersion);\n\n }\n\n mergeTempTableWithDestination = async (\n replicationMethod: ReplicationMethod\n ) => {\n\n let mergeQueries: string[] = [];\n if (replicationMethod === \"FULL_TABLE\") {\n mergeQueries = this.getReplaceQueries();\n } else if (replicationMethod === \"INCREMENTAL\") {\n mergeQueries = this.getMergeQueries();\n } else if (replicationMethod === \"APPEND\") {\n mergeQueries = this.getAppendQueries();\n } else if (replicationMethod === \"LOG_BASED\") {\n mergeQueries = this.getMergeQueries();\n }\n\n logger.info(`🍆 Table=${this.table} - Merging staging data with method ${replicationMethod}`);\n logger.debug(`Table=${this.table} - Merge queries: %j`, mergeQueries);\n\n await this.runQueriesWithRetry(mergeQueries);\n\n }\n\n}","import { ErrorObject } from \"ajv\";\nimport { StreamId } from \"../metadata\";\n\nexport class SchemaValidationError extends Error {\n\n streamId: StreamId;\n validationErrors: ErrorObject[];\n\n constructor(message: string, streamId: StreamId, errors: ErrorObject[]) {\n super(message); // (1)\n this.name = \"SchemaValidationError\"; // (2)\n this.streamId = streamId;\n this.validationErrors = errors;\n }\n\n}\n\nexport class MissingFieldInSchemaError extends Error {\n\n streamId: StreamId;\n\n constructor(message: string, streamId: StreamId) {\n super(message); // (1)\n this.name = \"MissingFieldInSchemaError\"; // (2)\n this.streamId = streamId;\n }\n\n}\n\nexport class MissingSchemaError extends Error {\n\n streamId: StreamId;\n\n constructor(message: string, streamId: StreamId) {\n super(message); // (1)\n this.name = \"MissingSchemaError\"; // (2)\n this.streamId = streamId;\n }\n\n}","import { FlattenedSchema } from \"./models\";\n\nexport const removeParasiteProperties = (record: any, schema: FlattenedSchema) => {\n const schemaKeys = Object.keys(schema);\n Object.keys(record).forEach(key => {\n if (!schemaKeys.includes(key)) {\n delete record[key]\n }\n })\n\n return record;\n}\n\nexport const addWhalyFields = (record: any, batchDate: string) => {\n return {\n ...record,\n _whaly_synced: batchDate\n }\n}","import { logger } from \"../../service/logger\";\nimport { FlattenedSchema } from \"./models\";\n\n// { \"streamId\": { \"originalColumnName\": \"renamedColumnName\" } }\nexport interface ColumnMappingStoreUnsafeToSafe {\n [originalColumnName: string]: string\n}\n\nexport type SafeColumnNameConverterFn = (unsafe: string) => string\n\n/**\n * This stateful class is to be used to store all the columns names mapping between the \"raw\" column name\n * found in the records and the destination column in the data warehouse\n * \n * A mapping exists between the fields declared by the Tap and the reality in the Warehouse for those reasons:\n * - Columns that are versionned due to type changes since the last load\n * - Columns that have a name conflict after \"Warehouse\" sanitization\n */\nexport class RenameColumnStore {\n\n // Store all the mappings store for all streamId\n private renamedColumns: { [streamId: string]: ColumnMappingStoreUnsafeToSafe };\n\n private safeColumnNameConverter?: SafeColumnNameConverterFn;\n\n constructor() {\n this.renamedColumns = {};\n }\n\n setSafeColumnNameConverter = (fn: SafeColumnNameConverterFn): void => {\n this.safeColumnNameConverter = fn;\n }\n\n // This function has a side effect on:\n // - `this.renamedColumns`\n // This isn't very clean and should be updated to write a pure version of this function\n computeColumnNameForStream = (\n streamId: string,\n flattenedSchema: FlattenedSchema,\n ) => {\n const safeColNameConv = this.safeColumnNameConverter;\n if (!safeColNameConv) {\n throw new Error(`safeColumnNameConverter is not defined!`)\n }\n const colSafeToUnsafeMapping = Object.keys(flattenedSchema)\n .sort()\n .reduce<{ [safeColName: string]: string }>((acc, unsafeColName) => {\n const safeColName = safeColNameConv(unsafeColName);\n if (!acc[safeColName]) {\n acc[safeColName] = unsafeColName;\n } else {\n logger.info(`🚨 Stream: ${streamId} - We have a column name conflict after sanitization for column unsafe=${unsafeColName}. We'll rename the sanitized name to a non taken name.\n Details: unsafeColName=${unsafeColName} is colliding with: ${acc[safeColName]}`)\n for (let i = 1; ; i++) {\n if (!acc[`${safeColName}_${i}`]) {\n acc[`${safeColName}_${i}`] = unsafeColName;\n break;\n }\n }\n }\n return acc;\n }, {});\n\n const colUnsafeToSafeMapping = Object.keys(colSafeToUnsafeMapping)\n .reduce<{ [unssafeColName: string]: string }>((acc, safeColName) => {\n const unsafeColname = colSafeToUnsafeMapping[safeColName];\n if (unsafeColname) {\n acc[unsafeColname] = safeColName;\n }\n return acc;\n }, {})\n\n // Init the renamedColumns dict\n const mapping = this.renamedColumns[streamId] || {};\n this.renamedColumns[streamId] = mapping;\n Object.keys(colUnsafeToSafeMapping).forEach(unsafeColName => {\n const safeName = colUnsafeToSafeMapping[unsafeColName];\n if (safeName) {\n mapping[unsafeColName] = safeName;\n }\n });\n }\n\n getColumnTranslation = (\n streamId: string,\n originalColumnName: string\n ): string => {\n if (!this.renamedColumns[streamId]) {\n throw new Error(\n `StreamId=${streamId} - Columns Mapping Store is not initialized! \n Trying to get renamed value for column '${originalColumnName}'`\n )\n }\n const value = this.renamedColumns[streamId][originalColumnName];\n if (!value) {\n throw new Error(`StreamId=${streamId} - No renamed value found for column '${originalColumnName}'`)\n }\n return value;\n }\n\n getUnsafeToSafeColumnMapping = (streamId: string): ColumnMappingStoreUnsafeToSafe => {\n const mapping = this.renamedColumns[streamId];\n if (!mapping) {\n throw new Error(`StreamId=${streamId} - Columns Mapping Store is not initialized!`)\n }\n return mapping;\n }\n\n isReady = (streamId: string): boolean => {\n if (!this.renamedColumns[streamId]) {\n return false;\n } else {\n return true;\n }\n }\n}","import { StreamId } from \"../metadata\";\nimport { FlattenedSchema } from \"./models\";\nimport { logger } from \"../../service/logger\";\nimport { gracefulExit } from \"../../service/exit\";\n\nexport const flattenSchema = <T>(streamId: StreamId, schema: T): FlattenedSchema => {\n\n logger.debug(`Flattening schema for stream: ${streamId}`)\n\n try {\n const mSchema = schema as any;\n\n if (!mSchema[\"properties\"]) {\n return {};\n }\n\n const properties = mSchema[\"properties\"];\n\n const flattenedSchema = Object.keys(properties).reduce<FlattenedSchema>((acc, propertyName) => {\n const propertySchema = properties[propertyName];\n const columnName = propertyName;\n\n if (!propertySchema) {\n return acc;\n }\n\n if (!propertySchema[\"type\"]) {\n throw new Error(`We don't have any \\`type\\` for the property: \\`${propertyName}\\`.\n Schema of the property is: ${JSON.stringify(propertySchema)}`)\n }\n\n acc[columnName] = {\n type: propertySchema[\"type\"],\n format: propertySchema[\"format\"],\n items: propertySchema[\"items\"]\n };\n\n return acc;\n }, {});\n\n return flattenedSchema;\n } catch (err: any) {\n logger.error(`There was an error when processing the schema of stream:\\`${streamId}\\`: err: ${err.message} - ${err.stack}.\n Processed schema: ${JSON.stringify(schema)}`);\n gracefulExit(1);\n return {};\n }\n\n}","import { ReplicationMethodMessage, RecordMessage, SchemaMessage, StateMessage } from \"../messages\";\nimport { TargetSchemaHook, TargetSchemaHookInput } from \"./targetHook\";\nimport Ajv from \"ajv\";\nimport addFormats from \"ajv-formats\";\nimport dayjs, { Dayjs } from \"dayjs\";\nimport { RenameColumnStore, SafeColumnNameConverterFn } from \"./renameColumnStore\";\nimport { StreamState } from \"./streamDbState\";\nimport { logger } from \"../../service/logger\";\nimport { MissingSchemaError, SchemaValidationError } from \"./error\";\nimport { addWhalyFields, removeParasiteProperties } from \"./record\";\nimport { BaseConfig, FlattenedSchema } from \"./models\";\nimport { flattenSchema } from \"./schema\";\nimport { StreamWarehouseSyncService } from \"./dbSync\";\nimport { Semaphore } from \"async-mutex\";\nimport { ReplicationMethod } from \"../replication\";\nimport Bluebird from \"bluebird\";\nimport { StateProvider } from \"../state-provider/types\";\nimport { StreamId } from \"../metadata\";\n\nconst semaphore = new Semaphore(1);\n\nexport abstract class ITarget<C extends BaseConfig = BaseConfig> {\n config: C;\n schemaHooks: TargetSchemaHook[]\n syncTime: Dayjs;\n stateProvider: StateProvider;\n\n // Latest state message received from the Tap\n // Not yet flushed as we didn't upload the stream data since receiving it \n batchedState: any;\n\n // Latest \"flushed\" state message\n // A state message is flushed when we do a stream upload.\n flushedState: any;\n\n renameColumnStore: RenameColumnStore;\n\n streams: {\n [streamName: string]: StreamState\n }\n\n // JSON Schema validator (ajv — pre-compiles schemas into optimized JS functions)\n ajv: Ajv\n\n constructor(config: C, stateProvider: StateProvider) {\n this.config = config;\n this.stateProvider = stateProvider;\n this.schemaHooks = [];\n\n this.streams = {}\n\n this.batchedState = {}\n this.flushedState = {}\n\n this.ajv = addFormats(new Ajv({ allErrors: true, strict: false }));\n this.syncTime = dayjs();\n\n this.renameColumnStore = new RenameColumnStore()\n }\n\n ///////////////////////////////////////////\n //// To be overriden by child classes /////\n ///////////////////////////////////////////\n static requiredConfigKeys: string[] = [];\n // Generate instance of DBSync\n abstract newDBSyncInstance: (\n streamId: StreamId,\n database: string,\n schema: string,\n table: string\n ) => StreamWarehouseSyncService;\n // Function to render safe table names\n abstract genTableName: (streamId: string) => string;\n // Function to render safe column names\n abstract safeColumnNameConverter: SafeColumnNameConverterFn;\n // Convert the date values of a record into valid ones for the Warehouse\n abstract validateDateRange: (reacord: any, schema: FlattenedSchema) => any;\n // Convert the number values of a record into valid ones for the Warehouse\n abstract convertNumberIntoDecimal: (record: any, schema: FlattenedSchema) => any;\n\n ////////////////////////////////////////////\n /////////// Implementation /////////////////\n ////////////////////////////////////////////\n\n // Analyze schema changes to determine if they are breaking or non-breaking\n private analyzeSchemaChanges = (\n previousSchema: FlattenedSchema,\n newSchema: FlattenedSchema,\n streamId: string\n ): { hasBreakingChanges: boolean; changes: string[] } => {\n const changes: string[] = [];\n let hasBreakingChanges = false;\n\n // Get all column names from both schemas\n const prevColumns = new Set(Object.keys(previousSchema).filter(col => !col.startsWith(\"_whaly\")));\n const newColumns = new Set(Object.keys(newSchema).filter(col => !col.startsWith(\"_whaly\")));\n\n // Check for new columns (non-breaking)\n for (const columnName of newColumns) {\n if (!prevColumns.has(columnName)) {\n changes.push(`Added column '${columnName}'`);\n }\n }\n\n // Check for removed columns (breaking)\n for (const columnName of prevColumns) {\n if (!newColumns.has(columnName)) {\n changes.push(`Removed column '${columnName}'`);\n hasBreakingChanges = true;\n }\n }\n\n // Check for type changes in existing columns (breaking)\n for (const columnName of prevColumns) {\n if (newColumns.has(columnName)) {\n const prevType = previousSchema[columnName];\n const newType = newSchema[columnName];\n\n // Compare the type definitions\n if (JSON.stringify(prevType) !== JSON.stringify(newType)) {\n changes.push(`Changed type of column '${columnName}'`);\n hasBreakingChanges = true;\n }\n }\n }\n\n if (changes.length === 0) {\n changes.push('No schema changes detected');\n }\n\n logger.debug(`StreamId=${streamId} - Schema analysis: ${hasBreakingChanges ? 'BREAKING' : 'NON-BREAKING'} changes found: ${changes.join(', ')}`);\n\n return { hasBreakingChanges, changes };\n }\n\n // Serialize a RECORD message into a line that will be uploaded in the staging area\n getSerializedRecord = (streamId: string, record: any): string => {\n const stream = this.streams[streamId];\n if (!stream) {\n throw new MissingSchemaError(`A record for stream:\\`${streamId}\\` was encountered before a corresponding schema.`, streamId)\n }\n return stream.getDbSync().getSerializedRecord(record)\n }\n\n record = async (message: RecordMessage): Promise<void> => {\n try {\n\n const streamId = message.stream;\n const stream = this.streams[streamId];\n\n if (!stream) {\n throw new MissingSchemaError(`A record for stream:\\`${streamId}\\` was encountered before a corresponding schema.`, streamId)\n }\n\n // To avoid getting any conflicts when loading data in the warehouse, we run a semaphore to have a concurrency of 1\n // Only check every 10,000 rows to avoid semaphore acquisition overhead on every single row\n // (intermediate batch threshold is 1,000,000 rows, so checking every 10,000 is more than sufficient)\n if (stream.getBatchedRowCount() % 10_000 === 0) {\n await semaphore.runExclusive(async () => {\n const shouldUploadIntermediateBatch = this.shouldUploadIntermediateBatch(streamId)\n if (shouldUploadIntermediateBatch) {\n await this.loadAllStreamsInWarehouse({ isFinalLoad: false })\n }\n })\n }\n\n const record = message.record;\n const schema = stream.getSchema();\n\n if (!schema) {\n logger.warn(`Stream: ${streamId} - Received a RECORD message while schema is undefined. Dropping message.`)\n return;\n }\n\n const recordWithoutParasiteProperties = removeParasiteProperties(record, schema);\n\n const recordWithWhalyFields = addWhalyFields(recordWithoutParasiteProperties, stream.getBatchDate());\n\n // Checking that the RECORD is valid compared to the previously received SCHEMA.\n // Uses a pre-compiled ajv ValidateFunction (compiled once in schema()) for maximum throughput.\n const validateFn = stream.getCompiledValidateFn();\n if (validateFn && !validateFn(recordWithWhalyFields)) {\n throw new SchemaValidationError(`Stream: ${streamId} - Record is not valid according to schema.\n Validation errors: ${JSON.stringify(validateFn.errors)}\n\n Record: ${JSON.stringify(recordWithoutParasiteProperties)}\n Schema: ${JSON.stringify(stream.getSchema())}`, streamId, validateFn.errors ?? [])\n }\n\n // Making sure that the date are in valid range supported by Warehouse\n const recordWithValidDate = this.validateDateRange(recordWithWhalyFields, schema);\n // Working with Decimal.js is better as the JS `number` type is quite imprecise\n const recordWithDecimal = this.convertNumberIntoDecimal(recordWithValidDate, schema)\n\n // Columns should be renamed to:\n // - Be \"safe\" for Warehouse\n // - Handle the case where there are conflicts in column names after sanitization\n // - There is a column versionning due to a column type change since the last sync\n const dbSyncInstance = stream.getDbSync();\n const recordWithrenamedColumns = dbSyncInstance.renameColumns(recordWithDecimal);\n\n const serializedRecord = this.getSerializedRecord(streamId, recordWithrenamedColumns);\n\n return new Promise((resolve, reject) => {\n stream.getFileToLoad().stream.write(serializedRecord, (error) => {\n if (error) {\n reject(error);\n }\n\n stream.incrementBatchedRowCount();\n resolve();\n });\n })\n\n } catch (err) {\n logger.error(`Error when handling \"record\" message`);\n throw err;\n }\n }\n\n private initStreamStateAndSyncService(\n streamId: string,\n replicationMethod?: ReplicationMethod\n ): void {\n const dbSyncInstance = this.newDBSyncInstance(\n streamId,\n this.config.database,\n this.config.schema,\n this.genTableName(streamId)\n )\n this.streams[streamId] = new StreamState(\n streamId,\n dbSyncInstance,\n replicationMethod || ReplicationMethod.FULL_TABLE\n );\n }\n\n replicationMethod = (message: ReplicationMethodMessage): void => {\n\n try {\n logger.info(`👈 Received replicationMethod message: %j`, message)\n const streamId = message.stream;\n if (!this.streams[streamId]) {\n this.initStreamStateAndSyncService(streamId, message.replication)\n } else {\n this.streams[streamId].setReplicationMethod(message.replication);\n }\n } catch (err) {\n logger.error(`Error when handling \"replicationMethod\" event`)\n throw err;\n }\n }\n\n schema = async (message: SchemaMessage): Promise<void> => {\n\n try {\n const streamId = message.stream;\n\n logger.info(`Stream: ${streamId} - Got a SCHEMA message from the tap`);\n logger.debug(`Stream: ${streamId} - Got a SCHEMA message from the tap: %j`, message);\n\n if (!this.streams[streamId]) {\n this.initStreamStateAndSyncService(streamId)\n } else {\n // Load the previous batched data as there can be schema changes\n const prevStreamState = this.streams[streamId];\n if (prevStreamState.batchedRowCount > 0) {\n const prevSchema = prevStreamState.getSchema();\n if(prevSchema) {\n // Flatten the new schema to compare with the previous one\n const newFlattenedSchema = flattenSchema(streamId, message.schema);\n // Check if schema changes are breaking or non-breaking\n const { hasBreakingChanges, changes } = this.analyzeSchemaChanges(prevSchema, newFlattenedSchema, streamId);\n if (hasBreakingChanges) {\n logger.info(`🔥 StreamId=${streamId} - Detected BREAKING schema changes: ${changes.join(', ')}. Loading batched records before applying new schema.`);\n await ITarget.uploadSingleStreamToWarehouse(prevStreamState);\n } else {\n logger.info(`✅ StreamId=${streamId} - Detected NON-BREAKING schema changes: ${changes.join(', ')}. Continuing without uploading batched records.`);\n }\n }\n }\n }\n\n const streamState = this.streams[streamId];\n if (!streamState) {\n throw new MissingSchemaError(`Stream: ${streamId} - Received SCHEMA message before stream state was initialized.`, streamId)\n }\n const schema = flattenSchema(streamId, message.schema);\n\n // Add Whaly specific columns\n schema[\"_whaly_synced\"] = {\n format: \"date-time\",\n type: [\"null\", \"string\"]\n }\n\n const dbSync = streamState.getDbSync();\n Object.keys(schema).forEach(fieldUnsafeKey => {\n // Remove the key associated to no warehouse type\n const fieldDef = schema[fieldUnsafeKey];\n const targetWarehouseType = fieldDef ? dbSync.getWarehouseTypeFromJSONSchema(fieldDef) : undefined;\n\n if (!targetWarehouseType) {\n delete schema[fieldUnsafeKey]\n }\n })\n\n streamState.setSchema(schema);\n streamState.setCompiledValidateFn(this.ajv.compile({ type: \"object\", properties: schema }));\n\n const streamReplicationMethod = this.streams[streamId]?.getReplicationMethod();\n if (message.keyProperties.length === 0 && streamReplicationMethod !== ReplicationMethod.APPEND) {\n throw new Error(`StreamId: ${message.stream} - \\`key_properties\\` field is required and can't be empty in SCHEMA message.\n Received SCHEMA message: ${JSON.stringify(message)}`)\n }\n\n streamState.setKeyProperties(message.keyProperties);\n\n await dbSync.updateSchemaInWarehouse(schema, message.keyProperties);\n\n const {\n database: databaseName,\n schema: schemaName\n } = this.config;\n\n const tableName = this.genTableName(streamId);\n\n const formattedRelationshipMessage: SchemaMessage = {\n ...message,\n keyProperties: message.keyProperties.map(k => {\n const translation = streamState.getDbSync().renamedColumnStore.getColumnTranslation(message.stream, k);\n if (translation) {\n return translation;\n }\n return k\n })\n }\n\n await Bluebird.map(this.schemaHooks, async (hook) => {\n const input: TargetSchemaHookInput = {\n databaseName,\n schemaName,\n tableName,\n message: formattedRelationshipMessage,\n }\n await hook.writeSchema(input);\n }, { concurrency: 3 })\n\n return Promise.resolve();\n } catch (err) {\n logger.error(`Error when handling schema event.`, err)\n throw err;\n }\n }\n\n state = (message: StateMessage): Promise<void> => {\n\n try {\n this.batchedState = message.value;\n\n if (!this.flushedState) {\n this.flushedState = Object.assign({}, this.state);\n }\n return Promise.resolve()\n } catch (err) {\n logger.error(`Error while handling state event.`)\n throw err;\n }\n }\n\n complete = async (): Promise<void> => {\n\n try {\n logger.info(`👍 Data Extraction is complete. Will load remaining batched stream records.`)\n\n await this.loadAllStreamsInWarehouse({ isFinalLoad: true });\n return Promise.resolve();\n } catch (err) {\n logger.error(`Error while handling complete event.`)\n throw err;\n }\n }\n\n private shouldUploadIntermediateBatch = (streamId: string): boolean => {\n const stream = this.streams[streamId];\n if (!stream) {\n return false;\n }\n const batchedRecords = stream.getBatchedRowCount()\n const method = stream.getReplicationMethod();\n if ((method === \"INCREMENTAL\" || method === \"APPEND\") && batchedRecords > 1_000_000) {\n logger.info(`🧊 Stream=${streamId} has reached the maximum amount of batched records. We'll trigger a flush of ALL streams in the Warehouse.`)\n return true;\n } else {\n return false;\n }\n }\n\n private loadAllStreamsInWarehouse = async (opts: { isFinalLoad: boolean }): Promise<void> => {\n logger.info(`🚛🚛🚛 Loading ALL Streams in Warehouse.`)\n const { isFinalLoad } = opts;\n const streamsWithRemainingRecords = Object\n .keys(this.streams)\n .filter(streamId => {\n // FULL TABLE streams are removed from the load if it's not the final load\n const s = this.streams[streamId];\n if (!s) {\n return false;\n }\n if (!isFinalLoad && s.getReplicationMethod() === \"FULL_TABLE\") {\n return false;\n }\n return s.getBatchedRowCount() > 0\n });\n\n if (streamsWithRemainingRecords.length > 0) {\n this.flushedState = await this.uploadStreamsToWarehouse(streamsWithRemainingRecords)\n }\n\n if (Object.keys(this.flushedState).length > 0) {\n await this.emitState(Object.assign({}, this.flushedState))\n // Special case where nothing was written in the warehouse (nothing to sync then)\n // We keep the previous state\n } else {\n await this.emitState(Object.assign({}, this.state))\n }\n }\n\n private emitState = (state: any): Promise<void> => {\n return this.stateProvider.writeState(JSON.stringify(state));\n }\n\n private uploadStreamsToWarehouse = async (\n streamsToUpload: string[]\n ) => {\n\n try {\n await Bluebird.map(streamsToUpload, async (streamId) => {\n logger.info(`📤 Upload stream: ${streamId} to Warehouse`)\n const streamState = this.streams[streamId];\n if (streamState) {\n await ITarget.uploadSingleStreamToWarehouse(streamState)\n }\n }, { concurrency: 3 });\n\n return this.batchedState;\n } catch (err) {\n logger.error(`Error while uploading all streams + merging them.`)\n throw err;\n }\n }\n\n static uploadSingleStreamToWarehouse = async (\n streamState: StreamState\n ) => {\n\n const dbSync = streamState.getDbSync();\n\n try {\n const replicationMethod = streamState.getReplicationMethod();\n const fileToLoad = streamState.getFileToLoad();\n\n await dbSync.createStagingArea();\n await dbSync.loadStreamInStagingArea(fileToLoad.path);\n await dbSync.mergeTempTableWithDestination(replicationMethod);\n await dbSync.deleteStagingArea();\n streamState.setHasBeenLoadedYet();\n streamState.resetFileToLoad();\n } catch (err) {\n if (err instanceof Error) {\n logger.error(`StreamId=${dbSync.streamId} - Couldn't upload stream due to an error: %s`, err.message);\n throw err;\n } else {\n throw new Error('Unknown error')\n }\n }\n }\n}","import dayjs, { Dayjs } from \"dayjs\";\nimport { defaultDateTimeFormat } from \"../../constants/date\";\nimport { StreamId } from \"../metadata\";\nimport { ReplicationMethod } from \"../replication\";\nimport { StreamWarehouseSyncService } from \"./dbSync\";\nimport { FlattenedSchema, TempFile } from \"./models\";\nimport { createTemporaryFileStream } from \"./temporaryFile\";\nimport * as fs from \"fs\";\nimport { ValidateFunction } from \"ajv\";\n\n// This class is here to manage the State of a stream being loaded into a Warehouse\nexport class StreamState {\n streamId: StreamId;\n schema?: FlattenedSchema;\n dbSync: StreamWarehouseSyncService;\n\n batchDate: Dayjs;\n\n // Count rows batched in the local file, waiting for Warehouse upload\n batchedRowCount: number;\n // Local CSV files written to be sent to Warehouse\n fileToLoad: TempFile;\n // Count rows sent to Warehouse\n syncedRowCount: number;\n keyProperties: string[];\n\n // When a FULL_TABLE stream is loaded multiple times, the query used for the 2nd+ loads\n // needs to be different than the 1st merge query -> 1st load is dropping the existing table, 2nd+ loads are merging with the existing table (otherwise the previous load data are dropped)\n // So we need to keep track of whether we are at the first load or not\n _hasBeenLoadedYetDuringThisSync: boolean\n\n replicationMethod: ReplicationMethod\n\n // Pre-compiled ajv ValidateFunction — compiled once per schema, reused for every row\n compiledValidateFn?: ValidateFunction;\n\n constructor(\n streamId: StreamId, \n dbSync: StreamWarehouseSyncService, \n replicationMethod: ReplicationMethod, \n ) {\n this.streamId = streamId;\n this.dbSync = dbSync;\n\n this.batchedRowCount = 0;\n this.fileToLoad = createTemporaryFileStream(streamId);\n this.syncedRowCount = 0;\n this.keyProperties = [];\n this.batchDate = dayjs();\n this.replicationMethod = replicationMethod;\n this._hasBeenLoadedYetDuringThisSync = false;\n }\n\n setSchema(schema: FlattenedSchema) {\n this.schema = schema;\n }\n\n getSchema(): FlattenedSchema | undefined {\n return this.schema;\n }\n\n setCompiledValidateFn(fn: ValidateFunction) {\n this.compiledValidateFn = fn;\n }\n\n getCompiledValidateFn(): ValidateFunction | undefined {\n return this.compiledValidateFn;\n }\n\n getBatchDate(): string {\n return this.batchDate.format(defaultDateTimeFormat);\n }\n\n getBatchedRowCount(): number {\n return this.batchedRowCount;\n }\n\n incrementBatchedRowCount() {\n this.batchedRowCount += 1;\n }\n\n getFileToLoad(): TempFile {\n return this.fileToLoad;\n }\n\n resetFileToLoad() {\n this.fileToLoad.stream.close();\n const oldPath = this.fileToLoad.path;\n // Delete the old file to make some space\n fs.unlinkSync(oldPath);\n this.fileToLoad = createTemporaryFileStream(this.streamId);\n this.batchedRowCount = 0;\n }\n\n getKeyProperties(): string[] {\n return this.keyProperties;\n }\n\n setKeyProperties(keyProperties: string[]) {\n this.keyProperties = keyProperties\n }\n\n getDbSync(): StreamWarehouseSyncService {\n return this.dbSync\n }\n\n getReplicationMethod(): ReplicationMethod {\n return this.replicationMethod\n }\n\n setReplicationMethod(r: ReplicationMethod) {\n this.replicationMethod = r;\n }\n\n setHasBeenLoadedYet() {\n this._hasBeenLoadedYetDuringThisSync = true;\n }\n}","import fs from 'fs-extra';\nimport uniqueId from 'lodash/uniqueId.js';\nimport { StreamId } from '../metadata';\nimport { TempFile } from './models';\n\nexport const createTemporaryFileStream = (streamId: StreamId): TempFile => {\n fs.ensureDirSync(\"./tmp\")\n const path = `./tmp/${safePath(streamId)}-${uniqueId()}.tmp`;\n const writeStream = fs.createWriteStream(path, {flags: \"w\"});\n\n return {\n stream: writeStream,\n path\n };\n}\n\nexport function safePath(path: string): string {\n let formattedPath = path;\n formattedPath = formattedPath.replace(/^The\\s+/gi, '');\n formattedPath = formattedPath.replace(/\\s+(?:\\(|\\[)?Dis(?:c|k) (?:One|Two|Three|Four|Five|Six|Seven|Eight|Nine|Ten|\\d)+(?:\\)|\\])?/gi, '');\n formattedPath = formattedPath.replace(/\\s+/gi, '_');\n formattedPath = formattedPath.replace(/(?:\\'|`)/gi, '');\n formattedPath = replaceAccented(formattedPath);\n formattedPath = replaceSymbols(formattedPath);\n formattedPath = formattedPath.replace(/(?:[^a-z0-9])+/gi, '_');\n\n return formattedPath;\n};\n\nfunction replaceAccented(str: string) {\n str = str.replace(/(?:\\xC0|\\xC1|\\xC2|\\xC3|\\xC4|\\xC5)/g, 'A');\n str = str.replace(/(?:\\xC7)/g, 'C');\n str = str.replace(/(?:\\xC8|\\xC9|\\xCA|\\xCB)/g, 'E');\n str = str.replace(/(?:\\xCC|\\xCD|\\xCE|\\xCF)/g, 'I');\n str = str.replace(/(?:\\xD2|\\xD3|\\xD4|\\xD6|\\xD5)/g, 'O');\n str = str.replace(/(?:\\xD9|\\xDA|\\xDB|\\xDC)/g, 'U');\n str = str.replace(/(?:\\xDD|\\x9F)/g, 'Y');\n str = str.replace(/(?:\\xD1)/g, 'N');\n str = str.replace(/(?:\\xC6)/g, 'Ae');\n str = str.replace(/(?:\\xDF)/g, 'ss');\n str = str.replace(/(?:\\xE0|\\xE1|\\xE2|\\xE4|\\xE5|\\xE3)/g, 'a');\n str = str.replace(/(?:\\xE7)/g, 'c');\n str = str.replace(/(?:\\xE8|\\xE9|\\xEA|\\xEB)/g, 'e');\n str = str.replace(/(?:\\xEC|\\xED|\\xEE|\\xEF)/g, 'i');\n str = str.replace(/(?:\\xF2|\\xF3|\\xF4|\\xF6|\\xF5)/g, 'o');\n str = str.replace(/(?:\\xF9|\\xFA|\\xFB|\\xFC)/g, 'u');\n str = str.replace(/(?:\\xFD|\\xFF)/g, 'y');\n str = str.replace(/(?:\\xF1)/g, 'n');\n str = str.replace(/(?:\\xE6)/g, 'ae');\n return str;\n}\n\nfunction replaceSymbols(str: string) {\n str = str.replace(/(?:\\(|\\))/g, '');\n str = str.replace(/(?:\\.|\\?)/g, '');\n str = str.replace(/(?:_+)/g, '_');\n str = str.replace(/(?:\\$+)/g, 's');\n return str;\n}","import { WorkBook } from \"xlsx\";\nimport { ReplicationMethod } from \"../models/replication\";\n\n// Re-export WorkBook so client projects don't need xlsx as a direct dependency\nexport type { WorkBook } from \"xlsx\";\n\n// Re-export ReplicationMethod so file-processing consumers don't need a separate import\nexport { ReplicationMethod } from \"../models/replication\";\n\n/**\n * Field types for file processing columns.\n * Maps to JSON Schema types via fieldTypeToJsonSchema().\n */\nexport type FieldType = \"STRING\" | \"FLOAT\" | \"TIMESTAMP\";\n\nexport enum FileFormat {\n CSV = \"CSV\",\n EXCEL = \"EXCEL\",\n}\n\n// ─── Excel Types ───────────────────────────────────────────────────────\n\nexport type ExcelFieldSpec = ExcelSourceColumn | ExcelDerivedField;\n\nexport interface ExcelSourceColumn {\n type: FieldType;\n column: string;\n primaryKey?: boolean;\n}\n\nexport interface ExcelDerivedField {\n variableName: string;\n primaryKey?: boolean;\n type: FieldType;\n}\n\nexport interface ExcelFieldMapping {\n [key: string]: ExcelFieldSpec;\n}\n\nexport type ExcelExtractionConfig = ExcelSingleSheetExtractionConfig | ExcelCustomExtractorConfig;\n\nexport interface ExcelExtractionBaseConfig {\n type: \"single-sheet-extraction\" | \"processor\";\n extension: string;\n fileNameValidator: (fileName: string) => boolean;\n fileNameVariablesExtractor: (fileName: string, workbook?: WorkBook) => { [key: string]: string | undefined };\n tableName: string | ((fileName: string, workbook?: WorkBook, variables?: { [key: string]: string | undefined }) => string);\n replicationMethod: ReplicationMethod;\n}\n\nexport interface ExcelCustomExtractorConfig extends ExcelExtractionBaseConfig {\n type: \"processor\";\n processor: (workbook: WorkBook) => Promise<Record<string, string>[]>;\n}\n\nexport interface ExcelSingleSheetExtractionConfig extends ExcelExtractionBaseConfig {\n type: \"single-sheet-extraction\";\n columns: ExcelFieldMapping;\n sheetName?: string;\n numberOfRowsToSkip: number;\n}\n\n// ─── CSV Types ─────────────────────────────────────────────────────────\n\nexport type CsvFieldsConfig = CsvFieldsArrayConfig | CsvFieldsDictConfig;\n\nexport type CsvFieldsArrayConfig = Array<{\n key: string;\n valueTransformer?: (val: any) => string;\n type: FieldType;\n}>;\n\nexport interface CsvFieldsDictConfig {\n [key: string]: {\n key: string;\n valueTransformer?: (val: any) => string;\n type: FieldType;\n };\n}\n\nexport interface CsvFileConfig {\n encoding?: string;\n separator: string;\n fields: CsvFieldsConfig;\n addSyncedAtColumn?: boolean;\n}\n\n// ─── FileStream Config (discriminated union) ────────────────────────────\n\ninterface FileStreamBaseConfig {\n streamId: string;\n replicationMethod: ReplicationMethod;\n primaryKeys: string[];\n}\n\nexport interface CsvStreamConfig extends FileStreamBaseConfig {\n format: FileFormat.CSV;\n csv: CsvFileConfig;\n}\n\nexport interface ExcelStreamConfig extends FileStreamBaseConfig {\n format: FileFormat.EXCEL;\n excel: ExcelExtractionConfig;\n}\n\nexport type FileStreamConfig = CsvStreamConfig | ExcelStreamConfig;\n\n// ─── FileStream Entry (for pairing config + file path) ─────────────────\n\nexport interface FileStreamEntry {\n config: FileStreamConfig;\n filePath: string | string[];\n}\n","import {\n FieldType,\n ExcelFieldMapping,\n ExcelSourceColumn,\n ExcelDerivedField,\n CsvFieldsConfig,\n CsvFieldsArrayConfig,\n CsvFieldsDictConfig,\n} from \"./types\";\n\ntype JsonSchemaProperty = {\n type: (string | \"null\")[];\n format?: string;\n};\n\n/**\n * Convert a FieldType to a JSON Schema property definition.\n */\nexport function fieldTypeToJsonSchema(fieldType: FieldType): JsonSchemaProperty {\n switch (fieldType) {\n case \"STRING\":\n return { type: [\"null\", \"string\"] };\n case \"FLOAT\":\n return { type: [\"null\", \"number\"] };\n case \"TIMESTAMP\":\n return { type: [\"null\", \"string\"], format: \"date-time\" };\n default:\n return { type: [\"null\", \"string\"] };\n }\n}\n\n/**\n * Convert an ExcelFieldMapping to a JSON Schema properties object.\n */\nexport function excelFieldsToJsonSchema(fields: ExcelFieldMapping): {\n type: \"object\";\n properties: Record<string, JsonSchemaProperty>;\n} {\n const properties: Record<string, JsonSchemaProperty> = {};\n for (const [key, field] of Object.entries(fields)) {\n properties[key] = fieldTypeToJsonSchema(field.type);\n }\n return { type: \"object\", properties };\n}\n\n/**\n * Convert a CsvFieldsConfig to a JSON Schema properties object.\n */\nexport function csvFieldsToJsonSchema(config: CsvFieldsConfig): {\n type: \"object\";\n properties: Record<string, JsonSchemaProperty>;\n} {\n const properties: Record<string, JsonSchemaProperty> = {};\n\n if (Array.isArray(config)) {\n for (const field of config as CsvFieldsArrayConfig) {\n properties[field.key] = fieldTypeToJsonSchema(field.type);\n }\n } else {\n for (const [, field] of Object.entries(config as CsvFieldsDictConfig)) {\n properties[field.key] = fieldTypeToJsonSchema(field.type);\n }\n }\n\n return { type: \"object\", properties };\n}\n\n/**\n * Extract all output keys from a CsvFieldsConfig to use as composite primary keys.\n * Useful for FULL_TABLE replication where all fields form the PK (since TRUNCATE + MERGE = INSERT).\n */\nexport function extractPrimaryKeysFromCsvConfig(config: CsvFieldsConfig): string[] {\n if (Array.isArray(config)) {\n return (config as CsvFieldsArrayConfig).map(f => f.key);\n }\n return Object.values(config as CsvFieldsDictConfig).map(f => f.key);\n}\n\n/**\n * Extract primary keys from an ExcelFieldMapping.\n */\nexport function extractPrimaryKeysFromExcelFields(fields: ExcelFieldMapping): string[] {\n return Object.entries(fields)\n .filter(([, field]) => {\n return (field as ExcelSourceColumn).primaryKey === true\n || (field as ExcelDerivedField).primaryKey === true;\n })\n .map(([key]) => key);\n}\n","import XLSX, { WorkBook } from \"xlsx\";\nimport path from \"path\";\nimport {\n ExcelSourceColumn,\n ExcelExtractionConfig,\n ExcelSingleSheetExtractionConfig,\n ExcelDerivedField,\n} from \"../types\";\n\n/**\n * Converts an Excel column letter (A, B, C, AA, AZ, etc.) to its zero-based index.\n */\nexport const excelColumnToIndex = (columnLetter: string): number => {\n const letters = columnLetter.toUpperCase();\n let index = 0;\n\n for (let i = 0; i < letters.length; i++) {\n const charCode = letters.charCodeAt(i);\n if (charCode < 65 || charCode > 90) {\n throw new Error(`Invalid column letter: ${columnLetter}`);\n }\n index = (index * 26) + (charCode - 64);\n }\n\n return index - 1;\n};\n\n/**\n * Converts a zero-based column index to Excel column letter(s).\n */\nexport const indexToExcelColumn = (columnIndex: number): string => {\n if (columnIndex < 0) {\n throw new Error(`Invalid column index: ${columnIndex}. Must be >= 0`);\n }\n\n let result = \"\";\n let index = columnIndex;\n\n while (true) {\n result = String.fromCharCode(65 + (index % 26)) + result;\n index = Math.floor(index / 26);\n\n if (index === 0) break;\n index--;\n }\n\n return result;\n};\n\n/**\n * Converts an Excel row number (1-based) to zero-based array index.\n */\nexport const excelRowToIndex = (rowNumber: string | number): number => {\n const rowNum = typeof rowNumber === \"string\" ? parseInt(rowNumber, 10) : rowNumber;\n if (isNaN(rowNum) || rowNum < 1) {\n throw new Error(`Invalid row number: ${rowNumber}. Must be >= 1`);\n }\n return rowNum - 1;\n};\n\n/**\n * Converts a zero-based array index to Excel row number (1-based).\n */\nexport const indexToExcelRow = (index: number): number => {\n if (index < 0) {\n throw new Error(`Invalid index: ${index}. Must be >= 0`);\n }\n return index + 1;\n};\n\n/**\n * Parses an Excel cell reference (like \"A1\", \"Z24\", \"AA100\") into column and row indices.\n */\nexport const parseCellReference = (cellRef: string): { columnIndex: number; rowIndex: number } => {\n const match = cellRef.match(/^([A-Z]+)(\\d+)$/);\n if (!match) {\n throw new Error(`Invalid cell reference: ${cellRef}. Expected format like \"A1\", \"Z24\", \"AA100\"`);\n }\n\n const [, columnLetter, rowNumber] = match;\n return {\n columnIndex: excelColumnToIndex(columnLetter!),\n rowIndex: excelRowToIndex(rowNumber!),\n };\n};\n\n/**\n * Creates an Excel cell reference from column and row indices.\n */\nexport const createCellReference = (columnIndex: number, rowIndex: number): string => {\n return indexToExcelColumn(columnIndex) + indexToExcelRow(rowIndex);\n};\n\n/**\n * Extract a single Excel sheet based on configuration.\n */\nconst extractSingleSheetRows = async (\n fileName: string,\n conf: ExcelSingleSheetExtractionConfig,\n): Promise<Record<string, string | null>[]> => {\n console.log(\"Extracting single sheet rows from file: %s\", fileName);\n const workbook = XLSX.readFile(fileName, { dense: true });\n const sheetKeys = Object.keys(workbook.Sheets);\n const sheet = conf.sheetName\n ? workbook.Sheets[conf.sheetName]\n : workbook.Sheets[sheetKeys[0]!];\n\n if (!sheet) {\n throw new Error(`Sheet ${conf.sheetName} not found in workbook`);\n }\n const sheetData = sheet[\"!data\"];\n if (!sheetData) {\n throw new Error(`No data in ${conf.sheetName || \"first\"} sheet`);\n }\n if (sheetData.length === 0) {\n throw new Error(`Sheet ${conf.sheetName || \"first\"} is empty`);\n }\n\n const variables = conf.fileNameVariablesExtractor(fileName, workbook);\n const data: Record<string, string | null>[] = [];\n let rowIdx = 0;\n\n // Find minimum column index to determine when to stop processing\n const minColumnIndex = Object.values(conf.columns).reduce((min, column) => {\n return (column as ExcelSourceColumn).column\n ? Math.min(min, excelColumnToIndex((column as ExcelSourceColumn).column))\n : min;\n }, Number.MAX_SAFE_INTEGER);\n\n for (const row of sheetData) {\n if (rowIdx < conf.numberOfRowsToSkip) {\n rowIdx++;\n continue;\n }\n\n if (!row) {\n console.log(\"Empty row at index: %s, skipped processing.\", rowIdx);\n continue;\n }\n\n // Stop processing if the first data column is empty\n if (minColumnIndex !== Number.MAX_SAFE_INTEGER && !row[minColumnIndex]?.v) {\n console.log(\"stopping processing because of empty value in the first data column (idx: %s)\", minColumnIndex);\n break;\n }\n\n const rowData = Object.entries(conf.columns).reduce<{ [key: string]: string | null }>((acc, [key, column]) => {\n if ((column as ExcelDerivedField).variableName) {\n if (!variables) {\n throw new Error(`No variables extracted from filename, cannot extract derived field ${key}`);\n }\n acc[key] = variables[(column as ExcelDerivedField).variableName] || null;\n } else {\n const colIndex = excelColumnToIndex((column as ExcelSourceColumn).column);\n acc[key] = (row[colIndex]?.v as string) || null;\n }\n return acc;\n }, {});\n\n data.push(rowData);\n rowIdx++;\n }\n console.log(\"Extracted %s rows from sheet %s\", data.length, conf.sheetName || \"first\");\n return data;\n};\n\n/**\n * Low-level Excel extractor: returns array of row records from a workbook.\n */\nexport const extractExcelRows = async (\n localFilePath: string,\n conf: ExcelExtractionConfig,\n): Promise<Record<string, string | null>[]> => {\n let data: Record<string, string | null>[];\n\n if (conf.type === \"single-sheet-extraction\") {\n data = await extractSingleSheetRows(localFilePath, conf);\n } else if (conf.type === \"processor\") {\n const workbook = XLSX.readFile(localFilePath, { dense: true });\n data = await conf.processor(workbook);\n } else {\n throw new Error(`Unsupported configuration type: ${(conf as any).type}`);\n }\n\n return data;\n};\n\n/**\n * Validates an Excel file configuration.\n */\nexport const validateExcelConfig = (config: ExcelExtractionConfig): void => {\n if (!config.extension) {\n throw new Error(\"Extension is required\");\n }\n\n if (!config.tableName) {\n throw new Error(\"Table name is required\");\n }\n\n if (!config.fileNameValidator || typeof config.fileNameValidator !== \"function\") {\n throw new Error(\"File name validator function is required\");\n }\n\n if (!config.fileNameVariablesExtractor || typeof config.fileNameVariablesExtractor !== \"function\") {\n throw new Error(\"File name variables extractor function is required\");\n }\n\n if (\n config.type === \"single-sheet-extraction\" &&\n (!config.columns || Object.keys(config.columns).length === 0)\n ) {\n throw new Error(\"At least one column configuration is required for single-sheet-extraction\");\n }\n\n if (config.type === \"single-sheet-extraction\") {\n Object.entries(config.columns).forEach(([key, column]) => {\n if (!column.type) {\n throw new Error(`Column ${key} must have a type`);\n }\n\n if ((column as ExcelSourceColumn).column) {\n const colLetter = (column as ExcelSourceColumn).column;\n if (!/^[A-Z]+$/i.test(colLetter)) {\n throw new Error(`Invalid column letter format: ${colLetter}`);\n }\n } else if ((column as ExcelDerivedField).variableName) {\n // Variable name column is valid\n } else {\n throw new Error(`Column ${key} must specify either 'column' or 'variableName'`);\n }\n });\n\n if (config.numberOfRowsToSkip === undefined || config.numberOfRowsToSkip < 0) {\n throw new Error(\"Number of rows to skip must be specified and non-negative\");\n }\n } else if (config.type === \"processor\") {\n if (!config.processor || typeof config.processor !== \"function\") {\n throw new Error(\"Processor function is required for processor type\");\n }\n }\n};\n\n/**\n * Finds all matching configurations for a given filename.\n */\nexport const findAllMatchingConfigs = (\n filename: string,\n configs: ExcelExtractionConfig[],\n): ExcelExtractionConfig[] => {\n const fileInfo = path.parse(filename);\n\n return configs.filter(config =>\n config.fileNameValidator(fileInfo.base) &&\n config.extension === fileInfo.ext.replace(\".\", \"\"),\n );\n};\n\n/**\n * Creates an async generator from Excel data.\n */\nexport async function* createExcelGenerator(\n data: Record<string, string | null>[],\n): AsyncGenerator<Record<string, any>, void, unknown> {\n for (const row of data) {\n yield row;\n }\n}\n","import { WorkBook } from \"xlsx\";\nimport { ReplicationMethod } from \"../../models/replication\";\nimport {\n ExcelExtractionConfig,\n ExcelSingleSheetExtractionConfig,\n ExcelCustomExtractorConfig,\n ExcelFieldSpec,\n} from \"../types\";\n\n/**\n * Builder pattern for creating Excel configurations.\n *\n * Sensible defaults:\n * - fileNameValidator: accepts all files\n * - fileNameVariablesExtractor: extracts nothing\n * - replicationMethod: FULL_TABLE\n */\nexport class ExcelExtractionConfigBuilder {\n private config: Partial<ExcelExtractionConfig> = {\n fileNameValidator: () => true,\n fileNameVariablesExtractor: () => ({}),\n replicationMethod: ReplicationMethod.FULL_TABLE,\n };\n\n static create(): ExcelExtractionConfigBuilder {\n return new ExcelExtractionConfigBuilder();\n }\n\n extension(ext: string): ExcelExtractionConfigBuilder {\n this.config.extension = ext;\n return this;\n }\n\n tableName(name: string | ((fileName: string, workbook?: WorkBook, variables?: { [key: string]: string | undefined }) => string)): ExcelExtractionConfigBuilder {\n this.config.tableName = name;\n return this;\n }\n\n fileValidator(validator: (filename: string) => boolean): ExcelExtractionConfigBuilder {\n this.config.fileNameValidator = validator;\n return this;\n }\n\n variablesExtractor(extractor: (filename: string, workbook?: WorkBook) => { [key: string]: string | undefined }): ExcelExtractionConfigBuilder {\n this.config.fileNameVariablesExtractor = extractor;\n return this;\n }\n\n replicationMethod(method: ReplicationMethod): ExcelExtractionConfigBuilder {\n this.config.replicationMethod = method;\n return this;\n }\n\n columns(cols: { [key: string]: ExcelFieldSpec }): ExcelExtractionConfigBuilder {\n if (this.config.type === \"single-sheet-extraction\") {\n (this.config as ExcelSingleSheetExtractionConfig).columns = cols;\n } else {\n throw new Error(\"Columns can only be set for single-sheet-extraction\");\n }\n return this;\n }\n\n singleSheet(sheetName?: string, skipRows: number = 0): ExcelExtractionConfigBuilder {\n this.config.type = \"single-sheet-extraction\";\n if (sheetName !== undefined) {\n (this.config as ExcelSingleSheetExtractionConfig).sheetName = sheetName;\n }\n (this.config as ExcelSingleSheetExtractionConfig).numberOfRowsToSkip = skipRows;\n return this;\n }\n\n processor(processorFn: (workbook: WorkBook) => Promise<Record<string, string>[]>): ExcelExtractionConfigBuilder {\n this.config.type = \"processor\";\n (this.config as ExcelCustomExtractorConfig).processor = processorFn;\n return this;\n }\n\n build(): ExcelExtractionConfig {\n if (!this.config.type) {\n throw new Error(\"Configuration type must be specified (singleSheet or processor)\");\n }\n\n if (!this.config.extension) {\n throw new Error(\"Extension must be set\");\n }\n\n if (!this.config.tableName) {\n throw new Error(\"Table name must be set\");\n }\n\n if (!this.config.replicationMethod) {\n throw new Error(\"Replication method must be set\");\n }\n\n if (typeof this.config.fileNameValidator !== \"function\") {\n throw new Error(\"fileNameValidator must be a function\");\n }\n\n if (typeof this.config.fileNameVariablesExtractor !== \"function\") {\n throw new Error(\"fileNameVariablesExtractor must be a function\");\n }\n\n if (this.config.type === \"single-sheet-extraction\") {\n const singleSheetConfig = this.config as Partial<ExcelSingleSheetExtractionConfig>;\n if (!singleSheetConfig.columns || Object.keys(singleSheetConfig.columns).length === 0) {\n throw new Error(\"Columns must be set with at least one column for single-sheet-extraction\");\n }\n }\n\n if (this.config.type === \"processor\") {\n const processorConfig = this.config as Partial<ExcelCustomExtractorConfig>;\n if (typeof processorConfig.processor !== \"function\") {\n throw new Error(\"Processor function must be set for processor configs\");\n }\n }\n\n return this.config as ExcelExtractionConfig;\n }\n}\n","import csv from \"csv-parser\";\nimport { createReadStream, ReadStream as FsReadStream } from \"fs\";\nimport { format } from \"util\";\nimport { CsvFileConfig, CsvFieldsArrayConfig, CsvFieldsDictConfig } from \"../types\";\nimport { Readable, Transform } from \"stream\";\nimport * as iconv from \"iconv-lite\";\n\nconst logPrefix = \"[csvReader]\";\n\nconst createStripBomTransform = () => {\n let isFirstChunk = true;\n return new Transform({\n transform(chunk, encoding, callback) {\n if (isFirstChunk) {\n isFirstChunk = false;\n if (chunk.length >= 3 && chunk[0] === 0xEF && chunk[1] === 0xBB && chunk[2] === 0xBF) {\n chunk = chunk.slice(3);\n }\n }\n callback(null, chunk);\n },\n });\n};\n\nconst getStringHexInfo = (str: string) => {\n const bytes = Buffer.from(str, \"utf8\");\n const hex = bytes.toString(\"hex\").match(/.{2}/g)?.join(\" \") || \"\";\n return {\n original: str,\n length: str.length,\n hex: hex,\n trimmed: str.trim(),\n };\n};\n\nconst formatHexComparison = (expected: string, actual: string) => {\n const expectedInfo = getStringHexInfo(expected);\n const actualInfo = getStringHexInfo(actual);\n\n return `\\nExpected: \"${expected}\" (${expectedInfo.length} chars) [${expectedInfo.hex}]\\nActual: \"${actual}\" (${actualInfo.length} chars) [${actualInfo.hex}]`;\n};\n\n/**\n * Async generator that yields parsed rows from a CSV file.\n * Supports custom separators, encoding, BOM stripping, and field transformers.\n */\nexport async function* rowGeneratorFromCsv(\n path: string,\n fileConfig: CsvFileConfig,\n): AsyncGenerator<Record<string, any>> {\n const isGeneratorConfigArray = Array.isArray(fileConfig.fields);\n // Cache config keys once — avoids re-enumerating the same static object on every row\n const configKeys = isGeneratorConfigArray ? [] : Object.keys(fileConfig.fields);\n const csvOptions: Record<string, any> = { separator: fileConfig.separator };\n if (isGeneratorConfigArray) {\n csvOptions.headers = false;\n }\n const csvStream = csv(csvOptions);\n const syncedAt = new Date().toISOString();\n\n let initialReadStream: FsReadStream;\n let finalInputStream: NodeJS.ReadableStream;\n\n const encodingToUse = fileConfig.encoding ? fileConfig.encoding.toLowerCase() : null;\n\n if (encodingToUse && encodingToUse !== \"utf-8\" && encodingToUse !== \"utf8\" && iconv.encodingExists(encodingToUse)) {\n initialReadStream = createReadStream(path);\n finalInputStream = initialReadStream.pipe(iconv.decodeStream(encodingToUse));\n } else {\n initialReadStream = createReadStream(path);\n finalInputStream = initialReadStream.pipe(createStripBomTransform());\n }\n\n finalInputStream.pipe(csvStream);\n\n try {\n for await (const row of Readable.from(csvStream)) {\n if (!isGeneratorConfigArray) {\n const rowData: Record<string, any> = fileConfig.addSyncedAtColumn ? { _wly_synced_at: syncedAt } : {};\n for (const key of configKeys) {\n const keyGenerator = (fileConfig.fields as CsvFieldsDictConfig)[key.trim()];\n if (!keyGenerator) continue;\n const rawValue = keyGenerator.valueTransformer\n ? keyGenerator.valueTransformer(row[key])\n : row[key];\n rowData[keyGenerator.key] = rawValue === \"\" ? null : rawValue;\n }\n yield rowData;\n } else {\n const rowKeys = Object.keys(row);\n const rowData: Record<string, any> = fileConfig.addSyncedAtColumn ? { _wly_synced_at: syncedAt } : {};\n for (let i = 0; i < rowKeys.length; i++) {\n const keyGenerator = (fileConfig.fields as CsvFieldsArrayConfig)[i];\n if (!keyGenerator) continue;\n const rawValue = keyGenerator.valueTransformer\n ? keyGenerator.valueTransformer(row[i])\n : row[i];\n rowData[keyGenerator.key] = rawValue === \"\" ? null : rawValue;\n }\n yield rowData;\n }\n }\n } finally {\n initialReadStream.destroy();\n }\n}\n\n/**\n * Counts data rows in a CSV file by scanning for newline bytes.\n * Subtracts 1 for the header row. Fast: no CSV parsing required.\n */\nexport async function countCsvLines(filePath: string): Promise<number> {\n return new Promise((resolve, reject) => {\n let newlines = 0;\n createReadStream(filePath)\n .on(\"data\", (chunk: Buffer | string) => {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n for (let i = 0; i < buf.length; i++) {\n if (buf[i] === 0x0a) newlines++;\n }\n })\n .on(\"end\", () => resolve(Math.max(0, newlines - 1)))\n .on(\"error\", reject);\n });\n}\n\n/**\n * Validates CSV header row against expected configuration.\n */\nexport const checkCsvHeaderRow = async (\n path: string,\n fileConfig: CsvFileConfig,\n): Promise<void> => {\n return new Promise<void>((resolve, reject) => {\n const colsWithParsingConfig = Object.keys(fileConfig.fields)\n .map(key => key.trim());\n\n console.debug(`${logPrefix} CSV Expected columns:`, colsWithParsingConfig.map(col => {\n const info = getStringHexInfo(col);\n return `\"${info.original}\" [${info.hex}]`;\n }));\n\n const isGeneratorConfigArray = Array.isArray(fileConfig.fields);\n const csvOptions2: Record<string, any> = { separator: fileConfig.separator };\n if (isGeneratorConfigArray) {\n csvOptions2.headers = false;\n }\n const csvStream = csv(csvOptions2);\n\n let initialReadStream: FsReadStream;\n let finalInputStream: NodeJS.ReadableStream;\n const encodingToUse = fileConfig.encoding ? fileConfig.encoding.toLowerCase() : null;\n\n if (\n encodingToUse\n && encodingToUse !== \"utf-8\"\n && encodingToUse !== \"utf8\"\n && iconv.encodingExists(encodingToUse)\n ) {\n initialReadStream = createReadStream(path);\n finalInputStream = initialReadStream.pipe(iconv.decodeStream(encodingToUse));\n } else {\n initialReadStream = createReadStream(path);\n finalInputStream = initialReadStream.pipe(createStripBomTransform());\n }\n\n let isFirstLine = true;\n\n finalInputStream\n .pipe(csvStream)\n .on(\"data\", (row: any) => {\n if (isFirstLine) {\n let headers: string[] = [];\n if (isGeneratorConfigArray) {\n headers = (Object.values(row) as string[]).filter(r => !!r);\n } else {\n headers = (Object.keys(row) as string[]).filter(r => !!r);\n }\n\n console.debug(`${logPrefix} CSV Detected headers:`, headers.map((h, idx) => {\n const info = getStringHexInfo(h);\n return `[${idx}]: \"${info.original}\" [${info.hex}]`;\n }));\n\n if (isGeneratorConfigArray) {\n colsWithParsingConfig.forEach((col, i) => {\n if (col !== headers[i]) {\n const hexComparison = formatHexComparison(col, headers[i] || \"<undefined>\");\n console.error(`${logPrefix} CSV Header Mismatch:${hexComparison}`);\n\n throw new Error(format(\n `CSV header mismatch at position %s: expected '%s' but got '%s' in file %s`,\n i,\n col,\n headers[i] || \"<undefined>\",\n path,\n ));\n }\n });\n } else {\n colsWithParsingConfig.forEach((col) => {\n if (!headers.includes(col)) {\n const colInfo = getStringHexInfo(col);\n console.error(`CSV Missing column: \"${col}\" [${colInfo.hex}]`);\n console.error(`Available headers:`, headers.map(h => `\"${h}\" [${getStringHexInfo(h).hex}]`));\n\n const trimmedMatch = headers.find(h => h.trim() === col.trim());\n if (trimmedMatch) {\n console.error(`Potential trimmed match: \"${trimmedMatch}\" [${getStringHexInfo(trimmedMatch).hex}]`);\n }\n\n throw new Error(format(\n `CSV missing expected column '%s' in file: %s`,\n col,\n path,\n ));\n }\n });\n }\n isFirstLine = false;\n } else {\n initialReadStream.destroy();\n }\n })\n .on(\"error\", (error: Error) => {\n reject(new Error(`Error processing CSV file: ${error.message}`));\n });\n initialReadStream.on(\"close\", () => {\n resolve();\n });\n });\n};\n","import { createObjectCsvWriter } from \"csv-writer\";\nimport { format } from \"util\";\n\nconst logPrefix = \"[csvWriter]\";\n\n/**\n * Writes an array of objects directly to a CSV file.\n */\nexport const writeDataToCsv = async (\n fileName: string,\n data: any[],\n): Promise<void> => {\n try {\n const firstRow = data[0];\n if (!firstRow) {\n console.log(`${logPrefix} No data to write to CSV file=%s`, fileName);\n return;\n }\n const csvWriter = createObjectCsvWriter({\n path: fileName,\n header: Object.keys(firstRow)\n .map(col => {\n return { id: col, title: col };\n }),\n });\n await csvWriter.writeRecords(data);\n console.log(`${logPrefix} CSV file=%s written successfully`, fileName);\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(`error while writing csv file=%s, err: %s`, fileName, err.message));\n }\n throw err;\n }\n};\n\n/**\n * Writes data from an async generator to CSV with batch writing (10k row batches).\n */\nexport const writeGeneratorToCSV = async (\n generator: AsyncGenerator,\n outputFileName: string,\n): Promise<number> => {\n try {\n let rowCount = 0;\n\n const firstDataRow = (await generator.next()).value;\n if (!firstDataRow) {\n console.log(`${logPrefix} [%s] first data row of csv empty, skipping`, outputFileName);\n return 0;\n }\n\n console.log(`${logPrefix} [%s] inferring headers from first data row`, outputFileName);\n const headers = Object.keys(firstDataRow)\n .map(col => {\n return {\n id: col,\n title: col,\n };\n });\n\n const csvWriter = createObjectCsvWriter({\n path: outputFileName,\n header: headers,\n alwaysQuote: true,\n });\n\n console.log(`${logPrefix} [%s] writing csv`, outputFileName);\n let batch = [firstDataRow];\n for await (const data of generator) {\n batch.push(data);\n rowCount++;\n if (batch.length > 10_000) {\n try {\n await csvWriter.writeRecords(batch as any[]);\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(\n format(\n `error while writing batch to csv batch (first 3 records)=%j, err: %s`,\n batch.slice(0, 3),\n err.message,\n ),\n );\n }\n throw err;\n }\n batch = [];\n }\n }\n await csvWriter.writeRecords(batch as any[]);\n console.log(`${logPrefix} [%s] csv written successfully with %d rows`, outputFileName, rowCount);\n return rowCount;\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(`error while writing csv file=%s, err: %s`, outputFileName, err.message));\n }\n throw err;\n }\n};\n","import XLSX from \"xlsx\";\nimport { Stream } from \"../models/tap/stream\";\nimport { Schema } from \"../models/schema\";\nimport { ReplicationMethod } from \"../models/replication\";\nimport { InputTapState } from \"../models/state\";\nimport { ITarget } from \"../models/target/target\";\nimport {\n FileStreamConfig,\n FileStreamEntry,\n FileFormat,\n ExcelExtractionConfig,\n CsvFileConfig,\n} from \"./types\";\nimport { extractExcelRows } from \"./excel/reader\";\nimport { rowGeneratorFromCsv, countCsvLines } from \"./csv/reader\";\nimport { excelFieldsToJsonSchema, csvFieldsToJsonSchema, extractPrimaryKeysFromExcelFields, extractPrimaryKeysFromCsvConfig } from \"./schema-utils\";\n\n/**\n * FileStream bridges file processing (Excel/CSV) into the connector SDK pipeline.\n *\n * It extends Stream so it integrates with the standard Tap -> Stream -> Target flow.\n * Each FileStream reads one file with one config and yields records.\n */\nexport class FileStream extends Stream<Record<string, any>, FileStreamConfig> {\n private localFilePaths: string[];\n\n constructor(\n config: FileStreamConfig,\n localFilePath: string | string[],\n tapState: InputTapState,\n target: ITarget,\n ) {\n super(config, tapState, target);\n this.localFilePaths = Array.isArray(localFilePath) ? localFilePath : [localFilePath];\n\n // Set stream properties from config\n this.streamId = config.streamId;\n this.primaryKey = config.primaryKeys;\n this.replicationMethod = config.replicationMethod;\n }\n\n /**\n * Build JSON Schema from the file config's field definitions.\n */\n async getSchema(): Promise<Schema | undefined> {\n if (this.config.format === FileFormat.EXCEL) {\n const excelConfig = this.config.excel;\n if (excelConfig.type === \"single-sheet-extraction\") {\n const jsonSchema = excelFieldsToJsonSchema(excelConfig.columns);\n return { jsonSchema };\n }\n // For processor-type configs, schema must be inferred from first row at runtime.\n return undefined;\n }\n\n if (this.config.format === FileFormat.CSV) {\n const jsonSchema = csvFieldsToJsonSchema(this.config.csv.fields);\n return { jsonSchema };\n }\n\n throw new Error(`FileStream: No valid format config for stream ${this.streamId}`);\n }\n\n /**\n * Yield records from all file(s).\n * When multiple file paths are provided, records are yielded sequentially from each file.\n * Pre-counts total rows across all files to enable percentage progress logging.\n */\n async *_getRecords(): AsyncIterable<Record<string, any>> {\n // Pre-count total rows across all files before yielding any record\n let total = 0;\n for (const filePath of this.localFilePaths) {\n if (this.config.format === FileFormat.EXCEL) {\n const data = await extractExcelRows(filePath, this.config.excel);\n total += data.length;\n } else if (this.config.format === FileFormat.CSV) {\n total += await countCsvLines(filePath);\n }\n }\n this.totalRows = total;\n\n // Now yield records\n for (const filePath of this.localFilePaths) {\n if (this.config.format === FileFormat.EXCEL) {\n const data = await extractExcelRows(filePath, this.config.excel);\n for (const row of data) {\n yield row;\n }\n } else if (this.config.format === FileFormat.CSV) {\n yield* rowGeneratorFromCsv(filePath, this.config.csv);\n } else {\n throw new Error(`FileStream: Unsupported format for stream ${this.streamId}`);\n }\n }\n }\n}\n\n/**\n * Create a FileStreamConfig from an ExcelExtractionConfig.\n * Handles both single-sheet-extraction and processor config types.\n *\n * For single-sheet configs, primary keys are extracted from column definitions.\n * For processor configs, primary keys default to an empty array.\n *\n * @param excelConfig - The Excel extraction config (single-sheet or processor)\n * @param fileName - The base filename (used for variable extraction and table name resolution)\n * @param localFilePath - Optional local file path; required for processor configs with dynamic table names\n */\nexport function createExcelStreamConfig(\n excelConfig: ExcelExtractionConfig,\n fileName: string,\n localFilePath?: string,\n): FileStreamConfig {\n if (excelConfig.type === \"single-sheet-extraction\") {\n const primaryKeys = extractPrimaryKeysFromExcelFields(excelConfig.columns);\n\n let tableName: string;\n if (typeof excelConfig.tableName === \"function\") {\n const variables = excelConfig.fileNameVariablesExtractor(fileName);\n tableName = excelConfig.tableName(fileName, undefined, variables);\n } else {\n tableName = excelConfig.tableName;\n }\n\n return {\n format: FileFormat.EXCEL,\n streamId: tableName,\n replicationMethod: excelConfig.replicationMethod,\n primaryKeys,\n excel: excelConfig,\n };\n }\n\n // Processor config\n let tableName: string;\n if (typeof excelConfig.tableName === \"function\") {\n if (!localFilePath) {\n throw new Error(\"localFilePath is required for processor configs with dynamic table names\");\n }\n const workbook = XLSX.readFile(localFilePath, { dense: true });\n const variables = excelConfig.fileNameVariablesExtractor(fileName, workbook);\n tableName = excelConfig.tableName(fileName, workbook, variables);\n } else {\n tableName = excelConfig.tableName;\n }\n\n return {\n format: FileFormat.EXCEL,\n streamId: tableName,\n replicationMethod: excelConfig.replicationMethod,\n primaryKeys: [],\n excel: excelConfig,\n };\n}\n\n/**\n * Create a FileStreamConfig from a CsvFileConfig.\n *\n * By default, uses FULL_TABLE replication and extracts all field keys as composite primary keys.\n * Override via the options parameter.\n *\n * @param streamId - The stream/table name\n * @param csvConfig - The CSV file configuration\n * @param options - Optional overrides for replicationMethod and primaryKeys\n */\nexport function createCsvStreamConfig(\n streamId: string,\n csvConfig: CsvFileConfig,\n options?: {\n replicationMethod?: ReplicationMethod;\n primaryKeys?: string[];\n },\n): FileStreamConfig {\n return {\n format: FileFormat.CSV,\n streamId,\n replicationMethod: options?.replicationMethod ?? ReplicationMethod.FULL_TABLE,\n primaryKeys: options?.primaryKeys ?? extractPrimaryKeysFromCsvConfig(csvConfig.fields),\n csv: csvConfig,\n };\n}\n\n/**\n * Process an array of FileStreamEntry sequentially, then signal completion to the target.\n *\n * This is the recommended pattern for SFTP and similar multi-file ingestion flows\n * where FileTap isn't needed.\n *\n * @param entries - Array of { config, filePath } pairs\n * @param tapState - The tap state (typically `{ bookmarks: {} }`)\n * @param target - The target (e.g. BigQueryTarget)\n */\nexport async function processFileStreams(\n entries: FileStreamEntry[],\n tapState: InputTapState,\n target: ITarget,\n): Promise<void> {\n for (const entry of entries) {\n const stream = new FileStream(entry.config, entry.filePath, tapState, target);\n await stream.sync();\n }\n await target.complete();\n}\n","import { ReplicationMethod } from \"../../models/replication\";\nimport {\n CsvFileConfig,\n CsvFieldsConfig,\n CsvFieldsDictConfig,\n CsvFieldsArrayConfig,\n FieldType,\n FileStreamConfig,\n} from \"../types\";\nimport { createCsvStreamConfig } from \"../file-stream\";\n\n/**\n * Builder pattern for creating CSV configurations.\n *\n * Usage:\n * ```ts\n * const config = CsvExtractionConfigBuilder.create()\n * .separator(\";\")\n * .encoding(\"latin1\")\n * .addSyncedAtColumn()\n * .fieldsFromDict({\n * \"Product ID\": { key: \"product_id\", type: \"STRING\" },\n * \"Product Name\": { key: \"product_name\", type: \"STRING\" },\n * \"Price\": { key: \"price\", type: \"FLOAT\" },\n * })\n * .build();\n * ```\n */\nexport class CsvExtractionConfigBuilder {\n private _separator: string = \",\";\n private _encoding?: string;\n private _addSyncedAtColumn?: boolean;\n private _fields?: CsvFieldsConfig;\n private _fieldsMode?: \"dict\" | \"array\";\n private _replicationMethod?: ReplicationMethod;\n private _primaryKeys?: string[];\n\n static create(): CsvExtractionConfigBuilder {\n return new CsvExtractionConfigBuilder();\n }\n\n separator(sep: string): CsvExtractionConfigBuilder {\n this._separator = sep;\n return this;\n }\n\n encoding(enc: string): CsvExtractionConfigBuilder {\n this._encoding = enc;\n return this;\n }\n\n addSyncedAtColumn(enabled: boolean = true): CsvExtractionConfigBuilder {\n this._addSyncedAtColumn = enabled;\n return this;\n }\n\n fieldsFromDict(mapping: {\n [header: string]: {\n key: string;\n valueTransformer?: (val: any) => string;\n type: FieldType;\n };\n }): CsvExtractionConfigBuilder {\n if (this._fieldsMode === \"array\") {\n throw new Error(\"Cannot use fieldsFromDict after fieldsFromArray\");\n }\n this._fieldsMode = \"dict\";\n this._fields = mapping as CsvFieldsDictConfig;\n return this;\n }\n\n fieldsFromArray(fields: Array<{\n key: string;\n valueTransformer?: (val: any) => string;\n type: FieldType;\n }>): CsvExtractionConfigBuilder {\n if (this._fieldsMode === \"dict\") {\n throw new Error(\"Cannot use fieldsFromArray after fieldsFromDict\");\n }\n this._fieldsMode = \"array\";\n this._fields = fields as CsvFieldsArrayConfig;\n return this;\n }\n\n replicationMethod(method: ReplicationMethod): CsvExtractionConfigBuilder {\n this._replicationMethod = method;\n return this;\n }\n\n primaryKeys(keys: string[]): CsvExtractionConfigBuilder {\n this._primaryKeys = keys;\n return this;\n }\n\n build(): CsvFileConfig {\n if (!this._fields) {\n throw new Error(\"Fields must be configured (use fieldsFromDict or fieldsFromArray)\");\n }\n\n if (Array.isArray(this._fields) && this._fields.length === 0) {\n throw new Error(\"Fields must not be empty\");\n }\n\n if (!Array.isArray(this._fields) && Object.keys(this._fields).length === 0) {\n throw new Error(\"Fields must not be empty\");\n }\n\n const config: CsvFileConfig = {\n separator: this._separator,\n fields: this._fields,\n };\n\n if (this._encoding !== undefined) {\n config.encoding = this._encoding;\n }\n\n if (this._addSyncedAtColumn !== undefined) {\n config.addSyncedAtColumn = this._addSyncedAtColumn;\n }\n\n return config;\n }\n\n buildStreamConfig(streamId: string): FileStreamConfig {\n const csvConfig = this.build();\n\n const options: { replicationMethod?: ReplicationMethod; primaryKeys?: string[] } = {};\n if (this._replicationMethod !== undefined) {\n options.replicationMethod = this._replicationMethod;\n }\n if (this._primaryKeys !== undefined) {\n options.primaryKeys = this._primaryKeys;\n }\n\n return createCsvStreamConfig(streamId, csvConfig, options);\n }\n}\n","import { Tap } from \"../models/tap/tap\";\nimport { ITarget } from \"../models/target/target\";\nimport { StateProvider } from \"../models/state-provider/types\";\nimport { FileStreamConfig, FileStreamEntry } from \"./types\";\nimport { FileStream } from \"./file-stream\";\n\nexport interface FileTapConfig {\n [key: string]: any;\n}\n\n/**\n * FileTap orchestrates multiple FileStreams.\n *\n * It extends Tap so it integrates with the standard Tap -> Stream -> Target flow.\n * Provide file stream entries (config + file path pairs), and it creates a FileStream per entry.\n *\n * For simple sequential file processing without the Tap lifecycle, use processFileStreams() instead.\n */\nexport class FileTap extends Tap<FileTapConfig> {\n private entries: FileStreamEntry[];\n\n constructor(\n target: ITarget,\n config: FileTapConfig,\n stateProvider: StateProvider,\n entries: FileStreamEntry[],\n ) {\n super(target, config, stateProvider);\n this.entries = entries;\n }\n\n /**\n * Convenience constructor for the common case where all configs share the same file path.\n */\n static fromConfigs(\n target: ITarget,\n config: FileTapConfig,\n stateProvider: StateProvider,\n fileConfigs: FileStreamConfig[],\n sharedFilePath: string,\n ): FileTap {\n const entries = fileConfigs.map(c => ({\n config: c,\n filePath: sharedFilePath,\n }));\n return new FileTap(target, config, stateProvider, entries);\n }\n\n async init(): Promise<void> {\n for (const entry of this.entries) {\n const stream = new FileStream(\n entry.config,\n entry.filePath,\n this.tapState,\n this.target,\n );\n\n this.streams.push(stream);\n }\n }\n}\n","/**\n * Variable extraction utilities for common filename patterns.\n */\nexport class VariableExtractors {\n /**\n * Returns the filename as a variable.\n */\n static filename(): (filename: string) => { [key: string]: string | undefined } {\n return (filename: string) => ({\n fileName: filename,\n });\n }\n\n /**\n * Extracts named capture groups from a regex pattern.\n */\n static regex(pattern: RegExp): (filename: string) => { [key: string]: string | undefined } {\n return (filename: string) => {\n const match = filename.match(pattern);\n return match?.groups ?? {};\n };\n }\n\n /**\n * Combines multiple extraction functions.\n */\n static combine(\n ...extractors: ((filename: string) => { [key: string]: string | undefined })[]\n ): (filename: string) => { [key: string]: string | undefined } {\n return (filename: string) => {\n return extractors.reduce((acc, extractor) => {\n return { ...acc, ...extractor(filename) };\n }, {});\n };\n }\n}\n\n/**\n * File pattern utilities for common filename validation patterns.\n */\nexport class FilePatterns {\n /**\n * Creates a validator for files starting with a specific prefix (case-insensitive).\n */\n static startsWith(prefix: string): (filename: string) => boolean {\n return (filename: string) => filename.toLowerCase().startsWith(prefix.toLowerCase());\n }\n\n /**\n * Creates a validator for files matching a regex pattern.\n */\n static regex(pattern: RegExp): (filename: string) => boolean {\n return (filename: string) => pattern.test(filename);\n }\n\n /**\n * Combines multiple validators with AND logic.\n */\n static and(...validators: ((filename: string) => boolean)[]): (filename: string) => boolean {\n return (filename: string) => validators.every(validator => validator(filename));\n }\n\n /**\n * Combines multiple validators with OR logic.\n */\n static or(...validators: ((filename: string) => boolean)[]): (filename: string) => boolean {\n return (filename: string) => validators.some(validator => validator(filename));\n }\n}\n","import Client from \"ssh2-sftp-client\";\n\nexport { default as SftpClient } from \"ssh2-sftp-client\";\nexport type { ConnectOptions as SftpConnectOptions } from \"ssh2-sftp-client\";\n\n/**\n * Pre-instantiated SFTP client singleton.\n * @deprecated Prefer creating your own SftpClient instance for better lifecycle control.\n */\nexport const SftpService = new Client();\n","import { Storage, File } from \"@google-cloud/storage\";\nimport { format } from \"util\";\nimport * as pathModule from \"path\";\nimport { existsSync, mkdirSync, unlinkSync } from \"fs\";\nimport { randomUUID } from \"crypto\";\nimport { logger } from \"../sdk/service/logger\";\n\nconst logPrefix = \"[CloudStorageService]\";\nconst tmpDir = \"tmp\";\n\nexport interface CloudStorageServiceOptions {\n processedSuffix?: string;\n supportedExtensions?: string[];\n}\n\n/**\n * Service for interacting with Google Cloud Storage.\n * Supports file download, upload, listing, and marker-file-based processing tracking.\n */\nexport class CloudStorageService {\n private storage: Storage;\n private bucket: ReturnType<Storage[\"bucket\"]>;\n private processedSuffix: string;\n private supportedExtensions: string[];\n private path: string | undefined;\n\n constructor(\n bucketName: string,\n path?: string,\n opts?: CloudStorageServiceOptions,\n ) {\n this.storage = new Storage({ retryOptions: { autoRetry: true, maxRetries: 20 } });\n this.bucket = this.storage.bucket(bucketName);\n this.path = path;\n this.processedSuffix = opts?.processedSuffix ?? \".processed\";\n this.supportedExtensions = opts?.supportedExtensions ?? [];\n }\n\n /**\n * Lists all files in the bucket with an optional prefix.\n */\n async listFiles(prefix?: string): Promise<string[]> {\n const effectivePrefix = prefix || this.path;\n const [files] = await this.bucket.getFiles(\n effectivePrefix ? { prefix: effectivePrefix } : undefined,\n );\n return files.map(f => f.name);\n }\n\n /**\n * Returns files that haven't been marked as processed.\n * Filters by supported extensions if configured.\n */\n async getUnprocessedFiles(): Promise<string[]> {\n const allFiles = await this.listFiles();\n\n const markerFiles = new Set(\n allFiles\n .filter(f => f.endsWith(this.processedSuffix))\n .map(f => f.replace(this.processedSuffix, \"\")),\n );\n\n return allFiles.filter(f => {\n if (f.endsWith(this.processedSuffix)) return false;\n if (f.endsWith(\"/\")) return false;\n\n if (this.supportedExtensions.length > 0) {\n const ext = pathModule.extname(f).toLowerCase();\n if (!this.supportedExtensions.includes(ext)) return false;\n }\n\n return !markerFiles.has(f);\n });\n }\n\n /**\n * Creates a marker file to indicate a file has been processed.\n */\n async createMarkerFile(fileName: string): Promise<void> {\n const markerFileName = `${fileName}${this.processedSuffix}`;\n try {\n const file = this.bucket.file(markerFileName);\n await file.save(format(\"Marked file %s as processed\", fileName));\n logger.info(`${logPrefix} Marker file ${markerFileName} created successfully.`);\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(`error while writing marker file=%s, err:%s`, markerFileName, err.message));\n }\n throw err;\n }\n }\n\n /**\n * Downloads a file from GCS to a local tmp directory.\n * Returns the local path of the downloaded file.\n */\n async downloadFile(filePath: string, fileName: string): Promise<string> {\n const file = this.bucket.file(filePath);\n const tmpDirPath = pathModule.join(process.cwd(), tmpDir);\n if (!existsSync(tmpDirPath)) {\n mkdirSync(tmpDirPath);\n }\n const destFilename = pathModule.join(process.cwd(), tmpDir, fileName);\n try {\n if (existsSync(destFilename)) {\n unlinkSync(destFilename);\n }\n await file.download({ destination: destFilename });\n logger.info(`${logPrefix} Downloaded ${fileName} to ${destFilename}`);\n return destFilename;\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(\n `can't download file=%s from bucket, err:%s`,\n fileName,\n err.message,\n ));\n }\n throw err;\n }\n }\n\n /**\n * Uploads a local file to GCS.\n */\n async uploadFile(localPath: string, destPath: string): Promise<File> {\n try {\n logger.info(`${logPrefix} preparing to upload '%s' to '%s'`, localPath, destPath);\n const [file] = await this.bucket.upload(localPath, { destination: destPath });\n logger.info(`${logPrefix} file %s has been successfully uploaded into %s`, localPath, destPath);\n return file;\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(`error while uploading file file=%s into path=%s, err:%s`, localPath, destPath, err.message));\n }\n throw err;\n }\n }\n\n /**\n * Reads a GCS object and returns its contents as a UTF-8 string.\n */\n async readObjectAsString(objectPath: string): Promise<string> {\n try {\n await this.bucket.get({ autoCreate: false });\n const fileRef = this.bucket.file(objectPath);\n const [exists] = await fileRef.exists();\n if (!exists) {\n throw new Error(`GCS object not found: gs://${this.bucket.name}/${objectPath}`);\n }\n const [contents] = await fileRef.download();\n return contents.toString('utf8');\n } catch (err: any) {\n throw new Error(format(`error reading GCS object gs://${this.bucket.name}/${objectPath}, err: %s`, err?.message));\n }\n }\n\n /**\n * Writes a string to a GCS object with JSON content type.\n */\n async writeStringObject(objectPath: string, contents: string): Promise<void> {\n try {\n await this.bucket.get({ autoCreate: false });\n const fileRef = this.bucket.file(objectPath);\n await fileRef.save(contents, { contentType: 'application/json' });\n logger.info(`Uploaded object to gs://${this.bucket.name}/${objectPath}`);\n } catch (err: any) {\n throw new Error(format(`error writing GCS object gs://${this.bucket.name}/${objectPath}, err: %s`, err?.message));\n }\n }\n\n /**\n * Uploads a local file to the bucket with a unique name based on prefix, streamId, and UUID.\n * Files are stored under `<prefix>/<run-id>/` when the RUN_ID env var is set,\n * or `<prefix>/default/` otherwise.\n * Returns the GCS File reference.\n */\n async uploadFileWithUniqueName(filePath: string, prefix: string, streamId: string): Promise<File> {\n try {\n await this.bucket.get({ autoCreate: false });\n\n const runFolder = process.env.RUN_ID ?? \"default\";\n const destinationFileName = `${prefix}/${runFolder}/${streamId}-${randomUUID()}.jsonnl`;\n\n await this.bucket.upload(filePath, {\n destination: destinationFileName\n });\n\n logger.info(`Uploaded ${filePath} into ${this.bucket.name}/${destinationFileName} GCS File`);\n\n return this.bucket.file(destinationFileName);\n } catch (err: any) {\n logger.error(`Issue when uploading file into GCS bucket for stream: ${streamId}\n\n Error: ${err.message}\n Stack: ${err.stack}\n Code: ${err.code}\n `);\n\n throw err;\n }\n }\n}\n","import * as fse from \"fs-extra\";\nimport decompress from \"decompress\";\n\n/**\n * Extract a ZIP (or other archive) file to a target directory.\n * Uses the `decompress` library which supports zip, tar, gz, bz2, etc.\n *\n * @param zipFilePath - Path to the archive file\n * @param extractedPath - Directory to extract into (created if it doesn't exist)\n * @returns The output directory path\n */\nexport const unzip = async (zipFilePath: string, extractedPath: string): Promise<string> => {\n await fse.ensureDir(extractedPath);\n await decompress(zipFilePath, extractedPath);\n return extractedPath;\n};\n","// https://cloud.google.com/bigquery/docs/schemas#column_names\nexport const safeColumnName = (key: string): string => {\n\n let returnString = key;\n // Remove unsupported prefix\n const shouldNotStartWith = [\"_TABLE_\", \"_FILE_\", \"_PARTITION\"]\n shouldNotStartWith.forEach(snm => {\n if (returnString.startsWith(snm)) {\n returnString = returnString.replace(snm, \"\")\n }\n })\n\n // remove begining numeric characters\n returnString = returnString.replace(/^[-\\d\\s]*/g, \"\")\n\n // Go in lowercase\n returnString = returnString.toLowerCase()\n\n // Remove ticks\n returnString = returnString.replace('`', '')\n\n // Remove accents in a nice way\n returnString = returnString.normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\")\n\n // Trim to first 300 characters\n if (returnString.length > 300) {\n returnString = returnString.substr(0, 300);\n }\n\n // Remove non alphabetic characters\n const pattern = /[^a-zA-Z0-9_]/gm\n return returnString.replace(pattern, '_');\n}\n\n// https://cloud.google.com/bigquery/docs/tables#table_naming\nexport const safeTableName = (key: string) => {\n\n let returnString = key;\n\n // Go in lowercase\n returnString = returnString.toLowerCase()\n\n // Remove ticks\n returnString = returnString.replace('`', '')\n\n // Remove accents in a nice way\n returnString = returnString.normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\")\n\n // Trim to first 300 characters\n if (returnString.length > 1024) {\n returnString = returnString.substr(0, 1024);\n }\n\n // Remove non alphabetic characters\n const pattern = /[^a-zA-Z0-9_]/gm\n return returnString.replace(pattern, '_');\n}","import Decimal from \"decimal.js\";\nimport dayjs from \"dayjs\";\nimport { defaultDateTimeFormat } from \"../../../sdk/constants/date\";\nimport { FlattenedSchema } from \"../../../sdk/models/target/models\";\nimport { logger } from \"../../../sdk/service/logger\";\n\n//TODO: Check that the date-time are in the BigQuery limits\n// Eg. From 0001-01-01 00:00:00 to 9999-12-31 23:59:59.999999\nexport const validateDateRange = (record: any, schema: FlattenedSchema): any => {\n\n Object.keys(schema).forEach(key => {\n const { format } = schema[key];\n\n if (format === \"date-time\") {\n if (record[key]) {\n const formattedDate = dayjs(record[key]).format(defaultDateTimeFormat);\n // sometimes we have dayjs that cannot convert a value that seemed appropriate previously so we need to skip it\n // ie: in the tap we had as an output from dayjs \"20222-07-01T00:00:00.000000+00:00\"\n // and reading it back in the target gives \"Invalid date\"\n\n // we also need to check it the date is greater that the limit in order to avoid chaos\n const isNotTooMuchInTheFuture = dayjs(record[key]).isBefore(dayjs(\"9999-12-31 23:59:59.999999\"));\n const isNotTooMuchInThePast = dayjs(record[key]).isAfter(dayjs(\"0001-01-01 00:00:00\"))\n if (formattedDate !== \"Invalid date\" && isNotTooMuchInTheFuture && isNotTooMuchInThePast) {\n record[key] = formattedDate\n } else {\n record[key] = undefined;\n logger.info(\"Skipping date for key %s for being invalid\", key)\n }\n }\n }\n\n })\n\n return record;\n}\n\nexport const maxBQNumericValue = new Decimal(\"9.9999999999999999999999999999999999999E+28\");\n\nexport const convertNumberIntoDecimal = (record: any, schema: FlattenedSchema) => {\n Object.keys(record).forEach(key => {\n\n if (schema[key]) {\n const { type, items } = schema[key];\n const types = type instanceof Array ? type : [type];\n\n if (types.includes(\"number\")) {\n if (typeof record[key] === 'number' || record[key] instanceof Decimal) {\n const decimal = new Decimal(record[key]).toDecimalPlaces(9);\n if (decimal.greaterThanOrEqualTo(maxBQNumericValue)) {\n record[key] = null;\n } else {\n record[key] = decimal;\n }\n } else {\n record[key] = null;\n }\n } else if(types.includes(\"array\") && items?.type.includes(\"number\")) {\n if (Array.isArray(record[key])) {\n const rawArr = record[key];\n const newArr = rawArr.map((item: any) => {\n if(typeof item === 'number' || item instanceof Decimal) {\n const parsed = new Decimal(item).toDecimalPlaces(9);\n if (parsed.greaterThanOrEqualTo(maxBQNumericValue)) {\n return undefined\n } else {\n return parsed;\n }\n } else {\n return undefined;\n }\n }).filter((item: any) => !!item);\n record[key] = newArr;\n } else {\n record[key] = null;\n }\n }\n }\n })\n\n return record;\n}","import { StreamId } from \"../../../sdk/models/metadata\";\nimport { logger } from \"../../../sdk/service/logger\";\nimport { Dataset, TableMetadata, TableField, Table, BigQuery, JobLoadMetadata } from \"@google-cloud/bigquery\";\nimport dayjs from \"dayjs\";\nimport { BqClientHolder } from \"./bigquery\";\nimport { File } from '@google-cloud/storage';\nimport { CloudStorageService } from \"../../../services/cloud-storage\";\nimport { safeColumnName } from \"../helpers\";\nimport chunk from \"lodash/chunk.js\";\nimport { haltAndCatchFire } from \"../../../sdk/service/error\";\nimport { StreamWarehouseSyncService } from \"../../../sdk/models/target/dbSync\";\nimport { InternalTableField, JSONSchemaFieldDefinition, WarehouseTableField } from \"../../../sdk/models/target/models\";\nimport { BigQueryConfig } from \"../models/config\";\nimport { RenameColumnStore } from \"../../../sdk/models/target/renameColumnStore\";\nimport { Semaphore } from \"async-mutex\";\nimport { gracefulExit } from \"../../../sdk/service/exit\";\n\nconst semaphore = new Semaphore(1);\n\nexport class BigQueryDBSync extends StreamWarehouseSyncService {\n\n config: BigQueryConfig;\n bqClient: BigQuery;\n bqDataset: Dataset;\n bqTable: Table;\n bqStagingTable: Table;\n tableName: string;\n stagingTableName: string;\n sqlTableId: string;\n sqlStagingTableId: string;\n\n constructor(\n config: BigQueryConfig,\n streamId: StreamId,\n database: string,\n schema: string,\n table: string,\n renameColumnStore: RenameColumnStore,\n ) {\n super(\n streamId,\n database,\n schema,\n table,\n renameColumnStore\n )\n this.config = config;\n this.bqClient = BqClientHolder.client(config);\n this.bqDataset = this.bqClient.dataset(schema, { location: config.location || \"EU\" });\n this.bqTable = this.bqDataset.table(table, { location: config.location || \"EU\" });\n this.tableName = table;\n this.stagingTableName = `${table}_temp`;\n this.bqStagingTable = this.bqDataset.table(this.stagingTableName, { location: config.location || \"EU\" });\n this.sqlTableId = `${schema}.${table}`;\n this.sqlStagingTableId = `${this.sqlTableId}_temp`;\n }\n\n // Implementation of abstract classes\n\n getSerializedRecord = (record: any): string => {\n return JSON.stringify(record) + `\\n`;\n }\n\n safeColumnName = safeColumnName\n\n getWarehouseTypeFromJSONSchema = (\n definition: JSONSchemaFieldDefinition\n ): string => {\n\n const type = definition.type;\n const format = definition.format;\n\n // Converting `string | string[]` into `string[]` is easier for later processing\n let typeArr: string[];\n\n if (type instanceof Array) {\n typeArr = type;\n } else {\n typeArr = [type];\n }\n\n if (format) {\n switch (format) {\n case \"date-time\":\n return \"TIMESTAMP\";\n case \"json\":\n return \"STRING\";\n default:\n throw new Error(`StreamId: ${this.streamId} - Unsupported format: ${format}`)\n }\n }\n else if (typeArr.includes('number')) {\n return \"NUMERIC\"\n }\n else if (typeArr.includes('integer') && type.includes('string')) {\n return \"NUMERIC\"\n }\n else if (typeArr.includes('integer')) {\n return \"INTEGER\"\n }\n else if (typeArr.includes('boolean')) {\n return \"BOOLEAN\"\n }\n else if (typeArr.includes('string')) {\n return \"STRING\"\n }\n else if (typeArr.includes('array')) {\n const items = definition.items;\n if (items) {\n return this.getWarehouseTypeFromJSONSchema(items)\n }\n throw new Error(`StreamId: ${this.streamId} - Unsupported array schema field definition: ${JSON.stringify(definition)}`)\n }\n else {\n throw new Error(`StreamId: ${this.streamId} - Unsupported schema field definition: ${JSON.stringify(definition)}`)\n }\n };\n\n getMergeQueries = (): string[] => {\n\n const primaryKeyCondition = this.primaryKeys\n .map(pk => {\n return `\\`sourced\\`.\\`${pk}\\` = \\`destination\\`.\\`${pk}\\``\n })\n .join(` AND `);\n\n const primaryKeys = this.primaryKeys.map(pk => `\\`${pk}\\``).join(` ,`)\n\n const columnUnsafeToSafeMapping = this.renamedColumnStore.getUnsafeToSafeColumnMapping(this.streamId);\n\n const columns = Object.keys(columnUnsafeToSafeMapping)\n .map(column => {\n return {\n isUnsafe: true,\n colName: column\n }\n });\n const columnsChunks = chunk(columns, 300)\n // We need to make sure that the PKs keys are in all chunks so that they are written in the first chunk in the destination table\n // Otherwise we write \"null\" in the PK cols in a first batch and then we can't the proper lines in subsequent batchs\n .map(chunk => {\n this.primaryKeys.forEach(pk => {\n if (!chunk.map(c => columnUnsafeToSafeMapping[c.colName]).includes(pk)) {\n chunk.push({\n isUnsafe: false,\n colName: pk\n });\n }\n })\n return chunk;\n });\n\n return columnsChunks.map(chunk => {\n\n const setValues = chunk\n .map(column => {\n if (column.isUnsafe) {\n return `\\`destination\\`.\\`${columnUnsafeToSafeMapping[column.colName]}\\` = \\`sourced\\`.\\`${columnUnsafeToSafeMapping[column.colName]}\\``\n } else {\n return `\\`destination\\`.\\`${column.colName}\\` = \\`sourced\\`.\\`${column.colName}\\``\n }\n }).join(`, `);\n\n const renamedCols = chunk\n .map(column => {\n if (column.isUnsafe) {\n return `\\`${columnUnsafeToSafeMapping[column.colName]}\\``\n } else {\n return `\\`${column.colName}\\``\n }\n }).join(`, `);\n\n const query = `\n MERGE ${this.sqlTableId} destination\n USING (\n WITH all_staging_rows AS (\n SELECT *\n FROM ${this.sqlStagingTableId}\n ),\n numbered_rows AS (\n SELECT *, \n ROW_NUMBER() OVER (PARTITION BY ${primaryKeys}) as _wly_row_nb,\n COUNT(1) OVER (PARTITION BY ${primaryKeys}) AS _wly_partition_size,\n FROM all_staging_rows\n ),\n staging_deduped AS (\n SELECT * EXCEPT(_wly_partition_size, _wly_row_nb)\n FROM numbered_rows \n WHERE _wly_partition_size = _wly_row_nb\n )\n SELECT *\n FROM staging_deduped\n ) AS sourced\n ON ${primaryKeyCondition}\n WHEN MATCHED THEN\n UPDATE SET ${setValues}\n WHEN NOT MATCHED THEN\n INSERT (${renamedCols}) VALUES (${renamedCols});\n `\n return query;\n });\n }\n\n getReplaceQueries = (): string[] => {\n return [\n `TRUNCATE TABLE ${this.sqlTableId};`,\n ...this.getMergeQueries()\n ];\n }\n\n getAppendQueries = (): string[] => {\n const columnUnsafeToSafeMapping = this.renamedColumnStore.getUnsafeToSafeColumnMapping(this.streamId);\n const columns = Object.keys(columnUnsafeToSafeMapping)\n .map(unsafeKey => `\\`${columnUnsafeToSafeMapping[unsafeKey]}\\``)\n .join(`, `);\n\n return [\n `INSERT INTO ${this.sqlTableId} (${columns}) SELECT ${columns} FROM ${this.sqlStagingTableId};`\n ];\n }\n\n createDatabaseAndSchemaIfNotExists = async (retryCount: number) => {\n try {\n // To avoid checking / creating the dataset multiple times when evaluating streams concurrently\n // We make sure that this portion of the code is run with a concurrency of 1\n await semaphore.runExclusive(async () => {\n const [exists] = await this.bqDataset.exists();\n if (!exists) {\n logger.info(`🐣 Creating dataset: ${this.bqDataset.id} on BigQuery`)\n await this.bqDataset.create();\n } else {\n const [metadata] = await this.bqDataset.getMetadata()\n const alreadyExistinglocation = metadata.location;\n if (this.config.location && this.config.location !== alreadyExistinglocation) {\n await haltAndCatchFire(\n `unknown`,\n `A BigQuery dataset called '${this.bqDataset.id}' already exists in location: '${alreadyExistinglocation}' 😅\n \n This connector is configured to load data into the location '${this.config.location}' which is not possible as 2 datasets sharing the same name can't exist in different location on Google Cloud 😿\n\n To fix this issue, could you either: a. Delete the already existing dataset? b. Change the configured destination schema name to avoid the name conflict? 🙏\n \n Please relaunch the connector once it's done to fix the issue 🤗\n `,\n `\n We have a conflict between an already existing dataset in location ${alreadyExistinglocation} and the configured location: ${this.config.location}\n `\n )\n throw Error()\n }\n logger.info(`👋 Dataset: ${this.bqDataset.id} already exists on BigQuery, reusing it.`)\n }\n });\n } catch (err: any) {\n if (err.code === 400) {\n await haltAndCatchFire(\n `unauthorized`,\n `We can't connect to your BigQuery account 😔\n\n Here is the message from BigQuery: ${err.message}\n \n Can you check that your Warehouse credentials and Source target schema are properly configured and try to sync again the source? 🙏\n `,\n `Got error when trying to get Dataset from BigQuery: ${err.message} - ${err.code}`\n )\n return;\n }\n if (retryCount && retryCount > this.maxRetryCount) {\n logger.error(`StreamId: ${this.streamId} - Error when checking if dataset already exists. ${err.message} - ${err.code}`)\n gracefulExit(1);\n } else {\n logger.error(`StreamId: ${this.streamId} - Error when checking if dataset already exists. Retrying... ${err.message} - ${err.code}`)\n await new Promise((resolve, reject) => setTimeout(resolve, 1000 * (retryCount)))\n await this.createDatabaseAndSchemaIfNotExists(retryCount + 1)\n }\n }\n return Promise.resolve();\n }\n\n createTable = async () => {\n\n try {\n const tableName = this.tableName;\n const schema = this.generateBigquerySchema();\n\n logger.info(`🐣 Creating table: ${tableName} on BigQuery`)\n\n const createTableOptions: TableMetadata = {\n schema\n }\n\n await this.bqDataset.createTable(\n tableName,\n createTableOptions\n )\n\n return;\n } catch (err: any) {\n throw new Error(`StreamId: ${this.streamId} - Issue when creating table in BigQuery\n\n Error: ${err.message}\n Stack: ${err.stack}`)\n }\n }\n\n addColumns = async (tableFields: InternalTableField[]): Promise<void> => {\n\n if (tableFields.length > 0) {\n logger.info(`🆕 Stream: ${this.streamId} - Adding following columns in BigQuery schema: ${JSON.stringify(tableFields)}`)\n const [metadata] = await this.bqTable.getMetadata();\n\n const bgTableFields = tableFields.map(tblField => {\n return this.getBigqueryTableFieldFromInternalSchemaFieldDefinition(tblField.name, tblField.definition)\n }).filter(fld => {\n return !!fld\n })\n const schema = metadata.schema;\n const new_schema = {\n ...schema,\n fields: schema.fields.concat(bgTableFields)\n };\n metadata.schema = new_schema;\n\n await this.bqTable.setMetadata(metadata);\n return;\n }\n\n }\n\n createStagingArea = async () => {\n\n try {\n const tableName = this.stagingTableName;\n\n // A temporary table from a previous load could still be there\n const [exists] = await this.bqDataset.table(tableName).exists();\n if (exists) {\n logger.info(`👴 Temporary table ${tableName} already exists, it should be a relic form the past.\n Dropping it.`)\n await this.deleteStagingArea();\n }\n\n const schema = this.generateBigquerySchema();\n const expirationTime = dayjs().add(1, \"day\").valueOf().toString();\n const createTableOptions: TableMetadata = {\n schema,\n expirationTime\n }\n\n logger.info(`🐣 Creating staging table: ${tableName} on BigQuery`)\n\n await this.bqDataset.createTable(\n tableName,\n createTableOptions\n )\n\n return;\n } catch (err: any) {\n throw new Error(`StreamId: ${this.streamId} - Issue when creating table in BigQuery\n\n Error: ${err.message}\n Stack: ${err.stack}`)\n }\n }\n\n loadStreamInStagingArea = async (localFilePath: string) => {\n\n try {\n\n const gcsService = new CloudStorageService(this.config.loading_deck_gcs_bucket_name);\n const file = await gcsService.uploadFileWithUniqueName(\n localFilePath,\n this.config.connector_id,\n this.streamId,\n );\n\n const metadata: JobLoadMetadata = {\n sourceFormat: 'NEWLINE_DELIMITED_JSON',\n writeDisposition: \"WRITE_TRUNCATE\",\n };\n\n await this.loadGCSFileInTable(this.sqlStagingTableId, file, metadata);\n\n } catch (err: any) {\n logger.error(`StreamId: ${this.streamId} - Error while uploading stream.`)\n\n if (err.code < 500) {\n await haltAndCatchFire(\n `unauthorized`,\n `We couldn't connect to your Cloud Storage bucket 😔\n\n The error from Google is: '${err.message}' 👀\n\n Could you troubleshoot your Cloud Storage configuration in Google Cloud and sync again the source? 🙏`,\n `Got error from cloud storage lib`\n )\n }\n throw err;\n }\n }\n\n deleteStagingArea = () => {\n const query = `DROP TABLE IF EXISTS ${this.sqlStagingTableId};`;\n return this.runQueriesWithRetry([query]);\n }\n\n getTablesInSchema = async (): Promise<{ tableName: string }[]> => {\n const [bqTables] = await this.bqDataset.getTables();\n const foundTables = bqTables\n .filter(tbl => {\n return !!tbl.id\n })\n .map(bqTable => {\n return {\n tableName: bqTable.id\n }\n });\n\n return foundTables as { tableName: string }[];\n }\n\n getTableColumnsFromWarehouse = async (): Promise<WarehouseTableField[]> => {\n const [table] = await this.bqTable.getMetadata();\n return table.schema.fields;\n }\n\n runQueries = async (queries: string[]): Promise<void> => {\n const sqlQuery = `\n BEGIN\n ${queries.join(`\n `)}\n END;\n `;\n await this.bqClient.query(sqlQuery);\n }\n\n // Specific methods\n /**\n * \n * Generate a TableField definition object that can be passed to BigQuery APIs to define a column on a table\n * \n * @param colName \n * @param schemaFieldDefinition \n * @returns \n */\n private getBigqueryTableFieldFromInternalSchemaFieldDefinition = (\n colName: string,\n schemaFieldDefinition: JSONSchemaFieldDefinition | undefined\n ): TableField | undefined => {\n\n const name = colName;\n\n if (!schemaFieldDefinition) {\n throw new Error(`StreamId: ${this.streamId} - Schema is unknown for colName=${colName}, so we can't infer the proper BigQuery definition for this column.`)\n }\n const type = schemaFieldDefinition.type;\n\n // Converting `string | string[]` into `string[]` is easier for later processing\n let typeArr: string[];\n\n if (type instanceof Array) {\n typeArr = type;\n } else {\n typeArr = [type];\n }\n\n if (typeArr.includes('array')) {\n return {\n name,\n mode: \"REPEATED\",\n type: this.getWarehouseTypeFromJSONSchema(schemaFieldDefinition)\n }\n } else {\n // Only supported mode is NULLABLE as:\n // REQUIRED is not working great with adding columns later on so we keep NULLABLE\n let nullableMode = \"NULLABLE\";\n return {\n name,\n mode: nullableMode,\n type: this.getWarehouseTypeFromJSONSchema(schemaFieldDefinition)\n }\n }\n\n }\n\n private generateBigquerySchema = (): TableField[] => {\n const unsafeToSafeMappingColumnsFromColumnStore = this.renamedColumnStore.getUnsafeToSafeColumnMapping(this.streamId);\n if (!unsafeToSafeMappingColumnsFromColumnStore) {\n throw new Error(`StreamId: ${this.streamId} - There is no unsafe->safe column mapping`)\n }\n return Object.keys(unsafeToSafeMappingColumnsFromColumnStore).reduce<TableField[]>((acc, unsafeKey) => {\n\n const renamedColName = this.renamedColumnStore.getColumnTranslation(this.streamId, unsafeKey)!;\n const bigqueryTableField = this.getBigqueryTableFieldFromInternalSchemaFieldDefinition(renamedColName, this.flattenedSchema[unsafeKey]);\n if (bigqueryTableField) {\n acc.push(bigqueryTableField);\n }\n\n return acc;\n }, [])\n }\n\n private loadGCSFileInTable = async (\n tableName: string,\n file: File,\n metadata: JobLoadMetadata\n ): Promise<void> => {\n try {\n const [job] = await this.bqStagingTable.load(file, metadata);\n\n logger.info(`🚚 Loaded GCS file \\`${file.id}\\` in BigQuery table: ${tableName} with Job: \\`${job.id}\\``);\n logger.debug(`Upload Stats: ${JSON.stringify(job.statistics)}`)\n\n // Check the job's status for errors\n const errors = job.status?.errors;\n if (errors && errors.length > 0) {\n throw errors;\n }\n } catch (err: any) {\n logger.error(err)\n throw new Error(`StreamId: ${this.streamId} - Issue when loading file in BigQuery table | fileName: ${file.name}, tableName: ${tableName}\n\n Error: ${err.message}\n Stack: ${err.stack}`)\n }\n }\n\n}","import { BigQueryConfig } from \"../models/config\";\nimport { BigQuery } from \"@google-cloud/bigquery\";\n\nexport class BqClientHolder {\n private static instance: BqClientHolder;\n\n client: BigQuery;\n\n constructor(config: BigQueryConfig) {\n\n const retryOptions = {\n autoRetry: true,\n maxRetries: 3\n }\n\n this.client = new BigQuery({\n projectId: config.database.trim(),\n ...retryOptions\n });\n }\n\n static client(config: BigQueryConfig): BigQuery {\n if (!this.instance) {\n this.instance = new this(config);\n }\n\n return this.instance.client;\n }\n\n}","import { ITarget } from \"../../sdk/models/target/target\"\nimport { BigQueryConfig } from \"./models/config\";\n\nimport { safeColumnName, safeTableName } from \"./helpers\";\nimport { convertNumberIntoDecimal, validateDateRange } from \"./service/record\";\nimport { BigQueryDBSync } from \"./service/dbSync\";\nimport { StreamId } from \"../../sdk/models/metadata\";\nimport { StateProvider } from \"../../sdk/models/state-provider/types\";\n\nexport class BigQueryTarget extends ITarget<BigQueryConfig> {\n\n\n constructor(config: BigQueryConfig, stateProvider: StateProvider) {\n super(config, stateProvider);\n this.renameColumnStore.setSafeColumnNameConverter(this.safeColumnNameConverter);\n }\n static requiredConfigKeys = [\n \"schema\",\n \"project_id\",\n \"loading_deck_gcs_bucket_name\"\n ]\n\n newDBSyncInstance = (\n streamId: StreamId,\n database: string,\n schema: string,\n table: string,\n ): BigQueryDBSync => {\n return new BigQueryDBSync(\n this.config,\n streamId,\n database,\n schema,\n table,\n this.renameColumnStore,\n )\n };\n\n genTableName = safeTableName;\n safeColumnNameConverter = safeColumnName;\n validateDateRange = validateDateRange;\n convertNumberIntoDecimal = convertNumberIntoDecimal;\n\n}","import { logger } from \"../../sdk/service/logger\";\nimport { CloudStorageService } from \"../../services/cloud-storage\";\nimport { StateHolder, StateProvider } from \"../../sdk/models/state-provider/types\";\nimport { format } from \"util\";\n\nexport class GCSStateProvider implements StateProvider {\n private bucketName: string;\n private connectorId: string;\n private service: CloudStorageService;\n\n constructor(connectorId: string, bucketName: string) {\n this.connectorId = connectorId;\n this.bucketName = bucketName;\n this.service = new CloudStorageService(bucketName);\n }\n\n private getObjectPath(): string {\n return `${this.connectorId}/state.json`;\n }\n\n async getState(): Promise<StateHolder> {\n const objectPath = this.getObjectPath();\n try {\n logger.info(`📁 Loading state from gs://${this.bucketName}/${objectPath}`);\n const raw = await this.service.readObjectAsString(objectPath);\n const parsed = JSON.parse(raw);\n return { state: parsed };\n } catch (err: any) {\n logger.warn(format(`error loading state from gs://${this.bucketName}/${objectPath}, will start with empty state, err: %s`, err?.message));\n return { state: undefined };\n }\n }\n\n async writeState(state: string): Promise<void> {\n const objectPath = this.getObjectPath();\n try {\n logger.info(`📝 Writing state to gs://${this.bucketName}/${objectPath}`);\n await this.service.writeStringObject(objectPath, state);\n } catch (err: any) {\n logger.error(format(`💥 Error while writing state to gs://${this.bucketName}/${objectPath}, err: %s`, err?.message));\n throw new Error(format(`error writing state to gs://${this.bucketName}/${objectPath}, err: %s`, err?.message));\n }\n }\n}\n"],"mappings":";AAAA,SAAS,oBAAoB;;;ACA7B,YAAY,aAAa;AAClB,IAAM,oBAAoB;AAEjC,IAAMA,cAAa;AAAA,EACf,SAAS,IAAY,mBAAW,QAAQ;AAAA,IACpC,cAAc,CAAC;AAAA,IACf,OAAO;AAAA,EACX,CAAC;AACL;AAEA,IAAM,gBAAgB,MAA2B;AAC7C,SAAO;AAAA,IACHA,YAAW;AAAA,EACf;AACJ;AAEA,IAAM,EAAE,SAAS,aAAa,WAAW,QAAQ,MAAM,IAAY;AAEnE,IAAM,gBAAwB,qBAAa;AAAA,EACvC,QAAQ;AAAA,IACJ,UAAU;AAAA,IACV,OAAO,EAAE,OAAO,KAAK,CAAC;AAAA,IACtB,MAAM;AAAA,IACN,YAAY;AAAA,EAChB;AAAA,EACA,YAAY,cAAc;AAC9B,CAAC;AAED,IAAI,gBAAgB;AACpB,IAAM,eAAe,CAAC,OAAmB;AACrC,kBAAgB;AAChB,gBAAc,IAAI;AAClB,gBAAc,GAAG,UAAU,MAAM;AAC7B,eAAW,MAAM;AACb,aAAO,GAAG;AAAA,IACd,GAAG,oBAAoB,CAAC;AAAA,EAC5B,CAAC;AACL;AAIA,IAAM,MAAM,CACR,OACA,YACG,SACI;AACP,MAAI,eAAe;AACf,kBAAc,KAAK,EAAE,SAAS,GAAG,IAAI;AAAA,EACzC,OAAO;AACH,YAAQ,KAAK,EAAE,SAAS,GAAG,IAAI;AAAA,EACnC;AACJ;AAEO,IAAM,SAAS;AAAA,EAClB,MAAM,CAAC,YAA0B,SAAsB,IAAI,QAAQ,SAAS,GAAG,IAAI;AAAA,EACnF,OAAO,CAAC,YAA0B,SAAsB,IAAI,SAAS,SAAS,GAAG,IAAI;AAAA,EACrF,OAAO,CAAC,YAA0B,SAAsB,IAAI,SAAS,SAAS,GAAG,IAAI;AAAA,EACrF,MAAM,CAAC,YAA0B,SAAsB,IAAI,QAAQ,SAAS,GAAG,IAAI;AAAA,EACnF;AACJ;;;ADxDA,SAAS,SAAS,UAAkB,UAAkB;AAClD,MAAI;AACA,WAAO,aAAa,QAAQ;AAAA,EAChC,SAAS,KAAK;AACV,WAAO,MAAM,sBAAsB,QAAQ,iBAAiB,QAAQ,gCAAgC;AACpG,UAAM;AAAA,EACV;AACJ;AAEA,SAAS,iBAAiB,UAAkB,aAAqB;AAC7D,MAAI;AACA,WAAO,KAAK,MAAM,YAAY,SAAS,CAAC;AAAA,EAC5C,SAAS,KAAK;AACV,WAAO,MAAM,uBAAuB,QAAQ,uCAAuC;AACnF,UAAM;AAAA,EACV;AACJ;AAEO,IAAM,WAAW,CAAC,aAA0B;AAC/C,QAAM,WAAW,QAAQ,IAAI,IAAI,MAAM;AACvC,QAAM,cAAc,SAAS,UAAU,QAAQ;AAC/C,SAAO,iBAAiB,UAAU,WAAW;AACjD;AAEO,IAAM,aAAa,CAAC,aAAqB;AAC5C,QAAM,SAAS,SAAS,WAAW,QAAQ,OAAO;AAClD,SAAO;AACX;;;AE9BA,OAAO,WAAkG;AACzG,SAAS,uBAAuB;AAChC,YAAY,QAAQ;AACpB,YAAY,QAAQ;AACpB,OAAO,cAAc,yCAAyC;AAO9D,IAAM,cAAc,CAAC,UAA+B;AAEhD,QAAM,aAAa,MAAM,WAAW,MAAM,SAAS,SAAS;AAE5D,SAAO,MAAM,SAAS,mBAEd,CAAC,MAAM,YACJ,eAAe,OACf,eAAe,OACf,eAAe,OACd,cAAc,OAAO,aAAa;AAElD;AAEO,IAAM,mBAAmB,CAAC,eAAuC;AACpE,QAAM,WAAW,MAAM,OAAO;AAAA,IAC1B,SAAS;AAAA,EACb,CAAC;AACD;AAAA,IAAW;AAAA,IACP;AAAA,MACI,SAAS,cAAc;AAAA,MACvB,YAAY,CAACC,aAAY,UAAU;AAC/B,eAAO;AAAA,UAAK,8BAAuBA,WAAU;AAAA,6BAChC,MAAM,QAAQ,MAAM;AAAA,0BACvB,MAAM,QAAQ,GAAG;AAAA;AAAA;AAAA,UAGvB,MAAM,QAAQ;AAAA,UACd,MAAM,QAAQ;AAAA,QAClB;AACA,YAAIA,cAAa,GAAG;AAChB,iBAAO;AAAA,QACX;AACA,eAAO,WAAW,iBAAiBA,WAAU;AAAA,MACjD;AAAA,MACA,gBAAgB,CAAC,UAA+B;AAC5C,eAAO,MAAM,8BAAuB,MAAM,QAAQ,MAAM,IAAI,MAAM,QAAQ,GAAG;AAAA;AAAA,0BAEnE,OAAO,UAAU,MAAM;AAAA,6BACpB,MAAM,IAAI;AAAA,sCACD,KAAK,EAAE;AAE7B,eAAO,kCAAkC,KAAK,KACvC,YAAY,KAAK;AAAA,MAC5B;AAAA,IACJ;AAAA,EAAC;AACL,SAAO;AACX;AAQO,IAAM,oBAAoB,OAC7B,UACA,QACA,mBAC4B;AAE5B,QAAM,WAAW,iBAAiB,OAAO,UAAU;AAGnD,QAAM,mBAAmB,CAAC,WAAgB;AACtC,WAAU,aAAU,QAAQ,EAAE,aAAa,SAAS,CAAC;AAAA,EACzD;AAEA,MAAI;AACA,WAAO,KAAK,iBAAU,QAAQ,IAAI,EAAE,SAAS,eAAe,CAAC;AAC7D,UAAM,gBAAoC;AAAA,MACtC,QAAQ,OAAO;AAAA,MACf,kBAAkB,EAAE,WAAW,CAAC,WAAc,aAAU,QAAQ,EAAE,aAAa,SAAS,CAAC,EAAE;AAAA,IAC/F;AACA,QAAI,OAAO,SAAS;AAChB,oBAAc,UAAU,OAAO;AAAA,IACnC;AACA,UAAM,WAAW,MAAM,SAAS;AAAA,MAC5B;AAAA,MACA;AAAA,IACJ;AACA,WAAO;AAAA,EACX,SAAS,KAAU;AACf,QAAI,IAAI,SAAS,SAAS,KAAK;AAC3B,YAAM,IAAI,MAAM,cAAc,IAAI,SAAS,MAAM,mCAAmC,QAAQ;AAAA;AAAA,gCAExE,KAAK,UAAU,IAAI,SAAS,OAAO,CAAC;AAAA;AAAA,6CAEvB,KAAK,UAAU,IAAI,SAAS,IAAI,CAAC,EAAE;AAAA,IACxE;AACA,UAAM;AAAA,EACV;AACJ;AAEO,IAAM,iCAAiC,OAC1C,UACA,QACA,mBACC;AACD,QAAM,WAAW,iBAAiB,OAAO,UAAU;AAGnD,QAAM,mBAAmB,CAAC,WAAgB;AACtC,WAAU,aAAU,QAAQ,EAAE,aAAa,SAAS,CAAC;AAAA,EACzD;AAEA,MAAI;AACA,WAAO,KAAK,iBAAU,QAAQ,oBAAoB,OAAO,IAAI,EAAE,SAAS,eAAe,CAAC;AACxF,UAAM,gBAAoC;AAAA,MACtC,QAAQ,OAAO;AAAA,MACf,kBAAkB,EAAE,WAAW,CAAC,WAAc,aAAU,QAAQ,EAAE,aAAa,SAAS,CAAC,EAAE;AAAA,IAC/F;AACA,QAAI,OAAO,SAAS;AAChB,oBAAc,UAAU,OAAO;AAAA,IACnC;AACA,UAAM,WAAW,MAAM,SAAS,IAAI,UAAU,aAAa;AAC3D,WAAO;AAAA,EACX,SAAS,KAAK;AACV,QAAI,eAAe,OAAO;AACtB,UAAI,MAAM,aAAa,GAAG,GAAG;AACzB,aAAK,IAAI,UAAU,UAAU,KAAK,KAAK;AACnC,iBAAO,KAAK,cAAc,IAAI,UAAU,MAAM,mCAAmC,QAAQ;AAAA;AAAA,gCAE7E,KAAK,UAAU,IAAI,UAAU,OAAO,CAAC;AAAA;AAAA,6CAExB,KAAK,UAAU,IAAI,UAAU,IAAI,CAAC,EAAE;AAAA,QACjE;AAAA,MACJ;AAAA,IACJ;AACA,UAAM;AAAA,EACV;AACJ;AAEO,IAAM,iBAAiB,OAC1B,UACA,QACA,mBACa;AACb,QAAM,eAAe,MAAM;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AACA,SAAO,aAAa;AACxB;AAEO,IAAM,yBAAyB,OAClC,UACA,QACA,QACA,mBACiC;AAEjC,QAAM,WAAW,iBAAiB,OAAO,UAAU;AAEnD,QAAM,SAAY,qBAAkB,MAAM;AAE1C,QAAM,mBAAmB,CAAC,WAAgB;AACtC,WAAU,aAAU,QAAQ,EAAE,aAAa,SAAS,CAAC;AAAA,EACzD;AAEA,SAAO,KAAK,iBAAU,QAAQ,IAAI,EAAE,SAAS,eAAe,CAAC;AAE7D,SAAO,SAAS;AAAA,IACZ,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,cAAc;AAAA,IACd,QAAQ,OAAO;AAAA,IACf,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IACpD,kBAAkB,EAAE,WAAW,CAAC,WAAc,aAAU,QAAQ,EAAE,aAAa,SAAS,CAAC,EAAE;AAAA,EAC/F,CAAC,EAAE,KAAK,cAAY;AAChB,WAAO,IAAI,QAA+B,CAAC,SAAS,WAAW;AAC3D,eAAS,KAAK,KAAK,MAAM;AACzB,UAAI,QAAa;AACjB,aAAO,GAAG,SAAS,SAAO;AACtB,gBAAQ;AACR,eAAO,MAAM;AACb,eAAO,GAAG;AAAA,MACd,CAAC;AACD,aAAO,GAAG,SAAS,MAAM;AACrB,YAAI,CAAC,OAAO;AACR,kBAAQ,EAAE,WAAW,OAAO,CAAC;AAAA,QACjC;AAAA,MAGJ,CAAC;AAAA,IACL,CAAC;AAAA,EACL,CAAC;AACL;AAQO,IAAM,kBAAkB,OAC3B,UACA,QACA,YACa;AAEb,QAAM,WAAW,iBAAiB,OAAO,UAAU;AACnD,MAAI;AACA,UAAM,gBAAoC,EAAE,QAAQ,OAAO,GAAG;AAC9D,QAAI,OAAO,SAAS;AAChB,oBAAc,UAAU,OAAO;AAAA,IACnC;AACA,UAAM,WAAW,MAAM,SAAS;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,WAAO,SAAS;AAAA,EACpB,SAAS,KAAU;AACf,QAAI,KAAK,UAAU,UAAU,KAAK;AAC9B,YAAM,IAAI,MAAM,cAAc,IAAI,SAAS,MAAM,mCAAmC,QAAQ;AAAA;AAAA,6CAE3D,KAAK,UAAU,IAAI,SAAS,IAAI,CAAC,EAAE;AAAA,IACxE;AACA,UAAM;AAAA,EACV;AACJ;AAEO,IAAM,sBAAsB,OAAU,UAAkB,QAAoB,YAA6B;AAE5G,QAAM,WAAW,iBAAiB,OAAO,UAAU;AAEnD,MAAI;AACA,UAAM,WAAW,MAAM,SAAS;AAAA,MAC5B,QAAQ;AAAA,MACR,KAAK;AAAA,MACL,SAAS;AAAA,QACL,GAAI,QAAgB,WAAW;AAAA,MACnC;AAAA,MACA,MAAM;AAAA,IACV,CAAC;AACD,WAAO,SAAS;AAAA,EACpB,SAAS,KAAU;AACf,QAAI,IAAI,SAAS,SAAS,KAAK;AAC3B,YAAM,IAAI,MAAM,cAAc,IAAI,SAAS,MAAM,mCAAmC,QAAQ;AAAA;AAAA,6CAE3D,KAAK,UAAU,IAAI,SAAS,IAAI,CAAC,EAAE;AAAA,IACxE;AACA,UAAM;AAAA,EACV;AACJ;AAEO,IAAM,wBAAwB,OAAO,UAAkB,QAAoB,YAAiB;AAE/F,QAAM,WAAW,iBAAiB,OAAO,UAAU;AAEnD,MAAI;AAEA,UAAM,SAAS,IAAI,gBAAgB,OAAc;AAEjD,UAAM,WAAW,MAAM,SAAS;AAAA,MAC5B;AAAA,MACA,OAAO,SAAS;AAAA,MAChB;AAAA,QACI,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,MACxD;AAAA,IAAC;AACL,WAAO,SAAS;AAAA,EACpB,SAAS,KAAU;AACf,QAAI,IAAI,SAAS,SAAS,KAAK;AAC3B,YAAM,IAAI,MAAM,cAAc,IAAI,SAAS,MAAM,mCAAmC,QAAQ;AAAA;AAAA,6CAE3D,KAAK,UAAU,IAAI,SAAS,IAAI,CAAC,EAAE;AAAA,IACxE;AACA,UAAM;AAAA,EACV;AACJ;;;AC1RA,IAAM,cAIF,CAAC;AAEE,IAAM,wBAAwB;AAC9B,IAAM,0BAA0B;AAChC,IAAM,wBAAwB;AAC9B,IAAM,6BAA6B;AAUnC,IAAM,oBAAoB,CAC7B,MACA,cACkB;AAClB,SAAO,UAAU,IAAI,cAAY;AAC7B,WAAO,iBAAiB,MAAM,QAAQ;AAAA,EAC1C,CAAC;AACL;AAEO,IAAM,mBAAmB,CAC5B,MACA,WAAmB,0BACH;AAChB,MAAI,CAAC,YAAY,QAAQ,GAAG;AACxB,gBAAY,QAAQ,IAAI,CAAC;AAAA,EAC7B;AACA,QAAM,oBAAoB,YAAY,QAAQ;AAE9C,MAAI,CAAC,kBAAkB,IAAI,GAAG;AAC1B,sBAAkB,IAAI,IAAI,IAAI,cAAc,MAAM,QAAQ;AAAA,EAC9D;AACA,SAAO,kBAAkB,IAAI;AACjC;AAEO,IAAM,gBAAgB,MAAuB;AAChD,SAAO,OAAO,KAAK,WAAW,EACzB,QAAQ,cAAY;AACjB,UAAM,oBAAoB,YAAY,QAAQ;AAC9C,QAAI,CAAC,mBAAmB;AACpB,aAAO,CAAC;AAAA,IACZ;AACA,WAAO,OAAO,KAAK,iBAAiB,EAC/B,IAAI,gBAAc,kBAAkB,UAAU,CAAC,EAC/C,OAAO,CAAC,MAA0B,MAAM,MAAS;AAAA,EAC1D,CAAC;AACT;AAEO,IAAM,gBAAN,MAAoB;AAAA,EACf,QAAgB;AAAA,EACxB;AAAA,EACA;AAAA,EAEA,YACI,MACA,UACF;AACE,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EACpB;AAAA,EAEA,UAAU,MAAc,GAAS;AAC7B,SAAK,QAAQ,KAAK,QAAQ;AAAA,EAC9B;AAAA,EAEA,cAAsB;AAClB,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,UAAkB;AACd,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,WAAmB;AACf,WAAO,KAAK;AAAA,EAChB;AACJ;;;AClFA,IAAM,oBAAoB,CAAC,SAAiB,GAAG,KAAK,MAAM,OAAO,OAAO,OAAO,GAAG,IAAI,GAAG;AAElF,IAAM,uBAAuB,CAAC,WAAmB;AACpD,QAAM,aAAa,QAAQ,YAAY;AAEvC,QAAM,cAAc;AAAA,IAChB,KAAK,GAAG,kBAAkB,WAAW,GAAG,CAAC;AAAA,IACzC,WAAW,GAAG,kBAAkB,WAAW,SAAS,CAAC;AAAA,IACrD,UAAU,GAAG,kBAAkB,WAAW,QAAQ,CAAC;AAAA,IACnD,UAAU,GAAG,kBAAkB,WAAW,QAAQ,CAAC;AAAA,EACvD;AAEA,SAAO,KAAK,GAAG,MAAM,QAAQ,WAAW;AAC5C;;;ACbA,eAAsB,aAAa,UAAkB;AAGjD,QAAM,eAAe,IAAI,QAAc,CAAC,SAAS,WAAW;AACxD,WAAO,aAAa,OAAO;AAAA,EAC/B,CAAC;AACD,QAAM;AACN,UAAQ,KAAK,QAAQ;AACzB;;;ACNO,IAAM,mBAAmB,OAC5B,WACA,WACA,mBACgB;AAEhB,SAAO;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AAEA,QAAM,aAAa,CAAC;AACxB;;;ACtBO,IAAK,oBAAL,kBAAKC,uBAAL;AACH,EAAAA,mBAAA,iBAAc;AACd,EAAAA,mBAAA,gBAAa;AACb,EAAAA,mBAAA,YAAS;AAHD,SAAAA;AAAA,GAAA;;;ACWL,IAAM,gBAAN,MAAuC;AAAA,EAE1C,OAAoB;AAAA,EACpB;AAAA,EACA;AAAA,EAEA,YAAY,QAAa,QAAkB;AACvC,SAAK,SAAS;AACd,SAAK,SAAS;AAAA,EAClB;AAAA,EAEA,WAAW;AACP,UAAM,SAAS;AAAA,MACX,MAAM;AAAA,MACN,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK;AAAA,IACjB;AACA,WAAO,KAAK,UAAU,MAAM;AAAA,EAChC;AACJ;AAEO,IAAM,eAAN,MAAsC;AAAA,EAEzC,OAAoB;AAAA,EACpB;AAAA,EAEA,YAAY,OAAY;AACpB,SAAK,QAAQ;AAAA,EACjB;AAAA,EAEA,WAAW;AACP,UAAM,SAAS;AAAA,MACX,MAAM;AAAA,MACN,OAAO,KAAK;AAAA,IAChB;AACA,WAAO,KAAK,UAAU,MAAM;AAAA,EAChC;AACJ;AAEO,IAAM,2BAAN,MAAkD;AAAA,EAErD,OAAoB;AAAA,EACpB;AAAA,EACA;AAAA,EAEA,YAAY,QAAgB,SAA4B;AACpD,SAAK,SAAS;AACd,SAAK,cAAc;AAAA,EACvB;AAAA,EAEA,WAAW;AACP,UAAM,SAAS;AAAA,MACX,MAAM;AAAA,MACN,aAAa,KAAK;AAAA,MAClB,QAAQ,KAAK;AAAA,IACjB;AACA,WAAO,KAAK,UAAU,MAAM;AAAA,EAChC;AACJ;AAEO,IAAM,gBAAN,MAAuC;AAAA,EAE1C,OAAoB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,MAQT;AACC,UAAM;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ,IAAI;AAEJ,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,gBAAgB;AACrB,SAAK,qBAAqB;AAC1B,SAAK,eAAe;AACpB,SAAK,cAAc;AACnB,SAAK,qBAAqB;AAAA,EAC9B;AAAA,EAEA,WAAW;AACP,UAAM,SAAc;AAAA,MAChB,MAAM;AAAA,MACN,QAAQ,KAAK;AAAA,MACb,QAAQ,KAAK;AAAA,MACb,gBAAgB,KAAK;AAAA,MACrB,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK;AAAA,IACtB;AAEA,QAAI,KAAK,oBAAoB;AACzB,aAAO,qBAAqB,IAAI,KAAK;AAAA,IACzC;AAEA,WAAO,KAAK,UAAU,MAAM;AAAA,EAChC;AACJ;;;AC5HA,OAAO,WAAsB;;;ACFtB,IAAM,wBAAwB;;;ADKrC,SAAS,UAAAC,eAAc;AAsCvB,IAAM,mBAAmB;AACzB,IAAM,uBAAuB;AAC7B,IAAM,kBAAkB;AAEjB,IAAM,uBAAuB,CAChC,OACA,gBACA,cACA,aACc;AAEd,MAAI,aAAa,aAAa,cAAc;AAC5C,MAAI,CAAC,YAAY;AACb,UAAM,IAAI,MAAMA,QAAO,gCAAgC,cAAc,4BAA4B,OAAO,KAAK,YAAY,CAAC,CAAC;AAAA,EAC/H;AACA,MAAI,mBAAmB,MAAM,UAAU;AAEvC,MAAI;AACJ,MAAI;AAEJ,MAAI,UAAU;AACV,kBAAc,MAAM,qBAAqB;AACzC,wBAAoB,MAAM,WAAW;AACrC,QAAI,eAAe,kBAAkB,QAAQ,gBAAgB,GAAG;AAC5D,YAAM,IAAI;AAAA,QACN,mDAAmD,UAAU;AAAA,yDACpB,WAAW;AAAA,MACxD;AAAA,IACJ;AAAA,EACJ;AAGA,MAAI,CAAC,UAAU;AAIX,QAAI,CAAC,MAAM,gBAAgB,GAAG;AAC1B,YAAM,SAA0B,CAAC;AACjC,aAAO,oBAAoB,IAAI;AAC/B,YAAM,gBAAgB,IAAI;AAAA,IAC9B;AACA,kBAAe,MAAM,gBAAgB,EAAU,qBAAqB;AAIpE,wBAAoB,MAAM,eAAe,MAAM,qBAAqB,CAAC;AAGrE,QAAI,eAAe,kBAAkB,QAAQ,gBAAgB,GAAG;AAC5D,yBAAmB;AACnB,mBAAa;AAAA,IACjB;AAAA,EACJ;AAIA,QAAM,iBAAiB,MAAM,eAAe;AAC5C,QAAM,+BAA+B,MAAM,cAAc;AAEzD,MAAI,gCAAgC,6BAA6B,SAAS,gBAAgB,GAAG;AAEzF,uBAAmB;AACnB,iBAAa,6BAA6B,OAAO,qBAAqB;AAAA,EAC1E;AAEA,MAAI,aAAa,OAAO;AACpB,IAAC,MAAM,gBAAgB,EAAsB,gBAAgB,IAAI;AACjE,IAAC,MAAM,gBAAgB,EAAsB,qBAAqB,IAAI,MAAM,gBAAgB,EAAE,OAAO,qBAAqB;AAAA,EAC9H,OAAO;AACH,UAAM,gBAAgB,IAAI;AAC1B,UAAM,qBAAqB,IAAI,MAAM,gBAAgB,EAAE,OAAO,qBAAqB;AAAA,EACvF;AAEA,SAAO;AACX;AAQO,IAAM,+BAA+B,CAAC,UAAoC;AAE7E,QAAM,gBAAgB,MAAM,eAAe;AAC3C,QAAM,kBAAkB,MAAM,gBAAgB;AAC9C,MAAI,mBAAmB,gBAAgB,gBAAgB,KAAK,gBAAgB,qBAAqB,GAAG;AAEhG,UAAM,gBAAgB,IAAI,gBAAgB,gBAAgB;AAC1D,QAAI,aAAa,gBAAgB,qBAAqB;AAGtD,QAAI,iBAAiB,aAAa,YAAY,aAAa,GAAG;AAC1D,mBAAa;AAAA,IACjB;AAEA,UAAM,2BAA2B,MAAM,qBAAqB;AAC5D,QAAI,CAAC,4BAA6B,4BAA4B,aAAa,YAAY,wBAAwB,GAAI;AAC/G,YAAM,qBAAqB,IAAI;AAAA,IACnC;AAAA,EACJ;AAEA,SAAO,MAAM,gBAAgB;AAE7B,SAAO;AACX;AAEO,IAAM,eAAe,CAAC,QAAgB,WAA4B;AACrE,SAAO,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM,CAAC;AAC9C;AAEO,IAAM,wBAAwB,CAAC,OAAsB,aAAuB;AAC/E,MAAI,CAAC,MAAM,WAAW;AAClB,UAAM,YAAY,CAAC;AAAA,EACvB;AACA,MAAI,CAAC,MAAM,UAAU,QAAQ,GAAG;AAC5B,UAAM,UAAU,QAAQ,IAAI,CAAC;AAAA,EACjC;AACA,SAAO,MAAM,UAAU,QAAQ;AACnC;AAEO,IAAM,eAAN,MAAmB;AAAA,EAEtB,OAAe;AAAA,EAEf;AAAA,EAEA,cAAc;AACV,SAAK,YAAY,CAAC;AAAA,EACtB;AAAA,EAEA,OAAO,cAA4B;AAC/B,QAAI,CAAC,KAAK,UAAU;AAChB,WAAK,WAAW,IAAI,KAAK;AAAA,IAC7B;AAEA,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,YAAY,UAAoB,aAA0B;AACtD,SAAK,UAAU,QAAQ,IAAI;AAAA,EAC/B;AAAA,EAEA,oBAAoB,UAAoB,eAAuB;AAC3D,QAAI,CAAC,KAAK,UAAU,QAAQ,GAAG;AAC3B,WAAK,UAAU,QAAQ,IAAI,CAAC;AAAA,IAChC;AACA,SAAK,UAAU,QAAQ,EAAE,eAAe,IAAI;AAAA,EAChD;AAAA,EAEA,YAAY,UAAiC;AACzC,QAAI,KAAK,UAAU,QAAQ,GAAG;AAC1B,aAAO,KAAK,UAAU,QAAQ;AAAA,IAClC,OAAO;AACH,aAAO,CAAC;AAAA,IACZ;AAAA,EACJ;AAAA,EAEA,aAAa;AACT,SAAK,YAAY,CAAC;AAAA,EACtB;AAAA,EAEA,MAAa;AACT,UAAM,QAAe;AAAA,MACjB,WAAW,KAAK;AAAA,IACpB;AACA,WAAO;AAAA,EACX;AAAA,EAEA,MAAM,qBAAqB,QAAiB;AACxC,UAAM,QAAe;AAAA,MACjB,WAAW,KAAK;AAAA,IACpB;AAEA,UAAM,UAAU,IAAI,aAAa,KAAK;AACtC,UAAM,OAAO,MAAM,OAAO;AAAA,EAC9B;AACJ;;;AEvNO,IAAM,gBAAN,MAAuB;AAAA,EAE1B,eAAe,QAAiC;AAC5C,WAAO,QAAQ,QAAQ,CAAC,CAAC;AAAA,EAC7B;AAAA,EAEA,UAAU,QAA+B;AACrC,WAAO,QAAQ,QAAQ,CAAC,CAAC;AAAA,EAC7B;AAEJ;;;ACfA,OAAOC,YAA8D;AAGrE,YAAYC,SAAQ;;;ACHpB,OAAOC,YAAsB;;;ACctB,IAAM,iBAAiB,CAAC,YAA8B;AAEzD,MAAI,CAAC,SAAS;AACV,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACrE;AAEA,MAAI,QAAQ,OAAO,MAAM,QAAW;AAChC,eAAW,cAAc,QAAQ,OAAO,GAAG;AACvC,UAAI,eAAe,UAAU,GAAG;AAC5B,eAAO;AAAA,MACX;AAAA,IACJ;AACA,WAAO;AAAA,EACX,WAES,QAAQ,MAAM,MAAM,QAAW;AACpC,WAAO,QAAQ,QAAQ,MAAM;AAAA,EACjC;AAEA,QAAM,IAAI;AAAA,IACN,8CAA8C,OAAO;AAAA,EACzD;AAEJ;;;AD3BA,OAAOC,gBAAe;AAEtB,OAAOC,eAAc;;;AEZrB,OAAO,eAAe;AAMtB,OAAO,cAAc;AAEd,IAAM,iCAAiC;AAIvC,IAAe,MAAf,MAAsB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAsB;AAAA,EACtB;AAAA,EACA;AAAA,EAKA,YACI,QACA,QACA,eACF;AACE,SAAK,UAAU,CAAC;AAChB,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,gBAAgB;AACrB,SAAK,WAAW,EAAE,WAAW,CAAC,EAAE;AAAA,EACpC;AAAA,EACA,OAAO,OAAO,YAAyC;AAGnD,UAAM,eAAe,MAAM,KAAK,cAAc,SAAS;AACvD,QAAG,aAAa,SAAS,aAAa,MAAM,WAAW;AACnD,WAAK,WAAW,UAAU,aAAa,KAAK;AAAA,IAChD;AAEA,UAAM,KAAK,KAAK;AAChB,WAAO,KAAK,yBAAkB;AAE9B,UAAM,QAAQ,aAAa,YAAY,EAAE,IAAI;AAC7C,WAAO,KAAK,gCAAyB,KAAK;AAE1C,UAAM,aAAa,QAAQ,IAAI,cACzB,QAAQ,IAAI,YAAY,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC,EAAE,OAAO,OAAK,EAAE,SAAS,CAAC,IAC9E;AAEN,UAAM,UAAU,SAAS,WAAW,QAAQ,QAAQ,SAAS,IACvD,QAAQ,UACR;AACN,UAAM,UAAU,IAAI,KAAK,SAAS,WAAW,CAAC,GAAG,IAAI,OAAK,EAAE,KAAK,CAAC,CAAC;AAEnE,QAAI,eAAe,KAAK,QAAQ,OAAO,OAAK,CAAC,EAAE,QAAQ;AACvD,QAAI,WAAW,QAAQ,SAAS,GAAG;AAC/B,YAAM,aAAa,IAAI,IAAI,OAAO;AAClC,qBAAe,aAAa,OAAO,OAAK,WAAW,IAAI,EAAE,QAAQ,CAAC;AAAA,IACtE;AACA,QAAI,QAAQ,OAAO,GAAG;AAClB,qBAAe,aAAa,OAAO,OAAK,CAAC,QAAQ,IAAI,EAAE,QAAQ,CAAC;AAAA,IACpE;AAEA,UAAM,oBAAoB,aAAa,IAAI,OAAK,EAAE,QAAQ;AAC1D,WAAO,KAAK,iCAA0B,kBAAkB,KAAK,GAAG,CAAC;AAEjE,UAAM,SAAS,IAAI,cAAc,CAAC,WAAW;AACzC,aAAO,OAAO,KAAK;AAAA,IACvB,GAAG,EAAE,aAAa,KAAK,YAAY,CAAC;AAEpC,WAAO,MAAM,uFAAuF;AACpG,UAAM,KAAK,OAAO,SAAS;AAC3B,WAAO,QAAQ,QAAQ;AAAA,EAC3B;AAAA;AAAA,EAGA,MAAqB;AACjB,WAAO,QAAQ,QAAQ;AAAA,EAC3B;AACJ;;;AFnEA,SAAS,UAAAC,eAAc;AAShB,IAAe,SAAf,MAAuD;AAAA;AAAA,EAG1D;AAAA,EACA;AAAA,EACA;AAAA,EAEA,oBAAmD;AAAA,EACnD,oBAA6B;AAAA,EAC7B,sBAA8B;AAAA,EAC9B,WAAqB;AAAA,EACrB,aAAiC;AAAA,EACjC,eAAmC;AAAA,EACnC,cAAkC;AAAA,EAClC,aAAuB,CAAC;AAAA,EACxB,iBAAqC;AAAA;AAAA,EAErC,uBAA2C;AAAA,EAE3C,WAAwC,CAAC;AAAA;AAAA;AAAA,EAGzC,WAAoB;AAAA;AAAA;AAAA,EAGpB,WAAoB;AAAA,EAEpB;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EAEA,YACI,QACA,UACA,QACA,mBAA2B,gCAC7B;AACE,SAAK,SAAS;AACd,SAAK,WAAWC,WAAU,QAAQ;AAClC,SAAK,SAAS;AACd,SAAK,mBAAmB;AAGxB,SAAK,wBAAwB;AAAA,MACzB,WAAW,MAAM,CAAC,KAAK;AAAA,MACvB,cAAc,MAAM,CAAC,KAAK,QAAQ;AAAA,IACtC;AACA,SAAK,2BAA2B;AAAA,MAC5B,WAAW,MAAM,CAAC,KAAK;AAAA,MACvB,cAAc,MAAM,CAAC,KAAK,QAAQ;AAAA,IACtC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,YAA2B;AAC9B,QAAI;AACA,YAAM,oBAAoB,KAAK,4BAA4B,EAAE;AAC7D,aAAO;AAAA,QACH,uBAAgB,iBAAiB,oBAAoB,KAAK,QAAQ;AAAA,MACtE;AAEA,YAAM,KAAK,UAAU;AAGrB,YAAM,KAAK,oBAAoB;AAE/B,YAAM,KAAK,+BAA+B;AAG1C,YAAM,KAAK,sBAAsB;AAGjC,YAAM,KAAK,aAAa;AAGxB,aAAO,KAAK,MAAM;AAAA,IACtB,SAAS,KAAK;AACV,UAAI,eAAe,OAAO;AACtB,cAAM,IAAI,MAAMD,QAAO,mDAAmD,KAAK,UAAU,IAAI,OAAO,CAAC;AAAA,MACzG;AACA,YAAM;AAAA,IACV;AAAA,EACJ;AAAA,EAEA,QAAQ,YAA2B;AAC/B,UAAM,oBAAoB,KAAK,4BAA4B,EAAE;AAC7D,WAAO;AAAA,MACH,sBAAe,iBAAiB,oBAAoB,KAAK,QAAQ;AAAA,IACrE;AAEA,UAAM,KAAK,OAAO;AAElB,UAAME,UAAS,IAAI,KAAK,UAAU,WAAS;AACvC,aAAO,MAAM,MAAM;AAAA,IACvB,GAAG,EAAE,aAAa,EAAE,CAAC;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,qBAAqB,MAAqB;AACtC,UAAM,UAAU,IAAI,aAAa,aAAa,YAAY,EAAE,IAAI,CAAC;AACjE,WAAO,KAAK,OAAO,MAAM,OAAO;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,iCAAiC,YAA2B;AACxD,UAAM,SAAS,KAAK,4BAA4B,EAAE;AAClD,UAAM,UAAU,IAAI,yBAAyB,KAAK,UAAU,MAAM;AAElE,UAAMA,UAAS,IAAI,KAAK,UAAU,OAAM,MAAK;AACzC,aAAO,EAAE,+BAA+B;AAAA,IAC5C,GAAG,EAAE,aAAa,EAAE,CAAC;AACrB,UAAM,KAAK,OAAO,kBAAkB,OAAO;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,OAAO,uBAAgD;AAEzE,QAAI,CAAC,KAAK,UAAU;AAChB,YAAM,SAAS,MAAM,KAAK,UAAU;AACpC,UAAI,WAAW,QAAW;AACtB,cAAM,oBAAoB,KAAK,4BAA4B;AAE3D,cAAM,UAAU,IAAI,cAAc;AAAA,UAC9B,eAAe,KAAK;AAAA,UACpB,QAAQ,KAAK;AAAA,UACb,QAAQ,OAAO;AAAA,UACf,GAAI,kBAAkB,iBAAiB,EAAE,oBAAoB,CAAC,kBAAkB,cAAc,EAAE,IAAI,CAAC;AAAA,UACrG,GAAI,KAAK,eAAe,EAAE,cAAc,KAAK,aAAa,IAAI,CAAC;AAAA,UAC/D,GAAI,KAAK,cAAc,EAAE,aAAa,KAAK,YAAY,IAAI,CAAC;AAAA,UAC5D,GAAI,OAAO,qBAAqB,EAAE,oBAAoB,OAAO,mBAAmB,IAAI,CAAC;AAAA,QACzF,CAAC;AACD,cAAM,KAAK,OAAO,OAAO,OAAO;AAAA,MACpC;AAAA,IACJ;AAEA,QAAI,uBAAuB,MAAM;AAC7B,YAAMA,UAAS,IAAI,KAAK,UAAU,OAAO,UAAU;AAC/C,cAAM,MAAM,oBAAoB;AAAA,MACpC,GAAG,EAAE,aAAa,EAAE,CAAC;AAAA,IACzB;AAAA,EACJ;AAAA;AAAA,EAIA,wBAAwB,YAAY;AAChC,UAAM,iBAAiB,MAAM,KAAK,0BAA0B;AAC5D,UAAM,gBAAgB,gBAAgB,OAAO,qBAAqB;AAElE,QAAI,eAAe;AACf,mBAAa,YAAY,EAAE,oBAAoB,KAAK,UAAU,aAAa;AAAA,IAC/E;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,wBAAwB,CAAC,iBAA0B;AAE/C,QAAI,cAAc;AACd,YAAM,oBAAoB,KAAK,4BAA4B;AAC3D,UAAI;AAAA,QACA;AAAA,QACA;AAAA,MACJ,EAAE,SAAS,kBAAkB,iBAAiB,GAAG;AAE7C,YAAI,KAAK,sBAAsB;AAC3B;AAAA,QACJ;AAGA,YAAI,KAAK,qBAAqB,CAAC,KAAK,gBAAgB;AAChD;AAAA,QACJ;AAGA,YAAI,CAAC,kBAAkB,gBAAgB;AACnC,gBAAM,IAAI;AAAA,YAAM,yCAAyC,KAAK,QAAQ;AAAA,6CAC7C,kBAAkB,iBAAiB;AAAA,UAC5D;AAAA,QACJ;AAEA,cAAM,mBAAmB,aAAa,YAAY;AAClD,cAAM,QAAQ,iBAAiB,YAAY,KAAK,QAAQ;AAExD,cAAM,WAAW;AAAA,UACb;AAAA,UACA,kBAAkB;AAAA,UAClB;AAAA,UACA,KAAK;AAAA,QACT;AAEA,qBAAa,YAAY,EAAE,YAAY,KAAK,UAAU,QAAQ;AAAA,MAClE;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,4BAA4B,YAA8B;AAEtD,UAAM,oBAAoB,KAAK,4BAA4B;AAE3D,QAAI,CAAC,kBAAkB,gBAAgB;AACnC,aAAO;AAAA,IACX;AAEA,UAAM,SAAS,MAAM,KAAK,UAAU;AACpC,QAAI,CAAC,UAAU,CAAC,OAAO,cAAc,CAAC,OAAO,WAAW,YAAY;AAChE,aAAO;AAAA,IACX;AAEA,UAAM,iBAAiB,OAAO,WAAW,YAAY,EAAE,kBAAkB,cAAc;AACvF,QAAI,CAAC,gBAAgB;AACjB,aAAO;AAAA,IACX;AAEA,WAAO,eAAe,cAAc;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,uBAA8B;AAC1B,UAAM,qBAAqB,KAAK,uBAC1B,KAAK,uBACL,KAAK;AACX,UAAM,QAAQ,sBAAsB,KAAK,UAAU,kBAAkB;AAErE,UAAM,YAAa,KAAK,OAAe;AACvC,UAAM,oBAAoB,KAAK,4BAA4B;AAE3D,WAAO,MAAM,GAAG,KAAK,QAAQ,gCAAgC,MAAM,mBAAmB;AAAA,gCAC9D,MAAM,cAAc;AAAA,+BACrB,kBAAkB,cAAc,EAAE;AAEzD,QAAI,MAAM,qBAAqB;AAC3B,aAAO,MAAM,GAAG,KAAK,QAAQ,+DAA+D,MAAM,mBAAmB,EAAE;AACvH,aAAOC,OAAM,MAAM,mBAAmB;AAAA,IAC1C,WAAW,WAAW;AAClB,aAAO,MAAM,GAAG,KAAK,QAAQ,2DAA2D,SAAS,EAAE;AACnG,aAAOA,OAAM,SAAS;AAAA,IAC1B,OAAO;AACH,aAAO,MAAM,GAAG,KAAK,QAAQ,mDAAmD;AAChF,aAAOA,OAAM,CAAC;AAAA,IAClB;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,4BAA4B,YAAwC;AAEhE,QAAI,MAAM,KAAK,0BAA0B,GAAG;AACxC,aAAOA,OAAM;AAAA,IACjB;AAEA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,2BAA2B,MAKtB;AACD,QAAI,KAAK,mBAAmB;AACxB,aAAO;AAAA,QACH,mBAAmB,KAAK;AAAA,QACxB,gBAAgB,KAAK;AAAA,QACrB,UAAU;AAAA,MACd;AAAA,IACJ;AACA,QAAI,KAAK,kBAAkB,KAAK,sBAAsB;AAClD,aAAO;AAAA,QACH;AAAA,QACA,gBAAgB,KAAK;AAAA,QACrB,UAAU;AAAA,MACd;AAAA,IACJ;AAEA,WAAO;AAAA,MACH;AAAA,MACA,gBAAgB;AAAA,MAChB,UAAU;AAAA,IACd;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,8BAA8B,MAGzB;AACD,UAAM,WAAW,KAAK,yBAAyB;AAC/C,WAAO;AAAA,MACH,mBAAmB,SAAS;AAAA,MAC5B,gBAAgB,SAAS;AAAA,IAC7B;AAAA,EACJ;AAAA;AAAA,EAGA,MAAM,aAAa,QAA2B;AAC1C,QAAI,WAAW;AAEf,QAAI,sBAAuC,CAAC;AAC5C,QAAI,KAAK,sBAAsB,UAAU,MAAM,MAAM;AACjD,4BAAsB;AAAA,QAClB;AAAA,QACA,KAAK,sBAAsB,eACrB,KAAK,sBAAsB,aAAa,IACxC,CAAC;AAAA,MACX;AAAA,IACJ;AAEA,QAAI,uBAAwC,CAAC;AAC7C,QAAI,KAAK,yBAAyB,UAAU,MAAM,MAAM;AACpD,6BAAuB;AAAA,QACnB;AAAA,QACA,KAAK,yBAAyB,eACxB,KAAK,yBAAyB,aAAa,IAC3C,CAAC;AAAA,MACX;AAAA,IACJ;AAEA,UAAM,aAAY,oBAAI,KAAK,GAAE,QAAQ;AAErC,qBAAiB,OAAO,KAAK,YAAY,MAAM,GAAG;AAE9C,WAAK,WAAW,KAAK,KAAK,uBAAuB,GAAG;AAChD,cAAM,KAAK,mBAAmB;AAAA,MAClC;AAEA,YAAM,gBAAgB,IAAI;AAAA,QACtB,EAAE,GAAG,IAAI;AAAA,QACT,KAAK;AAAA,MACT;AAEA,UAAI,CAAC,KAAK,UAAU;AAChB,cAAM,KAAK,OAAO,OAAO,aAAa;AAAA,MAC1C;AAEA,YAAMD,UAAS;AAAA,QAAI,KAAK;AAAA,QAAU,OAAO,UAAU;AAC/C,gBAAM,MAAM,UAAU,GAAG;AACzB,iBAAO,MAAM,aAAa,GAAG;AAAA,QACjC;AAAA,QACI;AAAA,UACI,aAAa,KAAK;AAAA,QACtB;AAAA,MAAC;AACL,WAAK,sBAAsB,GAAG;AAC9B,0BAAoB,QAAQ,CAAC,WAAW;AACpC,eAAO,UAAU;AAAA,MACrB,CAAC;AACD,kBAAY;AAEZ,UAAI,WAAW,QAAS,GAAG;AACvB,cAAM,aAAa,KAAK,YAClB,KAAK,KAAK,MAAO,WAAW,KAAK,YAAa,GAAG,CAAC,OAClD;AACN,eAAO,KAAK,kBAAa,KAAK,QAAQ,MAAM,QAAQ,4BAA4B,UAAU,EAAE;AAAA,MAChG;AAAA,IACJ;AAEA,UAAM,mBAAmB,aAAa,YAAY;AAClD,UAAM,QAAQ,iBAAiB,YAAY,KAAK,QAAQ;AACxD,UAAM,WAAW,6BAA6B,KAAK;AACnD,qBAAiB,YAAY,KAAK,UAAU,QAAQ;AAEpD,QAAI,CAAC,QAAQ;AACT,aAAO,KAAK,qCAAgC,KAAK,QAAQ,KAAK,QAAQ,WAAW;AAAA,IACrF,OAAO;AACH,aAAO,MAAM,yCAAoC,KAAK,QAAQ,KAAK,QAAQ,WAAW;AAAA,IAC1F;AAEA,UAAM,KAAK,mBAAmB;AAC9B,UAAM,WAAU,oBAAI,KAAK,GAAE,QAAQ;AACnC,UAAM,kBAAkB,UAAU;AAClC,yBAAqB,QAAQ,YAAU;AACnC,aAAO,UAAU,eAAe;AAAA,IACpC,CAAC;AAAA,EAEL;AAAA;AAAA,EAIA,UAAU,QAA2B;AACjC,WAAO,QAAQ,QAAQ;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAyC;AACrC,WAAO,MAAM,WAAW,KAAK,QAAQ,0BAA0B;AAC/D,QAAI,KAAK,YAAY;AACjB,YAAM,SAAS,SAAS,WAAW,KAAK,UAAU,EAAE;AACpD,aAAO,QAAQ,QAAQ,EAAE,YAAY,OAAO,CAAC;AAAA,IACjD,OAAO;AACH,UAAI,KAAK,UAAU;AACf,eAAO,QAAQ,QAAQ,MAAS;AAAA,MACpC;AACA,YAAM,IAAI,MAAM,UAAU,KAAK,QAAQ;AAAA;AAAA,2DAEQ;AAAA,IACnD;AAAA,EACJ;AAAA,EAEA,cAA2C;AACvC,WAAO,QAAQ,QAAQ,MAAS;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,QAA8B;AACtC,UAAM,IAAI,MAAM,6DAA6D;AAAA,EACjF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,0BAA6C;AACzC,WAAO,QAAQ,QAAQ,CAAC,CAAC;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,SAAwB;AAC1B,UAAM,QAAQ,QAAQ;AAAA,EAC1B;AACJ;;;AG7eA,OAAO,mBAAmB;AAG1B,IAAM,cAAc;AACpB,IAAM,uBAAuB;AAC7B,IAAM,qBAAqB;AAC3B,IAAM,eAAe;AAErB,SAAS,oBAAoB,OAAY,QAAgB,GAAQ;AAC7D,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,SAAS,aAAc,QAAO;AAElC,MAAI,OAAO,UAAU,UAAU;AAC3B,QAAI,MAAM,UAAU,qBAAsB,QAAO;AACjD,UAAM,YAAY,MAAM,MAAM,GAAG,oBAAoB;AACrD,WAAO,GAAG,SAAS,WAAM,MAAM,SAAS,oBAAoB;AAAA,EAChE;AAEA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACtB,UAAM,QAAQ,MACT,MAAM,GAAG,kBAAkB,EAC3B,IAAI,CAAC,MAAM,oBAAoB,GAAG,QAAQ,CAAC,CAAC;AACjD,UAAM,eAAe,KAAK,IAAI,GAAG,MAAM,SAAS,kBAAkB;AAClE,QAAI,eAAe,GAAG;AAClB,YAAM,KAAK,WAAM,YAAY,cAAc;AAAA,IAC/C;AACA,WAAO;AAAA,EACX;AAEA,MAAI,cAAc,KAAK,GAAG;AACtB,UAAM,OAAO,OAAO,KAAK,KAAK;AAC9B,UAAM,SAA8B,CAAC;AACrC,eAAW,OAAO,KAAK,MAAM,GAAG,WAAW,GAAG;AAC1C,aAAO,GAAG,IAAI,oBAAqB,MAAc,GAAG,GAAG,QAAQ,CAAC;AAAA,IACpE;AACA,UAAM,eAAe,KAAK,IAAI,GAAG,KAAK,SAAS,WAAW;AAC1D,QAAI,eAAe,GAAG;AAClB,MAAC,OAAe,eAAe,IAAI;AAAA,IACvC;AACA,WAAO;AAAA,EACX;AAEA,SAAO;AACX;AAEO,SAAS,yBAAyB,QAAkB;AACvD,MAAI;AACA,WAAO,oBAAoB,MAAM;AAAA,EACrC,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;;;AJvCA,OAAOE,gBAAe;AACtB,OAAO,aAAa;AAMb,IAAe,aAAf,cACK,OAAgB;AAAA,EAExB;AAAA,EAEA,YACI,QACA,OACA,QACA,mBAA2B,gCAC7B;AACE,UAAM,QAAQ,OAAO,QAAQ,gBAAgB;AAC7C,SAAK,sBAAsB;AAAA,MACvB,WAAW,MAAM,CAAC,KAAK;AAAA,MACvB,cAAc,MAAM,CAAC,KAAK,QAAQ;AAAA,IACtC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,kBAAkB,OAAO,eAAgC,WACpB;AAEjC,UAAM,SAAS,KAAK;AACpB,UAAM,MAAM,KAAK,WAAW,eAAe,MAAM;AACjD,QAAI,CAAC,KAAK;AACN,YAAM,IAAI,MAAM,aAAa,KAAK,QAAQ,wEAAwE;AAAA,IACtH;AAEA,UAAM,gBAAgB,KAAK;AAK3B,QAAI,WAAW;AACf,QAAI,iBAAsC,CAAC;AAC3C,UAAM,aAAa,IAAI,QAAQ,GAAG;AAClC,QAAI,eAAe,IAAI;AACnB,iBAAW,IAAI,UAAU,GAAG,UAAU;AACtC,YAAM,iBAAiB,IAAI,UAAU,aAAa,CAAC;AACnD,uBAAoB,UAAM,cAAc;AAAA,IAC5C;AAEA,UAAM,SAAS;AAAA,MACX,GAAG,KAAK,iBAAiB,eAAe,MAAM;AAAA;AAAA;AAAA,MAG9C,GAAG;AAAA,MACH,GAAI,MAAM,eAAe,UAAU,KAAK,MAAM;AAAA,IAClD;AAEA,UAAM,cAAc,KAAK,0BAA0B,eAAe,MAAM;AACxE,QAAI,UAAU,KAAK,qBAAqB,MAAM;AAC9C,QAAI,CAAC,SAAS;AACV,gBAAU,CAAC;AAAA,IACf;AAEA,QAAI,eAAe;AACf,YAAM,cAAc,MAAM,cAAc,eAAe,KAAK,MAAM;AAClE,gBAAU;AAAA,QACN,GAAG;AAAA,QACH,GAAG;AAAA,MACP;AAAA,IACJ;AAEA,UAAM,mBAAmB,CAACC,YAAgB;AACtC,aAAU,cAAUA,SAAQ,EAAE,aAAa,SAAS,CAAC;AAAA,IACzD;AAEA,UAAM,UAA8B;AAAA,MAChC,KAAK;AAAA,MACL;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAAA,EAEA,MAAM,kBAAkB,SAA6B,gBAAoD;AACrG,QAAI;AACA,aAAO;AAAA,QAAM,aAAM,QAAQ,MAAM,IAAI,QAAQ,GAAG;AAAA,QAC5C,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,EAAE,SAAS,eAAe;AAAA,MAAC;AAC/B,aAAO;AAAA,QAAK,aAAM,QAAQ,MAAM,IAAI,QAAQ,GAAG;AAAA,QAC3C,yBAAyB,QAAQ,MAAM;AAAA,QACvC,EAAE,SAAS,eAAe;AAAA,MAAC;AAC/B,YAAM,gBAAgB,KAAK;AAC3B,UAAI,CAAC,eAAe;AAChB,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACxD;AACA,YAAM,WAAW,MAAM,cAAc,QAAW,OAAO;AACvD,aAAO,SAAS;AAAA,IACpB,SAAS,KAAK;AACV,UAAIC,OAAM,aAAa,GAAG,GAAG;AACzB,eAAO;AAAA,UAAM,sBAAe,QAAQ,MAAM,IAAI,QAAQ,GAAG;AAAA,UACrD,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,IAAI;AAAA,UACJ,IAAI,UAAU;AAAA,QAClB;AACA,cAAM,iBAAiB,MAAM,KAAK,iBAAiB,QAAQ,KAAK,GAAG;AACnE,YAAI,mBAAmB,QAAW;AAC9B,iBAAO;AAAA,QACX,OAAO;AACH,iBAAO;AAAA,QACX;AAAA,MACJ,OAAO;AACH,cAAM;AAAA,MACV;AAAA,IACJ;AAAA,EACJ;AAAA,EAEA,OAAO,gBAAgB,QAA8B;AACjD,QAAI,gBAAiC;AACrC,QAAI,WAAW;AAEf,QAAI,kBAAmC,CAAC;AACxC,QAAI,KAAK,oBAAoB,UAAU,MAAM,MAAM;AAC/C,wBAAkB;AAAA,QACd;AAAA,QACA,KAAK,oBAAoB,eACnB,KAAK,oBAAoB,aAAa,IACtC,CAAC;AAAA,MACX;AAAA,IACJ;AAIA,SAAK,gBAAgB,iBAAiB,KAAK,cAAc;AAEzD,WAAO,CAAC,UAAU;AACd,YAAM,kBAAkB,MAAM,KAAK,gBAAgB,eAAe,MAAM;AACxE,YAAM,OAAO,MAAM,KAAK,kBAAkB,eAAe;AAEzD,sBAAgB,QAAQ,YAAU;AAC9B,eAAO,UAAU;AAAA,MACrB,CAAC;AAGD,UAAI,SAAS,aAAa;AACtB;AAAA,MACJ;AACA,YAAM,OAAO,KAAK,cAAc,MAAM,QAAQ,aAAa;AAC3D,uBAAiB,OAAO,MAAM;AAC1B,cAAM;AAAA,MACV;AAEA,YAAM,gBAAgBF,WAAU,aAAa;AAC7C,sBAAgB,KAAK,iBAAiB,MAAM,aAAa;AAEzD,UAAI,iBAAiB,QAAQ,eAAe,aAAa,GAAG;AACxD,cAAM,IAAI;AAAA,UACN,GAAG,KAAK,QAAQ;AAAA,0CACM,KAAK,UAAU,aAAa,CAAC,oCAAoC,KAAK,UAAU,aAAa,CAAC;AAAA,QACxH;AAAA,MACJ;AAEA,iBAAW,CAAC;AAAA,IAChB;AAAA,EACJ;AAAA,EAEA,OAAO,YAAY,QAA8B;AAC7C,qBAAiB,OAAO,KAAK,gBAAgB,MAAM,GAAG;AAClD,YAAM;AAAA,IACV;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,aAAyB;AAAA,EACzB,UAAkB;AAAA,EAClB,OAAe;AAAA,EACf,iBAAiB;AAAA,EACjB;AAAA,EAEA;AAAA;AAAA,EAGA,MAAM,iBAAiB,KAAyB,KAAyC;AACrF,SAAK,IAAI,UAAU,UAAU,KAAK,KAAK;AACnC,YAAM,IAAI,MAAM,cAAc,IAAI,UAAU,MAAM,mCAAmC,GAAG;AAAA;AAAA,6CAEvD,KAAK,UAAU,IAAI,UAAU,IAAI,CAAC,EAAE;AAAA,IACzE;AACA,UAAM;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiB,eAAgC,QAAuB;AACpE,WAAO,CAAC;AAAA,EACZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,0BAA0B,eAAgC,QAAiB;AACvE,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,iBAAiB,UAAa,eAAsC;AAChE,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,qBAAqB,QAAqC;AACtD,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAW,eAAoB,QAAoB;AAC/C,UAAM,aAAa,CAAC,KAAK,SAAS,KAAK,IAAI,EAAE,KAAK,EAAE;AACpD,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,cACH,UACA,QACA,eACgB;AAChB,QAAI,MAAM,QAAQ,QAAQ,GAAG;AACzB,iBAAW,OAAO,UAAU;AACxB,cAAM;AAAA,MACV;AAAA,IACJ,OAAO;AACH,YAAM;AAAA,IACV;AAAA,EACJ;AAEJ;;;AK/RA,OAAO,WAAW;AAMX,IAAe,6BAAf,MAA0C;AAAA,EAE7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAEhB;AAAA,EAEA,YACI,UACA,UACA,QACA,OACA,mBACF;AACE,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,SAAK,SAAS;AACd,SAAK,QAAQ;AAEb,SAAK,cAAc,CAAC;AACpB,SAAK,kBAAkB,CAAC;AACxB,SAAK,qBAAqB;AAAA,EAC9B;AAAA,EASA,4BAA4B,SAAiB,eAA2C;AACpF,WAAO,GAAG,OAAO,KAAK,aAAa;AAAA,EACvC;AAAA;AAAA,EA2BA,0BAA0B,OACtB,iBACA,gBACC;AACD,UAAM,KAAK,mCAAmC,CAAC;AAE/C,SAAK,kBAAkB;AAEvB,SAAK,mBAAmB;AAAA,MACpB,KAAK;AAAA,MACL;AAAA,IACJ;AAEA,SAAK,cAAc,YAAY,IAAI,QAAM;AACrC,aAAO,KAAK,mBAAmB,qBAAqB,KAAK,UAAU,EAAE;AAAA,IACzE,CAAC;AAED,UAAM,KAAK,6BAA6B;AAAA,EAC5C;AAAA,EAEA,cAAc,QAAkB;AAC5B,UAAM,oBAAyB,CAAC;AAEhC,WAAO,KAAK,MAAM,EAAE,QAAQ,qBAAmB;AAC3C,wBAAkB,KAAK,mBAAmB,qBAAqB,KAAK,UAAU,eAAe,CAAE,IAAI,OAAO,eAAe;AAAA,IAC7H,CAAC;AACD,WAAO;AAAA,EACX;AAAA;AAAA,EAGU,sBAAsB,OAAO,YAAqC;AACxE,UAAM;AAAA,MACF,YAAY;AACR,cAAM,KAAK,WAAW,OAAO;AAAA,MACjC;AAAA,MACA;AAAA,QACI,SAAS;AAAA,MACb;AAAA,IACJ;AAAA,EACJ;AAAA,EAEQ,+BAA+B,YAAY;AAE/C,UAAM,SAAS,MAAM,KAAK,kBAAkB;AAC5C,UAAM,cAAc,OAAO,OAAO,WAAS,KAAK,UAAU,MAAM,SAAS;AAEzE,QAAI,YAAY,WAAW,GAAG;AAC1B,aAAO,KAAK,yBAAkB,KAAK,QAAQ,iBAAiB,KAAK,MAAM,gBAAgB,KAAK,KAAK,gDAAgD;AACjJ,YAAM,KAAK,YAAY;AAAA,IAC3B,WAAW,YAAY,WAAW,GAAG;AACjC,aAAO,KAAK,yBAAkB,KAAK,QAAQ,iBAAiB,KAAK,MAAM,gBAAgB,KAAK,KAAK,oDAAoD;AACrJ,YAAM,KAAK,mBAAmB;AAAA,IAClC;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,sBAAsB,OAAO,gBAAsC;AAEvE,QAAI,YAAY,SAAS,GAAG;AACxB,aAAO,KAAK,qBAAc,KAAK,QAAQ,yDAAyD,KAAK,UAAU,WAAW,CAAC,EAAE;AAE7H,YAAM,uBAAuB,MAAM,KAAK,6BAA6B;AACrE,YAAM,2BAA2B,qBAAqB,IAAI,SAAO,IAAI,IAAI;AAEzE,UAAI,8BAAoD,CAAC;AACzD,kBAAY,QAAQ,cAAY;AAC5B,cAAM,WAAW,SAAS;AAC1B,cAAM,wBAAwB,KAAK,+BAA+B,SAAS,UAAU;AACrF,cAAM,2BAA2B,KAAK,4BAA4B,UAAU,qBAAqB;AAGjG,aAAK,mBAAmB,6BAA6B,KAAK,QAAQ,EAAE,SAAS,UAAU,IAAI;AAE3F,YAAI,CAAC,yBAAyB,SAAS,wBAAwB,GAAG;AAC9D,sCAA4B,KAAK;AAAA,YAC7B,YAAY;AAAA,YACZ,MAAM;AAAA,YACN,YAAY,SAAS;AAAA,UACzB,CAAC;AAAA,QACL;AAAA,MACJ,CAAC;AAED,UAAI,4BAA4B,SAAS,GAAG;AACxC,cAAM,KAAK,WAAW,2BAA2B;AAAA,MACrD;AAAA,IACJ;AAAA,EACJ;AAAA,EAEQ,qBAAqB,YAAY;AAErC,UAAM,uBAAuB,MAAM,KAAK,6BAA6B;AACrE,UAAM,2BAA2B,qBAAqB,IAAI,SAAO,IAAI,IAAI;AAEzE,UAAM,sBAAsB,KAAK,mBAAmB,6BAA6B,KAAK,QAAQ;AAC9F,UAAM,eAAqC,OAAO,KAAK,mBAAmB,EACrE,OAAO,qBAAmB;AACvB,YAAMG,kBAAiB,oBAAoB,eAAe;AAC1D,UAAI,CAACA,iBAAgB;AACjB,eAAO;AAAA,MACX;AACA,aAAO,CAAC,yBAAyB,SAASA,eAAc;AAAA,IAC5D,CAAC,EACA,IAAI,qBAAmB;AACpB,YAAMA,kBAAiB,oBAAoB,eAAe;AAC1D,YAAM,aAAa,KAAK,gBAAgB,eAAe;AACvD,UAAI,CAACA,mBAAkB,CAAC,YAAY;AAChC,eAAO;AAAA,MACX;AACA,aAAO;AAAA,QACH,YAAY;AAAA,QACZ,MAAMA;AAAA,QACN;AAAA,MACJ;AAAA,IACJ,CAAC,EACA,OAAO,CAAC,SAAqC,CAAC,CAAC,IAAI;AAExD,UAAM,KAAK,WAAW,YAAY;AAElC,UAAM,mBAAyC,OAAO,KAAK,KAAK,eAAe,EAE1E,OAAO,qBAAmB;AACvB,YAAM,aAAa,KAAK,gBAAgB,eAAe;AACvD,UAAI,CAAC,YAAY;AACb,eAAO;AAAA,MACX;AACA,YAAM,wBAAwB,KAAK,+BAA+B,UAAU;AAC5E,UAAI,uBAAuB;AACvB,cAAM,WAAW,KAAK,eAAe,eAAe;AACpD,YAAI,yBAAyB,SAAS,QAAQ,GAAG;AAC7C,gBAAM,sBAAsB,qBAAqB,KAAK,SAAO,IAAI,SAAS,QAAQ;AAElF,cAAI,CAAC,qBAAqB;AACtB,kBAAM,IAAI,MAAM,wEAAwE,QAAQ,EAAE;AAAA,UACtG;AAEA,gBAAM,EAAE,KAAK,IAAI;AAEjB,cAAI,0BAA0B,MAAM;AAChC,mBAAO;AAAA,UACX;AAAA,QACJ;AAAA,MACJ;AACA,aAAO;AAAA,IACX,CAAC,EACA,IAAI,qBAAmB;AACpB,YAAM,aAAa,KAAK,gBAAgB,eAAe;AACvD,UAAI,CAAC,YAAY;AACb,eAAO;AAAA,MACX;AACA,aAAO;AAAA,QACH,YAAY;AAAA,QACZ,MAAM,KAAK,eAAe,eAAe;AAAA,QACzC;AAAA,MACJ;AAAA,IACJ,CAAC,EACA,OAAO,CAAC,eAAiD,CAAC,CAAC,UAAU;AAE1E,UAAM,KAAK,oBAAoB,gBAAgB;AAAA,EAEnD;AAAA,EAEA,gCAAgC,OAC5B,sBACC;AAED,QAAI,eAAyB,CAAC;AAC9B,QAAI,sBAAsB,cAAc;AACpC,qBAAe,KAAK,kBAAkB;AAAA,IAC1C,WAAW,sBAAsB,eAAe;AAC5C,qBAAe,KAAK,gBAAgB;AAAA,IACxC,WAAW,sBAAsB,UAAU;AACvC,qBAAe,KAAK,iBAAiB;AAAA,IACzC,WAAW,sBAAsB,aAAa;AAC1C,qBAAe,KAAK,gBAAgB;AAAA,IACxC;AAEA,WAAO,KAAK,mBAAY,KAAK,KAAK,uCAAuC,iBAAiB,EAAE;AAC5F,WAAO,MAAM,SAAS,KAAK,KAAK,wBAAwB,YAAY;AAEpE,UAAM,KAAK,oBAAoB,YAAY;AAAA,EAE/C;AAEJ;;;ACzQO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAE7C;AAAA,EACA;AAAA,EAEA,YAAY,SAAiB,UAAoBC,SAAuB;AACpE,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,WAAW;AAChB,SAAK,mBAAmBA;AAAA,EAC5B;AAEJ;AAEO,IAAM,4BAAN,cAAwC,MAAM;AAAA,EAEjD;AAAA,EAEA,YAAY,SAAiB,UAAoB;AAC7C,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EACpB;AAEJ;AAEO,IAAM,qBAAN,cAAiC,MAAM;AAAA,EAE1C;AAAA,EAEA,YAAY,SAAiB,UAAoB;AAC7C,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EACpB;AAEJ;;;ACrCO,IAAM,2BAA2B,CAAC,QAAa,WAA4B;AAC9E,QAAM,aAAa,OAAO,KAAK,MAAM;AACrC,SAAO,KAAK,MAAM,EAAE,QAAQ,SAAO;AAC/B,QAAI,CAAC,WAAW,SAAS,GAAG,GAAG;AAC3B,aAAO,OAAO,GAAG;AAAA,IACrB;AAAA,EACJ,CAAC;AAED,SAAO;AACX;AAEO,IAAM,iBAAiB,CAAC,QAAa,cAAsB;AAC9D,SAAO;AAAA,IACH,GAAG;AAAA,IACH,eAAe;AAAA,EACnB;AACJ;;;ACAO,IAAM,oBAAN,MAAwB;AAAA;AAAA,EAGnB;AAAA,EAEA;AAAA,EAER,cAAc;AACV,SAAK,iBAAiB,CAAC;AAAA,EAC3B;AAAA,EAEA,6BAA6B,CAAC,OAAwC;AAClE,SAAK,0BAA0B;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,6BAA6B,CACzB,UACA,oBACC;AACD,UAAM,kBAAkB,KAAK;AAC7B,QAAI,CAAC,iBAAiB;AAClB,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC7D;AACA,UAAM,yBAAyB,OAAO,KAAK,eAAe,EACrD,KAAK,EACL,OAA0C,CAAC,KAAK,kBAAkB;AAC/D,YAAM,cAAc,gBAAgB,aAAa;AACjD,UAAI,CAAC,IAAI,WAAW,GAAG;AACnB,YAAI,WAAW,IAAI;AAAA,MACvB,OAAO;AACH,eAAO,KAAK,qBAAc,QAAQ,0EAA0E,aAAa;AAAA,yCACpG,aAAa,uBAAuB,IAAI,WAAW,CAAC,EAAE;AAC3E,iBAAS,IAAI,KAAK,KAAK;AACnB,cAAI,CAAC,IAAI,GAAG,WAAW,IAAI,CAAC,EAAE,GAAG;AAC7B,gBAAI,GAAG,WAAW,IAAI,CAAC,EAAE,IAAI;AAC7B;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AACA,aAAO;AAAA,IACX,GAAG,CAAC,CAAC;AAET,UAAM,yBAAyB,OAAO,KAAK,sBAAsB,EAC5D,OAA6C,CAAC,KAAK,gBAAgB;AAChE,YAAM,gBAAgB,uBAAuB,WAAW;AACxD,UAAI,eAAe;AACf,YAAI,aAAa,IAAI;AAAA,MACzB;AACA,aAAO;AAAA,IACX,GAAG,CAAC,CAAC;AAGT,UAAM,UAAU,KAAK,eAAe,QAAQ,KAAK,CAAC;AAClD,SAAK,eAAe,QAAQ,IAAI;AAChC,WAAO,KAAK,sBAAsB,EAAE,QAAQ,mBAAiB;AACzD,YAAM,WAAW,uBAAuB,aAAa;AACrD,UAAI,UAAU;AACV,gBAAQ,aAAa,IAAI;AAAA,MAC7B;AAAA,IACJ,CAAC;AAAA,EACL;AAAA,EAEA,uBAAuB,CACnB,UACA,uBACS;AACT,QAAI,CAAC,KAAK,eAAe,QAAQ,GAAG;AAChC,YAAM,IAAI;AAAA,QACN,YAAY,QAAQ;AAAA,0DACsB,kBAAkB;AAAA,MAChE;AAAA,IACJ;AACA,UAAM,QAAQ,KAAK,eAAe,QAAQ,EAAE,kBAAkB;AAC9D,QAAI,CAAC,OAAO;AACR,YAAM,IAAI,MAAM,YAAY,QAAQ,yCAAyC,kBAAkB,GAAG;AAAA,IACtG;AACA,WAAO;AAAA,EACX;AAAA,EAEA,+BAA+B,CAAC,aAAqD;AACjF,UAAM,UAAU,KAAK,eAAe,QAAQ;AAC5C,QAAI,CAAC,SAAS;AACV,YAAM,IAAI,MAAM,YAAY,QAAQ,8CAA8C;AAAA,IACtF;AACA,WAAO;AAAA,EACX;AAAA,EAEA,UAAU,CAAC,aAA8B;AACrC,QAAI,CAAC,KAAK,eAAe,QAAQ,GAAG;AAChC,aAAO;AAAA,IACX,OAAO;AACH,aAAO;AAAA,IACX;AAAA,EACJ;AACJ;;;AC9GO,IAAM,gBAAgB,CAAI,UAAoB,WAA+B;AAEhF,SAAO,MAAM,iCAAiC,QAAQ,EAAE;AAExD,MAAI;AACA,UAAM,UAAU;AAEhB,QAAI,CAAC,QAAQ,YAAY,GAAG;AACxB,aAAO,CAAC;AAAA,IACZ;AAEA,UAAM,aAAa,QAAQ,YAAY;AAEvC,UAAM,kBAAkB,OAAO,KAAK,UAAU,EAAE,OAAwB,CAAC,KAAK,iBAAiB;AAC3F,YAAM,iBAAiB,WAAW,YAAY;AAC9C,YAAM,aAAa;AAEnB,UAAI,CAAC,gBAAgB;AACjB,eAAO;AAAA,MACX;AAEA,UAAI,CAAC,eAAe,MAAM,GAAG;AACzB,cAAM,IAAI,MAAM,kDAAkD,YAAY;AAAA,yCACrD,KAAK,UAAU,cAAc,CAAC,EAAE;AAAA,MAC7D;AAEA,UAAI,UAAU,IAAI;AAAA,QACd,MAAM,eAAe,MAAM;AAAA,QAC3B,QAAQ,eAAe,QAAQ;AAAA,QAC/B,OAAO,eAAe,OAAO;AAAA,MACjC;AAEA,aAAO;AAAA,IACX,GAAG,CAAC,CAAC;AAEL,WAAO;AAAA,EACX,SAAS,KAAU;AACf,WAAO,MAAM,6DAA6D,QAAQ,YAAY,IAAI,OAAO,MAAM,IAAI,KAAK;AAAA,wBACxG,KAAK,UAAU,MAAM,CAAC,EAAE;AACxC,iBAAa,CAAC;AACd,WAAO,CAAC;AAAA,EACZ;AAEJ;;;AC9CA,OAAO,SAAS;AAChB,OAAO,gBAAgB;AACvB,OAAOC,YAAsB;;;ACJ7B,OAAOC,YAAsB;;;ACA7B,OAAOC,SAAQ;AACf,OAAO,cAAc;AAId,IAAM,4BAA4B,CAAC,aAAiC;AACvE,EAAAA,IAAG,cAAc,OAAO;AACxB,QAAMC,QAAO,SAAS,SAAS,QAAQ,CAAC,IAAI,SAAS,CAAC;AACtD,QAAM,cAAcD,IAAG,kBAAkBC,OAAM,EAAC,OAAO,IAAG,CAAC;AAE3D,SAAO;AAAA,IACH,QAAQ;AAAA,IACR,MAAAA;AAAA,EACJ;AACJ;AAEO,SAAS,SAASA,OAAsB;AAC3C,MAAI,gBAAgBA;AACpB,kBAAgB,cAAc,QAAQ,aAAa,EAAE;AACrD,kBAAgB,cAAc,QAAQ,gGAAgG,EAAE;AACxI,kBAAgB,cAAc,QAAQ,SAAS,GAAG;AAClD,kBAAgB,cAAc,QAAQ,cAAc,EAAE;AACtD,kBAAgB,gBAAgB,aAAa;AAC7C,kBAAgB,eAAe,aAAa;AAC5C,kBAAgB,cAAc,QAAQ,oBAAoB,GAAG;AAE7D,SAAO;AACX;AAEA,SAAS,gBAAgB,KAAa;AAClC,QAAM,IAAI,QAAQ,sCAAsC,GAAG;AAC3D,QAAM,IAAI,QAAQ,aAAa,GAAG;AAClC,QAAM,IAAI,QAAQ,4BAA4B,GAAG;AACjD,QAAM,IAAI,QAAQ,4BAA4B,GAAG;AACjD,QAAM,IAAI,QAAQ,iCAAiC,GAAG;AACtD,QAAM,IAAI,QAAQ,4BAA4B,GAAG;AACjD,QAAM,IAAI,QAAQ,kBAAkB,GAAG;AACvC,QAAM,IAAI,QAAQ,aAAa,GAAG;AAClC,QAAM,IAAI,QAAQ,aAAa,IAAI;AACnC,QAAM,IAAI,QAAQ,aAAa,IAAI;AACnC,QAAM,IAAI,QAAQ,sCAAsC,GAAG;AAC3D,QAAM,IAAI,QAAQ,aAAa,GAAG;AAClC,QAAM,IAAI,QAAQ,4BAA4B,GAAG;AACjD,QAAM,IAAI,QAAQ,4BAA4B,GAAG;AACjD,QAAM,IAAI,QAAQ,iCAAiC,GAAG;AACtD,QAAM,IAAI,QAAQ,4BAA4B,GAAG;AACjD,QAAM,IAAI,QAAQ,kBAAkB,GAAG;AACvC,QAAM,IAAI,QAAQ,aAAa,GAAG;AAClC,QAAM,IAAI,QAAQ,aAAa,IAAI;AACnC,SAAO;AACX;AAEA,SAAS,eAAe,KAAa;AACjC,QAAM,IAAI,QAAQ,cAAc,EAAE;AAClC,QAAM,IAAI,QAAQ,cAAc,EAAE;AAClC,QAAM,IAAI,QAAQ,WAAW,GAAG;AAChC,QAAM,IAAI,QAAQ,YAAY,GAAG;AACjC,SAAO;AACX;;;ADnDA,YAAYC,SAAQ;AAIb,IAAM,cAAN,MAAkB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA;AAAA,EAGA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA,EAEA;AAAA;AAAA,EAGA;AAAA,EAEA,YACI,UACA,QACA,mBACE;AACF,SAAK,WAAW;AAChB,SAAK,SAAS;AAEd,SAAK,kBAAkB;AACvB,SAAK,aAAa,0BAA0B,QAAQ;AACpD,SAAK,iBAAiB;AACtB,SAAK,gBAAgB,CAAC;AACtB,SAAK,YAAYC,OAAM;AACvB,SAAK,oBAAoB;AACzB,SAAK,kCAAkC;AAAA,EAC3C;AAAA,EAEA,UAAU,QAAyB;AAC/B,SAAK,SAAS;AAAA,EAClB;AAAA,EAEA,YAAyC;AACrC,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,sBAAsB,IAAsB;AACxC,SAAK,qBAAqB;AAAA,EAC9B;AAAA,EAEA,wBAAsD;AAClD,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,eAAuB;AACnB,WAAO,KAAK,UAAU,OAAO,qBAAqB;AAAA,EACtD;AAAA,EAEA,qBAA6B;AACzB,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,2BAA2B;AACvB,SAAK,mBAAmB;AAAA,EAC5B;AAAA,EAEA,gBAA0B;AACtB,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,kBAAkB;AACd,SAAK,WAAW,OAAO,MAAM;AAC7B,UAAM,UAAU,KAAK,WAAW;AAEhC,IAAG,eAAW,OAAO;AACrB,SAAK,aAAa,0BAA0B,KAAK,QAAQ;AACzD,SAAK,kBAAkB;AAAA,EAC3B;AAAA,EAEA,mBAA6B;AACzB,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,iBAAiB,eAAyB;AACtC,SAAK,gBAAgB;AAAA,EACzB;AAAA,EAEA,YAAwC;AACpC,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,uBAA0C;AACtC,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,qBAAqB,GAAsB;AACvC,SAAK,oBAAoB;AAAA,EAC7B;AAAA,EAEA,sBAAsB;AAClB,SAAK,kCAAkC;AAAA,EAC3C;AACJ;;;ADxGA,SAAS,iBAAiB;AAE1B,OAAOC,eAAc;AAIrB,IAAM,YAAY,IAAI,UAAU,CAAC;AAE1B,IAAe,UAAf,MAAe,SAA2C;AAAA,EAC7D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA,EAIA;AAAA,EAEA;AAAA,EAEA;AAAA;AAAA,EAKA;AAAA,EAEA,YAAY,QAAW,eAA8B;AACjD,SAAK,SAAS;AACd,SAAK,gBAAgB;AACrB,SAAK,cAAc,CAAC;AAEpB,SAAK,UAAU,CAAC;AAEhB,SAAK,eAAe,CAAC;AACrB,SAAK,eAAe,CAAC;AAErB,SAAK,MAAM,WAAW,IAAI,IAAI,EAAE,WAAW,MAAM,QAAQ,MAAM,CAAC,CAAC;AACjE,SAAK,WAAWC,OAAM;AAEtB,SAAK,oBAAoB,IAAI,kBAAkB;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,qBAA+B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAsB/B,uBAAuB,CAC3B,gBACA,WACA,aACqD;AACrD,UAAM,UAAoB,CAAC;AAC3B,QAAI,qBAAqB;AAGzB,UAAM,cAAc,IAAI,IAAI,OAAO,KAAK,cAAc,EAAE,OAAO,SAAO,CAAC,IAAI,WAAW,QAAQ,CAAC,CAAC;AAChG,UAAM,aAAa,IAAI,IAAI,OAAO,KAAK,SAAS,EAAE,OAAO,SAAO,CAAC,IAAI,WAAW,QAAQ,CAAC,CAAC;AAG1F,eAAW,cAAc,YAAY;AACjC,UAAI,CAAC,YAAY,IAAI,UAAU,GAAG;AAC9B,gBAAQ,KAAK,iBAAiB,UAAU,GAAG;AAAA,MAC/C;AAAA,IACJ;AAGA,eAAW,cAAc,aAAa;AAClC,UAAI,CAAC,WAAW,IAAI,UAAU,GAAG;AAC7B,gBAAQ,KAAK,mBAAmB,UAAU,GAAG;AAC7C,6BAAqB;AAAA,MACzB;AAAA,IACJ;AAGA,eAAW,cAAc,aAAa;AAClC,UAAI,WAAW,IAAI,UAAU,GAAG;AAC5B,cAAM,WAAW,eAAe,UAAU;AAC1C,cAAM,UAAU,UAAU,UAAU;AAGpC,YAAI,KAAK,UAAU,QAAQ,MAAM,KAAK,UAAU,OAAO,GAAG;AACtD,kBAAQ,KAAK,2BAA2B,UAAU,GAAG;AACrD,+BAAqB;AAAA,QACzB;AAAA,MACJ;AAAA,IACJ;AAEA,QAAI,QAAQ,WAAW,GAAG;AACtB,cAAQ,KAAK,4BAA4B;AAAA,IAC7C;AAEA,WAAO,MAAM,YAAY,QAAQ,uBAAuB,qBAAqB,aAAa,cAAc,mBAAmB,QAAQ,KAAK,IAAI,CAAC,EAAE;AAE/I,WAAO,EAAE,oBAAoB,QAAQ;AAAA,EACzC;AAAA;AAAA,EAGA,sBAAsB,CAAC,UAAkB,WAAwB;AAC7D,UAAM,SAAS,KAAK,QAAQ,QAAQ;AACpC,QAAI,CAAC,QAAQ;AACT,YAAM,IAAI,mBAAmB,yBAAyB,QAAQ,qDAAqD,QAAQ;AAAA,IAC/H;AACA,WAAO,OAAO,UAAU,EAAE,oBAAoB,MAAM;AAAA,EACxD;AAAA,EAEA,SAAS,OAAO,YAA0C;AACtD,QAAI;AAEA,YAAM,WAAW,QAAQ;AACzB,YAAM,SAAS,KAAK,QAAQ,QAAQ;AAEpC,UAAI,CAAC,QAAQ;AACT,cAAM,IAAI,mBAAmB,yBAAyB,QAAQ,qDAAqD,QAAQ;AAAA,MAC/H;AAKA,UAAI,OAAO,mBAAmB,IAAI,QAAW,GAAG;AAC5C,cAAM,UAAU,aAAa,YAAY;AACrC,gBAAM,gCAAgC,KAAK,8BAA8B,QAAQ;AACjF,cAAI,+BAA+B;AAC/B,kBAAM,KAAK,0BAA0B,EAAE,aAAa,MAAM,CAAC;AAAA,UAC/D;AAAA,QACJ,CAAC;AAAA,MACL;AAEA,YAAM,SAAS,QAAQ;AACvB,YAAM,SAAS,OAAO,UAAU;AAEhC,UAAI,CAAC,QAAQ;AACT,eAAO,KAAK,WAAW,QAAQ,2EAA2E;AAC1G;AAAA,MACJ;AAEA,YAAM,kCAAkC,yBAAyB,QAAQ,MAAM;AAE/E,YAAM,wBAAwB,eAAe,iCAAiC,OAAO,aAAa,CAAC;AAInG,YAAM,aAAa,OAAO,sBAAsB;AAChD,UAAI,cAAc,CAAC,WAAW,qBAAqB,GAAG;AAClD,cAAM,IAAI,sBAAsB,WAAW,QAAQ;AAAA,qCAC9B,KAAK,UAAU,WAAW,MAAM,CAAC;AAAA;AAAA,0BAE5C,KAAK,UAAU,+BAA+B,CAAC;AAAA,0BAC/C,KAAK,UAAU,OAAO,UAAU,CAAC,CAAC,IAAI,UAAU,WAAW,UAAU,CAAC,CAAC;AAAA,MACrF;AAGA,YAAM,sBAAsB,KAAK,kBAAkB,uBAAuB,MAAM;AAEhF,YAAM,oBAAoB,KAAK,yBAAyB,qBAAqB,MAAM;AAMnF,YAAM,iBAAiB,OAAO,UAAU;AACxC,YAAM,2BAA2B,eAAe,cAAc,iBAAiB;AAE/E,YAAM,mBAAmB,KAAK,oBAAoB,UAAU,wBAAwB;AAEpF,aAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACpC,eAAO,cAAc,EAAE,OAAO,MAAM,kBAAkB,CAAC,UAAU;AAC7D,cAAI,OAAO;AACP,mBAAO,KAAK;AAAA,UAChB;AAEA,iBAAO,yBAAyB;AAChC,kBAAQ;AAAA,QACZ,CAAC;AAAA,MACL,CAAC;AAAA,IAEL,SAAS,KAAK;AACV,aAAO,MAAM,sCAAsC;AACnD,YAAM;AAAA,IACV;AAAA,EACJ;AAAA,EAEQ,8BACJ,UACA,mBACI;AACJ,UAAM,iBAAiB,KAAK;AAAA,MACxB;AAAA,MACA,KAAK,OAAO;AAAA,MACZ,KAAK,OAAO;AAAA,MACZ,KAAK,aAAa,QAAQ;AAAA,IAC9B;AACA,SAAK,QAAQ,QAAQ,IAAI,IAAI;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AAAA,EACJ;AAAA,EAEA,oBAAoB,CAAC,YAA4C;AAE7D,QAAI;AACA,aAAO,KAAK,oDAA6C,OAAO;AAChE,YAAM,WAAW,QAAQ;AACzB,UAAI,CAAC,KAAK,QAAQ,QAAQ,GAAG;AACzB,aAAK,8BAA8B,UAAU,QAAQ,WAAW;AAAA,MACpE,OAAO;AACH,aAAK,QAAQ,QAAQ,EAAE,qBAAqB,QAAQ,WAAW;AAAA,MACnE;AAAA,IACJ,SAAS,KAAK;AACV,aAAO,MAAM,+CAA+C;AAC5D,YAAM;AAAA,IACV;AAAA,EACJ;AAAA,EAEA,SAAS,OAAO,YAA0C;AAEtD,QAAI;AACA,YAAM,WAAW,QAAQ;AAEzB,aAAO,KAAK,WAAW,QAAQ,sCAAsC;AACrE,aAAO,MAAM,WAAW,QAAQ,4CAA4C,OAAO;AAEnF,UAAI,CAAC,KAAK,QAAQ,QAAQ,GAAG;AACzB,aAAK,8BAA8B,QAAQ;AAAA,MAC/C,OAAO;AAEH,cAAM,kBAAkB,KAAK,QAAQ,QAAQ;AAC7C,YAAI,gBAAgB,kBAAkB,GAAG;AACrC,gBAAM,aAAa,gBAAgB,UAAU;AAC7C,cAAG,YAAY;AAEX,kBAAM,qBAAqB,cAAc,UAAU,QAAQ,MAAM;AAEjE,kBAAM,EAAE,oBAAoB,QAAQ,IAAI,KAAK,qBAAqB,YAAY,oBAAoB,QAAQ;AAC1G,gBAAI,oBAAoB;AACpB,qBAAO,KAAK,sBAAe,QAAQ,wCAAwC,QAAQ,KAAK,IAAI,CAAC,uDAAuD;AACpJ,oBAAM,SAAQ,8BAA8B,eAAe;AAAA,YAC/D,OAAO;AACH,qBAAO,KAAK,mBAAc,QAAQ,4CAA4C,QAAQ,KAAK,IAAI,CAAC,iDAAiD;AAAA,YACrJ;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAEA,YAAM,cAAc,KAAK,QAAQ,QAAQ;AACzC,UAAI,CAAC,aAAa;AACd,cAAM,IAAI,mBAAmB,WAAW,QAAQ,mEAAmE,QAAQ;AAAA,MAC/H;AACA,YAAM,SAAS,cAAc,UAAU,QAAQ,MAAM;AAGrD,aAAO,eAAe,IAAI;AAAA,QACtB,QAAQ;AAAA,QACR,MAAM,CAAC,QAAQ,QAAQ;AAAA,MAC3B;AAEA,YAAM,SAAS,YAAY,UAAU;AACrC,aAAO,KAAK,MAAM,EAAE,QAAQ,oBAAkB;AAE1C,cAAM,WAAW,OAAO,cAAc;AACtC,cAAM,sBAAsB,WAAW,OAAO,+BAA+B,QAAQ,IAAI;AAEzF,YAAI,CAAC,qBAAqB;AACtB,iBAAO,OAAO,cAAc;AAAA,QAChC;AAAA,MACJ,CAAC;AAED,kBAAY,UAAU,MAAM;AAC5B,kBAAY,sBAAsB,KAAK,IAAI,QAAQ,EAAE,MAAM,UAAU,YAAY,OAAO,CAAC,CAAC;AAE1F,YAAM,0BAA0B,KAAK,QAAQ,QAAQ,GAAG,qBAAqB;AAC7E,UAAI,QAAQ,cAAc,WAAW,KAAK,mDAAsD;AAC5F,cAAM,IAAI,MAAM,aAAa,QAAQ,MAAM;AAAA,uCACpB,KAAK,UAAU,OAAO,CAAC,EAAE;AAAA,MACpD;AAEA,kBAAY,iBAAiB,QAAQ,aAAa;AAElD,YAAM,OAAO,wBAAwB,QAAQ,QAAQ,aAAa;AAElE,YAAM;AAAA,QACF,UAAU;AAAA,QACV,QAAQ;AAAA,MACZ,IAAI,KAAK;AAET,YAAM,YAAY,KAAK,aAAa,QAAQ;AAE5C,YAAM,+BAA8C;AAAA,QAChD,GAAG;AAAA,QACH,eAAe,QAAQ,cAAc,IAAI,OAAK;AAC1C,gBAAM,cAAc,YAAY,UAAU,EAAE,mBAAmB,qBAAqB,QAAQ,QAAQ,CAAC;AACrG,cAAI,aAAa;AACb,mBAAO;AAAA,UACX;AACA,iBAAO;AAAA,QACX,CAAC;AAAA,MACL;AAEA,YAAMD,UAAS,IAAI,KAAK,aAAa,OAAO,SAAS;AACjD,cAAM,QAA+B;AAAA,UACjC;AAAA,UACA;AAAA,UACA;AAAA,UACA,SAAS;AAAA,QACb;AACA,cAAM,KAAK,YAAY,KAAK;AAAA,MAChC,GAAG,EAAE,aAAa,EAAE,CAAC;AAErB,aAAO,QAAQ,QAAQ;AAAA,IAC3B,SAAS,KAAK;AACV,aAAO,MAAM,qCAAqC,GAAG;AACrD,YAAM;AAAA,IACV;AAAA,EACJ;AAAA,EAEA,QAAQ,CAAC,YAAyC;AAE9C,QAAI;AACA,WAAK,eAAe,QAAQ;AAE5B,UAAI,CAAC,KAAK,cAAc;AACpB,aAAK,eAAe,OAAO,OAAO,CAAC,GAAG,KAAK,KAAK;AAAA,MACpD;AACA,aAAO,QAAQ,QAAQ;AAAA,IAC3B,SAAS,KAAK;AACV,aAAO,MAAM,mCAAmC;AAChD,YAAM;AAAA,IACV;AAAA,EACJ;AAAA,EAEA,WAAW,YAA2B;AAElC,QAAI;AACA,aAAO,KAAK,oFAA6E;AAEzF,YAAM,KAAK,0BAA0B,EAAE,aAAa,KAAK,CAAC;AAC1D,aAAO,QAAQ,QAAQ;AAAA,IAC3B,SAAS,KAAK;AACV,aAAO,MAAM,sCAAsC;AACnD,YAAM;AAAA,IACV;AAAA,EACJ;AAAA,EAEQ,gCAAgC,CAAC,aAA8B;AACnE,UAAM,SAAS,KAAK,QAAQ,QAAQ;AACpC,QAAI,CAAC,QAAQ;AACT,aAAO;AAAA,IACX;AACA,UAAM,iBAAiB,OAAO,mBAAmB;AACjD,UAAM,SAAS,OAAO,qBAAqB;AAC3C,SAAK,WAAW,iBAAiB,WAAW,aAAa,iBAAiB,KAAW;AACjF,aAAO,KAAK,oBAAa,QAAQ,4GAA4G;AAC7I,aAAO;AAAA,IACX,OAAO;AACH,aAAO;AAAA,IACX;AAAA,EACJ;AAAA,EAEQ,4BAA4B,OAAO,SAAkD;AACzF,WAAO,KAAK,+DAA0C;AACtD,UAAM,EAAE,YAAY,IAAI;AACxB,UAAM,8BAA8B,OAC/B,KAAK,KAAK,OAAO,EACjB,OAAO,cAAY;AAEhB,YAAM,IAAI,KAAK,QAAQ,QAAQ;AAC/B,UAAI,CAAC,GAAG;AACJ,eAAO;AAAA,MACX;AACA,UAAI,CAAC,eAAe,EAAE,qBAAqB,MAAM,cAAc;AAC3D,eAAO;AAAA,MACX;AACA,aAAO,EAAE,mBAAmB,IAAI;AAAA,IACpC,CAAC;AAEL,QAAI,4BAA4B,SAAS,GAAG;AACxC,WAAK,eAAe,MAAM,KAAK,yBAAyB,2BAA2B;AAAA,IACvF;AAEA,QAAI,OAAO,KAAK,KAAK,YAAY,EAAE,SAAS,GAAG;AAC3C,YAAM,KAAK,UAAU,OAAO,OAAO,CAAC,GAAG,KAAK,YAAY,CAAC;AAAA,IAG7D,OAAO;AACH,YAAM,KAAK,UAAU,OAAO,OAAO,CAAC,GAAG,KAAK,KAAK,CAAC;AAAA,IACtD;AAAA,EACJ;AAAA,EAEQ,YAAY,CAAC,UAA8B;AAC/C,WAAO,KAAK,cAAc,WAAW,KAAK,UAAU,KAAK,CAAC;AAAA,EAC9D;AAAA,EAEQ,2BAA2B,OAC/B,oBACC;AAED,QAAI;AACA,YAAMA,UAAS,IAAI,iBAAiB,OAAO,aAAa;AACpD,eAAO,KAAK,4BAAqB,QAAQ,eAAe;AACxD,cAAM,cAAc,KAAK,QAAQ,QAAQ;AACzC,YAAI,aAAa;AACb,gBAAM,SAAQ,8BAA8B,WAAW;AAAA,QAC3D;AAAA,MACJ,GAAG,EAAE,aAAa,EAAE,CAAC;AAErB,aAAO,KAAK;AAAA,IAChB,SAAS,KAAK;AACV,aAAO,MAAM,mDAAmD;AAChE,YAAM;AAAA,IACV;AAAA,EACJ;AAAA,EAEA,OAAO,gCAAgC,OACnC,gBACC;AAED,UAAM,SAAS,YAAY,UAAU;AAErC,QAAI;AACA,YAAM,oBAAoB,YAAY,qBAAqB;AAC3D,YAAM,aAAa,YAAY,cAAc;AAE7C,YAAM,OAAO,kBAAkB;AAC/B,YAAM,OAAO,wBAAwB,WAAW,IAAI;AACpD,YAAM,OAAO,8BAA8B,iBAAiB;AAC5D,YAAM,OAAO,kBAAkB;AAC/B,kBAAY,oBAAoB;AAChC,kBAAY,gBAAgB;AAAA,IAChC,SAAS,KAAK;AACV,UAAI,eAAe,OAAO;AACtB,eAAO,MAAM,YAAY,OAAO,QAAQ,iDAAiD,IAAI,OAAO;AACpG,cAAM;AAAA,MACV,OAAO;AACH,cAAM,IAAI,MAAM,eAAe;AAAA,MACnC;AAAA,IACJ;AAAA,EACJ;AACJ;;;AG7cO,IAAK,aAAL,kBAAKE,gBAAL;AACH,EAAAA,YAAA,SAAM;AACN,EAAAA,YAAA,WAAQ;AAFA,SAAAA;AAAA,GAAA;;;ACGL,SAAS,sBAAsB,WAA0C;AAC5E,UAAQ,WAAW;AAAA,IACf,KAAK;AACD,aAAO,EAAE,MAAM,CAAC,QAAQ,QAAQ,EAAE;AAAA,IACtC,KAAK;AACD,aAAO,EAAE,MAAM,CAAC,QAAQ,QAAQ,EAAE;AAAA,IACtC,KAAK;AACD,aAAO,EAAE,MAAM,CAAC,QAAQ,QAAQ,GAAG,QAAQ,YAAY;AAAA,IAC3D;AACI,aAAO,EAAE,MAAM,CAAC,QAAQ,QAAQ,EAAE;AAAA,EAC1C;AACJ;AAKO,SAAS,wBAAwB,QAGtC;AACE,QAAM,aAAiD,CAAC;AACxD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC/C,eAAW,GAAG,IAAI,sBAAsB,MAAM,IAAI;AAAA,EACtD;AACA,SAAO,EAAE,MAAM,UAAU,WAAW;AACxC;AAKO,SAAS,sBAAsB,QAGpC;AACE,QAAM,aAAiD,CAAC;AAExD,MAAI,MAAM,QAAQ,MAAM,GAAG;AACvB,eAAW,SAAS,QAAgC;AAChD,iBAAW,MAAM,GAAG,IAAI,sBAAsB,MAAM,IAAI;AAAA,IAC5D;AAAA,EACJ,OAAO;AACH,eAAW,CAAC,EAAE,KAAK,KAAK,OAAO,QAAQ,MAA6B,GAAG;AACnE,iBAAW,MAAM,GAAG,IAAI,sBAAsB,MAAM,IAAI;AAAA,IAC5D;AAAA,EACJ;AAEA,SAAO,EAAE,MAAM,UAAU,WAAW;AACxC;AAMO,SAAS,gCAAgC,QAAmC;AAC/E,MAAI,MAAM,QAAQ,MAAM,GAAG;AACvB,WAAQ,OAAgC,IAAI,OAAK,EAAE,GAAG;AAAA,EAC1D;AACA,SAAO,OAAO,OAAO,MAA6B,EAAE,IAAI,OAAK,EAAE,GAAG;AACtE;AAKO,SAAS,kCAAkC,QAAqC;AACnF,SAAO,OAAO,QAAQ,MAAM,EACvB,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM;AACnB,WAAQ,MAA4B,eAAe,QAC3C,MAA4B,eAAe;AAAA,EACvD,CAAC,EACA,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG;AAC3B;;;ACxFA,OAAO,UAAwB;AAC/B,OAAO,UAAU;AAWV,IAAM,qBAAqB,CAAC,iBAAiC;AAChE,QAAM,UAAU,aAAa,YAAY;AACzC,MAAI,QAAQ;AAEZ,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACrC,UAAM,WAAW,QAAQ,WAAW,CAAC;AACrC,QAAI,WAAW,MAAM,WAAW,IAAI;AAChC,YAAM,IAAI,MAAM,0BAA0B,YAAY,EAAE;AAAA,IAC5D;AACA,YAAS,QAAQ,MAAO,WAAW;AAAA,EACvC;AAEA,SAAO,QAAQ;AACnB;AAKO,IAAM,qBAAqB,CAAC,gBAAgC;AAC/D,MAAI,cAAc,GAAG;AACjB,UAAM,IAAI,MAAM,yBAAyB,WAAW,gBAAgB;AAAA,EACxE;AAEA,MAAI,SAAS;AACb,MAAI,QAAQ;AAEZ,SAAO,MAAM;AACT,aAAS,OAAO,aAAa,KAAM,QAAQ,EAAG,IAAI;AAClD,YAAQ,KAAK,MAAM,QAAQ,EAAE;AAE7B,QAAI,UAAU,EAAG;AACjB;AAAA,EACJ;AAEA,SAAO;AACX;AAKO,IAAM,kBAAkB,CAAC,cAAuC;AACnE,QAAM,SAAS,OAAO,cAAc,WAAW,SAAS,WAAW,EAAE,IAAI;AACzE,MAAI,MAAM,MAAM,KAAK,SAAS,GAAG;AAC7B,UAAM,IAAI,MAAM,uBAAuB,SAAS,gBAAgB;AAAA,EACpE;AACA,SAAO,SAAS;AACpB;AAKO,IAAM,kBAAkB,CAAC,UAA0B;AACtD,MAAI,QAAQ,GAAG;AACX,UAAM,IAAI,MAAM,kBAAkB,KAAK,gBAAgB;AAAA,EAC3D;AACA,SAAO,QAAQ;AACnB;AAKO,IAAM,qBAAqB,CAAC,YAA+D;AAC9F,QAAM,QAAQ,QAAQ,MAAM,iBAAiB;AAC7C,MAAI,CAAC,OAAO;AACR,UAAM,IAAI,MAAM,2BAA2B,OAAO,6CAA6C;AAAA,EACnG;AAEA,QAAM,CAAC,EAAE,cAAc,SAAS,IAAI;AACpC,SAAO;AAAA,IACH,aAAa,mBAAmB,YAAa;AAAA,IAC7C,UAAU,gBAAgB,SAAU;AAAA,EACxC;AACJ;AAKO,IAAM,sBAAsB,CAAC,aAAqB,aAA6B;AAClF,SAAO,mBAAmB,WAAW,IAAI,gBAAgB,QAAQ;AACrE;AAKA,IAAM,yBAAyB,OAC3B,UACA,SAC2C;AAC3C,UAAQ,IAAI,8CAA8C,QAAQ;AAClE,QAAM,WAAW,KAAK,SAAS,UAAU,EAAE,OAAO,KAAK,CAAC;AACxD,QAAM,YAAY,OAAO,KAAK,SAAS,MAAM;AAC7C,QAAM,QAAQ,KAAK,YACb,SAAS,OAAO,KAAK,SAAS,IAC9B,SAAS,OAAO,UAAU,CAAC,CAAE;AAEnC,MAAI,CAAC,OAAO;AACR,UAAM,IAAI,MAAM,SAAS,KAAK,SAAS,wBAAwB;AAAA,EACnE;AACA,QAAM,YAAY,MAAM,OAAO;AAC/B,MAAI,CAAC,WAAW;AACZ,UAAM,IAAI,MAAM,cAAc,KAAK,aAAa,OAAO,QAAQ;AAAA,EACnE;AACA,MAAI,UAAU,WAAW,GAAG;AACxB,UAAM,IAAI,MAAM,SAAS,KAAK,aAAa,OAAO,WAAW;AAAA,EACjE;AAEA,QAAM,YAAY,KAAK,2BAA2B,UAAU,QAAQ;AACpE,QAAM,OAAwC,CAAC;AAC/C,MAAI,SAAS;AAGb,QAAM,iBAAiB,OAAO,OAAO,KAAK,OAAO,EAAE,OAAO,CAAC,KAAK,WAAW;AACvE,WAAQ,OAA6B,SAC/B,KAAK,IAAI,KAAK,mBAAoB,OAA6B,MAAM,CAAC,IACtE;AAAA,EACV,GAAG,OAAO,gBAAgB;AAE1B,aAAW,OAAO,WAAW;AACzB,QAAI,SAAS,KAAK,oBAAoB;AAClC;AACA;AAAA,IACJ;AAEA,QAAI,CAAC,KAAK;AACN,cAAQ,IAAI,+CAA+C,MAAM;AACjE;AAAA,IACJ;AAGA,QAAI,mBAAmB,OAAO,oBAAoB,CAAC,IAAI,cAAc,GAAG,GAAG;AACvE,cAAQ,IAAI,iFAAiF,cAAc;AAC3G;AAAA,IACJ;AAEA,UAAM,UAAU,OAAO,QAAQ,KAAK,OAAO,EAAE,OAAyC,CAAC,KAAK,CAAC,KAAK,MAAM,MAAM;AAC1G,UAAK,OAA6B,cAAc;AAC5C,YAAI,CAAC,WAAW;AACZ,gBAAM,IAAI,MAAM,sEAAsE,GAAG,EAAE;AAAA,QAC/F;AACA,YAAI,GAAG,IAAI,UAAW,OAA6B,YAAY,KAAK;AAAA,MACxE,OAAO;AACH,cAAM,WAAW,mBAAoB,OAA6B,MAAM;AACxE,YAAI,GAAG,IAAK,IAAI,QAAQ,GAAG,KAAgB;AAAA,MAC/C;AACA,aAAO;AAAA,IACX,GAAG,CAAC,CAAC;AAEL,SAAK,KAAK,OAAO;AACjB;AAAA,EACJ;AACA,UAAQ,IAAI,mCAAmC,KAAK,QAAQ,KAAK,aAAa,OAAO;AACrF,SAAO;AACX;AAKO,IAAM,mBAAmB,OAC5B,eACA,SAC2C;AAC3C,MAAI;AAEJ,MAAI,KAAK,SAAS,2BAA2B;AACzC,WAAO,MAAM,uBAAuB,eAAe,IAAI;AAAA,EAC3D,WAAW,KAAK,SAAS,aAAa;AAClC,UAAM,WAAW,KAAK,SAAS,eAAe,EAAE,OAAO,KAAK,CAAC;AAC7D,WAAO,MAAM,KAAK,UAAU,QAAQ;AAAA,EACxC,OAAO;AACH,UAAM,IAAI,MAAM,mCAAoC,KAAa,IAAI,EAAE;AAAA,EAC3E;AAEA,SAAO;AACX;AAKO,IAAM,sBAAsB,CAAC,WAAwC;AACxE,MAAI,CAAC,OAAO,WAAW;AACnB,UAAM,IAAI,MAAM,uBAAuB;AAAA,EAC3C;AAEA,MAAI,CAAC,OAAO,WAAW;AACnB,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC5C;AAEA,MAAI,CAAC,OAAO,qBAAqB,OAAO,OAAO,sBAAsB,YAAY;AAC7E,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC9D;AAEA,MAAI,CAAC,OAAO,8BAA8B,OAAO,OAAO,+BAA+B,YAAY;AAC/F,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACxE;AAEA,MACI,OAAO,SAAS,8BACf,CAAC,OAAO,WAAW,OAAO,KAAK,OAAO,OAAO,EAAE,WAAW,IAC7D;AACE,UAAM,IAAI,MAAM,2EAA2E;AAAA,EAC/F;AAEA,MAAI,OAAO,SAAS,2BAA2B;AAC3C,WAAO,QAAQ,OAAO,OAAO,EAAE,QAAQ,CAAC,CAAC,KAAK,MAAM,MAAM;AACtD,UAAI,CAAC,OAAO,MAAM;AACd,cAAM,IAAI,MAAM,UAAU,GAAG,mBAAmB;AAAA,MACpD;AAEA,UAAK,OAA6B,QAAQ;AACtC,cAAM,YAAa,OAA6B;AAChD,YAAI,CAAC,YAAY,KAAK,SAAS,GAAG;AAC9B,gBAAM,IAAI,MAAM,iCAAiC,SAAS,EAAE;AAAA,QAChE;AAAA,MACJ,WAAY,OAA6B,cAAc;AAAA,MAEvD,OAAO;AACH,cAAM,IAAI,MAAM,UAAU,GAAG,iDAAiD;AAAA,MAClF;AAAA,IACJ,CAAC;AAED,QAAI,OAAO,uBAAuB,UAAa,OAAO,qBAAqB,GAAG;AAC1E,YAAM,IAAI,MAAM,2DAA2D;AAAA,IAC/E;AAAA,EACJ,WAAW,OAAO,SAAS,aAAa;AACpC,QAAI,CAAC,OAAO,aAAa,OAAO,OAAO,cAAc,YAAY;AAC7D,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACvE;AAAA,EACJ;AACJ;AAKO,IAAM,yBAAyB,CAClC,UACA,YAC0B;AAC1B,QAAM,WAAW,KAAK,MAAM,QAAQ;AAEpC,SAAO,QAAQ;AAAA,IAAO,YAClB,OAAO,kBAAkB,SAAS,IAAI,KACtC,OAAO,cAAc,SAAS,IAAI,QAAQ,KAAK,EAAE;AAAA,EACrD;AACJ;AAKA,gBAAuB,qBACnB,MACkD;AAClD,aAAW,OAAO,MAAM;AACpB,UAAM;AAAA,EACV;AACJ;;;ACzPO,IAAM,+BAAN,MAAM,8BAA6B;AAAA,EAC9B,SAAyC;AAAA,IAC7C,mBAAmB,MAAM;AAAA,IACzB,4BAA4B,OAAO,CAAC;AAAA,IACpC;AAAA,EACJ;AAAA,EAEA,OAAO,SAAuC;AAC1C,WAAO,IAAI,8BAA6B;AAAA,EAC5C;AAAA,EAEA,UAAU,KAA2C;AACjD,SAAK,OAAO,YAAY;AACxB,WAAO;AAAA,EACX;AAAA,EAEA,UAAU,MAAqJ;AAC3J,SAAK,OAAO,YAAY;AACxB,WAAO;AAAA,EACX;AAAA,EAEA,cAAc,WAAwE;AAClF,SAAK,OAAO,oBAAoB;AAChC,WAAO;AAAA,EACX;AAAA,EAEA,mBAAmB,WAA2H;AAC1I,SAAK,OAAO,6BAA6B;AACzC,WAAO;AAAA,EACX;AAAA,EAEA,kBAAkB,QAAyD;AACvE,SAAK,OAAO,oBAAoB;AAChC,WAAO;AAAA,EACX;AAAA,EAEA,QAAQ,MAAuE;AAC3E,QAAI,KAAK,OAAO,SAAS,2BAA2B;AAChD,MAAC,KAAK,OAA4C,UAAU;AAAA,IAChE,OAAO;AACH,YAAM,IAAI,MAAM,qDAAqD;AAAA,IACzE;AACA,WAAO;AAAA,EACX;AAAA,EAEA,YAAY,WAAoB,WAAmB,GAAiC;AAChF,SAAK,OAAO,OAAO;AACnB,QAAI,cAAc,QAAW;AACzB,MAAC,KAAK,OAA4C,YAAY;AAAA,IAClE;AACA,IAAC,KAAK,OAA4C,qBAAqB;AACvE,WAAO;AAAA,EACX;AAAA,EAEA,UAAU,aAAsG;AAC5G,SAAK,OAAO,OAAO;AACnB,IAAC,KAAK,OAAsC,YAAY;AACxD,WAAO;AAAA,EACX;AAAA,EAEA,QAA+B;AAC3B,QAAI,CAAC,KAAK,OAAO,MAAM;AACnB,YAAM,IAAI,MAAM,iEAAiE;AAAA,IACrF;AAEA,QAAI,CAAC,KAAK,OAAO,WAAW;AACxB,YAAM,IAAI,MAAM,uBAAuB;AAAA,IAC3C;AAEA,QAAI,CAAC,KAAK,OAAO,WAAW;AACxB,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC5C;AAEA,QAAI,CAAC,KAAK,OAAO,mBAAmB;AAChC,YAAM,IAAI,MAAM,gCAAgC;AAAA,IACpD;AAEA,QAAI,OAAO,KAAK,OAAO,sBAAsB,YAAY;AACrD,YAAM,IAAI,MAAM,sCAAsC;AAAA,IAC1D;AAEA,QAAI,OAAO,KAAK,OAAO,+BAA+B,YAAY;AAC9D,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACnE;AAEA,QAAI,KAAK,OAAO,SAAS,2BAA2B;AAChD,YAAM,oBAAoB,KAAK;AAC/B,UAAI,CAAC,kBAAkB,WAAW,OAAO,KAAK,kBAAkB,OAAO,EAAE,WAAW,GAAG;AACnF,cAAM,IAAI,MAAM,0EAA0E;AAAA,MAC9F;AAAA,IACJ;AAEA,QAAI,KAAK,OAAO,SAAS,aAAa;AAClC,YAAM,kBAAkB,KAAK;AAC7B,UAAI,OAAO,gBAAgB,cAAc,YAAY;AACjD,cAAM,IAAI,MAAM,sDAAsD;AAAA,MAC1E;AAAA,IACJ;AAEA,WAAO,KAAK;AAAA,EAChB;AACJ;;;ACtHA,OAAO,SAAS;AAChB,SAAS,wBAAoD;AAC7D,SAAS,UAAAC,eAAc;AAEvB,SAAS,UAAU,iBAAiB;AACpC,YAAY,WAAW;AAEvB,IAAM,YAAY;AAElB,IAAM,0BAA0B,MAAM;AAClC,MAAI,eAAe;AACnB,SAAO,IAAI,UAAU;AAAA,IACjB,UAAUC,QAAO,UAAU,UAAU;AACjC,UAAI,cAAc;AACd,uBAAe;AACf,YAAIA,OAAM,UAAU,KAAKA,OAAM,CAAC,MAAM,OAAQA,OAAM,CAAC,MAAM,OAAQA,OAAM,CAAC,MAAM,KAAM;AAClF,UAAAA,SAAQA,OAAM,MAAM,CAAC;AAAA,QACzB;AAAA,MACJ;AACA,eAAS,MAAMA,MAAK;AAAA,IACxB;AAAA,EACJ,CAAC;AACL;AAEA,IAAM,mBAAmB,CAAC,QAAgB;AACtC,QAAM,QAAQ,OAAO,KAAK,KAAK,MAAM;AACrC,QAAM,MAAM,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,GAAG,KAAK,GAAG,KAAK;AAC/D,SAAO;AAAA,IACH,UAAU;AAAA,IACV,QAAQ,IAAI;AAAA,IACZ;AAAA,IACA,SAAS,IAAI,KAAK;AAAA,EACtB;AACJ;AAEA,IAAM,sBAAsB,CAAC,UAAkB,WAAmB;AAC9D,QAAM,eAAe,iBAAiB,QAAQ;AAC9C,QAAM,aAAa,iBAAiB,MAAM;AAE1C,SAAO;AAAA,aAAgB,QAAQ,MAAM,aAAa,MAAM,YAAY,aAAa,GAAG;AAAA,aAAiB,MAAM,MAAM,WAAW,MAAM,YAAY,WAAW,GAAG;AAChK;AAMA,gBAAuB,oBACnBC,OACA,YACmC;AACnC,QAAM,yBAAyB,MAAM,QAAQ,WAAW,MAAM;AAE9D,QAAM,aAAa,yBAAyB,CAAC,IAAI,OAAO,KAAK,WAAW,MAAM;AAC9E,QAAM,aAAkC,EAAE,WAAW,WAAW,UAAU;AAC1E,MAAI,wBAAwB;AACxB,eAAW,UAAU;AAAA,EACzB;AACA,QAAM,YAAY,IAAI,UAAU;AAChC,QAAM,YAAW,oBAAI,KAAK,GAAE,YAAY;AAExC,MAAI;AACJ,MAAI;AAEJ,QAAM,gBAAgB,WAAW,WAAW,WAAW,SAAS,YAAY,IAAI;AAEhF,MAAI,iBAAiB,kBAAkB,WAAW,kBAAkB,UAAgB,qBAAe,aAAa,GAAG;AAC/G,wBAAoB,iBAAiBA,KAAI;AACzC,uBAAmB,kBAAkB,KAAW,mBAAa,aAAa,CAAC;AAAA,EAC/E,OAAO;AACH,wBAAoB,iBAAiBA,KAAI;AACzC,uBAAmB,kBAAkB,KAAK,wBAAwB,CAAC;AAAA,EACvE;AAEA,mBAAiB,KAAK,SAAS;AAE/B,MAAI;AACA,qBAAiB,OAAO,SAAS,KAAK,SAAS,GAAG;AAC9C,UAAI,CAAC,wBAAwB;AACzB,cAAM,UAA+B,WAAW,oBAAoB,EAAE,gBAAgB,SAAS,IAAI,CAAC;AACpG,mBAAW,OAAO,YAAY;AAC1B,gBAAM,eAAgB,WAAW,OAA+B,IAAI,KAAK,CAAC;AAC1E,cAAI,CAAC,aAAc;AACnB,gBAAM,WAAW,aAAa,mBACxB,aAAa,iBAAiB,IAAI,GAAG,CAAC,IACtC,IAAI,GAAG;AACb,kBAAQ,aAAa,GAAG,IAAI,aAAa,KAAK,OAAO;AAAA,QACzD;AACA,cAAM;AAAA,MACV,OAAO;AACH,cAAM,UAAU,OAAO,KAAK,GAAG;AAC/B,cAAM,UAA+B,WAAW,oBAAoB,EAAE,gBAAgB,SAAS,IAAI,CAAC;AACpG,iBAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACrC,gBAAM,eAAgB,WAAW,OAAgC,CAAC;AAClE,cAAI,CAAC,aAAc;AACnB,gBAAM,WAAW,aAAa,mBACxB,aAAa,iBAAiB,IAAI,CAAC,CAAC,IACpC,IAAI,CAAC;AACX,kBAAQ,aAAa,GAAG,IAAI,aAAa,KAAK,OAAO;AAAA,QACzD;AACA,cAAM;AAAA,MACV;AAAA,IACJ;AAAA,EACJ,UAAE;AACE,sBAAkB,QAAQ;AAAA,EAC9B;AACJ;AAMA,eAAsB,cAAc,UAAmC;AACnE,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACpC,QAAI,WAAW;AACf,qBAAiB,QAAQ,EACpB,GAAG,QAAQ,CAACD,WAA2B;AACpC,YAAM,MAAM,OAAO,SAASA,MAAK,IAAIA,SAAQ,OAAO,KAAKA,MAAK;AAC9D,eAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACjC,YAAI,IAAI,CAAC,MAAM,GAAM;AAAA,MACzB;AAAA,IACJ,CAAC,EACA,GAAG,OAAO,MAAM,QAAQ,KAAK,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,EAClD,GAAG,SAAS,MAAM;AAAA,EAC3B,CAAC;AACL;AAKO,IAAM,oBAAoB,OAC7BC,OACA,eACgB;AAChB,SAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC1C,UAAM,wBAAwB,OAAO,KAAK,WAAW,MAAM,EACtD,IAAI,SAAO,IAAI,KAAK,CAAC;AAE1B,YAAQ,MAAM,GAAG,SAAS,0BAA0B,sBAAsB,IAAI,SAAO;AACjF,YAAM,OAAO,iBAAiB,GAAG;AACjC,aAAO,IAAI,KAAK,QAAQ,MAAM,KAAK,GAAG;AAAA,IAC1C,CAAC,CAAC;AAEF,UAAM,yBAAyB,MAAM,QAAQ,WAAW,MAAM;AAC9D,UAAM,cAAmC,EAAE,WAAW,WAAW,UAAU;AAC3E,QAAI,wBAAwB;AACxB,kBAAY,UAAU;AAAA,IAC1B;AACA,UAAM,YAAY,IAAI,WAAW;AAEjC,QAAI;AACJ,QAAI;AACJ,UAAM,gBAAgB,WAAW,WAAW,WAAW,SAAS,YAAY,IAAI;AAEhF,QACI,iBACG,kBAAkB,WAClB,kBAAkB,UACZ,qBAAe,aAAa,GACvC;AACE,0BAAoB,iBAAiBA,KAAI;AACzC,yBAAmB,kBAAkB,KAAW,mBAAa,aAAa,CAAC;AAAA,IAC/E,OAAO;AACH,0BAAoB,iBAAiBA,KAAI;AACzC,yBAAmB,kBAAkB,KAAK,wBAAwB,CAAC;AAAA,IACvE;AAEA,QAAI,cAAc;AAElB,qBACK,KAAK,SAAS,EACd,GAAG,QAAQ,CAAC,QAAa;AACtB,UAAI,aAAa;AACb,YAAI,UAAoB,CAAC;AACzB,YAAI,wBAAwB;AACxB,oBAAW,OAAO,OAAO,GAAG,EAAe,OAAO,OAAK,CAAC,CAAC,CAAC;AAAA,QAC9D,OAAO;AACH,oBAAW,OAAO,KAAK,GAAG,EAAe,OAAO,OAAK,CAAC,CAAC,CAAC;AAAA,QAC5D;AAEA,gBAAQ,MAAM,GAAG,SAAS,0BAA0B,QAAQ,IAAI,CAAC,GAAG,QAAQ;AACxE,gBAAM,OAAO,iBAAiB,CAAC;AAC/B,iBAAO,IAAI,GAAG,OAAO,KAAK,QAAQ,MAAM,KAAK,GAAG;AAAA,QACpD,CAAC,CAAC;AAEF,YAAI,wBAAwB;AACxB,gCAAsB,QAAQ,CAAC,KAAK,MAAM;AACtC,gBAAI,QAAQ,QAAQ,CAAC,GAAG;AACpB,oBAAM,gBAAgB,oBAAoB,KAAK,QAAQ,CAAC,KAAK,aAAa;AAC1E,sBAAQ,MAAM,GAAG,SAAS,wBAAwB,aAAa,EAAE;AAEjE,oBAAM,IAAI,MAAMF;AAAA,gBACZ;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,QAAQ,CAAC,KAAK;AAAA,gBACdE;AAAA,cACJ,CAAC;AAAA,YACL;AAAA,UACJ,CAAC;AAAA,QACL,OAAO;AACH,gCAAsB,QAAQ,CAAC,QAAQ;AACnC,gBAAI,CAAC,QAAQ,SAAS,GAAG,GAAG;AACxB,oBAAM,UAAU,iBAAiB,GAAG;AACpC,sBAAQ,MAAM,wBAAwB,GAAG,MAAM,QAAQ,GAAG,GAAG;AAC7D,sBAAQ,MAAM,sBAAsB,QAAQ,IAAI,OAAK,IAAI,CAAC,MAAM,iBAAiB,CAAC,EAAE,GAAG,GAAG,CAAC;AAE3F,oBAAM,eAAe,QAAQ,KAAK,OAAK,EAAE,KAAK,MAAM,IAAI,KAAK,CAAC;AAC9D,kBAAI,cAAc;AACd,wBAAQ,MAAM,6BAA6B,YAAY,MAAM,iBAAiB,YAAY,EAAE,GAAG,GAAG;AAAA,cACtG;AAEA,oBAAM,IAAI,MAAMF;AAAA,gBACZ;AAAA,gBACA;AAAA,gBACAE;AAAA,cACJ,CAAC;AAAA,YACL;AAAA,UACJ,CAAC;AAAA,QACL;AACA,sBAAc;AAAA,MAClB,OAAO;AACH,0BAAkB,QAAQ;AAAA,MAC9B;AAAA,IACJ,CAAC,EACA,GAAG,SAAS,CAAC,UAAiB;AAC3B,aAAO,IAAI,MAAM,8BAA8B,MAAM,OAAO,EAAE,CAAC;AAAA,IACnE,CAAC;AACL,sBAAkB,GAAG,SAAS,MAAM;AAChC,cAAQ;AAAA,IACZ,CAAC;AAAA,EACL,CAAC;AACL;;;ACvOA,SAAS,6BAA6B;AACtC,SAAS,UAAAC,eAAc;AAEvB,IAAMC,aAAY;AAKX,IAAM,iBAAiB,OAC1B,UACA,SACgB;AAChB,MAAI;AACA,UAAM,WAAW,KAAK,CAAC;AACvB,QAAI,CAAC,UAAU;AACX,cAAQ,IAAI,GAAGA,UAAS,oCAAoC,QAAQ;AACpE;AAAA,IACJ;AACA,UAAM,YAAY,sBAAsB;AAAA,MACpC,MAAM;AAAA,MACN,QAAQ,OAAO,KAAK,QAAQ,EACvB,IAAI,SAAO;AACR,eAAO,EAAE,IAAI,KAAK,OAAO,IAAI;AAAA,MACjC,CAAC;AAAA,IACT,CAAC;AACD,UAAM,UAAU,aAAa,IAAI;AACjC,YAAQ,IAAI,GAAGA,UAAS,qCAAqC,QAAQ;AAAA,EACzE,SAAS,KAAK;AACV,QAAI,eAAe,OAAO;AACtB,YAAM,IAAI,MAAMD,QAAO,4CAA4C,UAAU,IAAI,OAAO,CAAC;AAAA,IAC7F;AACA,UAAM;AAAA,EACV;AACJ;AAKO,IAAM,sBAAsB,OAC/B,WACA,mBACkB;AAClB,MAAI;AACA,QAAI,WAAW;AAEf,UAAM,gBAAgB,MAAM,UAAU,KAAK,GAAG;AAC9C,QAAI,CAAC,cAAc;AACf,cAAQ,IAAI,GAAGC,UAAS,+CAA+C,cAAc;AACrF,aAAO;AAAA,IACX;AAEA,YAAQ,IAAI,GAAGA,UAAS,+CAA+C,cAAc;AACrF,UAAM,UAAU,OAAO,KAAK,YAAY,EACnC,IAAI,SAAO;AACR,aAAO;AAAA,QACH,IAAI;AAAA,QACJ,OAAO;AAAA,MACX;AAAA,IACJ,CAAC;AAEL,UAAM,YAAY,sBAAsB;AAAA,MACpC,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,aAAa;AAAA,IACjB,CAAC;AAED,YAAQ,IAAI,GAAGA,UAAS,qBAAqB,cAAc;AAC3D,QAAI,QAAQ,CAAC,YAAY;AACzB,qBAAiB,QAAQ,WAAW;AAChC,YAAM,KAAK,IAAI;AACf;AACA,UAAI,MAAM,SAAS,KAAQ;AACvB,YAAI;AACA,gBAAM,UAAU,aAAa,KAAc;AAAA,QAC/C,SAAS,KAAK;AACV,cAAI,eAAe,OAAO;AACtB,kBAAM,IAAI;AAAA,cACND;AAAA,gBACI;AAAA,gBACA,MAAM,MAAM,GAAG,CAAC;AAAA,gBAChB,IAAI;AAAA,cACR;AAAA,YACJ;AAAA,UACJ;AACA,gBAAM;AAAA,QACV;AACA,gBAAQ,CAAC;AAAA,MACb;AAAA,IACJ;AACA,UAAM,UAAU,aAAa,KAAc;AAC3C,YAAQ,IAAI,GAAGC,UAAS,+CAA+C,gBAAgB,QAAQ;AAC/F,WAAO;AAAA,EACX,SAAS,KAAK;AACV,QAAI,eAAe,OAAO;AACtB,YAAM,IAAI,MAAMD,QAAO,4CAA4C,gBAAgB,IAAI,OAAO,CAAC;AAAA,IACnG;AACA,UAAM;AAAA,EACV;AACJ;;;AClGA,OAAOE,WAAU;AAuBV,IAAM,aAAN,cAAyB,OAA8C;AAAA,EAClE;AAAA,EAER,YACI,QACA,eACA,UACA,QACF;AACE,UAAM,QAAQ,UAAU,MAAM;AAC9B,SAAK,iBAAiB,MAAM,QAAQ,aAAa,IAAI,gBAAgB,CAAC,aAAa;AAGnF,SAAK,WAAW,OAAO;AACvB,SAAK,aAAa,OAAO;AACzB,SAAK,oBAAoB,OAAO;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAyC;AAC3C,QAAI,KAAK,OAAO,gCAA6B;AACzC,YAAM,cAAc,KAAK,OAAO;AAChC,UAAI,YAAY,SAAS,2BAA2B;AAChD,cAAM,aAAa,wBAAwB,YAAY,OAAO;AAC9D,eAAO,EAAE,WAAW;AAAA,MACxB;AAEA,aAAO;AAAA,IACX;AAEA,QAAI,KAAK,OAAO,4BAA2B;AACvC,YAAM,aAAa,sBAAsB,KAAK,OAAO,IAAI,MAAM;AAC/D,aAAO,EAAE,WAAW;AAAA,IACxB;AAEA,UAAM,IAAI,MAAM,iDAAiD,KAAK,QAAQ,EAAE;AAAA,EACpF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,cAAkD;AAErD,QAAI,QAAQ;AACZ,eAAW,YAAY,KAAK,gBAAgB;AACxC,UAAI,KAAK,OAAO,gCAA6B;AACzC,cAAM,OAAO,MAAM,iBAAiB,UAAU,KAAK,OAAO,KAAK;AAC/D,iBAAS,KAAK;AAAA,MAClB,WAAW,KAAK,OAAO,4BAA2B;AAC9C,iBAAS,MAAM,cAAc,QAAQ;AAAA,MACzC;AAAA,IACJ;AACA,SAAK,YAAY;AAGjB,eAAW,YAAY,KAAK,gBAAgB;AACxC,UAAI,KAAK,OAAO,gCAA6B;AACzC,cAAM,OAAO,MAAM,iBAAiB,UAAU,KAAK,OAAO,KAAK;AAC/D,mBAAW,OAAO,MAAM;AACpB,gBAAM;AAAA,QACV;AAAA,MACJ,WAAW,KAAK,OAAO,4BAA2B;AAC9C,eAAO,oBAAoB,UAAU,KAAK,OAAO,GAAG;AAAA,MACxD,OAAO;AACH,cAAM,IAAI,MAAM,6CAA6C,KAAK,QAAQ,EAAE;AAAA,MAChF;AAAA,IACJ;AAAA,EACJ;AACJ;AAaO,SAAS,wBACZ,aACA,UACA,eACgB;AAChB,MAAI,YAAY,SAAS,2BAA2B;AAChD,UAAM,cAAc,kCAAkC,YAAY,OAAO;AAEzE,QAAIC;AACJ,QAAI,OAAO,YAAY,cAAc,YAAY;AAC7C,YAAM,YAAY,YAAY,2BAA2B,QAAQ;AACjE,MAAAA,aAAY,YAAY,UAAU,UAAU,QAAW,SAAS;AAAA,IACpE,OAAO;AACH,MAAAA,aAAY,YAAY;AAAA,IAC5B;AAEA,WAAO;AAAA,MACH;AAAA,MACA,UAAUA;AAAA,MACV,mBAAmB,YAAY;AAAA,MAC/B;AAAA,MACA,OAAO;AAAA,IACX;AAAA,EACJ;AAGA,MAAI;AACJ,MAAI,OAAO,YAAY,cAAc,YAAY;AAC7C,QAAI,CAAC,eAAe;AAChB,YAAM,IAAI,MAAM,0EAA0E;AAAA,IAC9F;AACA,UAAM,WAAWC,MAAK,SAAS,eAAe,EAAE,OAAO,KAAK,CAAC;AAC7D,UAAM,YAAY,YAAY,2BAA2B,UAAU,QAAQ;AAC3E,gBAAY,YAAY,UAAU,UAAU,UAAU,SAAS;AAAA,EACnE,OAAO;AACH,gBAAY,YAAY;AAAA,EAC5B;AAEA,SAAO;AAAA,IACH;AAAA,IACA,UAAU;AAAA,IACV,mBAAmB,YAAY;AAAA,IAC/B,aAAa,CAAC;AAAA,IACd,OAAO;AAAA,EACX;AACJ;AAYO,SAAS,sBACZ,UACA,WACA,SAIgB;AAChB,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA,mBAAmB,SAAS;AAAA,IAC5B,aAAa,SAAS,eAAe,gCAAgC,UAAU,MAAM;AAAA,IACrF,KAAK;AAAA,EACT;AACJ;AAYA,eAAsB,mBAClB,SACA,UACA,QACa;AACb,aAAW,SAAS,SAAS;AACzB,UAAM,SAAS,IAAI,WAAW,MAAM,QAAQ,MAAM,UAAU,UAAU,MAAM;AAC5E,UAAM,OAAO,KAAK;AAAA,EACtB;AACA,QAAM,OAAO,SAAS;AAC1B;;;AC9KO,IAAM,6BAAN,MAAM,4BAA2B;AAAA,EAC5B,aAAqB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,OAAO,SAAqC;AACxC,WAAO,IAAI,4BAA2B;AAAA,EAC1C;AAAA,EAEA,UAAU,KAAyC;AAC/C,SAAK,aAAa;AAClB,WAAO;AAAA,EACX;AAAA,EAEA,SAAS,KAAyC;AAC9C,SAAK,YAAY;AACjB,WAAO;AAAA,EACX;AAAA,EAEA,kBAAkB,UAAmB,MAAkC;AACnE,SAAK,qBAAqB;AAC1B,WAAO;AAAA,EACX;AAAA,EAEA,eAAe,SAMgB;AAC3B,QAAI,KAAK,gBAAgB,SAAS;AAC9B,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACrE;AACA,SAAK,cAAc;AACnB,SAAK,UAAU;AACf,WAAO;AAAA,EACX;AAAA,EAEA,gBAAgB,QAIgB;AAC5B,QAAI,KAAK,gBAAgB,QAAQ;AAC7B,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACrE;AACA,SAAK,cAAc;AACnB,SAAK,UAAU;AACf,WAAO;AAAA,EACX;AAAA,EAEA,kBAAkB,QAAuD;AACrE,SAAK,qBAAqB;AAC1B,WAAO;AAAA,EACX;AAAA,EAEA,YAAY,MAA4C;AACpD,SAAK,eAAe;AACpB,WAAO;AAAA,EACX;AAAA,EAEA,QAAuB;AACnB,QAAI,CAAC,KAAK,SAAS;AACf,YAAM,IAAI,MAAM,mEAAmE;AAAA,IACvF;AAEA,QAAI,MAAM,QAAQ,KAAK,OAAO,KAAK,KAAK,QAAQ,WAAW,GAAG;AAC1D,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC9C;AAEA,QAAI,CAAC,MAAM,QAAQ,KAAK,OAAO,KAAK,OAAO,KAAK,KAAK,OAAO,EAAE,WAAW,GAAG;AACxE,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC9C;AAEA,UAAM,SAAwB;AAAA,MAC1B,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK;AAAA,IACjB;AAEA,QAAI,KAAK,cAAc,QAAW;AAC9B,aAAO,WAAW,KAAK;AAAA,IAC3B;AAEA,QAAI,KAAK,uBAAuB,QAAW;AACvC,aAAO,oBAAoB,KAAK;AAAA,IACpC;AAEA,WAAO;AAAA,EACX;AAAA,EAEA,kBAAkB,UAAoC;AAClD,UAAM,YAAY,KAAK,MAAM;AAE7B,UAAM,UAA6E,CAAC;AACpF,QAAI,KAAK,uBAAuB,QAAW;AACvC,cAAQ,oBAAoB,KAAK;AAAA,IACrC;AACA,QAAI,KAAK,iBAAiB,QAAW;AACjC,cAAQ,cAAc,KAAK;AAAA,IAC/B;AAEA,WAAO,sBAAsB,UAAU,WAAW,OAAO;AAAA,EAC7D;AACJ;;;ACtHO,IAAM,UAAN,MAAM,iBAAgB,IAAmB;AAAA,EACpC;AAAA,EAER,YACI,QACA,QACA,eACA,SACF;AACE,UAAM,QAAQ,QAAQ,aAAa;AACnC,SAAK,UAAU;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,YACH,QACA,QACA,eACA,aACA,gBACO;AACP,UAAM,UAAU,YAAY,IAAI,QAAM;AAAA,MAClC,QAAQ;AAAA,MACR,UAAU;AAAA,IACd,EAAE;AACF,WAAO,IAAI,SAAQ,QAAQ,QAAQ,eAAe,OAAO;AAAA,EAC7D;AAAA,EAEA,MAAM,OAAsB;AACxB,eAAW,SAAS,KAAK,SAAS;AAC9B,YAAM,SAAS,IAAI;AAAA,QACf,MAAM;AAAA,QACN,MAAM;AAAA,QACN,KAAK;AAAA,QACL,KAAK;AAAA,MACT;AAEA,WAAK,QAAQ,KAAK,MAAM;AAAA,IAC5B;AAAA,EACJ;AACJ;;;ACzDO,IAAM,qBAAN,MAAyB;AAAA;AAAA;AAAA;AAAA,EAI5B,OAAO,WAAwE;AAC3E,WAAO,CAAC,cAAsB;AAAA,MAC1B,UAAU;AAAA,IACd;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,MAAM,SAA8E;AACvF,WAAO,CAAC,aAAqB;AACzB,YAAM,QAAQ,SAAS,MAAM,OAAO;AACpC,aAAO,OAAO,UAAU,CAAC;AAAA,IAC7B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,WACA,YACwD;AAC3D,WAAO,CAAC,aAAqB;AACzB,aAAO,WAAW,OAAO,CAAC,KAAK,cAAc;AACzC,eAAO,EAAE,GAAG,KAAK,GAAG,UAAU,QAAQ,EAAE;AAAA,MAC5C,GAAG,CAAC,CAAC;AAAA,IACT;AAAA,EACJ;AACJ;AAKO,IAAM,eAAN,MAAmB;AAAA;AAAA;AAAA;AAAA,EAItB,OAAO,WAAW,QAA+C;AAC7D,WAAO,CAAC,aAAqB,SAAS,YAAY,EAAE,WAAW,OAAO,YAAY,CAAC;AAAA,EACvF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,MAAM,SAAgD;AACzD,WAAO,CAAC,aAAqB,QAAQ,KAAK,QAAQ;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,OAAO,YAA8E;AACxF,WAAO,CAAC,aAAqB,WAAW,MAAM,eAAa,UAAU,QAAQ,CAAC;AAAA,EAClF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,MAAM,YAA8E;AACvF,WAAO,CAAC,aAAqB,WAAW,KAAK,eAAa,UAAU,QAAQ,CAAC;AAAA,EACjF;AACJ;;;ACpEA,OAAO,YAAY;AAEnB,SAAoB,WAAXC,gBAA6B;AAO/B,IAAM,cAAc,IAAI,OAAO;;;ACTtC,SAAS,eAAqB;AAC9B,SAAS,UAAAC,eAAc;AACvB,YAAY,gBAAgB;AAC5B,SAAS,YAAY,WAAW,cAAAC,mBAAkB;AAClD,SAAS,kBAAkB;AAG3B,IAAMC,aAAY;AAClB,IAAM,SAAS;AAWR,IAAM,sBAAN,MAA0B;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAER,YACI,YACAC,OACA,MACF;AACE,SAAK,UAAU,IAAI,QAAQ,EAAE,cAAc,EAAE,WAAW,MAAM,YAAY,GAAG,EAAE,CAAC;AAChF,SAAK,SAAS,KAAK,QAAQ,OAAO,UAAU;AAC5C,SAAK,OAAOA;AACZ,SAAK,kBAAkB,MAAM,mBAAmB;AAChD,SAAK,sBAAsB,MAAM,uBAAuB,CAAC;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,QAAoC;AAChD,UAAM,kBAAkB,UAAU,KAAK;AACvC,UAAM,CAAC,KAAK,IAAI,MAAM,KAAK,OAAO;AAAA,MAC9B,kBAAkB,EAAE,QAAQ,gBAAgB,IAAI;AAAA,IACpD;AACA,WAAO,MAAM,IAAI,OAAK,EAAE,IAAI;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,sBAAyC;AAC3C,UAAM,WAAW,MAAM,KAAK,UAAU;AAEtC,UAAM,cAAc,IAAI;AAAA,MACpB,SACK,OAAO,OAAK,EAAE,SAAS,KAAK,eAAe,CAAC,EAC5C,IAAI,OAAK,EAAE,QAAQ,KAAK,iBAAiB,EAAE,CAAC;AAAA,IACrD;AAEA,WAAO,SAAS,OAAO,OAAK;AACxB,UAAI,EAAE,SAAS,KAAK,eAAe,EAAG,QAAO;AAC7C,UAAI,EAAE,SAAS,GAAG,EAAG,QAAO;AAE5B,UAAI,KAAK,oBAAoB,SAAS,GAAG;AACrC,cAAM,MAAiB,mBAAQ,CAAC,EAAE,YAAY;AAC9C,YAAI,CAAC,KAAK,oBAAoB,SAAS,GAAG,EAAG,QAAO;AAAA,MACxD;AAEA,aAAO,CAAC,YAAY,IAAI,CAAC;AAAA,IAC7B,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB,UAAiC;AACpD,UAAM,iBAAiB,GAAG,QAAQ,GAAG,KAAK,eAAe;AACzD,QAAI;AACA,YAAM,OAAO,KAAK,OAAO,KAAK,cAAc;AAC5C,YAAM,KAAK,KAAKC,QAAO,+BAA+B,QAAQ,CAAC;AAC/D,aAAO,KAAK,GAAGF,UAAS,gBAAgB,cAAc,wBAAwB;AAAA,IAClF,SAAS,KAAK;AACV,UAAI,eAAe,OAAO;AACtB,cAAM,IAAI,MAAME,QAAO,8CAA8C,gBAAgB,IAAI,OAAO,CAAC;AAAA,MACrG;AACA,YAAM;AAAA,IACV;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,UAAkB,UAAmC;AACpE,UAAM,OAAO,KAAK,OAAO,KAAK,QAAQ;AACtC,UAAM,aAAwB,gBAAK,QAAQ,IAAI,GAAG,MAAM;AACxD,QAAI,CAAC,WAAW,UAAU,GAAG;AACzB,gBAAU,UAAU;AAAA,IACxB;AACA,UAAM,eAA0B,gBAAK,QAAQ,IAAI,GAAG,QAAQ,QAAQ;AACpE,QAAI;AACA,UAAI,WAAW,YAAY,GAAG;AAC1B,QAAAC,YAAW,YAAY;AAAA,MAC3B;AACA,YAAM,KAAK,SAAS,EAAE,aAAa,aAAa,CAAC;AACjD,aAAO,KAAK,GAAGH,UAAS,eAAe,QAAQ,OAAO,YAAY,EAAE;AACpE,aAAO;AAAA,IACX,SAAS,KAAK;AACV,UAAI,eAAe,OAAO;AACtB,cAAM,IAAI,MAAME;AAAA,UACZ;AAAA,UACA;AAAA,UACA,IAAI;AAAA,QACR,CAAC;AAAA,MACL;AACA,YAAM;AAAA,IACV;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,WAAmB,UAAiC;AACjE,QAAI;AACA,aAAO,KAAK,GAAGF,UAAS,qCAAqC,WAAW,QAAQ;AAChF,YAAM,CAAC,IAAI,IAAI,MAAM,KAAK,OAAO,OAAO,WAAW,EAAE,aAAa,SAAS,CAAC;AAC5E,aAAO,KAAK,GAAGA,UAAS,mDAAmD,WAAW,QAAQ;AAC9F,aAAO;AAAA,IACX,SAAS,KAAK;AACV,UAAI,eAAe,OAAO;AACtB,cAAM,IAAI,MAAME,QAAO,2DAA2D,WAAW,UAAU,IAAI,OAAO,CAAC;AAAA,MACvH;AACA,YAAM;AAAA,IACV;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,mBAAmB,YAAqC;AAC1D,QAAI;AACA,YAAM,KAAK,OAAO,IAAI,EAAE,YAAY,MAAM,CAAC;AAC3C,YAAM,UAAU,KAAK,OAAO,KAAK,UAAU;AAC3C,YAAM,CAAC,MAAM,IAAI,MAAM,QAAQ,OAAO;AACtC,UAAI,CAAC,QAAQ;AACT,cAAM,IAAI,MAAM,8BAA8B,KAAK,OAAO,IAAI,IAAI,UAAU,EAAE;AAAA,MAClF;AACA,YAAM,CAAC,QAAQ,IAAI,MAAM,QAAQ,SAAS;AAC1C,aAAO,SAAS,SAAS,MAAM;AAAA,IACnC,SAAS,KAAU;AACf,YAAM,IAAI,MAAMA,QAAO,iCAAiC,KAAK,OAAO,IAAI,IAAI,UAAU,aAAa,KAAK,OAAO,CAAC;AAAA,IACpH;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,YAAoB,UAAiC;AACzE,QAAI;AACA,YAAM,KAAK,OAAO,IAAI,EAAE,YAAY,MAAM,CAAC;AAC3C,YAAM,UAAU,KAAK,OAAO,KAAK,UAAU;AAC3C,YAAM,QAAQ,KAAK,UAAU,EAAE,aAAa,mBAAmB,CAAC;AAChE,aAAO,KAAK,2BAA2B,KAAK,OAAO,IAAI,IAAI,UAAU,EAAE;AAAA,IAC3E,SAAS,KAAU;AACf,YAAM,IAAI,MAAMA,QAAO,iCAAiC,KAAK,OAAO,IAAI,IAAI,UAAU,aAAa,KAAK,OAAO,CAAC;AAAA,IACpH;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,yBAAyB,UAAkB,QAAgB,UAAiC;AAC9F,QAAI;AACA,YAAM,KAAK,OAAO,IAAI,EAAE,YAAY,MAAM,CAAC;AAE3C,YAAM,YAAY,QAAQ,IAAI,UAAU;AACxC,YAAM,sBAAsB,GAAG,MAAM,IAAI,SAAS,IAAI,QAAQ,IAAI,WAAW,CAAC;AAE9E,YAAM,KAAK,OAAO,OAAO,UAAU;AAAA,QAC/B,aAAa;AAAA,MACjB,CAAC;AAED,aAAO,KAAK,YAAY,QAAQ,SAAS,KAAK,OAAO,IAAI,IAAI,mBAAmB,WAAW;AAE3F,aAAO,KAAK,OAAO,KAAK,mBAAmB;AAAA,IAC/C,SAAS,KAAU;AACf,aAAO,MAAM,yDAAyD,QAAQ;AAAA;AAAA,iBAEzE,IAAI,OAAO;AAAA,iBACX,IAAI,KAAK;AAAA,gBACV,IAAI,IAAI;AAAA,SACf;AAEG,YAAM;AAAA,IACV;AAAA,EACJ;AACJ;;;AC1MA,YAAY,SAAS;AACrB,OAAO,gBAAgB;AAUhB,IAAM,QAAQ,OAAO,aAAqB,kBAA2C;AACxF,QAAU,cAAU,aAAa;AACjC,QAAM,WAAW,aAAa,aAAa;AAC3C,SAAO;AACX;;;ACdO,IAAM,iBAAiB,CAAC,QAAwB;AAEnD,MAAI,eAAe;AAEnB,QAAM,qBAAqB,CAAC,WAAW,UAAU,YAAY;AAC7D,qBAAmB,QAAQ,SAAO;AAC9B,QAAI,aAAa,WAAW,GAAG,GAAG;AAC9B,qBAAe,aAAa,QAAQ,KAAK,EAAE;AAAA,IAC/C;AAAA,EACJ,CAAC;AAGD,iBAAe,aAAa,QAAQ,cAAc,EAAE;AAGpD,iBAAe,aAAa,YAAY;AAGxC,iBAAe,aAAa,QAAQ,KAAK,EAAE;AAG3C,iBAAe,aAAa,UAAU,KAAK,EAAE,QAAQ,oBAAoB,EAAE;AAG3E,MAAI,aAAa,SAAS,KAAK;AAC3B,mBAAe,aAAa,OAAO,GAAG,GAAG;AAAA,EAC7C;AAGA,QAAM,UAAU;AAChB,SAAO,aAAa,QAAQ,SAAS,GAAG;AAC5C;AAGO,IAAM,gBAAgB,CAAC,QAAgB;AAE1C,MAAI,eAAe;AAGnB,iBAAe,aAAa,YAAY;AAGxC,iBAAe,aAAa,QAAQ,KAAK,EAAE;AAG3C,iBAAe,aAAa,UAAU,KAAK,EAAE,QAAQ,oBAAoB,EAAE;AAG3E,MAAI,aAAa,SAAS,MAAM;AAC5B,mBAAe,aAAa,OAAO,GAAG,IAAI;AAAA,EAC9C;AAGA,QAAM,UAAU;AAChB,SAAO,aAAa,QAAQ,SAAS,GAAG;AAC5C;;;ACxDA,OAAO,aAAa;AACpB,OAAOE,YAAW;AAOX,IAAM,oBAAoB,CAAC,QAAa,WAAiC;AAE5E,SAAO,KAAK,MAAM,EAAE,QAAQ,SAAO;AAC/B,UAAM,EAAE,QAAAC,QAAO,IAAI,OAAO,GAAG;AAE7B,QAAIA,YAAW,aAAa;AACxB,UAAI,OAAO,GAAG,GAAG;AACb,cAAM,gBAAgBC,OAAM,OAAO,GAAG,CAAC,EAAE,OAAO,qBAAqB;AAMrE,cAAM,0BAA0BA,OAAM,OAAO,GAAG,CAAC,EAAE,SAASA,OAAM,4BAA4B,CAAC;AAC/F,cAAM,wBAAwBA,OAAM,OAAO,GAAG,CAAC,EAAE,QAAQA,OAAM,qBAAqB,CAAC;AACrF,YAAI,kBAAkB,kBAAkB,2BAA2B,uBAAuB;AACtF,iBAAO,GAAG,IAAI;AAAA,QAClB,OAAO;AACH,iBAAO,GAAG,IAAI;AACd,iBAAO,KAAK,8CAA8C,GAAG;AAAA,QACjE;AAAA,MACJ;AAAA,IACJ;AAAA,EAEJ,CAAC;AAED,SAAO;AACX;AAEO,IAAM,oBAAoB,IAAI,QAAQ,6CAA6C;AAEnF,IAAM,2BAA2B,CAAC,QAAa,WAA4B;AAC9E,SAAO,KAAK,MAAM,EAAE,QAAQ,SAAO;AAE/B,QAAI,OAAO,GAAG,GAAG;AACb,YAAM,EAAE,MAAM,MAAM,IAAI,OAAO,GAAG;AAClC,YAAM,QAAQ,gBAAgB,QAAQ,OAAO,CAAC,IAAI;AAElD,UAAI,MAAM,SAAS,QAAQ,GAAG;AAC1B,YAAI,OAAO,OAAO,GAAG,MAAM,YAAY,OAAO,GAAG,aAAa,SAAS;AACnE,gBAAM,UAAU,IAAI,QAAQ,OAAO,GAAG,CAAC,EAAE,gBAAgB,CAAC;AAC1D,cAAI,QAAQ,qBAAqB,iBAAiB,GAAG;AACjD,mBAAO,GAAG,IAAI;AAAA,UAClB,OAAO;AACH,mBAAO,GAAG,IAAI;AAAA,UAClB;AAAA,QACJ,OAAO;AACH,iBAAO,GAAG,IAAI;AAAA,QAClB;AAAA,MACJ,WAAU,MAAM,SAAS,OAAO,KAAK,OAAO,KAAK,SAAS,QAAQ,GAAG;AACjE,YAAI,MAAM,QAAQ,OAAO,GAAG,CAAC,GAAG;AAC5B,gBAAM,SAAS,OAAO,GAAG;AACzB,gBAAM,SAAS,OAAO,IAAI,CAAC,SAAc;AACrC,gBAAG,OAAO,SAAS,YAAY,gBAAgB,SAAS;AACpD,oBAAM,SAAS,IAAI,QAAQ,IAAI,EAAE,gBAAgB,CAAC;AAClD,kBAAI,OAAO,qBAAqB,iBAAiB,GAAG;AAChD,uBAAO;AAAA,cACX,OAAO;AACH,uBAAO;AAAA,cACX;AAAA,YACJ,OAAO;AACH,qBAAO;AAAA,YACX;AAAA,UACJ,CAAC,EAAE,OAAO,CAAC,SAAc,CAAC,CAAC,IAAI;AAC/B,iBAAO,GAAG,IAAI;AAAA,QAClB,OAAO;AACH,iBAAO,GAAG,IAAI;AAAA,QAClB;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ,CAAC;AAED,SAAO;AACX;;;AC9EA,OAAOC,YAAW;;;ACFlB,SAAS,gBAAgB;AAElB,IAAM,iBAAN,MAAqB;AAAA,EACxB,OAAe;AAAA,EAEf;AAAA,EAEA,YAAY,QAAwB;AAEhC,UAAM,eAAe;AAAA,MACjB,WAAW;AAAA,MACX,YAAY;AAAA,IAChB;AAEA,SAAK,SAAS,IAAI,SAAS;AAAA,MACvB,WAAW,OAAO,SAAS,KAAK;AAAA,MAChC,GAAG;AAAA,IACP,CAAC;AAAA,EACL;AAAA,EAEA,OAAO,OAAO,QAAkC;AAC5C,QAAI,CAAC,KAAK,UAAU;AAChB,WAAK,WAAW,IAAI,KAAK,MAAM;AAAA,IACnC;AAEA,WAAO,KAAK,SAAS;AAAA,EACzB;AAEJ;;;ADrBA,OAAO,WAAW;AAMlB,SAAS,aAAAC,kBAAiB;AAG1B,IAAMC,aAAY,IAAIC,WAAU,CAAC;AAE1B,IAAM,iBAAN,cAA6B,2BAA2B;AAAA,EAE3D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YACI,QACA,UACA,UACA,QACA,OACA,mBACF;AACE;AAAA,MACI;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,SAAK,SAAS;AACd,SAAK,WAAW,eAAe,OAAO,MAAM;AAC5C,SAAK,YAAY,KAAK,SAAS,QAAQ,QAAQ,EAAE,UAAU,OAAO,YAAY,KAAK,CAAC;AACpF,SAAK,UAAU,KAAK,UAAU,MAAM,OAAO,EAAE,UAAU,OAAO,YAAY,KAAK,CAAC;AAChF,SAAK,YAAY;AACjB,SAAK,mBAAmB,GAAG,KAAK;AAChC,SAAK,iBAAiB,KAAK,UAAU,MAAM,KAAK,kBAAkB,EAAE,UAAU,OAAO,YAAY,KAAK,CAAC;AACvG,SAAK,aAAa,GAAG,MAAM,IAAI,KAAK;AACpC,SAAK,oBAAoB,GAAG,KAAK,UAAU;AAAA,EAC/C;AAAA;AAAA,EAIA,sBAAsB,CAAC,WAAwB;AAC3C,WAAO,KAAK,UAAU,MAAM,IAAI;AAAA;AAAA,EACpC;AAAA,EAEA,iBAAiB;AAAA,EAEjB,iCAAiC,CAC7B,eACS;AAET,UAAM,OAAO,WAAW;AACxB,UAAMC,UAAS,WAAW;AAG1B,QAAI;AAEJ,QAAI,gBAAgB,OAAO;AACvB,gBAAU;AAAA,IACd,OAAO;AACH,gBAAU,CAAC,IAAI;AAAA,IACnB;AAEA,QAAIA,SAAQ;AACR,cAAQA,SAAQ;AAAA,QACZ,KAAK;AACD,iBAAO;AAAA,QACX,KAAK;AACD,iBAAO;AAAA,QACX;AACI,gBAAM,IAAI,MAAM,aAAa,KAAK,QAAQ,2BAA2BA,OAAM,EAAE;AAAA,MACrF;AAAA,IACJ,WACS,QAAQ,SAAS,QAAQ,GAAG;AACjC,aAAO;AAAA,IACX,WACS,QAAQ,SAAS,SAAS,KAAK,KAAK,SAAS,QAAQ,GAAG;AAC7D,aAAO;AAAA,IACX,WACS,QAAQ,SAAS,SAAS,GAAG;AAClC,aAAO;AAAA,IACX,WACS,QAAQ,SAAS,SAAS,GAAG;AAClC,aAAO;AAAA,IACX,WACS,QAAQ,SAAS,QAAQ,GAAG;AACjC,aAAO;AAAA,IACX,WACS,QAAQ,SAAS,OAAO,GAAG;AAChC,YAAM,QAAQ,WAAW;AACzB,UAAI,OAAO;AACP,eAAO,KAAK,+BAA+B,KAAK;AAAA,MACpD;AACA,YAAM,IAAI,MAAM,aAAa,KAAK,QAAQ,kDAAkD,KAAK,UAAU,UAAU,CAAC,EAAE;AAAA,IAC5H,OACK;AACD,YAAM,IAAI,MAAM,aAAa,KAAK,QAAQ,4CAA4C,KAAK,UAAU,UAAU,CAAC,EAAE;AAAA,IACtH;AAAA,EACJ;AAAA,EAEA,kBAAkB,MAAgB;AAE9B,UAAM,sBAAsB,KAAK,YAC5B,IAAI,QAAM;AACP,aAAO,iBAAiB,EAAE,0BAA0B,EAAE;AAAA,IAC1D,CAAC,EACA,KAAK,OAAO;AAEjB,UAAM,cAAc,KAAK,YAAY,IAAI,QAAM,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI;AAErE,UAAM,4BAA4B,KAAK,mBAAmB,6BAA6B,KAAK,QAAQ;AAEpG,UAAM,UAAU,OAAO,KAAK,yBAAyB,EAChD,IAAI,YAAU;AACX,aAAO;AAAA,QACH,UAAU;AAAA,QACV,SAAS;AAAA,MACb;AAAA,IACJ,CAAC;AACL,UAAM,gBAAgB,MAAM,SAAS,GAAG,EAGnC,IAAI,CAAAC,WAAS;AACV,WAAK,YAAY,QAAQ,QAAM;AAC3B,YAAI,CAACA,OAAM,IAAI,OAAK,0BAA0B,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG;AACpE,UAAAA,OAAM,KAAK;AAAA,YACP,UAAU;AAAA,YACV,SAAS;AAAA,UACb,CAAC;AAAA,QACL;AAAA,MACJ,CAAC;AACD,aAAOA;AAAA,IACX,CAAC;AAEL,WAAO,cAAc,IAAI,CAAAA,WAAS;AAE9B,YAAM,YAAYA,OACb,IAAI,YAAU;AACX,YAAI,OAAO,UAAU;AACjB,iBAAO,qBAAqB,0BAA0B,OAAO,OAAO,CAAC,sBAAsB,0BAA0B,OAAO,OAAO,CAAC;AAAA,QACxI,OAAO;AACH,iBAAO,qBAAqB,OAAO,OAAO,sBAAsB,OAAO,OAAO;AAAA,QAClF;AAAA,MACJ,CAAC,EAAE,KAAK,IAAI;AAEhB,YAAM,cAAcA,OACf,IAAI,YAAU;AACX,YAAI,OAAO,UAAU;AACjB,iBAAO,KAAK,0BAA0B,OAAO,OAAO,CAAC;AAAA,QACzD,OAAO;AACH,iBAAO,KAAK,OAAO,OAAO;AAAA,QAC9B;AAAA,MACJ,CAAC,EAAE,KAAK,IAAI;AAEhB,YAAM,QAAQ;AAAA,gBACV,KAAK,UAAU;AAAA;AAAA;AAAA;AAAA,uBAIR,KAAK,iBAAiB;AAAA;AAAA;AAAA;AAAA,sDAIS,WAAW;AAAA,kDACf,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAWhD,mBAAmB;AAAA;AAAA,yBAEP,SAAS;AAAA;AAAA,sBAEZ,WAAW,aAAa,WAAW;AAAA;AAE7C,aAAO;AAAA,IACX,CAAC;AAAA,EACL;AAAA,EAEA,oBAAoB,MAAgB;AAChC,WAAO;AAAA,MACH,kBAAkB,KAAK,UAAU;AAAA,MACjC,GAAG,KAAK,gBAAgB;AAAA,IAC5B;AAAA,EACJ;AAAA,EAEA,mBAAmB,MAAgB;AAC/B,UAAM,4BAA4B,KAAK,mBAAmB,6BAA6B,KAAK,QAAQ;AACpG,UAAM,UAAU,OAAO,KAAK,yBAAyB,EAChD,IAAI,eAAa,KAAK,0BAA0B,SAAS,CAAC,IAAI,EAC9D,KAAK,IAAI;AAEd,WAAO;AAAA,MACH,eAAe,KAAK,UAAU,KAAK,OAAO,YAAY,OAAO,SAAS,KAAK,iBAAiB;AAAA,IAChG;AAAA,EACJ;AAAA,EAEA,qCAAqC,OAAO,eAAuB;AAC/D,QAAI;AAGA,YAAMH,WAAU,aAAa,YAAY;AACrC,cAAM,CAAC,MAAM,IAAI,MAAM,KAAK,UAAU,OAAO;AAC7C,YAAI,CAAC,QAAQ;AACT,iBAAO,KAAK,+BAAwB,KAAK,UAAU,EAAE,cAAc;AACnE,gBAAM,KAAK,UAAU,OAAO;AAAA,QAChC,OAAO;AACH,gBAAM,CAAC,QAAQ,IAAI,MAAM,KAAK,UAAU,YAAY;AACpD,gBAAM,0BAA0B,SAAS;AACzC,cAAI,KAAK,OAAO,YAAY,KAAK,OAAO,aAAa,yBAAyB;AAC1E,kBAAM;AAAA,cACF;AAAA,cACA,8BAA8B,KAAK,UAAU,EAAE,kCAAkC,uBAAuB;AAAA;AAAA,2FAEzC,KAAK,OAAO,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAMnF;AAAA,iGACqE,uBAAuB,iCAAiC,KAAK,OAAO,QAAQ;AAAA;AAAA,YAErJ;AACA,kBAAM,MAAM;AAAA,UAChB;AACA,iBAAO,KAAK,sBAAe,KAAK,UAAU,EAAE,0CAA0C;AAAA,QAC1F;AAAA,MACJ,CAAC;AAAA,IACL,SAAS,KAAU;AACf,UAAI,IAAI,SAAS,KAAK;AAClB,cAAM;AAAA,UACF;AAAA,UACA;AAAA;AAAA,yDAEqC,IAAI,OAAO;AAAA;AAAA;AAAA;AAAA,UAIhD,uDAAuD,IAAI,OAAO,MAAM,IAAI,IAAI;AAAA,QACpF;AACA;AAAA,MACJ;AACA,UAAI,cAAc,aAAa,KAAK,eAAe;AAC/C,eAAO,MAAM,aAAa,KAAK,QAAQ,qDAAqD,IAAI,OAAO,MAAM,IAAI,IAAI,EAAE;AACvH,qBAAa,CAAC;AAAA,MAClB,OAAO;AACH,eAAO,MAAM,aAAa,KAAK,QAAQ,iEAAiE,IAAI,OAAO,MAAM,IAAI,IAAI,EAAE;AACnI,cAAM,IAAI,QAAQ,CAAC,SAAS,WAAW,WAAW,SAAS,MAAQ,UAAW,CAAC;AAC/E,cAAM,KAAK,mCAAmC,aAAa,CAAC;AAAA,MAChE;AAAA,IACJ;AACA,WAAO,QAAQ,QAAQ;AAAA,EAC3B;AAAA,EAEA,cAAc,YAAY;AAEtB,QAAI;AACA,YAAM,YAAY,KAAK;AACvB,YAAM,SAAS,KAAK,uBAAuB;AAE3C,aAAO,KAAK,6BAAsB,SAAS,cAAc;AAEzD,YAAM,qBAAoC;AAAA,QACtC;AAAA,MACJ;AAEA,YAAM,KAAK,UAAU;AAAA,QACjB;AAAA,QACA;AAAA,MACJ;AAEA;AAAA,IACJ,SAAS,KAAU;AACf,YAAM,IAAI,MAAM,aAAa,KAAK,QAAQ;AAAA;AAAA,qBAEjC,IAAI,OAAO;AAAA,qBACX,IAAI,KAAK,EAAE;AAAA,IACxB;AAAA,EACJ;AAAA,EAEA,aAAa,OAAO,gBAAqD;AAErE,QAAI,YAAY,SAAS,GAAG;AACxB,aAAO,KAAK,qBAAc,KAAK,QAAQ,mDAAmD,KAAK,UAAU,WAAW,CAAC,EAAE;AACvH,YAAM,CAAC,QAAQ,IAAI,MAAM,KAAK,QAAQ,YAAY;AAElD,YAAM,gBAAgB,YAAY,IAAI,cAAY;AAC9C,eAAO,KAAK,uDAAuD,SAAS,MAAM,SAAS,UAAU;AAAA,MACzG,CAAC,EAAE,OAAO,SAAO;AACb,eAAO,CAAC,CAAC;AAAA,MACb,CAAC;AACD,YAAM,SAAS,SAAS;AACxB,YAAM,aAAa;AAAA,QACf,GAAG;AAAA,QACH,QAAQ,OAAO,OAAO,OAAO,aAAa;AAAA,MAC9C;AACA,eAAS,SAAS;AAElB,YAAM,KAAK,QAAQ,YAAY,QAAQ;AACvC;AAAA,IACJ;AAAA,EAEJ;AAAA,EAEA,oBAAoB,YAAY;AAE5B,QAAI;AACA,YAAM,YAAY,KAAK;AAGvB,YAAM,CAAC,MAAM,IAAI,MAAM,KAAK,UAAU,MAAM,SAAS,EAAE,OAAO;AAC9D,UAAI,QAAQ;AACR,eAAO,KAAK,6BAAsB,SAAS;AAAA,6BAC9B;AACb,cAAM,KAAK,kBAAkB;AAAA,MACjC;AAEA,YAAM,SAAS,KAAK,uBAAuB;AAC3C,YAAM,iBAAiBI,OAAM,EAAE,IAAI,GAAG,KAAK,EAAE,QAAQ,EAAE,SAAS;AAChE,YAAM,qBAAoC;AAAA,QACtC;AAAA,QACA;AAAA,MACJ;AAEA,aAAO,KAAK,qCAA8B,SAAS,cAAc;AAEjE,YAAM,KAAK,UAAU;AAAA,QACjB;AAAA,QACA;AAAA,MACJ;AAEA;AAAA,IACJ,SAAS,KAAU;AACf,YAAM,IAAI,MAAM,aAAa,KAAK,QAAQ;AAAA;AAAA,qBAEjC,IAAI,OAAO;AAAA,qBACX,IAAI,KAAK,EAAE;AAAA,IACxB;AAAA,EACJ;AAAA,EAEA,0BAA0B,OAAO,kBAA0B;AAEvD,QAAI;AAEA,YAAM,aAAa,IAAI,oBAAoB,KAAK,OAAO,4BAA4B;AACnF,YAAM,OAAO,MAAM,WAAW;AAAA,QAC1B;AAAA,QACA,KAAK,OAAO;AAAA,QACZ,KAAK;AAAA,MACT;AAEA,YAAM,WAA4B;AAAA,QAC9B,cAAc;AAAA,QACd,kBAAkB;AAAA,MACtB;AAEA,YAAM,KAAK,mBAAmB,KAAK,mBAAmB,MAAM,QAAQ;AAAA,IAExE,SAAS,KAAU;AACf,aAAO,MAAM,aAAa,KAAK,QAAQ,kCAAkC;AAEzE,UAAI,IAAI,OAAO,KAAK;AAChB,cAAM;AAAA,UACF;AAAA,UACA;AAAA;AAAA,iDAE6B,IAAI,OAAO;AAAA;AAAA;AAAA,UAGxC;AAAA,QACJ;AAAA,MACJ;AACA,YAAM;AAAA,IACV;AAAA,EACJ;AAAA,EAEA,oBAAoB,MAAM;AACtB,UAAM,QAAQ,wBAAwB,KAAK,iBAAiB;AAC5D,WAAO,KAAK,oBAAoB,CAAC,KAAK,CAAC;AAAA,EAC3C;AAAA,EAEA,oBAAoB,YAA8C;AAC9D,UAAM,CAAC,QAAQ,IAAI,MAAM,KAAK,UAAU,UAAU;AAClD,UAAM,cAAc,SACf,OAAO,SAAO;AACX,aAAO,CAAC,CAAC,IAAI;AAAA,IACjB,CAAC,EACA,IAAI,aAAW;AACZ,aAAO;AAAA,QACH,WAAW,QAAQ;AAAA,MACvB;AAAA,IACJ,CAAC;AAEL,WAAO;AAAA,EACX;AAAA,EAEA,+BAA+B,YAA4C;AACvE,UAAM,CAAC,KAAK,IAAI,MAAM,KAAK,QAAQ,YAAY;AAC/C,WAAO,MAAM,OAAO;AAAA,EACxB;AAAA,EAEA,aAAa,OAAO,YAAqC;AACrD,UAAM,WAAW;AAAA;AAAA,cAEX,QAAQ,KAAK;AAAA,aACd,CAAC;AAAA;AAAA;AAGN,UAAM,KAAK,SAAS,MAAM,QAAQ;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,yDAAyD,CAC7D,SACA,0BACyB;AAEzB,UAAM,OAAO;AAEb,QAAI,CAAC,uBAAuB;AACxB,YAAM,IAAI,MAAM,aAAa,KAAK,QAAQ,oCAAoC,OAAO,qEAAqE;AAAA,IAC9J;AACA,UAAM,OAAO,sBAAsB;AAGnC,QAAI;AAEJ,QAAI,gBAAgB,OAAO;AACvB,gBAAU;AAAA,IACd,OAAO;AACH,gBAAU,CAAC,IAAI;AAAA,IACnB;AAEA,QAAI,QAAQ,SAAS,OAAO,GAAG;AAC3B,aAAO;AAAA,QACH;AAAA,QACA,MAAM;AAAA,QACN,MAAM,KAAK,+BAA+B,qBAAqB;AAAA,MACnE;AAAA,IACJ,OAAO;AAGH,UAAI,eAAe;AACnB,aAAO;AAAA,QACH;AAAA,QACA,MAAM;AAAA,QACN,MAAM,KAAK,+BAA+B,qBAAqB;AAAA,MACnE;AAAA,IACJ;AAAA,EAEJ;AAAA,EAEQ,yBAAyB,MAAoB;AACjD,UAAM,4CAA4C,KAAK,mBAAmB,6BAA6B,KAAK,QAAQ;AACpH,QAAI,CAAC,2CAA2C;AAC5C,YAAM,IAAI,MAAM,aAAa,KAAK,QAAQ,4CAA4C;AAAA,IAC1F;AACA,WAAO,OAAO,KAAK,yCAAyC,EAAE,OAAqB,CAAC,KAAK,cAAc;AAEnG,YAAM,iBAAiB,KAAK,mBAAmB,qBAAqB,KAAK,UAAU,SAAS;AAC5F,YAAM,qBAAqB,KAAK,uDAAuD,gBAAgB,KAAK,gBAAgB,SAAS,CAAC;AACtI,UAAI,oBAAoB;AACpB,YAAI,KAAK,kBAAkB;AAAA,MAC/B;AAEA,aAAO;AAAA,IACX,GAAG,CAAC,CAAC;AAAA,EACT;AAAA,EAEQ,qBAAqB,OACzB,WACA,MACA,aACgB;AAChB,QAAI;AACA,YAAM,CAAC,GAAG,IAAI,MAAM,KAAK,eAAe,KAAK,MAAM,QAAQ;AAE3D,aAAO,KAAK,+BAAwB,KAAK,EAAE,yBAAyB,SAAS,gBAAgB,IAAI,EAAE,IAAI;AACvG,aAAO,MAAM,iBAAiB,KAAK,UAAU,IAAI,UAAU,CAAC,EAAE;AAG9D,YAAMC,UAAS,IAAI,QAAQ;AAC3B,UAAIA,WAAUA,QAAO,SAAS,GAAG;AAC7B,cAAMA;AAAA,MACV;AAAA,IACJ,SAAS,KAAU;AACf,aAAO,MAAM,GAAG;AAChB,YAAM,IAAI,MAAM,aAAa,KAAK,QAAQ,4DAA4D,KAAK,IAAI,gBAAgB,SAAS;AAAA;AAAA,qBAE/H,IAAI,OAAO;AAAA,qBACX,IAAI,KAAK,EAAE;AAAA,IACxB;AAAA,EACJ;AAEJ;;;AEtgBO,IAAM,iBAAN,cAA6B,QAAwB;AAAA,EAGxD,YAAY,QAAwB,eAA8B;AAC9D,UAAM,QAAQ,aAAa;AAC3B,SAAK,kBAAkB,2BAA2B,KAAK,uBAAuB;AAAA,EAClF;AAAA,EACA,OAAO,qBAAqB;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AAAA,EAEA,oBAAoB,CAChB,UACA,UACA,QACA,UACiB;AACjB,WAAO,IAAI;AAAA,MACP,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACT;AAAA,EACJ;AAAA,EAEA,eAAe;AAAA,EACf,0BAA0B;AAAA,EAC1B,oBAAoB;AAAA,EACpB,2BAA2B;AAE/B;;;ACxCA,SAAS,UAAAC,eAAc;AAEhB,IAAM,mBAAN,MAAgD;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,aAAqB,YAAoB;AACjD,SAAK,cAAc;AACnB,SAAK,aAAa;AAClB,SAAK,UAAU,IAAI,oBAAoB,UAAU;AAAA,EACrD;AAAA,EAEQ,gBAAwB;AAC5B,WAAO,GAAG,KAAK,WAAW;AAAA,EAC9B;AAAA,EAEA,MAAM,WAAiC;AACnC,UAAM,aAAa,KAAK,cAAc;AACtC,QAAI;AACA,aAAO,KAAK,qCAA8B,KAAK,UAAU,IAAI,UAAU,EAAE;AACzE,YAAM,MAAM,MAAM,KAAK,QAAQ,mBAAmB,UAAU;AAC5D,YAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,aAAO,EAAE,OAAO,OAAO;AAAA,IAC3B,SAAS,KAAU;AACf,aAAO,KAAKA,QAAO,iCAAiC,KAAK,UAAU,IAAI,UAAU,0CAA0C,KAAK,OAAO,CAAC;AACxI,aAAO,EAAE,OAAO,OAAU;AAAA,IAC9B;AAAA,EACJ;AAAA,EAEA,MAAM,WAAW,OAA8B;AAC3C,UAAM,aAAa,KAAK,cAAc;AACtC,QAAI;AACA,aAAO,KAAK,mCAA4B,KAAK,UAAU,IAAI,UAAU,EAAE;AACvE,YAAM,KAAK,QAAQ,kBAAkB,YAAY,KAAK;AAAA,IAC1D,SAAS,KAAU;AACf,aAAO,MAAMA,QAAO,+CAAwC,KAAK,UAAU,IAAI,UAAU,aAAa,KAAK,OAAO,CAAC;AACnH,YAAM,IAAI,MAAMA,QAAO,+BAA+B,KAAK,UAAU,IAAI,UAAU,aAAa,KAAK,OAAO,CAAC;AAAA,IACjH;AAAA,EACJ;AACJ;","names":["transports","retryCount","ReplicationMethod","format","axios","qs","dayjs","cloneDeep","Bluebird","format","cloneDeep","Bluebird","dayjs","cloneDeep","params","axios","safeColumnName","errors","dayjs","dayjs","fs","path","fs","dayjs","Bluebird","dayjs","FileFormat","format","chunk","path","format","logPrefix","XLSX","tableName","XLSX","default","format","unlinkSync","logPrefix","path","format","unlinkSync","dayjs","format","dayjs","dayjs","Semaphore","semaphore","Semaphore","format","chunk","dayjs","errors","format"]}
|
|
1
|
+
{"version":3,"sources":["../src/sdk/utils.ts","../src/sdk/service/logger.ts","../src/sdk/service/network.ts","../src/sdk/service/metric.ts","../src/sdk/service/memory.ts","../src/sdk/service/exit.ts","../src/sdk/service/error.ts","../src/sdk/models/replication.ts","../src/sdk/models/messages.ts","../src/sdk/models/state.ts","../src/sdk/constants/date.ts","../src/sdk/models/tap/authenticator.ts","../src/sdk/models/tap/restStream.ts","../src/sdk/models/tap/stream.ts","../src/sdk/helpers/typing.ts","../src/sdk/models/tap/tap.ts","../src/sdk/helpers/qs-logger.ts","../src/sdk/models/target/dbSync.ts","../src/sdk/models/target/error.ts","../src/sdk/models/target/models.ts","../src/sdk/models/target/record.ts","../src/sdk/models/target/renameColumnStore.ts","../src/sdk/models/target/schema.ts","../src/sdk/models/target/target.ts","../src/sdk/models/target/streamDbState.ts","../src/sdk/models/target/temporaryFile.ts","../src/sdk/file-processing/types.ts","../src/sdk/file-processing/schema-utils.ts","../src/sdk/file-processing/excel/reader.ts","../src/sdk/file-processing/excel/config-builder.ts","../src/sdk/file-processing/csv/reader.ts","../src/sdk/file-processing/csv/writer.ts","../src/sdk/file-processing/file-stream.ts","../src/sdk/file-processing/csv/config-builder.ts","../src/sdk/file-processing/file-tap.ts","../src/sdk/file-processing/file-patterns.ts","../src/services/sftp.ts","../src/services/cloud-storage.ts","../src/services/zip.ts","../src/targets/bigquery/helpers.ts","../src/targets/bigquery/service/record.ts","../src/targets/bigquery/service/dbSync.ts","../src/targets/bigquery/service/bigquery.ts","../src/targets/bigquery/main.ts","../src/state-providers/gcs/main.ts"],"sourcesContent":["import { readFileSync } from \"fs\";\nimport { logger } from \"./service/logger.js\";\n\nfunction readFile(fileName: string, filePath: string) {\n try {\n return readFileSync(filePath);\n } catch (err) {\n logger.error(`Can't open file: \\`${fileName}\\` at path: \\`${filePath}\\`. Is it at the proper place?`)\n throw err;\n }\n}\n\nfunction parseFileContent(fileName: string, fileContent: Buffer) {\n try {\n return JSON.parse(fileContent.toString());\n } catch (err) {\n logger.error(`Can't parse file: \\`${fileName}\\` as JSON. Is it properly formatted?`)\n throw err;\n }\n}\n\nexport const loadJson = (fileName: string): any => {\n const filePath = process.cwd() + `/` + fileName\n const fileContent = readFile(fileName, filePath);\n return parseFileContent(fileName, fileContent);\n}\n\nexport const loadSchema = (streamId: string) => {\n const schema = loadJson(`schemas/${streamId}.json`)\n return schema;\n}","import * as winston from \"winston\";\nexport const BATCH_INTERVAL_MS = 100;\n\nconst transports = {\n console: new winston.transports.Console({\n stderrLevels: [],\n level: 'info'\n })\n};\n\nconst getTransports = (): winston.transport[] => {\n return [\n transports.console\n ]\n}\n\nconst { combine, prettyPrint, timestamp, errors, splat } = winston.format;\n\nconst winstonLogger = winston.createLogger({\n format: combine(\n timestamp(),\n errors({ stack: true }),\n splat(),\n prettyPrint()\n ),\n transports: getTransports(),\n});\n\nlet isWinstonOpen = true;\nconst closeWinston = (cb: () => void) => {\n isWinstonOpen = false;\n winstonLogger.end();\n winstonLogger.on('finish', () => {\n setTimeout(() => {\n return cb()\n }, BATCH_INTERVAL_MS * 2)\n });\n}\n\ntype LogLevel = 'info' | 'error' | 'debug' | 'warn';\n\nconst log = (\n level: LogLevel,\n message: string | any,\n ...args: any[]\n): void => {\n if (isWinstonOpen) {\n winstonLogger[level](message, ...args);\n } else {\n console[level](message, ...args);\n }\n};\n\nexport const logger = {\n info: (message: string | any, ...args: any[]): void => log('info', message, ...args),\n error: (message: string | any, ...args: any[]): void => log('error', message, ...args),\n debug: (message: string | any, ...args: any[]): void => log('debug', message, ...args),\n warn: (message: string | any, ...args: any[]): void => log('warn', message, ...args),\n closeWinston\n}","import axios, { AxiosError, AxiosInstance, AxiosResponse, AxiosRequestConfig, AxiosRequestHeaders } from \"axios\";\nimport { URLSearchParams } from \"url\";\nimport * as fs from 'fs';\nimport * as qs from 'qs';\nimport axiosRetry, { isNetworkOrIdempotentRequestError } from 'axios-retry';\nimport { logger } from \"./logger\";\n\n// This retry regardless of whether the call is idempotent or not. \n// e.g. this will retry POST and PUT.\n// Hence, this service and all its function SHOULD not be used to create things as it is not safe. \n// This service should be only used for extracting data.\nconst shouldRetry = (error: AxiosError): boolean => {\n\n const statusCode = error.response ? error.response.status : 0;\n\n return error.code !== 'ECONNABORTED' // Triggered if there is not enough local socket. In those case, retrying will only make things worse\n && (\n !error.response\n || statusCode === 429\n || statusCode === 409\n || statusCode === 400\n || (statusCode >= 500 && statusCode < 599)\n );\n}\n\nexport const getAxiosInstance = (retryCount?: number): AxiosInstance => {\n const instance = axios.create({\n timeout: 120_000\n });\n axiosRetry(instance,\n {\n retries: retryCount || 24,\n retryDelay: (retryCount, error) => {\n logger.info(`🔁 Retrying for the ${retryCount}th time the call for \n method=${error.config?.method}\n url=${error.config?.url}\n params=%j\n body=%j`,\n error.config?.params,\n error.config?.data\n )\n if (retryCount > 6) {\n return 10000\n }\n return axiosRetry.exponentialDelay(retryCount)\n },\n retryCondition: (error: AxiosError): boolean => {\n logger.debug(`😱 Got an error for ${error.config?.method} ${error.config?.url}\n \n Status: ${error?.response?.status}\n Error code ${error.code}\n Error config method ${error}`)\n\n return isNetworkOrIdempotentRequestError(error)\n || shouldRetry(error)\n }\n });\n return instance;\n}\n\nexport interface GetConfig {\n qs?: { [key: string]: any },\n headers?: AxiosRequestHeaders,\n retryCount?: number\n}\n\nexport const getRawJSONApiCall = async <T>(\n endpoint: string,\n config: GetConfig,\n privateLogging?: boolean\n): Promise<AxiosResponse<T>> => {\n\n const instance = getAxiosInstance(config.retryCount);\n\n // Repeat the key/value pair multiple time when having arrays to be passed in the QS\n const paramsSerializer = (params: any) => {\n return qs.stringify(params, { arrayFormat: 'repeat' })\n }\n\n try {\n logger.info(`🤖 GET ${endpoint}`, { private: privateLogging })\n const requestConfig: AxiosRequestConfig = {\n params: config.qs,\n paramsSerializer: { serialize: (params) => qs.stringify(params, { arrayFormat: 'repeat' }) }\n };\n if (config.headers) {\n requestConfig.headers = config.headers;\n }\n const response = await instance.get(\n endpoint,\n requestConfig\n );\n return response;\n } catch (err: any) {\n if (err.response.status > 400) {\n throw new Error(`We got a \\`${err.response.status}\\` status code from endpoint: \\`${endpoint}\\`. \n\n headers response: ${JSON.stringify(err.response.headers)}\n\n Response body from the server: ${JSON.stringify(err.response.data)}`);\n }\n throw err;\n }\n}\n\nexport const getJSONApiCallWithFullResponse = async <T>(\n endpoint: string,\n config: GetConfig,\n privateLogging?: boolean\n) => {\n const instance = getAxiosInstance(config.retryCount);\n\n // Repeat the key/value pair multiple time when having arrays to be passed in the QS\n const paramsSerializer = (params: any) => {\n return qs.stringify(params, { arrayFormat: 'repeat' })\n }\n\n try {\n logger.info(`🤖 GET ${endpoint} with params: %s`, config.qs, { private: privateLogging })\n const requestConfig: AxiosRequestConfig = {\n params: config.qs,\n paramsSerializer: { serialize: (params) => qs.stringify(params, { arrayFormat: 'repeat' }) }\n };\n if (config.headers) {\n requestConfig.headers = config.headers;\n }\n const response = await instance.get(endpoint, requestConfig);\n return response;\n } catch (err) {\n if (err instanceof Error) {\n if (axios.isAxiosError(err)) {\n if ((err.response?.status || 0) > 400) {\n logger.warn(`We got a \\`${err.response?.status}\\` status code from endpoint: \\`${endpoint}\\`. \n\n Headers response: ${JSON.stringify(err.response?.headers)}\n\n Response body from the server: ${JSON.stringify(err.response?.data)}`);\n }\n }\n }\n throw err;\n }\n}\n\nexport const getJSONApiCall = async <T>(\n endpoint: string,\n config: GetConfig,\n privateLogging?: boolean\n): Promise<T> => {\n const fullResponse = await getJSONApiCallWithFullResponse(\n endpoint,\n config,\n privateLogging\n );\n return fullResponse.data;\n}\n\nexport const getDownloadFileApiCall = async <T>(\n endpoint: string,\n config: GetConfig,\n output: string,\n privateLogging?: boolean\n): Promise<{ outputDir: string }> => {\n\n const instance = getAxiosInstance(config.retryCount);\n\n const writer = fs.createWriteStream(output)\n\n const paramsSerializer = (params: any) => {\n return qs.stringify(params, { arrayFormat: 'repeat' })\n }\n\n logger.info(`🤖 GET ${endpoint}`, { private: privateLogging })\n\n return instance({\n method: \"GET\",\n url: endpoint,\n responseType: 'stream',\n params: config.qs,\n ...(config.headers ? { headers: config.headers } : {}),\n paramsSerializer: { serialize: (params) => qs.stringify(params, { arrayFormat: 'repeat' }) }\n }).then(response => {\n return new Promise<{ outputDir: string }>((resolve, reject) => {\n response.data.pipe(writer);\n let error: any = null;\n writer.on('error', err => {\n error = err;\n writer.close();\n reject(err);\n });\n writer.on('close', () => {\n if (!error) {\n resolve({ outputDir: output });\n }\n //no need to call the reject here, as it will have been called in the\n //'error' stream;\n });\n });\n });\n}\n\nexport interface PostConfig {\n qs?: { [key: string]: any },\n headers?: AxiosRequestHeaders,\n retryCount?: number\n}\n\nexport const postJSONApiCall = async <T>(\n endpoint: string,\n config: PostConfig,\n payload: any\n): Promise<T> => {\n\n const instance = getAxiosInstance(config.retryCount);\n try {\n const requestConfig: AxiosRequestConfig = { params: config.qs };\n if (config.headers) {\n requestConfig.headers = config.headers;\n }\n const response = await instance.post(\n endpoint,\n payload,\n requestConfig\n );\n return response.data;\n } catch (err: any) {\n if (err?.response?.status >= 400) {\n throw new Error(`We got a \\`${err.response.status}\\` status code from endpoint: \\`${endpoint}\\`. \n \n Response body from the server: ${JSON.stringify(err.response.data)}`);\n }\n throw err;\n }\n}\n\nexport const postFormDataApiCall = async <T>(endpoint: string, config: PostConfig, payload: any): Promise<T> => {\n\n const instance = getAxiosInstance(config.retryCount);\n\n try {\n const response = await instance({\n method: 'post',\n url: endpoint,\n headers: {\n ...(payload as any).getHeaders()\n },\n data: payload\n });\n return response.data;\n } catch (err: any) {\n if (err.response.status > 400) {\n throw new Error(`We got a \\`${err.response.status}\\` status code from endpoint: \\`${endpoint}\\`. \n \n Response body from the server: ${JSON.stringify(err.response.data)}`);\n }\n throw err;\n }\n}\n\nexport const postUrlEncodedApiCall = async (endpoint: string, config: PostConfig, payload: any) => {\n\n const instance = getAxiosInstance(config.retryCount);\n\n try {\n\n const params = new URLSearchParams(payload as any);\n\n const response = await instance.post(\n endpoint,\n params.toString(),\n {\n ...(config.headers ? { headers: config.headers } : {})\n });\n return response.data;\n } catch (err: any) {\n if (err.response.status > 400) {\n throw new Error(`We got a \\`${err.response.status}\\` status code from endpoint: \\`${endpoint}\\`. \n \n Response body from the server: ${JSON.stringify(err.response.data)}`);\n }\n throw err;\n }\n}","const metricStore: {\n [streamId: string]: {\n [metricName: string]: CounterMetric\n }\n} = {};\n\nexport const ALL_STREAM_ID_KEYWORD = \"all\";\nexport const ROWS_SYNCED_METRIC_NAME = \"rows_synced_count\";\nexport const API_CALLS_METRIC_NAME = \"api_calls_count\";\nexport const EXECUTION_TIME_METRIC_NAME = \"execution_time_ms\";\n\n// We're using functions here so that the call is done lazily\n// when the stream is initialized and the proper isSilent + streamId is configured\n// otherwise we have the default streamId value here\nexport interface MetricConfiguration {\n isEnabled: () => boolean;\n getStreamIds?: () => string[];\n}\n\nexport const getCounterMetrics = (\n name: string,\n streamIds: string[]\n): CounterMetric[] => {\n return streamIds.map(streamId => {\n return getCounterMetric(name, streamId)\n })\n}\n\nexport const getCounterMetric = (\n name: string,\n streamId: string = ALL_STREAM_ID_KEYWORD\n): CounterMetric => {\n if (!metricStore[streamId]) {\n metricStore[streamId] = {};\n }\n const streamMetricStore = metricStore[streamId];\n\n if (!streamMetricStore[name]) {\n streamMetricStore[name] = new CounterMetric(name, streamId);\n }\n return streamMetricStore[name];\n}\n\nexport const getAllMetrics = (): CounterMetric[] => {\n return Object.keys(metricStore)\n .flatMap(streamId => {\n const streamMetricStore = metricStore[streamId];\n if (!streamMetricStore) {\n return [] as CounterMetric[];\n }\n return Object.keys(streamMetricStore)\n .map(metricName => streamMetricStore[metricName])\n .filter((m): m is CounterMetric => m !== undefined)\n })\n}\n\nexport class CounterMetric {\n private value: number = 0;\n name: string;\n streamId: string;\n\n constructor(\n name: string,\n streamId: string\n ) {\n this.name = name;\n this.streamId = streamId;\n }\n\n increment(inc: number = 1): void {\n this.value = this.value + inc;\n }\n\n getStreamId(): string {\n return this.streamId\n }\n\n getName(): string {\n return this.name\n }\n\n getValue(): number {\n return this.value\n }\n}","import { logger } from \"./logger\";\n\nconst formatMemoryUsage = (data: number) => `${Math.round(data / 1024 / 1024 * 100) / 100} MB`;\n\nexport const printMemoryFootprint = (prefix: string) => {\n const memoryData = process.memoryUsage();\n\n const memoryUsage = {\n rss: `${formatMemoryUsage(memoryData.rss)} -> Resident Set Size - total memory allocated for the process execution`,\n heapTotal: `${formatMemoryUsage(memoryData.heapTotal)} -> total size of the allocated heap`,\n heapUsed: `${formatMemoryUsage(memoryData.heapUsed)} -> actual memory used during the execution`,\n external: `${formatMemoryUsage(memoryData.external)} -> V8 external memory`,\n };\n\n logger.info(`${prefix}: %j`, memoryUsage);\n}","import { logger } from \"./logger\";\n\nexport async function gracefulExit(exitCode: number) {\n // Wait for winston to have logged all messages\n // Required as we are using HTTP transport\n const loggerFinish = new Promise<void>((resolve, reject) => {\n logger.closeWinston(resolve)\n })\n await loggerFinish;\n process.exit(exitCode);\n}","import { gracefulExit } from \"./exit\";\nimport { logger } from \"./logger\";\nimport { ErrorType } from \"../models/error\";\n\nexport const haltAndCatchFire = async (\n errorType: ErrorType,\n errorText: string,\n errorDebugText: string\n): Promise<void> => {\n\n logger.error(\n `💥 Got a fatal error that will reported to the end user. Process will stop.\n errorType=%s\n errorText=%s\n errorDebugText=%s\n `,\n errorType,\n errorText,\n errorDebugText\n )\n // we return sucess but we let the sucess job pass the error params\n await gracefulExit(0);\n}","export enum ReplicationMethod {\n INCREMENTAL = \"INCREMENTAL\",\n FULL_TABLE = \"FULL_TABLE\",\n APPEND = \"APPEND\"\n}","import { StreamId } from \"./metadata\";\nimport { ReplicationMethod } from \"./replication\";\nimport { PropertiesMetadata } from \"./schema\";\n\nexport type MessageType = \"RECORD\" | \"STATE\" | \"SCHEMA\" | \"ACTIVATE_VERSION\" | \"REPLICATION_METHOD\";\n\nexport interface Message {\n type: MessageType;\n toString(): string;\n}\n\nexport class RecordMessage implements Message {\n\n type: MessageType = \"RECORD\"\n stream: StreamId;\n record: any;\n\n constructor(record: any, stream: StreamId) {\n this.record = record;\n this.stream = stream;\n }\n\n toString() {\n const result = {\n type: \"RECORD\",\n record: this.record,\n stream: this.stream\n }\n return JSON.stringify(result);\n }\n}\n\nexport class StateMessage implements Message {\n\n type: MessageType = \"STATE\"\n value: any\n\n constructor(value: any) {\n this.value = value\n }\n\n toString() {\n const result = {\n type: \"STATE\",\n value: this.value\n }\n return JSON.stringify(result);\n }\n}\n\nexport class ReplicationMethodMessage implements Message {\n\n type: MessageType = \"REPLICATION_METHOD\";\n stream: string;\n replication: ReplicationMethod;\n\n constructor(stream: string, version: ReplicationMethod) {\n this.stream = stream;\n this.replication = version;\n }\n\n toString() {\n const result = {\n type: \"REPLICATION_METHOD\",\n replication: this.replication,\n stream: this.stream\n }\n return JSON.stringify(result);\n }\n}\n\nexport class SchemaMessage implements Message {\n\n type: MessageType = \"SCHEMA\";\n stream: StreamId;\n schema: any;\n keyProperties: string[];\n bookmarkProperties: string[] | undefined;\n displayLabel: string | undefined;\n description: string | undefined;\n propertiesMetadata: PropertiesMetadata | undefined\n\n constructor(opts: {\n stream: StreamId,\n schema: any,\n keyProperties: string[],\n bookmarkProperties?: string[],\n displayLabel?: string,\n description?: string,\n propertiesMetadata?: PropertiesMetadata | undefined\n }) {\n const {\n stream,\n schema,\n keyProperties,\n bookmarkProperties,\n displayLabel,\n description,\n propertiesMetadata\n } = opts;\n\n this.stream = stream;\n this.schema = schema;\n this.keyProperties = keyProperties;\n this.bookmarkProperties = bookmarkProperties;\n this.displayLabel = displayLabel;\n this.description = description;\n this.propertiesMetadata = propertiesMetadata;\n }\n\n toString() {\n const result: any = {\n type: \"SCHEMA\",\n stream: this.stream,\n schema: this.schema,\n key_properties: this.keyProperties,\n label: this.displayLabel,\n description: this.description,\n }\n\n if (this.bookmarkProperties) {\n result[\"bookmark_properties\"] = this.bookmarkProperties\n }\n\n return JSON.stringify(result);\n }\n}","import { StreamId } from \"./metadata\";\nimport { StateMessage } from \"./messages\";\nimport dayjs, { Dayjs } from \"dayjs\";\nimport { ITarget } from \"./target/target\";\nimport { defaultDateTimeFormat } from \"../constants/date\";\nimport { format } from \"util\";\n\nexport interface InputTapState {\n bookmarks?: {\n [streamId: string]: StreamState\n }\n}\n\nexport interface TapState {\n bookmarks: {\n [streamId: string]: StreamState\n }\n}\n\nexport interface Bookmark {\n replicationKey?: string;\n replicationKeyValue?: string; // Contains ISO 8601 string\n}\n\nexport interface StreamState extends Bookmark {\n progressMarkers?: ProgressMarkers\n replicationKeySignpost?: string\n}\n\nexport interface ProgressMarkers extends Bookmark {\n Note?: string;\n}\n\n// To deprecate\nexport interface State {\n bookmarks: Bookmarks;\n}\n\n// To deprecate\nexport interface Bookmarks {\n [streamId: string]: any;\n}\n\nconst PROGRESS_MARKERS = \"progressMarkers\"\nconst PROGRESS_MARKER_NOTE = \"Note\"\nconst SIGNPOST_MARKER = \"replicationKeySignpost\"\n\nexport const incrementStreamState = (\n state: StreamState,\n replicationKey: string,\n latestRecord: any,\n isSorted: boolean\n): StreamState => {\n\n let newRkValue = latestRecord[replicationKey] as string;\n if (!newRkValue) {\n throw new Error(format(`No value for replicationKey: ${replicationKey} in record with keys: %j`, Object.keys(latestRecord)))\n }\n let newRkValueMoment = dayjs(newRkValue);\n\n let prevRkValue: string | undefined;\n let prevRkValueMoment: Dayjs | undefined;\n\n if (isSorted) {\n prevRkValue = state[\"replicationKeyValue\"];\n prevRkValueMoment = dayjs(prevRkValue);\n if (prevRkValue && prevRkValueMoment.isAfter(newRkValueMoment)) {\n throw new Error(\n `Unsorted data detected in stream. Latest value '${newRkValue}' is\n smaller than previous max '${prevRkValue}'.`\n )\n }\n }\n\n // For unsorted streams, we have to make sure that the \"new\" replication key is newer or equal than the previous one\n if (!isSorted) {\n\n // Progress markers are living only during the current sync\n // They are erased at the end of the sync and the stored value is used to write the new state\n if (!state[PROGRESS_MARKERS]) {\n const marker: ProgressMarkers = {};\n marker[PROGRESS_MARKER_NOTE] = \"Progress is not resumable if interrupted.\"\n state[PROGRESS_MARKERS] = marker;\n }\n prevRkValue = (state[PROGRESS_MARKERS] as any)[\"replicationKeyValue\"];\n\n // In case we don't have any previous value in the PROGRESS_MARKERS, \n // which happens for the first record of the current sync, we take the last state value\n prevRkValueMoment = dayjs(prevRkValue || state[\"replicationKeyValue\"]);\n\n // If we just got an \"old\" record, we keep the previous state as the max ts\n if (prevRkValue && prevRkValueMoment.isAfter(newRkValueMoment)) {\n newRkValueMoment = prevRkValueMoment;\n newRkValue = prevRkValue;\n }\n }\n\n // Signpost is the moment we start the current sync,\n // we make sure that our replication value can't be greater than the signpost\n const signpostMarker = state[SIGNPOST_MARKER];\n const replicationKeySignpostMoment = dayjs(signpostMarker);\n\n if (replicationKeySignpostMoment && replicationKeySignpostMoment.isBefore(newRkValueMoment)) {\n // Overflowed max bookmark threshold, reset to the max for this key:\n newRkValueMoment = replicationKeySignpostMoment\n newRkValue = replicationKeySignpostMoment.format(defaultDateTimeFormat);\n }\n\n if (isSorted === false) {\n (state[PROGRESS_MARKERS] as ProgressMarkers)['replicationKey'] = replicationKey;\n (state[PROGRESS_MARKERS] as ProgressMarkers)['replicationKeyValue'] = dayjs(newRkValueMoment).format(defaultDateTimeFormat);\n } else {\n state['replicationKey'] = replicationKey;\n state['replicationKeyValue'] = dayjs(newRkValueMoment).format(defaultDateTimeFormat);\n }\n\n return state;\n}\n\n/**\n * Promote or wipe progress markers once sync is complete.\"\"\"\n\n * @param state \n * @returns \n */\nexport const finalizeStateProgressMarkers = (state: StreamState): StreamState => {\n\n const signpostValue = state[SIGNPOST_MARKER];\n const progressMarkers = state[PROGRESS_MARKERS];\n if (progressMarkers && progressMarkers[\"replicationKey\"] && progressMarkers[\"replicationKeyValue\"]) {\n // Replication keys valid (only) after sync is complete\n state[\"replicationKey\"] = progressMarkers[\"replicationKey\"]\n let newRkValue = progressMarkers[\"replicationKeyValue\"]\n\n // Reset to signpost if needed\n if (signpostValue && _greaterThan(newRkValue, signpostValue)) {\n newRkValue = signpostValue\n }\n\n const previousReplicationValue = state[\"replicationKeyValue\"];\n if (!previousReplicationValue || (previousReplicationValue && _greaterThan(newRkValue, previousReplicationValue))) {\n state[\"replicationKeyValue\"] = newRkValue\n }\n }\n // Wipe any markers that have not been promoted\n delete state[PROGRESS_MARKERS];\n\n return state;\n}\n\nexport const _greaterThan = (aValue: string, bValue: string): boolean => {\n return dayjs(aValue).isAfter(dayjs(bValue));\n}\n\nexport const extractStateForStream = (state: InputTapState, streamId: StreamId) => {\n if (!state.bookmarks) {\n state.bookmarks = {}\n }\n if (!state.bookmarks[streamId]) {\n state.bookmarks[streamId] = {}\n }\n return state.bookmarks[streamId];\n}\n\nexport class StateService {\n\n private static instance: StateService;\n\n bookmarks: Bookmarks;\n\n constructor() {\n this.bookmarks = {}\n }\n\n static getInstance(): StateService {\n if (!this.instance) {\n this.instance = new this();\n }\n\n return this.instance;\n }\n\n setBookmark(streamId: StreamId, streamState: StreamState) {\n this.bookmarks[streamId] = streamState;\n }\n\n setBookmarkSignpost(streamId: StreamId, signpostValue: string) {\n if (!this.bookmarks[streamId]) {\n this.bookmarks[streamId] = {}\n }\n this.bookmarks[streamId][SIGNPOST_MARKER] = signpostValue;\n }\n\n getBookmark(streamId: StreamId): StreamState {\n if (this.bookmarks[streamId]) {\n return this.bookmarks[streamId];\n } else {\n return {}\n }\n }\n\n clearState() {\n this.bookmarks = {};\n }\n\n get(): State {\n const state: State = {\n bookmarks: this.bookmarks\n }\n return state\n }\n\n async forwardStateToTarget(target: ITarget) {\n const state: State = {\n bookmarks: this.bookmarks\n }\n\n const message = new StateMessage(state);\n await target.state(message);\n }\n}","export const defaultDateTimeFormat = \"YYYY-MM-DDTHH:mm:ss.SSSSSSZ\"","import { HTTPHeaders, URLParams } from \"../http\";\n\n/**\n * C: The type of the tap config\n */\nexport class Authenticator<C> {\n\n getAuthHeaders(config: C): Promise<HTTPHeaders> {\n return Promise.resolve({})\n }\n\n getAuthQS(config: C): Promise<URLParams> {\n return Promise.resolve({})\n }\n\n}","import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from \"axios\";\nimport { Authenticator } from \"./authenticator\";\nimport { HTTPHeaders, HTTPMethod, URLParams } from \"../http\";\nimport * as qs from 'qs';\nimport { logger } from \"../../service/logger\";\nimport { Stream } from \"./stream\";\nimport { InputTapState } from \"../state\";\nimport { ITarget } from \"../target/target\";\nimport { getAxiosInstance } from \"../../service/network\";\nimport { DEFAULT_MAX_CONCURRENT_STREAMS } from \"./tap\";\nimport { API_CALLS_METRIC_NAME, CounterMetric, getCounterMetrics, MetricConfiguration } from \"../../service/metric\";\nimport { getTruncatedParamsForLog } from \"../../helpers/qs-logger\";\nimport cloneDeep from \"lodash/cloneDeep.js\";\nimport isEqual from \"lodash/isEqual.js\";\n\n/**\n * R: Type of the API result\n * NPT: Type of the \"nextPageToken\"\n */\nexport abstract class RESTStream<R, O, NPT, C, P = undefined>\n extends Stream<O, C, P> {\n\n axiosInstance: AxiosInstance | undefined;\n\n constructor(\n config: C,\n state: InputTapState,\n target: ITarget,\n childConcurrency: number = DEFAULT_MAX_CONCURRENT_STREAMS\n ) {\n super(config, state, target, childConcurrency);\n this.apiCallsMetricsConf = {\n isEnabled: () => !this.isSilent,\n getStreamIds: () => [this.streamId]\n }\n }\n\n // Internal\n // Those functions shouldn't be overriden (or it means that we fuck'ed up the SDK during the design phase)\n\n /**\n * Prepare an Axios request object.\n * Pagination information can be parsed from `nextPageToken` if `nextPageToken` is not undefined.\n * @param nextPageToken \n * @returns \n */\n _prepareRequest = async (nextPageToken: NPT | undefined, parent?: P)\n : Promise<AxiosRequestConfig> => {\n\n const method = this.httpMethod;\n const url = this.getNextUrl(nextPageToken, parent);\n if (!url) {\n throw new Error(`StreamId: ${this.streamId} - URL is undefined. Did your properly define the URL for this stream?`)\n }\n\n const authenticator = this.authenticator\n\n // If getNextUrl returns a URL that already contains query string parameters,\n // extract them and merge into params. We remove the query part from the URL\n // to avoid duplication with axios params handling.\n let finalUrl = url;\n let urlQueryParams: Record<string, any> = {};\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex !== -1) {\n finalUrl = url.substring(0, queryIndex);\n const rawQueryString = url.substring(queryIndex + 1);\n urlQueryParams = qs.parse(rawQueryString) as Record<string, any>;\n }\n\n const params = {\n ...this.getNextUrlParams(nextPageToken, parent),\n // Query params embedded in URL should override computed pagination params\n // but should not override auth params which are appended last\n ...urlQueryParams,\n ...(await authenticator?.getAuthQS(this.config))\n }\n\n const requestBody = this.getRequestBodyForNextCall(nextPageToken, parent)\n let headers = this.getCustomHTTPHeaders(parent);\n if (!headers) {\n headers = {};\n }\n\n if (authenticator) {\n const authHeaders = await authenticator.getAuthHeaders(this.config)\n headers = {\n ...headers,\n ...authHeaders\n }\n }\n\n const paramsSerializer = (params: any) => {\n return qs.stringify(params, { arrayFormat: 'repeat' })\n }\n\n const request: AxiosRequestConfig = {\n url: finalUrl,\n method,\n data: requestBody,\n params,\n paramsSerializer,\n headers\n }\n return request\n }\n\n async _requestWithRetry(request: AxiosRequestConfig, privateLogging?: boolean): Promise<R | \"STOP_SYNC\"> {\n try {\n logger.debug(`🤖 ${request.method} ${request.url} with params: %j | body: %j`,\n request.params,\n request.data,\n { private: privateLogging });\n logger.info(`🤖 ${request.method} ${request.url} qs: %j`,\n getTruncatedParamsForLog(request.params),\n { private: privateLogging });\n const axiosInstance = this.axiosInstance;\n if (!axiosInstance) {\n throw new Error(`Axios Instance is not initialized!`)\n }\n const response = await axiosInstance.request<R>(request);\n return response.data;\n } catch (err) {\n if (axios.isAxiosError(err)) {\n logger.error(`🤖 Error on ${request.method} ${request.url} with params %j | body: %j | headers: %j - getting error %s - response body: %j`,\n request.params,\n request.data,\n request.headers,\n err.message,\n err.response?.data\n )\n const recoveredValue = await this.httpErrorHandler(request.url, err);\n if (recoveredValue === undefined) {\n return \"STOP_SYNC\"\n } else {\n return recoveredValue;\n }\n } else {\n throw err;\n }\n }\n }\n\n async *_requestRecords(parent?: P): AsyncIterable<O> {\n let nextPageToken: NPT | undefined = undefined;\n let finished = false;\n\n let apiCallsMetrics: CounterMetric[] = [];\n if (this.apiCallsMetricsConf.isEnabled() === true) {\n apiCallsMetrics = getCounterMetrics(\n API_CALLS_METRIC_NAME,\n this.apiCallsMetricsConf.getStreamIds\n ? this.apiCallsMetricsConf.getStreamIds()\n : []\n )\n }\n\n // We reset the axios instance here to use the value of `httpRetryCount` after the initialization of custom values defined in the Streams impl.\n // Doing it in the constructor is givingf us access only to the default value of `httpRetryCount`\n this.axiosInstance = getAxiosInstance(this.httpRetryCount);\n\n while (!finished) {\n const preparedRequest = await this._prepareRequest(nextPageToken, parent);\n const resp = await this._requestWithRetry(preparedRequest);\n\n apiCallsMetrics.forEach(metric => {\n metric.increment();\n })\n\n // We stop the sync for this stream\n if (resp === \"STOP_SYNC\") {\n return;\n }\n const rows = this.parseResponse(resp, parent, nextPageToken);\n for await (const row of rows) {\n yield row\n }\n\n const previousToken = cloneDeep(nextPageToken);\n nextPageToken = this.getNextPageToken(resp, previousToken);\n\n if (nextPageToken && isEqual(nextPageToken, previousToken)) {\n throw new Error(\n `${this.streamId} - Loop detected in pagination. \"\n Pagination token: \\`${JSON.stringify(nextPageToken)}\\` is identical to prior token \\`${JSON.stringify(previousToken)}\\`.`\n )\n }\n // Cycle until getNextPageToken() no longer returns a value\n finished = !nextPageToken\n }\n }\n\n async *_getRecords(parent?: P): AsyncIterable<O> {\n for await (const row of this._requestRecords(parent)) {\n yield row\n }\n }\n\n // Overridable\n // Even if the default impl. of some function can be used as-is, those functions\n // are meant to be overriden when necessary to match the API needs.\n httpMethod: HTTPMethod = \"GET\";\n baseUrl: string = \"\";\n path: string = \"\";\n httpRetryCount = 24;\n authenticator?: Authenticator<C>;\n\n apiCallsMetricsConf: MetricConfiguration\n\n // When undefined is returned, we should stop the sync without any error\n async httpErrorHandler(url: string | undefined, err: AxiosError): Promise<R | undefined> {\n if ((err.response?.status || 0) > 400) {\n throw new Error(`We got a \\`${err.response?.status}\\` status code from endpoint: \\`${url}\\`. \n\n Response body from the server: ${JSON.stringify(err.response?.data)}`);\n }\n throw err;\n }\n\n /** \n * Return a dictionary of values to be used in URL parameterization.\n * If paging is supported, developers may override with specific paging logic.\n * \n * By default, no params are passed.\n */\n getNextUrlParams(nextPageToken: NPT | undefined, parent?: P): URLParams {\n return {}\n }\n\n /** \n * Prepare the data payload for the REST API request.\n * Useful when working with POST APIs.\n * \n * By default, no payload will be sent (return undefined).\n */\n getRequestBodyForNextCall(nextPageToken: NPT | undefined, parent?: P): any {\n return undefined\n }\n\n /**\n * Return token identifying next page or undefined if all records have been read.\n * \n * By default, no token will be returned and a single API call will be made.\n * \n * @param response \n * @param previousToken \n * @returns \n */\n getNextPageToken(response: R, previousToken?: NPT): NPT | undefined {\n return undefined;\n }\n\n /**\n * Return custom headers to be used for HTTP requests.\n * \n * By default, no additional header will be added\n */\n getCustomHTTPHeaders(parent?: P): HTTPHeaders | undefined {\n return undefined;\n }\n\n /**\n * Return a URL, optionally targeted to a specific partition.\n * This can be overriden to perform dynamic URL generation.\n * \n * TODO: Make URL + Path templatisable and replace those with Extractor (or Tap) config\n * @returns \n */\n getNextUrl(previousToken?: NPT,parent?: P): string {\n const urlPattern = [this.baseUrl, this.path].join(\"\")\n return urlPattern;\n }\n\n /**\n * Parse the response and return an iterator of result rows.\n * \n * Default impl assume that R = O or R = O[]\n * @param response\n */\n async *parseResponse(\n response: R,\n parent?: P,\n nextPageToken?: NPT\n ): AsyncIterable<O> {\n if (Array.isArray(response)) {\n for (const row of response) {\n yield row as any as O\n }\n } else {\n yield response as any as O\n }\n }\n\n}","import dayjs, { Dayjs } from \"dayjs\";\nimport { defaultDateTimeFormat } from \"../../constants/date\";\nimport { isDatetimeType } from \"../../helpers/typing\";\nimport { logger } from \"../../service/logger\";\nimport { loadJson } from \"../../utils\";\nimport { StreamId } from \"../metadata\";\nimport { RecordMessage, ReplicationMethodMessage, SchemaMessage, StateMessage } from \"../messages\";\nimport { ReplicationMethod } from \"../replication\";\nimport { extractStateForStream, finalizeStateProgressMarkers, incrementStreamState, InputTapState, StateService } from \"../state\";\nimport { ITarget } from \"../target/target\";\nimport cloneDeep from \"lodash/cloneDeep.js\";\nimport { Schema } from \"../schema\";\nimport Bluebird from \"bluebird\";\nimport { DEFAULT_MAX_CONCURRENT_STREAMS } from \"./tap\";\nimport { CounterMetric, EXECUTION_TIME_METRIC_NAME, getCounterMetrics, MetricConfiguration, ROWS_SYNCED_METRIC_NAME } from \"../../service/metric\";\nimport { format } from \"util\";\n\n/**\n * TODO: Handle non timestamp based replication key\n *\n * O: Type of a resulted row after post processing\n * C: Type of the tap configuration\n * P: For children Streams, this is the type of the parent\n */\nexport abstract class Stream<O = any, C = any, P = undefined> {\n\n // Runtime values, can't be overriden\n config: C;\n tapState: InputTapState;\n target: ITarget;\n\n replicationMethod: ReplicationMethod | undefined = undefined;\n selectedByDefault: boolean = true;\n STATE_MSG_FREQUENCY: number = 10;\n streamId: StreamId = \"default\";\n schemaPath: string | undefined = undefined;\n displayLabel: string | undefined = undefined;\n description: string | undefined = undefined;\n primaryKey: string[] = [];\n replicationKey: string | undefined = undefined;\n // When set, use the state from another stream for this stream\n useStateFromStreamId: string | undefined = undefined;\n\n children: Stream<any, any, O | O[]>[] = [];\n // If true, it means that the records in this stream are sorted by replicationKey.\n // If false, then the records are coming in an unsorted manner.\n isSorted: boolean = false;\n // If true, then no SCHEMA / RECORD messages will be sent for this Stream.\n // However, a STATE will still be emitted if the Stream is using an incremental sync type.\n isSilent: boolean = false;\n\n childConcurrency: number;\n\n // Optional total row count for percentage progress logging\n totalRows?: number;\n\n // Metrics configuration\n rowsSyncedMetricsConf: MetricConfiguration\n executionTimeMetricsConf: MetricConfiguration\n\n constructor(\n config: C,\n tapState: InputTapState,\n target: ITarget,\n childConcurrency: number = DEFAULT_MAX_CONCURRENT_STREAMS\n ) {\n this.config = config;\n this.tapState = cloneDeep(tapState);\n this.target = target;\n this.childConcurrency = childConcurrency;\n\n // Default metric configuration\n this.rowsSyncedMetricsConf = {\n isEnabled: () => !this.isSilent,\n getStreamIds: () => [this.streamId]\n }\n this.executionTimeMetricsConf = {\n isEnabled: () => !this.isSilent,\n getStreamIds: () => [this.streamId]\n }\n }\n\n // No root metadata: replication config is derived from stream defaults only\n\n /**\n * Sync this stream\n * Called only for streams with no parents, aka. \"root tap streams\"\n * @returns \n */\n sync = async (): Promise<void> => {\n try {\n const replicationMethod = this.configuredReplicationConfig().replicationMethod;\n logger.info(\n `🎬 Beginning ${replicationMethod} sync of stream '${this.streamId}'...`\n )\n\n await this.asyncInit();\n\n // Send a SCHEMA message to the downstream target\n await this._writeSchemaMessage();\n\n await this._writeReplicationMethodMessage();\n\n // Write the signpost\n await this._writeSignpostInState();\n\n // Sync the records themselves\n await this._syncRecords();\n\n // Flush the stream\n return this.flush();\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(`got an error while syncing streamId=%s, err: %s`, this.streamId, err.message))\n }\n throw err;\n }\n }\n\n flush = async (): Promise<void> => {\n const replicationMethod = this.configuredReplicationConfig().replicationMethod;\n logger.info(\n `🚽 Flushing ${replicationMethod} sync of stream '${this.streamId}' + all of its children...`\n )\n\n await this._flush();\n\n await Bluebird.map(this.children, child => {\n return child.flush();\n }, { concurrency: 3 });\n }\n\n // Private message authoring methods:\n\n /**\n * Write out a STATE message with the latest state.\n */\n _writeStateMessage = (): Promise<void> => {\n const message = new StateMessage(StateService.getInstance().get());\n return this.target.state(message);\n }\n\n /**\n * Write out a ACTIVATE_VERSION message.\n */\n _writeReplicationMethodMessage = async (): Promise<void> => {\n const method = this.configuredReplicationConfig().replicationMethod;\n const message = new ReplicationMethodMessage(this.streamId, method);\n\n await Bluebird.map(this.children, async c => {\n return c._writeReplicationMethodMessage()\n }, { concurrency: 3 })\n await this.target.replicationMethod(message);\n }\n\n /**\n * Write out a SCHEMA message with the stream schema.\n */\n _writeSchemaMessage = async (skipChildrenSchema?: boolean): Promise<void> => {\n\n if (!this.isSilent) {\n const schema = await this.getSchema();\n if (schema !== undefined) {\n const replicationConfig = this.configuredReplicationConfig();\n\n const message = new SchemaMessage({\n keyProperties: this.primaryKey,\n stream: this.streamId,\n schema: schema.jsonSchema,\n ...(replicationConfig.replicationKey ? { bookmarkProperties: [replicationConfig.replicationKey] } : {}),\n ...(this.displayLabel ? { displayLabel: this.displayLabel } : {}),\n ...(this.description ? { description: this.description } : {}),\n ...(schema.propertiesMetadata ? { propertiesMetadata: schema.propertiesMetadata } : {})\n })\n await this.target.schema(message);\n }\n }\n\n if (skipChildrenSchema !== true) {\n await Bluebird.map(this.children, async (child) => {\n await child._writeSchemaMessage();\n }, { concurrency: 3 });\n }\n }\n\n // Private bookmarking methods\n\n _writeSignpostInState = async () => {\n const signpostMoment = await this.getReplicationKeySignpost();\n const signpostValue = signpostMoment?.format(defaultDateTimeFormat);\n\n if (signpostValue) {\n StateService.getInstance().setBookmarkSignpost(this.streamId, signpostValue);\n }\n }\n\n /**\n * Update state of stream with data from the provided record. \n */\n _incrementStreamState = (latestRecord: O): void => {\n\n if (latestRecord) {\n const replicationConfig = this.configuredReplicationConfig()\n if ([\n \"INCREMENTAL\",\n \"LOG_BASED\",\n ].includes(replicationConfig.replicationMethod)) {\n // If the stream is using another stream state, it doesn't own the state and can't increment it\n if (this.useStateFromStreamId) {\n return;\n }\n // If the replication method was forced, it can be that the stream is the child of anohter stream that is managing the state (ex. a paginated stream). \n // The state is not owned by the current stream then.\n if (this.replicationMethod && !this.replicationKey) {\n return;\n }\n\n // If the stream has been detected as being incremental and has no excuses for not owning its state, it should have the replicationKey\n if (!replicationConfig.replicationKey) {\n throw new Error(`Could not detect replication key for '${this.streamId}' stream\"\n replication method=${replicationConfig.replicationMethod})`\n )\n }\n\n const stateServiceInst = StateService.getInstance();\n const state = stateServiceInst.getBookmark(this.streamId);\n\n const newState = incrementStreamState(\n state,\n replicationConfig.replicationKey,\n latestRecord,\n this.isSorted\n )\n\n StateService.getInstance().setBookmark(this.streamId, newState)\n }\n }\n }\n\n /**\n * Return True if the stream uses a timestamp-based replication key.\n * \n * Developers can override with `is_timestamp_replication_key = True` in\n order to force this value.\n */\n isTimestampReplicationKey = async (): Promise<boolean> => {\n\n const replicationConfig = this.configuredReplicationConfig()\n\n if (!replicationConfig.replicationKey) {\n return false;\n }\n\n const schema = await this.getSchema();\n if (!schema || !schema.jsonSchema || !schema.jsonSchema.properties) {\n return false;\n }\n\n const typeFromSchema = schema.jsonSchema[\"properties\"][replicationConfig.replicationKey]\n if (!typeFromSchema) {\n return false;\n }\n\n return isDatetimeType(typeFromSchema);\n }\n\n /**\n * Return state timestamp if set for the stream, \n * or `start_date` config if set, \n * or the UNIX Epoch\n **/\n getStartingTimestamp(): Dayjs {\n const streamIdToReadFrom = this.useStateFromStreamId\n ? this.useStateFromStreamId\n : this.streamId;\n const state = extractStateForStream(this.tapState, streamIdToReadFrom);\n\n const startDate = (this.config as any).start_date as string | undefined;\n const replicationConfig = this.configuredReplicationConfig();\n\n logger.debug(`${this.streamId}: state.replicationKeyValue: ${state.replicationKeyValue}, \n state.replicationKey: ${state.replicationKey},\n this.replicationKey: ${replicationConfig.replicationKey}`)\n\n if (state.replicationKeyValue) {\n logger.debug(`${this.streamId} - getStartingTimestamp -> Returning replication key value: ${state.replicationKeyValue}`)\n return dayjs(state.replicationKeyValue);\n } else if (startDate) {\n logger.debug(`${this.streamId} - getStartingTimestamp -> Returning config start date: ${startDate}`)\n return dayjs(startDate)\n } else {\n logger.debug(`${this.streamId} - getStartingTimestamp -> Returning EPOCH (1970)`)\n return dayjs(0);\n }\n }\n\n /**\n * Return the max allowable bookmark value for this stream's replication key.\n * \n * For timestamp-based replication keys, this defaults to `dayjs()`. For\n * non-timestamp replication keys, default to `undefined`.\n * \n * Override this value to prevent bookmarks from being advanced in cases where we\n * may only have a partial set of records.\n */\n getReplicationKeySignpost = async (): Promise<Dayjs | undefined> => {\n\n if (await this.isTimestampReplicationKey()) {\n return dayjs()\n }\n\n return undefined\n }\n\n /**\n * Return the default replication method for the stream that will be used to write the catalog.\n */\n defaultReplicationConfig = (): {\n replicationMethod: ReplicationMethod,\n replicationKey: string | undefined,\n // When replication method is forced, it means that end user can't override it.\n isForced: boolean\n } => {\n if (this.replicationMethod) {\n return {\n replicationMethod: this.replicationMethod,\n replicationKey: this.replicationKey,\n isForced: true\n }\n }\n if (this.replicationKey || this.useStateFromStreamId) {\n return {\n replicationMethod: ReplicationMethod.INCREMENTAL,\n replicationKey: this.replicationKey,\n isForced: true\n }\n }\n\n return {\n replicationMethod: ReplicationMethod.FULL_TABLE,\n replicationKey: undefined,\n isForced: false\n }\n }\n\n /**\n * Return the configured replication method that will be used for the sync.\n */\n configuredReplicationConfig = (): {\n replicationMethod: ReplicationMethod,\n replicationKey: string | undefined\n } => {\n const defaults = this.defaultReplicationConfig();\n return {\n replicationMethod: defaults.replicationMethod,\n replicationKey: defaults.replicationKey\n }\n }\n\n // Private sync methods:\n async _syncRecords(parent?: P): Promise<void> {\n let rowsSent = 0;\n\n let recordSyncedMetrics: CounterMetric[] = [];\n if (this.rowsSyncedMetricsConf.isEnabled() === true) {\n recordSyncedMetrics = getCounterMetrics(\n ROWS_SYNCED_METRIC_NAME,\n this.rowsSyncedMetricsConf.getStreamIds\n ? this.rowsSyncedMetricsConf.getStreamIds()\n : []\n )\n }\n\n let executionTimeMetrics: CounterMetric[] = [];\n if (this.executionTimeMetricsConf.isEnabled() === true) {\n executionTimeMetrics = getCounterMetrics(\n EXECUTION_TIME_METRIC_NAME,\n this.executionTimeMetricsConf.getStreamIds\n ? this.executionTimeMetricsConf.getStreamIds()\n : []\n )\n }\n\n const startTime = new Date().getTime();\n\n for await (const row of this._getRecords(parent)) {\n\n if ((rowsSent - 1) % this.STATE_MSG_FREQUENCY == 0) {\n await this._writeStateMessage()\n }\n\n const recordMessage = new RecordMessage(\n { ...row },\n this.streamId\n )\n\n if (!this.isSilent) {\n await this.target.record(recordMessage);\n }\n\n await Bluebird.map(this.children, async (child) => {\n await child.asyncInit(row);\n return child._syncRecords(row);\n },\n {\n concurrency: this.childConcurrency\n });\n this._incrementStreamState(row);\n recordSyncedMetrics.forEach((metric) => {\n metric.increment();\n })\n rowsSent += 1;\n\n if (rowsSent % 1000 === 0) {\n const percentStr = this.totalRows\n ? ` (${Math.round((rowsSent / this.totalRows) * 100)}%)`\n : \"\";\n logger.info(`⏳ Stream: ${this.streamId} - ${rowsSent} records synced so far...${percentStr}`);\n }\n }\n\n const stateServiceInst = StateService.getInstance();\n const state = stateServiceInst.getBookmark(this.streamId);\n const newState = finalizeStateProgressMarkers(state);\n stateServiceInst.setBookmark(this.streamId, newState);\n\n if (!parent) {\n logger.info(`✅ Completed sync for stream: ${this.streamId} (${rowsSent} records)`);\n } else {\n logger.debug(`✅ Completed sync for sub-stream: ${this.streamId} (${rowsSent} records)`);\n }\n\n await this._writeStateMessage();\n const endTime = new Date().getTime();\n const executionTimeMs = endTime - startTime;\n executionTimeMetrics.forEach(metric => {\n metric.increment(executionTimeMs);\n })\n\n }\n\n // Overridable Methods\n\n asyncInit(parent?: P): Promise<void> {\n return Promise.resolve()\n }\n\n /**\n * Return the stream schema.\n * \n * Can be overriden to return a dynamic schema\n */\n getSchema(): Promise<Schema | undefined> {\n logger.debug(`stream: ${this.streamId} - getSchema() is called`)\n if (this.schemaPath) {\n const schema = loadJson(`schemas/${this.schemaPath}`)\n return Promise.resolve({ jsonSchema: schema });\n } else {\n if (this.isSilent) {\n return Promise.resolve(undefined);\n }\n throw new Error(`Stream=${this.streamId} - No schema path was passed.\n Either you forgot to fill the the \\`schemaPath\\` property,\n or to override the getSchema() method.`)\n }\n }\n\n getRowCount(): Promise<number | undefined> {\n return Promise.resolve(undefined)\n }\n\n /**\n * Abstract row generator function. Must be overridden by the child class.\n */\n _getRecords(parent?: P): AsyncIterable<O> {\n throw new Error(`Stream._getRecords() - Should be implemented by child class`);\n }\n\n /**\n * Return the list of keys that can be configured in the UI by the end user as the replication key\n * @returns \n */\n getValidReplicationKeys(): Promise<string[]> {\n return Promise.resolve([]);\n }\n\n /**\n * Called at the end of the sync. Use to flush all records before closing the Stream.\n * @returns \n */\n async _flush(): Promise<void> {\n await Promise.resolve();\n }\n}","\ninterface TypeDef {\n anyOf?: TypeDef[]\n type: string | string[]\n format?: \"date-time\"\n}\n/**\n * Return True if JSON Schema type definition is a 'date-time' type.\n * \n * Also returns True if 'date-time' is nested within an 'anyOf' type Array.\n\n * @param typeDef \n * @returns \n */\nexport const isDatetimeType = (typeDef: TypeDef): boolean => {\n\n if (!typeDef) {\n throw new Error(\"Could not detect type from empty typeDef param.\")\n }\n\n if (typeDef[\"anyOf\"] !== undefined) {\n for (const subTypeDef of typeDef[\"anyOf\"]) {\n if (isDatetimeType(subTypeDef)) {\n return true\n }\n }\n return false\n }\n\n else if (typeDef[\"type\"] !== undefined) {\n return typeDef[\"format\"] === \"date-time\"\n }\n\n throw new Error(\n `Could not detect type of key using schema '${typeDef}'`\n )\n\n}","import cloneDeep from \"lodash/cloneDeep.js\";\nimport { logger } from \"../../service/logger\";\nimport { InputTapState, StateService } from \"../state\";\nimport { StateProvider } from \"../state-provider/types\";\nimport { ITarget } from \"../target/target\";\nimport { Stream } from \"./stream\";\nimport Bluebird from \"bluebird\";\n\nexport const DEFAULT_MAX_CONCURRENT_STREAMS = 5;\n\nexport type SyncOptions = { include?: string[]; exclude?: string[] };\n\nexport abstract class Tap<C> {\n target: ITarget;\n config: C;\n streams: Stream[];\n concurrency: number = DEFAULT_MAX_CONCURRENT_STREAMS;\n stateProvider: StateProvider;\n tapState: InputTapState;\n\n // To be implemented by the concrete tap implementation\n abstract init(): Promise<void>;\n\n constructor(\n target: ITarget,\n config: C,\n stateProvider: StateProvider\n ) {\n this.streams = [];\n this.target = target;\n this.config = config\n this.stateProvider = stateProvider;\n this.tapState = { bookmarks: {} };\n }\n sync = async (options?: SyncOptions): Promise<void> => {\n\n // Set the initial state from the state provider\n const initialState = await this.stateProvider.getState();\n if(initialState.state && initialState.state.bookmarks) {\n this.tapState = cloneDeep(initialState.state);\n }\n\n await this.init();\n logger.info(`🚀 Start syncing`)\n\n const state = StateService.getInstance().get();\n logger.info(`📍 Received state: %j`, state)\n\n const envInclude = process.env.TAP_STREAMS\n ? process.env.TAP_STREAMS.split(',').map(s => s.trim()).filter(s => s.length > 0)\n : undefined;\n\n const include = options?.include && options.include.length > 0\n ? options.include\n : envInclude;\n const exclude = new Set((options?.exclude || []).map(s => s.trim()))\n\n let streamsToRun = this.streams.filter(s => !s.isSilent);\n if (include && include.length > 0) {\n const includeSet = new Set(include);\n streamsToRun = streamsToRun.filter(s => includeSet.has(s.streamId));\n }\n if (exclude.size > 0) {\n streamsToRun = streamsToRun.filter(s => !exclude.has(s.streamId));\n }\n\n const selectedStreamIds = streamsToRun.map(s => s.streamId);\n logger.info(`🥳 Syncing streams: %s`, selectedStreamIds.join(\",\"))\n\n await Bluebird.map(streamsToRun, (stream) => {\n return stream.sync();\n }, { concurrency: this.concurrency });\n\n logger.debug(`[TAP] All streams have finished syncing. We send the [complete] signal to the target.`)\n await this.target.complete();\n return Promise.resolve();\n };\n\n // Used to clean up any ressource before exit\n end(): Promise<void> {\n return Promise.resolve()\n }\n}","import isPlainObject from \"lodash/isPlainObject.js\";\n\n// Truncate potentially large query params for logging efficiency\nconst MAX_QS_KEYS = 10;\nconst MAX_QS_STRING_LENGTH = 200;\nconst MAX_QS_ARRAY_ITEMS = 5;\nconst MAX_QS_DEPTH = 2;\n\nfunction truncateQueryParams(value: any, depth: number = 0): any {\n if (value == null) return value;\n if (depth >= MAX_QS_DEPTH) return \"[…]\";\n\n if (typeof value === \"string\") {\n if (value.length <= MAX_QS_STRING_LENGTH) return value;\n const truncated = value.slice(0, MAX_QS_STRING_LENGTH);\n return `${truncated}…(+${value.length - MAX_QS_STRING_LENGTH} chars)`;\n }\n\n if (Array.isArray(value)) {\n const items = value\n .slice(0, MAX_QS_ARRAY_ITEMS)\n .map((v) => truncateQueryParams(v, depth + 1));\n const omittedCount = Math.max(0, value.length - MAX_QS_ARRAY_ITEMS);\n if (omittedCount > 0) {\n items.push(`[… ${omittedCount} more items]`);\n }\n return items;\n }\n\n if (isPlainObject(value)) {\n const keys = Object.keys(value);\n const result: Record<string, any> = {};\n for (const key of keys.slice(0, MAX_QS_KEYS)) {\n result[key] = truncateQueryParams((value as any)[key], depth + 1);\n }\n const omittedCount = Math.max(0, keys.length - MAX_QS_KEYS);\n if (omittedCount > 0) {\n (result as any)[\"__omittedKeys\"] = omittedCount;\n }\n return result;\n }\n\n return value;\n}\n\nexport function getTruncatedParamsForLog(params: any): any {\n try {\n return truncateQueryParams(params);\n } catch {\n return \"[unserializable params]\";\n }\n}","import { logger } from \"../../service/logger\";\nimport { StreamId } from \"../metadata\";\nimport { ReplicationMethod } from \"../replication\";\nimport { FlattenedSchema, InternalTableField, JSONSchemaFieldDefinition, WarehouseTableField } from \"./models\";\nimport { RenameColumnStore } from \"./renameColumnStore\";\nimport retry from 'async-retry';\n\n// This class is a Stateless interface with the APIs of a Warehouse when it comes to dealing with\n// loading a stream into a table.\n\n// TODO: Move flattenedSchema + renamedColumnStore into the StreamDbState class.\nexport abstract class StreamWarehouseSyncService {\n\n streamId: StreamId;\n database: string;\n schema: string;\n table: string;\n\n flattenedSchema: FlattenedSchema;\n primaryKeys: string[];\n maxRetryCount = 5;\n\n renamedColumnStore: RenameColumnStore;\n\n constructor(\n streamId: StreamId,\n database: string,\n schema: string,\n table: string,\n renameColumnStore: RenameColumnStore\n ) {\n this.streamId = streamId;\n this.database = database;\n this.schema = schema;\n this.table = table;\n\n this.primaryKeys = [];\n this.flattenedSchema = {};\n this.renamedColumnStore = renameColumnStore;\n }\n\n /////////////////////////////////////////////////////////////////\n ///////// Functions to be implented for each Warehouse //////////\n /////////////////////////////////////////////////////////////////\n\n // Function to adapt to the Warehouse SQL dialect\n abstract safeColumnName: (unsafe: string) => string;\n abstract getWarehouseTypeFromJSONSchema: (definition: JSONSchemaFieldDefinition) => string | undefined;\n getcolumnNameWithTypeSuffix(colName: string, warehouseType: string | undefined): string {\n return `${colName}__${warehouseType}`\n }\n // In order to not overload Warehouse, we update the destination table by chunks of columns as updating all the columns at once is generating a too complex query\n abstract getMergeQueries: () => string[]\n abstract getReplaceQueries: () => string[]\n abstract getAppendQueries: () => string[]\n\n // Functions to provision the tables, columns, etc.\n abstract createDatabaseAndSchemaIfNotExists: (retryCount: number) => Promise<void>;\n abstract createTable: () => Promise<void>;\n abstract addColumns: (fields: InternalTableField[]) => Promise<void>;\n\n // Functions to deal with the staging area that will be used to load data in the Warehouse\n abstract createStagingArea: () => Promise<void>;\n abstract loadStreamInStagingArea: (localFilePath: string) => Promise<void>;\n abstract deleteStagingArea: () => Promise<void>;\n\n // Function to read from the Warehouse\n abstract getTablesInSchema: () => Promise<{ tableName: string }[]>;\n abstract getTableColumnsFromWarehouse: () => Promise<WarehouseTableField[]>;\n\n // Function to execute queries on the warehouse\n abstract runQueries: (queries: string[]) => Promise<void>;\n\n // Function to serialize the record\n abstract getSerializedRecord: (record: any) => string;\n\n // Orchestration functions\n updateSchemaInWarehouse = async (\n flattenedSchema: FlattenedSchema,\n primaryKeys: string[]\n ) => {\n await this.createDatabaseAndSchemaIfNotExists(0);\n\n this.flattenedSchema = flattenedSchema;\n\n this.renamedColumnStore.computeColumnNameForStream(\n this.streamId,\n flattenedSchema\n )\n\n this.primaryKeys = primaryKeys.map(pk => {\n return this.renamedColumnStore.getColumnTranslation(this.streamId, pk)!;\n });\n\n await this.syncTableSchemaWithWarehouse();\n }\n\n renameColumns(record: any): any {\n const renamedColsRecord: any = {}\n\n Object.keys(record).forEach(originalColName => {\n renamedColsRecord[this.renamedColumnStore.getColumnTranslation(this.streamId, originalColName)!] = record[originalColName]\n })\n return renamedColsRecord;\n }\n\n // Function to execute queries on the warehouse\n protected runQueriesWithRetry = async (queries: string[]): Promise<void> => {\n await retry(\n async () => {\n await this.runQueries(queries);\n },\n {\n retries: 5,\n }\n );\n };\n\n private syncTableSchemaWithWarehouse = async () => {\n\n const tables = await this.getTablesInSchema();\n const foundTables = tables.filter(table => this.table === table.tableName);\n\n if (foundTables.length === 0) {\n logger.info(`🐣 Database: \\`${this.database}\\`, Schema: \\`${this.schema}\\`, Table: \\`${this.table}\\` does not exist in Warehouse. Creating it...`)\n await this.createTable();\n } else if (foundTables.length === 1) {\n logger.info(`👋 Database: \\`${this.database}\\`, Schema: \\`${this.schema}\\`, Table: \\`${this.table}\\` already exists. Updating the columns if needed.`);\n await this.updateTableColumns();\n }\n }\n\n /**\n * When there is a conflict between the synced data type and the data type of an\n * already existing column in the Warehouse, this create a new column in Warehouse with the new\n * datatype as suffix.\n * \n * This refer the fact that data should now be synced with the new column.\n * \n * @param tableFields \n */\n private addVersionedColumns = async (tableFields: InternalTableField[]) => {\n\n if (tableFields.length > 0) {\n logger.info(`🛂 Stream: ${this.streamId} - Versionning following columns in Warehouse schema: ${JSON.stringify(tableFields)}`)\n\n const columnsFromWarehouse = await this.getTableColumnsFromWarehouse();\n const columnNamesFromWarehouse = columnsFromWarehouse.map(col => col.name);\n\n let columnsToBeAddedInWarehouse: InternalTableField[] = [];\n tableFields.forEach(tblField => {\n const safeName = tblField.name as string;\n const warehouseTypeToBeUsed = this.getWarehouseTypeFromJSONSchema(tblField.definition)\n const columnNameWithTypeSuffix = this.getcolumnNameWithTypeSuffix(safeName, warehouseTypeToBeUsed)\n\n // Rewrite the safe mapping of the column to the versionned column\n this.renamedColumnStore.getUnsafeToSafeColumnMapping(this.streamId)[tblField.unsafeName] = columnNameWithTypeSuffix;\n\n if (!columnNamesFromWarehouse.includes(columnNameWithTypeSuffix)) {\n columnsToBeAddedInWarehouse.push({\n unsafeName: columnNameWithTypeSuffix,\n name: columnNameWithTypeSuffix,\n definition: tblField.definition\n })\n }\n })\n\n if (columnsToBeAddedInWarehouse.length > 0) {\n await this.addColumns(columnsToBeAddedInWarehouse);\n }\n }\n }\n\n private updateTableColumns = async () => {\n\n const columnsFromWarehouse = await this.getTableColumnsFromWarehouse();\n const columnNamesFromWarehouse = columnsFromWarehouse.map(col => col.name);\n\n const columnsMappingStore = this.renamedColumnStore.getUnsafeToSafeColumnMapping(this.streamId);\n const columnsToAdd: InternalTableField[] = Object.keys(columnsMappingStore)\n .filter(unsafeColumnKey => {\n const safeColumnName = columnsMappingStore[unsafeColumnKey];\n if (!safeColumnName) {\n return false;\n }\n return !columnNamesFromWarehouse.includes(safeColumnName);\n })\n .map(unsafeColumnKey => {\n const safeColumnName = columnsMappingStore[unsafeColumnKey];\n const definition = this.flattenedSchema[unsafeColumnKey];\n if (!safeColumnName || !definition) {\n return undefined as unknown as InternalTableField;\n }\n return {\n unsafeName: unsafeColumnKey,\n name: safeColumnName,\n definition\n }\n })\n .filter((item): item is InternalTableField => !!item)\n\n await this.addColumns(columnsToAdd);\n\n const columnsToVersion: InternalTableField[] = Object.keys(this.flattenedSchema)\n // We keep only the columns already declared in Warehouse but with a different type\n .filter(unsafeColumnKey => {\n const definition = this.flattenedSchema[unsafeColumnKey];\n if (!definition) {\n return false;\n }\n const warehouseTypeToBeUsed = this.getWarehouseTypeFromJSONSchema(definition)\n if (warehouseTypeToBeUsed) {\n const safeName = this.safeColumnName(unsafeColumnKey);\n if (columnNamesFromWarehouse.includes(safeName)) {\n const columnFromWarehouse = columnsFromWarehouse.find(col => col.name === safeName);\n\n if (!columnFromWarehouse) {\n throw new Error(`We can't find in Warehouse schema any column definition for colName: ${safeName}`);\n }\n\n const { type } = columnFromWarehouse;\n\n if (warehouseTypeToBeUsed !== type) {\n return true;\n }\n }\n }\n return false;\n })\n .map(unsafeColumnKey => {\n const definition = this.flattenedSchema[unsafeColumnKey];\n if (!definition) {\n return undefined as unknown as InternalTableField;\n }\n return {\n unsafeName: unsafeColumnKey,\n name: this.safeColumnName(unsafeColumnKey),\n definition\n }\n })\n .filter((tableField): tableField is InternalTableField => !!tableField);\n\n await this.addVersionedColumns(columnsToVersion);\n\n }\n\n mergeTempTableWithDestination = async (\n replicationMethod: ReplicationMethod\n ) => {\n\n let mergeQueries: string[] = [];\n if (replicationMethod === \"FULL_TABLE\") {\n mergeQueries = this.getReplaceQueries();\n } else if (replicationMethod === \"INCREMENTAL\") {\n mergeQueries = this.getMergeQueries();\n } else if (replicationMethod === \"APPEND\") {\n mergeQueries = this.getAppendQueries();\n } else if (replicationMethod === \"LOG_BASED\") {\n mergeQueries = this.getMergeQueries();\n }\n\n logger.info(`🍆 Table=${this.table} - Merging staging data with method ${replicationMethod}`);\n logger.debug(`Table=${this.table} - Merge queries: %j`, mergeQueries);\n\n await this.runQueriesWithRetry(mergeQueries);\n\n }\n\n}","import { ErrorObject } from \"ajv\";\nimport { StreamId } from \"../metadata\";\n\nexport class SchemaValidationError extends Error {\n\n streamId: StreamId;\n validationErrors: ErrorObject[];\n\n constructor(message: string, streamId: StreamId, errors: ErrorObject[]) {\n super(message); // (1)\n this.name = \"SchemaValidationError\"; // (2)\n this.streamId = streamId;\n this.validationErrors = errors;\n }\n\n}\n\nexport class MissingFieldInSchemaError extends Error {\n\n streamId: StreamId;\n\n constructor(message: string, streamId: StreamId) {\n super(message); // (1)\n this.name = \"MissingFieldInSchemaError\"; // (2)\n this.streamId = streamId;\n }\n\n}\n\nexport class MissingSchemaError extends Error {\n\n streamId: StreamId;\n\n constructor(message: string, streamId: StreamId) {\n super(message); // (1)\n this.name = \"MissingSchemaError\"; // (2)\n this.streamId = streamId;\n }\n\n}","import { WriteStream } from \"fs\"\nimport { StreamId } from \"../metadata\";\n\nexport interface FlattenedSchema {\n [unsafePropertyName: string]: JSONSchemaFieldDefinition\n}\n\nexport interface JSONSchemaFieldDefinition {\n type: string[] | string\n format?: \"date-time\" | \"json\";\n items?: JSONSchemaFieldDefinition;\n}\n\nexport interface WarehouseTableField {\n name: string; // This name is already safe as it's coming from the Warehouse\n type: string;\n}\n\nexport interface InternalTableField {\n unsafeName: string;\n name: string, // This name should be already safe for the Warehouse\n definition: JSONSchemaFieldDefinition\n}\n\nexport interface TempFile {\n stream: WriteStream,\n path: string;\n}\n\nexport interface StreamWithTempFile {\n streamId: StreamId,\n tempFile: TempFile\n}\n\nexport const DEFAULT_SYNCED_AT_COLUMN = \"_wly_synced_at\";\n\nexport interface BaseConfig {\n connector_id: string;\n database: string;\n schema: string;\n syncedAtColumnName?: string;\n}","import { DEFAULT_SYNCED_AT_COLUMN, FlattenedSchema } from \"./models\";\n\nexport const removeParasiteProperties = (record: any, schema: FlattenedSchema) => {\n const schemaKeys = Object.keys(schema);\n Object.keys(record).forEach(key => {\n if (!schemaKeys.includes(key)) {\n delete record[key]\n }\n })\n\n return record;\n}\n\nexport const addWhalyFields = (record: any, batchDate: string, columnName: string = DEFAULT_SYNCED_AT_COLUMN) => {\n return {\n ...record,\n [columnName]: batchDate\n }\n}","import { logger } from \"../../service/logger\";\nimport { FlattenedSchema } from \"./models\";\n\n// { \"streamId\": { \"originalColumnName\": \"renamedColumnName\" } }\nexport interface ColumnMappingStoreUnsafeToSafe {\n [originalColumnName: string]: string\n}\n\nexport type SafeColumnNameConverterFn = (unsafe: string) => string\n\n/**\n * This stateful class is to be used to store all the columns names mapping between the \"raw\" column name\n * found in the records and the destination column in the data warehouse\n * \n * A mapping exists between the fields declared by the Tap and the reality in the Warehouse for those reasons:\n * - Columns that are versionned due to type changes since the last load\n * - Columns that have a name conflict after \"Warehouse\" sanitization\n */\nexport class RenameColumnStore {\n\n // Store all the mappings store for all streamId\n private renamedColumns: { [streamId: string]: ColumnMappingStoreUnsafeToSafe };\n\n private safeColumnNameConverter?: SafeColumnNameConverterFn;\n\n constructor() {\n this.renamedColumns = {};\n }\n\n setSafeColumnNameConverter = (fn: SafeColumnNameConverterFn): void => {\n this.safeColumnNameConverter = fn;\n }\n\n // This function has a side effect on:\n // - `this.renamedColumns`\n // This isn't very clean and should be updated to write a pure version of this function\n computeColumnNameForStream = (\n streamId: string,\n flattenedSchema: FlattenedSchema,\n ) => {\n const safeColNameConv = this.safeColumnNameConverter;\n if (!safeColNameConv) {\n throw new Error(`safeColumnNameConverter is not defined!`)\n }\n const colSafeToUnsafeMapping = Object.keys(flattenedSchema)\n .sort()\n .reduce<{ [safeColName: string]: string }>((acc, unsafeColName) => {\n const safeColName = safeColNameConv(unsafeColName);\n if (!acc[safeColName]) {\n acc[safeColName] = unsafeColName;\n } else {\n logger.info(`🚨 Stream: ${streamId} - We have a column name conflict after sanitization for column unsafe=${unsafeColName}. We'll rename the sanitized name to a non taken name.\n Details: unsafeColName=${unsafeColName} is colliding with: ${acc[safeColName]}`)\n for (let i = 1; ; i++) {\n if (!acc[`${safeColName}_${i}`]) {\n acc[`${safeColName}_${i}`] = unsafeColName;\n break;\n }\n }\n }\n return acc;\n }, {});\n\n const colUnsafeToSafeMapping = Object.keys(colSafeToUnsafeMapping)\n .reduce<{ [unssafeColName: string]: string }>((acc, safeColName) => {\n const unsafeColname = colSafeToUnsafeMapping[safeColName];\n if (unsafeColname) {\n acc[unsafeColname] = safeColName;\n }\n return acc;\n }, {})\n\n // Init the renamedColumns dict\n const mapping = this.renamedColumns[streamId] || {};\n this.renamedColumns[streamId] = mapping;\n Object.keys(colUnsafeToSafeMapping).forEach(unsafeColName => {\n const safeName = colUnsafeToSafeMapping[unsafeColName];\n if (safeName) {\n mapping[unsafeColName] = safeName;\n }\n });\n }\n\n getColumnTranslation = (\n streamId: string,\n originalColumnName: string\n ): string => {\n if (!this.renamedColumns[streamId]) {\n throw new Error(\n `StreamId=${streamId} - Columns Mapping Store is not initialized! \n Trying to get renamed value for column '${originalColumnName}'`\n )\n }\n const value = this.renamedColumns[streamId][originalColumnName];\n if (!value) {\n throw new Error(`StreamId=${streamId} - No renamed value found for column '${originalColumnName}'`)\n }\n return value;\n }\n\n getUnsafeToSafeColumnMapping = (streamId: string): ColumnMappingStoreUnsafeToSafe => {\n const mapping = this.renamedColumns[streamId];\n if (!mapping) {\n throw new Error(`StreamId=${streamId} - Columns Mapping Store is not initialized!`)\n }\n return mapping;\n }\n\n isReady = (streamId: string): boolean => {\n if (!this.renamedColumns[streamId]) {\n return false;\n } else {\n return true;\n }\n }\n}","import { StreamId } from \"../metadata\";\nimport { FlattenedSchema } from \"./models\";\nimport { logger } from \"../../service/logger\";\nimport { gracefulExit } from \"../../service/exit\";\n\nexport const flattenSchema = <T>(streamId: StreamId, schema: T): FlattenedSchema => {\n\n logger.debug(`Flattening schema for stream: ${streamId}`)\n\n try {\n const mSchema = schema as any;\n\n if (!mSchema[\"properties\"]) {\n return {};\n }\n\n const properties = mSchema[\"properties\"];\n\n const flattenedSchema = Object.keys(properties).reduce<FlattenedSchema>((acc, propertyName) => {\n const propertySchema = properties[propertyName];\n const columnName = propertyName;\n\n if (!propertySchema) {\n return acc;\n }\n\n if (!propertySchema[\"type\"]) {\n throw new Error(`We don't have any \\`type\\` for the property: \\`${propertyName}\\`.\n Schema of the property is: ${JSON.stringify(propertySchema)}`)\n }\n\n acc[columnName] = {\n type: propertySchema[\"type\"],\n format: propertySchema[\"format\"],\n items: propertySchema[\"items\"]\n };\n\n return acc;\n }, {});\n\n return flattenedSchema;\n } catch (err: any) {\n logger.error(`There was an error when processing the schema of stream:\\`${streamId}\\`: err: ${err.message} - ${err.stack}.\n Processed schema: ${JSON.stringify(schema)}`);\n gracefulExit(1);\n return {};\n }\n\n}","import { ReplicationMethodMessage, RecordMessage, SchemaMessage, StateMessage } from \"../messages\";\nimport { TargetSchemaHook, TargetSchemaHookInput } from \"./targetHook\";\nimport Ajv from \"ajv\";\nimport addFormats from \"ajv-formats\";\nimport dayjs, { Dayjs } from \"dayjs\";\nimport { RenameColumnStore, SafeColumnNameConverterFn } from \"./renameColumnStore\";\nimport { StreamState } from \"./streamDbState\";\nimport { logger } from \"../../service/logger\";\nimport { MissingSchemaError, SchemaValidationError } from \"./error\";\nimport { addWhalyFields, removeParasiteProperties } from \"./record\";\nimport { BaseConfig, DEFAULT_SYNCED_AT_COLUMN, FlattenedSchema } from \"./models\";\nimport { flattenSchema } from \"./schema\";\nimport { StreamWarehouseSyncService } from \"./dbSync\";\nimport { Semaphore } from \"async-mutex\";\nimport { ReplicationMethod } from \"../replication\";\nimport Bluebird from \"bluebird\";\nimport { StateProvider } from \"../state-provider/types\";\nimport { StreamId } from \"../metadata\";\n\nconst semaphore = new Semaphore(1);\n\nexport abstract class ITarget<C extends BaseConfig = BaseConfig> {\n config: C;\n syncedAtColumnName: string;\n schemaHooks: TargetSchemaHook[]\n syncTime: Dayjs;\n stateProvider: StateProvider;\n\n // Latest state message received from the Tap\n // Not yet flushed as we didn't upload the stream data since receiving it \n batchedState: any;\n\n // Latest \"flushed\" state message\n // A state message is flushed when we do a stream upload.\n flushedState: any;\n\n renameColumnStore: RenameColumnStore;\n\n streams: {\n [streamName: string]: StreamState\n }\n\n // JSON Schema validator (ajv — pre-compiles schemas into optimized JS functions)\n ajv: Ajv\n\n constructor(config: C, stateProvider: StateProvider) {\n this.config = config;\n this.syncedAtColumnName = config.syncedAtColumnName ?? DEFAULT_SYNCED_AT_COLUMN;\n this.stateProvider = stateProvider;\n this.schemaHooks = [];\n\n this.streams = {}\n\n this.batchedState = {}\n this.flushedState = {}\n\n this.ajv = addFormats(new Ajv({ allErrors: true, strict: false }));\n this.syncTime = dayjs();\n\n this.renameColumnStore = new RenameColumnStore()\n }\n\n ///////////////////////////////////////////\n //// To be overriden by child classes /////\n ///////////////////////////////////////////\n static requiredConfigKeys: string[] = [];\n // Generate instance of DBSync\n abstract newDBSyncInstance: (\n streamId: StreamId,\n database: string,\n schema: string,\n table: string\n ) => StreamWarehouseSyncService;\n // Function to render safe table names\n abstract genTableName: (streamId: string) => string;\n // Function to render safe column names\n abstract safeColumnNameConverter: SafeColumnNameConverterFn;\n // Convert the date values of a record into valid ones for the Warehouse\n abstract validateDateRange: (reacord: any, schema: FlattenedSchema) => any;\n // Convert the number values of a record into valid ones for the Warehouse\n abstract convertNumberIntoDecimal: (record: any, schema: FlattenedSchema) => any;\n\n ////////////////////////////////////////////\n /////////// Implementation /////////////////\n ////////////////////////////////////////////\n\n // Analyze schema changes to determine if they are breaking or non-breaking\n private analyzeSchemaChanges = (\n previousSchema: FlattenedSchema,\n newSchema: FlattenedSchema,\n streamId: string\n ): { hasBreakingChanges: boolean; changes: string[] } => {\n const changes: string[] = [];\n let hasBreakingChanges = false;\n\n // Get all column names from both schemas\n const prevColumns = new Set(Object.keys(previousSchema).filter(col => col !== this.syncedAtColumnName));\n const newColumns = new Set(Object.keys(newSchema).filter(col => col !== this.syncedAtColumnName));\n\n // Check for new columns (non-breaking)\n for (const columnName of newColumns) {\n if (!prevColumns.has(columnName)) {\n changes.push(`Added column '${columnName}'`);\n }\n }\n\n // Check for removed columns (breaking)\n for (const columnName of prevColumns) {\n if (!newColumns.has(columnName)) {\n changes.push(`Removed column '${columnName}'`);\n hasBreakingChanges = true;\n }\n }\n\n // Check for type changes in existing columns (breaking)\n for (const columnName of prevColumns) {\n if (newColumns.has(columnName)) {\n const prevType = previousSchema[columnName];\n const newType = newSchema[columnName];\n\n // Compare the type definitions\n if (JSON.stringify(prevType) !== JSON.stringify(newType)) {\n changes.push(`Changed type of column '${columnName}'`);\n hasBreakingChanges = true;\n }\n }\n }\n\n if (changes.length === 0) {\n changes.push('No schema changes detected');\n }\n\n logger.debug(`StreamId=${streamId} - Schema analysis: ${hasBreakingChanges ? 'BREAKING' : 'NON-BREAKING'} changes found: ${changes.join(', ')}`);\n\n return { hasBreakingChanges, changes };\n }\n\n // Serialize a RECORD message into a line that will be uploaded in the staging area\n getSerializedRecord = (streamId: string, record: any): string => {\n const stream = this.streams[streamId];\n if (!stream) {\n throw new MissingSchemaError(`A record for stream:\\`${streamId}\\` was encountered before a corresponding schema.`, streamId)\n }\n return stream.getDbSync().getSerializedRecord(record)\n }\n\n record = async (message: RecordMessage): Promise<void> => {\n try {\n\n const streamId = message.stream;\n const stream = this.streams[streamId];\n\n if (!stream) {\n throw new MissingSchemaError(`A record for stream:\\`${streamId}\\` was encountered before a corresponding schema.`, streamId)\n }\n\n // To avoid getting any conflicts when loading data in the warehouse, we run a semaphore to have a concurrency of 1\n // Only check every 10,000 rows to avoid semaphore acquisition overhead on every single row\n // (intermediate batch threshold is 1,000,000 rows, so checking every 10,000 is more than sufficient)\n if (stream.getBatchedRowCount() % 10_000 === 0) {\n await semaphore.runExclusive(async () => {\n const shouldUploadIntermediateBatch = this.shouldUploadIntermediateBatch(streamId)\n if (shouldUploadIntermediateBatch) {\n await this.loadAllStreamsInWarehouse({ isFinalLoad: false })\n }\n })\n }\n\n const record = message.record;\n const schema = stream.getSchema();\n\n if (!schema) {\n logger.warn(`Stream: ${streamId} - Received a RECORD message while schema is undefined. Dropping message.`)\n return;\n }\n\n const recordWithoutParasiteProperties = removeParasiteProperties(record, schema);\n\n const recordWithWhalyFields = addWhalyFields(recordWithoutParasiteProperties, stream.getBatchDate(), this.syncedAtColumnName);\n\n // Checking that the RECORD is valid compared to the previously received SCHEMA.\n // Uses a pre-compiled ajv ValidateFunction (compiled once in schema()) for maximum throughput.\n const validateFn = stream.getCompiledValidateFn();\n if (validateFn && !validateFn(recordWithWhalyFields)) {\n throw new SchemaValidationError(`Stream: ${streamId} - Record is not valid according to schema.\n Validation errors: ${JSON.stringify(validateFn.errors)}\n\n Record: ${JSON.stringify(recordWithoutParasiteProperties)}\n Schema: ${JSON.stringify(stream.getSchema())}`, streamId, validateFn.errors ?? [])\n }\n\n // Making sure that the date are in valid range supported by Warehouse\n const recordWithValidDate = this.validateDateRange(recordWithWhalyFields, schema);\n // Working with Decimal.js is better as the JS `number` type is quite imprecise\n const recordWithDecimal = this.convertNumberIntoDecimal(recordWithValidDate, schema)\n\n // Columns should be renamed to:\n // - Be \"safe\" for Warehouse\n // - Handle the case where there are conflicts in column names after sanitization\n // - There is a column versionning due to a column type change since the last sync\n const dbSyncInstance = stream.getDbSync();\n const recordWithrenamedColumns = dbSyncInstance.renameColumns(recordWithDecimal);\n\n const serializedRecord = this.getSerializedRecord(streamId, recordWithrenamedColumns);\n\n return new Promise((resolve, reject) => {\n stream.getFileToLoad().stream.write(serializedRecord, (error) => {\n if (error) {\n reject(error);\n }\n\n stream.incrementBatchedRowCount();\n resolve();\n });\n })\n\n } catch (err) {\n logger.error(`Error when handling \"record\" message`);\n throw err;\n }\n }\n\n private initStreamStateAndSyncService(\n streamId: string,\n replicationMethod?: ReplicationMethod\n ): void {\n const dbSyncInstance = this.newDBSyncInstance(\n streamId,\n this.config.database,\n this.config.schema,\n this.genTableName(streamId)\n )\n this.streams[streamId] = new StreamState(\n streamId,\n dbSyncInstance,\n replicationMethod || ReplicationMethod.FULL_TABLE\n );\n }\n\n replicationMethod = (message: ReplicationMethodMessage): void => {\n\n try {\n logger.info(`👈 Received replicationMethod message: %j`, message)\n const streamId = message.stream;\n if (!this.streams[streamId]) {\n this.initStreamStateAndSyncService(streamId, message.replication)\n } else {\n this.streams[streamId].setReplicationMethod(message.replication);\n }\n } catch (err) {\n logger.error(`Error when handling \"replicationMethod\" event`)\n throw err;\n }\n }\n\n schema = async (message: SchemaMessage): Promise<void> => {\n\n try {\n const streamId = message.stream;\n\n logger.info(`Stream: ${streamId} - Got a SCHEMA message from the tap`);\n logger.debug(`Stream: ${streamId} - Got a SCHEMA message from the tap: %j`, message);\n\n if (!this.streams[streamId]) {\n this.initStreamStateAndSyncService(streamId)\n } else {\n // Load the previous batched data as there can be schema changes\n const prevStreamState = this.streams[streamId];\n if (prevStreamState.batchedRowCount > 0) {\n const prevSchema = prevStreamState.getSchema();\n if(prevSchema) {\n // Flatten the new schema to compare with the previous one\n const newFlattenedSchema = flattenSchema(streamId, message.schema);\n // Check if schema changes are breaking or non-breaking\n const { hasBreakingChanges, changes } = this.analyzeSchemaChanges(prevSchema, newFlattenedSchema, streamId);\n if (hasBreakingChanges) {\n logger.info(`🔥 StreamId=${streamId} - Detected BREAKING schema changes: ${changes.join(', ')}. Loading batched records before applying new schema.`);\n await ITarget.uploadSingleStreamToWarehouse(prevStreamState);\n } else {\n logger.info(`✅ StreamId=${streamId} - Detected NON-BREAKING schema changes: ${changes.join(', ')}. Continuing without uploading batched records.`);\n }\n }\n }\n }\n\n const streamState = this.streams[streamId];\n if (!streamState) {\n throw new MissingSchemaError(`Stream: ${streamId} - Received SCHEMA message before stream state was initialized.`, streamId)\n }\n const schema = flattenSchema(streamId, message.schema);\n\n // Add synced-at column\n schema[this.syncedAtColumnName] = {\n format: \"date-time\",\n type: [\"null\", \"string\"]\n }\n\n const dbSync = streamState.getDbSync();\n Object.keys(schema).forEach(fieldUnsafeKey => {\n // Remove the key associated to no warehouse type\n const fieldDef = schema[fieldUnsafeKey];\n const targetWarehouseType = fieldDef ? dbSync.getWarehouseTypeFromJSONSchema(fieldDef) : undefined;\n\n if (!targetWarehouseType) {\n delete schema[fieldUnsafeKey]\n }\n })\n\n streamState.setSchema(schema);\n streamState.setCompiledValidateFn(this.ajv.compile({ type: \"object\", properties: schema }));\n\n const streamReplicationMethod = this.streams[streamId]?.getReplicationMethod();\n if (message.keyProperties.length === 0 && streamReplicationMethod !== ReplicationMethod.APPEND) {\n throw new Error(`StreamId: ${message.stream} - \\`key_properties\\` field is required and can't be empty in SCHEMA message.\n Received SCHEMA message: ${JSON.stringify(message)}`)\n }\n\n streamState.setKeyProperties(message.keyProperties);\n\n await dbSync.updateSchemaInWarehouse(schema, message.keyProperties);\n\n const {\n database: databaseName,\n schema: schemaName\n } = this.config;\n\n const tableName = this.genTableName(streamId);\n\n const formattedRelationshipMessage: SchemaMessage = {\n ...message,\n keyProperties: message.keyProperties.map(k => {\n const translation = streamState.getDbSync().renamedColumnStore.getColumnTranslation(message.stream, k);\n if (translation) {\n return translation;\n }\n return k\n })\n }\n\n await Bluebird.map(this.schemaHooks, async (hook) => {\n const input: TargetSchemaHookInput = {\n databaseName,\n schemaName,\n tableName,\n message: formattedRelationshipMessage,\n }\n await hook.writeSchema(input);\n }, { concurrency: 3 })\n\n return Promise.resolve();\n } catch (err) {\n logger.error(`Error when handling schema event.`, err)\n throw err;\n }\n }\n\n state = (message: StateMessage): Promise<void> => {\n\n try {\n this.batchedState = message.value;\n\n if (!this.flushedState) {\n this.flushedState = Object.assign({}, this.state);\n }\n return Promise.resolve()\n } catch (err) {\n logger.error(`Error while handling state event.`)\n throw err;\n }\n }\n\n complete = async (): Promise<void> => {\n\n try {\n logger.info(`👍 Data Extraction is complete. Will load remaining batched stream records.`)\n\n await this.loadAllStreamsInWarehouse({ isFinalLoad: true });\n return Promise.resolve();\n } catch (err) {\n logger.error(`Error while handling complete event.`)\n throw err;\n }\n }\n\n private shouldUploadIntermediateBatch = (streamId: string): boolean => {\n const stream = this.streams[streamId];\n if (!stream) {\n return false;\n }\n const batchedRecords = stream.getBatchedRowCount()\n const method = stream.getReplicationMethod();\n if ((method === \"INCREMENTAL\" || method === \"APPEND\") && batchedRecords > 1_000_000) {\n logger.info(`🧊 Stream=${streamId} has reached the maximum amount of batched records. We'll trigger a flush of ALL streams in the Warehouse.`)\n return true;\n } else {\n return false;\n }\n }\n\n private loadAllStreamsInWarehouse = async (opts: { isFinalLoad: boolean }): Promise<void> => {\n logger.info(`🚛🚛🚛 Loading ALL Streams in Warehouse.`)\n const { isFinalLoad } = opts;\n const streamsWithRemainingRecords = Object\n .keys(this.streams)\n .filter(streamId => {\n // FULL TABLE streams are removed from the load if it's not the final load\n const s = this.streams[streamId];\n if (!s) {\n return false;\n }\n if (!isFinalLoad && s.getReplicationMethod() === \"FULL_TABLE\") {\n return false;\n }\n return s.getBatchedRowCount() > 0\n });\n\n if (streamsWithRemainingRecords.length > 0) {\n this.flushedState = await this.uploadStreamsToWarehouse(streamsWithRemainingRecords)\n }\n\n if (Object.keys(this.flushedState).length > 0) {\n await this.emitState(Object.assign({}, this.flushedState))\n // Special case where nothing was written in the warehouse (nothing to sync then)\n // We keep the previous state\n } else {\n await this.emitState(Object.assign({}, this.state))\n }\n }\n\n private emitState = (state: any): Promise<void> => {\n return this.stateProvider.writeState(JSON.stringify(state));\n }\n\n private uploadStreamsToWarehouse = async (\n streamsToUpload: string[]\n ) => {\n\n try {\n await Bluebird.map(streamsToUpload, async (streamId) => {\n logger.info(`📤 Upload stream: ${streamId} to Warehouse`)\n const streamState = this.streams[streamId];\n if (streamState) {\n await ITarget.uploadSingleStreamToWarehouse(streamState)\n }\n }, { concurrency: 3 });\n\n return this.batchedState;\n } catch (err) {\n logger.error(`Error while uploading all streams + merging them.`)\n throw err;\n }\n }\n\n static uploadSingleStreamToWarehouse = async (\n streamState: StreamState\n ) => {\n\n const dbSync = streamState.getDbSync();\n\n try {\n const replicationMethod = streamState.getReplicationMethod();\n const fileToLoad = streamState.getFileToLoad();\n\n await dbSync.createStagingArea();\n await dbSync.loadStreamInStagingArea(fileToLoad.path);\n await dbSync.mergeTempTableWithDestination(replicationMethod);\n await dbSync.deleteStagingArea();\n streamState.setHasBeenLoadedYet();\n streamState.resetFileToLoad();\n } catch (err) {\n if (err instanceof Error) {\n logger.error(`StreamId=${dbSync.streamId} - Couldn't upload stream due to an error: %s`, err.message);\n throw err;\n } else {\n throw new Error('Unknown error')\n }\n }\n }\n}","import dayjs, { Dayjs } from \"dayjs\";\nimport { defaultDateTimeFormat } from \"../../constants/date\";\nimport { StreamId } from \"../metadata\";\nimport { ReplicationMethod } from \"../replication\";\nimport { StreamWarehouseSyncService } from \"./dbSync\";\nimport { FlattenedSchema, TempFile } from \"./models\";\nimport { createTemporaryFileStream } from \"./temporaryFile\";\nimport * as fs from \"fs\";\nimport { ValidateFunction } from \"ajv\";\n\n// This class is here to manage the State of a stream being loaded into a Warehouse\nexport class StreamState {\n streamId: StreamId;\n schema?: FlattenedSchema;\n dbSync: StreamWarehouseSyncService;\n\n batchDate: Dayjs;\n\n // Count rows batched in the local file, waiting for Warehouse upload\n batchedRowCount: number;\n // Local CSV files written to be sent to Warehouse\n fileToLoad: TempFile;\n // Count rows sent to Warehouse\n syncedRowCount: number;\n keyProperties: string[];\n\n // When a FULL_TABLE stream is loaded multiple times, the query used for the 2nd+ loads\n // needs to be different than the 1st merge query -> 1st load is dropping the existing table, 2nd+ loads are merging with the existing table (otherwise the previous load data are dropped)\n // So we need to keep track of whether we are at the first load or not\n _hasBeenLoadedYetDuringThisSync: boolean\n\n replicationMethod: ReplicationMethod\n\n // Pre-compiled ajv ValidateFunction — compiled once per schema, reused for every row\n compiledValidateFn?: ValidateFunction;\n\n constructor(\n streamId: StreamId, \n dbSync: StreamWarehouseSyncService, \n replicationMethod: ReplicationMethod, \n ) {\n this.streamId = streamId;\n this.dbSync = dbSync;\n\n this.batchedRowCount = 0;\n this.fileToLoad = createTemporaryFileStream(streamId);\n this.syncedRowCount = 0;\n this.keyProperties = [];\n this.batchDate = dayjs();\n this.replicationMethod = replicationMethod;\n this._hasBeenLoadedYetDuringThisSync = false;\n }\n\n setSchema(schema: FlattenedSchema) {\n this.schema = schema;\n }\n\n getSchema(): FlattenedSchema | undefined {\n return this.schema;\n }\n\n setCompiledValidateFn(fn: ValidateFunction) {\n this.compiledValidateFn = fn;\n }\n\n getCompiledValidateFn(): ValidateFunction | undefined {\n return this.compiledValidateFn;\n }\n\n getBatchDate(): string {\n return this.batchDate.format(defaultDateTimeFormat);\n }\n\n getBatchedRowCount(): number {\n return this.batchedRowCount;\n }\n\n incrementBatchedRowCount() {\n this.batchedRowCount += 1;\n }\n\n getFileToLoad(): TempFile {\n return this.fileToLoad;\n }\n\n resetFileToLoad() {\n this.fileToLoad.stream.close();\n const oldPath = this.fileToLoad.path;\n // Delete the old file to make some space\n fs.unlinkSync(oldPath);\n this.fileToLoad = createTemporaryFileStream(this.streamId);\n this.batchedRowCount = 0;\n }\n\n getKeyProperties(): string[] {\n return this.keyProperties;\n }\n\n setKeyProperties(keyProperties: string[]) {\n this.keyProperties = keyProperties\n }\n\n getDbSync(): StreamWarehouseSyncService {\n return this.dbSync\n }\n\n getReplicationMethod(): ReplicationMethod {\n return this.replicationMethod\n }\n\n setReplicationMethod(r: ReplicationMethod) {\n this.replicationMethod = r;\n }\n\n setHasBeenLoadedYet() {\n this._hasBeenLoadedYetDuringThisSync = true;\n }\n}","import fs from 'fs-extra';\nimport uniqueId from 'lodash/uniqueId.js';\nimport { StreamId } from '../metadata';\nimport { TempFile } from './models';\n\nexport const createTemporaryFileStream = (streamId: StreamId): TempFile => {\n fs.ensureDirSync(\"./tmp\")\n const path = `./tmp/${safePath(streamId)}-${uniqueId()}.tmp`;\n const writeStream = fs.createWriteStream(path, {flags: \"w\"});\n\n return {\n stream: writeStream,\n path\n };\n}\n\nexport function safePath(path: string): string {\n let formattedPath = path;\n formattedPath = formattedPath.replace(/^The\\s+/gi, '');\n formattedPath = formattedPath.replace(/\\s+(?:\\(|\\[)?Dis(?:c|k) (?:One|Two|Three|Four|Five|Six|Seven|Eight|Nine|Ten|\\d)+(?:\\)|\\])?/gi, '');\n formattedPath = formattedPath.replace(/\\s+/gi, '_');\n formattedPath = formattedPath.replace(/(?:\\'|`)/gi, '');\n formattedPath = replaceAccented(formattedPath);\n formattedPath = replaceSymbols(formattedPath);\n formattedPath = formattedPath.replace(/(?:[^a-z0-9])+/gi, '_');\n\n return formattedPath;\n};\n\nfunction replaceAccented(str: string) {\n str = str.replace(/(?:\\xC0|\\xC1|\\xC2|\\xC3|\\xC4|\\xC5)/g, 'A');\n str = str.replace(/(?:\\xC7)/g, 'C');\n str = str.replace(/(?:\\xC8|\\xC9|\\xCA|\\xCB)/g, 'E');\n str = str.replace(/(?:\\xCC|\\xCD|\\xCE|\\xCF)/g, 'I');\n str = str.replace(/(?:\\xD2|\\xD3|\\xD4|\\xD6|\\xD5)/g, 'O');\n str = str.replace(/(?:\\xD9|\\xDA|\\xDB|\\xDC)/g, 'U');\n str = str.replace(/(?:\\xDD|\\x9F)/g, 'Y');\n str = str.replace(/(?:\\xD1)/g, 'N');\n str = str.replace(/(?:\\xC6)/g, 'Ae');\n str = str.replace(/(?:\\xDF)/g, 'ss');\n str = str.replace(/(?:\\xE0|\\xE1|\\xE2|\\xE4|\\xE5|\\xE3)/g, 'a');\n str = str.replace(/(?:\\xE7)/g, 'c');\n str = str.replace(/(?:\\xE8|\\xE9|\\xEA|\\xEB)/g, 'e');\n str = str.replace(/(?:\\xEC|\\xED|\\xEE|\\xEF)/g, 'i');\n str = str.replace(/(?:\\xF2|\\xF3|\\xF4|\\xF6|\\xF5)/g, 'o');\n str = str.replace(/(?:\\xF9|\\xFA|\\xFB|\\xFC)/g, 'u');\n str = str.replace(/(?:\\xFD|\\xFF)/g, 'y');\n str = str.replace(/(?:\\xF1)/g, 'n');\n str = str.replace(/(?:\\xE6)/g, 'ae');\n return str;\n}\n\nfunction replaceSymbols(str: string) {\n str = str.replace(/(?:\\(|\\))/g, '');\n str = str.replace(/(?:\\.|\\?)/g, '');\n str = str.replace(/(?:_+)/g, '_');\n str = str.replace(/(?:\\$+)/g, 's');\n return str;\n}","import { WorkBook } from \"xlsx\";\nimport { ReplicationMethod } from \"../models/replication\";\n\n// Re-export WorkBook so client projects don't need xlsx as a direct dependency\nexport type { WorkBook } from \"xlsx\";\n\n// Re-export ReplicationMethod so file-processing consumers don't need a separate import\nexport { ReplicationMethod } from \"../models/replication\";\n\n/**\n * Field types for file processing columns.\n * Maps to JSON Schema types via fieldTypeToJsonSchema().\n */\nexport type FieldType = \"STRING\" | \"FLOAT\" | \"TIMESTAMP\";\n\nexport enum FileFormat {\n CSV = \"CSV\",\n EXCEL = \"EXCEL\",\n}\n\n// ─── Excel Types ───────────────────────────────────────────────────────\n\nexport type ExcelFieldSpec = ExcelSourceColumn | ExcelDerivedField;\n\nexport interface ExcelSourceColumn {\n type: FieldType;\n column: string;\n primaryKey?: boolean;\n}\n\nexport interface ExcelDerivedField {\n variableName: string;\n primaryKey?: boolean;\n type: FieldType;\n}\n\nexport interface ExcelFieldMapping {\n [key: string]: ExcelFieldSpec;\n}\n\nexport type ExcelExtractionConfig = ExcelSingleSheetExtractionConfig | ExcelCustomExtractorConfig;\n\nexport interface ExcelExtractionBaseConfig {\n type: \"single-sheet-extraction\" | \"processor\";\n extension: string;\n fileNameValidator: (fileName: string) => boolean;\n fileNameVariablesExtractor: (fileName: string, workbook?: WorkBook) => { [key: string]: string | undefined };\n tableName: string | ((fileName: string, workbook?: WorkBook, variables?: { [key: string]: string | undefined }) => string);\n replicationMethod: ReplicationMethod;\n}\n\nexport interface ExcelCustomExtractorConfig extends ExcelExtractionBaseConfig {\n type: \"processor\";\n processor: (workbook: WorkBook) => Promise<Record<string, string>[]>;\n}\n\nexport interface ExcelSingleSheetExtractionConfig extends ExcelExtractionBaseConfig {\n type: \"single-sheet-extraction\";\n columns: ExcelFieldMapping;\n sheetName?: string;\n numberOfRowsToSkip: number;\n}\n\n// ─── CSV Types ─────────────────────────────────────────────────────────\n\nexport type CsvFieldsConfig = CsvFieldsArrayConfig | CsvFieldsDictConfig;\n\nexport type CsvFieldsArrayConfig = Array<{\n key: string;\n valueTransformer?: (val: any) => string;\n type: FieldType;\n}>;\n\nexport interface CsvFieldsDictConfig {\n [key: string]: {\n key: string;\n valueTransformer?: (val: any) => string;\n type: FieldType;\n };\n}\n\nexport interface CsvFileConfig {\n encoding?: string;\n separator: string;\n fields: CsvFieldsConfig;\n}\n\n// ─── FileStream Config (discriminated union) ────────────────────────────\n\ninterface FileStreamBaseConfig {\n streamId: string;\n replicationMethod: ReplicationMethod;\n primaryKeys: string[];\n}\n\nexport interface CsvStreamConfig extends FileStreamBaseConfig {\n format: FileFormat.CSV;\n csv: CsvFileConfig;\n}\n\nexport interface ExcelStreamConfig extends FileStreamBaseConfig {\n format: FileFormat.EXCEL;\n excel: ExcelExtractionConfig;\n}\n\nexport type FileStreamConfig = CsvStreamConfig | ExcelStreamConfig;\n\n// ─── FileStream Entry (for pairing config + file path) ─────────────────\n\nexport interface FileStreamEntry {\n config: FileStreamConfig;\n filePath: string | string[];\n}\n","import {\n FieldType,\n ExcelFieldMapping,\n ExcelSourceColumn,\n ExcelDerivedField,\n CsvFieldsConfig,\n CsvFieldsArrayConfig,\n CsvFieldsDictConfig,\n} from \"./types\";\n\ntype JsonSchemaProperty = {\n type: (string | \"null\")[];\n format?: string;\n};\n\n/**\n * Convert a FieldType to a JSON Schema property definition.\n */\nexport function fieldTypeToJsonSchema(fieldType: FieldType): JsonSchemaProperty {\n switch (fieldType) {\n case \"STRING\":\n return { type: [\"null\", \"string\"] };\n case \"FLOAT\":\n return { type: [\"null\", \"number\"] };\n case \"TIMESTAMP\":\n return { type: [\"null\", \"string\"], format: \"date-time\" };\n default:\n return { type: [\"null\", \"string\"] };\n }\n}\n\n/**\n * Convert an ExcelFieldMapping to a JSON Schema properties object.\n */\nexport function excelFieldsToJsonSchema(fields: ExcelFieldMapping): {\n type: \"object\";\n properties: Record<string, JsonSchemaProperty>;\n} {\n const properties: Record<string, JsonSchemaProperty> = {};\n for (const [key, field] of Object.entries(fields)) {\n properties[key] = fieldTypeToJsonSchema(field.type);\n }\n return { type: \"object\", properties };\n}\n\n/**\n * Convert a CsvFieldsConfig to a JSON Schema properties object.\n */\nexport function csvFieldsToJsonSchema(config: CsvFieldsConfig): {\n type: \"object\";\n properties: Record<string, JsonSchemaProperty>;\n} {\n const properties: Record<string, JsonSchemaProperty> = {};\n\n if (Array.isArray(config)) {\n for (const field of config as CsvFieldsArrayConfig) {\n properties[field.key] = fieldTypeToJsonSchema(field.type);\n }\n } else {\n for (const [, field] of Object.entries(config as CsvFieldsDictConfig)) {\n properties[field.key] = fieldTypeToJsonSchema(field.type);\n }\n }\n\n return { type: \"object\", properties };\n}\n\n/**\n * Extract all output keys from a CsvFieldsConfig to use as composite primary keys.\n * Useful for FULL_TABLE replication where all fields form the PK (since TRUNCATE + MERGE = INSERT).\n */\nexport function extractPrimaryKeysFromCsvConfig(config: CsvFieldsConfig): string[] {\n if (Array.isArray(config)) {\n return (config as CsvFieldsArrayConfig).map(f => f.key);\n }\n return Object.values(config as CsvFieldsDictConfig).map(f => f.key);\n}\n\n/**\n * Extract primary keys from an ExcelFieldMapping.\n */\nexport function extractPrimaryKeysFromExcelFields(fields: ExcelFieldMapping): string[] {\n return Object.entries(fields)\n .filter(([, field]) => {\n return (field as ExcelSourceColumn).primaryKey === true\n || (field as ExcelDerivedField).primaryKey === true;\n })\n .map(([key]) => key);\n}\n","import XLSX, { WorkBook } from \"xlsx\";\nimport path from \"path\";\nimport {\n ExcelSourceColumn,\n ExcelExtractionConfig,\n ExcelSingleSheetExtractionConfig,\n ExcelDerivedField,\n} from \"../types\";\n\n/**\n * Converts an Excel column letter (A, B, C, AA, AZ, etc.) to its zero-based index.\n */\nexport const excelColumnToIndex = (columnLetter: string): number => {\n const letters = columnLetter.toUpperCase();\n let index = 0;\n\n for (let i = 0; i < letters.length; i++) {\n const charCode = letters.charCodeAt(i);\n if (charCode < 65 || charCode > 90) {\n throw new Error(`Invalid column letter: ${columnLetter}`);\n }\n index = (index * 26) + (charCode - 64);\n }\n\n return index - 1;\n};\n\n/**\n * Converts a zero-based column index to Excel column letter(s).\n */\nexport const indexToExcelColumn = (columnIndex: number): string => {\n if (columnIndex < 0) {\n throw new Error(`Invalid column index: ${columnIndex}. Must be >= 0`);\n }\n\n let result = \"\";\n let index = columnIndex;\n\n while (true) {\n result = String.fromCharCode(65 + (index % 26)) + result;\n index = Math.floor(index / 26);\n\n if (index === 0) break;\n index--;\n }\n\n return result;\n};\n\n/**\n * Converts an Excel row number (1-based) to zero-based array index.\n */\nexport const excelRowToIndex = (rowNumber: string | number): number => {\n const rowNum = typeof rowNumber === \"string\" ? parseInt(rowNumber, 10) : rowNumber;\n if (isNaN(rowNum) || rowNum < 1) {\n throw new Error(`Invalid row number: ${rowNumber}. Must be >= 1`);\n }\n return rowNum - 1;\n};\n\n/**\n * Converts a zero-based array index to Excel row number (1-based).\n */\nexport const indexToExcelRow = (index: number): number => {\n if (index < 0) {\n throw new Error(`Invalid index: ${index}. Must be >= 0`);\n }\n return index + 1;\n};\n\n/**\n * Parses an Excel cell reference (like \"A1\", \"Z24\", \"AA100\") into column and row indices.\n */\nexport const parseCellReference = (cellRef: string): { columnIndex: number; rowIndex: number } => {\n const match = cellRef.match(/^([A-Z]+)(\\d+)$/);\n if (!match) {\n throw new Error(`Invalid cell reference: ${cellRef}. Expected format like \"A1\", \"Z24\", \"AA100\"`);\n }\n\n const [, columnLetter, rowNumber] = match;\n return {\n columnIndex: excelColumnToIndex(columnLetter!),\n rowIndex: excelRowToIndex(rowNumber!),\n };\n};\n\n/**\n * Creates an Excel cell reference from column and row indices.\n */\nexport const createCellReference = (columnIndex: number, rowIndex: number): string => {\n return indexToExcelColumn(columnIndex) + indexToExcelRow(rowIndex);\n};\n\n/**\n * Extract a single Excel sheet based on configuration.\n */\nconst extractSingleSheetRows = async (\n fileName: string,\n conf: ExcelSingleSheetExtractionConfig,\n): Promise<Record<string, string | null>[]> => {\n console.log(\"Extracting single sheet rows from file: %s\", fileName);\n const workbook = XLSX.readFile(fileName, { dense: true });\n const sheetKeys = Object.keys(workbook.Sheets);\n const sheet = conf.sheetName\n ? workbook.Sheets[conf.sheetName]\n : workbook.Sheets[sheetKeys[0]!];\n\n if (!sheet) {\n throw new Error(`Sheet ${conf.sheetName} not found in workbook`);\n }\n const sheetData = sheet[\"!data\"];\n if (!sheetData) {\n throw new Error(`No data in ${conf.sheetName || \"first\"} sheet`);\n }\n if (sheetData.length === 0) {\n throw new Error(`Sheet ${conf.sheetName || \"first\"} is empty`);\n }\n\n const variables = conf.fileNameVariablesExtractor(fileName, workbook);\n const data: Record<string, string | null>[] = [];\n let rowIdx = 0;\n\n // Find minimum column index to determine when to stop processing\n const minColumnIndex = Object.values(conf.columns).reduce((min, column) => {\n return (column as ExcelSourceColumn).column\n ? Math.min(min, excelColumnToIndex((column as ExcelSourceColumn).column))\n : min;\n }, Number.MAX_SAFE_INTEGER);\n\n for (const row of sheetData) {\n if (rowIdx < conf.numberOfRowsToSkip) {\n rowIdx++;\n continue;\n }\n\n if (!row) {\n console.log(\"Empty row at index: %s, skipped processing.\", rowIdx);\n continue;\n }\n\n // Stop processing if the first data column is empty\n if (minColumnIndex !== Number.MAX_SAFE_INTEGER && !row[minColumnIndex]?.v) {\n console.log(\"stopping processing because of empty value in the first data column (idx: %s)\", minColumnIndex);\n break;\n }\n\n const rowData = Object.entries(conf.columns).reduce<{ [key: string]: string | null }>((acc, [key, column]) => {\n if ((column as ExcelDerivedField).variableName) {\n if (!variables) {\n throw new Error(`No variables extracted from filename, cannot extract derived field ${key}`);\n }\n acc[key] = variables[(column as ExcelDerivedField).variableName] || null;\n } else {\n const colIndex = excelColumnToIndex((column as ExcelSourceColumn).column);\n acc[key] = (row[colIndex]?.v as string) || null;\n }\n return acc;\n }, {});\n\n data.push(rowData);\n rowIdx++;\n }\n console.log(\"Extracted %s rows from sheet %s\", data.length, conf.sheetName || \"first\");\n return data;\n};\n\n/**\n * Low-level Excel extractor: returns array of row records from a workbook.\n */\nexport const extractExcelRows = async (\n localFilePath: string,\n conf: ExcelExtractionConfig,\n): Promise<Record<string, string | null>[]> => {\n let data: Record<string, string | null>[];\n\n if (conf.type === \"single-sheet-extraction\") {\n data = await extractSingleSheetRows(localFilePath, conf);\n } else if (conf.type === \"processor\") {\n const workbook = XLSX.readFile(localFilePath, { dense: true });\n data = await conf.processor(workbook);\n } else {\n throw new Error(`Unsupported configuration type: ${(conf as any).type}`);\n }\n\n return data;\n};\n\n/**\n * Validates an Excel file configuration.\n */\nexport const validateExcelConfig = (config: ExcelExtractionConfig): void => {\n if (!config.extension) {\n throw new Error(\"Extension is required\");\n }\n\n if (!config.tableName) {\n throw new Error(\"Table name is required\");\n }\n\n if (!config.fileNameValidator || typeof config.fileNameValidator !== \"function\") {\n throw new Error(\"File name validator function is required\");\n }\n\n if (!config.fileNameVariablesExtractor || typeof config.fileNameVariablesExtractor !== \"function\") {\n throw new Error(\"File name variables extractor function is required\");\n }\n\n if (\n config.type === \"single-sheet-extraction\" &&\n (!config.columns || Object.keys(config.columns).length === 0)\n ) {\n throw new Error(\"At least one column configuration is required for single-sheet-extraction\");\n }\n\n if (config.type === \"single-sheet-extraction\") {\n Object.entries(config.columns).forEach(([key, column]) => {\n if (!column.type) {\n throw new Error(`Column ${key} must have a type`);\n }\n\n if ((column as ExcelSourceColumn).column) {\n const colLetter = (column as ExcelSourceColumn).column;\n if (!/^[A-Z]+$/i.test(colLetter)) {\n throw new Error(`Invalid column letter format: ${colLetter}`);\n }\n } else if ((column as ExcelDerivedField).variableName) {\n // Variable name column is valid\n } else {\n throw new Error(`Column ${key} must specify either 'column' or 'variableName'`);\n }\n });\n\n if (config.numberOfRowsToSkip === undefined || config.numberOfRowsToSkip < 0) {\n throw new Error(\"Number of rows to skip must be specified and non-negative\");\n }\n } else if (config.type === \"processor\") {\n if (!config.processor || typeof config.processor !== \"function\") {\n throw new Error(\"Processor function is required for processor type\");\n }\n }\n};\n\n/**\n * Finds all matching configurations for a given filename.\n */\nexport const findAllMatchingConfigs = (\n filename: string,\n configs: ExcelExtractionConfig[],\n): ExcelExtractionConfig[] => {\n const fileInfo = path.parse(filename);\n\n return configs.filter(config =>\n config.fileNameValidator(fileInfo.base) &&\n config.extension === fileInfo.ext.replace(\".\", \"\"),\n );\n};\n\n/**\n * Creates an async generator from Excel data.\n */\nexport async function* createExcelGenerator(\n data: Record<string, string | null>[],\n): AsyncGenerator<Record<string, any>, void, unknown> {\n for (const row of data) {\n yield row;\n }\n}\n","import { WorkBook } from \"xlsx\";\nimport { ReplicationMethod } from \"../../models/replication\";\nimport {\n ExcelExtractionConfig,\n ExcelSingleSheetExtractionConfig,\n ExcelCustomExtractorConfig,\n ExcelFieldSpec,\n} from \"../types\";\n\n/**\n * Builder pattern for creating Excel configurations.\n *\n * Sensible defaults:\n * - fileNameValidator: accepts all files\n * - fileNameVariablesExtractor: extracts nothing\n * - replicationMethod: FULL_TABLE\n */\nexport class ExcelExtractionConfigBuilder {\n private config: Partial<ExcelExtractionConfig> = {\n fileNameValidator: () => true,\n fileNameVariablesExtractor: () => ({}),\n replicationMethod: ReplicationMethod.FULL_TABLE,\n };\n\n static create(): ExcelExtractionConfigBuilder {\n return new ExcelExtractionConfigBuilder();\n }\n\n extension(ext: string): ExcelExtractionConfigBuilder {\n this.config.extension = ext;\n return this;\n }\n\n tableName(name: string | ((fileName: string, workbook?: WorkBook, variables?: { [key: string]: string | undefined }) => string)): ExcelExtractionConfigBuilder {\n this.config.tableName = name;\n return this;\n }\n\n fileValidator(validator: (filename: string) => boolean): ExcelExtractionConfigBuilder {\n this.config.fileNameValidator = validator;\n return this;\n }\n\n variablesExtractor(extractor: (filename: string, workbook?: WorkBook) => { [key: string]: string | undefined }): ExcelExtractionConfigBuilder {\n this.config.fileNameVariablesExtractor = extractor;\n return this;\n }\n\n replicationMethod(method: ReplicationMethod): ExcelExtractionConfigBuilder {\n this.config.replicationMethod = method;\n return this;\n }\n\n columns(cols: { [key: string]: ExcelFieldSpec }): ExcelExtractionConfigBuilder {\n if (this.config.type === \"single-sheet-extraction\") {\n (this.config as ExcelSingleSheetExtractionConfig).columns = cols;\n } else {\n throw new Error(\"Columns can only be set for single-sheet-extraction\");\n }\n return this;\n }\n\n singleSheet(sheetName?: string, skipRows: number = 0): ExcelExtractionConfigBuilder {\n this.config.type = \"single-sheet-extraction\";\n if (sheetName !== undefined) {\n (this.config as ExcelSingleSheetExtractionConfig).sheetName = sheetName;\n }\n (this.config as ExcelSingleSheetExtractionConfig).numberOfRowsToSkip = skipRows;\n return this;\n }\n\n processor(processorFn: (workbook: WorkBook) => Promise<Record<string, string>[]>): ExcelExtractionConfigBuilder {\n this.config.type = \"processor\";\n (this.config as ExcelCustomExtractorConfig).processor = processorFn;\n return this;\n }\n\n build(): ExcelExtractionConfig {\n if (!this.config.type) {\n throw new Error(\"Configuration type must be specified (singleSheet or processor)\");\n }\n\n if (!this.config.extension) {\n throw new Error(\"Extension must be set\");\n }\n\n if (!this.config.tableName) {\n throw new Error(\"Table name must be set\");\n }\n\n if (!this.config.replicationMethod) {\n throw new Error(\"Replication method must be set\");\n }\n\n if (typeof this.config.fileNameValidator !== \"function\") {\n throw new Error(\"fileNameValidator must be a function\");\n }\n\n if (typeof this.config.fileNameVariablesExtractor !== \"function\") {\n throw new Error(\"fileNameVariablesExtractor must be a function\");\n }\n\n if (this.config.type === \"single-sheet-extraction\") {\n const singleSheetConfig = this.config as Partial<ExcelSingleSheetExtractionConfig>;\n if (!singleSheetConfig.columns || Object.keys(singleSheetConfig.columns).length === 0) {\n throw new Error(\"Columns must be set with at least one column for single-sheet-extraction\");\n }\n }\n\n if (this.config.type === \"processor\") {\n const processorConfig = this.config as Partial<ExcelCustomExtractorConfig>;\n if (typeof processorConfig.processor !== \"function\") {\n throw new Error(\"Processor function must be set for processor configs\");\n }\n }\n\n return this.config as ExcelExtractionConfig;\n }\n}\n","import csv from \"csv-parser\";\nimport { createReadStream, ReadStream as FsReadStream } from \"fs\";\nimport { format } from \"util\";\nimport { CsvFileConfig, CsvFieldsArrayConfig, CsvFieldsDictConfig } from \"../types\";\nimport { Readable, Transform } from \"stream\";\nimport * as iconv from \"iconv-lite\";\n\nconst logPrefix = \"[csvReader]\";\n\nconst createStripBomTransform = () => {\n let isFirstChunk = true;\n return new Transform({\n transform(chunk, encoding, callback) {\n if (isFirstChunk) {\n isFirstChunk = false;\n if (chunk.length >= 3 && chunk[0] === 0xEF && chunk[1] === 0xBB && chunk[2] === 0xBF) {\n chunk = chunk.slice(3);\n }\n }\n callback(null, chunk);\n },\n });\n};\n\nconst getStringHexInfo = (str: string) => {\n const bytes = Buffer.from(str, \"utf8\");\n const hex = bytes.toString(\"hex\").match(/.{2}/g)?.join(\" \") || \"\";\n return {\n original: str,\n length: str.length,\n hex: hex,\n trimmed: str.trim(),\n };\n};\n\nconst formatHexComparison = (expected: string, actual: string) => {\n const expectedInfo = getStringHexInfo(expected);\n const actualInfo = getStringHexInfo(actual);\n\n return `\\nExpected: \"${expected}\" (${expectedInfo.length} chars) [${expectedInfo.hex}]\\nActual: \"${actual}\" (${actualInfo.length} chars) [${actualInfo.hex}]`;\n};\n\n/**\n * Async generator that yields parsed rows from a CSV file.\n * Supports custom separators, encoding, BOM stripping, and field transformers.\n */\nexport async function* rowGeneratorFromCsv(\n path: string,\n fileConfig: CsvFileConfig,\n): AsyncGenerator<Record<string, any>> {\n const isGeneratorConfigArray = Array.isArray(fileConfig.fields);\n // Cache config keys once — avoids re-enumerating the same static object on every row\n const configKeys = isGeneratorConfigArray ? [] : Object.keys(fileConfig.fields);\n const csvOptions: Record<string, any> = { separator: fileConfig.separator };\n if (isGeneratorConfigArray) {\n csvOptions.headers = false;\n }\n const csvStream = csv(csvOptions);\n\n let initialReadStream: FsReadStream;\n let finalInputStream: NodeJS.ReadableStream;\n\n const encodingToUse = fileConfig.encoding ? fileConfig.encoding.toLowerCase() : null;\n\n if (encodingToUse && encodingToUse !== \"utf-8\" && encodingToUse !== \"utf8\" && iconv.encodingExists(encodingToUse)) {\n initialReadStream = createReadStream(path);\n finalInputStream = initialReadStream.pipe(iconv.decodeStream(encodingToUse));\n } else {\n initialReadStream = createReadStream(path);\n finalInputStream = initialReadStream.pipe(createStripBomTransform());\n }\n\n finalInputStream.pipe(csvStream);\n\n try {\n for await (const row of Readable.from(csvStream)) {\n if (!isGeneratorConfigArray) {\n const rowData: Record<string, any> = {};\n for (const key of configKeys) {\n const keyGenerator = (fileConfig.fields as CsvFieldsDictConfig)[key.trim()];\n if (!keyGenerator) continue;\n const rawValue = keyGenerator.valueTransformer\n ? keyGenerator.valueTransformer(row[key])\n : row[key];\n rowData[keyGenerator.key] = rawValue === \"\" ? null : rawValue;\n }\n yield rowData;\n } else {\n const rowKeys = Object.keys(row);\n const rowData: Record<string, any> = {};\n for (let i = 0; i < rowKeys.length; i++) {\n const keyGenerator = (fileConfig.fields as CsvFieldsArrayConfig)[i];\n if (!keyGenerator) continue;\n const rawValue = keyGenerator.valueTransformer\n ? keyGenerator.valueTransformer(row[i])\n : row[i];\n rowData[keyGenerator.key] = rawValue === \"\" ? null : rawValue;\n }\n yield rowData;\n }\n }\n } finally {\n initialReadStream.destroy();\n }\n}\n\n/**\n * Counts data rows in a CSV file by scanning for newline bytes.\n * Subtracts 1 for the header row. Fast: no CSV parsing required.\n */\nexport async function countCsvLines(filePath: string): Promise<number> {\n return new Promise((resolve, reject) => {\n let newlines = 0;\n createReadStream(filePath)\n .on(\"data\", (chunk: Buffer | string) => {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n for (let i = 0; i < buf.length; i++) {\n if (buf[i] === 0x0a) newlines++;\n }\n })\n .on(\"end\", () => resolve(Math.max(0, newlines - 1)))\n .on(\"error\", reject);\n });\n}\n\n/**\n * Validates CSV header row against expected configuration.\n */\nexport const checkCsvHeaderRow = async (\n path: string,\n fileConfig: CsvFileConfig,\n): Promise<void> => {\n return new Promise<void>((resolve, reject) => {\n const colsWithParsingConfig = Object.keys(fileConfig.fields)\n .map(key => key.trim());\n\n console.debug(`${logPrefix} CSV Expected columns:`, colsWithParsingConfig.map(col => {\n const info = getStringHexInfo(col);\n return `\"${info.original}\" [${info.hex}]`;\n }));\n\n const isGeneratorConfigArray = Array.isArray(fileConfig.fields);\n const csvOptions2: Record<string, any> = { separator: fileConfig.separator };\n if (isGeneratorConfigArray) {\n csvOptions2.headers = false;\n }\n const csvStream = csv(csvOptions2);\n\n let initialReadStream: FsReadStream;\n let finalInputStream: NodeJS.ReadableStream;\n const encodingToUse = fileConfig.encoding ? fileConfig.encoding.toLowerCase() : null;\n\n if (\n encodingToUse\n && encodingToUse !== \"utf-8\"\n && encodingToUse !== \"utf8\"\n && iconv.encodingExists(encodingToUse)\n ) {\n initialReadStream = createReadStream(path);\n finalInputStream = initialReadStream.pipe(iconv.decodeStream(encodingToUse));\n } else {\n initialReadStream = createReadStream(path);\n finalInputStream = initialReadStream.pipe(createStripBomTransform());\n }\n\n let isFirstLine = true;\n\n finalInputStream\n .pipe(csvStream)\n .on(\"data\", (row: any) => {\n if (isFirstLine) {\n let headers: string[] = [];\n if (isGeneratorConfigArray) {\n headers = (Object.values(row) as string[]).filter(r => !!r);\n } else {\n headers = (Object.keys(row) as string[]).filter(r => !!r);\n }\n\n console.debug(`${logPrefix} CSV Detected headers:`, headers.map((h, idx) => {\n const info = getStringHexInfo(h);\n return `[${idx}]: \"${info.original}\" [${info.hex}]`;\n }));\n\n if (isGeneratorConfigArray) {\n colsWithParsingConfig.forEach((col, i) => {\n if (col !== headers[i]) {\n const hexComparison = formatHexComparison(col, headers[i] || \"<undefined>\");\n console.error(`${logPrefix} CSV Header Mismatch:${hexComparison}`);\n\n throw new Error(format(\n `CSV header mismatch at position %s: expected '%s' but got '%s' in file %s`,\n i,\n col,\n headers[i] || \"<undefined>\",\n path,\n ));\n }\n });\n } else {\n colsWithParsingConfig.forEach((col) => {\n if (!headers.includes(col)) {\n const colInfo = getStringHexInfo(col);\n console.error(`CSV Missing column: \"${col}\" [${colInfo.hex}]`);\n console.error(`Available headers:`, headers.map(h => `\"${h}\" [${getStringHexInfo(h).hex}]`));\n\n const trimmedMatch = headers.find(h => h.trim() === col.trim());\n if (trimmedMatch) {\n console.error(`Potential trimmed match: \"${trimmedMatch}\" [${getStringHexInfo(trimmedMatch).hex}]`);\n }\n\n throw new Error(format(\n `CSV missing expected column '%s' in file: %s`,\n col,\n path,\n ));\n }\n });\n }\n isFirstLine = false;\n } else {\n initialReadStream.destroy();\n }\n })\n .on(\"error\", (error: Error) => {\n reject(new Error(`Error processing CSV file: ${error.message}`));\n });\n initialReadStream.on(\"close\", () => {\n resolve();\n });\n });\n};\n","import { createObjectCsvWriter } from \"csv-writer\";\nimport { format } from \"util\";\n\nconst logPrefix = \"[csvWriter]\";\n\n/**\n * Writes an array of objects directly to a CSV file.\n */\nexport const writeDataToCsv = async (\n fileName: string,\n data: any[],\n): Promise<void> => {\n try {\n const firstRow = data[0];\n if (!firstRow) {\n console.log(`${logPrefix} No data to write to CSV file=%s`, fileName);\n return;\n }\n const csvWriter = createObjectCsvWriter({\n path: fileName,\n header: Object.keys(firstRow)\n .map(col => {\n return { id: col, title: col };\n }),\n });\n await csvWriter.writeRecords(data);\n console.log(`${logPrefix} CSV file=%s written successfully`, fileName);\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(`error while writing csv file=%s, err: %s`, fileName, err.message));\n }\n throw err;\n }\n};\n\n/**\n * Writes data from an async generator to CSV with batch writing (10k row batches).\n */\nexport const writeGeneratorToCSV = async (\n generator: AsyncGenerator,\n outputFileName: string,\n): Promise<number> => {\n try {\n let rowCount = 0;\n\n const firstDataRow = (await generator.next()).value;\n if (!firstDataRow) {\n console.log(`${logPrefix} [%s] first data row of csv empty, skipping`, outputFileName);\n return 0;\n }\n\n console.log(`${logPrefix} [%s] inferring headers from first data row`, outputFileName);\n const headers = Object.keys(firstDataRow)\n .map(col => {\n return {\n id: col,\n title: col,\n };\n });\n\n const csvWriter = createObjectCsvWriter({\n path: outputFileName,\n header: headers,\n alwaysQuote: true,\n });\n\n console.log(`${logPrefix} [%s] writing csv`, outputFileName);\n let batch = [firstDataRow];\n for await (const data of generator) {\n batch.push(data);\n rowCount++;\n if (batch.length > 10_000) {\n try {\n await csvWriter.writeRecords(batch as any[]);\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(\n format(\n `error while writing batch to csv batch (first 3 records)=%j, err: %s`,\n batch.slice(0, 3),\n err.message,\n ),\n );\n }\n throw err;\n }\n batch = [];\n }\n }\n await csvWriter.writeRecords(batch as any[]);\n console.log(`${logPrefix} [%s] csv written successfully with %d rows`, outputFileName, rowCount);\n return rowCount;\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(`error while writing csv file=%s, err: %s`, outputFileName, err.message));\n }\n throw err;\n }\n};\n","import XLSX from \"xlsx\";\nimport { Stream } from \"../models/tap/stream\";\nimport { Schema } from \"../models/schema\";\nimport { ReplicationMethod } from \"../models/replication\";\nimport { InputTapState } from \"../models/state\";\nimport { ITarget } from \"../models/target/target\";\nimport {\n FileStreamConfig,\n FileStreamEntry,\n FileFormat,\n ExcelExtractionConfig,\n CsvFileConfig,\n} from \"./types\";\nimport { extractExcelRows } from \"./excel/reader\";\nimport { rowGeneratorFromCsv, countCsvLines } from \"./csv/reader\";\nimport { excelFieldsToJsonSchema, csvFieldsToJsonSchema, extractPrimaryKeysFromExcelFields, extractPrimaryKeysFromCsvConfig } from \"./schema-utils\";\n\n/**\n * FileStream bridges file processing (Excel/CSV) into the connector SDK pipeline.\n *\n * It extends Stream so it integrates with the standard Tap -> Stream -> Target flow.\n * Each FileStream reads one file with one config and yields records.\n */\nexport class FileStream extends Stream<Record<string, any>, FileStreamConfig> {\n private localFilePaths: string[];\n\n constructor(\n config: FileStreamConfig,\n localFilePath: string | string[],\n tapState: InputTapState,\n target: ITarget,\n ) {\n super(config, tapState, target);\n this.localFilePaths = Array.isArray(localFilePath) ? localFilePath : [localFilePath];\n\n // Set stream properties from config\n this.streamId = config.streamId;\n this.primaryKey = config.primaryKeys;\n this.replicationMethod = config.replicationMethod;\n }\n\n /**\n * Build JSON Schema from the file config's field definitions.\n */\n async getSchema(): Promise<Schema | undefined> {\n if (this.config.format === FileFormat.EXCEL) {\n const excelConfig = this.config.excel;\n if (excelConfig.type === \"single-sheet-extraction\") {\n const jsonSchema = excelFieldsToJsonSchema(excelConfig.columns);\n return { jsonSchema };\n }\n // For processor-type configs, schema must be inferred from first row at runtime.\n return undefined;\n }\n\n if (this.config.format === FileFormat.CSV) {\n const jsonSchema = csvFieldsToJsonSchema(this.config.csv.fields);\n return { jsonSchema };\n }\n\n throw new Error(`FileStream: No valid format config for stream ${this.streamId}`);\n }\n\n /**\n * Yield records from all file(s).\n * When multiple file paths are provided, records are yielded sequentially from each file.\n * Pre-counts total rows across all files to enable percentage progress logging.\n */\n async *_getRecords(): AsyncIterable<Record<string, any>> {\n // Pre-count total rows across all files before yielding any record\n let total = 0;\n for (const filePath of this.localFilePaths) {\n if (this.config.format === FileFormat.EXCEL) {\n const data = await extractExcelRows(filePath, this.config.excel);\n total += data.length;\n } else if (this.config.format === FileFormat.CSV) {\n total += await countCsvLines(filePath);\n }\n }\n this.totalRows = total;\n\n // Now yield records\n for (const filePath of this.localFilePaths) {\n if (this.config.format === FileFormat.EXCEL) {\n const data = await extractExcelRows(filePath, this.config.excel);\n for (const row of data) {\n yield row;\n }\n } else if (this.config.format === FileFormat.CSV) {\n yield* rowGeneratorFromCsv(filePath, this.config.csv);\n } else {\n throw new Error(`FileStream: Unsupported format for stream ${this.streamId}`);\n }\n }\n }\n}\n\n/**\n * Create a FileStreamConfig from an ExcelExtractionConfig.\n * Handles both single-sheet-extraction and processor config types.\n *\n * For single-sheet configs, primary keys are extracted from column definitions.\n * For processor configs, primary keys default to an empty array.\n *\n * @param excelConfig - The Excel extraction config (single-sheet or processor)\n * @param fileName - The base filename (used for variable extraction and table name resolution)\n * @param localFilePath - Optional local file path; required for processor configs with dynamic table names\n */\nexport function createExcelStreamConfig(\n excelConfig: ExcelExtractionConfig,\n fileName: string,\n localFilePath?: string,\n): FileStreamConfig {\n if (excelConfig.type === \"single-sheet-extraction\") {\n const primaryKeys = extractPrimaryKeysFromExcelFields(excelConfig.columns);\n\n let tableName: string;\n if (typeof excelConfig.tableName === \"function\") {\n const variables = excelConfig.fileNameVariablesExtractor(fileName);\n tableName = excelConfig.tableName(fileName, undefined, variables);\n } else {\n tableName = excelConfig.tableName;\n }\n\n return {\n format: FileFormat.EXCEL,\n streamId: tableName,\n replicationMethod: excelConfig.replicationMethod,\n primaryKeys,\n excel: excelConfig,\n };\n }\n\n // Processor config\n let tableName: string;\n if (typeof excelConfig.tableName === \"function\") {\n if (!localFilePath) {\n throw new Error(\"localFilePath is required for processor configs with dynamic table names\");\n }\n const workbook = XLSX.readFile(localFilePath, { dense: true });\n const variables = excelConfig.fileNameVariablesExtractor(fileName, workbook);\n tableName = excelConfig.tableName(fileName, workbook, variables);\n } else {\n tableName = excelConfig.tableName;\n }\n\n return {\n format: FileFormat.EXCEL,\n streamId: tableName,\n replicationMethod: excelConfig.replicationMethod,\n primaryKeys: [],\n excel: excelConfig,\n };\n}\n\n/**\n * Create a FileStreamConfig from a CsvFileConfig.\n *\n * By default, uses FULL_TABLE replication and extracts all field keys as composite primary keys.\n * Override via the options parameter.\n *\n * @param streamId - The stream/table name\n * @param csvConfig - The CSV file configuration\n * @param options - Optional overrides for replicationMethod and primaryKeys\n */\nexport function createCsvStreamConfig(\n streamId: string,\n csvConfig: CsvFileConfig,\n options?: {\n replicationMethod?: ReplicationMethod;\n primaryKeys?: string[];\n },\n): FileStreamConfig {\n return {\n format: FileFormat.CSV,\n streamId,\n replicationMethod: options?.replicationMethod ?? ReplicationMethod.FULL_TABLE,\n primaryKeys: options?.primaryKeys ?? extractPrimaryKeysFromCsvConfig(csvConfig.fields),\n csv: csvConfig,\n };\n}\n\n/**\n * Process an array of FileStreamEntry sequentially, then signal completion to the target.\n *\n * This is the recommended pattern for SFTP and similar multi-file ingestion flows\n * where FileTap isn't needed.\n *\n * @param entries - Array of { config, filePath } pairs\n * @param tapState - The tap state (typically `{ bookmarks: {} }`)\n * @param target - The target (e.g. BigQueryTarget)\n */\nexport async function processFileStreams(\n entries: FileStreamEntry[],\n tapState: InputTapState,\n target: ITarget,\n): Promise<void> {\n for (const entry of entries) {\n const stream = new FileStream(entry.config, entry.filePath, tapState, target);\n await stream.sync();\n }\n await target.complete();\n}\n","import { ReplicationMethod } from \"../../models/replication\";\nimport {\n CsvFileConfig,\n CsvFieldsConfig,\n CsvFieldsDictConfig,\n CsvFieldsArrayConfig,\n FieldType,\n FileStreamConfig,\n} from \"../types\";\nimport { createCsvStreamConfig } from \"../file-stream\";\n\n/**\n * Builder pattern for creating CSV configurations.\n *\n * Usage:\n * ```ts\n * const config = CsvExtractionConfigBuilder.create()\n * .separator(\";\")\n * .encoding(\"latin1\")\n * .fieldsFromDict({\n * \"Product ID\": { key: \"product_id\", type: \"STRING\" },\n * \"Product Name\": { key: \"product_name\", type: \"STRING\" },\n * \"Price\": { key: \"price\", type: \"FLOAT\" },\n * })\n * .build();\n * ```\n */\nexport class CsvExtractionConfigBuilder {\n private _separator: string = \",\";\n private _encoding?: string;\n\n private _fields?: CsvFieldsConfig;\n private _fieldsMode?: \"dict\" | \"array\";\n private _replicationMethod?: ReplicationMethod;\n private _primaryKeys?: string[];\n\n static create(): CsvExtractionConfigBuilder {\n return new CsvExtractionConfigBuilder();\n }\n\n separator(sep: string): CsvExtractionConfigBuilder {\n this._separator = sep;\n return this;\n }\n\n encoding(enc: string): CsvExtractionConfigBuilder {\n this._encoding = enc;\n return this;\n }\n\n fieldsFromDict(mapping: {\n [header: string]: {\n key: string;\n valueTransformer?: (val: any) => string;\n type: FieldType;\n };\n }): CsvExtractionConfigBuilder {\n if (this._fieldsMode === \"array\") {\n throw new Error(\"Cannot use fieldsFromDict after fieldsFromArray\");\n }\n this._fieldsMode = \"dict\";\n this._fields = mapping as CsvFieldsDictConfig;\n return this;\n }\n\n fieldsFromArray(fields: Array<{\n key: string;\n valueTransformer?: (val: any) => string;\n type: FieldType;\n }>): CsvExtractionConfigBuilder {\n if (this._fieldsMode === \"dict\") {\n throw new Error(\"Cannot use fieldsFromArray after fieldsFromDict\");\n }\n this._fieldsMode = \"array\";\n this._fields = fields as CsvFieldsArrayConfig;\n return this;\n }\n\n replicationMethod(method: ReplicationMethod): CsvExtractionConfigBuilder {\n this._replicationMethod = method;\n return this;\n }\n\n primaryKeys(keys: string[]): CsvExtractionConfigBuilder {\n this._primaryKeys = keys;\n return this;\n }\n\n build(): CsvFileConfig {\n if (!this._fields) {\n throw new Error(\"Fields must be configured (use fieldsFromDict or fieldsFromArray)\");\n }\n\n if (Array.isArray(this._fields) && this._fields.length === 0) {\n throw new Error(\"Fields must not be empty\");\n }\n\n if (!Array.isArray(this._fields) && Object.keys(this._fields).length === 0) {\n throw new Error(\"Fields must not be empty\");\n }\n\n const config: CsvFileConfig = {\n separator: this._separator,\n fields: this._fields,\n };\n\n if (this._encoding !== undefined) {\n config.encoding = this._encoding;\n }\n\n\n return config;\n }\n\n buildStreamConfig(streamId: string): FileStreamConfig {\n const csvConfig = this.build();\n\n const options: { replicationMethod?: ReplicationMethod; primaryKeys?: string[] } = {};\n if (this._replicationMethod !== undefined) {\n options.replicationMethod = this._replicationMethod;\n }\n if (this._primaryKeys !== undefined) {\n options.primaryKeys = this._primaryKeys;\n }\n\n return createCsvStreamConfig(streamId, csvConfig, options);\n }\n}\n","import { Tap } from \"../models/tap/tap\";\nimport { ITarget } from \"../models/target/target\";\nimport { StateProvider } from \"../models/state-provider/types\";\nimport { FileStreamConfig, FileStreamEntry } from \"./types\";\nimport { FileStream } from \"./file-stream\";\n\nexport interface FileTapConfig {\n [key: string]: any;\n}\n\n/**\n * FileTap orchestrates multiple FileStreams.\n *\n * It extends Tap so it integrates with the standard Tap -> Stream -> Target flow.\n * Provide file stream entries (config + file path pairs), and it creates a FileStream per entry.\n *\n * For simple sequential file processing without the Tap lifecycle, use processFileStreams() instead.\n */\nexport class FileTap extends Tap<FileTapConfig> {\n private entries: FileStreamEntry[];\n\n constructor(\n target: ITarget,\n config: FileTapConfig,\n stateProvider: StateProvider,\n entries: FileStreamEntry[],\n ) {\n super(target, config, stateProvider);\n this.entries = entries;\n }\n\n /**\n * Convenience constructor for the common case where all configs share the same file path.\n */\n static fromConfigs(\n target: ITarget,\n config: FileTapConfig,\n stateProvider: StateProvider,\n fileConfigs: FileStreamConfig[],\n sharedFilePath: string,\n ): FileTap {\n const entries = fileConfigs.map(c => ({\n config: c,\n filePath: sharedFilePath,\n }));\n return new FileTap(target, config, stateProvider, entries);\n }\n\n async init(): Promise<void> {\n for (const entry of this.entries) {\n const stream = new FileStream(\n entry.config,\n entry.filePath,\n this.tapState,\n this.target,\n );\n\n this.streams.push(stream);\n }\n }\n}\n","/**\n * Variable extraction utilities for common filename patterns.\n */\nexport class VariableExtractors {\n /**\n * Returns the filename as a variable.\n */\n static filename(): (filename: string) => { [key: string]: string | undefined } {\n return (filename: string) => ({\n fileName: filename,\n });\n }\n\n /**\n * Extracts named capture groups from a regex pattern.\n */\n static regex(pattern: RegExp): (filename: string) => { [key: string]: string | undefined } {\n return (filename: string) => {\n const match = filename.match(pattern);\n return match?.groups ?? {};\n };\n }\n\n /**\n * Combines multiple extraction functions.\n */\n static combine(\n ...extractors: ((filename: string) => { [key: string]: string | undefined })[]\n ): (filename: string) => { [key: string]: string | undefined } {\n return (filename: string) => {\n return extractors.reduce((acc, extractor) => {\n return { ...acc, ...extractor(filename) };\n }, {});\n };\n }\n}\n\n/**\n * File pattern utilities for common filename validation patterns.\n */\nexport class FilePatterns {\n /**\n * Creates a validator for files starting with a specific prefix (case-insensitive).\n */\n static startsWith(prefix: string): (filename: string) => boolean {\n return (filename: string) => filename.toLowerCase().startsWith(prefix.toLowerCase());\n }\n\n /**\n * Creates a validator for files matching a regex pattern.\n */\n static regex(pattern: RegExp): (filename: string) => boolean {\n return (filename: string) => pattern.test(filename);\n }\n\n /**\n * Combines multiple validators with AND logic.\n */\n static and(...validators: ((filename: string) => boolean)[]): (filename: string) => boolean {\n return (filename: string) => validators.every(validator => validator(filename));\n }\n\n /**\n * Combines multiple validators with OR logic.\n */\n static or(...validators: ((filename: string) => boolean)[]): (filename: string) => boolean {\n return (filename: string) => validators.some(validator => validator(filename));\n }\n}\n","import Client from \"ssh2-sftp-client\";\n\nexport { default as SftpClient } from \"ssh2-sftp-client\";\nexport type { ConnectOptions as SftpConnectOptions } from \"ssh2-sftp-client\";\n\n/**\n * Pre-instantiated SFTP client singleton.\n * @deprecated Prefer creating your own SftpClient instance for better lifecycle control.\n */\nexport const SftpService = new Client();\n","import { Storage, File } from \"@google-cloud/storage\";\nimport { format } from \"util\";\nimport * as pathModule from \"path\";\nimport { existsSync, mkdirSync, unlinkSync } from \"fs\";\nimport { randomUUID } from \"crypto\";\nimport { logger } from \"../sdk/service/logger\";\n\nconst logPrefix = \"[CloudStorageService]\";\nconst tmpDir = \"tmp\";\n\nexport interface CloudStorageServiceOptions {\n processedSuffix?: string;\n supportedExtensions?: string[];\n}\n\n/**\n * Service for interacting with Google Cloud Storage.\n * Supports file download, upload, listing, and marker-file-based processing tracking.\n */\nexport class CloudStorageService {\n private storage: Storage;\n private bucket: ReturnType<Storage[\"bucket\"]>;\n private processedSuffix: string;\n private supportedExtensions: string[];\n private path: string | undefined;\n\n constructor(\n bucketName: string,\n path?: string,\n opts?: CloudStorageServiceOptions,\n ) {\n this.storage = new Storage({ retryOptions: { autoRetry: true, maxRetries: 20 } });\n this.bucket = this.storage.bucket(bucketName);\n this.path = path;\n this.processedSuffix = opts?.processedSuffix ?? \".processed\";\n this.supportedExtensions = opts?.supportedExtensions ?? [];\n }\n\n /**\n * Lists all files in the bucket with an optional prefix.\n */\n async listFiles(prefix?: string): Promise<string[]> {\n const effectivePrefix = prefix || this.path;\n const [files] = await this.bucket.getFiles(\n effectivePrefix ? { prefix: effectivePrefix } : undefined,\n );\n return files.map(f => f.name);\n }\n\n /**\n * Returns files that haven't been marked as processed.\n * Filters by supported extensions if configured.\n */\n async getUnprocessedFiles(): Promise<string[]> {\n const allFiles = await this.listFiles();\n\n const markerFiles = new Set(\n allFiles\n .filter(f => f.endsWith(this.processedSuffix))\n .map(f => f.replace(this.processedSuffix, \"\")),\n );\n\n return allFiles.filter(f => {\n if (f.endsWith(this.processedSuffix)) return false;\n if (f.endsWith(\"/\")) return false;\n\n if (this.supportedExtensions.length > 0) {\n const ext = pathModule.extname(f).toLowerCase();\n if (!this.supportedExtensions.includes(ext)) return false;\n }\n\n return !markerFiles.has(f);\n });\n }\n\n /**\n * Creates a marker file to indicate a file has been processed.\n */\n async createMarkerFile(fileName: string): Promise<void> {\n const markerFileName = `${fileName}${this.processedSuffix}`;\n try {\n const file = this.bucket.file(markerFileName);\n await file.save(format(\"Marked file %s as processed\", fileName));\n logger.info(`${logPrefix} Marker file ${markerFileName} created successfully.`);\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(`error while writing marker file=%s, err:%s`, markerFileName, err.message));\n }\n throw err;\n }\n }\n\n /**\n * Downloads a file from GCS to a local tmp directory.\n * Returns the local path of the downloaded file.\n */\n async downloadFile(filePath: string, fileName: string): Promise<string> {\n const file = this.bucket.file(filePath);\n const tmpDirPath = pathModule.join(process.cwd(), tmpDir);\n if (!existsSync(tmpDirPath)) {\n mkdirSync(tmpDirPath);\n }\n const destFilename = pathModule.join(process.cwd(), tmpDir, fileName);\n try {\n if (existsSync(destFilename)) {\n unlinkSync(destFilename);\n }\n await file.download({ destination: destFilename });\n logger.info(`${logPrefix} Downloaded ${fileName} to ${destFilename}`);\n return destFilename;\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(\n `can't download file=%s from bucket, err:%s`,\n fileName,\n err.message,\n ));\n }\n throw err;\n }\n }\n\n /**\n * Uploads a local file to GCS.\n */\n async uploadFile(localPath: string, destPath: string): Promise<File> {\n try {\n logger.info(`${logPrefix} preparing to upload '%s' to '%s'`, localPath, destPath);\n const [file] = await this.bucket.upload(localPath, { destination: destPath });\n logger.info(`${logPrefix} file %s has been successfully uploaded into %s`, localPath, destPath);\n return file;\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(format(`error while uploading file file=%s into path=%s, err:%s`, localPath, destPath, err.message));\n }\n throw err;\n }\n }\n\n /**\n * Reads a GCS object and returns its contents as a UTF-8 string.\n */\n async readObjectAsString(objectPath: string): Promise<string> {\n try {\n await this.bucket.get({ autoCreate: false });\n const fileRef = this.bucket.file(objectPath);\n const [exists] = await fileRef.exists();\n if (!exists) {\n throw new Error(`GCS object not found: gs://${this.bucket.name}/${objectPath}`);\n }\n const [contents] = await fileRef.download();\n return contents.toString('utf8');\n } catch (err: any) {\n throw new Error(format(`error reading GCS object gs://${this.bucket.name}/${objectPath}, err: %s`, err?.message));\n }\n }\n\n /**\n * Writes a string to a GCS object with JSON content type.\n */\n async writeStringObject(objectPath: string, contents: string): Promise<void> {\n try {\n await this.bucket.get({ autoCreate: false });\n const fileRef = this.bucket.file(objectPath);\n await fileRef.save(contents, { contentType: 'application/json' });\n logger.info(`Uploaded object to gs://${this.bucket.name}/${objectPath}`);\n } catch (err: any) {\n throw new Error(format(`error writing GCS object gs://${this.bucket.name}/${objectPath}, err: %s`, err?.message));\n }\n }\n\n /**\n * Uploads a local file to the bucket with a unique name based on prefix, streamId, and UUID.\n * Files are stored under `<prefix>/<run-id>/` when the RUN_ID env var is set,\n * or `<prefix>/default/` otherwise.\n * Returns the GCS File reference.\n */\n async uploadFileWithUniqueName(filePath: string, prefix: string, streamId: string): Promise<File> {\n try {\n await this.bucket.get({ autoCreate: false });\n\n const runFolder = process.env.RUN_ID ?? \"default\";\n const destinationFileName = `${prefix}/${runFolder}/${streamId}-${randomUUID()}.jsonnl`;\n\n await this.bucket.upload(filePath, {\n destination: destinationFileName\n });\n\n logger.info(`Uploaded ${filePath} into ${this.bucket.name}/${destinationFileName} GCS File`);\n\n return this.bucket.file(destinationFileName);\n } catch (err: any) {\n logger.error(`Issue when uploading file into GCS bucket for stream: ${streamId}\n\n Error: ${err.message}\n Stack: ${err.stack}\n Code: ${err.code}\n `);\n\n throw err;\n }\n }\n}\n","import * as fse from \"fs-extra\";\nimport decompress from \"decompress\";\n\n/**\n * Extract a ZIP (or other archive) file to a target directory.\n * Uses the `decompress` library which supports zip, tar, gz, bz2, etc.\n *\n * @param zipFilePath - Path to the archive file\n * @param extractedPath - Directory to extract into (created if it doesn't exist)\n * @returns The output directory path\n */\nexport const unzip = async (zipFilePath: string, extractedPath: string): Promise<string> => {\n await fse.ensureDir(extractedPath);\n await decompress(zipFilePath, extractedPath);\n return extractedPath;\n};\n","// https://cloud.google.com/bigquery/docs/schemas#column_names\nexport const safeColumnName = (key: string): string => {\n\n let returnString = key;\n // Remove unsupported prefix\n const shouldNotStartWith = [\"_TABLE_\", \"_FILE_\", \"_PARTITION\"]\n shouldNotStartWith.forEach(snm => {\n if (returnString.startsWith(snm)) {\n returnString = returnString.replace(snm, \"\")\n }\n })\n\n // remove begining numeric characters\n returnString = returnString.replace(/^[-\\d\\s]*/g, \"\")\n\n // Go in lowercase\n returnString = returnString.toLowerCase()\n\n // Remove ticks\n returnString = returnString.replace('`', '')\n\n // Remove accents in a nice way\n returnString = returnString.normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\")\n\n // Trim to first 300 characters\n if (returnString.length > 300) {\n returnString = returnString.substr(0, 300);\n }\n\n // Remove non alphabetic characters\n const pattern = /[^a-zA-Z0-9_]/gm\n return returnString.replace(pattern, '_');\n}\n\n// https://cloud.google.com/bigquery/docs/tables#table_naming\nexport const safeTableName = (key: string) => {\n\n let returnString = key;\n\n // Go in lowercase\n returnString = returnString.toLowerCase()\n\n // Remove ticks\n returnString = returnString.replace('`', '')\n\n // Remove accents in a nice way\n returnString = returnString.normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\")\n\n // Trim to first 300 characters\n if (returnString.length > 1024) {\n returnString = returnString.substr(0, 1024);\n }\n\n // Remove non alphabetic characters\n const pattern = /[^a-zA-Z0-9_]/gm\n return returnString.replace(pattern, '_');\n}","import Decimal from \"decimal.js\";\nimport dayjs from \"dayjs\";\nimport { defaultDateTimeFormat } from \"../../../sdk/constants/date\";\nimport { FlattenedSchema } from \"../../../sdk/models/target/models\";\nimport { logger } from \"../../../sdk/service/logger\";\n\n//TODO: Check that the date-time are in the BigQuery limits\n// Eg. From 0001-01-01 00:00:00 to 9999-12-31 23:59:59.999999\nexport const validateDateRange = (record: any, schema: FlattenedSchema): any => {\n\n Object.keys(schema).forEach(key => {\n const { format } = schema[key];\n\n if (format === \"date-time\") {\n if (record[key]) {\n const formattedDate = dayjs(record[key]).format(defaultDateTimeFormat);\n // sometimes we have dayjs that cannot convert a value that seemed appropriate previously so we need to skip it\n // ie: in the tap we had as an output from dayjs \"20222-07-01T00:00:00.000000+00:00\"\n // and reading it back in the target gives \"Invalid date\"\n\n // we also need to check it the date is greater that the limit in order to avoid chaos\n const isNotTooMuchInTheFuture = dayjs(record[key]).isBefore(dayjs(\"9999-12-31 23:59:59.999999\"));\n const isNotTooMuchInThePast = dayjs(record[key]).isAfter(dayjs(\"0001-01-01 00:00:00\"))\n if (formattedDate !== \"Invalid date\" && isNotTooMuchInTheFuture && isNotTooMuchInThePast) {\n record[key] = formattedDate\n } else {\n record[key] = undefined;\n logger.info(\"Skipping date for key %s for being invalid\", key)\n }\n }\n }\n\n })\n\n return record;\n}\n\nexport const maxBQNumericValue = new Decimal(\"9.9999999999999999999999999999999999999E+28\");\n\nexport const convertNumberIntoDecimal = (record: any, schema: FlattenedSchema) => {\n Object.keys(record).forEach(key => {\n\n if (schema[key]) {\n const { type, items } = schema[key];\n const types = type instanceof Array ? type : [type];\n\n if (types.includes(\"number\")) {\n if (typeof record[key] === 'number' || record[key] instanceof Decimal) {\n const decimal = new Decimal(record[key]).toDecimalPlaces(9);\n if (decimal.greaterThanOrEqualTo(maxBQNumericValue)) {\n record[key] = null;\n } else {\n record[key] = decimal;\n }\n } else {\n record[key] = null;\n }\n } else if(types.includes(\"array\") && items?.type.includes(\"number\")) {\n if (Array.isArray(record[key])) {\n const rawArr = record[key];\n const newArr = rawArr.map((item: any) => {\n if(typeof item === 'number' || item instanceof Decimal) {\n const parsed = new Decimal(item).toDecimalPlaces(9);\n if (parsed.greaterThanOrEqualTo(maxBQNumericValue)) {\n return undefined\n } else {\n return parsed;\n }\n } else {\n return undefined;\n }\n }).filter((item: any) => !!item);\n record[key] = newArr;\n } else {\n record[key] = null;\n }\n }\n }\n })\n\n return record;\n}","import { StreamId } from \"../../../sdk/models/metadata\";\nimport { logger } from \"../../../sdk/service/logger\";\nimport { Dataset, TableMetadata, TableField, Table, BigQuery, JobLoadMetadata } from \"@google-cloud/bigquery\";\nimport dayjs from \"dayjs\";\nimport { BqClientHolder } from \"./bigquery\";\nimport { File } from '@google-cloud/storage';\nimport { CloudStorageService } from \"../../../services/cloud-storage\";\nimport { safeColumnName } from \"../helpers\";\nimport chunk from \"lodash/chunk.js\";\nimport { haltAndCatchFire } from \"../../../sdk/service/error\";\nimport { StreamWarehouseSyncService } from \"../../../sdk/models/target/dbSync\";\nimport { InternalTableField, JSONSchemaFieldDefinition, WarehouseTableField } from \"../../../sdk/models/target/models\";\nimport { BigQueryConfig } from \"../models/config\";\nimport { RenameColumnStore } from \"../../../sdk/models/target/renameColumnStore\";\nimport { Semaphore } from \"async-mutex\";\nimport { gracefulExit } from \"../../../sdk/service/exit\";\n\nconst semaphore = new Semaphore(1);\n\nexport class BigQueryDBSync extends StreamWarehouseSyncService {\n\n config: BigQueryConfig;\n bqClient: BigQuery;\n bqDataset: Dataset;\n bqTable: Table;\n bqStagingTable: Table;\n tableName: string;\n stagingTableName: string;\n sqlTableId: string;\n sqlStagingTableId: string;\n\n constructor(\n config: BigQueryConfig,\n streamId: StreamId,\n database: string,\n schema: string,\n table: string,\n renameColumnStore: RenameColumnStore,\n ) {\n super(\n streamId,\n database,\n schema,\n table,\n renameColumnStore\n )\n this.config = config;\n this.bqClient = BqClientHolder.client(config);\n this.bqDataset = this.bqClient.dataset(schema, { location: config.location || \"EU\" });\n this.bqTable = this.bqDataset.table(table, { location: config.location || \"EU\" });\n this.tableName = table;\n this.stagingTableName = `${table}_temp`;\n this.bqStagingTable = this.bqDataset.table(this.stagingTableName, { location: config.location || \"EU\" });\n this.sqlTableId = `${schema}.${table}`;\n this.sqlStagingTableId = `${this.sqlTableId}_temp`;\n }\n\n // Implementation of abstract classes\n\n getSerializedRecord = (record: any): string => {\n return JSON.stringify(record) + `\\n`;\n }\n\n safeColumnName = safeColumnName\n\n getWarehouseTypeFromJSONSchema = (\n definition: JSONSchemaFieldDefinition\n ): string => {\n\n const type = definition.type;\n const format = definition.format;\n\n // Converting `string | string[]` into `string[]` is easier for later processing\n let typeArr: string[];\n\n if (type instanceof Array) {\n typeArr = type;\n } else {\n typeArr = [type];\n }\n\n if (format) {\n switch (format) {\n case \"date-time\":\n return \"TIMESTAMP\";\n case \"json\":\n return \"STRING\";\n default:\n throw new Error(`StreamId: ${this.streamId} - Unsupported format: ${format}`)\n }\n }\n else if (typeArr.includes('number')) {\n return \"NUMERIC\"\n }\n else if (typeArr.includes('integer') && type.includes('string')) {\n return \"NUMERIC\"\n }\n else if (typeArr.includes('integer')) {\n return \"INTEGER\"\n }\n else if (typeArr.includes('boolean')) {\n return \"BOOLEAN\"\n }\n else if (typeArr.includes('string')) {\n return \"STRING\"\n }\n else if (typeArr.includes('array')) {\n const items = definition.items;\n if (items) {\n return this.getWarehouseTypeFromJSONSchema(items)\n }\n throw new Error(`StreamId: ${this.streamId} - Unsupported array schema field definition: ${JSON.stringify(definition)}`)\n }\n else {\n throw new Error(`StreamId: ${this.streamId} - Unsupported schema field definition: ${JSON.stringify(definition)}`)\n }\n };\n\n getMergeQueries = (): string[] => {\n\n const primaryKeyCondition = this.primaryKeys\n .map(pk => {\n return `\\`sourced\\`.\\`${pk}\\` = \\`destination\\`.\\`${pk}\\``\n })\n .join(` AND `);\n\n const primaryKeys = this.primaryKeys.map(pk => `\\`${pk}\\``).join(` ,`)\n\n const columnUnsafeToSafeMapping = this.renamedColumnStore.getUnsafeToSafeColumnMapping(this.streamId);\n\n const columns = Object.keys(columnUnsafeToSafeMapping)\n .map(column => {\n return {\n isUnsafe: true,\n colName: column\n }\n });\n const columnsChunks = chunk(columns, 300)\n // We need to make sure that the PKs keys are in all chunks so that they are written in the first chunk in the destination table\n // Otherwise we write \"null\" in the PK cols in a first batch and then we can't the proper lines in subsequent batchs\n .map(chunk => {\n this.primaryKeys.forEach(pk => {\n if (!chunk.map(c => columnUnsafeToSafeMapping[c.colName]).includes(pk)) {\n chunk.push({\n isUnsafe: false,\n colName: pk\n });\n }\n })\n return chunk;\n });\n\n return columnsChunks.map(chunk => {\n\n const setValues = chunk\n .map(column => {\n if (column.isUnsafe) {\n return `\\`destination\\`.\\`${columnUnsafeToSafeMapping[column.colName]}\\` = \\`sourced\\`.\\`${columnUnsafeToSafeMapping[column.colName]}\\``\n } else {\n return `\\`destination\\`.\\`${column.colName}\\` = \\`sourced\\`.\\`${column.colName}\\``\n }\n }).join(`, `);\n\n const renamedCols = chunk\n .map(column => {\n if (column.isUnsafe) {\n return `\\`${columnUnsafeToSafeMapping[column.colName]}\\``\n } else {\n return `\\`${column.colName}\\``\n }\n }).join(`, `);\n\n const query = `\n MERGE ${this.sqlTableId} destination\n USING (\n WITH all_staging_rows AS (\n SELECT *\n FROM ${this.sqlStagingTableId}\n ),\n numbered_rows AS (\n SELECT *, \n ROW_NUMBER() OVER (PARTITION BY ${primaryKeys}) as _wly_row_nb,\n COUNT(1) OVER (PARTITION BY ${primaryKeys}) AS _wly_partition_size,\n FROM all_staging_rows\n ),\n staging_deduped AS (\n SELECT * EXCEPT(_wly_partition_size, _wly_row_nb)\n FROM numbered_rows \n WHERE _wly_partition_size = _wly_row_nb\n )\n SELECT *\n FROM staging_deduped\n ) AS sourced\n ON ${primaryKeyCondition}\n WHEN MATCHED THEN\n UPDATE SET ${setValues}\n WHEN NOT MATCHED THEN\n INSERT (${renamedCols}) VALUES (${renamedCols});\n `\n return query;\n });\n }\n\n getReplaceQueries = (): string[] => {\n return [\n `TRUNCATE TABLE ${this.sqlTableId};`,\n ...this.getMergeQueries()\n ];\n }\n\n getAppendQueries = (): string[] => {\n const columnUnsafeToSafeMapping = this.renamedColumnStore.getUnsafeToSafeColumnMapping(this.streamId);\n const columns = Object.keys(columnUnsafeToSafeMapping)\n .map(unsafeKey => `\\`${columnUnsafeToSafeMapping[unsafeKey]}\\``)\n .join(`, `);\n\n return [\n `INSERT INTO ${this.sqlTableId} (${columns}) SELECT ${columns} FROM ${this.sqlStagingTableId};`\n ];\n }\n\n createDatabaseAndSchemaIfNotExists = async (retryCount: number) => {\n try {\n // To avoid checking / creating the dataset multiple times when evaluating streams concurrently\n // We make sure that this portion of the code is run with a concurrency of 1\n await semaphore.runExclusive(async () => {\n const [exists] = await this.bqDataset.exists();\n if (!exists) {\n logger.info(`🐣 Creating dataset: ${this.bqDataset.id} on BigQuery`)\n await this.bqDataset.create();\n } else {\n const [metadata] = await this.bqDataset.getMetadata()\n const alreadyExistinglocation = metadata.location;\n if (this.config.location && this.config.location !== alreadyExistinglocation) {\n await haltAndCatchFire(\n `unknown`,\n `A BigQuery dataset called '${this.bqDataset.id}' already exists in location: '${alreadyExistinglocation}' 😅\n \n This connector is configured to load data into the location '${this.config.location}' which is not possible as 2 datasets sharing the same name can't exist in different location on Google Cloud 😿\n\n To fix this issue, could you either: a. Delete the already existing dataset? b. Change the configured destination schema name to avoid the name conflict? 🙏\n \n Please relaunch the connector once it's done to fix the issue 🤗\n `,\n `\n We have a conflict between an already existing dataset in location ${alreadyExistinglocation} and the configured location: ${this.config.location}\n `\n )\n throw Error()\n }\n logger.info(`👋 Dataset: ${this.bqDataset.id} already exists on BigQuery, reusing it.`)\n }\n });\n } catch (err: any) {\n if (err.code === 400) {\n await haltAndCatchFire(\n `unauthorized`,\n `We can't connect to your BigQuery account 😔\n\n Here is the message from BigQuery: ${err.message}\n \n Can you check that your Warehouse credentials and Source target schema are properly configured and try to sync again the source? 🙏\n `,\n `Got error when trying to get Dataset from BigQuery: ${err.message} - ${err.code}`\n )\n return;\n }\n if (retryCount && retryCount > this.maxRetryCount) {\n logger.error(`StreamId: ${this.streamId} - Error when checking if dataset already exists. ${err.message} - ${err.code}`)\n gracefulExit(1);\n } else {\n logger.error(`StreamId: ${this.streamId} - Error when checking if dataset already exists. Retrying... ${err.message} - ${err.code}`)\n await new Promise((resolve, reject) => setTimeout(resolve, 1000 * (retryCount)))\n await this.createDatabaseAndSchemaIfNotExists(retryCount + 1)\n }\n }\n return Promise.resolve();\n }\n\n createTable = async () => {\n\n try {\n const tableName = this.tableName;\n const schema = this.generateBigquerySchema();\n\n logger.info(`🐣 Creating table: ${tableName} on BigQuery`)\n\n const createTableOptions: TableMetadata = {\n schema\n }\n\n await this.bqDataset.createTable(\n tableName,\n createTableOptions\n )\n\n return;\n } catch (err: any) {\n throw new Error(`StreamId: ${this.streamId} - Issue when creating table in BigQuery\n\n Error: ${err.message}\n Stack: ${err.stack}`)\n }\n }\n\n addColumns = async (tableFields: InternalTableField[]): Promise<void> => {\n\n if (tableFields.length > 0) {\n logger.info(`🆕 Stream: ${this.streamId} - Adding following columns in BigQuery schema: ${JSON.stringify(tableFields)}`)\n const [metadata] = await this.bqTable.getMetadata();\n\n const bgTableFields = tableFields.map(tblField => {\n return this.getBigqueryTableFieldFromInternalSchemaFieldDefinition(tblField.name, tblField.definition)\n }).filter(fld => {\n return !!fld\n })\n const schema = metadata.schema;\n const new_schema = {\n ...schema,\n fields: schema.fields.concat(bgTableFields)\n };\n metadata.schema = new_schema;\n\n await this.bqTable.setMetadata(metadata);\n return;\n }\n\n }\n\n createStagingArea = async () => {\n\n try {\n const tableName = this.stagingTableName;\n\n // A temporary table from a previous load could still be there\n const [exists] = await this.bqDataset.table(tableName).exists();\n if (exists) {\n logger.info(`👴 Temporary table ${tableName} already exists, it should be a relic form the past.\n Dropping it.`)\n await this.deleteStagingArea();\n }\n\n const schema = this.generateBigquerySchema();\n const expirationTime = dayjs().add(1, \"day\").valueOf().toString();\n const createTableOptions: TableMetadata = {\n schema,\n expirationTime\n }\n\n logger.info(`🐣 Creating staging table: ${tableName} on BigQuery`)\n\n await this.bqDataset.createTable(\n tableName,\n createTableOptions\n )\n\n return;\n } catch (err: any) {\n throw new Error(`StreamId: ${this.streamId} - Issue when creating table in BigQuery\n\n Error: ${err.message}\n Stack: ${err.stack}`)\n }\n }\n\n loadStreamInStagingArea = async (localFilePath: string) => {\n\n try {\n\n const gcsService = new CloudStorageService(this.config.loading_deck_gcs_bucket_name);\n const file = await gcsService.uploadFileWithUniqueName(\n localFilePath,\n this.config.connector_id,\n this.streamId,\n );\n\n const metadata: JobLoadMetadata = {\n sourceFormat: 'NEWLINE_DELIMITED_JSON',\n writeDisposition: \"WRITE_TRUNCATE\",\n };\n\n await this.loadGCSFileInTable(this.sqlStagingTableId, file, metadata);\n\n } catch (err: any) {\n logger.error(`StreamId: ${this.streamId} - Error while uploading stream.`)\n\n if (err.code < 500) {\n await haltAndCatchFire(\n `unauthorized`,\n `We couldn't connect to your Cloud Storage bucket 😔\n\n The error from Google is: '${err.message}' 👀\n\n Could you troubleshoot your Cloud Storage configuration in Google Cloud and sync again the source? 🙏`,\n `Got error from cloud storage lib`\n )\n }\n throw err;\n }\n }\n\n deleteStagingArea = () => {\n const query = `DROP TABLE IF EXISTS ${this.sqlStagingTableId};`;\n return this.runQueriesWithRetry([query]);\n }\n\n getTablesInSchema = async (): Promise<{ tableName: string }[]> => {\n const [bqTables] = await this.bqDataset.getTables();\n const foundTables = bqTables\n .filter(tbl => {\n return !!tbl.id\n })\n .map(bqTable => {\n return {\n tableName: bqTable.id\n }\n });\n\n return foundTables as { tableName: string }[];\n }\n\n getTableColumnsFromWarehouse = async (): Promise<WarehouseTableField[]> => {\n const [table] = await this.bqTable.getMetadata();\n return table.schema.fields;\n }\n\n runQueries = async (queries: string[]): Promise<void> => {\n const sqlQuery = `\n BEGIN\n ${queries.join(`\n `)}\n END;\n `;\n await this.bqClient.query(sqlQuery);\n }\n\n // Specific methods\n /**\n * \n * Generate a TableField definition object that can be passed to BigQuery APIs to define a column on a table\n * \n * @param colName \n * @param schemaFieldDefinition \n * @returns \n */\n private getBigqueryTableFieldFromInternalSchemaFieldDefinition = (\n colName: string,\n schemaFieldDefinition: JSONSchemaFieldDefinition | undefined\n ): TableField | undefined => {\n\n const name = colName;\n\n if (!schemaFieldDefinition) {\n throw new Error(`StreamId: ${this.streamId} - Schema is unknown for colName=${colName}, so we can't infer the proper BigQuery definition for this column.`)\n }\n const type = schemaFieldDefinition.type;\n\n // Converting `string | string[]` into `string[]` is easier for later processing\n let typeArr: string[];\n\n if (type instanceof Array) {\n typeArr = type;\n } else {\n typeArr = [type];\n }\n\n if (typeArr.includes('array')) {\n return {\n name,\n mode: \"REPEATED\",\n type: this.getWarehouseTypeFromJSONSchema(schemaFieldDefinition)\n }\n } else {\n // Only supported mode is NULLABLE as:\n // REQUIRED is not working great with adding columns later on so we keep NULLABLE\n let nullableMode = \"NULLABLE\";\n return {\n name,\n mode: nullableMode,\n type: this.getWarehouseTypeFromJSONSchema(schemaFieldDefinition)\n }\n }\n\n }\n\n private generateBigquerySchema = (): TableField[] => {\n const unsafeToSafeMappingColumnsFromColumnStore = this.renamedColumnStore.getUnsafeToSafeColumnMapping(this.streamId);\n if (!unsafeToSafeMappingColumnsFromColumnStore) {\n throw new Error(`StreamId: ${this.streamId} - There is no unsafe->safe column mapping`)\n }\n return Object.keys(unsafeToSafeMappingColumnsFromColumnStore).reduce<TableField[]>((acc, unsafeKey) => {\n\n const renamedColName = this.renamedColumnStore.getColumnTranslation(this.streamId, unsafeKey)!;\n const bigqueryTableField = this.getBigqueryTableFieldFromInternalSchemaFieldDefinition(renamedColName, this.flattenedSchema[unsafeKey]);\n if (bigqueryTableField) {\n acc.push(bigqueryTableField);\n }\n\n return acc;\n }, [])\n }\n\n private loadGCSFileInTable = async (\n tableName: string,\n file: File,\n metadata: JobLoadMetadata\n ): Promise<void> => {\n try {\n const [job] = await this.bqStagingTable.load(file, metadata);\n\n logger.info(`🚚 Loaded GCS file \\`${file.id}\\` in BigQuery table: ${tableName} with Job: \\`${job.id}\\``);\n logger.debug(`Upload Stats: ${JSON.stringify(job.statistics)}`)\n\n // Check the job's status for errors\n const errors = job.status?.errors;\n if (errors && errors.length > 0) {\n throw errors;\n }\n } catch (err: any) {\n logger.error(err)\n throw new Error(`StreamId: ${this.streamId} - Issue when loading file in BigQuery table | fileName: ${file.name}, tableName: ${tableName}\n\n Error: ${err.message}\n Stack: ${err.stack}`)\n }\n }\n\n}","import { BigQueryConfig } from \"../models/config\";\nimport { BigQuery } from \"@google-cloud/bigquery\";\n\nexport class BqClientHolder {\n private static instance: BqClientHolder;\n\n client: BigQuery;\n\n constructor(config: BigQueryConfig) {\n\n const retryOptions = {\n autoRetry: true,\n maxRetries: 3\n }\n\n this.client = new BigQuery({\n projectId: config.database.trim(),\n ...retryOptions\n });\n }\n\n static client(config: BigQueryConfig): BigQuery {\n if (!this.instance) {\n this.instance = new this(config);\n }\n\n return this.instance.client;\n }\n\n}","import { ITarget } from \"../../sdk/models/target/target\"\nimport { BigQueryConfig } from \"./models/config\";\n\nimport { safeColumnName, safeTableName } from \"./helpers\";\nimport { convertNumberIntoDecimal, validateDateRange } from \"./service/record\";\nimport { BigQueryDBSync } from \"./service/dbSync\";\nimport { StreamId } from \"../../sdk/models/metadata\";\nimport { StateProvider } from \"../../sdk/models/state-provider/types\";\n\nexport class BigQueryTarget extends ITarget<BigQueryConfig> {\n\n\n constructor(config: BigQueryConfig, stateProvider: StateProvider) {\n super(config, stateProvider);\n this.renameColumnStore.setSafeColumnNameConverter(this.safeColumnNameConverter);\n }\n static requiredConfigKeys = [\n \"schema\",\n \"project_id\",\n \"loading_deck_gcs_bucket_name\"\n ]\n\n newDBSyncInstance = (\n streamId: StreamId,\n database: string,\n schema: string,\n table: string,\n ): BigQueryDBSync => {\n return new BigQueryDBSync(\n this.config,\n streamId,\n database,\n schema,\n table,\n this.renameColumnStore,\n )\n };\n\n genTableName = safeTableName;\n safeColumnNameConverter = safeColumnName;\n validateDateRange = validateDateRange;\n convertNumberIntoDecimal = convertNumberIntoDecimal;\n\n}","import { logger } from \"../../sdk/service/logger\";\nimport { CloudStorageService } from \"../../services/cloud-storage\";\nimport { StateHolder, StateProvider } from \"../../sdk/models/state-provider/types\";\nimport { format } from \"util\";\n\nexport class GCSStateProvider implements StateProvider {\n private bucketName: string;\n private connectorId: string;\n private service: CloudStorageService;\n\n constructor(connectorId: string, bucketName: string) {\n this.connectorId = connectorId;\n this.bucketName = bucketName;\n this.service = new CloudStorageService(bucketName);\n }\n\n private getObjectPath(): string {\n return `${this.connectorId}/state.json`;\n }\n\n async getState(): Promise<StateHolder> {\n const objectPath = this.getObjectPath();\n try {\n logger.info(`📁 Loading state from gs://${this.bucketName}/${objectPath}`);\n const raw = await this.service.readObjectAsString(objectPath);\n const parsed = JSON.parse(raw);\n return { state: parsed };\n } catch (err: any) {\n logger.warn(format(`error loading state from gs://${this.bucketName}/${objectPath}, will start with empty state, err: %s`, err?.message));\n return { state: undefined };\n }\n }\n\n async writeState(state: string): Promise<void> {\n const objectPath = this.getObjectPath();\n try {\n logger.info(`📝 Writing state to gs://${this.bucketName}/${objectPath}`);\n await this.service.writeStringObject(objectPath, state);\n } catch (err: any) {\n logger.error(format(`💥 Error while writing state to gs://${this.bucketName}/${objectPath}, err: %s`, err?.message));\n throw new Error(format(`error writing state to gs://${this.bucketName}/${objectPath}, err: %s`, err?.message));\n }\n }\n}\n"],"mappings":"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","names":["transports","retryCount","ReplicationMethod","format","axios","qs","dayjs","cloneDeep","Bluebird","format","cloneDeep","Bluebird","dayjs","cloneDeep","params","axios","safeColumnName","errors","dayjs","dayjs","fs","path","fs","dayjs","Bluebird","dayjs","FileFormat","format","chunk","path","format","logPrefix","XLSX","tableName","XLSX","default","format","unlinkSync","logPrefix","path","format","unlinkSync","dayjs","format","dayjs","dayjs","Semaphore","semaphore","Semaphore","format","chunk","dayjs","errors","format"]}
|