diff --git a/.lintstagedrc.mjs b/.lintstagedrc.mjs index ce75acb01..08dfa71f3 100644 --- a/.lintstagedrc.mjs +++ b/.lintstagedrc.mjs @@ -23,7 +23,7 @@ export default { "*": (files) => { const mrlFiles = micromatch(files, [ "package.json", - "**/package.json", + // "**/package.json", "tsconfig.json", "**/tsconfig.json", ], {}); diff --git a/examples/basic/cli/src/index.ts b/examples/basic/cli/src/index.ts index b1e00f023..07ef2d523 100644 --- a/examples/basic/cli/src/index.ts +++ b/examples/basic/cli/src/index.ts @@ -51,6 +51,7 @@ export const clientCtx = createClientContext( Ontology, process.env.FOUNDRY_STACK, () => process.env.FOUNDRY_USER_TOKEN!, + `typescript-sdk/dev osdk-cli/dev`, ); async function runTests() { diff --git a/examples/basic/sdk/package.json b/examples/basic/sdk/package.json index 0a42e1580..822f8e031 100644 --- a/examples/basic/sdk/package.json +++ b/examples/basic/sdk/package.json @@ -18,7 +18,7 @@ }, "scripts": { "clean": "rm -rf lib dist types build tsconfig.tsbuildinfo", - "codegen": "rm -rf src/generatedNoCheck/* && osdk unstable typescript generate --outDir src/generatedNoCheck --ontologyPath ontology.json --beta true --packageType module", + "codegen": "rm -rf src/generatedNoCheck/* && osdk unstable typescript generate --outDir src/generatedNoCheck --ontologyPath ontology.json --beta true --packageType module --version dev", "dev:transpile": "tsup --watch", "fix-lint": "eslint . --fix && dprint fmt --config $(find-up dprint.json)", "lint": "eslint . && dprint check --config $(find-up dprint.json)", diff --git a/examples/basic/sdk/src/generatedNoCheck/OntologyMetadata.ts b/examples/basic/sdk/src/generatedNoCheck/OntologyMetadata.ts index 8f698a45e..b925e82e8 100644 --- a/examples/basic/sdk/src/generatedNoCheck/OntologyMetadata.ts +++ b/examples/basic/sdk/src/generatedNoCheck/OntologyMetadata.ts @@ -1,5 +1,5 @@ export const OntologyMetadata = { ontologyRid: 'ridHere', ontologyApiName: 'OntologyApiName', - userAgent: 'foundry-typescript-osdk/2.0.0', + userAgent: 'typescript-sdk/dev osdk-cli/dev', }; diff --git a/examples/one_dot_one/package.json b/examples/one_dot_one/package.json index e98bf1135..a5a3c5ed0 100644 --- a/examples/one_dot_one/package.json +++ b/examples/one_dot_one/package.json @@ -18,7 +18,7 @@ }, "scripts": { "clean": "rm -rf lib dist types build tsconfig.tsbuildinfo", - "codegen": "rm -rf src/generatedNoCheck/* && osdk unstable typescript generate --outDir src/generatedNoCheck --ontologyPath ontology.json", + "codegen": "rm -rf src/generatedNoCheck/* && osdk unstable typescript generate --outDir src/generatedNoCheck --ontologyPath ontology.json --version dev", "dev:transpile": "tsup --watch", "fix-lint": "eslint . --fix && dprint fmt --config $(find-up dprint.json)", "lint": "eslint . && dprint check --config $(find-up dprint.json)", diff --git a/examples/one_dot_one/src/generatedNoCheck/Ontology.ts b/examples/one_dot_one/src/generatedNoCheck/Ontology.ts index 69e552b8b..10e7c7005 100644 --- a/examples/one_dot_one/src/generatedNoCheck/Ontology.ts +++ b/examples/one_dot_one/src/generatedNoCheck/Ontology.ts @@ -15,7 +15,7 @@ export const Ontology: { metadata: { ontologyRid: 'ridHere'; ontologyApiName: 'OntologyApiName'; - userAgent: 'foundry-typescript-osdk/0.0.1'; + userAgent: 'typescript-sdk/dev osdk-cli/dev'; }; objects: { Todo: typeof Todo; @@ -34,7 +34,7 @@ export const Ontology: { metadata: { ontologyRid: 'ridHere' as const, ontologyApiName: 'OntologyApiName' as const, - userAgent: 'foundry-typescript-osdk/0.0.1' as const, + userAgent: 'typescript-sdk/dev osdk-cli/dev' as const, }, objects: { Todo, diff --git a/examples/todoapp/package.json b/examples/todoapp/package.json index 2b511af5e..03027e677 100644 --- a/examples/todoapp/package.json +++ b/examples/todoapp/package.json @@ -5,7 +5,7 @@ "license": "Apache-2.0", "scripts": { "build": "tsc && vite build", - "codegen": "rm -rf src/generatedNoCheck/* src/generatedNoCheck2/* && osdk unstable typescript generate --outDir src/generatedNoCheck --ontologyPath ontology.json && osdk unstable typescript generate --outDir src/generatedNoCheck2 --beta --ontologyPath ontology.json", + "codegen": "rm -rf src/generatedNoCheck/* src/generatedNoCheck2/* && osdk unstable typescript generate --outDir src/generatedNoCheck --ontologyPath ontology.json --version dev && osdk unstable typescript generate --outDir src/generatedNoCheck2 --beta --ontologyPath ontology.json --version dev", "dev": "vite", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview" diff --git a/examples/todoapp/src/generatedNoCheck/Ontology.ts b/examples/todoapp/src/generatedNoCheck/Ontology.ts index 844664a4c..c418a6153 100644 --- a/examples/todoapp/src/generatedNoCheck/Ontology.ts +++ b/examples/todoapp/src/generatedNoCheck/Ontology.ts @@ -11,7 +11,7 @@ export const Ontology: { metadata: { ontologyRid: 'ri.ontology.main.ontology.a35bb7f9-2c57-4199-a1cd-af461d88bd6e'; ontologyApiName: 'ontology-d097f725-ab77-46cf-83c0-e3cb9186bff1'; - userAgent: 'foundry-typescript-osdk/0.0.1'; + userAgent: 'typescript-sdk/dev osdk-cli/dev'; }; objects: { Todo: typeof Todo; @@ -25,7 +25,7 @@ export const Ontology: { metadata: { ontologyRid: 'ri.ontology.main.ontology.a35bb7f9-2c57-4199-a1cd-af461d88bd6e' as const, ontologyApiName: 'ontology-d097f725-ab77-46cf-83c0-e3cb9186bff1' as const, - userAgent: 'foundry-typescript-osdk/0.0.1' as const, + userAgent: 'typescript-sdk/dev osdk-cli/dev' as const, }, objects: { Todo, diff --git a/examples/todoapp/src/generatedNoCheck2/OntologyMetadata.ts b/examples/todoapp/src/generatedNoCheck2/OntologyMetadata.ts index ebf873add..3c8309bb1 100644 --- a/examples/todoapp/src/generatedNoCheck2/OntologyMetadata.ts +++ b/examples/todoapp/src/generatedNoCheck2/OntologyMetadata.ts @@ -1,5 +1,5 @@ export const OntologyMetadata = { ontologyRid: 'ri.ontology.main.ontology.a35bb7f9-2c57-4199-a1cd-af461d88bd6e', ontologyApiName: 'ontology-d097f725-ab77-46cf-83c0-e3cb9186bff1', - userAgent: 'foundry-typescript-osdk/2.0.0', + userAgent: 'typescript-sdk/dev osdk-cli/dev', }; diff --git a/monorepo/mytsup/tsup.mjs b/monorepo/mytsup/tsup.mjs index 63ffc493f..2eb3afd6d 100644 --- a/monorepo/mytsup/tsup.mjs +++ b/monorepo/mytsup/tsup.mjs @@ -1,3 +1,5 @@ +import { readFile } from "fs/promises"; + /** * @param {import('tsup').Options} options * @param {{cjsExtension?: ".cjs" | ".js"}} ourOptions @@ -6,6 +8,8 @@ export default async (options, ourOptions) => { const babel = (await import("esbuild-plugin-babel")).default; + const packageJson = await readFile("package.json").then(f => JSON.parse(f)); + return { entry: [ "src/index.ts", @@ -18,6 +22,9 @@ export default async (options, ourOptions) => { js: format === "cjs" ? (ourOptions?.cjsExtension ?? ".cjs") : ".mjs", }; }, + env: { + PACKAGE_VERSION: packageJson.version, + }, outDir: "build/js", clean: true, silent: true, diff --git a/packages/cli/changelog/@unreleased/pr-20.v2.yml b/packages/cli/changelog/@unreleased/pr-20.v2.yml new file mode 100644 index 000000000..8799cdc20 --- /dev/null +++ b/packages/cli/changelog/@unreleased/pr-20.v2.yml @@ -0,0 +1,5 @@ +type: fix +fix: + description: Send consistent UserAgent strings + links: + - https://github.com/palantir/osdk-ts/pull/20 diff --git a/packages/cli/src/commands/typescript/generate/TypescriptGenerateArgs.ts b/packages/cli/src/commands/typescript/generate/TypescriptGenerateArgs.ts index 07b431a2d..f4b982093 100644 --- a/packages/cli/src/commands/typescript/generate/TypescriptGenerateArgs.ts +++ b/packages/cli/src/commands/typescript/generate/TypescriptGenerateArgs.ts @@ -22,4 +22,5 @@ export interface TypescriptGenerateArgs { clientId?: string; beta?: boolean; packageType: "commonjs" | "module"; + version: string; } diff --git a/packages/cli/src/commands/typescript/generate/generate.ts b/packages/cli/src/commands/typescript/generate/generate.ts index 234f820dd..830b95d27 100644 --- a/packages/cli/src/commands/typescript/generate/generate.ts +++ b/packages/cli/src/commands/typescript/generate/generate.ts @@ -15,6 +15,7 @@ */ import type { CommandModule } from "yargs"; +import { isValidSemver } from "../../../util/isValidSemver.js"; import type { TypescriptGenerateArgs } from "./TypescriptGenerateArgs.js"; export const command: CommandModule< @@ -67,23 +68,34 @@ export const command: CommandModule< default: "commonjs", choices: ["commonjs", "module"], }, + version: { + type: "string", + description: "Version of the generated code, or 'dev'", + demandOption: true, + }, } as const, ).group( - ["ontologyPath", "outDir"], + ["ontologyPath", "outDir", "version"], "Generate from a local file", ).group( - ["stack", "clientId", "outDir", "ontologyWritePath"], + ["stack", "clientId", "outDir", "ontologyWritePath", "version"], "OR Generate from a stack", ) .check( (argv) => { - if (argv.ontologyPath || argv.stack) { - return true; - } else { + if (!argv.ontologyPath && !argv.stack) { throw new Error( "Error: Must specify either ontologyPath or stack and clientId", ); } + + if (argv.version !== "dev" && !isValidSemver(argv.version)) { + throw new Error( + "Error: Version must be 'dev' or a valid semver version", + ); + } + + return true; }, ); }, diff --git a/packages/cli/src/commands/typescript/generate/handleGenerate.mts b/packages/cli/src/commands/typescript/generate/handleGenerate.mts index 544ca10cd..66e9c6dde 100644 --- a/packages/cli/src/commands/typescript/generate/handleGenerate.mts +++ b/packages/cli/src/commands/typescript/generate/handleGenerate.mts @@ -29,6 +29,8 @@ import * as fs from "node:fs"; import invokeLoginFlow from "../../auth/login/loginFlow.js"; import type { TypescriptGenerateArgs } from "./TypescriptGenerateArgs.js"; +const USER_AGENT = `osdk-cli/${process.env.PACKAGE_VERSION}`; + export default async function handleGenerate(args: TypescriptGenerateArgs) { let success = false; if (args.ontologyPath) { @@ -70,11 +72,12 @@ async function generateFromStack(args: TypescriptGenerateArgs) { const { fetch } = createClientContext( { metadata: { - userAgent: "@osdk/cli/0.0.0 ()", + userAgent: USER_AGENT, }, }, args.stack!, () => token.access_token, + USER_AGENT, ); try { @@ -123,6 +126,7 @@ async function generateClientSdk( if (args.beta) { await generateClientSdkVersionTwoPointZero( ontology, + getUserAgent(args.version), minimalFs, args.outDir, args.packageType, @@ -130,6 +134,7 @@ async function generateClientSdk( } else { await generateClientSdkVersionOneDotOne( ontology, + getUserAgent(args.version), minimalFs, args.outDir, args.packageType, @@ -141,3 +146,13 @@ async function generateClientSdk( } return true; } + +// If the user passed us `dev` as our version, we use that for both our generated package version AND the cli version. +// This makes it so that releases don't force us to have to regenerate the code when the version strings change. +function getUserAgent(version: string) { + if (version === "dev") { + return "typescript-sdk/dev osdk-cli/dev"; + } else { + return `typescript-sdk/${version} ${USER_AGENT}`; + } +} diff --git a/packages/cli/src/readCliVersionFromPackageJson.ts b/packages/cli/src/readCliVersionFromPackageJson.ts deleted file mode 100644 index a5141d12e..000000000 --- a/packages/cli/src/readCliVersionFromPackageJson.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2023 Palantir Technologies, Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as fs from "node:fs"; -import { dirname } from "node:path"; -import { fileURLToPath } from "node:url"; - -export async function readCliVersionFromPackageJson() { - const { findUp } = await import("find-up"); - const __dirname = dirname(fileURLToPath(import.meta.url)); - const result = await findUp("package.json", { cwd: __dirname }); - if (!result) { - return "(unknown version. No package.json found)"; - } - - const packageJson = JSON.parse(await fs.promises.readFile(result, "utf-8")); - if (packageJson.version) { - return `v${packageJson.version}`; - } else { - return "(unknown version. No version in package.json found)"; - } -} diff --git a/packages/cli/src/util/isValidSemver.ts b/packages/cli/src/util/isValidSemver.ts new file mode 100644 index 000000000..be670a867 --- /dev/null +++ b/packages/cli/src/util/isValidSemver.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2023 Palantir Technologies, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string +const semver = + /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/; + +export function isValidSemver(semverString: string): boolean { + return semver.test(semverString); +} diff --git a/packages/cli/src/yargs/logVersionMiddleware.ts b/packages/cli/src/yargs/logVersionMiddleware.ts index 59c61016f..bf7c27cbb 100644 --- a/packages/cli/src/yargs/logVersionMiddleware.ts +++ b/packages/cli/src/yargs/logVersionMiddleware.ts @@ -15,7 +15,6 @@ */ import type { CliCommonArgs } from "../CliCommonArgs.js"; -import { readCliVersionFromPackageJson } from "../readCliVersionFromPackageJson.js"; let firstTime = true; export async function logVersionMiddleware(args: CliCommonArgs) { @@ -25,7 +24,7 @@ export async function logVersionMiddleware(args: CliCommonArgs) { const consola = Consola.consola; consola.info( - `Palantir OSDK CLI ${await readCliVersionFromPackageJson()}`, + `Palantir OSDK CLI ${process.env.PACKAGE_VERSION}`, ); consola.level = 3 + args.verbose; // so 1 -v is debug logs and -vv is trace diff --git a/packages/client/changelog/@unreleased/pr-20.v2.yml b/packages/client/changelog/@unreleased/pr-20.v2.yml new file mode 100644 index 000000000..8799cdc20 --- /dev/null +++ b/packages/client/changelog/@unreleased/pr-20.v2.yml @@ -0,0 +1,5 @@ +type: fix +fix: + description: Send consistent UserAgent strings + links: + - https://github.com/palantir/osdk-ts/pull/20 diff --git a/packages/client/generateMockOntology.js b/packages/client/generateMockOntology.js index 049b8f60d..ea93bdb93 100644 --- a/packages/client/generateMockOntology.js +++ b/packages/client/generateMockOntology.js @@ -45,6 +45,7 @@ delete ontologyWithoutUnsupportedAction.actionTypes["unsupported-action"]; await generateClientSdkVersionTwoPointZero( ontologyWithoutUnsupportedAction, + "typescript-sdk/dev osdk-cli/dev", { writeFile: (path, contents) => { return writeFile(path, contents, "utf-8"); diff --git a/packages/client/src/createClient.test.ts b/packages/client/src/createClient.test.ts new file mode 100644 index 000000000..eb6863127 --- /dev/null +++ b/packages/client/src/createClient.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2023 Palantir Technologies, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { mockFetchResponse, MockOntology } from "@osdk/shared.test"; +import type { MockedFunction } from "vitest"; +import { describe, expect, it, vi } from "vitest"; +import { createClient } from "./createClient.js"; +import { USER_AGENT } from "./util/UserAgent.js"; + +describe(createClient, () => { + it("Passes the expected userAgent string", async () => { + const fetchFunction: MockedFunction = vi.fn(); + + const client = createClient( + MockOntology, + "https://mock.com", + () => "Token", + fetchFunction, + ); + + mockFetchResponse(fetchFunction, { data: [] }); + + await client.objects.Task.fetchPageOrThrow(); + expect(fetchFunction).toHaveBeenCalledTimes(1); + + const userAgent = (fetchFunction.mock.calls[0][1]?.headers as Headers).get( + "Fetch-User-Agent", + ); + const parts = userAgent?.split(" ") ?? []; + const [packageUA, generatorUA] = MockOntology.metadata.userAgent + .split(" "); + expect(parts).toHaveLength(3); + expect(parts[0]).toEqual(packageUA); + expect(parts[1]).toEqual(generatorUA); + expect(parts[2]).toEqual(USER_AGENT); // the client USER_AGENT has an undefined version during vitest runs + }); +}); diff --git a/packages/client/src/createClient.ts b/packages/client/src/createClient.ts index 21ff59181..503e06f87 100644 --- a/packages/client/src/createClient.ts +++ b/packages/client/src/createClient.ts @@ -21,6 +21,7 @@ import type { Client } from "./Client.js"; import { createObjectSet } from "./objectSet/createObjectSet.js"; import type { ObjectSetFactory } from "./objectSet/ObjectSet.js"; import { createObjectSetCreator } from "./ObjectSetCreator.js"; +import { USER_AGENT } from "./util/UserAgent.js"; export function createClient>( ontology: O, @@ -32,7 +33,7 @@ export function createClient>( ontology, stack, tokenProvider, - "@osdk/client/0.0.0 ()", + USER_AGENT, fetchFn, ); diff --git a/packages/client/src/object/aggregateOrThrow.test.ts b/packages/client/src/object/aggregateOrThrow.test.ts index 65cac44a7..d7e77d070 100644 --- a/packages/client/src/object/aggregateOrThrow.test.ts +++ b/packages/client/src/object/aggregateOrThrow.test.ts @@ -21,6 +21,7 @@ import type { TypeOf } from "ts-expect"; import { expectType } from "ts-expect"; import { describe, it, type Mock, vi } from "vitest"; import type { AggregateOpts } from "../query/aggregations/AggregateOpts.js"; +import { USER_AGENT } from "../util/UserAgent.js"; import { aggregateOrThrow } from "./aggregateOrThrow.js"; const mockOntology = { @@ -98,7 +99,7 @@ describe("aggregateOrThrow", () => { mockOntology as MockOntology, "host.com", () => "", - undefined, + USER_AGENT, mockFetch, ); diff --git a/packages/client/src/util/UserAgent.ts b/packages/client/src/util/UserAgent.ts new file mode 100644 index 000000000..1dad9691f --- /dev/null +++ b/packages/client/src/util/UserAgent.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2023 Palantir Technologies, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const USER_AGENT = `osdk-client/${process.env.PACKAGE_VERSION}`; diff --git a/packages/foundry-sdk-generator/changelog/@unreleased/pr-20.v2.yml b/packages/foundry-sdk-generator/changelog/@unreleased/pr-20.v2.yml new file mode 100644 index 000000000..8799cdc20 --- /dev/null +++ b/packages/foundry-sdk-generator/changelog/@unreleased/pr-20.v2.yml @@ -0,0 +1,5 @@ +type: fix +fix: + description: Send consistent UserAgent strings + links: + - https://github.com/palantir/osdk-ts/pull/20 diff --git a/packages/foundry-sdk-generator/package.json b/packages/foundry-sdk-generator/package.json index a8beba9ea..889f59bc7 100644 --- a/packages/foundry-sdk-generator/package.json +++ b/packages/foundry-sdk-generator/package.json @@ -43,6 +43,7 @@ }, "devDependencies": { "@osdk/shared.test": "workspace:*", + "@types/node": "^18.0.0", "@types/yargs": "^17.0.29", "typescript": "^5.2.2" }, diff --git a/packages/foundry-sdk-generator/src/generate/betaClient/generatePackage.ts b/packages/foundry-sdk-generator/src/generate/betaClient/generatePackage.ts index 19e66c195..325cf4c4c 100644 --- a/packages/foundry-sdk-generator/src/generate/betaClient/generatePackage.ts +++ b/packages/foundry-sdk-generator/src/generate/betaClient/generatePackage.ts @@ -18,6 +18,7 @@ import type { WireOntologyDefinition } from "@osdk/generator"; import { generateClientSdkVersionOneDotOne } from "@osdk/generator"; import { mkdir, readdir, readFile, writeFile } from "fs/promises"; import { isAbsolute, join, normalize } from "path"; +import { USER_AGENT } from "../../utils/UserAgent"; import { generateBundles } from "../generateBundles"; import { bundleDependencies } from "./bundleDependencies"; import { compileInMemory } from "./compileInMemory"; @@ -50,6 +51,7 @@ export async function generatePackage( const inMemoryFileSystem: { [fileName: string]: string } = {}; await generateClientSdkVersionOneDotOne( ontology, + `typescript-sdk/${options.packageVersion} ${USER_AGENT}`, { writeFile: async (path, contents) => { inMemoryFileSystem[normalize(path)] = contents; diff --git a/packages/foundry-sdk-generator/src/utils/UserAgent.ts b/packages/foundry-sdk-generator/src/utils/UserAgent.ts new file mode 100644 index 000000000..cd230714a --- /dev/null +++ b/packages/foundry-sdk-generator/src/utils/UserAgent.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2023 Palantir Technologies, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const USER_AGENT = + `typescript-sdk-generator/${process.env.PACKAGE_VERSION}`; diff --git a/packages/generator/changelog/@unreleased/pr-20.v2.yml b/packages/generator/changelog/@unreleased/pr-20.v2.yml new file mode 100644 index 000000000..8799cdc20 --- /dev/null +++ b/packages/generator/changelog/@unreleased/pr-20.v2.yml @@ -0,0 +1,5 @@ +type: fix +fix: + description: Send consistent UserAgent strings + links: + - https://github.com/palantir/osdk-ts/pull/20 diff --git a/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.test.ts b/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.test.ts index fbf56409a..38c9d0c34 100644 --- a/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.test.ts +++ b/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.test.ts @@ -28,6 +28,7 @@ describe("generator", () => { await generateClientSdkVersionOneDotOne( TodoWireOntology, + "typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0", helper.minimalFiles, BASE_PATH, ); @@ -66,6 +67,7 @@ describe("generator", () => { expect(async () => { await expect(generateClientSdkVersionOneDotOne( TodoWireOntology, + "typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0", helper.minimalFiles, BASE_PATH, )).rejects.toThrow(); @@ -83,6 +85,7 @@ describe("generator", () => { await generateClientSdkVersionOneDotOne( TodoWireOntology, + "typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0", helper.minimalFiles, BASE_PATH, ); @@ -98,6 +101,7 @@ describe("generator", () => { await mkdir(`${__dirname}/generated`, { recursive: true }); await generateClientSdkVersionOneDotOne( TodoWireOntology, + "typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0", { writeFile: async (path, contents) => { await writeFile(path, contents, { flag: "w" }); diff --git a/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts b/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts index 3d9ffbbf1..b2b652664 100644 --- a/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts +++ b/packages/generator/src/v1.1/generateClientSdkVersionOneDotOne.ts @@ -34,6 +34,7 @@ import { generateQueries } from "./generateQueries"; export async function generateClientSdkVersionOneDotOne( ontology: WireOntologyDefinition, + userAgent: string, fs: MinimalFs, outDir: string, packageType: "commonjs" | "module" = "commonjs", @@ -47,7 +48,13 @@ export async function generateClientSdkVersionOneDotOne( const sanitizedOntology = sanitizeMetadata(ontology); await generateFoundryClientFile(fs, outDir, importExt); - await generateMetadataFile(sanitizedOntology, fs, outDir, importExt); + await generateMetadataFile( + sanitizedOntology, + userAgent, + fs, + outDir, + importExt, + ); await generateOntologyIndexFile( fs, path.join(outDir, "ontology"), diff --git a/packages/generator/src/v1.1/generateMetadataFile.test.ts b/packages/generator/src/v1.1/generateMetadataFile.test.ts index 5b05283e1..e338ad00f 100644 --- a/packages/generator/src/v1.1/generateMetadataFile.test.ts +++ b/packages/generator/src/v1.1/generateMetadataFile.test.ts @@ -26,6 +26,7 @@ describe(generateMetadataFile, () => { await generateMetadataFile( TodoWireOntology, + "typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0", helper.minimalFiles, BASE_PATH, ); @@ -49,7 +50,7 @@ describe(generateMetadataFile, () => { metadata: { ontologyRid: 'ridHere'; ontologyApiName: 'OntologyApiName'; - userAgent: 'foundry-typescript-osdk/0.0.1'; + userAgent: 'typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0'; }; objects: { Todo: typeof Todo; @@ -65,7 +66,7 @@ describe(generateMetadataFile, () => { metadata: { ontologyRid: 'ridHere' as const, ontologyApiName: 'OntologyApiName' as const, - userAgent: 'foundry-typescript-osdk/0.0.1' as const, + userAgent: 'typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0' as const, }, objects: { Todo, @@ -151,6 +152,7 @@ describe(generateMetadataFile, () => { interfaceTypes: {}, sharedPropertyTypes: {}, }, + "typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0", helper.minimalFiles, BASE_PATH, ); @@ -175,7 +177,7 @@ describe(generateMetadataFile, () => { metadata: { ontologyRid: 'rid'; ontologyApiName: 'apiName'; - userAgent: 'foundry-typescript-osdk/0.0.1'; + userAgent: 'typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0'; }; objects: { foo: typeof foo; @@ -192,7 +194,7 @@ describe(generateMetadataFile, () => { metadata: { ontologyRid: 'rid' as const, ontologyApiName: 'apiName' as const, - userAgent: 'foundry-typescript-osdk/0.0.1' as const, + userAgent: 'typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0' as const, }, objects: { foo, @@ -234,6 +236,7 @@ describe(generateMetadataFile, () => { interfaceTypes: {}, sharedPropertyTypes: {}, }, + "typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0", helper.minimalFiles, BASE_PATH, ); @@ -253,7 +256,7 @@ describe(generateMetadataFile, () => { metadata: { ontologyRid: 'rid'; ontologyApiName: 'apiName'; - userAgent: 'foundry-typescript-osdk/0.0.1'; + userAgent: 'typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0'; }; objects: {}; actions: {}; @@ -262,7 +265,7 @@ describe(generateMetadataFile, () => { metadata: { ontologyRid: 'rid' as const, ontologyApiName: 'apiName' as const, - userAgent: 'foundry-typescript-osdk/0.0.1' as const, + userAgent: 'typescript-sdk/0.0.0 typescript-sdk-generator/0.0.0' as const, }, objects: {}, actions: {}, diff --git a/packages/generator/src/v1.1/generateMetadataFile.ts b/packages/generator/src/v1.1/generateMetadataFile.ts index b4c471f09..89ab8eb08 100644 --- a/packages/generator/src/v1.1/generateMetadataFile.ts +++ b/packages/generator/src/v1.1/generateMetadataFile.ts @@ -23,6 +23,7 @@ import type { WireOntologyDefinition } from "../WireOntologyDefinition"; export async function generateMetadataFile( ontology: WireOntologyDefinition, + userAgent: string, fs: MinimalFs, outDir: string, importExt: string = "", @@ -97,7 +98,7 @@ export async function generateMetadataFile( metadata: { ontologyRid: "${ontology.ontology.rid}", ontologyApiName: "${ontology.ontology.apiName}", - userAgent: "foundry-typescript-osdk/0.0.1", + userAgent: "${userAgent}", }, objects: { ${commaSeparatedTypeIdentifiers(objectNames)} @@ -112,7 +113,7 @@ export async function generateMetadataFile( metadata: { ontologyRid: "${ontology.ontology.rid}" as const, ontologyApiName: "${ontology.ontology.apiName}" as const, - userAgent: "foundry-typescript-osdk/0.0.1" as const, + userAgent: "${userAgent}" as const, }, objects: { ${commaSeparatedIdentifiers(objectNames)} diff --git a/packages/generator/src/v2.0/generateClientSdkVersionTwoPointZero.test.ts b/packages/generator/src/v2.0/generateClientSdkVersionTwoPointZero.test.ts index ee6005903..c3f09fe4a 100644 --- a/packages/generator/src/v2.0/generateClientSdkVersionTwoPointZero.test.ts +++ b/packages/generator/src/v2.0/generateClientSdkVersionTwoPointZero.test.ts @@ -28,6 +28,7 @@ describe("generator", () => { await generateClientSdkVersionTwoPointZero( TodoWireOntology, + "typescript-sdk/0.0.0 osdk-cli/0.0.0", helper.minimalFiles, BASE_PATH, ); @@ -63,6 +64,7 @@ describe("generator", () => { expect(async () => { await expect(generateClientSdkVersionTwoPointZero( TodoWireOntology, + "typescript-sdk/0.0.0 osdk-cli/0.0.0", helper.minimalFiles, BASE_PATH, )).rejects.toThrow(); @@ -77,6 +79,7 @@ describe("generator", () => { await mkdir(`${__dirname}/generated`, { recursive: true }); await generateClientSdkVersionTwoPointZero( TodoWireOntology, + "typescript-sdk/0.0.0 osdk-cli/0.0.0", { writeFile: async (path, contents) => { await writeFile(path, contents, { flag: "w" }); diff --git a/packages/generator/src/v2.0/generateClientSdkVersionTwoPointZero.ts b/packages/generator/src/v2.0/generateClientSdkVersionTwoPointZero.ts index 7d854705d..1e83416d2 100644 --- a/packages/generator/src/v2.0/generateClientSdkVersionTwoPointZero.ts +++ b/packages/generator/src/v2.0/generateClientSdkVersionTwoPointZero.ts @@ -27,6 +27,7 @@ import { generateOntologyMetadataFile } from "./generateMetadata"; export async function generateClientSdkVersionTwoPointZero( ontology: WireOntologyDefinition, + userAgent: string, fs: MinimalFs, outDir: string, packageType: "module" | "commonjs" = "commonjs", @@ -54,7 +55,7 @@ export async function generateClientSdkVersionTwoPointZero( ), ); - await generateOntologyMetadataFile(sanitizedOntology, fs, outDir); + await generateOntologyMetadataFile(sanitizedOntology, userAgent, fs, outDir); await fs.writeFile( path.join(outDir, "Ontology.ts"), diff --git a/packages/generator/src/v2.0/generateMetadata.ts b/packages/generator/src/v2.0/generateMetadata.ts index 3789acf5a..c41d8a38d 100644 --- a/packages/generator/src/v2.0/generateMetadata.ts +++ b/packages/generator/src/v2.0/generateMetadata.ts @@ -21,6 +21,7 @@ import type { WireOntologyDefinition } from "../WireOntologyDefinition"; export async function generateOntologyMetadataFile( ontology: WireOntologyDefinition, + userAgent: string, fs: MinimalFs, outDir: string, ) { @@ -31,7 +32,7 @@ export async function generateOntologyMetadataFile( export const OntologyMetadata = { ontologyRid: "${ontology.ontology.rid}", ontologyApiName: "${ontology.ontology.apiName}", - userAgent: "foundry-typescript-osdk/2.0.0", + userAgent: "${userAgent}", } `, ), diff --git a/packages/legacy-client/changelog/@unreleased/pr-20.v2.yml b/packages/legacy-client/changelog/@unreleased/pr-20.v2.yml new file mode 100644 index 000000000..8799cdc20 --- /dev/null +++ b/packages/legacy-client/changelog/@unreleased/pr-20.v2.yml @@ -0,0 +1,5 @@ +type: fix +fix: + description: Send consistent UserAgent strings + links: + - https://github.com/palantir/osdk-ts/pull/20 diff --git a/packages/legacy-client/src/USER_AGENT.ts b/packages/legacy-client/src/USER_AGENT.ts index 364ffb715..214b2fb2b 100644 --- a/packages/legacy-client/src/USER_AGENT.ts +++ b/packages/legacy-client/src/USER_AGENT.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export const USER_AGENT = "@osdk/legacy-client/0.0.0 ()"; +export const USER_AGENT = `osdk-legacy-client/${process.env.PACKAGE_VERSION}`; diff --git a/packages/legacy-client/src/client/actions/actions.test.ts b/packages/legacy-client/src/client/actions/actions.test.ts index b0f97aff6..d73b89fc8 100644 --- a/packages/legacy-client/src/client/actions/actions.test.ts +++ b/packages/legacy-client/src/client/actions/actions.test.ts @@ -41,6 +41,7 @@ import { type Result, ReturnEditsMode, } from "../.."; +import { USER_AGENT } from "../../USER_AGENT"; import { expectFetchToBeCalledWithBody, expectFetchToBeCalledWithGet, @@ -64,7 +65,7 @@ describe("Actions", () => { MockOntology, MOCK_ORIGIN, () => "Token", - undefined, + USER_AGENT, fetch, ); actions = createActionProxy(client); diff --git a/packages/legacy-client/src/client/foundryClient.test.ts b/packages/legacy-client/src/client/foundryClient.test.ts new file mode 100644 index 000000000..f454c598b --- /dev/null +++ b/packages/legacy-client/src/client/foundryClient.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright 2023 Palantir Technologies, Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { mockFetchResponse, MockOntology } from "@osdk/shared.test"; +import type { MockedFunction } from "vitest"; +import { describe, expect, it, vi } from "vitest"; +import { UserTokenAuth } from ".."; +import { USER_AGENT } from "../USER_AGENT"; +import { BaseFoundryClient } from "./foundryClient"; + +describe(BaseFoundryClient, () => { + it("Passes the expected userAgent string", async () => { + const fetchFunction: MockedFunction = vi.fn(); + + const client = new BaseFoundryClient({ + auth: new UserTokenAuth({ userToken: "Token" }), + url: "https://mock.com", + fetchFunction, + }, MockOntology); + + mockFetchResponse(fetchFunction, {}); + + await client.ontology.objects.Task.all(); + expect(fetchFunction).toHaveBeenCalledTimes(1); + + const userAgent = (fetchFunction.mock.calls[0][1]?.headers as Headers).get( + "Fetch-User-Agent", + ); + const parts = userAgent?.split(" ") ?? []; + const [packageUA, generatorUA] = MockOntology.metadata.userAgent + .split(" "); + expect(parts).toHaveLength(3); + expect(parts[0]).toEqual(packageUA); + expect(parts[1]).toEqual(generatorUA); + expect(parts[2]).toEqual(USER_AGENT); // the legacy-client USER_AGENT has an undefined version during vitest runs + }); +}); diff --git a/packages/legacy-client/src/client/net/getAttachment.test.ts b/packages/legacy-client/src/client/net/getAttachment.test.ts index db88bea3d..daaa0f7f8 100644 --- a/packages/legacy-client/src/client/net/getAttachment.test.ts +++ b/packages/legacy-client/src/client/net/getAttachment.test.ts @@ -23,6 +23,7 @@ import { } from "@osdk/shared.test"; import type { MockedFunction } from "vitest"; import { beforeEach, describe, expect, it, vi } from "vitest"; +import { USER_AGENT } from "../../USER_AGENT"; import { expectFetchToBeCalledWithGet } from "../../util/test/expectUtils"; import { unwrapResultOrThrow } from "../../util/test/resultUtils"; import { getAttachment } from "./getAttachment"; @@ -36,7 +37,7 @@ describe(getAttachment, () => { MockOntology, MOCK_ORIGIN, () => "Token", - undefined, + USER_AGENT, fetch, ); }); diff --git a/packages/legacy-client/src/client/net/getFirstPoint.test.ts b/packages/legacy-client/src/client/net/getFirstPoint.test.ts index 5e12e97e2..6886162bd 100644 --- a/packages/legacy-client/src/client/net/getFirstPoint.test.ts +++ b/packages/legacy-client/src/client/net/getFirstPoint.test.ts @@ -24,6 +24,7 @@ import { } from "@osdk/shared.test"; import type { MockedFunction } from "vitest"; import { beforeEach, describe, expect, it, vi } from "vitest"; +import { USER_AGENT } from "../../USER_AGENT"; import { expectFetchToBeCalledWithGet } from "../../util/test/expectUtils"; import { unwrapResultOrThrow } from "../../util/test/resultUtils"; import { Timestamp } from "../baseTypes"; @@ -35,7 +36,7 @@ describe(getFirstPoint, () => { MockOntology, MOCK_ORIGIN, () => "Token", - undefined, + USER_AGENT, fetch, ); beforeEach(() => { diff --git a/packages/legacy-client/src/client/net/getLastPoint.test.ts b/packages/legacy-client/src/client/net/getLastPoint.test.ts index e9f2da6c7..f0ce5b760 100644 --- a/packages/legacy-client/src/client/net/getLastPoint.test.ts +++ b/packages/legacy-client/src/client/net/getLastPoint.test.ts @@ -24,6 +24,7 @@ import { } from "@osdk/shared.test"; import type { MockedFunction } from "vitest"; import { beforeEach, describe, expect, it, vi } from "vitest"; +import { USER_AGENT } from "../../USER_AGENT"; import { expectFetchToBeCalledWithGet } from "../../util/test/expectUtils"; import { unwrapResultOrThrow } from "../../util/test/resultUtils"; import { Timestamp } from "../baseTypes"; @@ -35,7 +36,7 @@ describe(getLastPoint, () => { MockOntology, MOCK_ORIGIN, () => "Token", - undefined, + USER_AGENT, fetch, ); beforeEach(() => { diff --git a/packages/legacy-client/src/client/net/uploadAttachment.test.ts b/packages/legacy-client/src/client/net/uploadAttachment.test.ts index 829fbc9b4..a57f0217b 100644 --- a/packages/legacy-client/src/client/net/uploadAttachment.test.ts +++ b/packages/legacy-client/src/client/net/uploadAttachment.test.ts @@ -23,6 +23,7 @@ import { } from "@osdk/shared.test"; import type { MockedFunction } from "vitest"; import { beforeEach, describe, expect, it, vi } from "vitest"; +import { USER_AGENT } from "../../USER_AGENT"; import { expectFetchToBeCalledWithBlob } from "../../util/test/expectUtils"; import { unwrapResultOrThrow } from "../../util/test/resultUtils"; import { uploadAttachment } from "./uploadAttachment"; @@ -36,7 +37,7 @@ describe(uploadAttachment, () => { MockOntology, MOCK_ORIGIN, () => "Token", - undefined, + USER_AGENT, fetch, ); }); diff --git a/packages/legacy-client/src/client/objectSets/OsdkObjectSet.test.ts b/packages/legacy-client/src/client/objectSets/OsdkObjectSet.test.ts index 1f15a94c2..ad26a9e34 100644 --- a/packages/legacy-client/src/client/objectSets/OsdkObjectSet.test.ts +++ b/packages/legacy-client/src/client/objectSets/OsdkObjectSet.test.ts @@ -53,7 +53,7 @@ describe("OsdkObjectSet", () => { MockOntology, origin, () => "Token", - undefined, + USER_AGENT, fetch, ); }); diff --git a/packages/legacy-client/src/client/ontology.test.ts b/packages/legacy-client/src/client/ontology.test.ts index 056e53e3c..10df343c1 100644 --- a/packages/legacy-client/src/client/ontology.test.ts +++ b/packages/legacy-client/src/client/ontology.test.ts @@ -18,6 +18,7 @@ import type { ClientContext } from "@osdk/shared.net"; import { createClientContext } from "@osdk/shared.net"; import { MOCK_ORIGIN, MockOntology } from "@osdk/shared.test"; import { beforeEach, describe, expect, it } from "vitest"; +import { USER_AGENT } from "../USER_AGENT"; import { createObjectSetCreator } from "./ontology"; describe(createObjectSetCreator, () => { @@ -29,7 +30,7 @@ describe(createObjectSetCreator, () => { MockOntology, MOCK_ORIGIN, () => "Token", - undefined, + USER_AGENT, fetch, ); } catch (e) { diff --git a/packages/legacy-client/src/client/queries.test.ts b/packages/legacy-client/src/client/queries.test.ts index a1512e310..8bb853f3a 100644 --- a/packages/legacy-client/src/client/queries.test.ts +++ b/packages/legacy-client/src/client/queries.test.ts @@ -33,6 +33,7 @@ import { vi, } from "vitest"; import type { ObjectSet, Range } from "../client"; +import { USER_AGENT } from "../USER_AGENT"; import type { Todo } from "../util/test"; import { expectFetchToBeCalledWithBody } from "../util/test/expectUtils"; import { unwrapResultOrThrow } from "../util/test/resultUtils"; @@ -58,7 +59,7 @@ describe("Queries", () => { MockOntology, MOCK_ORIGIN, () => "Token", - undefined, + USER_AGENT, fetch, ); queries = createQueryProxy(client); diff --git a/packages/shared.net/changelog/@unreleased/pr-20.v2.yml b/packages/shared.net/changelog/@unreleased/pr-20.v2.yml new file mode 100644 index 000000000..8799cdc20 --- /dev/null +++ b/packages/shared.net/changelog/@unreleased/pr-20.v2.yml @@ -0,0 +1,5 @@ +type: fix +fix: + description: Send consistent UserAgent strings + links: + - https://github.com/palantir/osdk-ts/pull/20 diff --git a/packages/shared.net/src/createClientContext.ts b/packages/shared.net/src/createClientContext.ts index 4b8dd56da..36ff7518e 100644 --- a/packages/shared.net/src/createClientContext.ts +++ b/packages/shared.net/src/createClientContext.ts @@ -31,12 +31,15 @@ export function createClientContext< ontology: T, stack: string, tokenProvider: () => Promise | string, - additionalUserAgent?: `${string} (${string})`, + userAgent: string, fetchFn: typeof globalThis.fetch = fetch, ): ClientContext { if (stack.length === 0) { throw new Error("stack cannot be empty"); } + + const wireUserAgent = `${ontology.metadata.userAgent} ${userAgent}`; + const retryingFetchWithAuthOrThrow = createFetchHeaderMutator( createRetryingFetch(createFetchOrThrow(fetchFn)), async (headers) => { @@ -44,9 +47,7 @@ export function createClientContext< headers.set("Authorization", `Bearer ${token}`); headers.set( "Fetch-User-Agent", - `@osdk/shared.net/0.0.0 () ${ - additionalUserAgent ? additionalUserAgent + " " : "" - }${ontology.metadata.userAgent}`, + wireUserAgent, ); return headers; }, diff --git a/packages/shared.test/changelog/@unreleased/pr-20.v2.yml b/packages/shared.test/changelog/@unreleased/pr-20.v2.yml new file mode 100644 index 000000000..8799cdc20 --- /dev/null +++ b/packages/shared.test/changelog/@unreleased/pr-20.v2.yml @@ -0,0 +1,5 @@ +type: fix +fix: + description: Send consistent UserAgent strings + links: + - https://github.com/palantir/osdk-ts/pull/20 diff --git a/packages/shared.test/src/mock-ontology/mockOntology.ts b/packages/shared.test/src/mock-ontology/mockOntology.ts index 69ec1c471..c414bdc0b 100644 --- a/packages/shared.test/src/mock-ontology/mockOntology.ts +++ b/packages/shared.test/src/mock-ontology/mockOntology.ts @@ -22,7 +22,7 @@ export const MockOntology = { metadata: { ontologyRid: "", ontologyApiName: "Ontology", - userAgent: "", + userAgent: "typescript-sdk/0.0.0 osdk-cli/0.0.0", }, objects: { Task: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bdec97d80..bc769b67d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -428,6 +428,9 @@ importers: '@osdk/shared.test': specifier: workspace:* version: link:../shared.test + '@types/node': + specifier: ^18.0.0 + version: 18.17.15 '@types/yargs': specifier: ^17.0.29 version: 17.0.29