From 66924182538f624cb4c275239afb927ad7eedc48 Mon Sep 17 00:00:00 2001 From: Deep Singhvi Date: Tue, 14 Jan 2025 20:28:30 -0500 Subject: [PATCH 1/3] feat(openrpc): introduce json schema examle generator (#2017) --- packages/parsers/package.json | 2 +- .../examples/generateExampleForJsonSchema.ts | 75 + .../src/openrpc/1.x/MethodConverter.node.ts | 101 +- .../__test__/__snapshots__/ethereum.json | 1017 +++++++++- .../__test__/__snapshots__/petstore.json | 35 +- .../__test__/__snapshots__/solana.json | 1665 +++++++++++++++++ 6 files changed, 2847 insertions(+), 48 deletions(-) create mode 100644 packages/parsers/src/examples/generateExampleForJsonSchema.ts diff --git a/packages/parsers/package.json b/packages/parsers/package.json index 38b88c1e1e..1685372d26 100644 --- a/packages/parsers/package.json +++ b/packages/parsers/package.json @@ -1,6 +1,6 @@ { "name": "@fern-api/docs-parsers", - "version": "0.0.36", + "version": "0.0.37", "repository": { "type": "git", "url": "https://github.com/fern-api/fern-platform.git", diff --git a/packages/parsers/src/examples/generateExampleForJsonSchema.ts b/packages/parsers/src/examples/generateExampleForJsonSchema.ts new file mode 100644 index 0000000000..e157213e89 --- /dev/null +++ b/packages/parsers/src/examples/generateExampleForJsonSchema.ts @@ -0,0 +1,75 @@ +import { JSONSchema } from "@open-rpc/meta-schema"; + +export function generateExampleForJsonSchema(schema: JSONSchema): unknown { + if (typeof schema === "boolean") { + return schema; + } + + if (schema.enum != null && schema.enum.length > 0) { + return schema.enum[0]; + } + + if (schema.const != null) { + return schema.const; + } + + if (schema.examples != null && schema.examples.length > 0) { + return schema.examples[0]; + } + + if (schema.type === "object") { + const example: Record = {}; + if (schema.properties != null) { + for (const [key, value] of Object.entries(schema.properties)) { + example[key] = generateExampleForJsonSchema(value); + } + } + return example; + } + + if (schema.type === "array") { + if (schema.items == null) { + return []; + } + if (Array.isArray(schema.items)) { + return schema.items.map((item) => generateExampleForJsonSchema(item)); + } + return [generateExampleForJsonSchema(schema.items)]; + } + + if (schema.type === "string") { + return schema.default ?? "string"; + } + + if (schema.type === "number" || schema.type === "integer") { + return schema.default ?? 0; + } + + if (schema.type === "boolean") { + return schema.default ?? false; + } + + if (schema.type === "null") { + return null; + } + + if (schema.oneOf?.[0] != null) { + return generateExampleForJsonSchema(schema.oneOf[0]); + } + + if (schema.anyOf?.[0] != null) { + return generateExampleForJsonSchema(schema.anyOf[0]); + } + + if (schema.allOf != null && schema.allOf.length > 0) { + const example: Record = {}; + for (const subSchema of schema.allOf) { + if (subSchema != null) { + Object.assign(example, generateExampleForJsonSchema(subSchema)); + } + } + return example; + } + + return undefined; +} diff --git a/packages/parsers/src/openrpc/1.x/MethodConverter.node.ts b/packages/parsers/src/openrpc/1.x/MethodConverter.node.ts index d61a7e377e..bc766f793b 100644 --- a/packages/parsers/src/openrpc/1.x/MethodConverter.node.ts +++ b/packages/parsers/src/openrpc/1.x/MethodConverter.node.ts @@ -3,6 +3,7 @@ import { MethodObject } from "@open-rpc/meta-schema"; import { camelCase } from "es-toolkit"; import { UnreachableCaseError } from "ts-essentials"; import { FernRegistry } from "../../client/generated"; +import { generateExampleForJsonSchema } from "../../examples/generateExampleForJsonSchema"; import { SchemaConverterNode, ServerObjectConverterNode } from "../../openapi"; import { maybeSingleValueToArray } from "../../openapi/utils/maybeSingleValueToArray"; import { @@ -100,25 +101,8 @@ export class MethodConverterNode extends BaseOpenrpcConverterNode< } : undefined; - // Convert method to HTTP endpoint - // This is a basic implementation that needs to be expanded - return { - id: FernRegistry.EndpointId(this.input.name), - displayName: camelCase(this.input.name), - method: "POST", - path: [{ type: "literal", value: "" }], - auth: undefined, - pathParameters: [], - queryParameters: [], - requests: request != null ? [request] : undefined, - responses: - response != null - ? [ - this.convertToHttpResponse(response, this.input.description), - ].filter(isNonNullish) - : [], - errors: [], - examples: this.method.examples + const examples = + this.method.examples ?.map( ( example @@ -157,7 +141,84 @@ export class MethodConverterNode extends BaseOpenrpcConverterNode< }; } ) - .filter(isNonNullish), + .filter(isNonNullish) ?? []; + + if (examples.length <= 0) { + const example = { + name: "Example", + path: "", + pathParameters: {}, + queryParameters: {}, + headers: {}, + requestBody: { + type: "json" as const, + value: generateExampleForJsonSchema({ + type: "object", + properties: Object.fromEntries( + this.method.params?.map((param) => { + const resolvedParam = resolveContentDescriptorObject( + param, + this.context.openrpc + ); + return [ + resolvedParam?.name ?? "", + resolvedParam?.schema ?? {}, + ]; + }) ?? [] + ), + }), + }, + responseStatusCode: 200, + responseBody: { + type: "json" as const, + value: generateExampleForJsonSchema( + resolveContentDescriptorObject( + this.method.result, + this.context.openrpc + )?.schema ?? {} + ), + }, + snippets: undefined, + description: undefined, + }; + examples.push(example); + } + + const examplesWithJsonRPCMetadata = examples.map((example) => { + const originalRequestBody = example.requestBody?.value; + return { + ...example, + requestBody: { + type: "json" as const, + value: { + id: 1, + jsonrpc: "2.0", + method: this.method.name, + params: originalRequestBody, + }, + }, + }; + }); + + // Convert method to HTTP endpoint + // This is a basic implementation that needs to be expanded + return { + id: FernRegistry.EndpointId(this.input.name), + displayName: camelCase(this.input.name), + method: "POST", + path: [{ type: "literal", value: "" }], + auth: undefined, + pathParameters: [], + queryParameters: [], + requests: request != null ? [request] : undefined, + responses: + response != null + ? [ + this.convertToHttpResponse(response, this.input.description), + ].filter(isNonNullish) + : [], + errors: [], + examples: examplesWithJsonRPCMetadata, description: this.input.description ?? this.input.summary, operationId: this.input.name, defaultEnvironment: undefined, diff --git a/packages/parsers/src/openrpc/__test__/__snapshots__/ethereum.json b/packages/parsers/src/openrpc/__test__/__snapshots__/ethereum.json index 9f672f2ae9..87420958d7 100644 --- a/packages/parsers/src/openrpc/__test__/__snapshots__/ethereum.json +++ b/packages/parsers/src/openrpc/__test__/__snapshots__/ethereum.json @@ -1268,6 +1268,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "web3_clientVersion", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": "string" + } + } + ], "description": "Returns the version of the current client", "operationId": "web3_clientVersion", "environments": [], @@ -1335,9 +1358,14 @@ "headers": {}, "requestBody": { "type": "json", - "value": [ - "0x68656c6c6f20776f726c64" - ] + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "web3_sha3", + "params": [ + "0x68656c6c6f20776f726c64" + ] + } }, "responseStatusCode": 200, "responseBody": { @@ -1391,6 +1419,14 @@ "pathParameters": {}, "queryParameters": {}, "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "net_listening" + } + }, "responseStatusCode": 200, "responseBody": { "type": "json", @@ -1436,6 +1472,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "net_peerCount", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": "string" + } + } + ], "description": "Returns the number of peers currently connected to this client.", "operationId": "net_peerCount", "environments": [], @@ -1472,6 +1531,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "net_version", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": "string" + } + } + ], "description": "Returns the network ID associated with the current network.", "operationId": "net_version", "environments": [], @@ -1504,6 +1586,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_blockNumber", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the number of most recent block.", "operationId": "eth_blockNumber", "environments": [], @@ -1567,6 +1671,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_call", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Executes a new message call (locally) immediately without creating a transaction on the block chain.", "operationId": "eth_call", "environments": [], @@ -1603,6 +1729,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_chainId", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": "string" + } + } + ], "description": "Returns the currently configured chain id, a value used in replay-protected transaction signing as introduced by [EIP-155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md).", "operationId": "eth_chainId", "environments": [], @@ -1635,6 +1784,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_coinbase", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the client coinbase address.", "operationId": "eth_coinbase", "environments": [], @@ -1688,6 +1859,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_estimateGas", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Generates and returns an estimate of how much gas is necessary to allow the transaction to complete. The transaction will not be added to the blockchain. Note that the estimate may be significantly more than the amount of gas actually used by the transaction, for a variety of reasons including EVM mechanics and node performance.", "operationId": "eth_estimateGas", "environments": [], @@ -1720,6 +1913,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_gasPrice", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the current price per gas in wei", "operationId": "eth_gasPrice", "environments": [], @@ -1785,6 +2000,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns Ether balance of a given or account or contract", "operationId": "eth_getBalance", "environments": [], @@ -1851,6 +2088,30 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getBlockByHash", + "params": { + "includeTransactions": false + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Gets a block for a given hash", "operationId": "eth_getBlockByHash", "environments": [], @@ -1917,6 +2178,30 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params": { + "includeTransactions": false + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Gets a block for a given number", "operationId": "eth_getBlockByNumber", "environments": [], @@ -1970,6 +2255,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByHash", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the number of transactions in a block from a block matching the given block hash.", "operationId": "eth_getBlockTransactionCountByHash", "environments": [], @@ -2023,6 +2330,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getBlockTransactionCountByNumber", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the number of transactions in a block from a block matching the given block number.", "operationId": "eth_getBlockTransactionCountByNumber", "environments": [], @@ -2088,6 +2417,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getCode", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns code at a given contract address", "operationId": "eth_getCode", "environments": [], @@ -2147,6 +2498,31 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getFilterChanges", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + null + ] + } + } + ], "description": "Polling method for a filter, which returns an array of logs which occurred since last poll.", "operationId": "eth_getFilterChanges", "environments": [], @@ -2206,6 +2582,31 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getFilterLogs", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + null + ] + } + } + ], "description": "Returns an array of all logs matching filter with given id.", "operationId": "eth_getFilterLogs", "environments": [], @@ -2259,6 +2660,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getRawTransactionByHash", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns raw transaction data of a transaction with the given hash.", "operationId": "eth_getRawTransactionByHash", "environments": [], @@ -2323,6 +2746,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getRawTransactionByBlockHashAndIndex", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns raw transaction data of a transaction with the block hash and index of which it was mined.", "operationId": "eth_getRawTransactionByBlockHashAndIndex", "environments": [], @@ -2387,6 +2832,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getRawTransactionByBlockNumberAndIndex", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns raw transaction data of a transaction with the block number and index of which it was mined.", "operationId": "eth_getRawTransactionByBlockNumberAndIndex", "environments": [], @@ -2485,6 +2952,33 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getLogs", + "params": { + "filter": {} + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + null + ] + } + } + ], "description": "Returns an array of all logs matching a given filter object.", "operationId": "eth_getLogs", "environments": [], @@ -2558,6 +3052,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getStorageAt", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Gets a storage value from a contract address, a position, and an optional blockNumber", "operationId": "eth_getStorageAt", "environments": [], @@ -2631,10 +3147,15 @@ "headers": {}, "requestBody": { "type": "json", - "value": [ - "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", - "0x0" - ] + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getTransactionByBlockHashAndIndex", + "params": [ + "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + "0x0" + ] + } }, "responseStatusCode": 200, "responseBody": { @@ -2710,6 +3231,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getTransactionByBlockNumberAndIndex", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the information about a transaction requested by the block number and index of which it was mined.", "operationId": "eth_getTransactionByBlockNumberAndIndex", "environments": [], @@ -2763,6 +3306,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getTransactionByHash", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the information about a transaction requested by transaction hash.", "operationId": "eth_getTransactionByHash", "environments": [], @@ -2826,6 +3391,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the number of transactions sent from an address", "operationId": "eth_getTransactionCount", "environments": [], @@ -2879,6 +3466,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the receipt information of a transaction by its hash.", "operationId": "eth_getTransactionReceipt", "environments": [], @@ -2943,6 +3552,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getUncleByBlockHashAndIndex", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns information about a uncle of a block by hash and uncle index position.", "operationId": "eth_getUncleByBlockHashAndIndex", "environments": [], @@ -3016,11 +3647,16 @@ "queryParameters": {}, "headers": {}, "requestBody": { - "type": "json", - "value": [ - "0x0", - "0x0" - ] + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getUncleByBlockNumberAndIndex", + "params": [ + "0x0", + "0x0" + ] + } }, "responseStatusCode": 200, "responseBody": { @@ -3085,6 +3721,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getUncleCountByBlockHash", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the number of uncles in a block from a block matching the given block hash.", "operationId": "eth_getUncleCountByBlockHash", "environments": [], @@ -3138,6 +3796,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getUncleCountByBlockNumber", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the number of uncles in a block from a block matching the given block number.", "operationId": "eth_getUncleCountByBlockNumber", "environments": [], @@ -3276,6 +3956,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getProof", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": {} + } + } + ], "description": "Returns the account- and storage-values of the specified account including the Merkle-proof.", "operationId": "eth_getProof", "environments": [], @@ -3339,6 +4042,33 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_getWork", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + null, + null, + null + ] + } + } + ], "description": "Returns the hash of the current block, the seedHash, and the boundary condition to be met ('target').", "operationId": "eth_getWork", "environments": [], @@ -3371,6 +4101,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_hashrate", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the number of hashes per second that the node is mining with.", "operationId": "eth_hashrate", "environments": [], @@ -3405,6 +4157,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_mining", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": false + } + } + ], "description": "Returns true if client is actively mining new blocks.", "operationId": "eth_mining", "environments": [], @@ -3437,6 +4212,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_newBlockFilter", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Creates a filter in the node, to notify when a new block arrives. To check if the state has changed, call eth_getFilterChanges.", "operationId": "eth_newBlockFilter", "environments": [], @@ -3529,6 +4326,30 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_newFilter", + "params": { + "filter": {} + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Creates a filter object, based on filter options, to notify when the state changes (logs). To check if the state has changed, call eth_getFilterChanges.", "operationId": "eth_newFilter", "environments": [], @@ -3561,6 +4382,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_newPendingTransactionFilter", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Creates a filter in the node, to notify when new pending transactions arrive. To check if the state has changed, call eth_getFilterChanges.", "operationId": "eth_newPendingTransactionFilter", "environments": [], @@ -3593,6 +4436,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_pendingTransactions", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the transactions that are pending in the transaction pool and have a from address that is one of the accounts this node manages.", "operationId": "eth_pendingTransactions", "environments": [], @@ -3625,6 +4490,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_protocolVersion", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Returns the current ethereum protocol version.", "operationId": "eth_protocolVersion", "environments": [], @@ -3679,6 +4566,28 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_sendRawTransaction", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json" + } + } + ], "description": "Creates new message call transaction or a contract creation for signed transactions.", "operationId": "eth_sendRawTransaction", "environments": [], @@ -3745,6 +4654,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_submitHashrate", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": false + } + } + ], "description": "Used for submitting mining hashrate.", "operationId": "eth_submitHashrate", "environments": [], @@ -3830,11 +4762,16 @@ "headers": {}, "requestBody": { "type": "json", - "value": [ - "0x0000000000000001", - "0x6bf2cAE0dE3ec3ecA5E194a6C6e02cf42aADfe1C2c4Fff12E5D36C3Cf7297F22", - "0xD1FE5700000000000000000000000000D1FE5700000000000000000000000000" - ] + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_submitWork", + "params": [ + "0x0000000000000001", + "0x6bf2cAE0dE3ec3ecA5E194a6C6e02cf42aADfe1C2c4Fff12E5D36C3Cf7297F22", + "0xD1FE5700000000000000000000000000D1FE5700000000000000000000000000" + ] + } }, "responseStatusCode": 200, "responseBody": { @@ -3933,6 +4870,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_syncing", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": {} + } + } + ], "description": "Returns an object with data about the sync status or false.", "operationId": "eth_syncing", "environments": [], @@ -3988,6 +4948,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "eth_uninstallFilter", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": false + } + } + ], "description": "Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additionally Filters timeout when they aren't requested with eth_getFilterChanges for a period of time.", "operationId": "eth_uninstallFilter", "environments": [], diff --git a/packages/parsers/src/openrpc/__test__/__snapshots__/petstore.json b/packages/parsers/src/openrpc/__test__/__snapshots__/petstore.json index 1cf09e700a..da58426450 100644 --- a/packages/parsers/src/openrpc/__test__/__snapshots__/petstore.json +++ b/packages/parsers/src/openrpc/__test__/__snapshots__/petstore.json @@ -140,9 +140,14 @@ "headers": {}, "requestBody": { "type": "json", - "value": [ - 1 - ] + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "list_pets", + "params": [ + 1 + ] + } }, "responseStatusCode": 200, "responseBody": { @@ -243,10 +248,15 @@ "headers": {}, "requestBody": { "type": "json", - "value": [ - "fluffy", - "poodle" - ] + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "create_pet", + "params": [ + "fluffy", + "poodle" + ] + } }, "responseStatusCode": 200, "responseBody": { @@ -326,9 +336,14 @@ "headers": {}, "requestBody": { "type": "json", - "value": [ - 7 - ] + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "get_pet", + "params": [ + 7 + ] + } }, "responseStatusCode": 200, "responseBody": { diff --git a/packages/parsers/src/openrpc/__test__/__snapshots__/solana.json b/packages/parsers/src/openrpc/__test__/__snapshots__/solana.json index 7684a34b69..338a0686c9 100644 --- a/packages/parsers/src/openrpc/__test__/__snapshots__/solana.json +++ b/packages/parsers/src/openrpc/__test__/__snapshots__/solana.json @@ -231,6 +231,49 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getAccountInfo", + "params": { + "Pubkey": "string", + "Configuration": { + "commitment": "processed", + "encoding": "base58", + "dataSlice": { + "length": 0, + "offset": 0 + }, + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "lamports": 0, + "owner": "string", + "data": [ + "string" + ], + "executable": false, + "rentEpoch": 0, + "size": 0 + } + } + } + ], "description": "Returns all information associated with the account of provided Pubkey.", "operationId": "getAccountInfo", "environments": [], @@ -330,6 +373,35 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getBalance", + "params": { + "Pubkey": "string", + "Configuration": { + "commitment": "processed", + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": 0 + } + } + ], "description": "Returns the lamport balance of the account of the provided Pubkey.", "operationId": "getBalance", "environments": [], @@ -1391,6 +1463,143 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getBlock", + "params": { + "slot": 0, + "Configuration": { + "commitment": "processed", + "encoding": "json", + "transactionDetails": "full", + "maxSupportedTransactionVersion": 0, + "rewards": true + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "blockhash": "string", + "previousBlockhash": "string", + "parentSlot": 0, + "transactions": [ + { + "slot": 0, + "transaction": { + "signatures": [ + "string" + ], + "message": { + "accountKeys": [ + "string" + ], + "header": { + "numRequiredSignatures": 0, + "numReadonlySignedAccounts": 0, + "numReadonlyUnsignedAccounts": 0 + }, + "instructions": [ + { + "accounts": [ + 0 + ], + "data": "string", + "programIdIndex": 0 + } + ], + "recentBlockhash": "string" + } + }, + "blockTime": 0, + "meta": { + "err": {}, + "fee": 0, + "preBalances": [ + 0 + ], + "postBalances": [ + 0 + ], + "innerInstructions": [ + { + "index": 0, + "instructions": [ + { + "programId": "string", + "accounts": [ + "string" + ], + "data": "string" + } + ] + } + ], + "preTokenBalances": [ + { + "amount": "string", + "decimals": 0, + "uiAmount": 0, + "uiAmountString": "string" + } + ], + "postTokenBalances": [ + { + "amount": "string", + "decimals": 0, + "uiAmount": 0, + "uiAmountString": "string" + } + ], + "logMessages": [ + "string" + ], + "rewards": [ + { + "pubkey": "string", + "lamports": 0, + "postBalance": 0, + "rewardType": "fee", + "commission": 0 + } + ], + "loadedAddresses": {}, + "returnData": {}, + "computeUnitsConsumed": 0 + }, + "version": "string" + } + ], + "signatures": [ + "string" + ], + "rewards": [ + { + "pubkey": "string", + "lamports": 0, + "postBalance": 0, + "rewardType": "fee", + "commission": 0 + } + ], + "blockTime": 0, + "blockHeight": 0 + } + } + } + ], "description": "Returns identity and transaction information about a confirmed block in the ledger.", "operationId": "getBlock", "environments": [], @@ -1478,6 +1687,36 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getBlockCommitment", + "params": { + "block": 0 + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "commitment": [ + 0 + ], + "totalStake": 0 + } + } + } + ], "description": "Returns the commitment for a particular block.", "operationId": "getBlockCommitment", "environments": [], @@ -1564,6 +1803,34 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getBlockHeight", + "params": { + "Configuration": { + "commitment": "processed", + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": 0 + } + } + ], "description": "Returns the current block height of the node.", "operationId": "getBlockHeight", "environments": [], @@ -1751,6 +2018,44 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getBlockProduction", + "params": { + "Configuration": { + "commitment": "processed", + "identity": "string", + "range": { + "firstSlot": 0, + "lastSlot": 0 + } + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "byIdentity": {}, + "range": { + "firstSlot": 0, + "lastSlot": 0 + } + } + } + } + ], "description": "Returns recent block production information from the current or previous epoch.", "operationId": "getBlockProduction", "environments": [], @@ -1857,6 +2162,37 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getBlocks", + "params": { + "start_slot": 0, + "end_slot": 0, + "Configuration": { + "commitment": "processed" + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + 0 + ] + } + } + ], "description": "Returns a list of confirmed blocks between two slots.", "operationId": "getBlocks", "environments": [], @@ -1963,6 +2299,37 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getBlocksWithLimit", + "params": { + "start_slot": 0, + "limit": 0, + "Configuration": { + "commitment": "processed" + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + 0 + ] + } + } + ], "description": "Returns a list of confirmed blocks starting at the given slot.", "operationId": "getBlocksWithLimit", "environments": [], @@ -2031,6 +2398,33 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getBlockTime", + "params": { + "block": { + "block": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": 0 + } + } + ], "description": "Returns the estimated production time of a block.", "operationId": "getBlockTime", "environments": [], @@ -2195,6 +2589,39 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getClusterNodes", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + { + "pubkey": "string", + "gossip": "string", + "tpu": "string", + "rpc": "string", + "version": "string", + "featureSet": 0, + "shredVersion": 0 + } + ] + } + } + ], "description": "Returns information about all the nodes participating in the cluster.", "operationId": "getClusterNodes", "environments": [], @@ -2362,6 +2789,41 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getEpochInfo", + "params": { + "Configuration": { + "commitment": "processed", + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "absoluteSlot": 0, + "blockHeight": 0, + "epoch": 0, + "slotIndex": 0, + "slotsInEpoch": 0, + "transactionCount": 0 + } + } + } + ], "description": "Returns information about the current epoch.", "operationId": "getEpochInfo", "environments": [], @@ -2458,6 +2920,35 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getEpochSchedule", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "slotsPerEpoch": 0, + "leaderScheduleSlotOffset": 0, + "warmup": false, + "firstNormalEpoch": 0, + "firstNormalSlot": 0 + } + } + } + ], "description": "Returns the epoch schedule information from the cluster's genesis config.", "operationId": "getEpochSchedule", "environments": [], @@ -2573,6 +3064,37 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getFeeForMessage", + "params": { + "Message": { + "Message": "string" + }, + "Configuration": { + "commitment": "processed", + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": 0 + } + } + ], "description": "Get the fee the network will charge for a particular Message.", "operationId": "getFeeForMessage", "environments": [], @@ -2607,6 +3129,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getFirstAvailableBlock", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": 0 + } + } + ], "description": "Returns the slot of the lowest confirmed block that has not been purged from the ledger.", "operationId": "getFirstAvailableBlock", "environments": [], @@ -2641,6 +3186,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getGenesisHash", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": "string" + } + } + ], "description": "Returns the genesis hash.", "operationId": "getGenesisHash", "environments": [], @@ -2675,6 +3243,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getHealth", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": "string" + } + } + ], "description": "Returns the current health of the node.", "operationId": "getHealth", "environments": [], @@ -2738,6 +3329,32 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getHighestSnapshotSlot", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "full": 0, + "incremental": 0 + } + } + } + ], "description": "Returns the highest slot information that the node has snapshots for.", "operationId": "getHighestSnapshotSlot", "environments": [], @@ -2782,6 +3399,31 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getIdentity", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "identity": "string" + } + } + } + ], "description": "Returns the identity pubkey for the current node.", "operationId": "getIdentity", "environments": [], @@ -2930,6 +3572,40 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getInflationGovernor", + "params": { + "Configuration": { + "commitment": "processed", + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "initial": 0, + "terminal": 0, + "taper": 0, + "foundation": 0, + "foundationTerm": 0 + } + } + } + ], "description": "Returns the current inflation governor.", "operationId": "getInflationGovernor", "environments": [], @@ -3013,6 +3689,34 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getInflationRate", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "total": 0, + "validator": 0, + "foundation": 0, + "epoch": 0 + } + } + } + ], "description": "Returns the specific inflation values for the current epoch.", "operationId": "getInflationRate", "environments": [], @@ -3211,6 +3915,46 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getInflationReward", + "params": { + "Addresses": { + "Addresses": [ + "string" + ], + "commitment": "processed", + "epoch": 0, + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + { + "epoch": 0, + "effectiveSlot": 0, + "amount": 0, + "postBalance": 0, + "commission": 0 + } + ] + } + } + ], "description": "Returns the inflation or staking reward for a list of addresses for a specified epoch.", "operationId": "getInflationReward", "environments": [], @@ -3328,6 +4072,39 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getLargestAccounts", + "params": { + "Configuration": { + "commitment": "processed", + "filter": "circulating" + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + { + "address": "string", + "lamports": 0 + } + ] + } + } + ], "description": "Returns the 20 largest accounts, by lamport balance.", "operationId": "getLargestAccounts", "environments": [], @@ -3437,6 +4214,37 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getLatestBlockhash", + "params": { + "Configuration": { + "commitment": "processed", + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "blockhash": "string", + "lastValidBlockHeight": 0 + } + } + } + ], "description": "Returns the latest blockhash.", "operationId": "getLatestBlockhash", "environments": [], @@ -3471,6 +4279,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getMaxRetransmitSlot", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": 0 + } + } + ], "description": "Get the max slot seen from the retransmit stage.", "operationId": "getMaxRetransmitSlot", "environments": [], @@ -3505,6 +4336,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getMaxShredInsertSlot", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": 0 + } + } + ], "description": "Get the max slot seen from after shred insert.", "operationId": "getMaxShredInsertSlot", "environments": [], @@ -3601,6 +4455,36 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getMinimumBalanceForRentExemption", + "params": { + "Account data length": { + "dataLength": 0 + }, + "Configuration": { + "commitment": "processed" + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": 0 + } + } + ], "description": "Returns the minimum balance required to make an account rent exempt.", "operationId": "getMinimumBalanceForRentExemption", "environments": [], @@ -3850,6 +4734,53 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getMultipleAccounts", + "params": { + "Pubkeys": [ + "string" + ], + "Configuration": { + "commitment": "processed", + "minContextSlot": 0, + "dataSlice": { + "length": 0, + "offset": 0 + }, + "encoding": "base58" + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + { + "lamports": 0, + "owner": "string", + "data": [ + "string" + ], + "executable": false, + "rentEpoch": 0, + "size": 0 + } + ] + } + } + ], "description": "Returns the account information for a list of Pubkeys.", "operationId": "getMultipleAccounts", "environments": [], @@ -4128,6 +5059,56 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getProgramAccounts", + "params": { + "Pubkey": "string", + "Configuration": { + "commitment": "processed", + "minContextSlot": 0, + "withContext": false, + "encoding": "base58", + "dataSlice": { + "length": 0, + "offset": 0 + }, + "filters": [] + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + { + "pubkey": "string", + "account": { + "lamports": 0, + "owner": "string", + "data": [ + "string" + ], + "executable": false, + "rentEpoch": 0, + "size": 0 + } + } + ] + } + } + ], "description": "Returns all accounts owned by the provided program Pubkey.", "operationId": "getProgramAccounts", "environments": [], @@ -4254,6 +5235,39 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getRecentPerformanceSamples", + "params": { + "limit": 0 + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + { + "slot": 0, + "numTransactions": 0, + "numSlots": 0, + "samplePeriodSecs": 0, + "numNonVoteTransactions": 0 + } + ] + } + } + ], "description": "Returns a list of recent performance samples, in reverse slot order.", "operationId": "getRecentPerformanceSamples", "environments": [], @@ -4347,6 +5361,38 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getRecentPrioritizationFees", + "params": { + "Account addresses": [ + "string" + ] + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + { + "slot": 0, + "prioritizationFee": 0 + } + ] + } + } + ], "description": "Returns a list of prioritization fees from recent blocks.", "operationId": "getRecentPrioritizationFees", "environments": [], @@ -4587,6 +5633,47 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getSignaturesForAddress", + "params": { + "Account address": "string", + "Configuration": { + "commitment": "processed", + "minContextSlot": 0, + "limit": 1000, + "before": "string", + "until": "string" + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + { + "signature": "string", + "slot": 0, + "err": {}, + "memo": "string", + "blockTime": 0, + "confirmationStatus": "string" + } + ] + } + } + ], "description": "Returns signatures for confirmed transactions that include the given address.", "operationId": "getSignaturesForAddress", "environments": [], @@ -4752,6 +5839,44 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getSignatureStatuses", + "params": { + "Signatures": [ + "string" + ], + "Configuration": { + "searchTransactionHistory": false + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + { + "slot": 0, + "confirmations": 0, + "err": {}, + "confirmationStatus": "string", + "status": {} + } + ] + } + } + ], "description": "Returns the statuses of a list of transaction signatures.", "operationId": "getSignatureStatuses", "environments": [], @@ -4838,6 +5963,34 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getSlot", + "params": { + "Configuration": { + "commitment": "processed", + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": 0 + } + } + ], "description": "Returns the slot that has reached the given or default commitment level.", "operationId": "getSlot", "environments": [], @@ -4924,6 +6077,34 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getSlotLeader", + "params": { + "Configuration": { + "commitment": "processed", + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": "string" + } + } + ], "description": "Returns the current slot leader.", "operationId": "getSlotLeader", "environments": [], @@ -5001,6 +6182,34 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getSlotLeaders", + "params": { + "Start slot": 0, + "Limit": 0 + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + "string" + ] + } + } + ], "description": "Returns the slot leaders for a given slot range.", "operationId": "getSlotLeaders", "environments": [], @@ -5142,6 +6351,41 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getSupply", + "params": { + "Configuration": { + "commitment": "processed", + "excludeNonCirculatingAccountsList": false + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "total": 0, + "circulating": 0, + "nonCirculating": 0, + "nonCirculatingAccounts": [ + "string" + ] + } + } + } + ], "description": "Returns information about the current supply of lamports.", "operationId": "getSupply", "environments": [], @@ -5283,6 +6527,39 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getTokenAccountBalance", + "params": { + "Token account Pubkey": "string", + "Configuration": { + "commitment": "processed" + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "amount": "string", + "decimals": 0, + "uiAmount": 0, + "uiAmountString": "string" + } + } + } + ], "description": "Returns the token balance of an SPL Token account.", "operationId": "getTokenAccountBalance", "environments": [], @@ -5583,6 +6860,58 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getTokenAccountsByOwner", + "params": { + "Token owner Pubkey": "string", + "Token filter": { + "mint": "string", + "programId": "string" + }, + "Configuration": { + "commitment": "processed", + "minContextSlot": 0, + "dataSlice": { + "length": 0, + "offset": 0 + }, + "encoding": "base58" + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": [ + { + "pubkey": "string", + "account": { + "lamports": 0, + "owner": "string", + "data": [ + "string" + ], + "executable": false, + "rentEpoch": 0, + "size": 0 + } + } + ] + } + } + ], "description": "Returns all SPL Token accounts owned by the specified token owner.", "operationId": "getTokenAccountsByOwner", "environments": [], @@ -5724,6 +7053,39 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getTokenSupply", + "params": { + "Token Mint Pubkey": "string", + "Configuration": { + "commitment": "processed" + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "amount": "string", + "decimals": 0, + "uiAmount": 0, + "uiAmountString": "string" + } + } + } + ], "description": "Returns the total supply of an SPL Token type.", "operationId": "getTokenSupply", "environments": [], @@ -5916,6 +7278,42 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getTransaction", + "params": { + "Transaction signature": "string", + "Configuration": { + "commitment": "processed", + "maxSupportedTransactionVersion": 0, + "encoding": "json" + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "slot": 0, + "transaction": {}, + "blockTime": 0, + "meta": {}, + "version": "string" + } + } + } + ], "description": "Returns transaction details for a confirmed transaction.", "operationId": "getTransaction", "environments": [], @@ -5973,6 +7371,32 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getVersion", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "solana-core": "string", + "feature-set": 0 + } + } + } + ], "description": "Returns the current Solana version running on the node.", "operationId": "getVersion", "environments": [], @@ -6346,6 +7770,69 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "getVoteAccounts", + "params": { + "Configuration": { + "commitment": "processed", + "votePubkey": "string", + "keepUnstakedDelinquents": false, + "delinquentSlotDistance": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "current": [ + { + "votePubkey": "string", + "nodePubkey": "string", + "activatedStake": 0, + "epochVoteAccount": false, + "commission": 0, + "lastVote": 0, + "epochCredits": [ + [ + 0 + ] + ], + "rootSlot": 0 + } + ], + "delinquent": [ + { + "votePubkey": "string", + "nodePubkey": "string", + "activatedStake": 0, + "epochVoteAccount": false, + "commission": 0, + "lastVote": 0, + "epochCredits": [ + [ + 0 + ] + ], + "rootSlot": 0 + } + ] + } + } + } + ], "description": "Returns the account info and associated stake for all voting accounts in the current bank.", "operationId": "getVoteAccounts", "environments": [], @@ -6458,6 +7945,36 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "isBlockhashValid", + "params": { + "blockhash": "string", + "Configuration": { + "blockhash": "string", + "commitment": "processed", + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": false + } + } + ], "description": "Returns whether a blockhash is still valid or not.", "operationId": "isBlockhashValid", "environments": [], @@ -6492,6 +8009,29 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "minimumLedgerSlot", + "params": {} + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": 0 + } + } + ], "description": "Returns the lowest slot that the node has information about in its ledger.", "operationId": "minimumLedgerSlot", "environments": [], @@ -6591,6 +8131,35 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "requestAirdrop", + "params": { + "Pubkey": "string", + "Lamports": 0, + "Configuration": { + "commitment": "processed" + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": "string" + } + } + ], "description": "Requests an airdrop of lamports to a Pubkey.", "operationId": "requestAirdrop", "environments": [], @@ -6734,6 +8303,38 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "sendTransaction", + "params": { + "Transaction": "string", + "Configuration": { + "encoding": "base58", + "skipPreflight": false, + "preflightCommitment": "processed", + "maxRetries": 0, + "minContextSlot": 0 + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": "string" + } + } + ], "description": "Submits a signed transaction to the cluster for processing.", "operationId": "sendTransaction", "environments": [], @@ -7152,6 +8753,70 @@ } ], "errors": [], + "examples": [ + { + "name": "Example", + "path": "", + "pathParameters": {}, + "queryParameters": {}, + "headers": {}, + "requestBody": { + "type": "json", + "value": { + "id": 1, + "jsonrpc": "2.0", + "method": "simulateTransaction", + "params": { + "Transaction": "string", + "Configuration": { + "commitment": "processed", + "sigVerify": false, + "replaceRecentBlockhash": false, + "minContextSlot": 0, + "encoding": "base58", + "innerInstructions": false, + "accounts": { + "addresses": [ + "string" + ], + "encoding": "base58" + } + } + } + } + }, + "responseStatusCode": 200, + "responseBody": { + "type": "json", + "value": { + "err": "string", + "logs": [ + "string" + ], + "accounts": [ + { + "lamports": 0, + "owner": "string", + "data": [ + "string" + ], + "executable": false, + "rentEpoch": 0, + "size": 0 + } + ], + "unitsConsumed": 0, + "returnData": { + "programId": "string", + "data": [ + "string" + ] + }, + "innerInstructions": {} + } + } + } + ], "description": "Simulates sending a transaction.", "operationId": "simulateTransaction", "environments": [], From 1c203cbe6a6c6ba17d7839138fe37485731e6c01 Mon Sep 17 00:00:00 2001 From: naman agarwal Date: Tue, 14 Jan 2025 22:29:50 -0500 Subject: [PATCH 2/3] feat: Record and send audio via Chrome microphone (#1996) Co-authored-by: Rohin Bhargava --- fern/apis/fdr/definition/api/v1/read/type.yml | 1 + .../fdr/definition/api/v1/register/type.yml | 1 + .../read/resources/type/types/Base64Type.ts | 1 + .../resources/type/types/Base64Type.ts | 1 + packages/fern-docs/bundle/.gitignore | 1 + packages/fern-docs/ui/package.json | 2 + .../form/PlaygroundAudioControls.tsx | 98 ++++ .../form/PlaygroundFileUploadForm.tsx | 147 ++++-- .../form/PlaygroundMicrophoneForm.tsx | 89 ++++ .../form/PlaygroundTypeReferenceForm.tsx | 14 + .../form/PlaygroundWaveformAnimation.tsx | 23 + .../src/playground/hooks/useAudioRecorder.ts | 143 ++++++ .../read/resources/type/types/Base64Type.ts | 1 + .../resources/type/types/Base64Type.ts | 1 + ...rmDataPropertySchemaConverter.node.test.ts | 5 +- .../primitives/StringConverter.node.ts | 26 +- pnpm-lock.yaml | 441 +++++++++++------- .../read/resources/type/types/Base64Type.d.ts | 1 + .../resources/type/types/Base64Type.d.ts | 1 + 19 files changed, 776 insertions(+), 221 deletions(-) create mode 100644 packages/fern-docs/bundle/.gitignore create mode 100644 packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx create mode 100644 packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx create mode 100644 packages/fern-docs/ui/src/playground/form/PlaygroundWaveformAnimation.tsx create mode 100644 packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts diff --git a/fern/apis/fdr/definition/api/v1/read/type.yml b/fern/apis/fdr/definition/api/v1/read/type.yml index d72b0c543d..dddcc6b3b6 100644 --- a/fern/apis/fdr/definition/api/v1/read/type.yml +++ b/fern/apis/fdr/definition/api/v1/read/type.yml @@ -111,6 +111,7 @@ types: Base64Type: properties: default: optional + mimeType: optional DateType: properties: diff --git a/fern/apis/fdr/definition/api/v1/register/type.yml b/fern/apis/fdr/definition/api/v1/register/type.yml index f228c49f2b..6925ee469d 100644 --- a/fern/apis/fdr/definition/api/v1/register/type.yml +++ b/fern/apis/fdr/definition/api/v1/register/type.yml @@ -111,6 +111,7 @@ types: Base64Type: properties: default: optional + mimeType: optional DateType: properties: diff --git a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts index 4cc4ad7467..c6b46254b3 100644 --- a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts +++ b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts @@ -4,4 +4,5 @@ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } diff --git a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts index 4cc4ad7467..c6b46254b3 100644 --- a/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts +++ b/packages/fdr-sdk/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts @@ -4,4 +4,5 @@ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } diff --git a/packages/fern-docs/bundle/.gitignore b/packages/fern-docs/bundle/.gitignore new file mode 100644 index 0000000000..e985853ed8 --- /dev/null +++ b/packages/fern-docs/bundle/.gitignore @@ -0,0 +1 @@ +.vercel diff --git a/packages/fern-docs/ui/package.json b/packages/fern-docs/ui/package.json index 862df55b40..487243a592 100644 --- a/packages/fern-docs/ui/package.json +++ b/packages/fern-docs/ui/package.json @@ -92,6 +92,7 @@ "jotai-location": "^0.5.5", "jsonpath": "^1.1.1", "launchdarkly-react-client-sdk": "^3.6.0", + "lucide-react": "^0.460.0", "mdx-bundler": "^10.0.2", "mermaid": "^11.2.1", "moment": "^2.30.1", @@ -122,6 +123,7 @@ "unist-util-visit": "^5.0.0", "url-join": "5.0.0", "use-memo-one": "^1.1.3", + "webm-duration-fix": "^1.0.4", "zod": "^3.23.8" }, "devDependencies": { diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx new file mode 100644 index 0000000000..8f2b040949 --- /dev/null +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundAudioControls.tsx @@ -0,0 +1,98 @@ +import { FernButton, FernButtonGroup } from "@fern-docs/components"; +import { Download, Octagon, Play } from "lucide-react"; +import { useEffect, useRef, useState } from "react"; + +interface PlaygroundAudioControlsProps { + audioUrl: string | null; + fileName?: string; +} + +export function PlaygroundAudioControls({ + audioUrl, + fileName = "recording.webm", +}: PlaygroundAudioControlsProps) { + const [isPlaying, setIsPlaying] = useState(false); + const [currentTime, setCurrentTime] = useState(0); + const [duration, setDuration] = useState(0); + const [isLoaded, setIsLoaded] = useState(false); + const audioRef = useRef(null); + + useEffect(() => { + if (audioRef.current) { + audioRef.current.onended = () => setIsPlaying(false); + audioRef.current.onloadedmetadata = () => { + const audioDuration = audioRef.current?.duration; + if (audioDuration && !isNaN(audioDuration) && isFinite(audioDuration)) { + setDuration(Math.round(audioDuration)); + setIsLoaded(true); + } + }; + audioRef.current.ontimeupdate = () => { + const currentTime = audioRef.current?.currentTime; + if (currentTime && !isNaN(currentTime) && isFinite(currentTime)) { + setCurrentTime(Math.round(currentTime)); + } + }; + } + }, []); + + const formatTime = (seconds: number) => { + const mins = Math.floor(seconds / 60) + .toString() + .padStart(2, "0"); + const secs = (seconds % 60).toString().padStart(2, "0"); + return `${mins}:${secs}`; + }; + + const handlePlayPause = async () => { + if (!audioRef.current || !audioUrl) return; + + if (isPlaying) { + audioRef.current.pause(); + audioRef.current.currentTime = 0; + setCurrentTime(0); + } else { + await audioRef.current.play(); + } + setIsPlaying(!isPlaying); + }; + + const handleDownload = () => { + if (!audioUrl) return; + const a = document.createElement("a"); + a.href = audioUrl; + a.download = fileName; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + }; + + if (!audioUrl) return null; + + return ( +
+
+ ); +} diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx index cee8b972ea..bce5fb9f65 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundFileUploadForm.tsx @@ -1,7 +1,7 @@ import { FernButton, FernButtonGroup, FernCard } from "@fern-docs/components"; import cn from "clsx"; import { uniqBy } from "es-toolkit/array"; -import { Page, PagePlusIn, Xmark } from "iconoir-react"; +import { FilePlus, FileVolume, Mic, X } from "lucide-react"; import numeral from "numeral"; import { ChangeEvent, @@ -11,7 +11,10 @@ import { useRef, useState, } from "react"; +import { useAudioRecorder } from "../hooks/useAudioRecorder"; import { WithLabelInternal } from "../WithLabel"; +import { PlaygroundAudioControls } from "./PlaygroundAudioControls"; +import { WaveformAnimation } from "./PlaygroundWaveformAnimation"; export interface PlaygroundFileUploadFormProps { id: string; @@ -20,39 +23,63 @@ export interface PlaygroundFileUploadFormProps { isOptional?: boolean; onValueChange: (value: readonly File[] | undefined) => void; value: readonly File[] | undefined; + allowAudioRecording?: boolean; } export const PlaygroundFileUploadForm = memo( - ({ id, propertyKey, type, isOptional, onValueChange, value }) => { + ({ + id, + propertyKey, + type, + isOptional, + onValueChange, + value, + allowAudioRecording = true, + }) => { // Remove invalid files // TODO: This is a temporary workaround to remove invalid files from the value. // this should be handled in a better way useEffect(() => { if (value != null) { - const hasInvalidFiles = value.some((f) => !(f instanceof File)); + const hasInvalidFiles = value.some((f) => !isValidFile(f)); if (hasInvalidFiles) { - onValueChange(value.filter((f) => f instanceof File)); + onValueChange(value.filter(isValidFile)); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const [drag, setDrag] = useState(false); - const dragOver: DragEventHandler = (e) => { + const ref = useRef(null); + const [ + { isRecording, elapsedTime, volume, audioUrl, isSupported }, + { startRecording, stopRecording }, + ] = useAudioRecorder(({ file }) => onValueChange([file])); + + const canRecordAudio = isSupported && allowAudioRecording; + + const dragOver: DragEventHandler = (e) => { e.preventDefault(); setDrag(true); }; - const dragEnter: DragEventHandler = (e) => { + const dragEnter: DragEventHandler = (e) => { e.preventDefault(); setDrag(true); }; - const dragLeave: DragEventHandler = (e) => { + const dragLeave: DragEventHandler = (e) => { e.preventDefault(); setDrag(false); }; + const fileDrop: DragEventHandler = (e) => { + e.preventDefault(); + setDrag(false); + const files = Array.from(e.dataTransfer.files); + onValueChange(files); + }; + const handleChangeFiles = (files: FileList | null | undefined) => { const filesArray = files != null ? Array.from(files) : []; if (type === "files") { @@ -65,33 +92,22 @@ export const PlaygroundFileUploadForm = memo( } }; - const fileDrop: DragEventHandler = (e) => { - e.preventDefault(); - setDrag(false); - - const files = e.dataTransfer.files; - handleChangeFiles(files); - }; - const handleRemove = () => { onValueChange(undefined); }; - const handleChange = (e: ChangeEvent) => { + const handleFileChange = (e: ChangeEvent) => { const files = e.target.files; if (files != null) { handleChangeFiles(files); } - // NOTE: the input is not controlled, so we need to clear it manually... - // every time the user selects a file, we record the change in-state, and then clear the input - // so that the input can be used again to select the same file + // Clear input value to allow selecting same file again if (ref.current != null) { ref.current.value = ""; } }; - const ref = useRef(null); return ( ( > ( onDragLeave={dragLeave} onDrop={fileDrop} > - {value == null || value.length === 0 || value[0]?.name == null ? ( -
-
Drop files here to upload
+ {isRecording ? ( +
+
+
+
+ +
+ + {Math.floor(elapsedTime / 60) + .toString() + .padStart(2, "0")} + :{(elapsedTime % 60).toString().padStart(2, "0")} + +
+
ref.current?.click()} - text="Browse files" - rounded - variant="outlined" - intent="primary" + icon={isRecording ? : } + variant="minimal" + intent={isRecording ? "danger" : "primary"} + onClick={isRecording ? stopRecording : startRecording} />
+ ) : value == null || value.length === 0 ? ( +
+
+ {`Drop audio file${type === "files" ? "s" : ""} here to upload`} +
+
+ ref.current?.click()} + text="Browse files" + rounded + variant="outlined" + intent="primary" + /> + {canRecordAudio && ( + } + rounded + variant="outlined" + intent="primary" + /> + )} +
+
) : (
{value.map((file) => (
-
- +
+
{file.name} @@ -145,9 +197,11 @@ export const PlaygroundFileUploadForm = memo(
- - {type === "file" && ( + {audioUrl && ( + + )} + {!audioUrl && ( ref.current?.click()} @@ -155,8 +209,16 @@ export const PlaygroundFileUploadForm = memo( variant="minimal" /> )} + {canRecordAudio && ( + } + onClick={startRecording} + size="small" + variant="minimal" + /> + )} } + icon={} size="small" variant="minimal" onClick={() => { @@ -170,10 +232,11 @@ export const PlaygroundFileUploadForm = memo(
))} {type === "files" && ( + // TODO: allow multiple recordings
ref.current?.click()} - icon={} + icon={} text="Add more files" rounded variant="outlined" @@ -194,3 +257,13 @@ PlaygroundFileUploadForm.displayName = "PlaygroundFileUploadForm"; function uniqueFiles(files: File[]): readonly File[] | undefined { return uniqBy(files, (f) => `${f.webkitRelativePath}/${f.name}/${f.size}`); } + +function isValidFile(file: any): file is File { + return ( + file != null && + typeof file === "object" && + "name" in file && + "size" in file && + "type" in file + ); +} diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx new file mode 100644 index 0000000000..00244a56a6 --- /dev/null +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundMicrophoneForm.tsx @@ -0,0 +1,89 @@ +import { FernButton, FernInput, FernInputProps } from "@fern-docs/components"; +import { AnimatePresence, motion } from "framer-motion"; +import { Mic, RotateCcw } from "lucide-react"; +import { ReactElement } from "react"; +import { useAudioRecorder } from "../hooks/useAudioRecorder"; +import { PlaygroundAudioControls } from "./PlaygroundAudioControls"; +import { WaveformAnimation } from "./PlaygroundWaveformAnimation"; + +export interface PlaygroundMicrophoneFormProps extends FernInputProps { + onAudioData?: (base64Data: string) => void; +} + +export function PlaygroundMicrophoneForm({ + onAudioData, + ...props +}: PlaygroundMicrophoneFormProps): ReactElement { + const [ + { isRecording, elapsedTime, volume, audioUrl }, + { startRecording, stopRecording }, + ] = useAudioRecorder(({ base64 }) => onAudioData?.(base64)); + + return ( +
+
+ {audioUrl && !isRecording && ( + + )} +
+ + {!isRecording && ( + + + + )} + + + {isRecording && ( + +
+
+
+ +
+ + {Math.floor(elapsedTime / 60) + .toString() + .padStart(2, "0")} + :{(elapsedTime % 60).toString().padStart(2, "0")} + +
+
+
+ )} +
+
+ 0 ? ( + + ) : isRecording ? ( + + ) : ( + + ) + } + size="small" + variant="minimal" + intent={isRecording ? "danger" : "primary"} + onClick={isRecording ? stopRecording : startRecording} + disabled={props.disabled} + /> +
+
+ ); +} diff --git a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx index 89ed9fad43..5064f6ec07 100644 --- a/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx +++ b/packages/fern-docs/ui/src/playground/form/PlaygroundTypeReferenceForm.tsx @@ -20,6 +20,7 @@ import { PlaygroundElevenLabsVoiceIdForm } from "./PlaygroundElevenLabsVoiceIdFo import { PlaygroundEnumForm } from "./PlaygroundEnumForm"; import { PlaygroundListForm } from "./PlaygroundListForm"; import { PlaygroundMapForm } from "./PlaygroundMapForm"; +import { PlaygroundMicrophoneForm } from "./PlaygroundMicrophoneForm"; import { PlaygroundObjectForm } from "./PlaygroundObjectForm"; import { PlaygroundUniscriminatedUnionForm } from "./PlaygroundUniscriminatedUnionForm"; @@ -153,6 +154,19 @@ export const PlaygroundTypeReferenceForm = onValueChange={onChange} disabled={disabled} /> + ) : property?.key === "user_audio_chunk" || // TODO(naman): remove hardcoding for ElevenLabs once the backend mimeType is plumbed through + (primitive.value.type === "base64" && + primitive.value.mimeType?.includes("audio/webm") && + MediaRecorder.isTypeSupported("audio/webm")) ? ( + ) : ( + {Array.from({ length: 20 }).map((_, i) => ( + + ))} +
+ ); +} diff --git a/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts b/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts new file mode 100644 index 0000000000..f24c5503ed --- /dev/null +++ b/packages/fern-docs/ui/src/playground/hooks/useAudioRecorder.ts @@ -0,0 +1,143 @@ +import { useCallback, useEffect, useRef, useState } from "react"; +import fixWebmDuration from "webm-duration-fix"; + +interface AudioRecorderState { + isRecording: boolean; + elapsedTime: number; + volume: number; + audioUrl: string | null; + isSupported: boolean; +} + +interface AudioRecorderControls { + startRecording: () => Promise; + stopRecording: () => void; +} + +export function useAudioRecorder( + onAudioData?: (audioData: { base64: string; file: File }) => void +): [AudioRecorderState, AudioRecorderControls] { + const [isRecording, setIsRecording] = useState(false); + const [elapsedTime, setElapsedTime] = useState(0); + const [volume, setVolume] = useState(0.2); + const [mediaRecorder, setMediaRecorder] = useState( + null + ); + const analyserRef = useRef(null); + const animationFrameRef = useRef(); + const chunksRef = useRef([]); + const [audioUrl, setAudioUrl] = useState(null); + const mimeType = "audio/webm;codecs=opus"; + const [isSupported] = useState(() => MediaRecorder.isTypeSupported(mimeType)); + + const startRecording = useCallback(async () => { + try { + if (!isSupported) { + throw new Error(`${mimeType} is not supported on this browser`); + } + setElapsedTime(0); + chunksRef.current = []; + + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + const recorder = new MediaRecorder(stream, { + mimeType, + }); + + // for animation only: + const audioContext = new AudioContext(); + const source = audioContext.createMediaStreamSource(stream); + const analyser = audioContext.createAnalyser(); + analyser.fftSize = 256; + source.connect(analyser); + analyserRef.current = analyser; + const updateVolume = () => { + const dataArray = new Uint8Array(analyser.frequencyBinCount); + analyser.getByteFrequencyData(dataArray); + const average = + dataArray.reduce((acc, val) => acc + val, 0) / dataArray.length; + const normalizedVolume = Math.min(average / 20, 1); + setVolume(normalizedVolume); + animationFrameRef.current = requestAnimationFrame(updateVolume); + }; + updateVolume(); + + recorder.ondataavailable = (event) => { + chunksRef.current.push(event.data); + }; + + recorder.onstop = async () => { + const fixedBlob = await fixWebmDuration( + new Blob([...chunksRef.current], { + type: mimeType, + }) + ); + const file = new File([fixedBlob], `recording-${Date.now()}.webm`, { + type: mimeType, + }); + + const url = URL.createObjectURL(file); + setAudioUrl(url); + + const toBase64 = (file: File) => + new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve(reader.result); + reader.onerror = reject; + }); + const base64 = await toBase64(file); + + onAudioData?.({ base64: base64 as string, file }); + }; + + recorder.start(); + setMediaRecorder(recorder); + setIsRecording(true); + } catch (err) { + console.error("Error accessing microphone:", err); + } + }, [onAudioData, isSupported]); + + const stopRecording = useCallback(() => { + if (mediaRecorder) { + mediaRecorder.stop(); + mediaRecorder.stream.getTracks().forEach((track) => track.stop()); + setMediaRecorder(null); + setIsRecording(false); + if (animationFrameRef.current) { + cancelAnimationFrame(animationFrameRef.current); + } + analyserRef.current = null; + setVolume(0.2); + chunksRef.current = []; + } + }, [mediaRecorder]); + + useEffect(() => { + let interval: NodeJS.Timeout; + if (isRecording) { + interval = setInterval(() => { + setElapsedTime((prev) => prev + 1); + }, 1000); + } + return () => { + clearInterval(interval); + if (mediaRecorder) { + stopRecording(); + } + }; + }, [isRecording, mediaRecorder, stopRecording]); + + useEffect(() => { + return () => { + if (audioUrl) { + URL.revokeObjectURL(audioUrl); + } + }; + }, [audioUrl]); + + return [ + { isRecording, elapsedTime, volume, audioUrl, isSupported }, + { startRecording, stopRecording }, + ]; +} diff --git a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts index 4cc4ad7467..c6b46254b3 100644 --- a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts +++ b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.ts @@ -4,4 +4,5 @@ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } diff --git a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts index 4cc4ad7467..c6b46254b3 100644 --- a/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts +++ b/packages/parsers/src/client/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.ts @@ -4,4 +4,5 @@ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } diff --git a/packages/parsers/src/openapi/3.1/paths/__test__/request/MultipartFormDataPropertySchemaConverter.node.test.ts b/packages/parsers/src/openapi/3.1/paths/__test__/request/MultipartFormDataPropertySchemaConverter.node.test.ts index ce4afc59b1..df25f0f9e1 100644 --- a/packages/parsers/src/openapi/3.1/paths/__test__/request/MultipartFormDataPropertySchemaConverter.node.test.ts +++ b/packages/parsers/src/openapi/3.1/paths/__test__/request/MultipartFormDataPropertySchemaConverter.node.test.ts @@ -123,7 +123,10 @@ describe("MultipartFormDataPropertySchemaConverterNode", () => { const result = converter.convert(); expect(result).toEqual({ type: "alias", - value: { type: "primitive", value: { type: "base64" } }, + value: { + type: "primitive", + value: { type: "base64", mimeType: "image/jpeg" }, + }, }); }); }); diff --git a/packages/parsers/src/openapi/3.1/schemas/primitives/StringConverter.node.ts b/packages/parsers/src/openapi/3.1/schemas/primitives/StringConverter.node.ts index 020b69e47c..280936c78b 100644 --- a/packages/parsers/src/openapi/3.1/schemas/primitives/StringConverter.node.ts +++ b/packages/parsers/src/openapi/3.1/schemas/primitives/StringConverter.node.ts @@ -43,6 +43,7 @@ export class StringConverterNode extends BaseOpenApiV3_1ConverterNodeWithExample minLength: number | undefined; maxLength: number | undefined; enum: EnumConverterNode | undefined; + mimeType: string | undefined; constructor( args: BaseOpenApiV3_1ConverterNodeConstructorArgs @@ -108,6 +109,8 @@ export class StringConverterNode extends BaseOpenApiV3_1ConverterNodeWithExample this.minLength = this.input.minLength; this.maxLength = this.input.maxLength; + this.mimeType = this.input.contentMediaType; + if (this.input.default != null && typeof this.input.default !== "string") { this.context.errors.warning({ message: `Expected default value to be a string. Received ${this.input.default}`, @@ -154,14 +157,21 @@ export class StringConverterNode extends BaseOpenApiV3_1ConverterNodeWithExample type: "alias", value: { type: "primitive", - value: { - type, - format: type === "string" ? this.format : undefined, - regex: this.regex, - minLength: this.minLength, - maxLength: this.maxLength, - default: this.default, - }, + value: + type === "base64" + ? { + type, + mimeType: this.mimeType, + default: this.default, + } + : { + type, + format: type === "string" ? this.format : undefined, + regex: this.regex, + minLength: this.minLength, + maxLength: this.maxLength, + default: this.default, + }, }, }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bdef822178..4f3027c901 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,10 +68,10 @@ importers: version: 1.47.1 '@tailwindcss/forms': specifier: ^0.5.7 - version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@types/express': specifier: ^4.17.13 version: 4.17.21 @@ -131,7 +131,7 @@ importers: version: 5.1.0(eslint@9.17.0(jiti@1.21.7)) eslint-plugin-tailwindcss: specifier: ^3.17.5 - version: 3.17.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 3.17.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) eslint-plugin-vitest: specifier: ^0.5.4 version: 0.5.4(@typescript-eslint/eslint-plugin@8.18.1(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2)(vitest@2.1.4(@edge-runtime/vm@5.0.0)(@types/node@18.19.33)(jsdom@24.0.0)(less@4.2.0)(sass@1.77.0)(stylus@0.62.0)(terser@5.31.0)) @@ -197,16 +197,16 @@ importers: version: 13.1.0(postcss@8.4.31)(stylelint@16.5.0(typescript@5.7.2)) stylelint-config-tailwindcss: specifier: ^0.0.7 - version: 0.0.7(stylelint@16.5.0(typescript@5.7.2))(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.0.7(stylelint@16.5.0(typescript@5.7.2))(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) stylelint-scss: specifier: ^6.0.0 version: 6.3.0(stylelint@16.5.0(typescript@5.7.2)) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + version: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) tsx: specifier: ^4.19.2 version: 4.19.2 @@ -221,7 +221,7 @@ importers: version: 8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2) typescript-plugin-css-modules: specifier: ^5.1.0 - version: 5.1.0(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))(typescript@5.7.2) + version: 5.1.0(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))(typescript@5.7.2) vitest: specifier: ^2.1.4 version: 2.1.4(@edge-runtime/vm@5.0.0)(@types/node@18.19.33)(jsdom@24.0.0)(less@4.2.0)(sass@1.77.0)(stylus@0.62.0)(terser@5.31.0) @@ -273,7 +273,7 @@ importers: version: 3.0.3 tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.5.7)(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2) + version: 8.3.5(@swc/core@1.5.7(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2) typescript: specifier: 5.7.2 version: 5.7.2 @@ -859,10 +859,10 @@ importers: version: 14.2.9 '@tailwindcss/forms': specifier: ^0.5.7 - version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@types/node': specifier: ^18.7.18 version: 18.19.33 @@ -895,7 +895,7 @@ importers: version: 3.4.2 raw-loader: specifier: ^4.0.2 - version: 4.0.2(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + version: 4.0.2(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) sass: specifier: ^1.74.1 version: 1.77.0 @@ -904,7 +904,7 @@ importers: version: 16.5.0(typescript@5.7.2) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) typescript: specifier: 5.7.2 version: 5.7.2 @@ -1086,10 +1086,10 @@ importers: version: 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@tailwindcss/forms': specifier: ^0.5.7 - version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@testing-library/jest-dom': specifier: ^6.4.2 version: 6.5.0 @@ -1149,7 +1149,7 @@ importers: version: 16.5.0(typescript@5.7.2) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) typescript: specifier: 5.7.2 version: 5.7.2 @@ -1370,10 +1370,10 @@ importers: version: 14.2.9 '@tailwindcss/forms': specifier: ^0.5.7 - version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@types/node': specifier: ^18.7.18 version: 18.19.33 @@ -1412,7 +1412,7 @@ importers: version: 3.4.2 raw-loader: specifier: ^4.0.2 - version: 4.0.2(webpack@5.94.0(@swc/core@1.5.7)) + version: 4.0.2(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) sass: specifier: ^1.74.1 version: 1.77.0 @@ -1421,7 +1421,7 @@ importers: version: 16.5.0(typescript@5.7.2) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) typescript: specifier: 5.7.2 version: 5.7.2 @@ -1833,7 +1833,7 @@ importers: version: 8.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2)) '@storybook/nextjs': specifier: ^8.4.4 - version: 8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)) + version: 8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7(@swc/helpers@0.5.15))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) '@storybook/react': specifier: ^8.4.4 version: 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) @@ -1842,7 +1842,7 @@ importers: version: 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2))) '@types/hast': specifier: ^3.0.4 version: 3.0.4 @@ -1884,10 +1884,10 @@ importers: version: 2.2.5(react@18.3.1) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)) tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2))) typescript: specifier: 5.7.2 version: 5.7.2 @@ -2133,6 +2133,9 @@ importers: launchdarkly-react-client-sdk: specifier: ^3.6.0 version: 3.6.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + lucide-react: + specifier: ^0.460.0 + version: 0.460.0(react@18.3.1) mdx-bundler: specifier: ^10.0.2 version: 10.0.2(esbuild@0.20.2) @@ -2223,6 +2226,9 @@ importers: use-memo-one: specifier: ^1.1.3 version: 1.1.3(react@18.3.1) + webm-duration-fix: + specifier: ^1.0.4 + version: 1.0.4 zod: specifier: ^3.23.8 version: 3.23.8 @@ -2259,7 +2265,7 @@ importers: version: 8.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2)) '@storybook/nextjs': specifier: ^8.4.4 - version: 8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7)(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + version: 8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) '@storybook/react': specifier: ^8.4.4 version: 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) @@ -2268,10 +2274,10 @@ importers: version: 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@tailwindcss/forms': specifier: ^0.5.7 - version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))) + version: 0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))) '@testing-library/jest-dom': specifier: ^6.4.2 version: 6.5.0 @@ -2352,7 +2358,7 @@ importers: version: 16.5.0(typescript@5.7.2) tailwindcss: specifier: 3.4.17 - version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) ts-essentials: specifier: ^10.0.1 version: 10.0.1(typescript@5.7.2) @@ -2453,7 +2459,7 @@ importers: version: 3.4.2 tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.5.7)(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2) + version: 8.3.5(@swc/core@1.5.7(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2) typescript: specifier: 5.7.2 version: 5.7.2 @@ -2582,7 +2588,7 @@ importers: version: 9.17.0(jiti@1.21.7) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + version: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) typescript: specifier: 5.7.2 version: 5.7.2 @@ -2867,7 +2873,7 @@ importers: version: 2.1.2 ts-node: specifier: ^10.9.1 - version: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + version: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) typescript: specifier: 5.7.2 version: 5.7.2 @@ -2985,7 +2991,7 @@ importers: version: 1.52.1(esbuild@0.20.2) ts-node: specifier: ^10.4.0 - version: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + version: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) tsconfig-paths: specifier: ^3.9.0 version: 3.15.0 @@ -10194,6 +10200,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ebml-block@1.1.2: + resolution: {integrity: sha512-HgNlIsRFP6D9VKU5atCeHRJY7XkJP8bOe8yEhd8NB7B3b4++VWTyauz6g650iiPmLfPLGlVpoJmGSgMfXDYusg==} + ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} @@ -11652,6 +11661,9 @@ packages: peerDependencies: algoliasearch: '>= 3.1 < 6' + int64-buffer@1.1.0: + resolution: {integrity: sha512-94smTCQOvigN4d/2R/YDjz8YVG0Sufvv2aAh8P5m42gwhCsDAJqnbNOrxJsrADuAFAA69Q/ptGzxvNcNuIJcvw==} + internal-slot@1.0.7: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} @@ -16568,6 +16580,9 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} + webm-duration-fix@1.0.4: + resolution: {integrity: sha512-kvhmSmEnuohtK+j+mJswqCCM2ViKb9W8Ch0oAxcaeUvpok5CsMORQLnea+CYKDXPG6JH12H0CbRK85qhfeZLew==} + webpack-bundle-analyzer@4.10.1: resolution: {integrity: sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==} engines: {node: '>= 10.13.0'} @@ -20354,7 +20369,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))': + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -20368,7 +20383,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.12.12)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + jest-config: 29.7.0(@types/node@20.12.12)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -21126,7 +21141,7 @@ snapshots: dependencies: playwright: 1.47.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2))': dependencies: ansi-html-community: 0.0.8 core-js-pure: 3.37.0 @@ -21136,12 +21151,12 @@ snapshots: react-refresh: 0.14.2 schema-utils: 3.3.0 source-map: 0.7.4 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) optionalDependencies: type-fest: 4.21.0 webpack-hot-middleware: 2.26.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)))': dependencies: ansi-html-community: 0.0.8 core-js-pure: 3.37.0 @@ -21151,7 +21166,7 @@ snapshots: react-refresh: 0.14.2 schema-utils: 3.3.0 source-map: 0.7.4 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) optionalDependencies: type-fest: 4.21.0 webpack-hot-middleware: 2.26.1 @@ -23018,7 +23033,7 @@ snapshots: transitivePeerDependencies: - webpack-sources - '@storybook/builder-webpack5@8.4.4(@swc/core@1.5.7)(esbuild@0.20.2)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': + '@storybook/builder-webpack5@8.4.4(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': dependencies: '@storybook/core-webpack': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@types/node': 22.5.5 @@ -23027,23 +23042,23 @@ snapshots: case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.3.1 constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) es-module-lexer: 1.5.2 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) - html-webpack-plugin: 5.6.0(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) + html-webpack-plugin: 5.6.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) magic-string: 0.30.12 path-browserify: 1.0.1 process: 0.11.10 semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) - style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) - terser-webpack-plugin: 5.3.10(@swc/core@1.5.7)(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) + terser-webpack-plugin: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) ts-dedent: 2.2.0 url: 0.11.3 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) - webpack-dev-middleware: 6.1.3(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) + webpack-dev-middleware: 6.1.3(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -23055,7 +23070,7 @@ snapshots: - uglify-js - webpack-cli - '@storybook/builder-webpack5@8.4.4(@swc/core@1.5.7)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': + '@storybook/builder-webpack5@8.4.4(@swc/core@1.5.7(@swc/helpers@0.5.15))(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': dependencies: '@storybook/core-webpack': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@types/node': 22.5.5 @@ -23064,23 +23079,23 @@ snapshots: case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.3.1 constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7)) + css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) es-module-lexer: 1.5.2 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)) - html-webpack-plugin: 5.6.0(webpack@5.94.0(@swc/core@1.5.7)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) + html-webpack-plugin: 5.6.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) magic-string: 0.30.12 path-browserify: 1.0.1 process: 0.11.10 semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) - style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7)) - terser-webpack-plugin: 5.3.10(@swc/core@1.5.7)(webpack@5.94.0(@swc/core@1.5.7)) + style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) + terser-webpack-plugin: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) ts-dedent: 2.2.0 url: 0.11.3 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.94.0(@swc/core@1.5.7) - webpack-dev-middleware: 6.1.3(webpack@5.94.0(@swc/core@1.5.7)) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) + webpack-dev-middleware: 6.1.3(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -23176,7 +23191,7 @@ snapshots: dependencies: storybook: 8.4.4(prettier@3.4.2) - '@storybook/nextjs@8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7)(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2))': + '@storybook/nextjs@8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) @@ -23191,31 +23206,31 @@ snapshots: '@babel/preset-react': 7.25.9(@babel/core@7.26.0) '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) '@babel/runtime': 7.26.0 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) - '@storybook/builder-webpack5': 8.4.4(@swc/core@1.5.7)(esbuild@0.20.2)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) - '@storybook/preset-react-webpack': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7)(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) + '@storybook/builder-webpack5': 8.4.4(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) + '@storybook/preset-react-webpack': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) '@storybook/react': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) '@storybook/test': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@types/node': 22.5.5 '@types/semver': 7.5.8 - babel-loader: 9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) - css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + babel-loader: 9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) + css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) find-up: 5.0.0 image-size: 1.1.1 loader-utils: 3.2.1 next: '@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)' - node-polyfill-webpack-plugin: 2.0.1(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + node-polyfill-webpack-plugin: 2.0.1(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) pnp-webpack-plugin: 1.7.0(typescript@5.7.2) postcss: 8.4.31 - postcss-loader: 8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + postcss-loader: 8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-refresh: 0.14.2 resolve-url-loader: 5.0.0 - sass-loader: 13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + sass-loader: 13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) - style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) styled-jsx: 5.1.6(@babel/core@7.26.0)(react@18.3.1) ts-dedent: 2.2.0 tsconfig-paths: 4.2.0 @@ -23223,7 +23238,7 @@ snapshots: optionalDependencies: sharp: 0.33.3 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) transitivePeerDependencies: - '@rspack/core' - '@swc/core' @@ -23243,7 +23258,7 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/nextjs@8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7))': + '@storybook/nextjs@8.4.4(@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0))(@swc/core@1.5.7(@swc/helpers@0.5.15))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)(storybook@8.4.4(prettier@3.4.2))(type-fest@4.21.0)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) @@ -23258,31 +23273,31 @@ snapshots: '@babel/preset-react': 7.25.9(@babel/core@7.26.0) '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) '@babel/runtime': 7.26.0 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7)) - '@storybook/builder-webpack5': 8.4.4(@swc/core@1.5.7)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) - '@storybook/preset-react-webpack': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.13(react-refresh@0.14.2)(type-fest@4.21.0)(webpack-hot-middleware@2.26.1)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) + '@storybook/builder-webpack5': 8.4.4(@swc/core@1.5.7(@swc/helpers@0.5.15))(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) + '@storybook/preset-react-webpack': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7(@swc/helpers@0.5.15))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) '@storybook/react': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) '@storybook/test': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@types/node': 22.5.5 '@types/semver': 7.5.8 - babel-loader: 9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7)) - css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7)) + babel-loader: 9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) + css-loader: 6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) find-up: 5.0.0 image-size: 1.1.1 loader-utils: 3.2.1 next: '@fern-api/next@14.2.9-fork.2(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.0)' - node-polyfill-webpack-plugin: 2.0.1(webpack@5.94.0(@swc/core@1.5.7)) + node-polyfill-webpack-plugin: 2.0.1(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) pnp-webpack-plugin: 1.7.0(typescript@5.7.2) postcss: 8.4.31 - postcss-loader: 8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)) + postcss-loader: 8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) react-refresh: 0.14.2 resolve-url-loader: 5.0.0 - sass-loader: 13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7)) + sass-loader: 13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) - style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7)) + style-loader: 3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) styled-jsx: 5.1.6(@babel/core@7.26.0)(react@18.3.1) ts-dedent: 2.2.0 tsconfig-paths: 4.2.0 @@ -23290,7 +23305,7 @@ snapshots: optionalDependencies: sharp: 0.33.3 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) transitivePeerDependencies: - '@rspack/core' - '@swc/core' @@ -23310,11 +23325,11 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/preset-react-webpack@8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7)(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': + '@storybook/preset-react-webpack@8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': dependencies: '@storybook/core-webpack': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@storybook/react': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) '@types/node': 22.5.5 '@types/semver': 7.5.8 find-up: 5.0.0 @@ -23326,7 +23341,7 @@ snapshots: semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) tsconfig-paths: 4.2.0 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: @@ -23337,11 +23352,11 @@ snapshots: - uglify-js - webpack-cli - '@storybook/preset-react-webpack@8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': + '@storybook/preset-react-webpack@8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(@swc/core@1.5.7(@swc/helpers@0.5.15))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2)': dependencies: '@storybook/core-webpack': 8.4.4(storybook@8.4.4(prettier@3.4.2)) '@storybook/react': 8.4.4(@storybook/test@8.4.4(storybook@8.4.4(prettier@3.4.2)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.4(prettier@3.4.2))(typescript@5.7.2) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) '@types/node': 22.5.5 '@types/semver': 7.5.8 find-up: 5.0.0 @@ -23353,7 +23368,7 @@ snapshots: semver: 7.6.3 storybook: 8.4.4(prettier@3.4.2) tsconfig-paths: 4.2.0 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: @@ -23385,7 +23400,7 @@ snapshots: dependencies: storybook: 8.4.4(prettier@3.4.2) - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2))': dependencies: debug: 4.3.7 endent: 2.1.0 @@ -23395,11 +23410,11 @@ snapshots: react-docgen-typescript: 2.2.2(typescript@5.7.2) tslib: 2.8.1 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) transitivePeerDependencies: - supports-color - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)))': dependencies: debug: 4.3.7 endent: 2.1.0 @@ -23409,7 +23424,7 @@ snapshots: react-docgen-typescript: 2.2.2(typescript@5.7.2) tslib: 2.8.1 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) transitivePeerDependencies: - supports-color @@ -23509,7 +23524,7 @@ snapshots: '@swc/core-win32-x64-msvc@1.5.7': optional: true - '@swc/core@1.5.7': + '@swc/core@1.5.7(@swc/helpers@0.5.15)': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.7 @@ -23524,6 +23539,7 @@ snapshots: '@swc/core-win32-arm64-msvc': 1.5.7 '@swc/core-win32-ia32-msvc': 1.5.7 '@swc/core-win32-x64-msvc': 1.5.7 + '@swc/helpers': 0.5.15 optional: true '@swc/counter@0.1.3': {} @@ -23546,18 +23562,26 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tailwindcss/forms@0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)))': + '@tailwindcss/forms@0.5.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)))': dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) - '@tailwindcss/typography@0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)))': + '@tailwindcss/typography@0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)))': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) + + '@tailwindcss/typography@0.5.13(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)))': + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)) '@tanem/svg-injector@10.1.68': dependencies: @@ -25872,19 +25896,19 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + babel-loader@9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: '@babel/core': 7.26.0 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - babel-loader@9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7)): + babel-loader@9.1.3(@babel/core@7.26.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: '@babel/core': 7.26.0 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) babel-plugin-istanbul@6.1.1: dependencies: @@ -26649,13 +26673,13 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 - create-jest@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + create-jest@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + jest-config: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -26702,7 +26726,7 @@ snapshots: css-functions-list@3.2.2: {} - css-loader@6.11.0(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + css-loader@6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: icss-utils: 5.1.0(postcss@8.4.31) postcss: 8.4.31 @@ -26713,9 +26737,9 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.3 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - css-loader@6.11.0(webpack@5.94.0(@swc/core@1.5.7)): + css-loader@6.11.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: icss-utils: 5.1.0(postcss@8.4.31) postcss: 8.4.31 @@ -26726,7 +26750,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.3 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) css-select@4.3.0: dependencies: @@ -27363,6 +27387,8 @@ snapshots: eastasianwidth@0.2.0: {} + ebml-block@1.1.2: {} + ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 @@ -27748,7 +27774,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@1.21.7)))(eslint@9.17.0(jiti@1.21.7)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0(jiti@1.21.7)): dependencies: debug: 3.2.7 optionalDependencies: @@ -27780,7 +27806,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.17.0(jiti@1.21.7) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@1.21.7)))(eslint@9.17.0(jiti@1.21.7)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0(jiti@1.21.7)) hasown: 2.0.2 is-core-module: 2.16.0 is-glob: 4.0.3 @@ -27854,11 +27880,11 @@ snapshots: - supports-color - typescript - eslint-plugin-tailwindcss@3.17.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))): + eslint-plugin-tailwindcss@3.17.5(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))): dependencies: fast-glob: 3.3.2 postcss: 8.4.31 - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) eslint-plugin-turbo@2.3.3(eslint@9.17.0(jiti@1.21.7)): dependencies: @@ -28385,7 +28411,7 @@ snapshots: cross-spawn: 7.0.5 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: '@babel/code-frame': 7.26.2 chalk: 4.1.2 @@ -28400,9 +28426,9 @@ snapshots: semver: 7.6.3 tapable: 2.2.1 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: '@babel/code-frame': 7.26.2 chalk: 4.1.2 @@ -28417,7 +28443,7 @@ snapshots: semver: 7.6.3 tapable: 2.2.1 typescript: 5.7.2 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) form-data@2.5.1: dependencies: @@ -29116,7 +29142,7 @@ snapshots: html-void-elements@3.0.0: {} - html-webpack-plugin@5.6.0(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + html-webpack-plugin@5.6.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -29124,9 +29150,9 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - html-webpack-plugin@5.6.0(webpack@5.94.0(@swc/core@1.5.7)): + html-webpack-plugin@5.6.0(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -29134,7 +29160,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) htmlparser2@6.1.0: dependencies: @@ -29341,6 +29367,8 @@ snapshots: qs: 6.9.7 search-insights: 2.17.2 + int64-buffer@1.1.0: {} + internal-slot@1.0.7: dependencies: es-errors: 1.3.0 @@ -29759,16 +29787,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + jest-cli@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + create-jest: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + jest-config: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -29778,7 +29806,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + jest-config@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -29804,12 +29832,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 18.19.33 - ts-node: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + ts-node: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.12.12)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + jest-config@29.7.0(@types/node@20.12.12)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: '@babel/core': 7.26.0 '@jest/test-sequencer': 29.7.0 @@ -29835,7 +29863,7 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.12.12 - ts-node: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + ts-node: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -30050,7 +30078,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 20.12.12 + '@types/node': 18.19.33 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -30061,12 +30089,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + jest@29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + jest-cli: 29.7.0(@types/node@18.19.33)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -31641,7 +31669,7 @@ snapshots: node-int64@0.4.0: {} - node-polyfill-webpack-plugin@2.0.1(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + node-polyfill-webpack-plugin@2.0.1(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: assert: 2.1.0 browserify-zlib: 0.2.0 @@ -31668,9 +31696,9 @@ snapshots: url: 0.11.3 util: 0.12.5 vm-browserify: 1.1.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - node-polyfill-webpack-plugin@2.0.1(webpack@5.94.0(@swc/core@1.5.7)): + node-polyfill-webpack-plugin@2.0.1(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: assert: 2.1.0 browserify-zlib: 0.2.0 @@ -31697,7 +31725,7 @@ snapshots: url: 0.11.3 util: 0.12.5 vm-browserify: 1.1.2 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) node-releases@2.0.18: {} @@ -32231,21 +32259,29 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.31 - postcss-load-config@3.1.4(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + postcss-load-config@3.1.4(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: lilconfig: 2.1.0 yaml: 1.10.2 optionalDependencies: postcss: 8.4.31 - ts-node: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + ts-node: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) - postcss-load-config@4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + postcss-load-config@4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): dependencies: lilconfig: 3.1.3 yaml: 2.4.2 optionalDependencies: postcss: 8.4.31 - ts-node: 10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2) + ts-node: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2) + + postcss-load-config@4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)): + dependencies: + lilconfig: 3.1.3 + yaml: 2.4.2 + optionalDependencies: + postcss: 8.4.31 + ts-node: 10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2) postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(yaml@2.4.2): dependencies: @@ -32256,25 +32292,25 @@ snapshots: tsx: 4.19.2 yaml: 2.4.2 - postcss-loader@8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + postcss-loader@8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: cosmiconfig: 9.0.0(typescript@5.7.2) jiti: 1.21.0 postcss: 8.4.31 semver: 7.6.3 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) transitivePeerDependencies: - typescript - postcss-loader@8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7)): + postcss-loader@8.1.1(postcss@8.4.31)(typescript@5.7.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: cosmiconfig: 9.0.0(typescript@5.7.2) jiti: 1.21.0 postcss: 8.4.31 semver: 7.6.3 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) transitivePeerDependencies: - typescript @@ -32665,17 +32701,17 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 - raw-loader@4.0.2(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + raw-loader@4.0.2(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - raw-loader@4.0.2(webpack@5.94.0(@swc/core@1.5.7)): + raw-loader@4.0.2(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) rc@1.2.8: dependencies: @@ -33462,17 +33498,17 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + sass-loader@13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: neo-async: 2.6.2 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) optionalDependencies: sass: 1.77.0 - sass-loader@13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7)): + sass-loader@13.3.3(sass@1.77.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: neo-async: 2.6.2 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) optionalDependencies: sass: 1.77.0 @@ -34102,13 +34138,13 @@ snapshots: '@tokenizer/token': 0.3.0 peek-readable: 4.1.0 - style-loader@3.3.4(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + style-loader@3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - style-loader@3.3.4(webpack@5.94.0(@swc/core@1.5.7)): + style-loader@3.3.4(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) style-to-js@1.1.3: dependencies: @@ -34179,10 +34215,10 @@ snapshots: stylelint: 16.5.0(typescript@5.7.2) stylelint-config-recommended: 14.0.0(stylelint@16.5.0(typescript@5.7.2)) - stylelint-config-tailwindcss@0.0.7(stylelint@16.5.0(typescript@5.7.2))(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))): + stylelint-config-tailwindcss@0.0.7(stylelint@16.5.0(typescript@5.7.2))(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))): dependencies: stylelint: 16.5.0(typescript@5.7.2) - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) stylelint-scss@6.3.0(stylelint@16.5.0(typescript@5.7.2)): dependencies: @@ -34336,11 +34372,38 @@ snapshots: dependencies: '@babel/runtime': 7.26.0 - tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))): + tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2))): dependencies: - tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)) + + tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)): + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.4.31 + postcss-import: 15.1.0(postcss@8.4.31) + postcss-js: 4.0.1(postcss@8.4.31) + postcss-load-config: 4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) + postcss-nested: 6.2.0(postcss@8.4.31) + postcss-selector-parser: 6.1.2 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node - tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)): + tailwindcss@3.4.17(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -34359,7 +34422,7 @@ snapshots: postcss: 8.4.31 postcss-import: 15.1.0(postcss@8.4.31) postcss-js: 4.0.1(postcss@8.4.31) - postcss-load-config: 4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + postcss-load-config: 4.0.2(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2)) postcss-nested: 6.2.0(postcss@8.4.31) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -34406,28 +34469,28 @@ snapshots: dependencies: memoizerific: 1.11.3 - terser-webpack-plugin@5.3.10(@swc/core@1.5.7)(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + terser-webpack-plugin@5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.0 - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) optionalDependencies: - '@swc/core': 1.5.7 + '@swc/core': 1.5.7(@swc/helpers@0.5.15) esbuild: 0.20.2 - terser-webpack-plugin@5.3.10(@swc/core@1.5.7)(webpack@5.94.0(@swc/core@1.5.7)): + terser-webpack-plugin@5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.0 - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) optionalDependencies: - '@swc/core': 1.5.7 + '@swc/core': 1.5.7(@swc/helpers@0.5.15) terser@5.31.0: dependencies: @@ -34639,7 +34702,7 @@ snapshots: '@ts-morph/common': 0.20.0 code-block-writer: 12.0.0 - ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2): + ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -34647,7 +34710,7 @@ snapshots: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 18.19.33 - acorn: 8.11.3 + acorn: 8.14.0 acorn-walk: 8.3.2 arg: 4.1.3 create-require: 1.1.1 @@ -34657,7 +34720,28 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: - '@swc/core': 1.5.7 + '@swc/core': 1.5.7(@swc/helpers@0.5.15) + + ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@22.5.5)(typescript@5.7.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.5.5 + acorn: 8.14.0 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.7.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optionalDependencies: + '@swc/core': 1.5.7(@swc/helpers@0.5.15) + optional: true ts-pattern@5.0.5: {} @@ -34698,7 +34782,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.3.5(@swc/core@1.5.7)(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2): + tsup@8.3.5(@swc/core@1.5.7(@swc/helpers@0.5.15))(jiti@1.21.7)(postcss@8.4.31)(tsx@4.19.2)(typescript@5.7.2)(yaml@2.4.2): dependencies: bundle-require: 5.0.0(esbuild@0.20.2) cac: 6.7.14 @@ -34717,7 +34801,7 @@ snapshots: tinyglobby: 0.2.10 tree-kill: 1.2.2 optionalDependencies: - '@swc/core': 1.5.7 + '@swc/core': 1.5.7(@swc/helpers@0.5.15) postcss: 8.4.31 typescript: 5.7.2 transitivePeerDependencies: @@ -34875,7 +34959,7 @@ snapshots: transitivePeerDependencies: - supports-color - typescript-plugin-css-modules@5.1.0(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2))(typescript@5.7.2): + typescript-plugin-css-modules@5.1.0(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2))(typescript@5.7.2): dependencies: '@types/postcss-modules-local-by-default': 4.0.2 '@types/postcss-modules-scope': 3.0.4 @@ -34884,7 +34968,7 @@ snapshots: less: 4.2.0 lodash.camelcase: 4.3.0 postcss: 8.4.31 - postcss-load-config: 3.1.4(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7)(@types/node@18.19.33)(typescript@5.7.2)) + postcss-load-config: 3.1.4(postcss@8.4.31)(ts-node@10.9.2(@swc/core@1.5.7(@swc/helpers@0.5.15))(@types/node@18.19.33)(typescript@5.7.2)) postcss-modules-extract-imports: 3.1.0(postcss@8.4.31) postcss-modules-local-by-default: 4.0.5(postcss@8.4.31) postcss-modules-scope: 3.2.0(postcss@8.4.31) @@ -35442,6 +35526,13 @@ snapshots: webidl-conversions@7.0.0: {} + webm-duration-fix@1.0.4: + dependencies: + buffer: 6.0.3 + ebml-block: 1.1.2 + events: 3.3.0 + int64-buffer: 1.1.0 + webpack-bundle-analyzer@4.10.1: dependencies: '@discoveryjs/json-ext': 0.5.7 @@ -35461,7 +35552,7 @@ snapshots: - bufferutil - utf-8-validate - webpack-dev-middleware@6.1.3(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)): + webpack-dev-middleware@6.1.3(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)): dependencies: colorette: 2.0.20 memfs: 3.5.3 @@ -35469,9 +35560,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.2.0 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7)(esbuild@0.20.2) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2) - webpack-dev-middleware@6.1.3(webpack@5.94.0(@swc/core@1.5.7)): + webpack-dev-middleware@6.1.3(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))): dependencies: colorette: 2.0.20 memfs: 3.5.3 @@ -35479,7 +35570,7 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.2.0 optionalDependencies: - webpack: 5.94.0(@swc/core@1.5.7) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)) webpack-hot-middleware@2.26.1: dependencies: @@ -35491,7 +35582,7 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.94.0(@swc/core@1.5.7): + webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15)): dependencies: '@types/estree': 1.0.6 '@webassemblyjs/ast': 1.12.1 @@ -35513,7 +35604,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.5.7)(webpack@5.94.0(@swc/core@1.5.7)) + terser-webpack-plugin: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))) watchpack: 2.4.1 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -35521,7 +35612,7 @@ snapshots: - esbuild - uglify-js - webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2): + webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2): dependencies: '@types/estree': 1.0.6 '@webassemblyjs/ast': 1.12.1 @@ -35543,7 +35634,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.5.7)(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7)(esbuild@0.20.2)) + terser-webpack-plugin: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.15))(esbuild@0.20.2)) watchpack: 2.4.1 webpack-sources: 3.2.3 transitivePeerDependencies: diff --git a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.d.ts b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.d.ts index ca0acdc1bb..12bf81d734 100644 --- a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.d.ts +++ b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/read/resources/type/types/Base64Type.d.ts @@ -3,4 +3,5 @@ */ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } diff --git a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.d.ts b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.d.ts index ca0acdc1bb..12bf81d734 100644 --- a/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.d.ts +++ b/servers/fdr/src/api/generated/api/resources/api/resources/v1/resources/register/resources/type/types/Base64Type.d.ts @@ -3,4 +3,5 @@ */ export interface Base64Type { default: string | undefined; + mimeType: string | undefined; } From 28e61be16eb8b94d2fea0f7e3bc1464863d17283 Mon Sep 17 00:00:00 2001 From: Andrew Jiang Date: Tue, 14 Jan 2025 23:16:21 -0500 Subject: [PATCH 3/3] fix: LD context (#2014) --- .../integrations/launchdarkly/identify.ts | 20 --- .../integrations/launchdarkly/route.ts | 124 ------------------ .../bundle/src/server/withInitialProps.ts | 48 +++++-- .../src/getLaunchDarklySettings.ts | 16 ++- .../src/utils/getDocsPageProps.ts | 2 +- packages/fern-docs/ui/src/atoms/docs.ts | 2 +- packages/fern-docs/ui/src/atoms/types.ts | 8 +- packages/fern-docs/ui/src/docs/NextApp.tsx | 4 +- .../ui/src/feature-flags/Feature.tsx | 18 +++ .../src/feature-flags/FeatureFlagProvider.tsx | 35 +++++ .../feature => feature-flags}/LDFeature.tsx | 20 ++- .../feature-flags/LDFeatureFlagProvider.tsx | 114 ++++++++++++++++ .../fern-docs/ui/src/feature-flags/types.ts | 20 +++ .../ui/src/mdx/components/feature/Feature.tsx | 21 --- .../feature/FeatureFlagProvider.tsx | 32 ----- .../feature/LDFeatureFlagProvider.tsx | 46 ------- .../ui/src/mdx/components/feature/index.ts | 2 +- 17 files changed, 253 insertions(+), 279 deletions(-) delete mode 100644 packages/fern-docs/bundle/src/app/api/fern-docs/integrations/launchdarkly/identify.ts delete mode 100644 packages/fern-docs/bundle/src/app/api/fern-docs/integrations/launchdarkly/route.ts create mode 100644 packages/fern-docs/ui/src/feature-flags/Feature.tsx create mode 100644 packages/fern-docs/ui/src/feature-flags/FeatureFlagProvider.tsx rename packages/fern-docs/ui/src/{mdx/components/feature => feature-flags}/LDFeature.tsx (64%) create mode 100644 packages/fern-docs/ui/src/feature-flags/LDFeatureFlagProvider.tsx create mode 100644 packages/fern-docs/ui/src/feature-flags/types.ts delete mode 100644 packages/fern-docs/ui/src/mdx/components/feature/Feature.tsx delete mode 100644 packages/fern-docs/ui/src/mdx/components/feature/FeatureFlagProvider.tsx delete mode 100644 packages/fern-docs/ui/src/mdx/components/feature/LDFeatureFlagProvider.tsx diff --git a/packages/fern-docs/bundle/src/app/api/fern-docs/integrations/launchdarkly/identify.ts b/packages/fern-docs/bundle/src/app/api/fern-docs/integrations/launchdarkly/identify.ts deleted file mode 100644 index 201e9ae9cd..0000000000 --- a/packages/fern-docs/bundle/src/app/api/fern-docs/integrations/launchdarkly/identify.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { FernNextResponse } from "@/server/FernNextResponse"; -import { getHostEdge } from "@/server/xfernhost/edge"; -import { withDefaultProtocol } from "@fern-api/ui-core-utils"; -import { COOKIE_EMAIL } from "@fern-docs/utils"; -import { cookies } from "next/headers"; -import { NextRequest, NextResponse } from "next/server"; - -export const runtime = "edge"; - -export async function GET(req: NextRequest): Promise { - const email = req.nextUrl.searchParams.get(COOKIE_EMAIL); - - if (email) { - cookies().set({ name: COOKIE_EMAIL, value: email }); - } - - return FernNextResponse.redirect(req, { - destination: withDefaultProtocol(getHostEdge(req)), - }); -} diff --git a/packages/fern-docs/bundle/src/app/api/fern-docs/integrations/launchdarkly/route.ts b/packages/fern-docs/bundle/src/app/api/fern-docs/integrations/launchdarkly/route.ts deleted file mode 100644 index eee5a75fd9..0000000000 --- a/packages/fern-docs/bundle/src/app/api/fern-docs/integrations/launchdarkly/route.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { safeVerifyFernJWTConfig } from "@/server/auth/FernJWT"; -import { getDocsDomainEdge } from "@/server/xfernhost/edge"; -import { - LaunchDarklyEdgeConfig, - getAuthEdgeConfig, - getLaunchDarklySettings, -} from "@fern-docs/edge-config"; -import { COOKIE_EMAIL, COOKIE_FERN_TOKEN } from "@fern-docs/utils"; -import { cookies } from "next/headers"; -import { NextRequest, NextResponse, userAgent } from "next/server"; - -export const runtime = "edge"; - -interface LaunchDarklyContext { - kind: "multi"; - user: - | { anonymous: true } - | { - key: string; - email?: string; - name?: string; - }; - device: { - key: string; - [key: string]: unknown; - }; -} - -export async function GET( - req: NextRequest -): Promise> { - const domain = getDocsDomainEdge(req); - - const config = await safeGetLaunchDarklySettings(domain); - const clientSideId = config?.["client-side-id"]; - - if (clientSideId == null) { - return NextResponse.json(undefined, { status: 404 }); - } - - return NextResponse.json({ - kind: "multi" as const, - user: await getUserContext(req), - device: await getDeviceContext(req), - }); -} - -async function hashString( - input: string | undefined -): Promise { - if (!input) { - return undefined; - } - - // Encode the input string as a Uint8Array - const encoder = new TextEncoder(); - const data = encoder.encode(input); - - // Hash the data using SHA-256 - const hashBuffer = await crypto.subtle.digest("SHA-256", data); - - // Convert the hash to a hexadecimal string - const hashArray = Array.from(new Uint8Array(hashBuffer)); - const hashHex = hashArray - .map((byte) => byte.toString(16).padStart(2, "0")) - .join(""); - - return hashHex; -} - -async function getUserContext( - req: NextRequest -): Promise { - const jar = cookies(); - - const fernToken = jar.get(COOKIE_FERN_TOKEN)?.value; - const email = jar.get(COOKIE_EMAIL)?.value; - - const user = await safeVerifyFernJWTConfig( - fernToken, - await getAuthEdgeConfig(getDocsDomainEdge(req)) - ); - - if (user) { - const key = (await hashString(user.email)) ?? crypto.randomUUID(); - return { - key: `fern-docs-user-${key}`, - email: user.email, - name: user.name, - }; - } - - if (email) { - const key = (await hashString(email)) ?? crypto.randomUUID(); - return { key: `fern-docs-user-${key}`, email }; - } - - return { anonymous: true }; -} - -async function getDeviceContext( - req: NextRequest -): Promise { - const agent = userAgent(req); - - const hash = (await hashString(agent.ua)) ?? crypto.randomUUID(); - - return { - ...agent, - key: `fern-docs-device-${hash}`, - locale: req.nextUrl.locale, - }; -} - -async function safeGetLaunchDarklySettings( - domain: string -): Promise { - try { - return await getLaunchDarklySettings(domain); - } catch (e) { - console.error(e); - return undefined; - } -} diff --git a/packages/fern-docs/bundle/src/server/withInitialProps.ts b/packages/fern-docs/bundle/src/server/withInitialProps.ts index 7d113c4869..3475911fe6 100644 --- a/packages/fern-docs/bundle/src/server/withInitialProps.ts +++ b/packages/fern-docs/bundle/src/server/withInitialProps.ts @@ -24,7 +24,7 @@ import { GetServerSidePropsResult, Redirect } from "next"; import { ComponentProps } from "react"; import urlJoin from "url-join"; import { DocsLoader } from "./DocsLoader"; -import { getAuthState } from "./auth/getAuthState"; +import { AuthState, getAuthState } from "./auth/getAuthState"; import { getReturnToQueryParam } from "./auth/return-to"; import { handleLoadDocsError } from "./handleLoadDocsError"; import type { LoadWithUrlResponse } from "./loadWithUrl"; @@ -328,15 +328,19 @@ export async function withInitialProps({ const engine = edgeFlags.useMdxBundler ? "mdx-bundler" : "next-mdx-remote"; const serializeMdx = await getMdxBundler(engine); + // TODO: parallelize this with the other edge config calls: const launchDarklyConfig = await getLaunchDarklySettings(docs.baseUrl.domain); - const launchDarklyInfo = - !!launchDarklyConfig?.["client-side-id"] && - !!launchDarklyConfig?.["user-context-endpoint"] - ? { - clientSideId: launchDarklyConfig?.["client-side-id"], - userContextEndpoint: launchDarklyConfig?.["user-context-endpoint"], - } - : undefined; + const launchDarkly = launchDarklyConfig + ? { + clientSideId: launchDarklyConfig["client-side-id"], + contextEndpoint: launchDarklyConfig["context-endpoint"], + context: await withLaunchDarklyContext( + launchDarklyConfig["context-endpoint"], + authState, + found + ), + } + : undefined; const props: ComponentProps = { baseUrl: docs.baseUrl, @@ -395,8 +399,8 @@ export async function withInitialProps({ docs.definition.filesV2, found.tabs.length > 0 ), - featureFlags: { - launchDarkly: launchDarklyInfo, + featureFlagsConfig: { + launchDarkly, }, }; @@ -428,3 +432,25 @@ function withRedirect(destination: string): { redirect: Redirect } { } return { redirect: { destination, permanent: false } }; } + +async function withLaunchDarklyContext( + endpoint: string, + authState: AuthState, + node: FernNavigation.utils.Node +) { + try { + const url = new URL(endpoint); + url.searchParams.set("anonymous", String(!authState.authed)); + if (node.type === "found") { + if (node.currentVersion) { + url.searchParams.set("version", node.currentVersion.versionId); + } + } + + const context = await fetch(url).then((res) => res.json()); + + return context; + } catch { + return { kind: "user", key: "anonymous", anonymous: true }; + } +} diff --git a/packages/fern-docs/edge-config/src/getLaunchDarklySettings.ts b/packages/fern-docs/edge-config/src/getLaunchDarklySettings.ts index ad47725cbc..3e41d15bba 100644 --- a/packages/fern-docs/edge-config/src/getLaunchDarklySettings.ts +++ b/packages/fern-docs/edge-config/src/getLaunchDarklySettings.ts @@ -2,11 +2,10 @@ import { withoutStaging } from "@fern-docs/utils"; import { get } from "@vercel/edge-config"; import { z } from "zod"; -// eslint-disable-next-line @typescript-eslint/no-unused-vars const LaunchDarklyEdgeConfigSchema = z.object({ // NOTE: this is client-side visible, so we should be careful about what we expose here if we add more fields - "client-side-id": z.string().optional(), - "user-context-endpoint": z.string().optional(), + "client-side-id": z.string(), + "context-endpoint": z.string(), }); export type LaunchDarklyEdgeConfig = z.infer< @@ -16,7 +15,14 @@ export type LaunchDarklyEdgeConfig = z.infer< export async function getLaunchDarklySettings( domain: string ): Promise { - const config = + const allConfigs = await get>("launchdarkly"); - return config?.[domain] ?? config?.[withoutStaging(domain)]; + const config = allConfigs?.[domain] ?? allConfigs?.[withoutStaging(domain)]; + if (config) { + const result = LaunchDarklyEdgeConfigSchema.safeParse(config); + if (result.success) { + return result.data; + } + } + return undefined; } diff --git a/packages/fern-docs/local-preview-bundle/src/utils/getDocsPageProps.ts b/packages/fern-docs/local-preview-bundle/src/utils/getDocsPageProps.ts index 01846b9efd..60da6c96f3 100644 --- a/packages/fern-docs/local-preview-bundle/src/utils/getDocsPageProps.ts +++ b/packages/fern-docs/local-preview-bundle/src/utils/getDocsPageProps.ts @@ -244,7 +244,7 @@ export async function getDocsPageProps( docs.definition.filesV2, node.tabs.length > 0 ), - featureFlags: undefined, // TODO: match loading logic in withInitialProps ? + featureFlagsConfig: undefined, }; // if the user specifies a github navbar link, grab the repo info from it and save it as an SWR fallback diff --git a/packages/fern-docs/ui/src/atoms/docs.ts b/packages/fern-docs/ui/src/atoms/docs.ts index f003c99c02..ac080a1f00 100644 --- a/packages/fern-docs/ui/src/atoms/docs.ts +++ b/packages/fern-docs/ui/src/atoms/docs.ts @@ -73,7 +73,7 @@ export const EMPTY_DOCS_STATE: DocsProps = { user: undefined, defaultLang: "curl", stylesheet: "", - featureFlags: undefined, + featureFlagsConfig: undefined, }; export const DOCS_ATOM = atomWithReducer( diff --git a/packages/fern-docs/ui/src/atoms/types.ts b/packages/fern-docs/ui/src/atoms/types.ts index 4dc098e159..b15f9dfdd4 100644 --- a/packages/fern-docs/ui/src/atoms/types.ts +++ b/packages/fern-docs/ui/src/atoms/types.ts @@ -13,6 +13,7 @@ import { SidebarTab, VersionSwitcherInfo, } from "@fern-platform/fdr-utils"; +import type { LDContext } from "launchdarkly-react-client-sdk"; import { CustomerAnalytics } from "../analytics/types"; import { DocsContent } from "../resolver/DocsContent"; import { FernTheme } from "../themes/ThemedDocs"; @@ -53,10 +54,11 @@ export type NavbarLink = DefaultNavbarLink | GithubNavbarLink; export interface LaunchDarklyInfo { clientSideId: string; - userContextEndpoint: string; + contextEndpoint: string; + context: LDContext | undefined; } -export interface FeatureFlags { +export interface FeatureFlagsConfig { launchDarkly: LaunchDarklyInfo | undefined; } @@ -84,5 +86,5 @@ export interface DocsProps { user: FernUser | undefined; defaultLang: DocsV1Read.ProgrammingLanguage; stylesheet: string; - featureFlags: FeatureFlags | undefined; + featureFlagsConfig: FeatureFlagsConfig | undefined; } diff --git a/packages/fern-docs/ui/src/docs/NextApp.tsx b/packages/fern-docs/ui/src/docs/NextApp.tsx index 1329686b49..b149c2188e 100644 --- a/packages/fern-docs/ui/src/docs/NextApp.tsx +++ b/packages/fern-docs/ui/src/docs/NextApp.tsx @@ -10,9 +10,9 @@ import { DocsProps, HydrateAtoms, store } from "../atoms"; import { FernErrorBoundary } from "../components/FernErrorBoundary"; import { LocalPreviewContextProvider } from "../contexts/local-preview"; import "../css/globals.scss"; +import { FeatureFlagProvider } from "../feature-flags/FeatureFlagProvider"; import { NextNProgress } from "../header/NProgress"; import { useInterceptNextDataHref } from "../hooks/useInterceptNextDataHref"; -import { FeatureFlagProvider } from "../mdx/components/feature/FeatureFlagProvider"; import { ThemeScript } from "../themes/ThemeScript"; export function NextApp({ @@ -30,7 +30,7 @@ export function NextApp({ return ( - + import("./LDFeature").then((mod) => mod.LDFeature), + // however, we do need the default evaluation to be SSR'd + { ssr: true } +); + +// TODO: This becomes an indirection point where we can use different feature flag implementations +// with different providers depending on config +export const Feature = (props: FeatureProps): React.ReactNode => ( + + + +); diff --git a/packages/fern-docs/ui/src/feature-flags/FeatureFlagProvider.tsx b/packages/fern-docs/ui/src/feature-flags/FeatureFlagProvider.tsx new file mode 100644 index 0000000000..9d1b2251af --- /dev/null +++ b/packages/fern-docs/ui/src/feature-flags/FeatureFlagProvider.tsx @@ -0,0 +1,35 @@ +import dynamic from "next/dynamic"; +import { FC, ReactNode } from "react"; +import { FeatureFlagsConfig } from "../atoms"; + +const LDFeatureFlagProvider = dynamic( + () => + import("./LDFeatureFlagProvider").then((mod) => mod.LDFeatureFlagProvider), + { ssr: false } +); + +interface FeatureFlagProviderProps { + featureFlagsConfig: FeatureFlagsConfig | undefined; + children: ReactNode; +} + +export const FeatureFlagProvider: FC = ({ + featureFlagsConfig, + children, +}) => { + const launchDarklyInfo = featureFlagsConfig?.launchDarkly; + + if (!launchDarklyInfo) { + return children; + } + + return ( + + {children} + + ); +}; diff --git a/packages/fern-docs/ui/src/mdx/components/feature/LDFeature.tsx b/packages/fern-docs/ui/src/feature-flags/LDFeature.tsx similarity index 64% rename from packages/fern-docs/ui/src/mdx/components/feature/LDFeature.tsx rename to packages/fern-docs/ui/src/feature-flags/LDFeature.tsx index 5b073fb281..f2fd66c424 100644 --- a/packages/fern-docs/ui/src/mdx/components/feature/LDFeature.tsx +++ b/packages/fern-docs/ui/src/feature-flags/LDFeature.tsx @@ -1,6 +1,6 @@ import { camelCase } from "es-toolkit/string"; import { LDFlagSet, useFlags } from "launchdarkly-react-client-sdk"; -import { Feature } from "./Feature"; +import { FeatureProps } from "./types"; const ldFlagPredicate = ( flagKey: string, @@ -22,22 +22,18 @@ const ldFlagPredicate = ( }; }; -export const LDFeature: (props: Feature.Props) => React.ReactNode = ({ +export const LDFeature: (props: FeatureProps) => React.ReactNode = ({ flag, - flagDefaultValue, - match, + default: defaultValue = false, + match = true, children, }) => { const flags = useFlags(); - const flagPredicate = ldFlagPredicate(flag, flagDefaultValue); - const flagValue = flagPredicate(flags); + const flagPredicate = ldFlagPredicate(flag, defaultValue); - // If match is undefined, show content when flag evaluates to true - const neededValue = typeof match === "undefined" ? true : match; - - if (typeof flagValue !== "undefined" && flagValue === neededValue) { - return <>{children}; + if (flagPredicate(flags) === match) { + return children; } - return null; + return false; }; diff --git a/packages/fern-docs/ui/src/feature-flags/LDFeatureFlagProvider.tsx b/packages/fern-docs/ui/src/feature-flags/LDFeatureFlagProvider.tsx new file mode 100644 index 0000000000..74a9285f88 --- /dev/null +++ b/packages/fern-docs/ui/src/feature-flags/LDFeatureFlagProvider.tsx @@ -0,0 +1,114 @@ +import { useAtomValue } from "jotai"; +import { + LDContext, + LDProvider, + useLDClient, +} from "launchdarkly-react-client-sdk"; +import { FC, PropsWithChildren, ReactNode, useEffect } from "react"; +import useSWR from "swr"; +import { CURRENT_VERSION_ID_ATOM, useFernUser } from "../atoms"; + +interface Props extends PropsWithChildren { + clientSideId: string; + + /** + * The endpoint to fetch the user context from. + */ + contextEndpoint: string; + + /** + * Default anonymous user context. + * @default { kind: "user", key: "anonymous", anonymous: true } + */ + defaultContext?: LDContext; +} + +export const LDFeatureFlagProvider: FC = ({ + clientSideId, + contextEndpoint, + defaultContext, + children, +}) => { + return ( + + + {children} + + + ); +}; + +const IdentifyWrapper = ({ + children, + contextEndpoint: contextEndpointProp, + defaultContext = { + kind: "user", + key: "anonymous", + anonymous: true, + }, +}: { + children: ReactNode; + contextEndpoint: string; + defaultContext?: LDContext; +}) => { + const ldClient = useLDClient(); + const anonymous = useFernUser() == null; + const version = useAtomValue(CURRENT_VERSION_ID_ATOM); + + const endpoint = withParams(contextEndpointProp, { + anonymous, + version, + }); + + // using SWR to get refresh the LD context + const { data = { context: defaultContext, hash: null } } = useSWR<{ + context: LDContext; + hash: string | null; + }>( + endpoint, + async () => { + const res = await fetch(endpoint, { + credentials: anonymous ? undefined : "include", + }); + return { + context: (await res.json()) as LDContext, + hash: res.headers.get("x-hash"), + }; + }, + { + revalidateOnFocus: true, + revalidateOnReconnect: true, + revalidateOnMount: true, + errorRetryCount: 3, + keepPreviousData: true, + } + ); + + useEffect(() => { + void ldClient?.identify(data.context, data.hash ?? undefined); + }, [ldClient, data]); + + return children; +}; + +function withParams( + endpoint: string, + opts: { + anonymous: boolean; + version: string | undefined; + } +) { + try { + const url = new URL(endpoint); + url.searchParams.set("anonymous", opts.anonymous.toString()); + if (opts.version) { + url.searchParams.set("version", opts.version); + } + return String(url); + } catch { + return endpoint; + } +} diff --git a/packages/fern-docs/ui/src/feature-flags/types.ts b/packages/fern-docs/ui/src/feature-flags/types.ts new file mode 100644 index 0000000000..a5a5541909 --- /dev/null +++ b/packages/fern-docs/ui/src/feature-flags/types.ts @@ -0,0 +1,20 @@ +export interface FeatureProps { + /** + * The flag to check. This is typically kebab-case but depends on the feature flag provider. + */ + flag: string; + /** + * The default value to use if the flag is not set + * @default false + */ + default?: T; + /** + * The value to match against the flag + * @default true + */ + match?: T; + /** + * The content to render if the flag is set and matches the match value + */ + children: React.ReactNode; +} diff --git a/packages/fern-docs/ui/src/mdx/components/feature/Feature.tsx b/packages/fern-docs/ui/src/mdx/components/feature/Feature.tsx deleted file mode 100644 index 2302f21f3c..0000000000 --- a/packages/fern-docs/ui/src/mdx/components/feature/Feature.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import dynamic from "next/dynamic"; - -const LDFeature = dynamic( - () => import("./LDFeature").then((mod) => mod.LDFeature), - { ssr: true } -); - -export declare namespace Feature { - export interface Props { - flag: string; - flagDefaultValue?: T; - match?: T; - children: React.ReactNode; - } -} - -// TODO: This becomes an indirection point where we can use different feature flag implementations -// with different providers depending on config -export const Feature = (props: Feature.Props): React.ReactNode => ( - -); diff --git a/packages/fern-docs/ui/src/mdx/components/feature/FeatureFlagProvider.tsx b/packages/fern-docs/ui/src/mdx/components/feature/FeatureFlagProvider.tsx deleted file mode 100644 index 105cee7ed2..0000000000 --- a/packages/fern-docs/ui/src/mdx/components/feature/FeatureFlagProvider.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import dynamic from "next/dynamic"; -import { FC, ReactNode } from "react"; -import { DocsProps } from "../../.."; - -const LDFeatureFlagProvider = dynamic(() => - import("./LDFeatureFlagProvider").then((mod) => mod.LDFeatureFlagProvider) -); - -interface FeatureFlagProviderProps { - pageProps: DocsProps | undefined; - children: ReactNode; -} - -export const FeatureFlagProvider: FC = ({ - pageProps, - children, -}) => { - const launchDarklyInfo = pageProps?.featureFlags?.launchDarkly; - - if (!launchDarklyInfo) { - return <>{children}; - } - - return ( - - {children} - - ); -}; diff --git a/packages/fern-docs/ui/src/mdx/components/feature/LDFeatureFlagProvider.tsx b/packages/fern-docs/ui/src/mdx/components/feature/LDFeatureFlagProvider.tsx deleted file mode 100644 index 526fde7204..0000000000 --- a/packages/fern-docs/ui/src/mdx/components/feature/LDFeatureFlagProvider.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { LDProvider, useLDClient } from "launchdarkly-react-client-sdk"; -import { FC, ReactNode, useEffect } from "react"; - -interface Props { - clientSideId: string; - userContextEndpoint: string; - children: ReactNode; -} - -export const LDFeatureFlagProvider: FC = ({ - clientSideId, - userContextEndpoint, - children, -}) => { - return ( - - - {children} - - - ); -}; - -const IdentifyWrapper = ({ - children, - userContextEndpoint, -}: { - children: ReactNode; - userContextEndpoint: string; -}) => { - const ldClient = useLDClient(); - - useEffect(() => { - // TODO: have this context be set in page props maybe? - const getAndSetLdContext = async () => { - // TODO: switch from fetch to useApiRouteSWR - const response = await fetch(userContextEndpoint); - const data = await response.json(); - void ldClient?.identify(data); - }; - - void getAndSetLdContext(); - }, [userContextEndpoint, ldClient]); - - return <>{children}; -}; diff --git a/packages/fern-docs/ui/src/mdx/components/feature/index.ts b/packages/fern-docs/ui/src/mdx/components/feature/index.ts index 739e2fd3a1..5de3a1e301 100644 --- a/packages/fern-docs/ui/src/mdx/components/feature/index.ts +++ b/packages/fern-docs/ui/src/mdx/components/feature/index.ts @@ -1 +1 @@ -export * from "./Feature"; +export * from "../../../feature-flags/Feature";