@@ -13,6 +13,7 @@ import { FetchingJSONSchemaStore, InputData, JSONSchemaInput, quicktype } from "
1313import { promisify } from "util" ;
1414import {
1515 cloneSchemaForCodegen ,
16+ filterNodeByVisibility ,
1617 fixNullableRequiredRefsInApiSchema ,
1718 getApiSchemaPath ,
1819 getRpcSchemaTypeName ,
@@ -1161,6 +1162,21 @@ async function generateRpc(schemaPath?: string): Promise<void> {
11611162 `// Deprecated: ${ typeName } is deprecated and will be removed in a future version.\n$1`
11621163 ) ;
11631164 }
1165+
1166+ // Annotate internal data types (driven by the JSON Schema definition's
1167+ // `visibility: "internal"` flag, set via `.asInternal()` on the Zod source).
1168+ const internalTypeNames = new Set < string > ( ) ;
1169+ for ( const [ name , def ] of Object . entries ( allDefinitions ) ) {
1170+ if ( def && typeof def === "object" && ( def as Record < string , unknown > ) . visibility === "internal" ) {
1171+ internalTypeNames . add ( name ) ;
1172+ }
1173+ }
1174+ for ( const typeName of internalTypeNames ) {
1175+ qtCode = qtCode . replace (
1176+ new RegExp ( `^(type ${ typeName } struct)` , "m" ) ,
1177+ `// Internal: ${ typeName } is an internal SDK API and is not part of the public surface.\n$1`
1178+ ) ;
1179+ }
11641180 // Remove trailing blank lines from quicktype output before appending
11651181 qtCode = qtCode . replace ( / \n + $ / , "" ) ;
11661182 // Replace interface{} with any (quicktype emits the pre-1.18 form)
@@ -1196,12 +1212,18 @@ async function generateRpc(schemaPath?: string): Promise<void> {
11961212
11971213 // Emit ServerRpc
11981214 if ( schema . server ) {
1199- emitRpcWrapper ( lines , schema . server , false , resolveType , fieldNames ) ;
1215+ const publicNode = filterNodeByVisibility ( schema . server , "public" ) ;
1216+ if ( publicNode ) emitRpcWrapper ( lines , publicNode , false , resolveType , fieldNames , "" ) ;
1217+ const internalNode = filterNodeByVisibility ( schema . server , "internal" ) ;
1218+ if ( internalNode ) emitRpcWrapper ( lines , internalNode , false , resolveType , fieldNames , "Internal" ) ;
12001219 }
12011220
12021221 // Emit SessionRpc
12031222 if ( schema . session ) {
1204- emitRpcWrapper ( lines , schema . session , true , resolveType , fieldNames ) ;
1223+ const publicNode = filterNodeByVisibility ( schema . session , "public" ) ;
1224+ if ( publicNode ) emitRpcWrapper ( lines , publicNode , true , resolveType , fieldNames , "" ) ;
1225+ const internalNode = filterNodeByVisibility ( schema . session , "internal" ) ;
1226+ if ( internalNode ) emitRpcWrapper ( lines , internalNode , true , resolveType , fieldNames , "Internal" ) ;
12051227 }
12061228
12071229 if ( schema . clientSession ) {
@@ -1257,13 +1279,17 @@ function emitApiGroup(
12571279 }
12581280}
12591281
1260- function emitRpcWrapper ( lines : string [ ] , node : Record < string , unknown > , isSession : boolean , resolveType : ( name : string ) => string , fieldNames : Map < string , Map < string , string > > ) : void {
1282+ function emitRpcWrapper ( lines : string [ ] , node : Record < string , unknown > , isSession : boolean , resolveType : ( name : string ) => string , fieldNames : Map < string , Map < string , string > > , classPrefix : string = "" ) : void {
12611283 const groups = Object . entries ( node ) . filter ( ( [ , v ] ) => typeof v === "object" && v !== null && ! isRpcMethod ( v ) ) ;
12621284 const topLevelMethods = Object . entries ( node ) . filter ( ( [ , v ] ) => isRpcMethod ( v ) ) ;
12631285
1264- const wrapperName = isSession ? "SessionRpc" : "ServerRpc" ;
1286+ const wrapperName = classPrefix + ( isSession ? "SessionRpc" : "ServerRpc" ) ;
12651287 const apiSuffix = "Api" ;
1266- const serviceName = isSession ? "sessionApi" : "serverApi" ;
1288+ // Lowercase the prefix so the unexported service struct stays unexported in Go.
1289+ const prefixLower = classPrefix ? classPrefix . charAt ( 0 ) . toLowerCase ( ) + classPrefix . slice ( 1 ) : "" ;
1290+ const serviceName = prefixLower
1291+ ? prefixLower + ( isSession ? "SessionApi" : "ServerApi" )
1292+ : ( isSession ? "sessionApi" : "serverApi" ) ;
12671293
12681294 // Emit the common service struct (unexported, shared by all API groups via type cast)
12691295 lines . push ( `type ${ serviceName } struct {` ) ;
@@ -1274,7 +1300,7 @@ function emitRpcWrapper(lines: string[], node: Record<string, unknown>, isSessio
12741300
12751301 // Emit API types for groups
12761302 for ( const [ groupName , groupNode ] of groups ) {
1277- const prefix = isSession ? "" : "Server" ;
1303+ const prefix = classPrefix + ( isSession ? "" : "Server" ) ;
12781304 const apiName = prefix + toPascalCase ( groupName ) + apiSuffix ;
12791305 const groupExperimental = isNodeFullyExperimental ( groupNode as Record < string , unknown > ) ;
12801306 const groupDeprecated = isNodeFullyDeprecated ( groupNode as Record < string , unknown > ) ;
@@ -1288,12 +1314,14 @@ function emitRpcWrapper(lines: string[], node: Record<string, unknown>, isSessio
12881314 const pad = ( name : string ) => name . padEnd ( maxFieldLen ) ;
12891315
12901316 // Emit wrapper struct
1291- lines . push ( `// ${ wrapperName } provides typed ${ isSession ? "session" : "server" } -scoped RPC methods.` ) ;
1317+ lines . push ( classPrefix === "Internal"
1318+ ? `// ${ wrapperName } provides internal SDK ${ isSession ? "session" : "server" } -scoped RPC methods (handshake helpers etc.). Not part of the public API.`
1319+ : `// ${ wrapperName } provides typed ${ isSession ? "session" : "server" } -scoped RPC methods.` ) ;
12921320 lines . push ( `type ${ wrapperName } struct {` ) ;
12931321 lines . push ( `\t${ pad ( "common" ) } ${ serviceName } // Reuse a single struct instead of allocating one for each service on the heap.` ) ;
12941322 lines . push ( `` ) ;
12951323 for ( const [ groupName ] of groups ) {
1296- const prefix = isSession ? "" : "Server" ;
1324+ const prefix = classPrefix + ( isSession ? "" : "Server" ) ;
12971325 lines . push ( `\t${ pad ( toPascalCase ( groupName ) ) } *${ prefix } ${ toPascalCase ( groupName ) } ${ apiSuffix } ` ) ;
12981326 }
12991327 lines . push ( `}` ) ;
@@ -1315,7 +1343,7 @@ function emitRpcWrapper(lines: string[], node: Record<string, unknown>, isSessio
13151343 lines . push ( `\tr.common = ${ serviceName } {client: client}` ) ;
13161344 }
13171345 for ( const [ groupName ] of groups ) {
1318- const prefix = isSession ? "" : "Server" ;
1346+ const prefix = classPrefix + ( isSession ? "" : "Server" ) ;
13191347 lines . push ( `\tr.${ toPascalCase ( groupName ) } = (*${ prefix } ${ toPascalCase ( groupName ) } ${ apiSuffix } )(&r.common)` ) ;
13201348 }
13211349 lines . push ( `\treturn r` ) ;
@@ -1348,6 +1376,9 @@ function emitMethod(lines: string[], receiver: string, name: string, method: Rpc
13481376 if ( method . stability === "experimental" && ! groupExperimental ) {
13491377 lines . push ( `// Experimental: ${ methodName } is an experimental API and may change or be removed in future versions.` ) ;
13501378 }
1379+ if ( method . visibility === "internal" ) {
1380+ lines . push ( `// Internal: ${ methodName } is part of the SDK's internal handshake/plumbing; external callers should not use it.` ) ;
1381+ }
13511382 const sig = hasParams
13521383 ? `func (a *${ receiver } ) ${ methodName } (ctx context.Context, params *${ paramsType } ) (*${ resultType } , error)`
13531384 : `func (a *${ receiver } ) ${ methodName } (ctx context.Context) (*${ resultType } , error)` ;
0 commit comments