Skip to content

Conversation

github-actions[bot]
Copy link
Contributor

This PR was automatically generated by the Generate SDK workflow.

The OpenAPI specification has been updated and the SDK has been regenerated to reflect the latest changes.

Please review the changes and merge if they look correct.

@github-actions github-actions bot force-pushed the update-sdk-from-openapi branch from 11a0d40 to 6d9c9c9 Compare September 18, 2025 02:28
@vercel vercel bot temporarily deployed to Preview – v0-sdk-simple-demo September 18, 2025 02:28 Inactive
Copy link
Contributor

vercel bot commented Sep 18, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
v0-sdk-clone-demo Ready Ready Preview Comment Oct 11, 2025 2:27am
v0-sdk-simple-demo Ready Ready Preview Comment Oct 11, 2025 2:27am

| {
notifications: 'live-activity' | 'push-notifications' | 'none'
}
| unknown
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The preferences field in UserPreferencesPostResponseSchema should be | null instead of | unknown to match the OpenAPI specification.

View Details
📝 Patch Details
diff --git a/packages/v0-sdk/src/scripts/generate.ts b/packages/v0-sdk/src/scripts/generate.ts
index 2195325..edb5ffe 100644
--- a/packages/v0-sdk/src/scripts/generate.ts
+++ b/packages/v0-sdk/src/scripts/generate.ts
@@ -783,6 +783,8 @@ function schemaToTypeScript(schema: any, schemas: any): string {
       return 'number'
     case 'boolean':
       return 'boolean'
+    case 'null':
+      return 'null'
     default:
       return 'unknown'
   }
