diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4248337..c348128 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,6 +50,6 @@ jobs: - name: Publish to npm run: | npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN} - npm publish --access public --tag beta + npm publish --access public env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/README.md b/README.md index d02dd9e..2220032 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,6 @@ - The Fern Typescript library provides access to the Fern's Public API from JavaScript/TypeScript, and from the JavaScript runtime of your choice ([Node, Browser, Deno, Bun and more](#runtime-compatiblity)). ## Documentation @@ -15,6 +14,7 @@ API reference documentation is available [here](https://buildwithfern.com/learn/ This SDK primarily serves as a way to access Fern's **dynamic snippets** API. Fern's dynamic snippets API is meant to allow users to create code snippets for their Fern-generate SDKs with dynamic payloads. Common use cases include: + 1. In-app code examples 2. User-specific code examples in your documentation 3. So much more! @@ -22,6 +22,7 @@ Common use cases include:
Notable features: + 1. [Client-side execution](#client-side-execution), ideal for code examples that change often, potentially due to user input in a browser. 2. [Dynamic code examples](#dynamic-code-examples) 3. [Displaying default and auto-generated examples](#default-or-static-code-examples) @@ -39,6 +40,7 @@ yarn add @fern-api/sdk ## Usage ### Client-side Execution + ```typescript import { FernClient } from "@fern-api/sdk"; @@ -79,6 +81,7 @@ const snippet2 = template.resolve({ ``` ### Dynamic Code Examples + ```typescript import { FernClient } from "@fern-api/sdk"; @@ -107,6 +110,7 @@ const snippets = await fern.snippets.get({ ``` ### Default or Static Code Examples + ```typescript import { FernClient } from "@fern-api/sdk"; @@ -117,21 +121,21 @@ const fern = new FernClient({ // Without any payload specified, the SDK returns a snippet with the examples provided within your API spec // If there are no examples in your spec, a basic example is autogenerated for you. const snippets = await fern.snippets.get({ - endpoint: { - method: "GET", - path: "/api/users", - }, - // The name of your organization, found in your `fern.config.json` - orgId: "my_organization", - // The name of the API you'd like to generate snippets for, - apiId: "api", - sdks: [{ "type": "python", "package": "my_package", "version": "0.0.3" }], + endpoint: { + method: "GET", + path: "/api/users", + }, + // The name of your organization, found in your `fern.config.json` + orgId: "my_organization", + // The name of the API you'd like to generate snippets for, + apiId: "api", + sdks: [{ type: "python", package: "my_package", version: "0.0.3" }], }); ``` - ### Handling Errors -When the API returns a non-success status code (4xx or 5xx response), + +When the API returns a non-success status code (4xx or 5xx response), a subclass of [FernError](./src/errors/FernError.ts) will be thrown: @@ -142,56 +146,56 @@ try { await fern.snippets.get(...); } catch (err) { if (err instanceof FernError) { - console.log(err.statusCode); + console.log(err.statusCode); console.log(err.message); - console.log(err.body); + console.log(err.body); } } ``` ### Request Options -The HTTP Client accepts a `RequestOptions` class where you can specify -a customized timeout. +The HTTP Client accepts a `RequestOptions` class where you can specify +a customized timeout. ```typescript const snippets = await fern.snippets.get( - { - endpoint: { - method: "GET", - path: "/api/users", + { + endpoint: { + method: "GET", + path: "/api/users", + }, + }, + { + timeoutInSeconds: 60, // increase timeout in second } - }, - { - timeoutInSeconds: 60 // increase timeout in second - }); +); ``` ### Runtime compatiblity -The SDK defaults to `node-fetch` but will use the global fetch client if present. The SDK -works in the following runtimes: +The SDK defaults to `node-fetch` but will use the global fetch client if present. The SDK +works in the following runtimes: The following runtimes are supported: -- Node.js 15+ -- Vercel -- Cloudflare Workers -- Deno v1.25+ -- Bun 1.0+ - +- Node.js 15+ +- Vercel +- Cloudflare Workers +- Deno v1.25+ +- Bun 1.0+ ## Beta status -This SDK is in beta, and there may be breaking changes between versions without a major version update. Therefore, we -recommend pinning the package version to a specific version in your package.json file. This way, you can install the +This SDK is in beta, and there may be breaking changes between versions without a major version update. Therefore, we +recommend pinning the package version to a specific version in your package.json file. This way, you can install the same version each time without breaking changes unless you are intentionally looking for the latest version. ## Contributing -While we value open-source contributions to this SDK, this library is generated programmatically. -Additions made directly to this library would have to be moved over to our generation code, otherwise -they would be overwritten upon the next generated release. Feel free to open a PR as a proof of concept, +While we value open-source contributions to this SDK, this library is generated programmatically. +Additions made directly to this library would have to be moved over to our generation code, otherwise +they would be overwritten upon the next generated release. Feel free to open a PR as a proof of concept, but know that we will not be able to merge it as-is. We suggest opening an issue first to discuss with us! On the other hand, contributions to the README are always very welcome! diff --git a/package.json b/package.json index fa64eb6..f8947ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fern-api/sdk", - "version": "0.13.0-beta1", + "version": "0.13.0", "private": false, "repository": "https://github.com/fern-api/typescript-sdk", "license": "MIT", diff --git a/src/index.ts b/src/index.ts index 6e23f1f..b2db360 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,4 +2,4 @@ export * as Fern from "./api"; export { FernClient } from "./wrapper/FernClient"; export { FernEnvironment } from "./environments"; export { FernError, FernTimeoutError } from "./errors"; -export { Template } from "./wrapper/Template"; \ No newline at end of file +export { Template } from "./wrapper/Template"; diff --git a/src/wrapper/FernClient.ts b/src/wrapper/FernClient.ts index 168ee34..2938436 100644 --- a/src/wrapper/FernClient.ts +++ b/src/wrapper/FernClient.ts @@ -1,9 +1,7 @@ import { FernClient as GeneratedClient } from "../Client"; import { TemplatesClient } from "./TemplatesClient"; - export class FernClient extends GeneratedClient { - protected _templates: TemplatesClient | undefined; public get templates(): TemplatesClient { diff --git a/src/wrapper/Template.ts b/src/wrapper/Template.ts index ee029c8..a75966c 100644 --- a/src/wrapper/Template.ts +++ b/src/wrapper/Template.ts @@ -4,13 +4,14 @@ import { FernRegistry, FernRegistryClient } from "@fern-fern/fdr-cjs-sdk"; export class Template implements Fern.templates.EndpointSnippetTemplate { private endpointSnippetTemplate: Fern.EndpointSnippetTemplate; - + constructor( public readonly sdk: Fern.snippets.Sdk, public readonly endpointId: Fern.commons.EndpointIdentifier, - public readonly snippetTemplate: Fern.templates.VersionedSnippetTemplate + public readonly snippetTemplate: Fern.templates.VersionedSnippetTemplate, + public readonly apiDefinitionId?: Fern.ApiDefinitionId ) { - this.endpointSnippetTemplate = {sdk, endpointId, snippetTemplate}; + this.endpointSnippetTemplate = { sdk, endpointId, snippetTemplate, apiDefinitionId }; } /** @@ -18,31 +19,34 @@ export class Template implements Fern.templates.EndpointSnippetTemplate { * @param payload the paylod to resolve against * @returns the snippet */ - public resolve(payload: Fern.snippets.CustomSnippetPayload): Fern.snippets.Snippet { + public async resolve(payload: Fern.snippets.CustomSnippetPayload): Promise { + const response = this.apiDefinitionId != null ? await new FernRegistryClient().api.v1.read.getApi(FernRegistry.ApiDefinitionId(this.apiDefinitionId)) : undefined; const _innerResolver = new SnippetTemplateResolver({ payload: { ...payload, - headers: payload.headers?.map((header): FernRegistry.ParameterPayload => { return { name: header.name, value: header.value ?? undefined } }), - pathParameters: payload.pathParameters?.map((header): FernRegistry.ParameterPayload => { return { name: header.name, value: header.value ?? undefined } }), - queryParameters: payload.queryParameters?.map((header): FernRegistry.ParameterPayload => { return { name: header.name, value: header.value ?? undefined } }), + headers: payload.headers?.map((header): FernRegistry.ParameterPayload => { + return { name: header.name, value: header.value ?? undefined }; + }), + pathParameters: payload.pathParameters?.map((header): FernRegistry.ParameterPayload => { + return { name: header.name, value: header.value ?? undefined }; + }), + queryParameters: payload.queryParameters?.map((header): FernRegistry.ParameterPayload => { + return { name: header.name, value: header.value ?? undefined }; + }), requestBody: payload.requestBody ?? undefined, auth: payload.auth ?? undefined, }, endpointSnippetTemplate: this.endpointSnippetTemplate as FernRegistry.EndpointSnippetTemplate, - apiDefinitionGetter: async (id) => { - const response = await new FernRegistryClient().api.v1.read.getApi(FernRegistry.ApiDefinitionId(id)); - if (response.ok) { - return response.body; - } - throw new Error(JSON.stringify(response.error)); - }, }); - - return _innerResolver.resolve(); + if (response?.ok) { + return _innerResolver.resolve(response.body); + } else { + return _innerResolver.resolve(); + } } /** - * Resolves a particular request payload against the template to produce a snippet with + * Resolves a particular request payload against the template to produce a snippet with * formatting. * @param payload the paylod to resolve against * @returns the snippet @@ -51,9 +55,15 @@ export class Template implements Fern.templates.EndpointSnippetTemplate { const _innerResolver = new SnippetTemplateResolver({ payload: { ...payload, - headers: payload.headers?.map((header): FernRegistry.ParameterPayload => { return { name: header.name, value: header.value ?? undefined } }), - pathParameters: payload.pathParameters?.map((header): FernRegistry.ParameterPayload => { return { name: header.name, value: header.value ?? undefined } }), - queryParameters: payload.queryParameters?.map((header): FernRegistry.ParameterPayload => { return { name: header.name, value: header.value ?? undefined } }), + headers: payload.headers?.map((header): FernRegistry.ParameterPayload => { + return { name: header.name, value: header.value ?? undefined }; + }), + pathParameters: payload.pathParameters?.map((header): FernRegistry.ParameterPayload => { + return { name: header.name, value: header.value ?? undefined }; + }), + queryParameters: payload.queryParameters?.map((header): FernRegistry.ParameterPayload => { + return { name: header.name, value: header.value ?? undefined }; + }), requestBody: payload.requestBody ?? undefined, auth: payload.auth ?? undefined, }, @@ -75,10 +85,10 @@ export class Template implements Fern.templates.EndpointSnippetTemplate { } public static from(template: Fern.templates.EndpointSnippetTemplate): Template { - return new Template(template.sdk, template.endpointId, template.snippetTemplate); + return new Template(template.sdk, template.endpointId, template.snippetTemplate, template.apiDefinitionId); } } export function isNonNullish(x: T | null | undefined): x is T { return x != null; -} \ No newline at end of file +} diff --git a/src/wrapper/TemplatesClient.ts b/src/wrapper/TemplatesClient.ts index c0e2b65..7b8e0c0 100644 --- a/src/wrapper/TemplatesClient.ts +++ b/src/wrapper/TemplatesClient.ts @@ -1,10 +1,8 @@ -import { Templates as GeneratedTemplatesClient } from "../api/resources/templates/client/Client" +import { Templates as GeneratedTemplatesClient } from "../api/resources/templates/client/Client"; import { Fern } from "../index"; import { Template } from "./Template"; - export class TemplatesClient extends GeneratedTemplatesClient { - /** * Get the endpoint's snippet template for a particular SDK. * @throws {@link Fern.UnauthorizedError} @@ -15,6 +13,6 @@ export class TemplatesClient extends GeneratedTemplatesClient { requestOptions?: GeneratedTemplatesClient.RequestOptions ): Promise