Implement int64/uint64 encoding support in ts-client and openapiv3 generators. TypeScript types and OpenAPI schemas must accurately reflect the configured encoding.

Purpose: Ensure TypeScript clients and API documentation match the actual JSON format produced by Go servers. When int64 is encoded as NUMBER, TypeScript should use 'number' type and OpenAPI should document it as integer.

Output: ts-client generates correct TypeScript types based on encoding annotation. OpenAPI generates correct schemas with appropriate type and precision warnings.

<execution_context> @/Users/sebastienmelki/.claude/get-shit-done/workflows/execute-plan.md @/Users/sebastienmelki/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/phases/04-json-primitive-encoding/04-CONTEXT.md @.planning/phases/04-json-primitive-encoding/04-RESEARCH.md @.planning/phases/04-json-primitive-encoding/04-01-SUMMARY.md

Generator code to modify

@internal/tsclientgen/types.go @internal/tsclientgen/generator.go @internal/openapiv3/types.go @internal/openapiv3/generator.go

Annotation package from Plan 01#

@internal/annotations/int64_encoding.go

Task 1: Implement int64 encoding in ts-client generator internal/tsclientgen/types.go internal/tsclientgen/generator.go Modify internal/tsclientgen/types.go to check int64_encoding annotation:
  1. Update tsScalarType function to accept *protogen.Field instead of just protoreflect.Kind:

    • Current: func tsScalarType(kind protoreflect.Kind) string
    • New: func tsScalarTypeForField(field *protogen.Field) string
    • Keep tsScalarType as internal helper that tsScalarTypeForField calls
  2. For int64/uint64 kinds, check annotation:

case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind,
     protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
    if annotations.IsInt64NumberEncoding(field) {
        return tsNumber // "number" - precision risk but matches JSON
    }
    return tsString // default: "string" per proto3 JSON spec
  1. Update callers of tsScalarType to use tsScalarTypeForField where field context is available

  2. Update tsZeroCheck for NUMBER encoding:

case "int64", "sint64", "sfixed64", "uint64", "fixed64":
    // Check if NUMBER encoding - zero check is different
    // STRING: ' !== "0"'
    // NUMBER: ' !== 0'
    // Note: Need to pass field or encoding info to tsZeroCheck
  1. Consider adding a comment in generated TypeScript for NUMBER encoding:
export interface Tweet {
  id: number;  // int64 with NUMBER encoding - values > 2^53 may lose precision
  authorId: string;  // int64 with STRING encoding (default)
}
```bash go build ./internal/tsclientgen/... go test -v ./internal/tsclientgen/... ``` Generate TypeScript from test proto and verify: - NUMBER encoded int64 -> `number` type - STRING/UNSPECIFIED int64 -> `string` type - tsScalarTypeForField checks int64_encoding annotation - NUMBER encoding produces TypeScript 'number' type - STRING/UNSPECIFIED produces TypeScript 'string' type - tsZeroCheck handles both encodings correctly - All existing tests pass
Task 2: Implement int64 encoding in OpenAPI generator internal/openapiv3/types.go internal/openapiv3/generator.go Modify internal/openapiv3/types.go convertScalarField function:
  1. For int64/uint64 kinds, check annotation and generate appropriate schema:
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
    if annotations.IsInt64NumberEncoding(field) {
        schema.Type = []string{headerTypeInteger}
        schema.Format = headerTypeInt64
        // Add precision warning to description
        warningDesc := "Warning: Values > 2^53 may lose precision in JavaScript"
        if schema.Description != "" {
            schema.Description = schema.Description + ". " + warningDesc
        } else {
            schema.Description = warningDesc
        }
    } else {
        // Default: string encoding per proto3 JSON spec
        schema.Type = []string{headerTypeString}
        schema.Format = headerTypeInt64
    }
 
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
    if annotations.IsInt64NumberEncoding(field) {
        schema.Type = []string{headerTypeInteger}
        schema.Format = headerTypeUint64
        zero := 0.0
        schema.Minimum = &zero
        // Add precision warning
        warningDesc := "Warning: Values > 2^53 may lose precision in JavaScript"
        if schema.Description != "" {
            schema.Description = schema.Description + ". " + warningDesc
        } else {
            schema.Description = warningDesc
        }
    } else {
        // Default: string encoding per proto3 JSON spec
        schema.Type = []string{headerTypeString}
        schema.Format = headerTypeUint64
    }
  1. Verify OpenAPI output matches expected format from RESEARCH.md:

NUMBER encoding:

id:
  type: integer
  format: int64
  description: "Warning: Values > 2^53 may lose precision in JavaScript"

STRING encoding (default):

id:
  type: string
  format: int64
```bash go build ./internal/openapiv3/... go test -v ./internal/openapiv3/... ``` Generate OpenAPI from test proto and verify: - NUMBER: type=integer, format=int64, precision warning in description - STRING: type=string, format=int64 - convertScalarField checks int64_encoding annotation - NUMBER encoding produces type:integer format:int64 with warning - STRING/UNSPECIFIED produces type:string format:int64 - Warning description appended for NUMBER encoding - All existing tests pass
Task 3: Add golden file tests for ts-client and OpenAPI int64 encoding internal/tsclientgen/testdata/encoding.proto internal/tsclientgen/testdata/golden/encoding_client.ts internal/openapiv3/testdata/encoding.proto internal/openapiv3/testdata/golden/EncodingTestService.openapi.yaml Create test protos and golden files:
  1. For ts-client (symlink or copy from httpgen testdata):
# If using symlinks like other testdata
ln -sf ../../httpgen/testdata/encoding.proto internal/tsclientgen/testdata/encoding.proto

Or create internal/tsclientgen/testdata/encoding.proto with int64_encoding annotations.

  1. For openapiv3, create internal/openapiv3/testdata/encoding.proto (or symlink).

  2. Run golden file tests with UPDATE_GOLDEN:

UPDATE_GOLDEN=1 go test -run TestGoldenFiles ./internal/tsclientgen/...
UPDATE_GOLDEN=1 go test -run TestExhaustiveGoldenFiles ./internal/openapiv3/...
  1. Verify golden files contain expected patterns:

TypeScript golden (encoding_client.ts):

export interface Int64EncodingTest {
  defaultInt64: string;      // default -> string
  stringInt64: string;       // explicit STRING -> string
  numberInt64: number;       // NUMBER -> number
  defaultUint64: string;     // default -> string
  numberUint64: number;      // NUMBER -> number
  repeatedNumberInt64: number[];  // repeated NUMBER -> number[]
}

OpenAPI golden (EncodingTestService.openapi.yaml):

Int64EncodingTest:
  type: object
  properties:
    defaultInt64:
      type: string
      format: int64
    numberInt64:
      type: integer
      format: int64
      description: "Warning: Values > 2^53 may lose precision in JavaScript"
```bash go test -v -run Golden ./internal/tsclientgen/... go test -v -run Golden ./internal/openapiv3/... make lint-fix ``` All golden tests pass without UPDATE_GOLDEN flag. - Test protos with int64_encoding exist in tsclientgen and openapiv3 testdata - ts-client golden shows number/string types based on encoding - OpenAPI golden shows integer/string types based on encoding - OpenAPI golden includes precision warning for NUMBER - All golden tests pass
1. Build passes: `go build ./...` 2. All tests pass: `go test ./...` 3. Lint clean: `make lint-fix` 4. Golden files updated and committed 5. TypeScript types match server JSON format 6. OpenAPI schemas accurately document JSON format

<success_criteria>

  • TypeScript: int64_encoding=NUMBER -> number, STRING/UNSPECIFIED -> string
  • OpenAPI: int64_encoding=NUMBER -> type: integer, STRING/UNSPECIFIED -> type: string
  • OpenAPI NUMBER fields include precision warning in description
  • Cross-generator consistency: TS types match OpenAPI schemas match Go JSON output
  • Backward compatible: protos without annotations produce identical output to before </success_criteria>
After completion, create `.planning/phases/04-json-primitive-encoding/04-03-SUMMARY.md`