diff --git a/clients/data-management-client/CHANGELOG.md b/clients/data-management-client/CHANGELOG.md new file mode 100644 index 00000000..5b751ab8 --- /dev/null +++ b/clients/data-management-client/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## 0.1.0 +- Initial scaffold of `@epilot/data-management-client` +- Added OpenAPI generation scripts (including local path) +- Added build/test configuration and client stubs + + diff --git a/clients/data-management-client/README.md b/clients/data-management-client/README.md new file mode 100644 index 00000000..e184edc1 --- /dev/null +++ b/clients/data-management-client/README.md @@ -0,0 +1,42 @@ +# @epilot/data-management-client + +[![CI](https://github.com/epilot-dev/sdk-js/workflows/CI/badge.svg)](https://github.com/epilot-dev/sdk-js/actions?query=workflow%3ACI) +[![npm version](https://img.shields.io/npm/v/@epilot/data-management-client.svg)](https://www.npmjs.com/package/@epilot/data-management-client) +[![bundle size](https://img.shields.io/bundlephobia/minzip/@epilot/data-management-client?label=gzip%20bundle)](https://bundlephobia.com/package/@epilot/data-management-client) +[![License](http://img.shields.io/:license-mit-blue.svg)](https://github.com/epilot-dev/sdk-js/blob/main/LICENSE) + +Client library for epilot Data Management API + +Uses [`openapi-client-axios`](https://github.com/openapistack/openapi-client-axios) + +## Installation + +```bash +npm install --save @epilot/data-management-client +``` + +## Usage + +```typescript +import { getClient } from '@epilot/data-management-client'; + +const dataManagementClient = getClient(); +// Example: +// const res = await dataManagementClient.someOperation(); +``` + +## Generate from OpenAPI + +Use the local OpenAPI source: + +```bash +pnpm --filter @epilot/data-management-client run openapi:local && pnpm --filter @epilot/data-management-client run typegen +``` + +Or (if available) fetch from docs: + +```bash +pnpm --filter @epilot/data-management-client run openapi && pnpm --filter @epilot/data-management-client run typegen +``` + + diff --git a/clients/data-management-client/jest.config.ts b/clients/data-management-client/jest.config.ts new file mode 100644 index 00000000..99394f4e --- /dev/null +++ b/clients/data-management-client/jest.config.ts @@ -0,0 +1,16 @@ +import type { Config } from '@jest/types'; + +const config: Config.InitialOptions = { + preset: 'ts-jest', + testEnvironment: 'node', + testMatch: ['**/?(*.)+(spec|test).ts?(x)'], + testPathIgnorePatterns: ['node_modules'], + coveragePathIgnorePatterns: ['__tests__', 'node_modules'], + verbose: true, + silent: true, + moduleNameMapper: { + '^axios$': require.resolve('axios'), + }, +}; + +export default config; diff --git a/clients/data-management-client/package.json b/clients/data-management-client/package.json new file mode 100644 index 00000000..1ad7d040 --- /dev/null +++ b/clients/data-management-client/package.json @@ -0,0 +1,76 @@ +{ + "name": "@epilot/data-management-client", + "version": "1.2.1", + "description": "JavaScript client library for epilot's Data Management API", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": "epilot GmbH", + "license": "MIT", + "private": false, + "repository": { + "type": "git", + "url": "git+https://github.com/epilot-dev/sdk-js.git", + "directory": "clients/data-management-client" + }, + "bugs": { + "url": "https://github.com/epilot-dev/sdk-js/issues" + }, + "homepage": "https://github.com/epilot-dev/sdk-js/tree/main/clients/data-management-client#readme", + "keywords": [ + "epilot", + "sdk", + "data-management" + ], + "scripts": { + "test": "jest", + "typescript": "tsc", + "bundle-definition": "webpack", + "openapi": "node ../../scripts/update-openapi.js https://docs.api.epilot.io/data-management.yaml", + "openapi:local": "node ../../scripts/update-openapi.js /Users/manikandansubramanian/Workspace/data-management-api/lambda/ApiHandlerFunction/openapi.yml", + "typegen": "openapi typegen src/openapi.json --client -b '/* eslint-disable */' > src/openapi.d.ts", + "build": "tsc && npm run build:patch && npm run bundle-definition", + "build:patch": "sed -i'' -e '/^__exportStar.*openapi.*$/d' dist/index.js", + "build:watch": "npm run build && tsc -w", + "release-alpha": "npm version prerelease --preid alpha", + "lint": "pnpm exec eslint src" + }, + "files": [ + "*.js", + "*.d.ts", + "**/*.json", + "**/*.js", + "**/*.d.ts", + "!*.test.*", + "!**/*.test.*", + "!node_modules", + "!src", + "!src/**", + "!*.config.js" + ], + "peerDependencies": { + "axios": "^1.0.0 || >=0.25.0 <1.0.0" + }, + "dependencies": { + "@dazn/lambda-powertools-correlation-ids": "^1.28.1", + "buffer": "^6.0.3", + "https-browserify": "^1.0.0", + "openapi-client-axios": "^7.8.0", + "stream-http": "^3.2.0", + "url": "^0.11.0", + "util": "^0.12.3" + }, + "devDependencies": { + "@types/jest": "^26.0.20", + "axios": "^1.11.0", + "copy-webpack-plugin": "^7.0.0", + "jest": "^29.6.2", + "json-loader": "^0.5.7", + "openapicmd": "^2.7.0", + "ts-jest": "^29.4.1", + "ts-loader": "^8.0.14", + "ts-node": "^10.9.2", + "typescript": "^4.1.3", + "webpack": "^5.101.0", + "webpack-cli": "^4.10.0" + } +} \ No newline at end of file diff --git a/clients/data-management-client/src/client.ts b/clients/data-management-client/src/client.ts new file mode 100644 index 00000000..5802fcd4 --- /dev/null +++ b/clients/data-management-client/src/client.ts @@ -0,0 +1,30 @@ +import CorrelationIds from '@dazn/lambda-powertools-correlation-ids'; +import OpenAPIClientAxios from 'openapi-client-axios'; + +import definition from './definition'; +import { Client } from './openapi'; + +let client: Client; +export const getClient = () => { + if (!client) { + client = createClient(); + } + + return client; +}; + +export const createClient = () => { + const api = new OpenAPIClientAxios({ + definition, + quick: true, + }); + + const apiClient = api.initSync(); + + apiClient.defaults.headers.common = { + ...(apiClient.defaults.headers.common ?? {}), + ...(CorrelationIds.get() || {}), + }; + + return apiClient; +}; diff --git a/clients/data-management-client/src/definition.ts b/clients/data-management-client/src/definition.ts new file mode 100644 index 00000000..40fd23c3 --- /dev/null +++ b/clients/data-management-client/src/definition.ts @@ -0,0 +1,5 @@ +import type { Document } from 'openapi-client-axios'; + +import definition from './openapi-runtime.json'; + +export default definition as unknown as Document; diff --git a/clients/data-management-client/src/index.ts b/clients/data-management-client/src/index.ts new file mode 100644 index 00000000..8df6e038 --- /dev/null +++ b/clients/data-management-client/src/index.ts @@ -0,0 +1,4 @@ +export type { Document, OpenAPIClient, OpenAPIClientAxios } from 'openapi-client-axios'; + +export * from './client'; +export * from './openapi'; diff --git a/clients/data-management-client/src/openapi-runtime.json b/clients/data-management-client/src/openapi-runtime.json new file mode 100644 index 00000000..319cf69d --- /dev/null +++ b/clients/data-management-client/src/openapi-runtime.json @@ -0,0 +1,29 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "", + "version": "" + }, + "paths": { + "/data-management/v1/{entity_schema}/query": { + "post": { + "operationId": "queryEntities", + "parameters": [ + { + "name": "entity_schema", + "in": "path", + "required": true + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": {} + } + }, + "responses": {} + } + } + }, + "components": {} +} diff --git a/clients/data-management-client/src/openapi.d.ts b/clients/data-management-client/src/openapi.d.ts new file mode 100644 index 00000000..ff440c1f --- /dev/null +++ b/clients/data-management-client/src/openapi.d.ts @@ -0,0 +1,105 @@ +/* eslint-disable */ + +import type { + OpenAPIClient, + Parameters, + UnknownParamsObject, + OperationResponse, + AxiosRequestConfig, +} from 'openapi-client-axios'; + +declare namespace Components { + namespace Schemas { + export interface DataManagementFilter { + type: DataManagementFilterType; + related_entity_schemas?: string[]; + workflow_statuses?: string[]; + entity_statuses?: string[]; + lookback_period_months?: number; + } + export type DataManagementFilterType = "entity_workflows_only_in_closed_or_cancelled_status" | "no_related_entities" | "related_entities_all_in_closed_or_cancelled_status" | "related_entities_any_in_closed_or_cancelled_status" | "no_email_communication_since"; + } +} +declare namespace Paths { + namespace QueryEntitiesBySavedView { + namespace Parameters { + export type EntitySchema = string; + } + export interface PathParameters { + entity_schema: Parameters.EntitySchema; + } + export interface RequestBody { + /** + * ID of the saved view to use for querying entities + */ + saved_view_id: string; + /** + * Pagination start offset + */ + from?: number; + /** + * Page size (maximum number of entities to return) + */ + size?: number; + /** + * Whether to include soft-deleted entities in the result + */ + includeDeleted?: boolean; + /** + * Whether to hydrate entities with full data instead of returning only indexed / projection fields. + * + */ + hydrate?: boolean; + /** + * Optional list of fields to include in each entity. + * + */ + fields?: string[]; + filters?: Components.Schemas.DataManagementFilter; + } + namespace Responses { + export interface $200 { + entities?: { + [name: string]: any; + }[]; + } + } + } +} + + +export interface OperationMethods { + /** + * queryEntitiesBySavedView - Query entities using a saved view with additional data filters + * + * Executes a query against the specified entity schema using the saved view definition, optionally combined with additional filters. Returns the entities matching the composed query. + * + */ + 'queryEntitiesBySavedView'( + parameters?: Parameters | null, + data?: Paths.QueryEntitiesBySavedView.RequestBody, + config?: AxiosRequestConfig + ): OperationResponse +} + +export interface PathsDictionary { + ['/data-management/v1/{entity_schema}/query']: { + /** + * queryEntitiesBySavedView - Query entities using a saved view with additional data filters + * + * Executes a query against the specified entity schema using the saved view definition, optionally combined with additional filters. Returns the entities matching the composed query. + * + */ + 'post'( + parameters?: Parameters | null, + data?: Paths.QueryEntitiesBySavedView.RequestBody, + config?: AxiosRequestConfig + ): OperationResponse + } +} + +export type Client = OpenAPIClient + + +export type DataManagementFilter = Components.Schemas.DataManagementFilter; +export type DataManagementFilterType = Components.Schemas.DataManagementFilterType; diff --git a/clients/data-management-client/src/openapi.json b/clients/data-management-client/src/openapi.json new file mode 100644 index 00000000..575c2a8a --- /dev/null +++ b/clients/data-management-client/src/openapi.json @@ -0,0 +1,173 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Data Management API", + "version": "1.2.0" + }, + "tags": [ + { + "name": "Data Management", + "description": "Data Management endpoints" + } + ], + "security": [ + { + "EpilotAuth": [] + }, + { + "EpilotOrg": [] + } + ], + "paths": { + "/data-management/v1/{entity_schema}/query": { + "post": { + "operationId": "queryEntities", + "summary": "Query entities using a saved view with additional data filters", + "description": "Executes a query against the specified entity schema using the saved view definition, optionally combined with additional filters. Returns the entities matching the composed query.\n", + "tags": [ + "Data Management" + ], + "parameters": [ + { + "name": "entity_schema", + "in": "path", + "required": true, + "description": "Target entity schema to query (for example: \"contact\", \"opportunity\", \"order\").\n", + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryEntitiesRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "Query results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryEntitiesResult" + } + } + } + } + } + } + } + }, + "components": { + "securitySchemes": { + "EpilotAuth": { + "type": "http", + "scheme": "bearer", + "description": "Authorization header with epilot OAuth2 bearer token", + "bearerFormat": "JWT" + }, + "EpilotOrg": { + "description": "Overrides the target organization to allow shared tenantaccess", + "name": "x-epilot-org-id", + "in": "header", + "type": "apiKey" + } + }, + "schemas": { + "QueryFilter": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "$ref": "#/components/schemas/QueryFilterType" + }, + "related_entity_schemas": { + "type": "array", + "items": { + "type": "string" + } + }, + "lookback_period_months": { + "type": "integer" + } + } + }, + "QueryFilterType": { + "type": "string", + "enum": [ + "entity_workflows_only_in_closed_or_cancelled_status", + "no_related_entities", + "related_entities_all_in_closed_or_cancelled_status", + "related_entities_any_in_closed_or_cancelled_status", + "no_email_communication_since" + ] + }, + "QueryEntitiesResult": { + "type": "object", + "properties": { + "hits": { + "type": "number" + }, + "results": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "QueryEntitiesRequestBody": { + "type": "object", + "required": [ + "saved_view_id", + "filters" + ], + "properties": { + "saved_view_id": { + "type": "string", + "description": "ID of the saved view to use for querying entities" + }, + "from": { + "type": "integer", + "description": "Pagination start offset" + }, + "size": { + "type": "integer", + "description": "Page size (maximum number of entities to return)" + }, + "include_deleted": { + "type": "string", + "enum": [ + "true", + "false", + "only" + ], + "description": "Whether to include soft-deleted entities in the result" + }, + "hydrate": { + "type": "boolean", + "description": "Whether to hydrate entities with full data instead of returning only indexed / projection fields.\n" + }, + "fields": { + "type": "array", + "description": "Optional list of fields to include in each entity.\n", + "items": { + "type": "string" + } + }, + "filters": { + "$ref": "#/components/schemas/QueryFilter" + } + } + } + } + } +} diff --git a/clients/data-management-client/tsconfig.json b/clients/data-management-client/tsconfig.json new file mode 100644 index 00000000..071df1f0 --- /dev/null +++ b/clients/data-management-client/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "strict": true, + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "lib": ["esnext", "dom"], + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "esModuleInterop": true, + "noImplicitAny": true, + "strictPropertyInitialization": false, + "strictNullChecks": false, + "resolveJsonModule": true, + "baseUrl": ".", + "rootDir": "src", + "outDir": "dist", + "sourceMap": true, + "declaration": true + }, + "include": ["src/**/*"], + "exclude": ["**/*.test.ts"] +} + + diff --git a/clients/data-management-client/webpack.config.js b/clients/data-management-client/webpack.config.js new file mode 100644 index 00000000..eca5d441 --- /dev/null +++ b/clients/data-management-client/webpack.config.js @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const path = require('path'); + +const CopyPlugin = require('copy-webpack-plugin'); + +module.exports = { + entry: './src/definition.ts', + mode: 'production', + module: { + rules: [ + { + test: /\.tsx?$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + ], + }, + plugins: [ + new CopyPlugin({ + patterns: [ + { from: '*.d.ts', context: './src' }, + { from: '*.json', context: './src' }, + ], + }), + ], + output: { + path: path.join(__dirname, 'dist'), + filename: 'definition.js', + libraryTarget: 'commonjs', + }, +}; + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8017db7b..0f8524f8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -646,6 +646,67 @@ importers: specifier: ^4.4.0 version: 4.10.0(webpack@5.101.0) + clients/data-management-client: + dependencies: + '@dazn/lambda-powertools-correlation-ids': + specifier: ^1.28.1 + version: 1.28.1 + buffer: + specifier: ^6.0.3 + version: 6.0.3 + https-browserify: + specifier: ^1.0.0 + version: 1.0.0 + openapi-client-axios: + specifier: ^7.8.0 + version: 7.8.0(axios@1.11.0(debug@4.4.1))(js-yaml@4.1.0) + stream-http: + specifier: ^3.2.0 + version: 3.2.0 + url: + specifier: ^0.11.0 + version: 0.11.4 + util: + specifier: ^0.12.3 + version: 0.12.5 + devDependencies: + '@types/jest': + specifier: ^26.0.20 + version: 26.0.24 + axios: + specifier: ^1.11.0 + version: 1.11.0(debug@4.4.1) + copy-webpack-plugin: + specifier: ^7.0.0 + version: 7.0.0(webpack@5.101.0) + jest: + specifier: ^29.6.2 + version: 29.7.0(@types/node@24.2.0)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@24.2.0)(typescript@4.9.5)) + json-loader: + specifier: ^0.5.7 + version: 0.5.7 + openapicmd: + specifier: ^2.7.0 + version: 2.7.0(@types/node@24.2.0)(encoding@0.1.13)(node-notifier@8.0.2)(openapi-types@12.1.3)(ts-node@10.9.2(@types/node@24.2.0)(typescript@4.9.5)) + ts-jest: + specifier: ^29.4.1 + version: 29.4.1(@babel/core@7.28.0)(@jest/transform@30.0.5)(@jest/types@30.0.5)(babel-jest@30.0.5(@babel/core@7.28.0))(jest-util@30.0.5)(jest@29.7.0(@types/node@24.2.0)(node-notifier@8.0.2)(ts-node@10.9.2(@types/node@24.2.0)(typescript@4.9.5)))(typescript@4.9.5) + ts-loader: + specifier: ^8.0.14 + version: 8.4.0(typescript@4.9.5)(webpack@5.101.0) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@24.2.0)(typescript@4.9.5) + typescript: + specifier: ^4.1.3 + version: 4.9.5 + webpack: + specifier: ^5.101.0 + version: 5.101.0(webpack-cli@4.10.0) + webpack-cli: + specifier: ^4.10.0 + version: 4.10.0(webpack@5.101.0) + clients/deduplication-client: dependencies: '@dazn/lambda-powertools-correlation-ids': @@ -13477,7 +13538,7 @@ snapshots: - js-yaml - supports-color - openapi-client-axios@7.6.0(axios@1.11.0(debug@4.4.1))(js-yaml@4.1.0): + openapi-client-axios@7.6.0(axios@1.11.0)(js-yaml@4.1.0): dependencies: axios: 1.11.0(debug@4.4.1) bath-es5: 3.0.3 @@ -13535,7 +13596,7 @@ snapshots: koa-router: 12.0.1 koa-static: 5.0.0 openapi-backend: 5.11.1 - openapi-client-axios: 7.6.0(axios@1.11.0(debug@4.4.1))(js-yaml@4.1.0) + openapi-client-axios: 7.6.0(axios@1.11.0)(js-yaml@4.1.0) swagger-editor-dist: 4.14.6 swagger-ui-dist: 5.27.1 swagger2openapi: 7.0.8(encoding@0.1.13)