{"_id":"@bandeira-tech/b3nd-move","_rev":"3-68dbc02b6c75dfbb9db13caed90cfd19","name":"@bandeira-tech/b3nd-move","dist-tags":{"latest":"0.21.0"},"versions":{"0.18.2":{"name":"@bandeira-tech/b3nd-move","version":"0.18.2","license":"MIT","_id":"@bandeira-tech/b3nd-move@0.18.2","maintainers":[{"name":"r-bandeira-tech","email":"bandeira-tech@pm.me"}],"homepage":"https://github.com/bandeira-tech/b3nd-move#readme","bugs":{"url":"https://github.com/bandeira-tech/b3nd-move/issues"},"dist":{"shasum":"bb3fb3ef783a24af9426e2809c851b36255a94e6","tarball":"https://registry.npmjs.org/@bandeira-tech/b3nd-move/-/b3nd-move-0.18.2.tgz","fileCount":172,"integrity":"sha512-yHRdpHtSGeCEu6mwkkYJgjmT8AjD2gweNIB+iwv1SDUp+stOY+vctp6h65SnYq9RxcoOr1yXdlB+wUJQLbMEBA==","signatures":[{"sig":"MEUCIB42iDJ6Lqwn9PlXqygEhUgyyRjd/Ov2kxvkPDqCuVL1AiEA+vIDT8JpVfwFFkL9s/0gDlsOlc4SQaUsDE+xHcjJMHQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":489577},"module":"./esm/http/service.js","engines":{"node":">=20"},"exports":{"./http/client":{"types":"./esm/http/client.d.ts","import":"./esm/http/client.js"},"./mcp/service":{"types":"./esm/mcp/service.d.ts","import":"./esm/mcp/service.js"},"./http/service":{"types":"./esm/http/service.d.ts","import":"./esm/http/service.js"},"./grpc/http/client":{"types":"./esm/grpc/http/client.d.ts","import":"./esm/grpc/http/client.js"},"./grpc/proto/types":{"types":"./esm/grpc/proto/gen/b3nd_pb.d.ts","import":"./esm/grpc/proto/gen/b3nd_pb.js"},"./mcp/http/service":{"types":"./esm/mcp/http/service.d.ts","import":"./esm/mcp/http/service.js"},"./grpc/http/service":{"types":"./esm/grpc/http/service.d.ts","import":"./esm/grpc/http/service.js"},"./grpc/proto/convert":{"types":"./esm/grpc/proto/convert.d.ts","import":"./esm/grpc/proto/convert.js"}},"gitHead":"f32a5b889039d010c94905fcc1a3f703935e04f4","scripts":{},"_npmUser":{"name":"r-bandeira-tech","email":"bandeira-tech@pm.me"},"repository":{"url":"git+https://github.com/bandeira-tech/b3nd-move.git","type":"git"},"_npmVersion":"9.6.3","description":"B3nd Move — encoding, transport, decoding. Portable service handlers and clients for each transport (HTTP, WebSocket, gRPC-HTTP, MCP).","directories":{},"sideEffects":false,"_nodeVersion":"18.15.0","dependencies":{"canonicalize":"2.0.0","@bufbuild/protobuf":"^2.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/b3nd-move_0.18.2_1781823228970_0.6712111684080595","host":"s3://npm-registry-packages-npm-production"}},"0.20.1":{"name":"@bandeira-tech/b3nd-move","version":"0.20.1","license":"MIT","_id":"@bandeira-tech/b3nd-move@0.20.1","maintainers":[{"name":"r-bandeira-tech","email":"bandeira-tech@pm.me"}],"homepage":"https://github.com/bandeira-tech/b3nd-move#readme","bugs":{"url":"https://github.com/bandeira-tech/b3nd-move/issues"},"dist":{"shasum":"87be90896835d81e9814c593316a3becfc19f61e","tarball":"https://registry.npmjs.org/@bandeira-tech/b3nd-move/-/b3nd-move-0.20.1.tgz","fileCount":181,"integrity":"sha512-tYPX4K/bFyZDidygiEAJ0uDMzlN6KRzxvcllHcyWUi1U2XX+9nsFMb6S3gpalqhWmCAH+FCD8g/SrosncI6E/w==","signatures":[{"sig":"MEQCIF2M7Tg8+fAZxLYNQ/zfFsq/0KBgVqsSVb5fC7jUuLS2AiAPdRTc8F1CgD5rLkcykMTmxWB3X1NZAZgRXFJtV6bVhA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bandeira-tech%2fb3nd-move@0.20.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":511124},"module":"./esm/http/service.js","engines":{"node":">=20"},"exports":{"./http/client":{"types":"./esm/http/client.d.ts","import":"./esm/http/client.js"},"./mcp/service":{"types":"./esm/mcp/service.d.ts","import":"./esm/mcp/service.js"},"./http/service":{"types":"./esm/http/service.d.ts","import":"./esm/http/service.js"},"./grpc/http/client":{"types":"./esm/grpc/http/client.d.ts","import":"./esm/grpc/http/client.js"},"./grpc/proto/types":{"types":"./esm/grpc/proto/gen/b3nd_pb.d.ts","import":"./esm/grpc/proto/gen/b3nd_pb.js"},"./mcp/http/service":{"types":"./esm/mcp/http/service.d.ts","import":"./esm/mcp/http/service.js"},"./grpc/http/service":{"types":"./esm/grpc/http/service.d.ts","import":"./esm/grpc/http/service.js"},"./grpc/proto/convert":{"types":"./esm/grpc/proto/convert.d.ts","import":"./esm/grpc/proto/convert.js"}},"gitHead":"2588fa8bae46167e8bdc64214b33adeffc0afd4f","scripts":{},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:ce1f62ad-2e12-4d5b-850e-40143785f2e8"}},"repository":{"url":"git+https://github.com/bandeira-tech/b3nd-move.git","type":"git"},"_npmVersion":"12.0.1","description":"B3nd Move — encoding, transport, decoding. Portable service handlers and clients for each transport (HTTP, WebSocket, gRPC-HTTP, MCP).","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","dependencies":{"canonicalize":"2.0.0","@bufbuild/protobuf":"^2.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/b3nd-move_0.20.1_1783937756343_0.1850191202179845","host":"s3://npm-registry-packages-npm-production"}},"0.21.0":{"name":"@bandeira-tech/b3nd-move","version":"0.21.0","description":"B3nd Move — encoding, transport, decoding. Portable service handlers and clients for each transport (HTTP, WebSocket, gRPC-HTTP, MCP).","homepage":"https://github.com/bandeira-tech/b3nd-move#readme","repository":{"type":"git","url":"git+https://github.com/bandeira-tech/b3nd-move.git"},"license":"MIT","bugs":{"url":"https://github.com/bandeira-tech/b3nd-move/issues"},"module":"./esm/http/service.js","exports":{"./http/service":{"types":"./esm/http/service.d.ts","import":"./esm/http/service.js"},"./http/client":{"types":"./esm/http/client.d.ts","import":"./esm/http/client.js"},"./ws/client":{"types":"./esm/ws/client.d.ts","import":"./esm/ws/client.js"},"./grpc/http/service":{"types":"./esm/grpc/http/service.d.ts","import":"./esm/grpc/http/service.js"},"./grpc/http/client":{"types":"./esm/grpc/http/client.d.ts","import":"./esm/grpc/http/client.js"},"./grpc/proto/types":{"types":"./esm/grpc/proto/gen/b3nd_pb.d.ts","import":"./esm/grpc/proto/gen/b3nd_pb.js"},"./grpc/proto/convert":{"types":"./esm/grpc/proto/convert.d.ts","import":"./esm/grpc/proto/convert.js"},"./mcp/service":{"types":"./esm/mcp/service.d.ts","import":"./esm/mcp/service.js"},"./mcp/http/service":{"types":"./esm/mcp/http/service.d.ts","import":"./esm/mcp/http/service.js"}},"scripts":{},"engines":{"node":">=20"},"sideEffects":false,"publishConfig":{"access":"public"},"dependencies":{"@bufbuild/protobuf":"^2.2.0","canonicalize":"2.0.0"},"gitHead":"6b7b82ecfc397c857c02c1da800fcad9082a4db1","_id":"@bandeira-tech/b3nd-move@0.21.0","_nodeVersion":"22.23.1","_npmVersion":"12.0.2","dist":{"integrity":"sha512-D92UyBmeooNukQnrHMD5oDdUz7hI89AIZ/TSbFDks/ZUuxk98pPBi6veQgu8GC3reKThhmJxO07uMnXrMG15FQ==","shasum":"7a0cf19deb6def2f97f4505f0a89d8d7d78b54c4","tarball":"https://registry.npmjs.org/@bandeira-tech/b3nd-move/-/b3nd-move-0.21.0.tgz","fileCount":187,"unpackedSize":536404,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bandeira-tech%2fb3nd-move@0.21.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCmf8V77QcBz138jRkrdtlHIsw58V/D781OtAsqnJiusQIhALRqmb02gRpeAENJVNgSkCwryGwUcs4yKXcPdpPQtBdQ"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:ce1f62ad-2e12-4d5b-850e-40143785f2e8"}},"directories":{},"maintainers":[{"name":"r-bandeira-tech","email":"bandeira-tech@pm.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/b3nd-move_0.21.0_1785497062752_0.6290498131534938"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-18T22:53:48.860Z","modified":"2026-07-31T11:24:23.288Z","0.18.2":"2026-06-18T22:53:49.128Z","0.20.1":"2026-07-13T10:15:56.535Z","0.21.0":"2026-07-31T11:24:22.965Z"},"bugs":{"url":"https://github.com/bandeira-tech/b3nd-move/issues"},"license":"MIT","homepage":"https://github.com/bandeira-tech/b3nd-move#readme","repository":{"type":"git","url":"git+https://github.com/bandeira-tech/b3nd-move.git"},"description":"B3nd Move — encoding, transport, decoding. Portable service handlers and clients for each transport (HTTP, WebSocket, gRPC-HTTP, MCP).","maintainers":[{"name":"r-bandeira-tech","email":"bandeira-tech@pm.me"}],"readme":"# B3nd Move\n\nEncoding, transport, decoding. The moving layer for B3nd.\n\nFor each supported transport, `b3nd-move` ships two halves over a `Rig`: a\n**service** (incoming bytes → decode → drive the rig → encode → outgoing bytes)\nand a **client** that implements `ProtocolInterfaceNode`. The client side is the\nload-bearing detail — a client speaking one wire drops into a rig route exactly\nlike an in-process node, so any rig can be served over any subset of HTTP,\nWebSocket, gRPC-over-HTTP, and MCP while its individual routes are backed by\n`b3nd-move` clients pointing at upstream nodes on whatever wire they happen to\nspeak.\n\n## Example: HTTP-backed reads, WS-backed receives, served over gRPC\n\n```typescript\nimport { connection, Rig } from \"@bandeira-tech/b3nd-core\";\nimport { HttpClient } from \"@bandeira-tech/b3nd-move/http/client\";\nimport { WebSocketClient } from \"@bandeira-tech/b3nd-move/ws/client\";\nimport { grpcHttpApi } from \"@bandeira-tech/b3nd-move/grpc/http/service\";\nimport { httpOutputsFrame } from \"@bandeira-tech/b3nd-move/codecs/http\";\nimport { wsJsonEnvelope } from \"@bandeira-tech/b3nd-move/codecs/ws\";\nimport { grpcProto } from \"@bandeira-tech/b3nd-move/codecs/grpc\";\n\nconst reads = new HttpClient({\n  url: \"https://content.example.com\",\n  codec: httpOutputsFrame(),\n});\nconst writes = new WebSocketClient({\n  url: \"wss://ingest.example.com\",\n  codec: wsJsonEnvelope(),\n});\n\nconst rig = new Rig({\n  routes: {\n    read: [connection(reads, [\"*\"])],\n    receive: [connection(writes, [\"*\"])],\n  },\n});\n\nDeno.serve({ port: 50051 }, grpcHttpApi(rig, { codec: grpcProto() }));\n```\n\nA gRPC client hits one endpoint; reads fan out to the HTTP upstream, receives\nfan out to the WS upstream. Swap `grpcHttpApi` for `httpApi`, `wsApi`, or any\ncustom service handler without touching the rig.\n\n## Building custom network APIs\n\nTwo layers sit beneath the stock `httpApi` / `wsApi` / `grpcHttpApi` handlers.\nPick the higher one when you can; drop a level when you can't.\n\nThe **content facets** front one URI of `rig.read` / `rig.receive` with a\nhost-controlled response shape or body decoder — for consumers that can't speak\nthe JSON wire (`<img src>`, file uploads, CDNs):\n\n```typescript\nimport { httpGetContentApi } from \"@bandeira-tech/b3nd-move/http-get-content/service\";\nimport { payloadResponseMap as map } from \"@bandeira-tech/b3nd-move/http-get-content/payload-response-map\";\n\nDeno.serve(\n  { port: 3000 },\n  httpGetContentApi(rig, {\n    payloadResponseMap: map.byExtension({\n      png: map.fromField(\"bytes\", { contentType: \"image/png\" }),\n      json: map.json(),\n      \"*\": map.json(),\n    }),\n  }),\n);\n```\n\nFor anything else, build a `Route` directly — `on` matches the request, `decode`\nproduces the action's args, `action` does the work (typically one of the\nstandard rig-bound actions), `encode` shapes the wire response:\n\n```typescript\nimport {\n  dispatchHttp,\n  httpRequest,\n  route,\n} from \"@bandeira-tech/b3nd-move/http/router\";\nimport { readAction } from \"@bandeira-tech/b3nd-move/actions/standard\";\nimport { json } from \"@bandeira-tech/b3nd-move/http/wire\";\nimport { NotFound } from \"@bandeira-tech/b3nd-move/router/errors\";\n\nconst getThing = route({\n  on: httpRequest(\"GET\", \"/things/:id\"),\n  decode: ({ params }) =>\n    [[`mutable://things/${params.id}`]] as readonly [string[]],\n  action: readAction,\n  encode: ([output]) => {\n    if (!output || output[1] == null) throw new NotFound();\n    return json(output[1]);\n  },\n});\n\nDeno.serve({ port: 3000 }, (req) => dispatchHttp(rig, [getThing], req));\n```\n\n## Transports\n\nEach transport's wire format, route table, and `preSend` hook shape are\ndocumented in its own README. Every layer lives in one file with no barrel\nre-exports; runtime binding (`Deno.serve`, `node:http`, framework adapters) is\nthe host's job. A `deno task serve` helper at [`dev/serve.ts`](./dev/serve.ts)\nwires a stub rig to any combination of transports for ad-hoc testing.\n\n| Transport                                                                   | Expected encoding (outbound)       | Expected decoding (inbound)              | Surface                                                                                           |\n| --------------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------- |\n| [HTTP](./src/http/) — `http/{service,client}`                               | JSON                               | JSON + urlsafe-b64 URI lists + raw bytes | Full PIN (service + client)                                                                       |\n| [WebSocket](./src/ws/) — `ws/{service,client}`                              | JSON envelope per frame            | JSON envelope per frame                  | Full PIN (service + client)                                                                       |\n| [gRPC-over-HTTP](./src/grpc/http/) — `grpc/http/{service,client}`           | protobuf / JSON (per req)          | protobuf / JSON (per req)                | Full PIN (service + client)                                                                       |\n| [MCP](./src/mcp/) — `mcp/service` · `mcp/http/service` · `mcp/ws/service`   | JSON-RPC                           | JSON-RPC                                 | Service only; rig surfaced as MCP tools/resources (stdio: dev-only · Streamable HTTP · WebSocket) |\n| [HTTP GET content](./src/http-get-content/) — `http-get-content/service`    | host-shaped (`payloadResponseMap`) | URI in path                              | Custom — single-URI `rig.read` facet                                                              |\n| [HTTP POST content](./src/http-post-content/) — `http-post-content/service` | JSON (`ReceiveResult`)             | host-shaped (`payloadDecoder`)           | Custom — single-URI `rig.receive` facet                                                           |\n\nShared building blocks live under [`codecs/`](./src/codecs/) (symmetric\nencode/decode pairs), `router/{route,errors}` + `http/{router,wire}` +\n`actions/standard` (route construction), and `grpc/proto/{types,convert}`\n(generated protobuf + b3nd converters).\n\n## Development\n\n```bash\ndeno task check\ndeno task test\ndeno task build:npm   # universal slices → ./npm/\n```\n\nOne-time per clone, install the pre-push hook so the fast CI subset (type check,\nlint, fmt --check, unit, in-process integration) runs locally before every push:\n\n```bash\ndeno task hooks:install\n```\n\nBypass with `git push --no-verify` when you really need to.\n\n## Release rule\n\nReleasing any `@bandeira-tech` package requires, **same day**: bumping its pin\nin every direct workspace consumer and publishing their patch releases. The\n`dep-drift` CI job (running on every PR and weekly) fails when a pin lags\nJSR latest — a failing dep-drift check blocks the PR.\n\nRun `deno task check:deps` locally before opening a PR that touches pins.\n\n## Related\n\n- [b3nd-core](https://github.com/bandeira-tech/b3nd-core) — `Rig`,\n  `ProtocolInterfaceNode`, shared types\n- [b3nd-canon](https://github.com/bandeira-tech/b3nd-canon) — protocol-building\n  toolkit\n\n## License\n\nMIT\n","readmeFilename":"README.md"}