diff --git a/packages/v0-sdk/src/sdk/v0.ts b/packages/v0-sdk/src/sdk/v0.ts
index d41c1e4..d96f857 100644
--- a/packages/v0-sdk/src/sdk/v0.ts
+++ b/packages/v0-sdk/src/sdk/v0.ts
@@ -555,20 +555,16 @@ export interface UserDetail {
 
 export type UserPreferencesPostResponseSchema = {
   object: 'user_preferences'
-  preferences:
-    | {
-        notifications: 'live-activity' | 'push-notifications' | 'none'
-      }
-    | unknown
+  preferences: {
+    notifications: 'live-activity' | 'push-notifications' | 'none'
+  } | null
 }
 
 export type UserPreferencesResponseSchema = {
   object: 'user_preferences'
-  preferences:
-    | {
-        notifications: 'live-activity' | 'push-notifications' | 'none'
-      }
-    | unknown
+  preferences: {
+    notifications: 'live-activity' | 'push-notifications' | 'none'
+  } | null
 }
 
 export type UserPreferencesSchema = {

Analysis

Missing null type handling in OpenAPI TypeScript generation causes incorrect union types

What fails: schemaToTypeScript() in packages/v0-sdk/src/scripts/generate.ts lacks a case for 'null' type, causing {"type": "null"} schemas to generate as unknown instead of null

How to reproduce:

cd packages/v0-sdk
pnpm run sdk:generate
grep -A5 "UserPreferencesPostResponseSchema\|UserPreferencesResponseSchema" src/sdk/v0.ts

Result: Generated types show | unknown instead of | null:

preferences: { notifications: string } | unknown  // Wrong

Expected: Should generate | null per OpenAPI spec lines 15130-15132:

preferences: { notifications: string } | null     // Correct

The OpenAPI specification correctly defines anyOf: [object, {"type": "null"}] but the primitive type switch statement in the generation code falls through to default 'unknown' for null types.

| {
notifications: 'live-activity' | 'push-notifications' | 'none'
}
| unknown
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The preferences field in UserPreferencesResponseSchema should be | null instead of | unknown to match the OpenAPI specification.

View Details
📝 Patch Details
diff --git a/packages/v0-sdk/src/scripts/generate.ts b/packages/v0-sdk/src/scripts/generate.ts
index 2195325..edb5ffe 100644
--- a/packages/v0-sdk/src/scripts/generate.ts
+++ b/packages/v0-sdk/src/scripts/generate.ts
@@ -783,6 +783,8 @@ function schemaToTypeScript(schema: any, schemas: any): string {
       return 'number'
     case 'boolean':
       return 'boolean'
+    case 'null':
+      return 'null'
     default:
       return 'unknown'
   }
diff --git a/packages/v0-sdk/src/sdk/v0.ts b/packages/v0-sdk/src/sdk/v0.ts
index d41c1e4..d96f857 100644
--- a/packages/v0-sdk/src/sdk/v0.ts
+++ b/packages/v0-sdk/src/sdk/v0.ts
@@ -555,20 +555,16 @@ export interface UserDetail {
 
 export type UserPreferencesPostResponseSchema = {
   object: 'user_preferences'
-  preferences:
-    | {
-        notifications: 'live-activity' | 'push-notifications' | 'none'
-      }
-    | unknown
+  preferences: {
+    notifications: 'live-activity' | 'push-notifications' | 'none'
+  } | null
 }
 
 export type UserPreferencesResponseSchema = {
   object: 'user_preferences'
-  preferences:
-    | {
-        notifications: 'live-activity' | 'push-notifications' | 'none'
-      }
-    | unknown
+  preferences: {
+    notifications: 'live-activity' | 'push-notifications' | 'none'
+  } | null
 }
 
 export type UserPreferencesSchema = {

Analysis

TypeScript SDK generates | unknown instead of | null for nullable preferences field

What fails: UserPreferencesResponseSchema.preferences field incorrectly typed as | unknown instead of | null in generated TypeScript code

How to reproduce:

cd packages/v0-sdk && pnpm run sdk:generate
grep -A 5 "UserPreferencesResponseSchema" src/sdk/v0.ts

Result: Generated type shows preferences: {...} | unknown
Expected: Should be preferences: {...} | null to match OpenAPI spec at https://api.v0.dev/v1/openapi.json

Root cause: schemaToTypeScript() function in generation script missing case 'null': handler, causing {"type": "null"} schemas in anyOf to fall through to default: return 'unknown'

@github-actions github-actions bot force-pushed the update-sdk-from-openapi branch from 6d9c9c9 to 9cc0553 Compare September 19, 2025 02:30
@vercel vercel bot temporarily deployed to Preview – v0-sdk-simple-demo September 19, 2025 02:30 Inactive
@github-actions github-actions bot force-pushed the update-sdk-from-openapi branch from 9cc0553 to b05a2d6 Compare September 23, 2025 02:28
@github-actions github-actions bot force-pushed the update-sdk-from-openapi branch from b05a2d6 to bf90f42 Compare September 25, 2025 02:30
@github-actions github-actions bot force-pushed the update-sdk-from-openapi branch from bf90f42 to 0983303 Compare September 26, 2025 02:29
@github-actions github-actions bot force-pushed the update-sdk-from-openapi branch from 0983303 to b5092b4 Compare October 1, 2025 02:33
export interface DeploymentsFindLogsResponse {
error?: string
logs: string[]
export type DeploymentsFindLogsResponse = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DeploymentsFindLogsResponse type has breaking changes that will cause TypeScript compilation errors in dependent code. The error field was removed and logs structure was changed from string[] to structured objects, but consuming code in packages/ai-tools/src/tools/deployment-tools.ts (line 119) and the test file packages/v0-sdk/tests/deployments/findLogs.test.ts (lines 26-29, 79) were not updated.

View Details
📝 Patch Details
diff --git a/packages/ai-tools/src/tools/deployment-tools.ts b/packages/ai-tools/src/tools/deployment-tools.ts
index 5a1017d..3f78493 100644
--- a/packages/ai-tools/src/tools/deployment-tools.ts
+++ b/packages/ai-tools/src/tools/deployment-tools.ts
@@ -116,7 +116,6 @@ export function createDeploymentTools(config: V0ClientConfig = {}) {
 
       return {
         logs: result.logs,
-        error: result.error,
         nextSince: result.nextSince,
       }
     },
diff --git a/packages/v0-sdk/tests/deployments/findLogs.test.ts b/packages/v0-sdk/tests/deployments/findLogs.test.ts
index daa7699..8379023 100644
--- a/packages/v0-sdk/tests/deployments/findLogs.test.ts
+++ b/packages/v0-sdk/tests/deployments/findLogs.test.ts
@@ -23,11 +23,36 @@ describe('v0.deployments.findLogs', () => {
   it('should find deployment logs', async () => {
     const mockResponse = {
       logs: [
-        '2024-01-01T00:00:00Z [INFO] Starting deployment',
-        '2024-01-01T00:00:01Z [INFO] Building application',
-        '2024-01-01T00:00:05Z [INFO] Deployment successful',
+        {
+          createdAt: '2024-01-01T00:00:00Z',
+          deploymentId: 'deployment-123',
+          id: 'log-1',
+          text: 'Starting deployment',
+          type: 'stdout' as const,
+          level: 'info' as const,
+          object: 'deployment_log' as const,
+        },
+        {
+          createdAt: '2024-01-01T00:00:01Z',
+          deploymentId: 'deployment-123',
+          id: 'log-2',
+          text: 'Building application',
+          type: 'stdout' as const,
+          level: 'info' as const,
+          object: 'deployment_log' as const,
+        },
+        {
+          createdAt: '2024-01-01T00:00:05Z',
+          deploymentId: 'deployment-123',
+          id: 'log-3',
+          text: 'Deployment successful',
+          type: 'stdout' as const,
+          level: 'info' as const,
+          object: 'deployment_log' as const,
+        },
       ],
       nextSince: 1704067205,
+      object: 'list' as const,
     }
 
     mockFetcher.mockResolvedValue(mockResponse)
@@ -52,6 +77,7 @@ describe('v0.deployments.findLogs', () => {
     const mockResponse = {
       logs: [],
       nextSince: 1704067200,
+      object: 'list' as const,
     }
 
     mockFetcher.mockResolvedValue(mockResponse)
@@ -64,20 +90,13 @@ describe('v0.deployments.findLogs', () => {
     expect(result.nextSince).toBe(1704067200)
   })
 
-  it('should handle error response', async () => {
-    const mockResponse = {
-      error: 'Deployment not found',
-      logs: [],
-    }
-
-    mockFetcher.mockResolvedValue(mockResponse)
-
-    const result = await v0.deployments.findLogs({
-      deploymentId: 'nonexistent-deployment',
-    })
+  it('should handle deployment not found error', async () => {
+    const error = new Error('Deployment not found')
+    mockFetcher.mockRejectedValue(error)
 
-    expect(result.error).toBe('Deployment not found')
-    expect(result.logs).toHaveLength(0)
+    await expect(
+      v0.deployments.findLogs({ deploymentId: 'nonexistent-deployment' }),
+    ).rejects.toThrow('Deployment not found')
   })
 
   it('should handle API errors', async () => {

Analysis

TypeScript compilation error from breaking changes in DeploymentsFindLogsResponse

What fails: packages/ai-tools/src/tools/deployment-tools.ts line 119 accesses result.error property that no longer exists on DeploymentsFindLogsResponse type, causing TypeScript compilation error. Test file packages/v0-sdk/tests/deployments/findLogs.test.ts uses outdated mock structure with string array logs instead of structured objects.

How to reproduce:

cd packages/ai-tools && npx tsc --noEmit

Result:

error TS2339: Property 'error' does not exist on type 'DeploymentsFindLogsResponse'.

Expected: TypeScript compilation should pass. The DeploymentsFindLogsResponse type changed from having an optional error field and logs: string[] to having no error field and logs: Array<{...}> with structured log objects containing id, text, type, level, etc.

Fixed:

  • Removed error: result.error from deployment-tools.ts return statement
  • Updated test mocks from string arrays to structured log objects matching the new type definition
  • Changed error handling test to use rejected promise instead of checking non-existent error field

},
]
>
experimental_content?: Array<unknown[] | unknown[]>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The experimental_content field type has regressed from precise tuple types to Array<unknown[] | unknown[]>, losing type safety and making the union redundant.

View Details
📝 Patch Details
diff --git a/packages/v0-sdk/src/scripts/generate.ts b/packages/v0-sdk/src/scripts/generate.ts
index 6e4d6bd..fe99de9 100644
--- a/packages/v0-sdk/src/scripts/generate.ts
+++ b/packages/v0-sdk/src/scripts/generate.ts
@@ -664,6 +664,16 @@ function transformPath(route: string): string {
   return route.replace(/{([^}]+)}/g, '${pathParams.$1}')
 }
 
+function isValidIdentifier(str: string): boolean {
+  // Check if the string is a valid JavaScript identifier
+  return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(str)
+}
+
+function quotePropertyName(key: string): string {
+  // Quote property names that aren't valid identifiers
+  return isValidIdentifier(key) ? key : `"${key}"`
+}
+
 function schemaToTypeScript(schema: any, schemas: any): string {
   if (!schema) return 'unknown'
 
@@ -718,7 +728,7 @@ function schemaToTypeScript(schema: any, schemas: any): string {
             const propType = schemaToTypeScript(propSchema, schemas)
             const deprecatedComment =
               propSchema?.deprecated === true ? '  /** @deprecated */\n' : ''
-            return `${deprecatedComment}  ${key}${isRequired ? '' : '?'}: ${propType}`
+            return `${deprecatedComment}  ${quotePropertyName(key)}${isRequired ? '' : '?'}: ${propType}`
           })
           .join('\n')
         baseType = `{\n${properties}\n}`
@@ -735,7 +745,7 @@ function schemaToTypeScript(schema: any, schemas: any): string {
             const propType = schemaToTypeScript(propSchema, schemas)
             const deprecatedComment =
               propSchema?.deprecated === true ? '  /** @deprecated */\n' : ''
-            return `${deprecatedComment}  ${key}${isRequired ? '' : '?'}: ${propType}`
+            return `${deprecatedComment}  ${quotePropertyName(key)}${isRequired ? '' : '?'}: ${propType}`
           })
           .join('\n')
         return `{\n${properties}\n}`
@@ -768,7 +778,7 @@ function schemaToTypeScript(schema: any, schemas: any): string {
             const propType = schemaToTypeScript(propSchema, schemas)
             const deprecatedComment =
               propSchema?.deprecated === true ? '    /** @deprecated */\n' : ''
-            return `${deprecatedComment}    ${key}${isRequired ? '' : '?'}: ${propType}`
+            return `${deprecatedComment}    ${quotePropertyName(key)}${isRequired ? '' : '?'}: ${propType}`
           },
         )
 
@@ -807,7 +817,15 @@ function schemaToTypeScript(schema: any, schemas: any): string {
 
   // Handle arrays
   if (schema.type === 'array') {
-    // Handle tuple types (when items is an array)
+    // Handle prefixItems (JSON Schema 2020-12 tuple types)
+    if (schema.prefixItems && Array.isArray(schema.prefixItems)) {
+      const tupleTypes = schema.prefixItems.map((itemSchema: any) =>
+        schemaToTypeScript(itemSchema, schemas),
+      )
+      return `[${tupleTypes.join(', ')}]`
+    }
+
+    // Handle tuple types (when items is an array - older JSON Schema style)
     if (Array.isArray(schema.items)) {
       const tupleTypes = schema.items.map((itemSchema: any) =>
         schemaToTypeScript(itemSchema, schemas),
@@ -832,7 +850,7 @@ function schemaToTypeScript(schema: any, schemas: any): string {
           const propType = schemaToTypeScript(propSchema, schemas)
           const deprecatedComment =
             propSchema?.deprecated === true ? '  /** @deprecated */\n' : ''
-          return `${deprecatedComment}  ${key}${isRequired ? '' : '?'}: ${propType}`
+          return `${deprecatedComment}  ${quotePropertyName(key)}${isRequired ? '' : '?'}: ${propType}`
         })
         .join('\n')
 
diff --git a/packages/v0-sdk/src/sdk/v0.ts b/packages/v0-sdk/src/sdk/v0.ts
index f535435..d928f29 100644
--- a/packages/v0-sdk/src/sdk/v0.ts
+++ b/packages/v0-sdk/src/sdk/v0.ts
@@ -39,7 +39,67 @@ export type ChatDetail = {
     id: string
     object: 'message'
     content: string
-    experimental_content?: Array<unknown[] | unknown[]>
+    experimental_content?: Array<
+      | [0, unknown[]]
+      | [
+          1,
+          {
+            '~standard': string
+            def: string
+            type: string
+            check: string
+            clone: string
+            brand: string
+            register: string
+            parse: string
+            safeParse: string
+            parseAsync: string
+            safeParseAsync: string
+            spa: string
+            encode: string
+            decode: string
+            encodeAsync: string
+            decodeAsync: string
+            safeEncode: string
+            safeDecode: string
+            safeEncodeAsync: string
+            safeDecodeAsync: string
+            refine: string
+            superRefine: string
+            overwrite: string
+            optional: string
+            nullable: string
+            nullish: string
+            nonoptional: string
+            array: string
+            or: string
+            and: string
+            transform: string
+            default: string
+            prefault: string
+            catch: string
+            pipe: string
+            readonly: string
+            describe: string
+            meta: string
+            isOptional: string
+            isNullable: string
+            keyof: string
+            catchall: string
+            passthrough: string
+            loose: string
+            strict: string
+            strip: string
+            extend: string
+            safeExtend: string
+            merge: string
+            pick: string
+            omit: string
+            partial: string
+            required: string
+          },
+        ]
+    >
     createdAt: string
     updatedAt?: string
     type:
@@ -302,7 +362,67 @@ export type MessageDetail = {
   id: string
   object: 'message'
   content: string
-  experimental_content?: Array<unknown[] | unknown[]>
+  experimental_content?: Array<
+    | [0, unknown[]]
+    | [
+        1,
+        {
+          '~standard': string
+          def: string
+          type: string
+          check: string
+          clone: string
+          brand: string
+          register: string
+          parse: string
+          safeParse: string
+          parseAsync: string
+          safeParseAsync: string
+          spa: string
+          encode: string
+          decode: string
+          encodeAsync: string
+          decodeAsync: string
+          safeEncode: string
+          safeDecode: string
+          safeEncodeAsync: string
+          safeDecodeAsync: string
+          refine: string
+          superRefine: string
+          overwrite: string
+          optional: string
+          nullable: string
+          nullish: string
+          nonoptional: string
+          array: string
+          or: string
+          and: string
+          transform: string
+          default: string
+          prefault: string
+          catch: string
+          pipe: string
+          readonly: string
+          describe: string
+          meta: string
+          isOptional: string
+          isNullable: string
+          keyof: string
+          catchall: string
+          passthrough: string
+          loose: string
+          strict: string
+          strip: string
+          extend: string
+          safeExtend: string
+          merge: string
+          pick: string
+          omit: string
+          partial: string
+          required: string
+        },
+      ]
+  >
   createdAt: string
   updatedAt?: string
   type:
@@ -349,7 +469,67 @@ export type MessageSummary = {
   id: string
   object: 'message'
   content: string
-  experimental_content?: Array<unknown[] | unknown[]>
+  experimental_content?: Array<
+    | [0, unknown[]]
+    | [
+        1,
+        {
+          '~standard': string
+          def: string
+          type: string
+          check: string
+          clone: string
+          brand: string
+          register: string
+          parse: string
+          safeParse: string
+          parseAsync: string
+          safeParseAsync: string
+          spa: string
+          encode: string
+          decode: string
+          encodeAsync: string
+          decodeAsync: string
+          safeEncode: string
+          safeDecode: string
+          safeEncodeAsync: string
+          safeDecodeAsync: string
+          refine: string
+          superRefine: string
+          overwrite: string
+          optional: string
+          nullable: string
+          nullish: string
+          nonoptional: string
+          array: string
+          or: string
+          and: string
+          transform: string
+          default: string
+          prefault: string
+          catch: string
+          pipe: string
+          readonly: string
+          describe: string
+          meta: string
+          isOptional: string
+          isNullable: string
+          keyof: string
+          catchall: string
+          passthrough: string
+          loose: string
+          strict: string
+          strip: string
+          extend: string
+          safeExtend: string
+          merge: string
+          pick: string
+          omit: string
+          partial: string
+          required: string
+        },
+      ]
+  >
   createdAt: string
   updatedAt?: string
   type:
@@ -397,7 +577,67 @@ export type MessageSummaryList = {
     id: string
     object: 'message'
     content: string
-    experimental_content?: Array<unknown[] | unknown[]>
+    experimental_content?: Array<
+      | [0, unknown[]]
+      | [
+          1,
+          {
+            '~standard': string
+            def: string
+            type: string
+            check: string
+            clone: string
+            brand: string
+            register: string
+            parse: string
+            safeParse: string
+            parseAsync: string
+            safeParseAsync: string
+            spa: string
+            encode: string
+            decode: string
+            encodeAsync: string
+            decodeAsync: string
+            safeEncode: string
+            safeDecode: string
+            safeEncodeAsync: string
+            safeDecodeAsync: string
+            refine: string
+            superRefine: string
+            overwrite: string
+            optional: string
+            nullable: string
+            nullish: string
+            nonoptional: string
+            array: string
+            or: string
+            and: string
+            transform: string
+            default: string
+            prefault: string
+            catch: string
+            pipe: string
+            readonly: string
+            describe: string
+            meta: string
+            isOptional: string
+            isNullable: string
+            keyof: string
+            catchall: string
+            passthrough: string
+            loose: string
+            strict: string
+            strip: string
+            extend: string
+            safeExtend: string
+            merge: string
+            pick: string
+            omit: string
+            partial: string
+            required: string
+          },
+        ]
+    >
     createdAt: string
     updatedAt?: string
     type:

Analysis

SDK generator fails to handle prefixItems causing loss of tuple type information

What fails: The schemaToTypeScript() function in packages/v0-sdk/src/scripts/generate.ts doesn't recognize the JSON Schema 2020-12 prefixItems keyword, causing tuple types to collapse into redundant unions of unknown[].

How to reproduce:

cd packages/v0-sdk
# Check experimental_content type before fix
grep -A2 "experimental_content" src/sdk/v0.ts
# Shows: experimental_content?: Array<unknown[] | unknown[]>

Result: The experimental_content field in MessageDetail, MessageSummary, and ChatDetail types loses tuple structure defined in OpenAPI spec (lines 7218-7300 of openapi.json). The type becomes Array<unknown[] | unknown[]> instead of Array<[0, unknown[]] | [1, { properties... }]>, eliminating discriminator-based type narrowing.

Expected: Generate proper TypeScript tuple types [literal, type] from OpenAPI prefixItems definitions, preserving the discriminated union structure where first element is a literal (0 or 1) that enables type narrowing.

Fix: Added prefixItems handling in the array type generation section and property name quoting for invalid JavaScript identifiers (like ~standard).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant