ts-procedures 7.0.0-beta.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -246,52 +246,24 @@ async function emitRpcRoute(route: RPCHttpRouteDoc, ctx: EmitRouteContext): Prom
246
246
  const responseTypeName = refs['Response'] ?? 'unknown'
247
247
  const scopeStr = Array.isArray(route.scope) ? route.scope.join('-') : route.scope
248
248
 
249
- // Compute the error union once — used for both the .safe return type and
250
- // injectRouteErrors. Use errorUnion !== null (not route.errors?.length) so
251
- // we only emit Result<…, Errors> when keys were actually emitted in _errors.ts.
252
249
  const errorUnion = buildErrorUnion(route.errors, ctx)
253
250
  const hasErrors = errorUnion !== null
254
251
  const errorsRef = ctx.namespaceTypes
255
252
  ? `${ctx.scopePascal}.${pascal}.Errors`
256
253
  : `${pascal}Errors`
257
- const resultType = hasErrors
258
- ? `Result<${responseTypeName}, ${errorsRef}>`
259
- : `ResultNoTyped<${responseTypeName}>`
260
-
261
- // When no typed errors, cast Result<T, never> → ResultNoTyped<T> so consumers
262
- // see the simpler type in their IDE. The cast is safe: Result<T, never> has an
263
- // unreachable `kind: 'typed'` arm that ResultNoTyped intentionally omits.
264
- const safeReturn = hasErrors
265
- ? `return client.safeCall<${responseTypeName}, ${errorsRef}>({`
266
- : `return client.safeCall<${responseTypeName}>({`
267
- const safeResultCast = hasErrors ? '' : ` as Promise<${resultType}>`
254
+ const helperCall = hasErrors
255
+ ? `client.bindCallableTyped<${paramsTypeName}, ${responseTypeName}, ${errorsRef}>`
256
+ : `client.bindCallable<${paramsTypeName}, ${responseTypeName}>`
268
257
 
269
258
  const callable = [
270
259
  ` /** ${route.method.toUpperCase()} ${route.path} */`,
271
- ` ${pascal}: Object.assign(`,
272
- ` function ${pascal}(params: ${paramsTypeName}, options?: ProcedureCallOptions): Promise<${responseTypeName}> {`,
273
- ` return client.call<${responseTypeName}>({`,
274
- ` name: '${pascal}',`,
275
- ` scope: '${scopeStr}',`,
276
- ` path: '${route.path}',`,
277
- ` method: '${route.method}',`,
278
- ` kind: 'rpc',`,
279
- ` params,`,
280
- ` }, options)`,
281
- ` },`,
282
- ` {`,
283
- ` safe(params: ${paramsTypeName}, options?: ProcedureCallOptions): Promise<${resultType}> {`,
284
- ` ${safeReturn}`,
285
- ` name: '${pascal}',`,
286
- ` scope: '${scopeStr}',`,
287
- ` path: '${route.path}',`,
288
- ` method: '${route.method}',`,
289
- ` kind: 'rpc',`,
290
- ` params,`,
291
- ` }, options)${safeResultCast}`,
292
- ` },`,
293
- ` },`,
294
- ` ),`,
260
+ ` ${pascal}: ${helperCall}({`,
261
+ ` name: '${pascal}',`,
262
+ ` scope: '${scopeStr}',`,
263
+ ` path: '${route.path}',`,
264
+ ` method: '${route.method}',`,
265
+ ` kind: 'rpc',`,
266
+ ` }),`,
295
267
  ].join('\n')
296
268
 
297
269
  const hasErrorsInjected = injectRouteErrors(declarations, pascal, errorUnion, ctx.namespaceTypes)
@@ -352,56 +324,25 @@ async function emitApiRoute(route: APIHttpRouteDoc, ctx: EmitRouteContext): Prom
352
324
  const responseTypeName = refs['Response'] ?? 'unknown'
353
325
  const scopeStr = route.scope ?? 'default'
354
326
 
355
- // Compute the error union once — used for both the .safe return type and
356
- // injectRouteErrors. Use errorUnion !== null (not route.errors?.length) so
357
- // we only emit Result<…, Errors> when keys were actually emitted in _errors.ts.
358
327
  const errorUnion = buildErrorUnion(route.errors, ctx)
359
328
  const hasErrors = errorUnion !== null
