@abide/abide 0.41.1 → 0.43.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 (167) hide show
  1. package/AGENTS.md +234 -294
  2. package/CHANGELOG.md +82 -0
  3. package/README.md +51 -95
  4. package/package.json +3 -2
  5. package/src/abideLsp.ts +46 -8
  6. package/src/abideResolverPlugin.ts +107 -19
  7. package/src/buildCli.ts +1 -1
  8. package/src/discoveryEntry.ts +3 -3
  9. package/src/lib/bundle/BundleMenuItem.ts +1 -1
  10. package/src/lib/cli/createClient.ts +12 -12
  11. package/src/lib/cli/dispatchCommand.ts +1 -1
  12. package/src/lib/cli/printSessionStatus.ts +1 -1
  13. package/src/lib/cli/resolveCliTarget.ts +1 -1
  14. package/src/lib/cli/runCli.ts +1 -1
  15. package/src/lib/cli/types/CliManifest.ts +1 -1
  16. package/src/lib/cli/types/CliManifestEntry.ts +2 -2
  17. package/src/lib/mcp/annotationsForMethod.ts +5 -5
  18. package/src/lib/mcp/createMcpServer.ts +3 -3
  19. package/src/lib/mcp/mcpSurface.ts +14 -14
  20. package/src/lib/mcp/types/McpServerOptions.ts +1 -1
  21. package/src/lib/server/DELETE.ts +4 -4
  22. package/src/lib/server/GET.ts +4 -4
  23. package/src/lib/server/HEAD.ts +4 -4
  24. package/src/lib/server/PATCH.ts +4 -4
  25. package/src/lib/server/POST.ts +4 -4
  26. package/src/lib/server/PUT.ts +4 -4
  27. package/src/lib/server/agent.ts +4 -4
  28. package/src/lib/server/env.ts +1 -1
  29. package/src/lib/server/error.ts +49 -7
  30. package/src/lib/server/json.ts +1 -1
  31. package/src/lib/server/rpc/buildErrorConstructors.ts +19 -0
  32. package/src/lib/server/rpc/{defineVerb.ts → defineRpc.ts} +52 -34
  33. package/src/lib/server/rpc/{dispatchVerbInProcess.ts → dispatchRpcInProcess.ts} +3 -3
  34. package/src/lib/server/rpc/fieldErrorsFromIssues.ts +23 -0
  35. package/src/lib/server/rpc/{findVerbByCommandName.ts → findRpcByCommandName.ts} +5 -5
  36. package/src/lib/server/rpc/parseArgs.ts +6 -6
  37. package/src/lib/server/rpc/readBodyWithinLimit.ts +2 -2
  38. package/src/lib/server/rpc/registerRpc.ts +6 -0
  39. package/src/lib/server/rpc/{verbRegistry.ts → rpcRegistry.ts} +4 -4
  40. package/src/lib/server/rpc/{runWithVerbTimeout.ts → runWithRpcTimeout.ts} +4 -4
  41. package/src/lib/server/rpc/types/RemoteHandler.ts +9 -3
  42. package/src/lib/server/rpc/types/{VerbHelper.ts → RpcHelper.ts} +57 -23
  43. package/src/lib/server/rpc/types/{VerbRegistryEntry.ts → RpcRegistryEntry.ts} +3 -3
  44. package/src/lib/server/rpc/types/TypedResponse.ts +2 -2
  45. package/src/lib/server/rpc/unprocessed.ts +6 -7
  46. package/src/lib/server/rpc/validationError.ts +17 -0
  47. package/src/lib/server/runtime/buildInspectorSurface.ts +7 -7
  48. package/src/lib/server/runtime/buildOpenApiSpec.ts +6 -6
  49. package/src/lib/server/runtime/createRouteDispatcher.ts +7 -7
  50. package/src/lib/server/runtime/createServer.ts +4 -4
  51. package/src/lib/server/runtime/crossOriginForbidden.ts +1 -1
  52. package/src/lib/server/runtime/crossOriginGate.ts +4 -4
  53. package/src/lib/server/runtime/devClientFingerprint.ts +2 -1
  54. package/src/lib/server/runtime/logExposedSurfaces.ts +4 -4
  55. package/src/lib/server/runtime/registryManifests.ts +2 -2
  56. package/src/lib/server/runtime/types/InspectorCacheEntry.ts +1 -1
  57. package/src/lib/server/runtime/types/InspectorRpc.ts +27 -0
  58. package/src/lib/server/runtime/types/InspectorSurface.ts +4 -4
  59. package/src/lib/server/runtime/types/RequestStore.ts +1 -1
  60. package/src/lib/server/runtime/warnUnguardedMcp.ts +2 -2
  61. package/src/lib/server/sockets/createSocketDispatcher.ts +15 -14
  62. package/src/lib/server/sockets/types/SocketOperation.ts +2 -2
  63. package/src/lib/shared/HttpError.ts +15 -1
  64. package/src/lib/shared/UNREACHABLE_STATUSES.ts +13 -0
  65. package/src/lib/shared/buildRpcRequest.ts +5 -5
  66. package/src/lib/shared/cache.ts +50 -168
  67. package/src/lib/shared/carriesBodyArgs.ts +4 -4
  68. package/src/lib/shared/createCacheStore.ts +12 -0
  69. package/src/lib/shared/createRemoteFunction.ts +11 -6
  70. package/src/lib/shared/decodeResponse.ts +2 -2
  71. package/src/lib/shared/detectRpcMethod.ts +17 -0
  72. package/src/lib/shared/emitLogRecord.ts +3 -3
  73. package/src/lib/shared/escapeRegex.ts +9 -0
  74. package/src/lib/shared/extraForwardHeaders.ts +1 -1
  75. package/src/lib/shared/fileName.ts +9 -0
  76. package/src/lib/shared/fileStem.ts +3 -1
  77. package/src/lib/shared/findExportCallSite.ts +30 -273
  78. package/src/lib/shared/forwardHeaders.ts +2 -2
  79. package/src/lib/shared/httpErrorFor.ts +26 -0
  80. package/src/lib/shared/isAsciiWhitespace.ts +5 -0
  81. package/src/lib/shared/isIdentPart.ts +9 -0
  82. package/src/lib/shared/isIdentStart.ts +8 -0
  83. package/src/lib/shared/isReadOnlyMethod.ts +4 -4
  84. package/src/lib/shared/keyForRemoteCall.ts +4 -4
  85. package/src/lib/shared/log.ts +1 -1
  86. package/src/lib/shared/outboxProbeSlot.ts +20 -0
  87. package/src/lib/shared/pending.ts +4 -1
  88. package/src/lib/shared/prepareRpcModule.ts +96 -14
  89. package/src/lib/shared/probeRegistries.ts +17 -4
  90. package/src/lib/shared/programNameForPackage.ts +3 -1
  91. package/src/lib/shared/queryStringFromArgs.ts +1 -1
  92. package/src/lib/shared/remoteMetaStore.ts +2 -2
  93. package/src/lib/shared/resolveClientFlags.ts +1 -1
  94. package/src/lib/shared/skipNonCode.ts +230 -0
  95. package/src/lib/shared/streamResponse.ts +9 -6
  96. package/src/lib/shared/stripImport.ts +6 -4
  97. package/src/lib/shared/types/CacheEntry.ts +2 -4
  98. package/src/lib/shared/types/CacheOnContext.ts +1 -11
  99. package/src/lib/shared/types/CacheStore.ts +13 -7
  100. package/src/lib/shared/types/ClientFlags.ts +1 -1
  101. package/src/lib/shared/types/ErrorConstructors.ts +17 -0
  102. package/src/lib/shared/types/ErrorDescriptor.ts +10 -0
  103. package/src/lib/shared/types/ErrorSpec.ts +11 -0
  104. package/src/lib/shared/types/HttpMethod.ts +1 -0
  105. package/src/lib/shared/types/Outbox.ts +9 -0
  106. package/src/lib/shared/types/OutboxEntry.ts +27 -0
  107. package/src/lib/shared/types/RawRemoteFunction.ts +2 -2
  108. package/src/lib/shared/types/RemoteCallable.ts +2 -2
  109. package/src/lib/shared/types/RemoteFunction.ts +21 -6
  110. package/src/lib/shared/types/RequestScopeInfo.ts +1 -1
  111. package/src/lib/shared/types/RpcErrorGuard.ts +40 -0
  112. package/src/lib/shared/types/RpcInvoker.ts +1 -1
  113. package/src/lib/shared/types/StandardSchemaV1.ts +1 -1
  114. package/src/lib/shared/types/ValidationErrorData.ts +20 -0
  115. package/src/lib/shared/url.ts +3 -3
  116. package/src/lib/shared/writeRpcDts.ts +7 -7
  117. package/src/lib/shared/writeTestRpcDts.ts +3 -3
  118. package/src/lib/test/createTestApp.ts +10 -10
  119. package/src/lib/ui/compile/ABIDE_SEMANTIC_TOKENS_LEGEND.ts +45 -0
  120. package/src/lib/ui/compile/abideUiPlugin.ts +2 -1
  121. package/src/lib/ui/compile/awaitPlan.ts +48 -0
  122. package/src/lib/ui/compile/compileShadow.ts +117 -31
  123. package/src/lib/ui/compile/createShadowLanguageService.ts +48 -0
  124. package/src/lib/ui/compile/desugarSignals.ts +42 -6
  125. package/src/lib/ui/compile/encodeSemanticTokens.ts +37 -0
  126. package/src/lib/ui/compile/generateBuild.ts +45 -62
  127. package/src/lib/ui/compile/generateSSR.ts +90 -60
  128. package/src/lib/ui/compile/ifPlan.ts +30 -0
  129. package/src/lib/ui/compile/makeVarNamer.ts +10 -0
  130. package/src/lib/ui/compile/offsetToPosition.ts +9 -0
  131. package/src/lib/ui/compile/parseTemplate.ts +565 -115
  132. package/src/lib/ui/compile/stripEffects.ts +17 -9
  133. package/src/lib/ui/compile/structuralBlockTokens.ts +101 -0
  134. package/src/lib/ui/compile/switchPlan.ts +22 -0
  135. package/src/lib/ui/compile/tryPlan.ts +29 -0
  136. package/src/lib/ui/compile/types/SemanticToken.ts +11 -0
  137. package/src/lib/ui/compile/types/TemplateAttr.ts +8 -2
  138. package/src/lib/ui/compile/types/TemplateNode.ts +15 -2
  139. package/src/lib/ui/createScope.ts +20 -2
  140. package/src/lib/ui/dom/appendText.ts +1 -5
  141. package/src/lib/ui/dom/applyResolved.ts +1 -5
  142. package/src/lib/ui/dom/disposeRange.ts +6 -10
  143. package/src/lib/ui/dom/hydrate.ts +2 -5
  144. package/src/lib/ui/dom/isComment.ts +6 -0
  145. package/src/lib/ui/dom/mount.ts +1 -2
  146. package/src/lib/ui/dom/withScope.ts +6 -9
  147. package/src/lib/ui/effect.ts +4 -2
  148. package/src/lib/ui/navigate.ts +40 -13
  149. package/src/lib/ui/outbox.ts +30 -110
  150. package/src/lib/ui/remoteProxy.ts +160 -10
  151. package/src/lib/ui/router.ts +3 -3
  152. package/src/lib/ui/rpcOutbox/createOutboxQueue.ts +281 -0
  153. package/src/lib/ui/rpcOutbox/outboxRegistry.ts +69 -0
  154. package/src/lib/ui/runtime/createDoc.ts +3 -3
  155. package/src/lib/ui/runtime/pathSegments.ts +10 -0
  156. package/src/lib/ui/socketChannel.ts +7 -1
  157. package/src/lib/ui/types/Scope.ts +20 -5
  158. package/template/.zed/settings.json +4 -0
  159. package/template/CLAUDE.md +1 -1
  160. package/template/src/server/rpc/getHello.ts +3 -3
  161. package/template/src/ui/pages/page.abide +4 -4
  162. package/template/test/app.test.ts +2 -2
  163. package/src/lib/server/rpc/registerVerb.ts +0 -6
  164. package/src/lib/server/runtime/types/InspectorVerb.ts +0 -27
  165. package/src/lib/shared/detectVerbMethod.ts +0 -17
  166. package/src/lib/shared/types/HttpVerb.ts +0 -1
  167. package/src/lib/ui/types/Outbox.ts +0 -14
@@ -1,9 +1,12 @@
1
1
  // node:fs existsSync — Bun plugin onResolve is sync-only; Bun.file().exists() is async
2
2
  import { existsSync, statSync } from 'node:fs'
3
+ import { dirname, join } from 'node:path'
3
4
  import type { BunPlugin } from 'bun'
4
5
  import { Glob } from 'bun'
5
6
  import { abideImportName } from './lib/shared/abideImportName.ts'
6
7
  import { abideLog } from './lib/shared/abideLog.ts'
8
+ import { escapeRegex } from './lib/shared/escapeRegex.ts'
9
+ import { fileName } from './lib/shared/fileName.ts'
7
10
  import { fileStem } from './lib/shared/fileStem.ts'
8
11
  import { jsonSchemaForPromptArguments } from './lib/shared/jsonSchemaForPromptArguments.ts'
9
12
  import { manifestModule } from './lib/shared/manifestModule.ts'
@@ -65,10 +68,6 @@ function resolveExtensionUncached(path: string): string {
65
68
 
66
69
  const NS = 'abide-virtual'
67
70
 
68
- function escapeRegex(value: string): string {
69
- return value.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
70
- }
71
-
72
71
  /* Memoises a zero-arg async producer so repeat calls reuse the first in-flight promise. */
73
72
  function once<T>(produce: () => Promise<T>): () => Promise<T> {
74
73
  let promise: Promise<T> | undefined
@@ -82,7 +81,7 @@ function once<T>(produce: () => Promise<T>): () => Promise<T> {
82
81
 
83
82
  /*
84
83
  Bun plugin that wires every virtual import abide produces at build time:
85
- - `abide:rpc` — { rpcUrl: () => import(rpc-module) } HTTP-verb manifest
84
+ - `abide:rpc` — { rpcUrl: () => import(rpc-module) } HTTP-method manifest
86
85
  - `abide:sockets` — { socketName: () => import(socket-module) } socket manifest
87
86
  - `abide:pages` — { pageUrl: () => import(page.abide) } manifest
88
87
  - `abide:prompts` — { promptName: () => import(prompt-module) } manifest
@@ -93,8 +92,8 @@ Bun plugin that wires every virtual import abide produces at build time:
93
92
  - `abide:shell` — app.html content (custom or default)
94
93
 
95
94
  Also rewrites modules under src/server/rpc and src/server/sockets:
96
- - src/server/rpc/<file>.ts: each HTTP-verb export is bound to a runtime
97
- implementation — defineVerb on the server, remoteProxy on the client.
95
+ - src/server/rpc/<file>.ts: each HTTP-method export is bound to a runtime
96
+ implementation — defineRpc on the server, remoteProxy on the client.
98
97
  - src/server/sockets/<file>.ts: each `socket(opts)` export is bound to
99
98
  defineSocket on the server (with the socket name + opts) or
100
99
  socketProxy on the client (name only — opts are server-side).
@@ -149,7 +148,7 @@ export function abideResolverPlugin({
149
148
  scanDir(rpcDir, '**/*.ts').then(async (rpcFiles) => {
150
149
  const importName = await abideImportNameOnce()
151
150
  await writeRpcDts({ cwd, rpcDir, rpcFiles, importName })
152
- /* Typed createTestApp `app.rpc.<verb>` surface. */
151
+ /* Typed createTestApp `app.rpc.<rpc>` surface. */
153
152
  await writeTestRpcDts({ cwd, rpcFiles, importName })
154
153
  return rpcFiles
155
154
  }),
@@ -196,9 +195,91 @@ export function abideResolverPlugin({
196
195
  const socketsFilter = new RegExp(`^${escapeRegex(socketsDir)}/.*\\.ts$`)
197
196
  const promptsFilter = new RegExp(`^${escapeRegex(promptsDir)}/.*\\.md$`)
198
197
 
198
+ /*
199
+ Side-crossing guard (client target only). The client bundle must never pull a
200
+ server-only name into the browser. The exception is a registered rpc/socket —
201
+ `$server/rpc/*` and `$server/sockets/*` are replaced with remoteProxy/socketProxy
202
+ stubs by the onLoad hooks below — so only OTHER paths under src/server/ (helpers,
203
+ runtime/) and the public `abide/server/*` names are violations. `importerOf` records
204
+ each resolved edge so a violation can show the import chain back to its client-side
205
+ origin as evidence; it is reset per build in onStart.
206
+ */
207
+ const importerOf = new Map<string, string>()
208
+ const isProxiedServerModule = (path: string): boolean =>
209
+ path.startsWith(`${rpcDir}/`) || path.startsWith(`${socketsDir}/`)
210
+ const isServerOnlyModule = (path: string): boolean =>
211
+ path.startsWith(`${serverDir}/`) && !isProxiedServerModule(path)
212
+ const showPath = (path: string): string =>
213
+ path.startsWith(`${cwd}/`) ? path.slice(cwd.length + 1) : path
214
+ /* Walks the recorded edges from the offending importer back to a graph root (cycle-safe),
215
+ formatting each module relative to cwd — the evidence a side-crossing throws. */
216
+ function sideCrossingChain(leaf: string, importer: string): string {
217
+ const chain = [leaf, importer]
218
+ const seen = new Set([importer])
219
+ let cursor = importer
220
+ while (importerOf.has(cursor)) {
221
+ cursor = importerOf.get(cursor) as string
222
+ if (seen.has(cursor)) {
223
+ break
224
+ }
225
+ seen.add(cursor)
226
+ chain.push(cursor)
227
+ }
228
+ return chain.reverse().map(showPath).join('\n → ')
229
+ }
230
+ function throwSideCrossing(leaf: string, label: string, importer: string): never {
231
+ throw new Error(
232
+ `[abide] a client module imports the server-only name \`${label}\` — server code must not reach the browser bundle. Move it to src/shared/ or behind an RPC. Import chain:\n ${sideCrossingChain(leaf, importer)}`,
233
+ )
234
+ }
235
+ /* Records the edge and, on the client target, rejects a non-server module reaching a
236
+ server-only one. Shared by the relative-import and `$server` alias resolvers. */
237
+ function recordAndGuard(resolved: string, label: string, importer: string | undefined): void {
238
+ if (importer === undefined) {
239
+ return
240
+ }
241
+ importerOf.set(resolved, importer)
242
+ if (target === 'client' && isServerOnlyModule(resolved) && !isServerOnlyModule(importer)) {
243
+ throwSideCrossing(resolved, label, importer)
244
+ }
245
+ }
246
+
199
247
  return {
200
248
  name: 'abide-resolver',
201
249
  setup(build) {
250
+ /* Fresh edge graph each build (dev watch reuses the plugin instance).
251
+ onStart is build-time only — absent in the runtime/preload plugin context. */
252
+ build.onStart?.(() => {
253
+ importerOf.clear()
254
+ })
255
+
256
+ /*
257
+ Relative-import edge recorder + side-crossing guard. Matches `./` and `../`
258
+ specifiers, records the edge for the evidence chain, and (client target) throws
259
+ when a non-server module reaches a server-only file. Returns undefined so normal
260
+ resolution proceeds — this only observes and, on violation, aborts.
261
+ */
262
+ build.onResolve({ filter: /^\.\.?\// }, (args) => {
263
+ if (args.importer) {
264
+ const resolved = resolveExtension(join(dirname(args.importer), args.path))
265
+ recordAndGuard(resolved, args.path, args.importer)
266
+ }
267
+ return undefined
268
+ })
269
+
270
+ /*
271
+ The public `abide/server/*` names are server-only. Importing one into the client
272
+ bundle is a side-crossing (the canonical `abide` and `@abide/abide` specifiers; a
273
+ custom package alias falls through to the relative/`$server` guards). The server
274
+ target resolves these normally.
275
+ */
276
+ build.onResolve({ filter: /(^|\/)abide\/server\// }, (args) => {
277
+ if (target === 'client' && args.importer && !isServerOnlyModule(args.importer)) {
278
+ throwSideCrossing(args.path, args.path, args.importer)
279
+ }
280
+ return undefined
281
+ })
282
+
202
283
  build.onResolve(
203
284
  {
204
285
  filter: /\/_virtual\/(rpc|sockets|prompts|pages|layouts|app|config|mcp-resources|mcp|assets|public-assets|shell|app-info|cli-manifest|cli-name|cli-chrome|bundle-window|bundle-disconnected-component|bundle-disconnected)\.ts$/,
@@ -228,7 +309,11 @@ export function abideResolverPlugin({
228
309
  for (const [alias, baseDir] of Object.entries(dirAliases)) {
229
310
  build.onResolve({ filter: new RegExp(`^\\${alias}(\\/.*)?$`) }, (args) => {
230
311
  const subpath = args.path.slice(alias.length)
231
- return { path: resolveExtension(subpath ? `${baseDir}${subpath}` : baseDir) }
312
+ const resolved = resolveExtension(subpath ? `${baseDir}${subpath}` : baseDir)
313
+ /* `$server/rpc/*` + `$server/sockets/*` are proxied (allowed); other
314
+ `$server/*` imports into the client bundle are side-crossings. */
315
+ recordAndGuard(resolved, args.path, args.importer)
316
+ return { path: resolved }
232
317
  })
233
318
  }
234
319
 
@@ -264,7 +349,7 @@ export function abideResolverPlugin({
264
349
  const prepared = prepareRpcModule(source, importName)
265
350
  if (!prepared) {
266
351
  throw new Error(
267
- `[abide] src/server/rpc/${relativePath} has no \`export const <name> = <VERB>(...)\` — every $rpc module must declare exactly one remote function`,
352
+ `[abide] src/server/rpc/${relativePath} has no \`export const <name> = <METHOD>(...)\` — every $rpc module must declare exactly one remote function`,
268
353
  )
269
354
  }
270
355
  const expectedName = fileStem(relativePath)
@@ -281,22 +366,25 @@ export function abideResolverPlugin({
281
366
  so page imports resolve identically on both sides.
282
367
  */
283
368
  if (target === 'client') {
369
+ /* A durable rpc (`outbox: true`) gets the third arg so its client proxy
370
+ parks unreachable calls onto the outbox. */
371
+ const durableArg = prepared.durable ? ', { outbox: true }' : ''
284
372
  const contents = `import { remoteProxy as __abideRemoteProxy__ } from '${importName}/ui/remoteProxy';
285
- export const ${prepared.exportName} = __abideRemoteProxy__(${JSON.stringify(prepared.verb)}, ${JSON.stringify(url)});
373
+ export const ${prepared.exportName} = __abideRemoteProxy__(${JSON.stringify(prepared.method)}, ${JSON.stringify(url)}${durableArg});
286
374
  `
287
375
  return { contents, loader: 'ts' }
288
376
  }
289
377
  /*
290
- Server target: strip the user's verb import, then rewrite
291
- the `<VERB>(` call so the verb (from the identifier) and
378
+ Server target: strip the user's rpc import, then rewrite
379
+ the `<METHOD>(` call so the method (from the identifier) and
292
380
  the URL (from the file path) are threaded into the
293
- runtime constructor — defineVerb. The user's handler body
381
+ runtime constructor — defineRpc. The user's handler body
294
382
  stays intact between the parens; any generics on the call
295
383
  are dropped (they carry no runtime info). Rewriting is
296
384
  tokenizer-driven so `GET` mentions inside strings and
297
385
  comments are left alone.
298
386
  */
299
- const banner = `import { defineVerb as __abideDefineVerb__ } from '${importName}/server/rpc/defineVerb';
387
+ const banner = `import { defineRpc as __abideDefineRpc__ } from '${importName}/server/rpc/defineRpc';
300
388
  `
301
389
  return { contents: `${banner}${prepared.rewriteForServer(url)}`, loader: 'ts' }
302
390
  })
@@ -473,7 +561,7 @@ ${optionLines}
473
561
  The CLI binary's bake-time manifest. Discovery (a
474
562
  one-shot script the bundler runs separately) writes
475
563
  `${cwd}/dist/cli-manifest.json` from the populated
476
- verbRegistry; this virtual splices that JSON in as a
564
+ rpcRegistry; this virtual splices that JSON in as a
477
565
  default-exported object. Empty manifest when the
478
566
  discovery file is missing — the binary still works
479
567
  but exposes no subcommands until the user runs the
@@ -608,7 +696,7 @@ export const footer = ${JSON.stringify(footer)}
608
696
  if (args.path === 'abide:mcp') {
609
697
  /*
610
698
  The MCP server is fully framework-generated — tools from
611
- the verb registry, prompts from src/mcp/prompts, resources
699
+ the rpc registry, prompts from src/mcp/prompts, resources
612
700
  from src/mcp/resources. createMcpServer is internal; there
613
701
  is no user-authored server module. Server identity comes
614
702
  from package.json so the `mcp__<name>__*` permission prefix
@@ -791,7 +879,7 @@ async function scanPages(pagesDir: string): Promise<PagesScan> {
791
879
  return { pageFiles: [], layoutFiles: [] }
792
880
  }
793
881
  const allFiles = await Array.fromAsync(new Glob('**/*.abide').scan({ cwd: pagesDir }))
794
- const leafIs = (name: string) => (file: string) => (file.split('/').pop() ?? '') === name
882
+ const leafIs = (name: string) => (file: string) => fileName(file) === name
795
883
  return {
796
884
  pageFiles: allFiles.filter(leafIs('page.abide')),
797
885
  layoutFiles: allFiles.filter(leafIs('layout.abide')),
@@ -800,7 +888,7 @@ async function scanPages(pagesDir: string): Promise<PagesScan> {
800
888
 
801
889
  /*
802
890
  Walks one registry directory once: src/server/rpc (every `.ts` file is an
803
- HTTP-verb rpc handler), src/server/sockets (each `.ts` file declares one
891
+ HTTP-method rpc handler), src/server/sockets (each `.ts` file declares one
804
892
  socket, loaded lazily on first sub/pub frame), or src/mcp/prompts (each `.md`
805
893
  file declares one MCP prompt — frontmatter for metadata, body for the
806
894
  template). Returns an empty list when the directory doesn't exist so an app
package/src/buildCli.ts CHANGED
@@ -21,7 +21,7 @@ the compiled server beside it, so `/start` can spawn a local instance.
21
21
  1. Client build (once): `build` produces the platform-independent `dist/_app`
22
22
  the server binaries embed. It clears dist first, so it runs before everything.
23
23
  2. Discovery: build the discovery entry into a temporary JS bundle and run it. It
24
- imports every rpc/socket module so defineVerb / defineSocket populate the
24
+ imports every rpc/socket module so defineRpc / defineSocket populate the
25
25
  registries, then prints the CLI manifest to stdout → `dist/cli-manifest.json`.
26
26
  3. Per target: a server binary (`compile`, reusing the shared `dist/_app` via
27
27
  `buildClient:false`) plus the CLI binary, written side by side. The resolver's
@@ -3,14 +3,14 @@ import { rpc } from './_virtual/rpc.ts'
3
3
  // @ts-expect-error virtual module resolved by abideResolverPlugin
4
4
  import { sockets } from './_virtual/sockets.ts'
5
5
  import type { CliManifestEntry } from './lib/cli/types/CliManifestEntry.ts'
6
- import { verbRegistry } from './lib/server/rpc/verbRegistry.ts'
6
+ import { rpcRegistry } from './lib/server/rpc/rpcRegistry.ts'
7
7
  import { socketOperations } from './lib/server/sockets/socketOperations.ts'
8
8
  import { socketRegistry } from './lib/server/sockets/socketRegistry.ts'
9
9
  import { commandNameForUrl } from './lib/shared/commandNameForUrl.ts'
10
10
  import { jsonSchemaForSchema } from './lib/shared/jsonSchemaForSchema.ts'
11
11
 
12
12
  /*
13
- One-shot script that imports every rpc + socket module so defineVerb /
13
+ One-shot script that imports every rpc + socket module so defineRpc /
14
14
  defineSocket populate the process-wide registries, then prints the CLI
15
15
  manifest to stdout as JSON. Used by buildCli to bake the manifest into
16
16
  the standalone binary at build time without resorting to static source
@@ -23,7 +23,7 @@ await Promise.all([
23
23
 
24
24
  const manifest: Record<string, CliManifestEntry> = {}
25
25
 
26
- for (const entry of verbRegistry.values()) {
26
+ for (const entry of rpcRegistry.values()) {
27
27
  if (!entry.clients.cli) {
28
28
  continue
29
29
  }
@@ -8,7 +8,7 @@ handles it:
8
8
  if (event.detail.name === 'sync') syncNow()
9
9
  })
10
10
 
11
- Emitting an event (rather than calling a verb directly) is what lets a menu
11
+ Emitting an event (rather than calling a rpc directly) is what lets a menu
12
12
  drive parameterised work: a click carries no arguments, so the app computes
13
13
  them and makes the call itself. `shortcut` is the key for the Cmd-based
14
14
  equivalent (e.g. `'r'` → Cmd-R).
@@ -1,8 +1,8 @@
1
- import { dispatchVerbInProcess } from '../server/rpc/dispatchVerbInProcess.ts'
2
- import { findVerbByCommandName } from '../server/rpc/findVerbByCommandName.ts'
1
+ import { dispatchRpcInProcess } from '../server/rpc/dispatchRpcInProcess.ts'
2
+ import { findRpcByCommandName } from '../server/rpc/findRpcByCommandName.ts'
3
3
  import { buildRpcProxy } from '../shared/buildRpcProxy.ts'
4
4
  import { buildRpcRequest } from '../shared/buildRpcRequest.ts'
5
- import type { HttpVerb } from '../shared/types/HttpVerb.ts'
5
+ import type { HttpMethod } from '../shared/types/HttpMethod.ts'
6
6
  import type { RpcInvoker } from '../shared/types/RpcInvoker.ts'
7
7
  import type { CliManifest } from './types/CliManifest.ts'
8
8
 
@@ -24,8 +24,8 @@ decided at construction:
24
24
  against `<url>/<manifest[name].url>` using the manifest's method.
25
25
  Auth header is set from `token` when provided.
26
26
  - Without `url`: in-process mode. Each property access looks up the
27
- verb in the registry (populated by importing the project's rpc
28
- modules) and calls `verb.fetch(synthesizedRequest)` — same code
27
+ rpc in the registry (populated by importing the project's rpc
28
+ modules) and calls `rpc.fetch(synthesizedRequest)` — same code
29
29
  path the HTTP router uses, no network hop.
30
30
 
31
31
  The `manifest` is the bundler-emitted CLI manifest baked into the thin
@@ -62,9 +62,9 @@ export function createClient<Api extends AnyApi = AnyApi>(opts?: {
62
62
  undefined when the name is unknown in the active mode. Remote mode (url set)
63
63
  resolves method + url from the baked manifest — registry fallback for
64
64
  same-project callers — and sends the synthesized Request over the network.
65
- In-process mode resolves the verb from the registry and routes through
66
- dispatchVerbInProcess, the same synthesize-and-fetch the MCP dispatcher
67
- uses, so the two consumer surfaces can't drift on how a verb is invoked.
65
+ In-process mode resolves the rpc from the registry and routes through
66
+ dispatchRpcInProcess, the same synthesize-and-fetch the MCP dispatcher
67
+ uses, so the two consumer surfaces can't drift on how a rpc is invoked.
68
68
  */
69
69
  function resolveSend(name: string): ((args?: unknown) => Promise<Response>) | undefined {
70
70
  if (url) {
@@ -83,12 +83,12 @@ export function createClient<Api extends AnyApi = AnyApi>(opts?: {
83
83
  }),
84
84
  )
85
85
  }
86
- const entry = findVerbByCommandName(name)
86
+ const entry = findRpcByCommandName(name)
87
87
  if (!entry) {
88
88
  return undefined
89
89
  }
90
90
  return (args) =>
91
- dispatchVerbInProcess({
91
+ dispatchRpcInProcess({
92
92
  remote: entry.remote,
93
93
  args,
94
94
  baseUrl: 'http://localhost/',
@@ -99,8 +99,8 @@ export function createClient<Api extends AnyApi = AnyApi>(opts?: {
99
99
  // Remote-mode registry fallback for callers passing a url but no manifest.
100
100
  function registryCommand(
101
101
  name: string,
102
- ): { method: HttpVerb; url: string; accept?: string } | undefined {
103
- const found = findVerbByCommandName(name)
102
+ ): { method: HttpMethod; url: string; accept?: string } | undefined {
103
+ const found = findRpcByCommandName(name)
104
104
  return found ? { method: found.remote.method, url: found.remote.url } : undefined
105
105
  }
106
106
 
@@ -12,7 +12,7 @@ import type { CliManifest } from './types/CliManifest.ts'
12
12
  Runs one RPC command against a target server and prints the result, returning a
13
13
  process exit code. Shared by the one-shot path (runCli) and the interactive
14
14
  session (runSession) so a command behaves identically typed at the shell or at
15
- the session prompt. Streaming responses (sse/jsonl — a streaming verb or a socket
15
+ the session prompt. Streaming responses (sse/jsonl — a streaming rpc or a socket
16
16
  `tail`) print frame-by-frame as NDJSON; everything else decodes and prints once.
17
17
  */
18
18
  export async function dispatchCommand({
@@ -5,7 +5,7 @@ import type { CliTarget } from './types/CliTarget.ts'
5
5
  Prints the session's connection line. A local instance (spawned child) reads as
6
6
  "running a local instance"; a remote one reads as "connected to <name>", using the
7
7
  name the target already carries from its resolve-time probe and only re-probing
8
- when it doesn't. No target → the not-connected hint listing the verbs.
8
+ when it doesn't. No target → the not-connected hint listing the rpcs.
9
9
  */
10
10
  export async function printSessionStatus(target: CliTarget | undefined): Promise<void> {
11
11
  if (!target) {
@@ -11,7 +11,7 @@ const AUTO_START_CEILING_MS = 3000
11
11
 
12
12
  /*
13
13
  Resolves the connection to resume when the CLI runs without an explicit
14
- connection verb — the terminal analogue of the bundle's resolveLaunchTarget.
14
+ connection rpc — the terminal analogue of the bundle's resolveLaunchTarget.
15
15
  Reads the saved intent:
16
16
  - embedded → boot a fresh local instance (bounded; undefined on failure)
17
17
  - url, still alive → connect to it
@@ -67,7 +67,7 @@ a bare word runs a command:
67
67
  /disconnect → forget the saved connection, exit
68
68
  <cmd> [--flags] → one-shot RPC against the resumed target
69
69
 
70
- The connection verbs are `/`-prefixed only — no bare aliases — so a bare word is
70
+ The connection rpcs are `/`-prefixed only — no bare aliases — so a bare word is
71
71
  always an RPC command and never collides. Env layers ABIDE_APP_URL/ABIDE_APP_TOKEN (shell >
72
72
  data-dir > binary-dir) supply the baked default a fresh download resumes against.
73
73
  */
@@ -2,7 +2,7 @@ import type { CliManifestEntry } from './CliManifestEntry.ts'
2
2
 
3
3
  /*
4
4
  Map from rpc export-name (e.g. "getReport") to its manifest entry. Built
5
- by the bundler from the same verbRegistry MCP consumes; entries are
5
+ by the bundler from the same rpcRegistry MCP consumes; entries are
6
6
  emitted only for rpcs with `clients.cli: true`. The CLI binary and any
7
7
  programmatic createClient caller read this to dispatch calls.
8
8
  */
@@ -1,4 +1,4 @@
1
- import type { HttpVerb } from '../../shared/types/HttpVerb.ts'
1
+ import type { HttpMethod } from '../../shared/types/HttpMethod.ts'
2
2
 
3
3
  /*
4
4
  Per-command manifest entry baked into the standalone CLI binary by the
@@ -9,7 +9,7 @@ both rpcs and socket commands — a socket `tail` is a GET against
9
9
  streams it live; a socket `publish` is a POST to the same path.
10
10
  */
11
11
  export type CliManifestEntry = {
12
- method: HttpVerb
12
+ method: HttpMethod
13
13
  url: string
14
14
  jsonSchema?: Record<string, unknown>
15
15
  // Request Accept header. Socket tail sets text/event-stream to stream live frames.
@@ -1,8 +1,8 @@
1
- import type { HttpVerb } from '../shared/types/HttpVerb.ts'
1
+ import type { HttpMethod } from '../shared/types/HttpMethod.ts'
2
2
 
3
3
  /*
4
- Maps an HTTP verb to MCP tool annotations so a model can tell a read from
5
- a write before calling. Abide derives these from the verb the RPC was
4
+ Maps an HTTP method to MCP tool annotations so a model can tell a read from
5
+ a write before calling. Abide derives these from the rpc the RPC was
6
6
  declared with rather than asking the author to repeat the intent:
7
7
  - GET / HEAD → read-only, non-destructive
8
8
  - POST → creates; not idempotent, not (necessarily) destructive
@@ -10,9 +10,9 @@ declared with rather than asking the author to repeat the intent:
10
10
  - PATCH → modifies; destructive, not idempotent
11
11
  - DELETE → removes; idempotent + destructive
12
12
  The shape matches MCP's ToolAnnotations (readOnlyHint / destructiveHint /
13
- idempotentHint); fields a verb doesn't imply are left off.
13
+ idempotentHint); fields a rpc doesn't imply are left off.
14
14
  */
15
- export function annotationsForMethod(method: HttpVerb): Record<string, boolean> {
15
+ export function annotationsForMethod(method: HttpMethod): Record<string, boolean> {
16
16
  switch (method) {
17
17
  case 'GET':
18
18
  case 'HEAD':
@@ -14,10 +14,10 @@ object whose `handle(request)` is the function the bun route at
14
14
  default-constructs it; there is no user-authored server module. Server
15
15
  name/version default from package.json.
16
16
 
17
- Tools are derived from every verb with `clients.mcp: true` (auto-on for
18
- read-only verbs that carry a schema; mutating verbs opt in explicitly)
17
+ Tools are derived from every rpc with `clients.mcp: true` (auto-on for
18
+ read-only rpcs that carry a schema; mutating rpcs opt in explicitly)
19
19
  and from every socket with `clients.mcp: true` (a `<base>-tail` read tool
20
- plus a `<base>-publish` tool when clientPublish is set). The HTTP verb
20
+ plus a `<base>-publish` tool when clientPublish is set). The HTTP method
21
21
  feeds each rpc tool's annotations. Auth inherits from the inbound request
22
22
  — bearer / cookie headers flow into the synthesized Request that hits
23
23
  each rpc handler. An optional `authorize` hook in opts can short-circuit
@@ -1,7 +1,7 @@
1
1
  import { promptRegistry } from '../server/prompts/promptRegistry.ts'
2
- import { dispatchVerbInProcess } from '../server/rpc/dispatchVerbInProcess.ts'
3
- import { findVerbByCommandName } from '../server/rpc/findVerbByCommandName.ts'
4
- import { verbRegistry } from '../server/rpc/verbRegistry.ts'
2
+ import { dispatchRpcInProcess } from '../server/rpc/dispatchRpcInProcess.ts'
3
+ import { findRpcByCommandName } from '../server/rpc/findRpcByCommandName.ts'
4
+ import { rpcRegistry } from '../server/rpc/rpcRegistry.ts'
5
5
  import { socketOperations } from '../server/sockets/socketOperations.ts'
6
6
  import { socketRegistry } from '../server/sockets/socketRegistry.ts'
7
7
  import { abideLog } from '../shared/abideLog.ts'
@@ -58,12 +58,12 @@ export type McpSurface = {
58
58
  /*
59
59
  Builds the array of MCP tool descriptors.
60
60
 
61
- RPCs: every verb with clients.mcp=true becomes one tool named after the
62
- export's URL (folder segments joined with `-`). The HTTP verb feeds the
61
+ RPCs: every rpc with clients.mcp=true becomes one tool named after the
62
+ export's URL (folder segments joined with `-`). The HTTP method feeds the
63
63
  tool's annotations (readOnlyHint / destructiveHint / idempotentHint) so
64
64
  a model can tell a read from a write; reads auto-expose while mutating
65
- verbs require an explicit clients.mcp (see resolveClientFlags). When the
66
- verb declares an `outputSchema` it's advertised as the tool outputSchema.
65
+ rpcs require an explicit clients.mcp (see resolveClientFlags). When the
66
+ rpc declares an `outputSchema` it's advertised as the tool outputSchema.
67
67
 
68
68
  Sockets: every socket with clients.mcp=true contributes a `<base>-tail`
69
69
  read tool (recent buffered messages) and, when clientPublish is set, a
@@ -71,7 +71,7 @@ read tool (recent buffered messages) and, when clientPublish is set, a
71
71
  */
72
72
  export function buildTools(): ToolDescriptor[] {
73
73
  const tools: ToolDescriptor[] = []
74
- for (const entry of verbRegistry.values()) {
74
+ for (const entry of rpcRegistry.values()) {
75
75
  if (!entry.clients.mcp) {
76
76
  continue
77
77
  }
@@ -154,7 +154,7 @@ export function buildPrompts(): PromptDescriptor[] {
154
154
  }
155
155
 
156
156
  /* MCP tool-dispatch spans, opt-in via DEBUG=abide:mcp — a model's tool call,
157
- wrapping the underlying verb dispatch in the same trace. */
157
+ wrapping the underlying rpc dispatch in the same trace. */
158
158
  const mcpLog = abideLog.channel('abide:mcp')
159
159
 
160
160
  function textResult(text: string, isError = false): ToolResult {
@@ -203,7 +203,7 @@ function callSocketTool(
203
203
 
204
204
  /*
205
205
  Tool dispatch. RPC tools synthesize a Request (with forwarded auth
206
- headers from `inbound`) and pipe it through verb.fetch inside the request
206
+ headers from `inbound`) and pipe it through rpc.fetch inside the request
207
207
  scope — the same seam the HTTP router crosses, so validation, the handler,
208
208
  and the request-scoped helpers (per-call cache(), cookies(), request())
209
209
  behave identically. A handler throw is caught by the scope and framed as
@@ -217,14 +217,14 @@ export async function callTool(
217
217
  args: Record<string, unknown> | undefined,
218
218
  inbound: Request,
219
219
  ): Promise<ToolResult> {
220
- const entry = findVerbByCommandName(toolName)
220
+ const entry = findRpcByCommandName(toolName)
221
221
  if (entry) {
222
- /* A verb owns this name. If it isn't mcp-exposed it's still unavailable —
222
+ /* A rpc owns this name. If it isn't mcp-exposed it's still unavailable —
223
223
  don't fall through to a socket op that happens to share the name. */
224
224
  if (!entry.clients.mcp) {
225
225
  throw new Error(`unknown tool: ${toolName}`)
226
226
  }
227
- const response = await dispatchVerbInProcess({
227
+ const response = await dispatchRpcInProcess({
228
228
  remote: entry.remote,
229
229
  args,
230
230
  baseUrl: `${new URL(inbound.url).origin}/`,
@@ -264,7 +264,7 @@ export function renderPrompt(
264
264
 
265
265
  /*
266
266
  Projects the app's MCP surface for an in-process consumer bound to `request`
267
- — tool calls forward that request's auth headers into the verb handler, so
267
+ — tool calls forward that request's auth headers into the rpc handler, so
268
268
  the model acts with the caller's identity. Used by `agent()`.
269
269
  */
270
270
  export function mcpSurface(request: Request): McpSurface {
@@ -7,7 +7,7 @@ package.json by the bundler when MCP is wired into createServer).
7
7
  response. Defaults come from the project's package.json.
8
8
  - `authorize`: optional boundary check. Runs once per MCP request before
9
9
  any tool/resource dispatch. Throw HttpError (or any Error) to reject.
10
- Per-tool authorization stays in the underlying verb handler.
10
+ Per-tool authorization stays in the underlying rpc handler.
11
11
  */
12
12
  export type McpServerOptions = {
13
13
  name?: string
@@ -1,10 +1,10 @@
1
- import type { VerbHelper } from './rpc/types/VerbHelper.ts'
1
+ import type { MutatingRpcHelper } from './rpc/types/RpcHelper.ts'
2
2
  import { unprocessed } from './rpc/unprocessed.ts'
3
3
 
4
4
  /*
5
- DELETE verb helper. The bundler rewrites every `export const x = DELETE(fn)` inside
6
- `src/server/rpc/<file>.ts` into a defineVerb call (server target) or a
5
+ DELETE rpc helper. The bundler rewrites every `export const x = DELETE(fn)` inside
6
+ `src/server/rpc/<file>.ts` into a defineRpc call (server target) or a
7
7
  remoteProxy stub (client target). Calling this directly throws.
8
8
  */
9
9
  // @documentation rpc
10
- export const DELETE: VerbHelper = (_fn: any, _opts?: any) => unprocessed('DELETE')
10
+ export const DELETE: MutatingRpcHelper = (_fn: any, _opts?: any) => unprocessed('DELETE')
@@ -1,10 +1,10 @@
1
- import type { VerbHelper } from './rpc/types/VerbHelper.ts'
1
+ import type { RpcHelper } from './rpc/types/RpcHelper.ts'
2
2
  import { unprocessed } from './rpc/unprocessed.ts'
3
3
 
4
4
  /*
5
- GET verb helper. The bundler rewrites every `export const x = GET(fn)` inside
6
- `src/server/rpc/<file>.ts` into a defineVerb call (server target) or a
5
+ GET rpc helper. The bundler rewrites every `export const x = GET(fn)` inside
6
+ `src/server/rpc/<file>.ts` into a defineRpc call (server target) or a
7
7
  remoteProxy stub (client target). Calling this directly throws.
8
8
  */
9
9
  // @documentation rpc
10
- export const GET: VerbHelper = (_fn: any, _opts?: any) => unprocessed('GET')
10
+ export const GET: RpcHelper = (_fn: any, _opts?: any) => unprocessed('GET')
@@ -1,10 +1,10 @@
1
- import type { VerbHelper } from './rpc/types/VerbHelper.ts'
1
+ import type { RpcHelper } from './rpc/types/RpcHelper.ts'
2
2
  import { unprocessed } from './rpc/unprocessed.ts'
3
3
 
4
4
  /*
5
- HEAD verb helper. The bundler rewrites every `export const x = HEAD(fn)` inside
6
- `src/server/rpc/<file>.ts` into a defineVerb call (server target) or a
5
+ HEAD rpc helper. The bundler rewrites every `export const x = HEAD(fn)` inside
6
+ `src/server/rpc/<file>.ts` into a defineRpc call (server target) or a
7
7
  remoteProxy stub (client target). Calling this directly throws.
8
8
  */
9
9
  // @documentation rpc
10
- export const HEAD: VerbHelper = (_fn: any, _opts?: any) => unprocessed('HEAD')
10
+ export const HEAD: RpcHelper = (_fn: any, _opts?: any) => unprocessed('HEAD')
@@ -1,10 +1,10 @@
1
- import type { VerbHelper } from './rpc/types/VerbHelper.ts'
1
+ import type { MutatingRpcHelper } from './rpc/types/RpcHelper.ts'
2
2
  import { unprocessed } from './rpc/unprocessed.ts'
3
3
 
4
4
  /*
5
- PATCH verb helper. The bundler rewrites every `export const x = PATCH(fn)` inside
6
- `src/server/rpc/<file>.ts` into a defineVerb call (server target) or a
5
+ PATCH rpc helper. The bundler rewrites every `export const x = PATCH(fn)` inside
6
+ `src/server/rpc/<file>.ts` into a defineRpc call (server target) or a
7
7
  remoteProxy stub (client target). Calling this directly throws.
8
8
  */
9
9
  // @documentation rpc
10
- export const PATCH: VerbHelper = (_fn: any, _opts?: any) => unprocessed('PATCH')
10
+ export const PATCH: MutatingRpcHelper = (_fn: any, _opts?: any) => unprocessed('PATCH')
@@ -1,10 +1,10 @@
1
- import type { VerbHelper } from './rpc/types/VerbHelper.ts'
1
+ import type { MutatingRpcHelper } from './rpc/types/RpcHelper.ts'
2
2
  import { unprocessed } from './rpc/unprocessed.ts'
3
3
 
4
4
  /*
5
- POST verb helper. The bundler rewrites every `export const x = POST(fn)` inside
6
- `src/server/rpc/<file>.ts` into a defineVerb call (server target) or a
5
+ POST rpc helper. The bundler rewrites every `export const x = POST(fn)` inside
6
+ `src/server/rpc/<file>.ts` into a defineRpc call (server target) or a
7
7
  remoteProxy stub (client target). Calling this directly throws.
8
8
  */
9
9
  // @documentation rpc
10
- export const POST: VerbHelper = (_fn: any, _opts?: any) => unprocessed('POST')
10
+ export const POST: MutatingRpcHelper = (_fn: any, _opts?: any) => unprocessed('POST')
@@ -1,10 +1,10 @@
1
- import type { VerbHelper } from './rpc/types/VerbHelper.ts'
1
+ import type { MutatingRpcHelper } from './rpc/types/RpcHelper.ts'
2
2
  import { unprocessed } from './rpc/unprocessed.ts'
3
3
 
4
4
  /*
5
- PUT verb helper. The bundler rewrites every `export const x = PUT(fn)` inside
6
- `src/server/rpc/<file>.ts` into a defineVerb call (server target) or a
5
+ PUT rpc helper. The bundler rewrites every `export const x = PUT(fn)` inside
6
+ `src/server/rpc/<file>.ts` into a defineRpc call (server target) or a
7
7
  remoteProxy stub (client target). Calling this directly throws.
8
8
  */
9
9
  // @documentation rpc
10
- export const PUT: VerbHelper = (_fn: any, _opts?: any) => unprocessed('PUT')
10
+ export const PUT: MutatingRpcHelper = (_fn: any, _opts?: any) => unprocessed('PUT')