# Introduction


# Quick Start

Currently, Standard SDK is implemented as a JavaScript module. However, its functionality can be implemented in other popular languages. If you would like to contribute to creating a Standard SDK in another language, please start a [discussion](https://github.com/comake/standard-sdk-js/discussions) about it.

To get started with Standard SDK in Node.js, install the module with npm or yarn:

```shell
npm install @comake/standard-sdk-js
```

or

```shell
yarn add @comake/standard-sdk-js
```

To use Standard SDK in a browser, you'll need to use a bundling tool such as Webpack, Rollup, Parcel, or Browserify. Some bundlers may require a bit of configuration, such as setting `browser: true` in rollup-plugin-resolve.

## Usage

### Building

To use Standard SDK, it first needs to be built using the [StandardSDK.build](/reference/api-reference#standardsdkbuildoptions) method. StandardSDK is dynamically built based on the API specs you supply.

In Typescript:

```typescript
import type { OpenApi } from '@comake/standard-sdk-js';
import { StandardSDK } from '@comake/standard-sdk-js';
// Import your API specs. 
import ticketmasterOpenApiSpec from './path/to/ticketmaster-openapi-spec.json';
import dropboxOpenApiSpec from './path/to/dropbox-openapi-spec.json';
// Build the Standard SDK with your API specs of choice
const standardSdk = StandardSDK.build({
  apiSpecs: {
    ticketmaster: {
      type: 'openapi',
      value: ticketmasterOpenApiSpec as OpenAPI,
    },
    dropbox: {
      type: 'openapi',
      value: dropboxOpenApiSpec as OpenAPI,
    },
  },
});
```

Here we use OpenAPI specs imported as a JSON modules (requires the `resolveJsonModule` flag in your `tsconfig.json` file in Typescript). Alternatively, you could read a YAML file uing [fs](https://nodejs.org/api/fs.html#file-system) and use the [yaml](https://www.npmjs.com/package/yaml) npm module to convert to JSON.

To get full Typescript autocompletion support in Standard SDK, turn your JSON OpenAPI specs into typescript objects by doing the following:

1. Change the file extension from `.json` to `.ts`
2. Add this typescript code around the OpenAPI spec JSON.

   ```typescript
   export default {
     // Your OpenAPI spec here
   } as const;
   ```

Now you won't have to cast your imported OpenAPI specs to the `OpenApi` type

```typescript
import { StandardSDK } from '@comake/standard-sdk-js';
// Import your API specs as Typescript objects. 
import ticketmasterOpenApiSpec from './path/to/ticketmaster-openapi-spec.ts';

// Build the Standard SDK with your API specs of choice
const standardSdk = StandardSDK.build({
  apiSpecs: {
    ticketmaster: {
      type: 'openapi',
      value: ticketmasterOpenApiSpec,
    }
  },
});
```

### Operations

Once you have built a `StandardSDK` object, you can perform API operations with it according to the descriptions of operations in the API specs you supplied. For example, every operation in an OpenAPI spec has a unique field used to identify it, called an `operationId`. Every `operationId` in an OpenAPI spec can be used as the name of a function which can be called to execute the corresponding API request described by the API spec. The operations available to perform are namespaced with the same keys you use in the `apiSpecs` parameter when you build StandardSDK (eg. `ticketmaster` and `dropbox` in the example above).

In Typescript:

```typescript
const ticketmasterResponse = await standardSdk.ticketmaster.SearchEvents(
  { city: 'Atlanta' },
  { apiKey: '<your ticketmaster api key>' },
);

const dropboxResponse = await standardSdk.dropbox.FilesGetMetadata(
  { path: 'id:a4ayc_80_OEAAAAAAAAAYa' },
  { accessToken: '<your dropbox access token>' },
);
```

The Ticketmaster OpenAPI spec we supplied to Standard SDK describes an operation with `operationId` equal to `SearchEvents`. The operation in the spec describes the Event Search endpoint documented in [Ticketmaster's Discovery API documentation](https://developer.ticketmaster.com/products-and-docs/apis/discovery-api/v2/#search-events-v2). Similarly, the Dropbox OpenAPI spec we provided describes an operation with `operationId` equal to `FilesGetMetadata`. It is documented in [Dropbox's API documentation](https://www.dropbox.com/developers/documentation/http/documentation#files-get_metadata).

Each operation was supplied relevant arguments as the first parameter and configuration as the second. See the [standardSDKInstance.\<namespace>.\<operation>](/reference/api-reference#standardsdkinstancenamespaceoperationargs-configuration-options) api reference for more information on these parameters.

### OpenAPI Directory

For your convenience, we have compiled a [directory of OpenAPI specs](https://github.com/comake/openapi-directory) of many popular APIs that you can use in your projects. We'd like to acknowledge [APIs.guru](https://apis.guru/), who supplied most of the API specs in the directory. Please submit any missing OpenAPI specs or ones you create as PRs to the directory. That way other developers can re-use them!

### Default Configuration and Options

If your API requires certain security credentials or headers on all requests, it may get repetitive to supply those on every operation you execute. Instead, you can set default configuration either when you build your SDK, and/or at any other time after the SDK is built.

When building your SDK, you can supply optional parameters `defaultConfiguration` and `defaultOptions` for each API.

```typescript
import { StandardSDK } from '@comake/standard-sdk-js';
import ticketmasterOpenApiSpec from './path/to/ticketmaster-openapi-spec.ts';

// Build the Standard SDK with your API specs of choice
const standardSdk = StandardSDK.build({
  apiSpecs: {
    ticketmaster: {
      type: 'openapi',
      value: ticketmasterOpenApiSpec,
      defaultConfiguration: {
        apiKey: 'abc123'
      },
      defaultOptions: {
        headers: {
          'X-Powered-By': 'Comake'
        }
      }
    }
  },
});
```

After building your SDK, you can use the `setDefaultConfiguration` and `setDefaultOptions` methods to update the configuration and options applied to every operation you execute with an API.

```typescript
import { StandardSDK } from '@comake/standard-sdk-js';
import ticketmasterOpenApiSpec from './path/to/ticketmaster-openapi-spec.ts';

// Build the Standard SDK with your API specs of choice
const standardSdk = StandardSDK.build({
  apiSpecs: {
    ticketmaster: {
      type: 'openapi',
      value: ticketmasterOpenApiSpec
    }
  },
});

standardSdk.ticketmaster.setDefaultConfiguration({
  apiKey: 'abc123'
});

standardSdk.ticketmaster.setDefaultOptions({
  headers: {
    'X-Powered-By': 'Comake'
  }
});
```


# Getting Started With SKL

As mentioned in the [Introduction](https://github.com/comake/standard-sdk-js/blob/main/docs/README.md), SKL ([Standard Knowledge Language](https://docs.standardknowledge.com/)) can be used with Standard SDK to make it easier to interact with multiple similar APIs. Instead of writing custom code for the non-standard data formats of each API you want to integrate with, SKL enables you to use abstractions to build over a common model.

If you haven't already, review the [Conceptual Example](https://docs.standardknowledge.com/conceptual-example) of why and how a developer uses SKL.

## Install

To get started with Standard SDK and SKL in Node.js, install the module with npm or yarn:

```shell
npm install @comake/standard-sdk-js
```

or

```shell
yarn add @comake/standard-sdk-js
```

To use Standard SDK in a browser, you'll need to use a bundling tool such as Webpack, Rollup, Parcel, or Browserify. Some bundlers may require a bit of configuration, such as setting `browser: true` in rollup-plugin-resolve.

## Walkthrough

Lets assume we're building an events calendar web-app for the city we live in. On this calendar app, we want to display events listed on major public event ticketing platforms like Ticketmaster, Stubhub, & Seatgeek, etc. SKL is perfect for this task. With just a few Schemas, it dramatically reduces the amount code we would have to write to ingest event data from multiple APIs.

I order to build our system we have to:

1. **Define SKL** [**Schemas**](https://docs.standardknowledge.com/fundamentals#schemas) to abstract the data and operations we will be accessing from each API into a common data model.
2. **Use a** [**Standard Knowledge Language Engine (SKL Engine)**](https://docs.standardknowledge.com/get-started/engine) to read and execute our Schemas to perform the operations our app requires.
3. **Write code** to implement the application

## 1. Define SKL Schemas

As stated in the [SKL documentation](https://docs.standardknowledge.com/fundamentals#schemas):

> SKL is a schema validated and configuration driven framework. Standard Knowledge Schemas serve both as schema to ensure data conforms to specific structures, and configuration detailing what capabilities are possible and how those capabilities are performed. Schemas are made up of Nouns, Verbs, and Mappings:
>
> * Data is translated through Nouns.
> * Capabilities are represented by Verbs.
> * Mappings are used to relate Nouns and Verbs and translate between raw data and capabilities and Nouns and Verbs

In order to use SKL for our application, we need to create Schemas representing:

1. An abstraction of Events which data from each event ticketing platform will be mapped to. This is our primary [Noun](https://docs.standardknowledge.com/fundamentals#nouns). In this example, we use the Event data type from [schema.org](https://schema.org/Event).
2. An abstraction of the operation we want to perform with the API of each event ticketing platform. We want to get a list of events from each platform, filtered by only those in our city. We'll call this `getEvents`, it is a [Verb](https://docs.standardknowledge.com/fundamentals#verbs).
3. Rules defining how our Verb `getEvents` and its standardized parameters get mapped to the correct operation of each API and how the unique response of each API gets mapped into the standardized return value of the Verb. These are [Mappings](https://docs.standardknowledge.com/fundamentals#mappings).

Examples of these Schemas are available as JSON-LD in the [unified-events-api/skl-schemas](https://github.com/comake/skl-examples/tree/main/unified-events-api/skl-schemas) folder of the [SKL Examples](https://github.com/comake/skl-examples) repository. There you'll see the Event Noun in the [nouns.json](https://github.com/comake/skl-examples/blob/main/unified-events-api/skl-schemas/nouns.json) file, the `getEvents` Verb in the [verbs.json](https://github.com/comake/skl-examples/blob/main/unified-events-api/skl-schemas/verbs.json) file, the mappings in the [mappings.json](https://github.com/comake/skl-examples/blob/main/unified-events-api/skl-schemas/mappings.json) file, and entities needed for SKL to work in [entities.json](https://github.com/comake/skl-examples/blob/main/unified-events-api/skl-schemas/entities.json)

### API Security Credentials

Most APIs require a sensitive access token or API key to make authenticated requests. SKL automatically reads these from a `Security Credentials` entity in your schemas. You can see an example of one in [entities.json](https://github.com/comake/skl-examples/blob/main/unified-events-api/skl-schemas/entities.json#L30-L33). You'll notice that the `apiKey` field is stubbed out with `ENV_TICKETMASTER_APIKEY`. This is because we don't want to put a real API key in the public repository on Github. When the example code is run, we swap out any string starting with the prefix `ENV_` with the value of the environment variable named the remainder of the stub, in this case `TICKETMASTER_APIKEY`. If your schemas are private, you can include the environment variables directly in the Schemas.

## 2. Use a SKL Engine

Now that we have schemas, we need to use an [SKL Engine](https://docs.standardknowledge.com/get-started/engine) to read and execute them according to our code. Standard SDK JS includes the [SKL JS Engine](https://github.com/comake/skl-js-engine) inside of it. This way, with only one dependency, you can use Standard SDK normally when creating abstractions is too hard for your circumstance or use case but have the power of SKL's abstractions to solve the majority of your needs.

Build Standard SDK using the `sklEngineOptions` argument. This argument is the same interface as the arguments to build [SKL JS Engine](https://github.com/comake/skl-js-engine).

In Typescript:

```typescript
const standardSdk = StandardSDK.build({
  sklEngineOptions: {
    type: 'memory',
    schemas: <yourSchemasHere>,
  },
});
```

If your schemas are separated across multiple files and/or use a JSON-LD `@context`, you should combine and frame them using a function like [`combineSchemas`](https://github.com/comake/skl-examples/blob/main/unified-events-api/src/Util.ts#L5) in the [SKL Examples](https://github.com/comake/skl-examples/blob/main/unified-events-api/src/Util.ts#L5) repository.

## 3. Write Code

Finally, you're ready to write some code using the Standard SDK instance you just built. Since we provided `sklEngineOptions` you can access the SKL JS Engine through `standardSdk.skl`.

In Typescript:

```typescript
const ticketmasterResponse = await standardSdk.skl.verb.getEvents({
  account: 'https://example.com/data/TicketmasterAccount',
  city: 'New York',
});

const stubhubResponse = await standardSdk.skl.verb.getEvents({
  account: 'https://example.com/data/StubhubAccount',
  city: 'New York',
});

const seatgeekResponse = await standardSdk.skl.verb.getEvents({
  account: 'https://example.com/data/SeatgeekAccount',
  city: 'New York',
});
```

This code will tell the SKL JS Engine to execute the `getEvents` Verb using each `account` represented by URIs (eg. `https://example.com/data/TicketmasterAccount`). In [entities.json](https://github.com/comake/skl-examples/blob/main/unified-events-api/skl-schemas/entities.json), which you copied or reviewed earlier, there are Schemas which contain the [OpenAPI specifications](https://github.com/comake/skl-examples/blob/main/unified-events-api/skl-schemas/entities.json#L42) and [security credentials](https://github.com/comake/skl-examples/blob/main/unified-events-api/skl-schemas/entities.json#L30) for each API. In [mappings.json](https://github.com/comake/skl-examples/blob/main/unified-events-api/skl-schemas/mappings.json), there are mappings which relate each [Integration](https://github.com/comake/skl-examples/blob/main/unified-events-api/skl-schemas/mappings.json#L38) with the [getEvents Verb](https://github.com/comake/skl-examples/blob/main/unified-events-api/skl-schemas/mappings.json#L39). Together, these entities and mappings inform the SKL JS Engine how to map the parameters of the `getEvents` Verb to the parameters of each API, send a properly formatted web request to the API, and map the response of the API into our standardized Event Noun.


# API Reference

## [`StandardSDK.build(options)`](#standardsdkbuildoptions)

Instantiates a Standard SDK with your APIs of choice.

#### Parameters

The `build` method takes one argument which may have either or both of `apiSpecs` and `sklEngineOptions`.

| Parameter          | Type     | Description                                                                                                             |
| ------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------- |
| `apiSpecs`         | `object` | A hash of `ApiSpecOptions` objects. Describes the API specs for StandardSDK to construct namespaced operations from.    |
| `sklEngineOptions` | `object` | An `SKLEngineOptions` object as defined by [@comake/skl-js-engine](https://www.npmjs.com/package/@comake/skl-js-engine) |

#### ApiSpecOptions

`ApiSpecOptions` are the configurations you pass when building a Standard SDK for the APIs you want to work with. Different types of APIs have their own specific options. Currently we only support OpenAPI specs.

| Parameter              | Required | Description                                                                                                                                                                                                                                                      |
| ---------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                 | Required | A type of API specification. Possible values are: `openapi`                                                                                                                                                                                                      |
| `value`                | Required | The contents of the API specification. Usually a string or JSON object. When using Typescript, use `as const` on your API spec to get extended type support.                                                                                                     |
| `defaultConfiguration` |          | Optional configuration that will be added to every operation of this API. For OpenAPI specs, this field will be an `OpenApiClientConfiguration` object as defined in [@comake/openapi-operation-executor](https://github.com/comake/openapi-operation-executor). |
| `defaultOptions`       |          | Optional options that will be applied to every operation of this API. For OpenAPI operations, this is an `AxiosRequestConfig` object. See the [axios API documentation](https://github.com/axios/axios#request-config) for reference.                            |

#### Return Value

A `StandardSDK` instance with a namespace for each key in `apiSpecs`. It may also have an `skl` property if `sklEngineOptions` was supplied.

#### Example Usage

In Typescript:

```typescript
import ticketmasterOpenApiSpec from './path/to/ticketmaster-openapi-spec.json';

const standardSdk = StandardSDK.build({
  apiSpecs: {
    ticketmaster: {
      type: 'openapi',
      value: ticketmasterOpenApiSpec,
      defaultConfiguration: {
        apiKey: 'abc123'
      },
      defaultOptions: {
        headers: {
          'X-Powered-By': 'Comake'
        }
      }
    },
  },
});
```

## [`standardSDKInstance.<namespace>`](#standardsdkinstance-namespace)

A namespace of a `StandardSDK` instance corresponding to a set of supplied Api Spec Options. A namespace has a property for each operation in the supplied API specification. Each namespace also includes methods `setDefaultConfiguration` and `setDefaultOptions` to update the default configuration and options to all operations if the API.

#### Example Usage

In Typescript:

```typescript
const sdkNamespace = standardSdk.ticketmaster;
```

## [`standardSDKInstance.<namespace>.setDefaultConfiguration(configuration)`](#standardsdkinstance-namespace-setDefaultConfiguration)

Sets the default configuration for all operations of in an API namespace. When using an API described via an OpenAPI spec, the `configuration` parameter should be a `OpenApiClientConfiguration` object as defined in [@comake/openapi-operation-executor](https://github.com/comake/openapi-operation-executor).

#### Example Usage

In Typescript:

```typescript
standardSdk.ticketmaster.setDefaultConfiguration({
  apiKey: 'acb123'
});
```

## [`standardSDKInstance.<namespace>.setDefaultOptions(options)`](#standardsdkinstance-namespace-setDefaultConfiguration)

Sets the default options for all operations of in an API namespace. When using an API described via an OpenAPI spec, the `options` parameter should be an `AxiosRequestConfig` object as defined in the [axios API documentation](https://github.com/axios/axios#request-config).

#### Example Usage

In Typescript:

```typescript
standardSdk.ticketmaster.setDefaultOptions({
  headers: {
    'X-Powered-By': 'Comake'
  }
});
```

## [`standardSDKInstance.<namespace>.<operation>(args, configuration, options)`](#standardsdkinstance-namespace-operation)

Executes the API operation called `<operation>` according to the API specification corresponding to the namespace `<namespace>`.

#### Parameters

All parameters are optional, however, when using Typescript and executing an OpenAPI operation with required parameters or request body, the `args` parameter will be required.

| Parameter       | Type     | Description                                                                                                                                                                                                                                                                                                                                                                 |
| --------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `args`          | `object` | Arguments for the operation as defined by the API specification. For example, an operation in an OpenAPI spec has either a `requestBody` or a `parameters` field. StandardSDK will read these fields and construct and send a web request with the data from `args` in the correct parts of the request.                                                                    |
| `configuration` | `object` | An object holding any configuration necessary for the operation. Most often this includes security credentials. For example, for an OpenAPI operation `configuration` may include an `apiKey` or `accessToken` to satisfy the [Security Requirement](https://spec.openapis.org/oas/v3.1.0#securityRequirementObject) of the operation. See note below for more information. |
| `options`       | `object` | An object holding any options to supply to the operation execution module to modfy default behaviors the request or message sent for the operation. For OpenAPI operations, this is an `AxiosRequestConfig` object. See the [axios API documentation](https://github.com/axios/axios#request-config) for reference.                                                         |

⚠️ StandardSDK uses the [@comake/openapi-operation-executor](https://www.npmjs.com/package/@comake/openapi-operation-executor) package to execute OpenAPI operations. This library currently supports OpenAPI security types `oauth2`, `apiKey`, and `http` with schemes `basic` or `bearer`. See [the OpenAPI Spec](https://spec.openapis.org/oas/v3.1.0#security-scheme-object) for reference and the [@comake/openapi-operation-executor API docs](https://github.com/comake/openapi-operation-executor#api) for more information.

#### Return Value

Operations return [`Promises`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which resolve to different values depending on the type of API. OpenAPI operations will resolve to an [`AxiosResponse`](https://github.com/axios/axios#response-schema) object.

#### Example Usage

In Typescript:

```typescript
const axiosResponse = await standardSdk.ticketmaster.SearchEvents(
  { city: 'Atlanta' }, // args
  { apiKey: '<your ticketmaster api key>' }, // configuration
  { headers: { 'X-Origin-SDK': 'StandardSDK' } } // options
);
```

## [`standardSDKInstance.skl`](#standardsdkinstance-skl)

A [SKL JS Engine](https://www.npmjs.com/package/@comake/skl-js-engine) instance which is instantiated when the `sklEngineOptions` parameter is supplied when Standard SDK is built.

#### Example Usage

In Typescript:

```typescript
const skl = standardSdk.skl;
```

## [`standardSDKInstance.skl.verb`](#standardsdkinstance-skl-verb)

The [Verb](https://docs.standardknowledge.com/fundamentals#verbs) execution interface of the [SKL JS Engine](https://www.npmjs.com/package/@comake/skl-js-engine) instance accessed through Standard SDK.

#### Example Usage

In Typescript:

```typescript
const skl = standardSdk.skl.verb;
```

## [`standardSDKInstance.skl.verb.<verb>(args)`](#standardsdkinstance-skl-verb-verb)

Executes the verb called `<verb>` according to its Schema and related Mappings in the Schemas provided to the [SKL JS Engine](https://www.npmjs.com/package/@comake/skl-js-engine) instance via the `sklEngineOptions` parameter when building Standard SDK.

#### Parameters

| Parameter | Type     | Description                                                                                                    |
| --------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| `args`    | `object` | The arguments supplied to the Verb which should conform to the Verb's `parameters` field of the Verb's Schema. |

#### Return Value

Verbs executed using [SKL JS Engine](https://www.npmjs.com/package/@comake/skl-js-engine) return [`Promises`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which resolve to an [`AxiosResponse`](https://github.com/axios/axios#response-schema) object.

#### Example Usage

In Typescript:

```typescript
const response = standardSdk.skl.verb.getEvents({
  account: 'https://example.com/data/TicketmasterAccount',
  city: 'New York',
});
```


# Contributing

Thank you for taking the time to contribute! 🎉👍

The following is a set of guidelines for contributing to Standard SDK JS, which is hosted in the Comake Organization on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.

Please read our [Code of Conduct](https://github.com/comake/standard-sdk-js/blob/main/CODE_OF_CONDUCT.md) to keep our community approachable and respectable.

To get an overview of the project, read the [README](https://github.com/comake/standard-sdk-js/blob/main/README.md).

The repository is available at <https://github.com/comake/standard-sdk-js>

## Pull Requests

All changes should be done through [Pull Requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork).

We recommend first searching for existing [Issues](https://github.com/comake/standard-sdk-js/issues) related to your problem. If one does not exist, create a new [Issue](https://github.com/comake/standard-sdk-js/issues) to discuss a possible solution to reduce the amount of changes that will be requested.

After coming to consensus with maintainers, create a [Fork](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork) of the repo and implement your code changes and test.

In case any of your changes are breaking, make sure you target the next major branch (`versions/x.0.0`) instead of the `main` branch. Breaking changes include: changing interface/class signatures, potentially breaking external custom configurations, and breaking how internal data is stored. In case of doubt you probably want to target the next major branch.

## Writing Code

Standard SDK JS is fully written in [Typescript](https://www.typescriptlang.org/docs/home.html).

We make use of [Conventional Commits](https://www.conventionalcommits.org/) .

We use [Husky](https://typicode.github.io/husky/#/) to enforce strict requirements from the [linter](https://eslint.org/) and the [test coverage](https://jestjs.io/docs/configuration#coveragethreshold-object) before a PR is valid. These are configured to run automatically when trying to commit to git.

If a list of entries is alphabetically sorted, such as [index.ts](https://github.com/comake/standard-sdk-js/blob/main/src/index.ts), make sure it stays that way.

## Testing

As mentioned above, tests run automatically when trying to commit to git. You should add or update [unit tests](https://github.com/comake/standard-sdk-js/tree/main/test/unit) for any code that you add or change. If you are building a feature, please also add relevant [integration tests](https://github.com/comake/standard-sdk-js/tree/main/test/integration)

To run tests manually, use:

```
npm run test
```

or to only run tests in a specific file, use:

```
npm run test ./test/unit/path/to/test.ts
```


# License

For the avoidance of doubt, this license does not grant the licensee any rights or licenses under Comake's patent rights and Comake reserves any and all such rights.

MIT License

Copyright (c) 2023 Comake, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


