-
Notifications
You must be signed in to change notification settings - Fork 56
chore: update SDK from OpenAPI spec #67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
11a0d40
to
6d9c9c9
Compare
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| { | ||
notifications: 'live-activity' | 'push-notifications' | 'none' | ||
} | ||
| unknown |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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'
6d9c9c9
to
9cc0553
Compare
9cc0553
to
b05a2d6
Compare
b05a2d6
to
bf90f42
Compare
bf90f42
to
0983303
Compare
0983303
to
b5092b4
Compare
export interface DeploymentsFindLogsResponse { | ||
error?: string | ||
logs: string[] | ||
export type DeploymentsFindLogsResponse = { |
There was a problem hiding this comment.
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
b5092b4
to
42c4fca
Compare
42c4fca
to
8faabdb
Compare
8faabdb
to
8594983
Compare
}, | ||
] | ||
> | ||
experimental_content?: Array<unknown[] | unknown[]> |
There was a problem hiding this comment.
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
).
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.