diff --git a/cli.ts b/cli.ts index 690488e..4f08635 100644 --- a/cli.ts +++ b/cli.ts @@ -1,6 +1,5 @@ #!/usr/bin/env node import isEqual from "lodash/isEqual" -import { getCommandOpenApiDef } from "./lib/get-command-open-api-def" import { getConfigStore } from "./lib/get-config-store" import { interactForCommandParams } from "./lib/interact-for-command-params" import { interactForCommandSelection } from "./lib/interact-for-command-selection" @@ -12,12 +11,12 @@ import chalk from "chalk" import { interactForServerSelection } from "./lib/interact-for-server-selection" import { getServer } from "./lib/get-server" import prompts from "prompts" -import { pollActionAttemptUntilReady } from "./lib/util/poll-action-attempt-until-ready" import logResponse from "./lib/util/log-response" import { getApiDefinitions } from "./lib/get-api-definitions" import commandLineUsage from "command-line-usage" import { ContextHelpers } from "./lib/types" -import { version } from './package.json'; +import { version } from "./package.json" +import open from "open" const sections = [ { @@ -66,6 +65,12 @@ const sections = [ async function cli(args: ParsedArgs) { const config = getConfigStore() + if (args.help || args.h) { + const usage = commandLineUsage(sections) + console.log(usage) + return + } + if ( !config.get(`${getServer()}.pat`) && args._[0] !== "login" && @@ -75,12 +80,6 @@ async function cli(args: ParsedArgs) { process.exit(1) } - if (args.help || args.h) { - const usage = commandLineUsage(sections) - console.log(usage) - return - } - if (args.version) { console.log(version) process.exit(0) @@ -170,6 +169,30 @@ async function cli(args: ParsedArgs) { logResponse(response) + if (response.data.connect_webview) { + if ( + response.data && + response.data.connect_webview && + response.data.connect_webview.url + ) { + const url = response.data.connect_webview.url + + if (process.env.INSIDE_WEB_BROWSER !== "1") { + const { action } = await prompts({ + type: "confirm", + name: "action", + message: "Would you like to open the webview in your browser?", + }) + + if (action) { + await open(url) + } + } else { + //TODO: Figure out how to open the webview in the browser + } + } + } + if ("action_attempt" in response.data) { const { poll_for_action_attempt } = await prompts({ name: "poll_for_action_attempt", @@ -181,8 +204,10 @@ async function cli(args: ParsedArgs) { }) if (poll_for_action_attempt) { - await pollActionAttemptUntilReady( - response.data.action_attempt.action_attempt_id + const { action_attempt_id } = response.data.action_attempt + await seam.actionAttempts.get( + { action_attempt_id }, + { waitForActionAttempt: { pollingInterval: 240, timeout: 10_000 } } ) } } diff --git a/lib/get-api-definitions.ts b/lib/get-api-definitions.ts index 7b5b114..7c03d2e 100644 --- a/lib/get-api-definitions.ts +++ b/lib/get-api-definitions.ts @@ -13,7 +13,9 @@ export const getApiDefinitions = async ( return SwaggerParser.dereference(schema as unknown as OpenAPI.Document) } -const getSchema = async (useRemoteDefinitions: boolean): typeof openapi => { +const getSchema = async ( + useRemoteDefinitions: boolean +): Promise => { if (!useRemoteDefinitions) return openapi const endpoint = getServer() return getOpenapiSchema(endpoint) diff --git a/lib/get-seam.ts b/lib/get-seam.ts index 4a80446..4d28238 100644 --- a/lib/get-seam.ts +++ b/lib/get-seam.ts @@ -1,4 +1,8 @@ -import { SeamHttp, SeamHttpMultiWorkspace } from "@seamapi/http/connect" +import { + SeamHttp, + SeamHttpMultiWorkspace, + isApiKey, +} from "@seamapi/http/connect" import { getConfigStore } from "./get-config-store" import { getServer } from "./get-server" @@ -22,10 +26,12 @@ export const getSeam = async (): Promise => { return SeamHttp.fromApiKey(token, options) } -export const getSeamMultiWorkspace = - async (): Promise => { - const config = getConfigStore() - const token = config.get(`${getServer()}.pat`) - const options = { endpoint: getServer() } - return SeamHttpMultiWorkspace.fromPersonalAccessToken(token, options) - } +export const getSeamMultiWorkspace = async (): Promise< + SeamHttpMultiWorkspace | SeamHttp +> => { + const config = getConfigStore() + const token = config.get(`${getServer()}.pat`) + const options = { endpoint: getServer() } + if (isApiKey(token)) return SeamHttp.fromApiKey(token, options) + return SeamHttpMultiWorkspace.fromPersonalAccessToken(token, options) +} diff --git a/lib/interact-for-command-params.ts b/lib/interact-for-command-params.ts index f77ba99..c3fe9db 100644 --- a/lib/interact-for-command-params.ts +++ b/lib/interact-for-command-params.ts @@ -12,6 +12,7 @@ import { interactForAcsUser } from "./interact-for-acs-user" import { interactForCredentialPool } from "./interact-for-credential-pool" import { ContextHelpers } from "./types" import { interactForAcsEntrance } from "./interact-for-acs-entrance" +import { interactForOpenApiObject } from "./interact-for-open-api-object" const ergonomicPropOrder = [ "name", @@ -42,249 +43,14 @@ export const interactForCommandParams = async ( if (!("content" in requestBody)) throw new Error("No content in requestBody") - const schema: OpenApiSchema = flattenObjSchema( - (requestBody as any).content["application/json"].schema - ) - - const { properties = {}, required = [] } = schema - - const haveAllRequiredParams = required.every((k) => currentParams[k]) - - const propSortScore = (prop: string) => { - if (required.includes(prop)) return 100 - if (currentParams[prop] !== undefined) - return 50 - Object.keys(currentParams).indexOf(prop) - return ergonomicPropOrder.indexOf(prop) - } - - const cmdPath = `/${command.join("/").replace(/-/g, "_")}` - console.log("") - const { paramToEdit } = await prompts({ - name: "paramToEdit", - message: `[${cmdPath}] Parameters`, - type: "autocomplete", - choices: [ - ...(haveAllRequiredParams - ? [ - { - value: "done", - title: `[Make API Call] ${cmdPath}`, - }, - ] - : []), - ...Object.keys(properties) - .map((k) => { - let propDesc = (properties[k] as any)?.description ?? "" - return { - title: k + (required.includes(k) ? "*" : ""), - value: k, - description: - currentParams[k] !== undefined - ? `[${currentParams[k]}] ${propDesc}` - : propDesc, - } - }) - .sort((a, b) => propSortScore(b.value) - propSortScore(a.value)), - ], - }) - - if (paramToEdit === "done") { - // TODO check for required - return currentParams - } - - const prop = properties[paramToEdit] - - if (paramToEdit === "device_id") { - const device_id = await interactForDevice() - return interactForCommandParams( - { command, params: { ...currentParams, device_id } }, - ctx - ) - } else if (paramToEdit === "access_code_id") { - const access_code_id = await interactForAccessCode(currentParams as any) - return interactForCommandParams( - { - command, - params: { - ...currentParams, - access_code_id, - }, - }, - ctx - ) - } else if (paramToEdit === "connected_account_id") { - const connected_account_id = await interactForConnectedAccount() - return interactForCommandParams( - { - command, - params: { - ...currentParams, - connected_account_id, - }, - }, - ctx - ) - } else if (paramToEdit === "user_identity_id") { - const user_identity_id = await interactForUserIdentity() - return interactForCommandParams( - { - command, - params: { - ...currentParams, - user_identity_id, - }, - }, - ctx - ) - } else if (paramToEdit.endsWith("acs_system_id")) { - const acs_system_id = await interactForAcsSystem() - return interactForCommandParams( - { - command, - params: { - ...currentParams, - [paramToEdit]: acs_system_id, - }, - }, - ctx - ) - } else if (paramToEdit.endsWith("credential_pool_id")) { - const credential_pool_id = await interactForCredentialPool() - return interactForCommandParams( - { - command, - params: { - ...currentParams, - [paramToEdit]: credential_pool_id, - }, - }, - ctx - ) - } else if (paramToEdit.endsWith("acs_user_id")) { - const acs_user_id = await interactForAcsUser() - return interactForCommandParams( - { - command, - params: { - ...currentParams, - [paramToEdit]: acs_user_id, - }, - }, - ctx - ) - } else if (paramToEdit.endsWith("acs_entrance_id")) { - const acs_entrance_id = await interactForAcsEntrance() - return interactForCommandParams( - { - command, - params: { - ...currentParams, - [paramToEdit]: acs_entrance_id, - }, - }, - ctx - ) - } else if ( - // TODO replace when openapi returns if a field is a timestamp - paramToEdit.endsWith("_at") || - paramToEdit === "since" || - paramToEdit.endsWith("_before") || - paramToEdit.endsWith("_after") - ) { - const tsval = await interactForTimestamp() - return interactForCommandParams( - { - command, - params: { - ...currentParams, - [paramToEdit]: tsval, - }, - }, - ctx - ) - } - - if ("type" in prop) { - if (prop.type === "string") { - let value - if (prop.enum) { - value = ( - await prompts({ - name: "value", - message: `${paramToEdit}:`, - type: "select", - choices: prop.enum.map((v) => ({ - title: v.toString(), - value: v.toString(), - })), - }) - ).value - } else { - value = ( - await prompts({ - name: "value", - message: `${paramToEdit}:`, - type: "text", - }) - ).value - } - return interactForCommandParams( - { - command, - params: { - ...currentParams, - [paramToEdit]: value, - }, - }, - ctx - ) - } else if (prop.type === "boolean") { - const { value } = await prompts({ - name: "value", - message: `${paramToEdit}:`, - type: "toggle", - initial: true, - active: "true", - inactive: "false", - }) - - return interactForCommandParams( - { - command, - params: { - ...currentParams, - [paramToEdit]: value, - }, - }, - ctx - ) - } else if (prop.type === "array") { - const value = ( - await prompts({ - name: "value", - message: `${paramToEdit}:`, - type: "autocompleteMultiselect", - choices: (prop as any).items.enum.map((v: string) => ({ - title: v.toString(), - value: v.toString(), - })), - }) - ).value - return interactForCommandParams( - { - command, - params: { - ...currentParams, - [paramToEdit]: value, - }, - }, - ctx - ) - } - } + const requestSchema = (requestBody as any).content["application/json"].schema - throw new Error( - `Didn't know how to handle OpenAPI schema for property: "${paramToEdit}"` + return interactForOpenApiObject( + { + command: args.command, + params: args.params, + schema: requestSchema, + }, + ctx ) } diff --git a/lib/interact-for-open-api-object.ts b/lib/interact-for-open-api-object.ts new file mode 100644 index 0000000..60b3f34 --- /dev/null +++ b/lib/interact-for-open-api-object.ts @@ -0,0 +1,229 @@ +import prompts from "prompts" +import { getCommandOpenApiDef } from "./get-command-open-api-def" +import { OpenApiSchema } from "openapi-v3" +import { interactForDevice } from "./interact-for-device" +import { interactForAccessCode } from "./interact-for-access-code" +import { interactForConnectedAccount } from "./interact-for-connected-account" +import { flattenObjSchema } from "./openapi/flatten-obj-schema" +import { interactForTimestamp } from "./interact-for-timestamp" +import { interactForUserIdentity } from "./interact-for-user-identity" +import { interactForAcsSystem } from "./interact-for-acs-system" +import { interactForAcsUser } from "./interact-for-acs-user" +import { interactForCredentialPool } from "./interact-for-credential-pool" +import { ContextHelpers } from "./types" +import { interactForAcsEntrance } from "./interact-for-acs-entrance" +import { ellipsis } from "./util/ellipsis" + +const ergonomicPropOrder = [ + "name", + "connected_account_id", + "device_id", + "access_code_id", + "user_identity_id", + "code", + "starts_at", + "ends_at", +] + +export const interactForOpenApiObject = async ( + args: { + command: string[] + schema: OpenApiSchema + params: Record + isSubProperty?: boolean + subPropertyPath?: string + }, + ctx: ContextHelpers +): Promise => { + // Clone args and args params so that we can mutate it + args = { ...args, params: { ...args.params } } + + const schema: OpenApiSchema = flattenObjSchema(args.schema) + + const { properties = {}, required = [] } = schema + + const haveAllRequiredParams = required.every((k) => args.params[k]) + + const propSortScore = (prop: string) => { + if (required.includes(prop)) return 100 - ergonomicPropOrder.indexOf(prop) + if (args.params[prop] !== undefined) + return 50 - Object.keys(args.params).indexOf(prop) + return ergonomicPropOrder.indexOf(prop) + } + + const cmdPath = `/${args.command.join("/").replace(/-/g, "_")}` + const parameterSelectionMessage = args.isSubProperty + ? `Editing "${args.subPropertyPath}"` + : `[${cmdPath}] Parameters` + + console.log("") + const { paramToEdit } = await prompts({ + name: "paramToEdit", + message: parameterSelectionMessage, + type: "autocomplete", + choices: [ + ...(haveAllRequiredParams && !args.isSubProperty + ? [ + { + value: "done", + title: `[Make API Call] ${cmdPath}`, + }, + ] + : []), + ...(haveAllRequiredParams && args.isSubProperty + ? [ + { + title: `[Save]`, + value: "done", + }, + ] + : []), + ...Object.keys(properties) + .map((k) => { + let propDesc = (properties[k] as any)?.description ?? "" + return { + title: k + (required.includes(k) ? "*" : ""), + value: k, + description: + args.params[k] !== undefined + ? typeof args.params[k] === "object" + ? `${ellipsis( + JSON.stringify(args.params[k]), + 60 + )} ${propDesc}` + : `[${args.params[k]}] ${propDesc}` + : propDesc, + } + }) + .sort((a, b) => propSortScore(b.value) - propSortScore(a.value)), + ...(args.isSubProperty + ? [ + { + title: `[Leave Empty]`, + value: "empty", + }, + ] + : []), + ], + }) + + if (paramToEdit === "empty") { + return undefined + } + + if (paramToEdit === "done") { + // TODO check for required + return args.params + } + + const prop = properties[paramToEdit] + + if (paramToEdit === "device_id") { + args.params[paramToEdit] = await interactForDevice() + return interactForOpenApiObject(args, ctx) + } else if (paramToEdit === "access_code_id") { + args.params[paramToEdit] = await interactForAccessCode(args.params as any) + return interactForOpenApiObject(args, ctx) + } else if (paramToEdit === "connected_account_id") { + const connected_account_id = await interactForConnectedAccount() + args.params[paramToEdit] = connected_account_id + return interactForOpenApiObject(args, ctx) + } else if (paramToEdit === "user_identity_id") { + const user_identity_id = await interactForUserIdentity() + args.params[paramToEdit] = user_identity_id + return interactForOpenApiObject(args, ctx) + } else if (paramToEdit.endsWith("acs_system_id")) { + args.params[paramToEdit] = await interactForAcsSystem() + return interactForOpenApiObject(args, ctx) + } else if (paramToEdit.endsWith("credential_pool_id")) { + args.params[paramToEdit] = await interactForCredentialPool() + return interactForOpenApiObject(args, ctx) + } else if (paramToEdit.endsWith("acs_user_id")) { + args.params[paramToEdit] = await interactForAcsUser() + return interactForOpenApiObject(args, ctx) + } else if (paramToEdit.endsWith("acs_entrance_id")) { + args.params.acs_entrance_id = await interactForAcsEntrance() + return interactForOpenApiObject(args, ctx) + } else if ( + // TODO replace when openapi returns if a field is a timestamp + paramToEdit.endsWith("_at") || + paramToEdit === "since" || + paramToEdit.endsWith("_before") || + paramToEdit.endsWith("_after") + ) { + args.params[paramToEdit] = await interactForTimestamp() + return interactForOpenApiObject(args, ctx) + } + + if ("type" in prop) { + if (prop.type === "string") { + let value + if (prop.enum) { + value = ( + await prompts({ + name: "value", + message: `${paramToEdit}:`, + type: "select", + choices: prop.enum.map((v) => ({ + title: v.toString(), + value: v.toString(), + })), + }) + ).value + } else { + value = ( + await prompts({ + name: "value", + message: `${paramToEdit}:`, + type: "text", + }) + ).value + } + args.params[paramToEdit] = value + return interactForOpenApiObject(args, ctx) + } else if (prop.type === "boolean") { + const { value } = await prompts({ + name: "value", + message: `${paramToEdit}:`, + type: "toggle", + initial: true, + active: "true", + inactive: "false", + }) + + args.params[paramToEdit] = value + + return interactForOpenApiObject(args, ctx) + } else if (prop.type === "array" && (prop as any)?.items?.enum) { + const value = ( + await prompts({ + name: "value", + message: `${paramToEdit}:`, + type: "autocompleteMultiselect", + choices: (prop as any).items.enum.map((v: string) => ({ + title: v.toString(), + value: v.toString(), + })), + }) + ).value + args.params[paramToEdit] = value + return interactForOpenApiObject(args, ctx) + } else if (prop.type === "object") { + args.params[paramToEdit] = await interactForOpenApiObject( + { + command: args.command, + params: {}, + schema: prop, + isSubProperty: true, + subPropertyPath: paramToEdit, + }, + ctx + ) + return interactForOpenApiObject(args, ctx) + } + } + + throw new Error( + `Didn't know how to handle OpenAPI schema for property: "${paramToEdit}"` + ) +} diff --git a/lib/interact-for-workspace-id.ts b/lib/interact-for-workspace-id.ts index 022aed6..4d4a54c 100644 --- a/lib/interact-for-workspace-id.ts +++ b/lib/interact-for-workspace-id.ts @@ -1,11 +1,11 @@ import { getConfigStore } from "./get-config-store" import prompts from "prompts" -import { getSeamMultiWorkspace } from "./get-seam" +import { getSeam, getSeamMultiWorkspace } from "./get-seam" export const interactForWorkspaceId = async () => { const config = getConfigStore() - const seam = await getSeamMultiWorkspace() + const workspaces = await seam.workspaces.list() const { workspaceId } = await prompts({ diff --git a/lib/util/ellipsis.ts b/lib/util/ellipsis.ts new file mode 100644 index 0000000..bd3ecb9 --- /dev/null +++ b/lib/util/ellipsis.ts @@ -0,0 +1,4 @@ +export const ellipsis = (str: string, len: number) => { + if (str.length <= len) return str + return str.slice(0, len - 3) + "..." +} diff --git a/lib/util/poll-action-attempt-until-ready.ts b/lib/util/poll-action-attempt-until-ready.ts deleted file mode 100644 index 3d75476..0000000 --- a/lib/util/poll-action-attempt-until-ready.ts +++ /dev/null @@ -1,29 +0,0 @@ -import ms from "ms" -import type { AxiosResponse } from "axios" -import { getSeam } from "../get-seam" -import logResponse from "./log-response" - -export const pollActionAttemptUntilReady = async ( - action_attempt_id: string -) => { - const seam = await getSeam() - const start_time = Date.now() - - let action_attempt - while (Date.now() < start_time + ms("10s")) { - action_attempt = await seam.client.get("/action_attempts/get", { - params: { action_attempt_id }, - validateStatus: () => true, - }) - - if (action_attempt.data.action_attempt.status !== "pending") { - break - } - - await new Promise((resolve) => setTimeout(resolve, 250)) - } - - logResponse(action_attempt as AxiosResponse) - - return action_attempt?.data.action_attempt -} diff --git a/package-lock.json b/package-lock.json index 4aa40e6..c391e86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "seam-cli", - "version": "0.0.24", + "version": "0.0.27", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "seam-cli", - "version": "0.0.24", + "version": "0.0.27", "dependencies": { - "@seamapi/http": "^0.11.1", - "@seamapi/types": "^1.70.0", - "ms": "^2.1.3", + "@seamapi/http": "^0.12.0", + "@seamapi/types": "^1.74.0", + "open": "^10.0.2", "swagger-parser": "^10.0.3" }, "bin": { @@ -808,9 +808,9 @@ ] }, "node_modules/@seamapi/http": { - "version": "0.11.1", - "resolved": "https://npm.pkg.github.com/download/@seamapi/http/0.11.1/d3d62e2f4d968d65b67712ac9936523fe5508e97", - "integrity": "sha512-X/Yo60cCqPwBtggQGwqIfzk2QwoBkEWjuQrRHmRpBCD7oopfFUaRTAch7pgqiLsVtJ0i0xe6CBuN/++xrOJ3Kw==", + "version": "0.12.0", + "resolved": "https://npm.pkg.github.com/download/@seamapi/http/0.12.0/8401e040f1df542a4176dc77618d096e0d7764b7", + "integrity": "sha512-xOMvi3e8joBPVQ4I38FtZUBGFKuRIX7q6pIe+ik1UblRZzF+O7h77W97GMWF4WVavM5GNNVJjiCVoU6NkwBv3w==", "license": "MIT", "dependencies": { "axios": "^1.5.0", @@ -827,9 +827,9 @@ } }, "node_modules/@seamapi/types": { - "version": "1.71.0", - "resolved": "https://npm.pkg.github.com/download/@seamapi/types/1.71.0/2448a1b8b7908f771f4cc681d4b212c797d7de8f", - "integrity": "sha512-O/Pr+WkQcHbn8sVYV/oabT3sLWb6GdddQ9F4kH1SYRVcDZ4pQdOUuojWPhBFDWw6yZbkxPKqQJk7JG0LSOImSQ==", + "version": "1.75.0", + "resolved": "https://npm.pkg.github.com/download/@seamapi/types/1.75.0/f5e36f368d2670be459f124627f59ba2a5b7a69e", + "integrity": "sha512-oIFgwjaYkO8vjQkw7CPGNGru6FN9zhCrmdrb7HiHLZ/ciYQyihbhQZcf0Pj/+NQn/PQjw8EWDFFU9PnXe4T0cA==", "license": "MIT", "engines": { "node": ">=18.12.0", @@ -1365,6 +1365,20 @@ "undici-types": "^5.26.4" } }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bundle-require": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-4.0.2.tgz", @@ -1738,12 +1752,6 @@ } } }, - "node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -1768,6 +1776,43 @@ "node": ">=4.0.0" } }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2325,6 +2370,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2355,6 +2414,23 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2402,6 +2478,20 @@ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -2663,9 +2753,10 @@ "dev": true }, "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/multistream": { "version": "4.1.0", @@ -2808,6 +2899,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/open/-/open-10.0.2.tgz", + "integrity": "sha512-GnYLdE+E3K8NeSE23N0g67/9q9AXRph5oTUbz6IbIgElPigEnQ2aHuqRge3y0JUr67qoc84xME5kF03fDc3fcA==", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/openapi-types": { "version": "12.1.3", "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", @@ -3291,6 +3399,17 @@ "fsevents": "~2.3.2" } }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -3865,9 +3984,9 @@ } }, "node_modules/type-fest": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.8.3.tgz", - "integrity": "sha512-//BaTm14Q/gHBn09xlnKNqfI8t6bmdzx2DXYfPBNofN0WUybCEUDcbCWcTa0oF09lzLjZgPphXAsvRiMK0V6Bw==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.9.0.tgz", + "integrity": "sha512-KS/6lh/ynPGiHD/LnAobrEFq3Ad4pBzOlJ1wAnJx9N4EYoqFhMfLIBjUT2UEx4wg5ZE+cC1ob6DCSpppVo+rtg==", "peer": true, "engines": { "node": ">=16" diff --git a/package.json b/package.json index 04bade9..eb48105 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "seam-cli", "module": "index.ts", "type": "module", - "version": "0.0.24", +"version": "0.0.27", "homepage": "https://github.com/seamapi/seam-cli", "bugs": "https://github.com/seamapi/seam-cli/issues", "repository": "seamapi/seam-cli", @@ -55,9 +55,9 @@ "typescript": "^5.0.0" }, "dependencies": { - "@seamapi/http": "^0.11.1", - "@seamapi/types": "^1.70.0", - "ms": "^2.1.3", + "@seamapi/http": "^0.12.0", + "open": "^10.0.2", + "@seamapi/types": "^1.74.0", "swagger-parser": "^10.0.3" } }