360
329
  const errorsRef = ctx.namespaceTypes
361
330
  ? `${ctx.scopePascal}.${pascal}.Errors`
362
331
  : `${pascal}Errors`
363
- const resultType = hasErrors
364
- ? `Result<${responseTypeName}, ${errorsRef}>`
365
- : `ResultNoTyped<${responseTypeName}>`
366
-
367
- // When no typed errors, cast Result<T, never> ResultNoTyped<T> so consumers
368
- // see the simpler type in their IDE. The cast is safe: Result<T, never> has an
369
- // unreachable `kind: 'typed'` arm that ResultNoTyped intentionally omits.
370
- const safeReturn = hasErrors
371
- ? `return client.safeCall<${responseTypeName}, ${errorsRef}>({`
372
- : `return client.safeCall<${responseTypeName}>({`
373
- const safeResultCast = hasErrors ? '' : ` as Promise<${resultType}>`
374
-
375
- // Property key uses route.name verbatim (preserving the prior API
376
- // emission contract). Function name uses route.name as well — JS function
377
- // names accept any identifier, and matching the property key avoids any
378
- // surprise asymmetry in stack traces.
332
+ const helperCall = hasErrors
333
+ ? `client.bindCallableTyped<${paramsTypeName}, ${responseTypeName}, ${errorsRef}>`
334
+ : `client.bindCallable<${paramsTypeName}, ${responseTypeName}>`
335
+
336
+ // Property key uses route.name verbatim (preserving the prior API emission contract).
379
337
  const callable = [
380
338
  ` /** ${route.method.toUpperCase()} ${route.fullPath} */`,
381
- ` ${route.name}: Object.assign(`,
382
- ` function ${route.name}(params: ${paramsTypeName}, options?: ProcedureCallOptions): Promise<${responseTypeName}> {`,
383
- ` return client.call<${responseTypeName}>({`,
384
- ` name: '${route.name}',`,
385
- ` scope: '${scopeStr}',`,
386
- ` path: '${route.fullPath}',`,
387
- ` method: '${route.method}',`,
388
- ` kind: 'api',`,
389
- ` params,`,
390
- ` }, options)`,
391
- ` },`,
392
- ` {`,
393
- ` safe(params: ${paramsTypeName}, options?: ProcedureCallOptions): Promise<${resultType}> {`,
394
- ` ${safeReturn}`,
395
- ` name: '${route.name}',`,
396
- ` scope: '${scopeStr}',`,
397
- ` path: '${route.fullPath}',`,
398
- ` method: '${route.method}',`,
399
- ` kind: 'api',`,
400
- ` params,`,
401
- ` }, options)${safeResultCast}`,
402
- ` },`,
403
- ` },`,
404
- ` ),`,
339
+ ` ${route.name}: ${helperCall}({`,
340
+ ` name: '${route.name}',`,
341
+ ` scope: '${scopeStr}',`,
342
+ ` path: '${route.fullPath}',`,
343
+ ` method: '${route.method}',`,
344
+ ` kind: 'api',`,
345
+ ` }),`,
405
346
  ].join('\n')
406
347
 
407
348
  const hasErrorsInjected = injectRouteErrors(declarations, pascal, errorUnion, ctx.namespaceTypes)
@@ -518,10 +459,11 @@ export async function emitScopeFile(
518
459
  if (chunks.hasErrors) scopeHasErrors = true
519
460
  }
520
461
 
521
- // Build client import line
462
+ // Build client import line — Result/ResultNoTyped are no longer referenced
463
+ // directly in scope files; the bindCallable helpers infer them from ClientInstance.
522
464
  const clientImports = hasStream
523
- ? `import type { ClientInstance, ProcedureCallOptions, TypedStream, Result, ResultNoTyped } from '${clientImportPath}'`
524
- : `import type { ClientInstance, ProcedureCallOptions, Result, ResultNoTyped } from '${clientImportPath}'`
465
+ ? `import type { ClientInstance, ProcedureCallOptions, TypedStream } from '${clientImportPath}'`
466
+ : `import type { ClientInstance, ProcedureCallOptions } from '${clientImportPath}'`
525
467
 
526
468
  // Build _errors import line when at least one route emits an Errors union.
527
469
  // Namespace mode uses the qualified `${Service}Errors` namespace; flat mode