orpc-fn 0.1.0 → 0.2.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.
Files changed (141) hide show
  1. package/README.md +48 -32
  2. package/dist/assemble-procedure.d.ts +13 -0
  3. package/dist/assemble-procedure.d.ts.map +1 -0
  4. package/dist/assemble-procedure.js +29 -0
  5. package/dist/assemble-procedure.js.map +1 -0
  6. package/dist/bound-call.d.ts +1 -1
  7. package/dist/bound-call.d.ts.map +1 -1
  8. package/dist/bound-call.js.map +1 -1
  9. package/dist/client.d.ts +4 -2
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +4 -2
  12. package/dist/client.js.map +1 -1
  13. package/dist/compatibility.d.ts +16 -0
  14. package/dist/compatibility.d.ts.map +1 -0
  15. package/dist/compatibility.js +4 -0
  16. package/dist/compatibility.js.map +1 -0
  17. package/dist/create-fn.d.ts +30 -34
  18. package/dist/create-fn.d.ts.map +1 -1
  19. package/dist/create-fn.js +177 -121
  20. package/dist/create-fn.js.map +1 -1
  21. package/dist/expo.d.ts +11 -25
  22. package/dist/expo.d.ts.map +1 -1
  23. package/dist/expo.js +25 -30
  24. package/dist/expo.js.map +1 -1
  25. package/dist/hono.d.ts +12 -4
  26. package/dist/hono.d.ts.map +1 -1
  27. package/dist/hono.js +29 -12
  28. package/dist/hono.js.map +1 -1
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -2
  32. package/dist/index.js.map +1 -1
  33. package/dist/json-schema.d.ts +2 -0
  34. package/dist/json-schema.d.ts.map +1 -1
  35. package/dist/json-schema.js +11 -0
  36. package/dist/json-schema.js.map +1 -1
  37. package/dist/live/codec.d.ts +6 -1
  38. package/dist/live/codec.d.ts.map +1 -1
  39. package/dist/live/codec.js +14 -3
  40. package/dist/live/codec.js.map +1 -1
  41. package/dist/live/fn-live.d.ts +63 -22
  42. package/dist/live/fn-live.d.ts.map +1 -1
  43. package/dist/live/fn-live.js +98 -16
  44. package/dist/live/fn-live.js.map +1 -1
  45. package/dist/live/index.d.ts +1 -1
  46. package/dist/live/index.d.ts.map +1 -1
  47. package/dist/live/index.js.map +1 -1
  48. package/dist/live/ioredis.d.ts +4 -1
  49. package/dist/live/ioredis.d.ts.map +1 -1
  50. package/dist/live/ioredis.js +21 -2
  51. package/dist/live/ioredis.js.map +1 -1
  52. package/dist/live/lifecycle.d.ts +7 -0
  53. package/dist/live/lifecycle.d.ts.map +1 -0
  54. package/dist/live/lifecycle.js +36 -0
  55. package/dist/live/lifecycle.js.map +1 -0
  56. package/dist/live/memory.d.ts.map +1 -1
  57. package/dist/live/memory.js +4 -0
  58. package/dist/live/memory.js.map +1 -1
  59. package/dist/live/pub-sub.d.ts +76 -12
  60. package/dist/live/pub-sub.d.ts.map +1 -1
  61. package/dist/live/pub-sub.js +429 -125
  62. package/dist/live/pub-sub.js.map +1 -1
  63. package/dist/live/redis-bun.d.ts +1 -1
  64. package/dist/live/redis-bun.d.ts.map +1 -1
  65. package/dist/live/redis-bun.js +3 -5
  66. package/dist/live/redis-bun.js.map +1 -1
  67. package/dist/live/redis.d.ts +2 -2
  68. package/dist/live/redis.d.ts.map +1 -1
  69. package/dist/live/redis.js +36 -9
  70. package/dist/live/redis.js.map +1 -1
  71. package/dist/live/transport.d.ts +5 -1
  72. package/dist/live/transport.d.ts.map +1 -1
  73. package/dist/live/transport.js.map +1 -1
  74. package/dist/logger.d.ts +2 -0
  75. package/dist/logger.d.ts.map +1 -1
  76. package/dist/logger.js +21 -0
  77. package/dist/logger.js.map +1 -1
  78. package/dist/mastra.d.ts.map +1 -1
  79. package/dist/mastra.js +16 -7
  80. package/dist/mastra.js.map +1 -1
  81. package/dist/mcp/sdk.d.ts +20 -0
  82. package/dist/mcp/sdk.d.ts.map +1 -0
  83. package/dist/mcp/sdk.js +82 -0
  84. package/dist/mcp/sdk.js.map +1 -0
  85. package/dist/mcp.d.ts +3 -2
  86. package/dist/mcp.d.ts.map +1 -1
  87. package/dist/mcp.js +22 -7
  88. package/dist/mcp.js.map +1 -1
  89. package/dist/meta.d.ts +15 -7
  90. package/dist/meta.d.ts.map +1 -1
  91. package/dist/meta.js +9 -2
  92. package/dist/meta.js.map +1 -1
  93. package/dist/otel.d.ts.map +1 -1
  94. package/dist/otel.js +77 -6
  95. package/dist/otel.js.map +1 -1
  96. package/dist/route-options.d.ts +22 -0
  97. package/dist/route-options.d.ts.map +1 -0
  98. package/dist/route-options.js +67 -0
  99. package/dist/route-options.js.map +1 -0
  100. package/dist/router.d.ts +5 -1
  101. package/dist/router.d.ts.map +1 -1
  102. package/dist/router.js +22 -0
  103. package/dist/router.js.map +1 -1
  104. package/dist/timing.d.ts +8 -0
  105. package/dist/timing.d.ts.map +1 -0
  106. package/dist/timing.js +4 -0
  107. package/dist/timing.js.map +1 -0
  108. package/dist/types.d.ts +86 -41
  109. package/dist/types.d.ts.map +1 -1
  110. package/dist/types.js +6 -2
  111. package/dist/types.js.map +1 -1
  112. package/package.json +15 -3
  113. package/src/assemble-procedure.ts +42 -0
  114. package/src/bound-call.ts +4 -3
  115. package/src/client.ts +9 -2
  116. package/src/compatibility.ts +39 -0
  117. package/src/create-fn.ts +297 -183
  118. package/src/expo.ts +49 -44
  119. package/src/hono.ts +36 -17
  120. package/src/index.ts +6 -2
  121. package/src/json-schema.ts +16 -0
  122. package/src/live/codec.ts +22 -3
  123. package/src/live/fn-live.ts +244 -69
  124. package/src/live/index.ts +2 -0
  125. package/src/live/ioredis.ts +22 -2
  126. package/src/live/lifecycle.ts +44 -0
  127. package/src/live/memory.ts +4 -0
  128. package/src/live/pub-sub.ts +608 -166
  129. package/src/live/redis-bun.ts +7 -5
  130. package/src/live/redis.ts +37 -11
  131. package/src/live/transport.ts +4 -1
  132. package/src/logger.ts +20 -0
  133. package/src/mastra.ts +15 -7
  134. package/src/mcp/sdk.ts +118 -0
  135. package/src/mcp.ts +48 -20
  136. package/src/meta.ts +40 -24
  137. package/src/otel.ts +77 -10
  138. package/src/route-options.ts +100 -0
  139. package/src/router.ts +39 -1
  140. package/src/timing.ts +5 -0
  141. package/src/types.ts +204 -62
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,OAAe,EAAE,UAA0B,EAAE,EAAE,CAC7E,IAAI,KAAK,KAAK,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;AAE7E;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAChD,OAAO;QACN,KAAK,KAAI,CAAC;QACV,IAAI,KAAI,CAAC;QACT,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,CAC7B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACjD,KAAK,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,CAC9B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;KAClD,CAAA;AACF,CAAC","sourcesContent":["export type LogAttributes = Record<string, unknown>\n\n/** The logger handlers receive. Any app logger with these four methods fits. */\nexport interface FnLogger {\n\tdebug(message: string, attributes?: LogAttributes): void\n\tinfo(message: string, attributes?: LogAttributes): void\n\twarn(message: string, attributes?: LogAttributes): void\n\terror(message: string, attributes?: LogAttributes): void\n}\n\nconst format = (scope: string, message: string, attributes?: LogAttributes) =>\n\t`[${scope}] ${message}${attributes ? ` ${JSON.stringify(attributes)}` : ''}`\n\n/**\n * Default logger: silent for `debug`/`info`, console for `warn`/`error`, so a\n * library default never floods stdout with one line per call. Inject your own\n * with `createFn({ logger })`.\n */\nexport function createDefaultLogger(scope: string): FnLogger {\n\treturn {\n\t\tdebug() {},\n\t\tinfo() {},\n\t\twarn: (message, attributes) =>\n\t\t\tconsole.warn(format(scope, message, attributes)),\n\t\terror: (message, attributes) =>\n\t\t\tconsole.error(format(scope, message, attributes))\n\t}\n}\n"]}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,OAAe,EAAE,UAA0B,EAAE,EAAE,CAC7E,IAAI,KAAK,KAAK,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;AAE7E;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAChD,OAAO;QACN,KAAK,KAAI,CAAC;QACV,IAAI,KAAI,CAAC;QACT,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,CAC7B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QACjD,KAAK,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,CAC9B,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;KAClD,CAAA;AACF,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,aAAa,CAAqB,MAAS;IAC1D,OAAO,IAAI,KAAK,CAAC,MAAM,EAAE;QACxB,GAAG,CAAC,MAAM,EAAE,GAAG;YACd,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAA;YAC9C,IAAI,OAAO,KAAK,KAAK,UAAU;gBAAE,OAAO,KAAK,CAAA;YAC7C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBAC9D,OAAO,CAAC,GAAG,IAAe,EAAE,EAAE;oBAC7B,IAAI,CAAC;wBACJ,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;oBACjC,CAAC;oBAAC,MAAM,CAAC;wBACR,qDAAqD;oBACtD,CAAC;gBACF,CAAC,CAAA;YACF,CAAC;YACD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC1B,CAAC;KACD,CAAC,CAAA;AACH,CAAC","sourcesContent":["export type LogAttributes = Record<string, unknown>\n\n/** The logger handlers receive. Any app logger with these four methods fits. */\nexport interface FnLogger {\n\tdebug(message: string, attributes?: LogAttributes): void\n\tinfo(message: string, attributes?: LogAttributes): void\n\twarn(message: string, attributes?: LogAttributes): void\n\terror(message: string, attributes?: LogAttributes): void\n}\n\nconst format = (scope: string, message: string, attributes?: LogAttributes) =>\n\t`[${scope}] ${message}${attributes ? ` ${JSON.stringify(attributes)}` : ''}`\n\n/**\n * Default logger: silent for `debug`/`info`, console for `warn`/`error`, so a\n * library default never floods stdout with one line per call. Inject your own\n * with `createFn({ logger })`.\n */\nexport function createDefaultLogger(scope: string): FnLogger {\n\treturn {\n\t\tdebug() {},\n\t\tinfo() {},\n\t\twarn: (message, attributes) =>\n\t\t\tconsole.warn(format(scope, message, attributes)),\n\t\terror: (message, attributes) =>\n\t\t\tconsole.error(format(scope, message, attributes))\n\t}\n}\n\n/** Protect telemetry calls while preserving application logger extensions. */\nexport function protectLogger<T extends FnLogger>(logger: T): T {\n\treturn new Proxy(logger, {\n\t\tget(target, key) {\n\t\t\tconst value = Reflect.get(target, key, target)\n\t\t\tif (typeof value !== 'function') return value\n\t\t\tif (['debug', 'info', 'warn', 'error'].includes(String(key))) {\n\t\t\t\treturn (...args: unknown[]) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\treturn value.apply(target, args)\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t/* Telemetry must not replace a procedure outcome. */\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn value.bind(target)\n\t\t}\n\t})\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"mastra.d.ts","sourceRoot":"","sources":["../src/mastra.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,KAAK,YAAY,EAAQ,MAAM,cAAc,CAAA;AAMtD,OAAO,EAAc,UAAU,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjE,OAAO,EAAE,UAAU,EAAE,CAAA;AAErB,MAAM,MAAM,uBAAuB,GAAG;IACrC,kEAAkE;IAClE,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;OAGG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE;QACzB,MAAM,EAAE,MAAM,CAAA;QACd,UAAU,EAAE,MAAM,CAAA;QAClB,OAAO,EAAE,SAAS,GAAG,OAAO,CAAA;KAC5B,KAAK,IAAI,CAAA;IACV,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,gFAAgF;AAChF,MAAM,MAAM,eAAe,CAAC,KAAK,IAChC,OAAO,SAAS,cAAc,CAAC,KAAK,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GACrB,cAAc,CAAC,KAAK,CAAC,CAAA;AAEzB,0EAA0E;AAC1E,MAAM,MAAM,UAAU,CAAC,KAAK,SAAS,YAAY,IAAI,IAAI,CACxD,eAAe,CAAC,KAAK,CAAC,EACtB,eAAe,CAAC,KAAK,CAAC,CACtB,CAAA;AAED,4EAA4E;AAC5E,KAAK,gBAAgB,CAAC,KAAK,IAC1B,eAAe,CAAC,KAAK,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnD,OAAO,GACP;IAAE,8CAA8C,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;CAAE,CAAA;AAE7E;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,YAAY,EAC1D,SAAS,EAAE,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,EAC1C,OAAO,GAAE,uBAA4B,GACnC,UAAU,CAAC,KAAK,CAAC,CA2EnB"}
1
+ {"version":3,"file":"mastra.d.ts","sourceRoot":"","sources":["../src/mastra.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,KAAK,YAAY,EAAQ,MAAM,cAAc,CAAA;AAOtD,OAAO,EAAc,UAAU,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjE,OAAO,EAAE,UAAU,EAAE,CAAA;AAErB,MAAM,MAAM,uBAAuB,GAAG;IACrC,kEAAkE;IAClE,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,2DAA2D;IAC3D,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;OAGG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE;QACzB,MAAM,EAAE,MAAM,CAAA;QACd,UAAU,EAAE,MAAM,CAAA;QAClB,OAAO,EAAE,SAAS,GAAG,OAAO,CAAA;KAC5B,KAAK,IAAI,CAAA;IACV,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,gFAAgF;AAChF,MAAM,MAAM,eAAe,CAAC,KAAK,IAChC,OAAO,SAAS,cAAc,CAAC,KAAK,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GACrB,cAAc,CAAC,KAAK,CAAC,CAAA;AAEzB,0EAA0E;AAC1E,MAAM,MAAM,UAAU,CAAC,KAAK,SAAS,YAAY,IAAI,IAAI,CACxD,eAAe,CAAC,KAAK,CAAC,EACtB,eAAe,CAAC,KAAK,CAAC,CACtB,CAAA;AAED,4EAA4E;AAC5E,KAAK,gBAAgB,CAAC,KAAK,IAC1B,eAAe,CAAC,KAAK,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnD,OAAO,GACP;IAAE,8CAA8C,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;CAAE,CAAA;AAE7E;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,YAAY,EAC1D,SAAS,EAAE,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,EAC1C,OAAO,GAAE,uBAA4B,GACnC,UAAU,CAAC,KAAK,CAAC,CAkFnB"}
package/dist/mastra.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createTool } from '@mastra/core/tools';
2
2
  import { call } from '@orpc/server';
3
- import { passThroughOutputSchema, rawInputSchema } from './json-schema.js';
3
+ import { isObjectJsonSchema, passThroughOutputSchema, rawInputSchema } from './json-schema.js';
4
4
  import { readFnMeta, toToolName } from './meta.js';
5
5
  export { toToolName };
6
6
  /**
@@ -14,6 +14,8 @@ export { toToolName };
14
14
  */
15
15
  export function createMastraTool(procedure, options = {}) {
16
16
  const meta = readFnMeta(procedure);
17
+ if (meta.stream)
18
+ throw new TypeError('orpc-fn: streaming procedures cannot be Mastra tools');
17
19
  const name = options.id ?? meta.name;
18
20
  if (!name) {
19
21
  throw new Error('Procedure must be created with fn() to use createMastraTool');
@@ -21,7 +23,7 @@ export function createMastraTool(procedure, options = {}) {
21
23
  let inputSchema;
22
24
  if (meta.inputSchema) {
23
25
  inputSchema = rawInputSchema(meta.inputSchema);
24
- if (inputSchema['~standard'].jsonSchema.input().type !== 'object') {
26
+ if (!isObjectJsonSchema(inputSchema['~standard'].jsonSchema.input())) {
25
27
  throw new Error(`${name} must take an object input to be an agent tool`);
26
28
  }
27
29
  }
@@ -56,11 +58,18 @@ export function createMastraTool(procedure, options = {}) {
56
58
  throw new Error(`createMastraTool execution requires ${contextKey} in the Mastra request context`);
57
59
  }
58
60
  const startedAt = performance.now();
59
- const finish = (outcome) => options.onExecuteFinish?.({
60
- toolId: id,
61
- durationMs: performance.now() - startedAt,
62
- outcome
63
- });
61
+ const finish = (outcome) => {
62
+ try {
63
+ options.onExecuteFinish?.({
64
+ toolId: id,
65
+ durationMs: performance.now() - startedAt,
66
+ outcome
67
+ });
68
+ }
69
+ catch {
70
+ /* A telemetry hook cannot change tool execution. */
71
+ }
72
+ };
64
73
  try {
65
74
  const result = await call(procedure, meta.inputSchema ? input : undefined, ctx?.abortSignal ? { context, signal: ctx.abortSignal } : { context });
66
75
  finish('success');
@@ -1 +1 @@
1
- {"version":3,"file":"mastra.js","sourceRoot":"","sources":["../src/mastra.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RequestContext } from '@mastra/core/request-context'\nimport { createTool, type Tool } from '@mastra/core/tools'\nimport { type AnyProcedure, call } from '@orpc/server'\nimport {\n\tpassThroughOutputSchema,\n\trawInputSchema,\n\ttype ToolSchema\n} from './json-schema.js'\nimport { readFnMeta, toToolName } from './meta.js'\nimport type { ProcedureInput, ProcedureOutput } from './types.js'\n\nexport { toToolName }\n\nexport type CreateMastraToolOptions = {\n\t/** Override the tool id (defaults to the sanitized `fn` name). */\n\tid?: string\n\t/** Override the tool description (defaults to the route summary). */\n\tdescription?: string\n\t/** Gate execution behind the AI SDK tool-approval flow. */\n\trequireApproval?: boolean\n\t/**\n\t * Accept a procedure without an input schema (the tool then takes an empty\n\t * object). For no-input queries like `teams.list`.\n\t */\n\tallowMissingInputSchema?: boolean\n\tonExecuteFinish?: (event: {\n\t\ttoolId: string\n\t\tdurationMs: number\n\t\toutcome: 'success' | 'error'\n\t}) => void\n\t/** Key holding the oRPC context in Mastra's `RequestContext`. Default 'orpcContext'. */\n\tcontextKey?: string\n}\n\n/** What the tool takes: the procedure's raw input, or `{}` without a schema. */\nexport type MastraToolInput<TProc> =\n\tunknown extends ProcedureInput<TProc>\n\t\t? Record<string, never>\n\t\t: ProcedureInput<TProc>\n\n/** A Mastra tool typed by the procedure's raw input and parsed output. */\nexport type MastraTool<TProc extends AnyProcedure> = Tool<\n\tMastraToolInput<TProc>,\n\tProcedureOutput<TProc>\n>\n\n/** LLM tool parameters must be an object; other inputs are a type error. */\ntype ObjectInputCheck<TProc> =\n\tMastraToolInput<TProc> extends Record<string, unknown>\n\t\t? unknown\n\t\t: { 'orpc-fn: an agent tool needs an object input': ProcedureInput<TProc> }\n\n/**\n * Creates a Mastra tool from a procedure made with `fn()`. Execution calls\n * the procedure with the oRPC context stored in the Mastra request context\n * (`requestContext.set('orpcContext', context)`), so auth and guards apply.\n *\n * Mastra checks the input against the procedure's schema (with dates coerced\n * from strings) but passes the raw input on for the procedure to parse;\n * the output is the procedure's parsed result, passed through unchanged.\n */\nexport function createMastraTool<TProc extends AnyProcedure>(\n\tprocedure: TProc & ObjectInputCheck<TProc>,\n\toptions: CreateMastraToolOptions = {}\n): MastraTool<TProc> {\n\tconst meta = readFnMeta(procedure)\n\tconst name = options.id ?? meta.name\n\tif (!name) {\n\t\tthrow new Error(\n\t\t\t'Procedure must be created with fn() to use createMastraTool'\n\t\t)\n\t}\n\tlet inputSchema: ToolSchema | undefined\n\tif (meta.inputSchema) {\n\t\tinputSchema = rawInputSchema(meta.inputSchema)\n\t\tif (inputSchema['~standard'].jsonSchema.input().type !== 'object') {\n\t\t\tthrow new Error(`${name} must take an object input to be an agent tool`)\n\t\t}\n\t} else if (!options.allowMissingInputSchema) {\n\t\tthrow new Error(\n\t\t\t`${name} must declare an input schema to be exposed as an agent tool`\n\t\t)\n\t}\n\n\tconst id = options.id ?? toToolName(name)\n\tconst contextKey = options.contextKey ?? 'orpcContext'\n\n\tconst tool = createTool({\n\t\tid,\n\t\tdescription: options.description ?? meta.description,\n\t\trequireApproval: options.requireApproval === true,\n\t\tinputSchema:\n\t\t\tinputSchema ??\n\t\t\t({\n\t\t\t\t'~standard': {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tvendor: 'orpc-fn',\n\t\t\t\t\tvalidate: () => ({ value: {} }),\n\t\t\t\t\tjsonSchema: {\n\t\t\t\t\t\tinput: () => ({ type: 'object', properties: {} }),\n\t\t\t\t\t\toutput: () => ({ type: 'object', properties: {} })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} satisfies ToolSchema),\n\t\t...(meta.outputSchema\n\t\t\t? { outputSchema: passThroughOutputSchema(meta.outputSchema) }\n\t\t\t: {}),\n\t\texecute: async (input, ctx) => {\n\t\t\tconst requestContext = ctx?.requestContext as RequestContext | undefined\n\t\t\tconst context = requestContext?.get(contextKey)\n\t\t\tif (!context) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`createMastraTool execution requires ${contextKey} in the Mastra request context`\n\t\t\t\t)\n\t\t\t}\n\t\t\tconst startedAt = performance.now()\n\t\t\tconst finish = (outcome: 'success' | 'error') =>\n\t\t\t\toptions.onExecuteFinish?.({\n\t\t\t\t\ttoolId: id,\n\t\t\t\t\tdurationMs: performance.now() - startedAt,\n\t\t\t\t\toutcome\n\t\t\t\t})\n\t\t\ttry {\n\t\t\t\tconst result = await call(\n\t\t\t\t\tprocedure,\n\t\t\t\t\tmeta.inputSchema ? input : undefined,\n\t\t\t\t\tctx?.abortSignal ? { context, signal: ctx.abortSignal } : { context }\n\t\t\t\t)\n\t\t\t\tfinish('success')\n\t\t\t\treturn result\n\t\t\t} catch (error) {\n\t\t\t\tfinish('error')\n\t\t\t\tthrow error\n\t\t\t}\n\t\t}\n\t})\n\n\t// The runtime schemas are untyped `ToolSchema`s; `MastraTool` is the typed surface.\n\treturn tool as unknown as MastraTool<TProc>\n}\n"]}
1
+ {"version":3,"file":"mastra.js","sourceRoot":"","sources":["../src/mastra.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RequestContext } from '@mastra/core/request-context'\nimport { createTool, type Tool } from '@mastra/core/tools'\nimport { type AnyProcedure, call } from '@orpc/server'\nimport {\n\tisObjectJsonSchema,\n\tpassThroughOutputSchema,\n\trawInputSchema,\n\ttype ToolSchema\n} from './json-schema.js'\nimport { readFnMeta, toToolName } from './meta.js'\nimport type { ProcedureInput, ProcedureOutput } from './types.js'\n\nexport { toToolName }\n\nexport type CreateMastraToolOptions = {\n\t/** Override the tool id (defaults to the sanitized `fn` name). */\n\tid?: string\n\t/** Override the tool description (defaults to the route summary). */\n\tdescription?: string\n\t/** Gate execution behind the AI SDK tool-approval flow. */\n\trequireApproval?: boolean\n\t/**\n\t * Accept a procedure without an input schema (the tool then takes an empty\n\t * object). For no-input queries like `teams.list`.\n\t */\n\tallowMissingInputSchema?: boolean\n\tonExecuteFinish?: (event: {\n\t\ttoolId: string\n\t\tdurationMs: number\n\t\toutcome: 'success' | 'error'\n\t}) => void\n\t/** Key holding the oRPC context in Mastra's `RequestContext`. Default 'orpcContext'. */\n\tcontextKey?: string\n}\n\n/** What the tool takes: the procedure's raw input, or `{}` without a schema. */\nexport type MastraToolInput<TProc> =\n\tunknown extends ProcedureInput<TProc>\n\t\t? Record<string, never>\n\t\t: ProcedureInput<TProc>\n\n/** A Mastra tool typed by the procedure's raw input and parsed output. */\nexport type MastraTool<TProc extends AnyProcedure> = Tool<\n\tMastraToolInput<TProc>,\n\tProcedureOutput<TProc>\n>\n\n/** LLM tool parameters must be an object; other inputs are a type error. */\ntype ObjectInputCheck<TProc> =\n\tMastraToolInput<TProc> extends Record<string, unknown>\n\t\t? unknown\n\t\t: { 'orpc-fn: an agent tool needs an object input': ProcedureInput<TProc> }\n\n/**\n * Creates a Mastra tool from a procedure made with `fn()`. Execution calls\n * the procedure with the oRPC context stored in the Mastra request context\n * (`requestContext.set('orpcContext', context)`), so auth and guards apply.\n *\n * Mastra checks the input against the procedure's schema (with dates coerced\n * from strings) but passes the raw input on for the procedure to parse;\n * the output is the procedure's parsed result, passed through unchanged.\n */\nexport function createMastraTool<TProc extends AnyProcedure>(\n\tprocedure: TProc & ObjectInputCheck<TProc>,\n\toptions: CreateMastraToolOptions = {}\n): MastraTool<TProc> {\n\tconst meta = readFnMeta(procedure)\n\tif (meta.stream)\n\t\tthrow new TypeError('orpc-fn: streaming procedures cannot be Mastra tools')\n\tconst name = options.id ?? meta.name\n\tif (!name) {\n\t\tthrow new Error(\n\t\t\t'Procedure must be created with fn() to use createMastraTool'\n\t\t)\n\t}\n\tlet inputSchema: ToolSchema | undefined\n\tif (meta.inputSchema) {\n\t\tinputSchema = rawInputSchema(meta.inputSchema)\n\t\tif (!isObjectJsonSchema(inputSchema['~standard'].jsonSchema.input())) {\n\t\t\tthrow new Error(`${name} must take an object input to be an agent tool`)\n\t\t}\n\t} else if (!options.allowMissingInputSchema) {\n\t\tthrow new Error(\n\t\t\t`${name} must declare an input schema to be exposed as an agent tool`\n\t\t)\n\t}\n\n\tconst id = options.id ?? toToolName(name)\n\tconst contextKey = options.contextKey ?? 'orpcContext'\n\n\tconst tool = createTool({\n\t\tid,\n\t\tdescription: options.description ?? meta.description,\n\t\trequireApproval: options.requireApproval === true,\n\t\tinputSchema:\n\t\t\tinputSchema ??\n\t\t\t({\n\t\t\t\t'~standard': {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tvendor: 'orpc-fn',\n\t\t\t\t\tvalidate: () => ({ value: {} }),\n\t\t\t\t\tjsonSchema: {\n\t\t\t\t\t\tinput: () => ({ type: 'object', properties: {} }),\n\t\t\t\t\t\toutput: () => ({ type: 'object', properties: {} })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} satisfies ToolSchema),\n\t\t...(meta.outputSchema\n\t\t\t? { outputSchema: passThroughOutputSchema(meta.outputSchema) }\n\t\t\t: {}),\n\t\texecute: async (input, ctx) => {\n\t\t\tconst requestContext = ctx?.requestContext as RequestContext | undefined\n\t\t\tconst context = requestContext?.get(contextKey)\n\t\t\tif (!context) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`createMastraTool execution requires ${contextKey} in the Mastra request context`\n\t\t\t\t)\n\t\t\t}\n\t\t\tconst startedAt = performance.now()\n\t\t\tconst finish = (outcome: 'success' | 'error') => {\n\t\t\t\ttry {\n\t\t\t\t\toptions.onExecuteFinish?.({\n\t\t\t\t\t\ttoolId: id,\n\t\t\t\t\t\tdurationMs: performance.now() - startedAt,\n\t\t\t\t\t\toutcome\n\t\t\t\t\t})\n\t\t\t\t} catch {\n\t\t\t\t\t/* A telemetry hook cannot change tool execution. */\n\t\t\t\t}\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst result = await call(\n\t\t\t\t\tprocedure,\n\t\t\t\t\tmeta.inputSchema ? input : undefined,\n\t\t\t\t\tctx?.abortSignal ? { context, signal: ctx.abortSignal } : { context }\n\t\t\t\t)\n\t\t\t\tfinish('success')\n\t\t\t\treturn result\n\t\t\t} catch (error) {\n\t\t\t\tfinish('error')\n\t\t\t\tthrow error\n\t\t\t}\n\t\t}\n\t})\n\n\t// The runtime schemas are untyped `ToolSchema`s; `MastraTool` is the typed surface.\n\treturn tool as unknown as MastraTool<TProc>\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { type CallToolResult } from '@modelcontextprotocol/sdk/types.js';
3
+ import { type AnyRouter, type InferRouterInitialContext } from '@orpc/server';
4
+ import { listTools, type McpTool, type ProcedureFilter } from '../mcp.js';
5
+ export type RegisterMcpToolsOptions<R extends AnyRouter> = {
6
+ /** Tool exposure must be an explicit application choice. */
7
+ filter: ProcedureFilter;
8
+ context: (request: {
9
+ name: string;
10
+ signal: AbortSignal;
11
+ }) => InferRouterInitialContext<R> | Promise<InferRouterInitialContext<R>>;
12
+ readOnly?: ProcedureFilter;
13
+ name?: NonNullable<Parameters<typeof listTools>[1]>['name'];
14
+ formatResult?: (value: unknown, tool: McpTool) => CallToolResult | Promise<CallToolResult>;
15
+ };
16
+ /** Default protocol result: JSON/text. Provide formatResult for other MCP content. */
17
+ export declare function formatMcpResult(value: unknown): CallToolResult;
18
+ /** Register on the SDK's low-level Server, or on McpServer.server. */
19
+ export declare function registerMcpTools<R extends AnyRouter>(server: Pick<Server, 'setRequestHandler'>, router: R, options: RegisterMcpToolsOptions<R>): readonly string[];
20
+ //# sourceMappingURL=sdk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/mcp/sdk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAA;AACvE,OAAO,EAGN,KAAK,cAAc,EACnB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EACN,KAAK,SAAS,EACd,KAAK,yBAAyB,EAE9B,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,SAAS,EAAE,KAAK,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,WAAW,CAAA;AAEzE,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,SAAS,IAAI;IAC1D,4DAA4D;IAC5D,MAAM,EAAE,eAAe,CAAA;IACvB,OAAO,EAAE,CAAC,OAAO,EAAE;QAClB,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,EAAE,WAAW,CAAA;KACnB,KAAK,yBAAyB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1E,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,IAAI,CAAC,EAAE,WAAW,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;IAC3D,YAAY,CAAC,EAAE,CACd,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,OAAO,KACT,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;CAC7C,CAAA;AAED,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAQ9D;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,SAAS,EACnD,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACzC,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GACjC,SAAS,MAAM,EAAE,CAwEnB"}
@@ -0,0 +1,82 @@
1
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
2
+ import { call } from '@orpc/server';
3
+ import { isObjectJsonSchema } from '../json-schema.js';
4
+ import { listTools } from '../mcp.js';
5
+ /** Default protocol result: JSON/text. Provide formatResult for other MCP content. */
6
+ export function formatMcpResult(value) {
7
+ const text = typeof value === 'string'
8
+ ? value
9
+ : (JSON.stringify(value, (_key, item) => typeof item === 'bigint' ? item.toString() : item) ?? 'null');
10
+ return { content: [{ type: 'text', text }] };
11
+ }
12
+ /** Register on the SDK's low-level Server, or on McpServer.server. */
13
+ export function registerMcpTools(server, router, options) {
14
+ const definitions = listTools(router, {
15
+ filter: options.filter,
16
+ ...(options.readOnly ? { readOnly: options.readOnly } : {}),
17
+ ...(options.name ? { name: options.name } : {})
18
+ });
19
+ const tools = new Map(definitions.map((tool) => [tool.name, tool]));
20
+ const descriptions = definitions.map((tool) => {
21
+ const inputSchema = tool.config.inputSchema?.['~standard'].jsonSchema.input() ?? { type: 'object', properties: {} };
22
+ if (!isObjectJsonSchema(inputSchema))
23
+ throw new TypeError(`orpc-fn: MCP tool ${tool.name} needs an object input`);
24
+ // MCP requires a top-level object; object unions retain their constraints.
25
+ return {
26
+ name: tool.name,
27
+ ...tool.config,
28
+ inputSchema: { ...inputSchema, type: 'object' }
29
+ };
30
+ });
31
+ server.setRequestHandler(ListToolsRequestSchema, () => ({
32
+ tools: descriptions
33
+ }));
34
+ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
35
+ const tool = tools.get(request.params.name);
36
+ if (!tool)
37
+ return {
38
+ content: [
39
+ { type: 'text', text: `Unknown tool: ${request.params.name}` }
40
+ ],
41
+ isError: true
42
+ };
43
+ try {
44
+ extra.signal.throwIfAborted();
45
+ const validation = await tool.config.inputSchema?.['~standard'].validate(request.params.arguments ?? {});
46
+ if (validation?.issues)
47
+ return {
48
+ content: [
49
+ {
50
+ type: 'text',
51
+ text: validation.issues.map((issue) => issue.message).join('; ')
52
+ }
53
+ ],
54
+ isError: true
55
+ };
56
+ const context = await options.context({
57
+ name: tool.name,
58
+ signal: extra.signal
59
+ });
60
+ const result = await call(tool.procedure, validation?.value, {
61
+ context,
62
+ signal: extra.signal
63
+ });
64
+ return await (options.formatResult ?? formatMcpResult)(result, tool);
65
+ }
66
+ catch (error) {
67
+ if (extra.signal.aborted)
68
+ throw error;
69
+ return {
70
+ content: [
71
+ {
72
+ type: 'text',
73
+ text: error instanceof Error ? error.message : String(error)
74
+ }
75
+ ],
76
+ isError: true
77
+ };
78
+ }
79
+ });
80
+ return [...tools.keys()];
81
+ }
82
+ //# sourceMappingURL=sdk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../src/mcp/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Server } from '@modelcontextprotocol/sdk/server/index.js'\nimport {\n\tCallToolRequestSchema,\n\tListToolsRequestSchema,\n\ttype CallToolResult\n} from '@modelcontextprotocol/sdk/types.js'\nimport {\n\ttype AnyRouter,\n\ttype InferRouterInitialContext,\n\tcall\n} from '@orpc/server'\nimport { isObjectJsonSchema } from '../json-schema.js'\nimport { listTools, type McpTool, type ProcedureFilter } from '../mcp.js'\n\nexport type RegisterMcpToolsOptions<R extends AnyRouter> = {\n\t/** Tool exposure must be an explicit application choice. */\n\tfilter: ProcedureFilter\n\tcontext: (request: {\n\t\tname: string\n\t\tsignal: AbortSignal\n\t}) => InferRouterInitialContext<R> | Promise<InferRouterInitialContext<R>>\n\treadOnly?: ProcedureFilter\n\tname?: NonNullable<Parameters<typeof listTools>[1]>['name']\n\tformatResult?: (\n\t\tvalue: unknown,\n\t\ttool: McpTool\n\t) => CallToolResult | Promise<CallToolResult>\n}\n\n/** Default protocol result: JSON/text. Provide formatResult for other MCP content. */\nexport function formatMcpResult(value: unknown): CallToolResult {\n\tconst text =\n\t\ttypeof value === 'string'\n\t\t\t? value\n\t\t\t: (JSON.stringify(value, (_key, item) =>\n\t\t\t\t\ttypeof item === 'bigint' ? item.toString() : item\n\t\t\t\t) ?? 'null')\n\treturn { content: [{ type: 'text', text }] }\n}\n\n/** Register on the SDK's low-level Server, or on McpServer.server. */\nexport function registerMcpTools<R extends AnyRouter>(\n\tserver: Pick<Server, 'setRequestHandler'>,\n\trouter: R,\n\toptions: RegisterMcpToolsOptions<R>\n): readonly string[] {\n\tconst definitions = listTools(router, {\n\t\tfilter: options.filter,\n\t\t...(options.readOnly ? { readOnly: options.readOnly } : {}),\n\t\t...(options.name ? { name: options.name } : {})\n\t})\n\tconst tools = new Map(definitions.map((tool) => [tool.name, tool]))\n\tconst descriptions = definitions.map((tool) => {\n\t\tconst inputSchema = tool.config.inputSchema?.[\n\t\t\t'~standard'\n\t\t].jsonSchema.input() ?? { type: 'object', properties: {} }\n\t\tif (!isObjectJsonSchema(inputSchema))\n\t\t\tthrow new TypeError(\n\t\t\t\t`orpc-fn: MCP tool ${tool.name} needs an object input`\n\t\t\t)\n\t\t// MCP requires a top-level object; object unions retain their constraints.\n\t\treturn {\n\t\t\tname: tool.name,\n\t\t\t...tool.config,\n\t\t\tinputSchema: { ...inputSchema, type: 'object' as const }\n\t\t}\n\t})\n\tserver.setRequestHandler(ListToolsRequestSchema, () => ({\n\t\ttools: descriptions\n\t}))\n\tserver.setRequestHandler(CallToolRequestSchema, async (request, extra) => {\n\t\tconst tool = tools.get(request.params.name)\n\t\tif (!tool)\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{ type: 'text', text: `Unknown tool: ${request.params.name}` }\n\t\t\t\t],\n\t\t\t\tisError: true\n\t\t\t}\n\t\ttry {\n\t\t\textra.signal.throwIfAborted()\n\t\t\tconst validation = await tool.config.inputSchema?.['~standard'].validate(\n\t\t\t\trequest.params.arguments ?? {}\n\t\t\t)\n\t\t\tif (validation?.issues)\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\t\ttext: validation.issues.map((issue) => issue.message).join('; ')\n\t\t\t\t\t\t}\n\t\t\t\t\t],\n\t\t\t\t\tisError: true\n\t\t\t\t}\n\t\t\tconst context = await options.context({\n\t\t\t\tname: tool.name,\n\t\t\t\tsignal: extra.signal\n\t\t\t})\n\t\t\tconst result = await call(tool.procedure, validation?.value, {\n\t\t\t\tcontext,\n\t\t\t\tsignal: extra.signal\n\t\t\t})\n\t\t\treturn await (options.formatResult ?? formatMcpResult)(result, tool)\n\t\t} catch (error) {\n\t\t\tif (extra.signal.aborted) throw error\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\ttext: error instanceof Error ? error.message : String(error)\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\tisError: true\n\t\t\t}\n\t\t}\n\t})\n\treturn [...tools.keys()]\n}\n"]}
package/dist/mcp.d.ts CHANGED
@@ -26,8 +26,8 @@ export type McpTool = {
26
26
  export declare const hasTag: (tag: string) => ProcedureFilter;
27
27
  /**
28
28
  * MCP tool definitions for the procedures in `router` matching `filter`
29
- * (default: all). Register them with any MCP server:
30
- * `server.registerTool(tool.name, tool.config, run)`.
29
+ * (default: all). These are inspection definitions, not McpServer.registerTool configs.
30
+ * Use registerMcpTools from orpc-fn/mcp/sdk for executable registration.
31
31
  *
32
32
  * `readOnly` sets `readOnlyHint`; it defaults to GET routes, since an MCP
33
33
  * client treats anything else as a mutation and may ask for approval.
@@ -35,5 +35,6 @@ export declare const hasTag: (tag: string) => ProcedureFilter;
35
35
  export declare function listTools(router: AnyRouter, options?: {
36
36
  filter?: ProcedureFilter;
37
37
  readOnly?: ProcedureFilter;
38
+ name?: (options: TraverseContractProcedureCallbackOptions) => string;
38
39
  }): McpTool[];
39
40
  //# sourceMappingURL=mcp.d.ts.map
package/dist/mcp.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,wCAAwC,EAE7C,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAc,UAAU,EAAE,MAAM,WAAW,CAAA;AAElD,OAAO,EAAE,UAAU,EAAE,CAAA;AACrB,OAAO,EAAE,cAAc,IAAI,eAAe,EAAE,CAAA;AAC5C,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B,uEAAuE;AACvE,MAAM,MAAM,eAAe,GAAG,CAC7B,OAAO,EAAE,wCAAwC,KAC7C,OAAO,CAAA;AAEZ,MAAM,MAAM,OAAO,GAAG;IACrB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,YAAY,CAAA;IACvB,MAAM,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB;;;WAGG;QACH,WAAW,CAAC,EAAE,UAAU,CAAA;QACxB,WAAW,EAAE;YAAE,YAAY,EAAE,OAAO,CAAA;SAAE,CAAA;KACtC,CAAA;CACD,CAAA;AAED,6FAA6F;AAC7F,eAAO,MAAM,MAAM,QACZ,MAAM,KAAG,eAEsC,CAAA;AAKtD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACxB,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,EAAE,eAAe,CAAA;CAAO,GACpE,OAAO,EAAE,CAmBX"}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,wCAAwC,EAE7C,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAc,UAAU,EAAE,MAAM,WAAW,CAAA;AAElD,OAAO,EAAE,UAAU,EAAE,CAAA;AACrB,OAAO,EAAE,cAAc,IAAI,eAAe,EAAE,CAAA;AAC5C,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B,uEAAuE;AACvE,MAAM,MAAM,eAAe,GAAG,CAC7B,OAAO,EAAE,wCAAwC,KAC7C,OAAO,CAAA;AAEZ,MAAM,MAAM,OAAO,GAAG;IACrB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,YAAY,CAAA;IACvB,MAAM,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB;;;WAGG;QACH,WAAW,CAAC,EAAE,UAAU,CAAA;QACxB,WAAW,EAAE;YAAE,YAAY,EAAE,OAAO,CAAA;SAAE,CAAA;KACtC,CAAA;CACD,CAAA;AAED,6FAA6F;AAC7F,eAAO,MAAM,MAAM,QACZ,MAAM,KAAG,eAEmD,CAAA;AAKnE;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACxB,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE;IACR,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,wCAAwC,KAAK,MAAM,CAAA;CAC/D,GACJ,OAAO,EAAE,CA0CX"}
package/dist/mcp.js CHANGED
@@ -1,15 +1,16 @@
1
1
  import { traverseContractProcedures } from '@orpc/server';
2
+ import { procedureDefinition } from './compatibility.js';
2
3
  import { rawInputSchema } from './json-schema.js';
3
4
  import { readFnMeta, toToolName } from './meta.js';
4
5
  export { toToolName };
5
6
  export { rawInputSchema as toolInputSchema };
6
7
  /** Procedures whose route has `tag`: `listTools(router, { filter: hasTag('external') })`. */
7
- export const hasTag = (tag) => ({ contract }) => contract['~orpc'].route.tags?.includes(tag) ?? false;
8
- const isGet = ({ contract }) => contract['~orpc'].route.method === 'GET';
8
+ export const hasTag = (tag) => ({ contract }) => procedureDefinition(contract).route?.tags?.includes(tag) ?? false;
9
+ const isGet = ({ contract }) => procedureDefinition(contract).route?.method === 'GET';
9
10
  /**
10
11
  * MCP tool definitions for the procedures in `router` matching `filter`
11
- * (default: all). Register them with any MCP server:
12
- * `server.registerTool(tool.name, tool.config, run)`.
12
+ * (default: all). These are inspection definitions, not McpServer.registerTool configs.
13
+ * Use registerMcpTools from orpc-fn/mcp/sdk for executable registration.
13
14
  *
14
15
  * `readOnly` sets `readOnlyHint`; it defaults to GET routes, since an MCP
15
16
  * client treats anything else as a mutation and may ask for approval.
@@ -17,14 +18,26 @@ const isGet = ({ contract }) => contract['~orpc'].route.method === 'GET';
17
18
  export function listTools(router, options = {}) {
18
19
  const { filter, readOnly = isGet } = options;
19
20
  const tools = [];
20
- traverseContractProcedures({ router, path: [] }, (traversed) => {
21
+ const names = new Map();
22
+ const unresolved = traverseContractProcedures({ router, path: [] }, (traversed) => {
21
23
  if (filter && !filter(traversed))
22
24
  return;
23
25
  const procedure = traversed.contract;
24
- const { inputSchema, route } = procedure['~orpc'];
26
+ const meta = readFnMeta(procedure);
27
+ if (meta.stream)
28
+ throw new TypeError(`orpc-fn: streaming procedure ${meta.name ?? traversed.path.join('.')} cannot be an MCP tool`);
29
+ const name = options.name?.(traversed) ??
30
+ toToolName(meta.name ?? traversed.path.join('.'));
31
+ const previous = names.get(name);
32
+ if (previous === procedure)
33
+ return;
34
+ if (previous)
35
+ throw new TypeError(`orpc-fn: MCP tool name collision: ${name}; provide a name override`);
36
+ names.set(name, procedure);
37
+ const { inputSchema, route = {} } = procedureDefinition(procedure);
25
38
  const description = route.description ?? route.summary;
26
39
  tools.push({
27
- name: toToolName(readFnMeta(procedure).name ?? traversed.path.join('.')),
40
+ name,
28
41
  procedure,
29
42
  config: {
30
43
  ...(description === undefined ? {} : { description }),
@@ -33,6 +46,8 @@ export function listTools(router, options = {}) {
33
46
  }
34
47
  });
35
48
  });
49
+ if (unresolved.length)
50
+ throw new TypeError('orpc-fn: resolve lazy routers with unlazyRouter before listing MCP tools');
36
51
  return tools;
37
52
  }
38
53
  //# sourceMappingURL=mcp.js.map
package/dist/mcp.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,0BAA0B,EAC1B,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,cAAc,EAAmB,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAElD,OAAO,EAAE,UAAU,EAAE,CAAA;AACrB,OAAO,EAAE,cAAc,IAAI,eAAe,EAAE,CAAA;AAuB5C,6FAA6F;AAC7F,MAAM,CAAC,MAAM,MAAM,GAClB,CAAC,GAAW,EAAmB,EAAE,CACjC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAChB,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK,CAAA;AAEtD,MAAM,KAAK,GAAoB,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAC/C,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,KAAK,CAAA;AAEzC;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CACxB,MAAiB,EACjB,OAAO,GAA6D,EAAE;IAEtE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IAC5C,MAAM,KAAK,GAAc,EAAE,CAAA;IAC3B,0BAA0B,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,SAAS,EAAE,EAAE;QAC9D,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;YAAE,OAAM;QACxC,MAAM,SAAS,GAAG,SAAS,CAAC,QAAwB,CAAA;QACpD,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,CAAA;QACjD,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,OAAO,CAAA;QACtD,KAAK,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxE,SAAS;YACT,MAAM,EAAE;gBACP,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;gBACrD,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpE,WAAW,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE;aAClD;SACD,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;IACF,OAAO,KAAK,CAAA;AACb,CAAC","sourcesContent":["import {\n\ttype AnyProcedure,\n\ttype AnyRouter,\n\ttype TraverseContractProcedureCallbackOptions,\n\ttraverseContractProcedures\n} from '@orpc/server'\nimport { rawInputSchema, type ToolSchema } from './json-schema.js'\nimport { readFnMeta, toToolName } from './meta.js'\n\nexport { toToolName }\nexport { rawInputSchema as toolInputSchema }\nexport type { ToolSchema }\n\n/** Picks procedures; also fits oRPC's `OpenAPIHandler({ filter })`. */\nexport type ProcedureFilter = (\n\toptions: TraverseContractProcedureCallbackOptions\n) => boolean\n\nexport type McpTool = {\n\t/** Tool name: the sanitized `fn` name (`user.me` becomes `user-me`). */\n\tname: string\n\tprocedure: AnyProcedure\n\tconfig: {\n\t\tdescription?: string\n\t\t/**\n\t\t * Validates and coerces (date strings to `Date`) but returns the raw\n\t\t * input: pass it to `call(procedure, args)`, which parses it.\n\t\t */\n\t\tinputSchema?: ToolSchema\n\t\tannotations: { readOnlyHint: boolean }\n\t}\n}\n\n/** Procedures whose route has `tag`: `listTools(router, { filter: hasTag('external') })`. */\nexport const hasTag =\n\t(tag: string): ProcedureFilter =>\n\t({ contract }) =>\n\t\tcontract['~orpc'].route.tags?.includes(tag) ?? false\n\nconst isGet: ProcedureFilter = ({ contract }) =>\n\tcontract['~orpc'].route.method === 'GET'\n\n/**\n * MCP tool definitions for the procedures in `router` matching `filter`\n * (default: all). Register them with any MCP server:\n * `server.registerTool(tool.name, tool.config, run)`.\n *\n * `readOnly` sets `readOnlyHint`; it defaults to GET routes, since an MCP\n * client treats anything else as a mutation and may ask for approval.\n */\nexport function listTools(\n\trouter: AnyRouter,\n\toptions: { filter?: ProcedureFilter; readOnly?: ProcedureFilter } = {}\n): McpTool[] {\n\tconst { filter, readOnly = isGet } = options\n\tconst tools: McpTool[] = []\n\ttraverseContractProcedures({ router, path: [] }, (traversed) => {\n\t\tif (filter && !filter(traversed)) return\n\t\tconst procedure = traversed.contract as AnyProcedure\n\t\tconst { inputSchema, route } = procedure['~orpc']\n\t\tconst description = route.description ?? route.summary\n\t\ttools.push({\n\t\t\tname: toToolName(readFnMeta(procedure).name ?? traversed.path.join('.')),\n\t\t\tprocedure,\n\t\t\tconfig: {\n\t\t\t\t...(description === undefined ? {} : { description }),\n\t\t\t\t...(inputSchema ? { inputSchema: rawInputSchema(inputSchema) } : {}),\n\t\t\t\tannotations: { readOnlyHint: readOnly(traversed) }\n\t\t\t}\n\t\t})\n\t})\n\treturn tools\n}\n"]}
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype AnyProcedure,\n\ttype AnyRouter,\n\ttype TraverseContractProcedureCallbackOptions,\n\ttraverseContractProcedures\n} from '@orpc/server'\nimport { procedureDefinition } from './compatibility.js'\nimport { rawInputSchema, type ToolSchema } from './json-schema.js'\nimport { readFnMeta, toToolName } from './meta.js'\n\nexport { toToolName }\nexport { rawInputSchema as toolInputSchema }\nexport type { ToolSchema }\n\n/** Picks procedures; also fits oRPC's `OpenAPIHandler({ filter })`. */\nexport type ProcedureFilter = (\n\toptions: TraverseContractProcedureCallbackOptions\n) => boolean\n\nexport type McpTool = {\n\t/** Tool name: the sanitized `fn` name (`user.me` becomes `user-me`). */\n\tname: string\n\tprocedure: AnyProcedure\n\tconfig: {\n\t\tdescription?: string\n\t\t/**\n\t\t * Validates and coerces (date strings to `Date`) but returns the raw\n\t\t * input: pass it to `call(procedure, args)`, which parses it.\n\t\t */\n\t\tinputSchema?: ToolSchema\n\t\tannotations: { readOnlyHint: boolean }\n\t}\n}\n\n/** Procedures whose route has `tag`: `listTools(router, { filter: hasTag('external') })`. */\nexport const hasTag =\n\t(tag: string): ProcedureFilter =>\n\t({ contract }) =>\n\t\tprocedureDefinition(contract).route?.tags?.includes(tag) ?? false\n\nconst isGet: ProcedureFilter = ({ contract }) =>\n\tprocedureDefinition(contract).route?.method === 'GET'\n\n/**\n * MCP tool definitions for the procedures in `router` matching `filter`\n * (default: all). These are inspection definitions, not McpServer.registerTool configs.\n * Use registerMcpTools from orpc-fn/mcp/sdk for executable registration.\n *\n * `readOnly` sets `readOnlyHint`; it defaults to GET routes, since an MCP\n * client treats anything else as a mutation and may ask for approval.\n */\nexport function listTools(\n\trouter: AnyRouter,\n\toptions: {\n\t\tfilter?: ProcedureFilter\n\t\treadOnly?: ProcedureFilter\n\t\tname?: (options: TraverseContractProcedureCallbackOptions) => string\n\t} = {}\n): McpTool[] {\n\tconst { filter, readOnly = isGet } = options\n\tconst tools: McpTool[] = []\n\tconst names = new Map<string, AnyProcedure>()\n\tconst unresolved = traverseContractProcedures(\n\t\t{ router, path: [] },\n\t\t(traversed) => {\n\t\t\tif (filter && !filter(traversed)) return\n\t\t\tconst procedure = traversed.contract as AnyProcedure\n\t\t\tconst meta = readFnMeta(procedure)\n\t\t\tif (meta.stream)\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`orpc-fn: streaming procedure ${meta.name ?? traversed.path.join('.')} cannot be an MCP tool`\n\t\t\t\t)\n\t\t\tconst name =\n\t\t\t\toptions.name?.(traversed) ??\n\t\t\t\ttoToolName(meta.name ?? traversed.path.join('.'))\n\t\t\tconst previous = names.get(name)\n\t\t\tif (previous === procedure) return\n\t\t\tif (previous)\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`orpc-fn: MCP tool name collision: ${name}; provide a name override`\n\t\t\t\t)\n\t\t\tnames.set(name, procedure)\n\t\t\tconst { inputSchema, route = {} } = procedureDefinition(procedure)\n\t\t\tconst description = route.description ?? route.summary\n\t\t\ttools.push({\n\t\t\t\tname,\n\t\t\t\tprocedure,\n\t\t\t\tconfig: {\n\t\t\t\t\t...(description === undefined ? {} : { description }),\n\t\t\t\t\t...(inputSchema ? { inputSchema: rawInputSchema(inputSchema) } : {}),\n\t\t\t\t\tannotations: { readOnlyHint: readOnly(traversed) }\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t)\n\tif (unresolved.length)\n\t\tthrow new TypeError(\n\t\t\t'orpc-fn: resolve lazy routers with unlazyRouter before listing MCP tools'\n\t\t)\n\treturn tools\n}\n"]}
package/dist/meta.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import type { AnySchema } from '@orpc/contract';
1
+ import { type AnySchema } from '@orpc/contract';
2
+ import { type LibraryMeta } from './compatibility.js';
2
3
  import type { AnyProcedure } from '@orpc/server';
3
4
  /**
4
5
  * Key under which `fn()` stores its metadata in oRPC's procedure meta
@@ -7,16 +8,17 @@ import type { AnyProcedure } from '@orpc/server';
7
8
  * unlike a symbol property on the procedure object.
8
9
  */
9
10
  export declare const FN_META_KEY = "orpc-fn";
10
- export type StoredFnMeta = {
11
+ export type StoredFnMeta<TMeta extends object = Record<string, unknown>, TKey extends string = string> = {
11
12
  name: string;
12
- procedure: string;
13
- meta: Record<string, unknown>;
13
+ procedure: TKey;
14
+ meta: TMeta;
15
+ stream: boolean;
14
16
  };
15
- export type FnMeta<TMeta extends object = Record<string, unknown>> = {
17
+ export type FnMeta<TMeta extends object = Record<string, unknown>, TKey extends string = string> = {
16
18
  /** `fn({ name })`, also the OpenAPI operationId; undefined if not made by `fn()`. */
17
19
  name: string | undefined;
18
20
  /** The `procedures` key the route was built from. */
19
- procedure: string | undefined;
21
+ procedure: TKey | undefined;
20
22
  /** The app's typed meta (`createFn({ meta })`) declared on this route. */
21
23
  meta: Partial<TMeta>;
22
24
  /** Route summary, falling back to description, falling back to ''. */
@@ -24,12 +26,18 @@ export type FnMeta<TMeta extends object = Record<string, unknown>> = {
24
26
  summary: string | undefined;
25
27
  method: string | undefined;
26
28
  path: string | undefined;
29
+ stream: boolean;
27
30
  tags: readonly string[];
28
31
  inputSchema: AnySchema | undefined;
29
32
  outputSchema: AnySchema | undefined;
30
33
  };
31
34
  /** Read what `fn()` (and oRPC) recorded on a procedure. */
32
- export declare function readFnMeta<TMeta extends object = Record<string, unknown>>(procedure: AnyProcedure): FnMeta<TMeta>;
35
+ type MetaFrom<T> = [LibraryMeta<T>] extends [never] ? Record<string, unknown> : LibraryMeta<T> extends StoredFnMeta<infer M, string> ? M : Record<string, unknown>;
36
+ type KeyFrom<T> = [LibraryMeta<T>] extends [never] ? string : LibraryMeta<T> extends StoredFnMeta<object, infer K> ? K : string;
37
+ /** Declares the route metadata contract; it does not provide defaults. */
38
+ export declare function defineMeta<T extends object>(): T;
39
+ export declare function readFnMeta<T extends AnyProcedure>(procedure: T): FnMeta<MetaFrom<T>, KeyFrom<T>>;
33
40
  /** Tool-safe name (`a-z0-9-_`): `Users.Get` becomes `users-get`. */
34
41
  export declare function toToolName(name: string): string;
42
+ export {};
35
43
  //# sourceMappingURL=meta.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,WAAW,YAAY,CAAA;AAEpC,MAAM,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC7B,CAAA;AAED,MAAM,MAAM,MAAM,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IACpE,qFAAqF;IACrF,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,qDAAqD;IACrD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,0EAA0E;IAC1E,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;IACpB,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IACvB,WAAW,EAAE,SAAS,GAAG,SAAS,CAAA;IAClC,YAAY,EAAE,SAAS,GAAG,SAAS,CAAA;CACnC,CAAA;AAeD,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxE,SAAS,EAAE,YAAY,GACrB,MAAM,CAAC,KAAK,CAAC,CAgBf;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C"}
1
+ {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC9E,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,oBAAoB,CAAA;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,WAAW,YAAY,CAAA;AAEpC,MAAM,MAAM,YAAY,CACvB,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9C,IAAI,SAAS,MAAM,GAAG,MAAM,IACzB;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,IAAI,CAAA;IACf,IAAI,EAAE,KAAK,CAAA;IACX,MAAM,EAAE,OAAO,CAAA;CACf,CAAA;AAED,MAAM,MAAM,MAAM,CACjB,KAAK,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9C,IAAI,SAAS,MAAM,GAAG,MAAM,IACzB;IACH,qFAAqF;IACrF,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,qDAAqD;IACrD,SAAS,EAAE,IAAI,GAAG,SAAS,CAAA;IAC3B,0EAA0E;IAC1E,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;IACpB,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IACvB,WAAW,EAAE,SAAS,GAAG,SAAS,CAAA;IAClC,YAAY,EAAE,SAAS,GAAG,SAAS,CAAA;CACnC,CAAA;AAED,2DAA2D;AAC3D,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAChD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,WAAW,CAAC,CAAC,CAAC,SAAS,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,GACnD,CAAC,GACD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE3B,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC/C,MAAM,GACN,WAAW,CAAC,CAAC,CAAC,SAAS,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACnD,CAAC,GACD,MAAM,CAAA;AAEV,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,KAAK,CAAC,CAEhD;AAED,wBAAgB,UAAU,CAAC,CAAC,SAAS,YAAY,EAChD,SAAS,EAAE,CAAC,GACV,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAmBjC;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C"}
package/dist/meta.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { getEventIteratorSchemaDetails } from '@orpc/contract';
2
+ import { procedureDefinition } from './compatibility.js';
1
3
  /**
2
4
  * Key under which `fn()` stores its metadata in oRPC's procedure meta
3
5
  * (`.meta()`). Living in oRPC's own meta means it survives everything that
@@ -5,9 +7,12 @@
5
7
  * unlike a symbol property on the procedure object.
6
8
  */
7
9
  export const FN_META_KEY = 'orpc-fn';
8
- /** Read what `fn()` (and oRPC) recorded on a procedure. */
10
+ /** Declares the route metadata contract; it does not provide defaults. */
11
+ export function defineMeta() {
12
+ return {};
13
+ }
9
14
  export function readFnMeta(procedure) {
10
- const def = procedure['~orpc'] ?? {};
15
+ const def = procedureDefinition(procedure);
11
16
  const stored = def.meta?.[FN_META_KEY];
12
17
  const route = def.route ?? {};
13
18
  return {
@@ -19,6 +24,8 @@ export function readFnMeta(procedure) {
19
24
  method: route.method,
20
25
  path: route.path,
21
26
  tags: route.tags ?? [],
27
+ stream: stored?.stream === true ||
28
+ getEventIteratorSchemaDetails(def.outputSchema) !== undefined,
22
29
  inputSchema: def.inputSchema,
23
30
  outputSchema: def.outputSchema
24
31
  };
package/dist/meta.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"meta.js","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAA;AAsCpC,2DAA2D;AAC3D,MAAM,UAAU,UAAU,CACzB,SAAuB;IAEvB,MAAM,GAAG,GAAI,SAA+C,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;IAC3E,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,CAA6B,CAAA;IAClE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAAA;IAC7B,OAAO;QACN,IAAI,EAAE,MAAM,EAAE,IAAI;QAClB,SAAS,EAAE,MAAM,EAAE,SAAS;QAC5B,IAAI,EAAE,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,CAAmB;QAC5C,WAAW,EAAE,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,WAAW,IAAI,EAAE;QACrD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;QACtB,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,YAAY,EAAE,GAAG,CAAC,YAAY;KAC9B,CAAA;AACF,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,UAAU,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAA;AACvD,CAAC","sourcesContent":["import type { AnySchema } from '@orpc/contract'\nimport type { AnyProcedure } from '@orpc/server'\n\n/**\n * Key under which `fn()` stores its metadata in oRPC's procedure meta\n * (`.meta()`). Living in oRPC's own meta means it survives everything that\n * rebuilds a procedure (`os.router()`, `.use()` on a router, lazy routers),\n * unlike a symbol property on the procedure object.\n */\nexport const FN_META_KEY = 'orpc-fn'\n\nexport type StoredFnMeta = {\n\tname: string\n\tprocedure: string\n\tmeta: Record<string, unknown>\n}\n\nexport type FnMeta<TMeta extends object = Record<string, unknown>> = {\n\t/** `fn({ name })`, also the OpenAPI operationId; undefined if not made by `fn()`. */\n\tname: string | undefined\n\t/** The `procedures` key the route was built from. */\n\tprocedure: string | undefined\n\t/** The app's typed meta (`createFn({ meta })`) declared on this route. */\n\tmeta: Partial<TMeta>\n\t/** Route summary, falling back to description, falling back to ''. */\n\tdescription: string\n\tsummary: string | undefined\n\tmethod: string | undefined\n\tpath: string | undefined\n\ttags: readonly string[]\n\tinputSchema: AnySchema | undefined\n\toutputSchema: AnySchema | undefined\n}\n\ntype ProcedureDefinition = {\n\tmeta?: Record<string, unknown>\n\troute?: {\n\t\tsummary?: string\n\t\tdescription?: string\n\t\tmethod?: string\n\t\tpath?: string\n\t\ttags?: readonly string[]\n\t}\n\tinputSchema?: AnySchema\n\toutputSchema?: AnySchema\n}\n\n/** Read what `fn()` (and oRPC) recorded on a procedure. */\nexport function readFnMeta<TMeta extends object = Record<string, unknown>>(\n\tprocedure: AnyProcedure\n): FnMeta<TMeta> {\n\tconst def = (procedure as { '~orpc'?: ProcedureDefinition })['~orpc'] ?? {}\n\tconst stored = def.meta?.[FN_META_KEY] as StoredFnMeta | undefined\n\tconst route = def.route ?? {}\n\treturn {\n\t\tname: stored?.name,\n\t\tprocedure: stored?.procedure,\n\t\tmeta: (stored?.meta ?? {}) as Partial<TMeta>,\n\t\tdescription: route.summary ?? route.description ?? '',\n\t\tsummary: route.summary,\n\t\tmethod: route.method,\n\t\tpath: route.path,\n\t\ttags: route.tags ?? [],\n\t\tinputSchema: def.inputSchema,\n\t\toutputSchema: def.outputSchema\n\t}\n}\n\n/** Tool-safe name (`a-z0-9-_`): `Users.Get` becomes `users-get`. */\nexport function toToolName(name: string): string {\n\treturn name.toLowerCase().replace(/[^a-z0-9-_]/g, '-')\n}\n"]}
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAkB,MAAM,gBAAgB,CAAA;AAC9E,OAAO,EAAoB,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAG1E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAA;AA8CpC,0EAA0E;AAC1E,MAAM,UAAU,UAAU;IACzB,OAAO,EAAO,CAAA;AACf,CAAC;AAED,MAAM,UAAU,UAAU,CACzB,SAAY;IAEZ,MAAM,GAAG,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,CAA6B,CAAA;IAClE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAAA;IAC7B,OAAO;QACN,IAAI,EAAE,MAAM,EAAE,IAAI;QAClB,SAAS,EAAE,MAAM,EAAE,SAAmC;QACtD,IAAI,EAAE,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,CAAyB;QAClD,WAAW,EAAE,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,WAAW,IAAI,EAAE;QACrD,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;QACtB,MAAM,EACL,MAAM,EAAE,MAAM,KAAK,IAAI;YACvB,6BAA6B,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,SAAS;QAC9D,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,YAAY,EAAE,GAAG,CAAC,YAAY;KAC9B,CAAA;AACF,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,UAAU,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAA;AACvD,CAAC","sourcesContent":["import { getEventIteratorSchemaDetails, type AnySchema } from '@orpc/contract'\nimport { type LibraryMeta, procedureDefinition } from './compatibility.js'\nimport type { AnyProcedure } from '@orpc/server'\n\n/**\n * Key under which `fn()` stores its metadata in oRPC's procedure meta\n * (`.meta()`). Living in oRPC's own meta means it survives everything that\n * rebuilds a procedure (`os.router()`, `.use()` on a router, lazy routers),\n * unlike a symbol property on the procedure object.\n */\nexport const FN_META_KEY = 'orpc-fn'\n\nexport type StoredFnMeta<\n\tTMeta extends object = Record<string, unknown>,\n\tTKey extends string = string\n> = {\n\tname: string\n\tprocedure: TKey\n\tmeta: TMeta\n\tstream: boolean\n}\n\nexport type FnMeta<\n\tTMeta extends object = Record<string, unknown>,\n\tTKey extends string = string\n> = {\n\t/** `fn({ name })`, also the OpenAPI operationId; undefined if not made by `fn()`. */\n\tname: string | undefined\n\t/** The `procedures` key the route was built from. */\n\tprocedure: TKey | undefined\n\t/** The app's typed meta (`createFn({ meta })`) declared on this route. */\n\tmeta: Partial<TMeta>\n\t/** Route summary, falling back to description, falling back to ''. */\n\tdescription: string\n\tsummary: string | undefined\n\tmethod: string | undefined\n\tpath: string | undefined\n\tstream: boolean\n\ttags: readonly string[]\n\tinputSchema: AnySchema | undefined\n\toutputSchema: AnySchema | undefined\n}\n\n/** Read what `fn()` (and oRPC) recorded on a procedure. */\ntype MetaFrom<T> = [LibraryMeta<T>] extends [never]\n\t? Record<string, unknown>\n\t: LibraryMeta<T> extends StoredFnMeta<infer M, string>\n\t\t? M\n\t\t: Record<string, unknown>\n\ntype KeyFrom<T> = [LibraryMeta<T>] extends [never]\n\t? string\n\t: LibraryMeta<T> extends StoredFnMeta<object, infer K>\n\t\t? K\n\t\t: string\n\n/** Declares the route metadata contract; it does not provide defaults. */\nexport function defineMeta<T extends object>(): T {\n\treturn {} as T\n}\n\nexport function readFnMeta<T extends AnyProcedure>(\n\tprocedure: T\n): FnMeta<MetaFrom<T>, KeyFrom<T>> {\n\tconst def = procedureDefinition(procedure)\n\tconst stored = def.meta?.[FN_META_KEY] as StoredFnMeta | undefined\n\tconst route = def.route ?? {}\n\treturn {\n\t\tname: stored?.name,\n\t\tprocedure: stored?.procedure as KeyFrom<T> | undefined,\n\t\tmeta: (stored?.meta ?? {}) as Partial<MetaFrom<T>>,\n\t\tdescription: route.summary ?? route.description ?? '',\n\t\tsummary: route.summary,\n\t\tmethod: route.method,\n\t\tpath: route.path,\n\t\ttags: route.tags ?? [],\n\t\tstream:\n\t\t\tstored?.stream === true ||\n\t\t\tgetEventIteratorSchemaDetails(def.outputSchema) !== undefined,\n\t\tinputSchema: def.inputSchema,\n\t\toutputSchema: def.outputSchema\n\t}\n}\n\n/** Tool-safe name (`a-z0-9-_`): `Users.Get` becomes `users-get`. */\nexport function toToolName(name: string): string {\n\treturn name.toLowerCase().replace(/[^a-z0-9-_]/g, '-')\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"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"}
package/dist/otel.js CHANGED
@@ -1,9 +1,16 @@
1
1
  import { isAsyncIteratorObject, onStreamEnd } from './stream.js';
2
2
  export function createTracing(otel) {
3
- const tracer = otel?.trace.getTracer('orpc-fn');
3
+ let tracer;
4
+ try {
5
+ tracer = otel?.trace.getTracer('orpc-fn');
6
+ }
7
+ catch {
8
+ /* Missing telemetry cannot prevent execution. */
9
+ }
4
10
  const end = (span, ...error) => {
5
11
  if (!span || !otel)
6
12
  return;
13
+ span = protectSpan(span);
7
14
  if (error.length === 0) {
8
15
  span.setStatus({ code: otel.SpanStatusCode.OK });
9
16
  }
@@ -23,11 +30,15 @@ export function createTracing(otel) {
23
30
  try {
24
31
  onSettled?.(span, ...error);
25
32
  }
33
+ catch {
34
+ /* Telemetry callbacks cannot replace the original result. */
35
+ }
26
36
  finally {
27
37
  end(span, ...error);
28
38
  }
29
39
  };
30
40
  const run = async (span, scope) => {
41
+ span = span ? protectSpan(span) : undefined;
31
42
  let result;
32
43
  try {
33
44
  result = await fn(span);
@@ -44,15 +55,56 @@ export function createTracing(otel) {
44
55
  };
45
56
  if (!tracer || !otel)
46
57
  return run(undefined);
47
- return tracer.startActiveSpan(name, { kind: otel.SpanKind[kind] }, (span) => {
48
- const active = otel.context.active();
49
- return run(span, (step) => otel.context.with(active, step));
50
- });
58
+ let started;
59
+ try {
60
+ return tracer.startActiveSpan(name, { kind: otel.SpanKind[kind] }, (span) => {
61
+ let active;
62
+ try {
63
+ active = otel.context.active();
64
+ }
65
+ catch {
66
+ /* Fall back to the span without scope restoration. */
67
+ }
68
+ started = run(span, (step) => {
69
+ let completed;
70
+ let failed;
71
+ try {
72
+ return otel.context.with(active, () => {
73
+ try {
74
+ const value = step();
75
+ completed = { value };
76
+ return value;
77
+ }
78
+ catch (error) {
79
+ failed = { error };
80
+ throw error;
81
+ }
82
+ });
83
+ }
84
+ catch {
85
+ if (completed)
86
+ return completed.value;
87
+ if (failed)
88
+ throw failed.error;
89
+ return step();
90
+ }
91
+ });
92
+ return started;
93
+ });
94
+ }
95
+ catch {
96
+ return started ?? run(undefined);
97
+ }
51
98
  },
52
99
  startSpan(name, kind, attributes) {
53
100
  if (!tracer || !otel)
54
101
  return undefined;
55
- return tracer.startSpan(name, { kind: otel.SpanKind[kind], attributes });
102
+ try {
103
+ return protectSpan(tracer.startSpan(name, { kind: otel.SpanKind[kind], attributes }));
104
+ }
105
+ catch {
106
+ return undefined;
107
+ }
56
108
  },
57
109
  end
58
110
  };
@@ -60,4 +112,23 @@ export function createTracing(otel) {
60
112
  export function errorMessageOf(error) {
61
113
  return error instanceof Error ? error.message : String(error);
62
114
  }
115
+ function protectSpan(span) {
116
+ return new Proxy(span, {
117
+ get(target, key) {
118
+ const value = Reflect.get(target, key, target);
119
+ if (typeof value !== 'function')
120
+ return value;
121
+ if (['setAttribute', 'setStatus', 'recordException', 'end'].includes(String(key)))
122
+ return (...args) => {
123
+ try {
124
+ return value.apply(target, args);
125
+ }
126
+ catch {
127
+ /* Ignore exporter failures. */
128
+ }
129
+ };
130
+ return value.bind(target);
131
+ }
132
+ });
133
+ }
63
134
  //# sourceMappingURL=otel.js.map