├── .changeset ├── afraid-starfishes-occur.md ├── big-maps-march.md ├── brown-berries-prove.md ├── chilly-donuts-search.md ├── clever-berries-begin.md ├── clever-rivers-teach.md ├── config.json ├── curvy-deers-burn.md ├── dirty-olives-enjoy.md ├── eight-wasps-give.md ├── eighty-eyes-reflect.md ├── five-llamas-jam.md ├── flat-cycles-remember.md ├── flat-jokes-check.md ├── four-buttons-move.md ├── fresh-books-fry.md ├── gold-starfishes-hear.md ├── good-points-bathe.md ├── grumpy-falcons-tie.md ├── happy-sloths-learn.md ├── hot-mice-remember.md ├── khaki-turkeys-rescue.md ├── kind-tables-lay.md ├── kind-teachers-taste.md ├── lazy-laws-remember.md ├── lazy-pigs-try.md ├── mean-buttons-drop.md ├── mighty-horses-try.md ├── neat-candles-guess.md ├── neat-houses-tickle.md ├── nervous-impalas-sin.md ├── odd-files-join.md ├── old-buses-cheer.md ├── olive-dryers-give.md ├── plenty-boxes-joke.md ├── plenty-wombats-invent.md ├── pre.json ├── purple-oranges-dream.md ├── rare-owls-poke.md ├── selfish-ducks-move.md ├── selfish-trainers-buy.md ├── serious-paws-crash.md ├── shiny-wombats-ring.md ├── shy-jobs-mate.md ├── silent-seals-sneeze.md ├── silver-hats-film.md ├── slimy-jars-divide.md ├── slimy-rabbits-care.md ├── smart-beans-pretend.md ├── smart-toes-prove.md ├── spotty-dryers-wave.md ├── sweet-hats-smash.md ├── tall-jeans-count.md ├── tame-news-cheat.md ├── tasty-lizards-wash.md ├── ten-carrots-give.md ├── tender-timers-pretend.md ├── thirty-buckets-develop.md ├── tiny-cameras-watch.md ├── tricky-days-bathe.md ├── two-badgers-retire.md ├── unlucky-jars-buy.md ├── violet-balloons-fetch.md ├── warm-walls-design.md ├── wet-boxes-search.md ├── wild-kids-applaud.md ├── wise-actors-taste.md ├── wise-ravens-sing.md ├── witty-buttons-cough.md ├── witty-carrots-float.md └── yellow-dingos-shop.md ├── .env.example ├── .eslintrc.cjs ├── .github ├── docs-screenshot.png └── workflows │ ├── build.yml │ └── publish.yml ├── .gitignore ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc.yaml ├── .vscode └── project.code-snippets ├── CLA.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE-ASSETS.md ├── LICENSE-DOCS.md ├── LICENSE.txt ├── README.md ├── SECURITY.md ├── Taskfile.yml ├── apps ├── documentation │ ├── .eslintrc.cjs │ ├── .gitignore │ ├── CHANGELOG.md │ ├── astro.config.mjs │ ├── package.json │ ├── postcss.config.cjs │ ├── public │ │ ├── open_in_stackblitz.svg │ │ ├── placeholder.png │ │ ├── prim-doseofted-attribution.png │ │ ├── prim-nav-doseofted-attribution.png │ │ ├── robots.txt │ │ └── social.png │ ├── src │ │ ├── client.ts │ │ ├── components │ │ │ ├── Code │ │ │ │ ├── Code.astro │ │ │ │ ├── CodeFile.astro │ │ │ │ └── CodeTabs.react.tsx │ │ │ ├── Columns.astro │ │ │ ├── Container.astro │ │ │ ├── Documentation │ │ │ │ ├── NavigationDocs.astro │ │ │ │ └── VersionSelection.astro │ │ │ ├── FeatureCard.astro │ │ │ ├── Footer.astro │ │ │ ├── IntroText.react.tsx │ │ │ ├── Lights.astro │ │ │ ├── Markdown │ │ │ │ ├── Aside.astro │ │ │ │ ├── Button.astro │ │ │ │ ├── ButtonGroup.astro │ │ │ │ ├── Collapse.astro │ │ │ │ ├── DataList.astro │ │ │ │ ├── DataListItem.astro │ │ │ │ ├── DataListOptions.astro │ │ │ │ ├── DataListPlugin.astro │ │ │ │ ├── Heading │ │ │ │ │ ├── H2.astro │ │ │ │ │ ├── H3.astro │ │ │ │ │ └── Heading.astro │ │ │ │ ├── LinkButton.astro │ │ │ │ ├── ListGrid.astro │ │ │ │ ├── PluginChoices.astro │ │ │ │ └── Table.astro │ │ │ ├── Marquee.astro │ │ │ ├── Navigation.astro │ │ │ ├── NavigationItem.astro │ │ │ ├── Prerelease.astro │ │ │ ├── Prim.astro │ │ │ ├── ReportIssue.astro │ │ │ ├── Snippets │ │ │ │ └── ServerNotice.astro │ │ │ ├── TableOfContents.astro │ │ │ └── ToggleEffects.astro │ │ ├── content │ │ │ ├── api │ │ │ │ └── .gitkeep │ │ │ ├── config.ts │ │ │ ├── docs │ │ │ │ ├── learn │ │ │ │ │ ├── advanced.mdx │ │ │ │ │ ├── comparisons.mdx │ │ │ │ │ ├── examples.mdx │ │ │ │ │ ├── introduction.mdx │ │ │ │ │ ├── limitations.mdx │ │ │ │ │ ├── security.mdx │ │ │ │ │ └── setup.mdx │ │ │ │ ├── reference │ │ │ │ │ ├── api.mdx │ │ │ │ │ ├── config.mdx │ │ │ │ │ ├── create.mdx │ │ │ │ │ ├── plugins.mdx │ │ │ │ │ └── structure.mdx │ │ │ │ └── tooling │ │ │ │ │ ├── build.mdx │ │ │ │ │ └── docs.mdx │ │ │ └── plugins │ │ │ │ ├── additional │ │ │ │ ├── json-handlers.mdx │ │ │ │ └── validators.mdx │ │ │ │ ├── client │ │ │ │ ├── axios.mdx │ │ │ │ ├── browser-fetch.mdx │ │ │ │ ├── browser-websocket.mdx │ │ │ │ ├── capacitor-http.mdx │ │ │ │ ├── child-process.mdx │ │ │ │ ├── electron.mdx │ │ │ │ ├── socket-io.mdx │ │ │ │ ├── testing.mdx │ │ │ │ └── web-worker.mdx │ │ │ │ └── server │ │ │ │ ├── astro.mdx │ │ │ │ ├── child-process.mdx │ │ │ │ ├── electron.mdx │ │ │ │ ├── express.mdx │ │ │ │ ├── fastify.mdx │ │ │ │ ├── h3.mdx │ │ │ │ ├── hono.mdx │ │ │ │ ├── nextjs.mdx │ │ │ │ ├── remix.mdx │ │ │ │ ├── server-fetch.mdx │ │ │ │ ├── socket-io.mdx │ │ │ │ ├── testing.mdx │ │ │ │ ├── web-worker.mdx │ │ │ │ └── ws.mdx │ │ ├── env.d.ts │ │ ├── layouts │ │ │ ├── Default.astro │ │ │ ├── Default.css │ │ │ └── Documentation.astro │ │ ├── pages │ │ │ ├── docs │ │ │ │ ├── [...slug].astro │ │ │ │ └── reference │ │ │ │ │ └── plugins │ │ │ │ │ └── [...plugin].astro │ │ │ ├── index.astro │ │ │ ├── prim │ │ │ │ └── [...prim].ts │ │ │ └── tests │ │ │ │ ├── light.astro │ │ │ │ ├── screenshot.astro │ │ │ │ └── server-screenshot.astro │ │ ├── server │ │ │ ├── greetings.ts │ │ │ └── index.ts │ │ ├── snippets │ │ │ ├── docs │ │ │ │ └── simple-example.js │ │ │ └── homepage │ │ │ │ ├── client │ │ │ │ ├── index.ts │ │ │ │ └── prim.ts │ │ │ │ └── server │ │ │ │ ├── index.ts │ │ │ │ └── module.ts │ │ └── utils │ │ │ ├── disable-effects.ts │ │ │ ├── easings.ts │ │ │ ├── lenis.ts │ │ │ ├── lights │ │ │ ├── ElementSet.ts │ │ │ ├── Light.ts │ │ │ ├── LightCanvas.ts │ │ │ ├── LightElements.ts │ │ │ ├── LightGroup.ts │ │ │ └── index.ts │ │ │ ├── store.ts │ │ │ └── tweak-binding.ts │ ├── tailwind.config.cjs │ └── tsconfig.json └── example │ ├── .eslintrc.cjs │ ├── CHANGELOG.md │ ├── package.json │ ├── src │ ├── index.test.ts │ └── index.ts │ └── tsconfig.json ├── libs ├── example │ ├── .eslintrc.cjs │ ├── CHANGELOG.md │ ├── LICENSE.txt │ ├── build.config.js │ ├── package.json │ ├── src │ │ ├── dynamic.ts │ │ ├── index.test.ts │ │ ├── index.ts │ │ ├── submodule.ts │ │ └── things.ts │ └── tsconfig.json ├── plugins │ ├── .eslintrc.cjs │ ├── CHANGELOG.md │ ├── LICENSE.txt │ ├── NOTICE.md │ ├── README.md │ ├── build.config.js │ ├── package.json │ ├── src │ │ ├── client │ │ │ ├── axios.ts │ │ │ ├── browser-fetch.test.ts │ │ │ ├── browser-fetch.ts │ │ │ ├── browser-websocket.ts │ │ │ ├── browser.ts │ │ │ ├── capacitor-http.ts │ │ │ └── socket-io.ts │ │ ├── ipc │ │ │ ├── child-process.ts │ │ │ ├── electron.ts │ │ │ ├── testing │ │ │ │ ├── client.sharedworker.ts │ │ │ │ ├── client.worker.ts │ │ │ │ ├── server.sharedworker.ts │ │ │ │ └── server.worker.ts │ │ │ ├── web-worker.test.ts │ │ │ └── web-worker.ts │ │ ├── pseudo │ │ │ ├── callback-handler.ts │ │ │ ├── callback-plugin.ts │ │ │ ├── method-handler.ts │ │ │ └── method-plugin.ts │ │ ├── server │ │ │ ├── astro.ts │ │ │ ├── express.test.ts │ │ │ ├── express.ts │ │ │ ├── fastify.test.ts │ │ │ ├── fastify.ts │ │ │ ├── h3.test.ts │ │ │ ├── h3.ts │ │ │ ├── hono.test.ts │ │ │ ├── hono.ts │ │ │ ├── nextjs.ts │ │ │ ├── remix.ts │ │ │ ├── server-fetch.test.ts │ │ │ ├── server-fetch.ts │ │ │ ├── socket-io.ts │ │ │ ├── ws.test.ts │ │ │ └── ws.ts │ │ └── utils │ │ │ └── isomorphic.ts │ ├── tsconfig.json │ └── typedoc.json ├── rpc │ ├── .eslintrc.cjs │ ├── CHANGELOG.md │ ├── LICENSE.txt │ ├── NOTICE.md │ ├── README.md │ ├── README.png │ ├── build.config.js │ ├── package.json │ ├── src │ │ ├── allow.ts │ │ ├── client.test.ts │ │ ├── client.ts │ │ ├── constants.ts │ │ ├── error.ts │ │ ├── extract │ │ │ ├── base.ts │ │ │ ├── blobs.ts │ │ │ └── promises.ts │ │ ├── flags.ts │ │ ├── index.ts │ │ ├── interfaces.ts │ │ ├── options.ts │ │ ├── server.test.ts │ │ ├── server.ts │ │ ├── testing.ts │ │ └── validate.ts │ ├── tsconfig.json │ └── typedoc.json └── tooling │ ├── .eslintrc.cjs │ ├── CHANGELOG.md │ ├── LICENSE.txt │ ├── NOTICE.md │ ├── README.md │ ├── build.config.js │ ├── package.json │ ├── src │ ├── build │ │ └── index.ts │ ├── cli │ │ └── index.ts │ └── docs │ │ ├── generator.ts │ │ ├── helpers │ │ ├── create.ts │ │ └── read.ts │ │ ├── index.test.ts │ │ ├── index.ts │ │ └── interfaces.ts │ ├── tsconfig.json │ └── typedoc.json ├── package.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── prim-rpc.code-workspace ├── tsconfig.json └── turbo.json /.changeset/afraid-starfishes-occur.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-documentation-website": minor 3 | "@doseofted/prim-example-server": minor 4 | "@doseofted/prim-example": minor 5 | "@doseofted/prim-rpc-plugins": minor 6 | "@doseofted/prim-rpc-tooling": minor 7 | "@doseofted/prim-rpc": minor 8 | "@doseofted/prim-rpc-ui": minor 9 | --- 10 | 11 | Initial prerelease of Prim+RPC core, plugins, tooling 12 | -------------------------------------------------------------------------------- /.changeset/big-maps-march.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": minor 3 | --- 4 | 5 | The default JSON parser is now unjs/destr 6 | -------------------------------------------------------------------------------- /.changeset/brown-berries-prove.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Added .preRequest and .postRequest hooks, available in client options 6 | -------------------------------------------------------------------------------- /.changeset/chilly-donuts-search.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | File/Blob size is now checked prior to sending RPC (discarded if size is 0) 6 | -------------------------------------------------------------------------------- /.changeset/clever-berries-begin.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": minor 3 | --- 4 | 5 | Client's module type parameter created with createPrimTestingSuite() is no longer wrapped in Partial type 6 | -------------------------------------------------------------------------------- /.changeset/clever-rivers-teach.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Next.js handler renamed defineNextjsAppHandler -> defineNextjsAppPrimHandler 6 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /.changeset/curvy-deers-burn.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Updated dependencies to latest 6 | -------------------------------------------------------------------------------- /.changeset/dirty-olives-enjoy.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Function on client can now be passed as form's onsubmit handler directly 6 | -------------------------------------------------------------------------------- /.changeset/eight-wasps-give.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-documentation-website": patch 3 | "@doseofted/prim-example": patch 4 | "@doseofted/prim-rpc-plugins": patch 5 | "@doseofted/prim-rpc-tooling": patch 6 | "@doseofted/prim-rpc": patch 7 | --- 8 | 9 | Upgraded project lockfile 10 | -------------------------------------------------------------------------------- /.changeset/eighty-eyes-reflect.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Added ability to receive multiple promises from a function with callback handler (disabled by default, must be enabled in options under `flags`) 6 | -------------------------------------------------------------------------------- /.changeset/five-llamas-jam.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Next.js handler now supports files in RPC result 6 | -------------------------------------------------------------------------------- /.changeset/flat-cycles-remember.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | RPC result can now contain binary data with default JSON handler 6 | -------------------------------------------------------------------------------- /.changeset/flat-jokes-check.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Reverted file size check behavior (types on server should reflect client more closely) 6 | -------------------------------------------------------------------------------- /.changeset/four-buttons-move.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | contextTransform option of client-side Fetch method handler now passes argument of ResponseInit type instead of empty 6 | Response object 7 | -------------------------------------------------------------------------------- /.changeset/fresh-books-fry.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | "@doseofted/prim-rpc-tooling": patch 4 | "@doseofted/prim-rpc": patch 5 | --- 6 | 7 | Upgraded project dependencies 8 | -------------------------------------------------------------------------------- /.changeset/gold-starfishes-hear.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Fix for "excessively deep" type error on Prim RPC client (methods-on-methods type now only shown if method is defined 6 | directly on function) 7 | -------------------------------------------------------------------------------- /.changeset/good-points-bathe.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Improved type support on client for passing form events to a function (transformed by server) 6 | -------------------------------------------------------------------------------- /.changeset/grumpy-falcons-tie.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": minor 3 | --- 4 | 5 | Added method handler for Hono framework 6 | -------------------------------------------------------------------------------- /.changeset/happy-sloths-learn.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Fix for broken type definitions (introduced in last version) on async functions used with client 6 | -------------------------------------------------------------------------------- /.changeset/hot-mice-remember.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Added Remix plugin 6 | -------------------------------------------------------------------------------- /.changeset/khaki-turkeys-rescue.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Bump to package dependencies 6 | -------------------------------------------------------------------------------- /.changeset/kind-tables-lay.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Hono handler now supports files contained in RPC result 6 | -------------------------------------------------------------------------------- /.changeset/kind-teachers-taste.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": minor 3 | --- 4 | 5 | Module option of client and server now accepts dynamic imports and explicitly setting module value to null 6 | -------------------------------------------------------------------------------- /.changeset/lazy-laws-remember.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": minor 3 | --- 4 | 5 | Next.js now uses File object, no longer uses tmp directory 6 | -------------------------------------------------------------------------------- /.changeset/lazy-pigs-try.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Fix for custom paths used with Hono method handler 6 | -------------------------------------------------------------------------------- /.changeset/mean-buttons-drop.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Express handler now supports files in RPC result, now using formidable as multipart plugin 6 | -------------------------------------------------------------------------------- /.changeset/mighty-horses-try.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | "@doseofted/prim-rpc-tooling": patch 4 | "@doseofted/prim-rpc": patch 5 | "@doseofted/prim-rpc-ui": patch 6 | --- 7 | 8 | Added provenance option to package.json 9 | -------------------------------------------------------------------------------- /.changeset/neat-candles-guess.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Fetch API no longer errors on preflight requests, headers like CORS should be added as part of plugin setup 6 | -------------------------------------------------------------------------------- /.changeset/neat-houses-tickle.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | All type definitions for functions are transformed client-side because `this` argument is not needed on client 6 | -------------------------------------------------------------------------------- /.changeset/nervous-impalas-sin.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": minor 3 | --- 4 | 5 | H3 integration now uses File object, no longer saves file to tmp directory 6 | -------------------------------------------------------------------------------- /.changeset/odd-files-join.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Binary JSON handler is now supported (.parse and .stringify can utilize binary data) 6 | -------------------------------------------------------------------------------- /.changeset/old-buses-cheer.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Web Worker plugin now supports Shared Workers 6 | -------------------------------------------------------------------------------- /.changeset/olive-dryers-give.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Fix for dynamic imports used with Prim RPC server 6 | -------------------------------------------------------------------------------- /.changeset/plenty-boxes-joke.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Added Next.js server handler (for App Router) 6 | -------------------------------------------------------------------------------- /.changeset/plenty-wombats-invent.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-documentation-website": patch 3 | "@doseofted/prim-example-server": patch 4 | "@doseofted/prim-example": patch 5 | "@doseofted/prim-rpc-plugins": patch 6 | "@doseofted/prim-rpc-tooling": patch 7 | "@doseofted/prim-rpc": patch 8 | "@doseofted/prim-rpc-ui": patch 9 | --- 10 | 11 | Upgraded dependencies used in project 12 | -------------------------------------------------------------------------------- /.changeset/pre.json: -------------------------------------------------------------------------------- 1 | { 2 | "mode": "pre", 3 | "tag": "alpha", 4 | "initialVersions": { 5 | "@doseofted/prim-example-server": "0.0.0", 6 | "@doseofted/prim-documentation-website": "0.0.0", 7 | "@doseofted/prim-example": "0.0.0", 8 | "@doseofted/prim-rpc-plugins": "0.0.0", 9 | "@doseofted/prim-rpc": "0.0.0", 10 | "@doseofted/prim-rpc-tooling": "0.0.0", 11 | "@doseofted/prim-rpc-ui": "0.0.0" 12 | }, 13 | "changesets": [ 14 | "afraid-starfishes-occur", 15 | "big-maps-march", 16 | "brown-berries-prove", 17 | "chilly-donuts-search", 18 | "clever-berries-begin", 19 | "clever-rivers-teach", 20 | "curvy-deers-burn", 21 | "dirty-olives-enjoy", 22 | "eight-wasps-give", 23 | "eighty-eyes-reflect", 24 | "five-llamas-jam", 25 | "flat-cycles-remember", 26 | "flat-jokes-check", 27 | "four-buttons-move", 28 | "fresh-books-fry", 29 | "gold-starfishes-hear", 30 | "good-points-bathe", 31 | "grumpy-falcons-tie", 32 | "happy-sloths-learn", 33 | "hot-mice-remember", 34 | "khaki-turkeys-rescue", 35 | "kind-tables-lay", 36 | "kind-teachers-taste", 37 | "lazy-laws-remember", 38 | "lazy-pigs-try", 39 | "mean-buttons-drop", 40 | "mighty-horses-try", 41 | "neat-candles-guess", 42 | "neat-houses-tickle", 43 | "nervous-impalas-sin", 44 | "odd-files-join", 45 | "old-buses-cheer", 46 | "olive-dryers-give", 47 | "plenty-boxes-joke", 48 | "plenty-wombats-invent", 49 | "purple-oranges-dream", 50 | "rare-owls-poke", 51 | "selfish-ducks-move", 52 | "selfish-trainers-buy", 53 | "serious-paws-crash", 54 | "shiny-wombats-ring", 55 | "shy-jobs-mate", 56 | "silent-seals-sneeze", 57 | "silver-hats-film", 58 | "slimy-jars-divide", 59 | "slimy-rabbits-care", 60 | "smart-beans-pretend", 61 | "smart-toes-prove", 62 | "spotty-dryers-wave", 63 | "sweet-hats-smash", 64 | "tall-jeans-count", 65 | "tame-news-cheat", 66 | "tasty-lizards-wash", 67 | "ten-carrots-give", 68 | "tender-timers-pretend", 69 | "thirty-buckets-develop", 70 | "tiny-cameras-watch", 71 | "tricky-days-bathe", 72 | "two-badgers-retire", 73 | "unlucky-jars-buy", 74 | "violet-balloons-fetch", 75 | "warm-walls-design", 76 | "wet-boxes-search", 77 | "wild-kids-applaud", 78 | "wise-actors-taste", 79 | "wise-ravens-sing", 80 | "witty-buttons-cough", 81 | "witty-carrots-float", 82 | "yellow-dingos-shop" 83 | ] 84 | } 85 | -------------------------------------------------------------------------------- /.changeset/purple-oranges-dream.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": minor 3 | --- 4 | 5 | Pre-call and pre-request hooks can now return/resolve function calls early (and the return value from this hook must be an object consisting of .args and optionally .result) 6 | -------------------------------------------------------------------------------- /.changeset/rare-owls-poke.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | More in-depth checks added for calling module provided to Prim+RPC server 6 | -------------------------------------------------------------------------------- /.changeset/selfish-ducks-move.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | "@doseofted/prim-rpc-tooling": patch 4 | "@doseofted/prim-rpc": patch 5 | --- 6 | 7 | Upgraded dependencies 8 | -------------------------------------------------------------------------------- /.changeset/selfish-trainers-buy.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-tooling": minor 3 | "@doseofted/prim-rpc": minor 4 | --- 5 | 6 | Replaced usage of Lodash with "just" utilities 7 | -------------------------------------------------------------------------------- /.changeset/serious-paws-crash.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Fetch API plugin for servers now has "preprocess" option to modify Request and "postprocess" option to modify Response 6 | -------------------------------------------------------------------------------- /.changeset/shiny-wombats-ring.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Bug fix: Batch time of 0 now makes RPC immediately instead of using timer with 0 seconds (fixes possibly sending batched 6 | request when not configured to do so) 7 | -------------------------------------------------------------------------------- /.changeset/shy-jobs-mate.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Astro handler now supports files in RPC result 6 | -------------------------------------------------------------------------------- /.changeset/silent-seals-sneeze.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Fastify handler now supports sending back files as part of RPC result 6 | -------------------------------------------------------------------------------- /.changeset/silver-hats-film.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Context is now undefined by default but can be given in individual handler options 6 | -------------------------------------------------------------------------------- /.changeset/slimy-jars-divide.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Adjusted type definitions to resolve internal type issue caught with upgraded TypeScript 5.1.6 6 | -------------------------------------------------------------------------------- /.changeset/slimy-rabbits-care.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Added plugin to support Astro in SSR mode 6 | -------------------------------------------------------------------------------- /.changeset/smart-beans-pretend.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Only function types are given on module used with Prim RPC client, also available as new "RpcModule" type for usage 6 | outside of client or with JSDocs 7 | -------------------------------------------------------------------------------- /.changeset/smart-toes-prove.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Relaxed Hono file checking to prevent binary prefix string being returned for empty file 6 | -------------------------------------------------------------------------------- /.changeset/spotty-dryers-wave.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-tooling": minor 3 | --- 4 | 5 | New option added to preventImport tool that throws an error if imported on client at run-time (useful for testing with 6 | fullstack frameworks) 7 | -------------------------------------------------------------------------------- /.changeset/sweet-hats-smash.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Client module generic parameter must now match module option if provided 6 | -------------------------------------------------------------------------------- /.changeset/tall-jeans-count.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | H3 handler now supports files in RPC result 6 | -------------------------------------------------------------------------------- /.changeset/tame-news-cheat.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Allow list option is now typed according to module given on server 6 | -------------------------------------------------------------------------------- /.changeset/tasty-lizards-wash.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Improved type support for allow list option of Prim+RPC 6 | -------------------------------------------------------------------------------- /.changeset/ten-carrots-give.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Browser fetch plugin can now handle binary RPC result 6 | -------------------------------------------------------------------------------- /.changeset/tender-timers-pretend.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": minor 3 | --- 4 | 5 | .methodsOnMethods option now requires an key/value object where the key is the method-on-method name and the value is either `true` or `"idempotent"` (similar to .allowList option) 6 | -------------------------------------------------------------------------------- /.changeset/thirty-buckets-develop.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Bug fix: 400 HTTP status code no longer utilized when RPC result is a falsy value 6 | -------------------------------------------------------------------------------- /.changeset/tiny-cameras-watch.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | .headers is no longer a required parameter on the Next.js plugin 6 | -------------------------------------------------------------------------------- /.changeset/tricky-days-bathe.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Fixed methods-on-methods that were in allowed list not being callable 6 | -------------------------------------------------------------------------------- /.changeset/two-badgers-retire.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": minor 3 | --- 4 | 5 | Web Worker plugin now has new jsonHandler export (existing plugins now only return plugin without extra JSON handler) 6 | -------------------------------------------------------------------------------- /.changeset/unlucky-jars-buy.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Plugins now use dynamic import for Node-specific logic to support other runtimes 6 | -------------------------------------------------------------------------------- /.changeset/violet-balloons-fetch.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": minor 3 | --- 4 | 5 | Fastify plugin now saves to File object, no longer saves to tmp directory 6 | -------------------------------------------------------------------------------- /.changeset/warm-walls-design.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": minor 3 | --- 4 | 5 | Errors are now better handled during processing of HTTP-like requests/responses and processing of RPC calls/results 6 | -------------------------------------------------------------------------------- /.changeset/wet-boxes-search.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": minor 3 | --- 4 | 5 | RPC can no longer be made by GET requests by default: introduced new keyword for function's `.rpc` property named "idempotent" that, when used with HTTP plugins, allows RPC over GET requests 6 | -------------------------------------------------------------------------------- /.changeset/wild-kids-applaud.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": minor 3 | --- 4 | 5 | Express integration now uses File object, no longer uses tmp directory 6 | -------------------------------------------------------------------------------- /.changeset/wise-actors-taste.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc": patch 3 | --- 4 | 5 | Added .preCall and .postCall hooks on server to transform args and results respectively 6 | -------------------------------------------------------------------------------- /.changeset/wise-ravens-sing.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Fetch plugin now has empty Response added to contextTransform option's arguments 6 | -------------------------------------------------------------------------------- /.changeset/witty-buttons-cough.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-documentation-website": patch 3 | --- 4 | 5 | Documentation menu now highlights active item, added icons to buttons 6 | -------------------------------------------------------------------------------- /.changeset/witty-carrots-float.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-documentation-website": patch 3 | "@doseofted/prim-example-server": patch 4 | "@doseofted/prim-example": patch 5 | "@doseofted/prim-rpc-plugins": patch 6 | "@doseofted/prim-rpc-tooling": patch 7 | "@doseofted/prim-rpc": patch 8 | "@doseofted/prim-rpc-ui": patch 9 | --- 10 | 11 | Upgraded project dependencies 12 | -------------------------------------------------------------------------------- /.changeset/yellow-dingos-shop.md: -------------------------------------------------------------------------------- 1 | --- 2 | "@doseofted/prim-rpc-plugins": patch 3 | --- 4 | 5 | Added generic fetch/requests handler for modern runtimes like Bun/Deno 6 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # SECTION: Basics 2 | # ------------------------------------------------------------------------------ 3 | # Used for reverse proxy and containers that need to know the hostname 4 | WEBSITE_HOST="prim.localhost" 5 | # Email to be used for renewing certificates through Caddy's ACME client 6 | ADMIN_EMAIL= 7 | # !SECTION --------------------------------------------------------------------- 8 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | /** @type {import("eslint").ESLint.ConfigData} */ 3 | module.exports = { 4 | root: true, 5 | extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended-type-checked", "prettier"], 6 | plugins: ["@typescript-eslint"], 7 | parser: "@typescript-eslint/parser", 8 | parserOptions: { 9 | project: true, 10 | tsconfigRootDir: __dirname, 11 | // Needed for tsconfig project references 12 | EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true, 13 | }, 14 | overrides: [ 15 | { 16 | files: ["*.js", "*.cjs"], 17 | extends: ["plugin:@typescript-eslint/disable-type-checked"], 18 | }, 19 | ], 20 | env: { 21 | browser: true, 22 | node: true, 23 | es2023: true, 24 | }, 25 | ignorePatterns: [".eslintrc.*", "dist/", "/data/"], 26 | globals: {}, 27 | rules: { 28 | "@typescript-eslint/no-unused-vars": [ 29 | "warn", 30 | { 31 | argsIgnorePattern: "^_", 32 | varsIgnorePattern: "^_", 33 | }, 34 | ], 35 | "@typescript-eslint/no-misused-promises": ["warn", { checksVoidReturn: false }], 36 | }, 37 | } 38 | -------------------------------------------------------------------------------- /.github/docs-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doseofted/prim-rpc/8b9c9c1e91fe8443cf1216847575e40d3e5136c1/.github/docs-screenshot.png -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Prim+RPC 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - synchronize 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | env: 13 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} 14 | TURBO_TEAM: ${{ secrets.TURBO_TEAM }} 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: pnpm/action-setup@v2 18 | - uses: actions/setup-node@v3 19 | with: 20 | node-version: 18 21 | cache: "pnpm" 22 | - name: Install 23 | run: pnpm install --frozen-lockfile 24 | # - name: Lint 25 | # run: pnpm turbo lint 26 | - name: Build 27 | run: pnpm turbo build 28 | - name: Test 29 | run: pnpm turbo test 30 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Prim+RPC 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | 8 | jobs: 9 | publish: 10 | runs-on: ubuntu-latest 11 | # NOTE: don't add any Turbo cache here, publishing workflow needs to be clean 12 | permissions: 13 | contents: write 14 | pull-requests: write 15 | id-token: write 16 | steps: 17 | - uses: actions/checkout@v3 18 | - uses: pnpm/action-setup@v2 19 | - uses: actions/setup-node@v3 20 | with: 21 | node-version: 18 22 | # NOTE: don't use cache for publishing (install needs to be clean) 23 | - name: Install 24 | run: pnpm install --frozen-lockfile 25 | # - name: Lint 26 | # run: pnpm turbo lint 27 | - name: Build 28 | run: pnpm turbo build 29 | - name: Test 30 | run: pnpm turbo test 31 | - name: Release 32 | uses: changesets/action@v1 33 | with: 34 | publish: pnpm changeset publish 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 37 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 38 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}" 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Don't commit mounted volumes from Docker Compose 2 | /data/* 3 | # Keep an empty folder when needed 4 | !**/.gitkeep 5 | # Don't commit envionment but keep an example for reference 6 | .env 7 | .env.* 8 | !.env.example 9 | # Logs don't need to be committed 10 | *.log 11 | # Don't need to commit Mac-specific settings 12 | .DS_Store 13 | # Don't need Windows-specific cache either 14 | Thumbs.db 15 | [Dd]esktop.ini 16 | # Node modules are reinstalled on each client (and huge, don't commit) 17 | node_modules 18 | # TurboRepo cache doesn't need to be committed 19 | .turbo 20 | # Don't commit Checksums used by Taskfile when fingerprinting files 21 | .task/* 22 | # Don't need to commit JavaScript-specific, built, distributable files 23 | dist 24 | # The .pnpm-store folder is usually in a system-specific location but just in case: 25 | .pnpm-store 26 | # The API docs are generated with TypeDoc on each build are don't need to be commited to repo 27 | **/docs/api.json -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # Don't cache side-effects (like post-install hooks) since they will not run in GitHub Actions with cache enabled 2 | side-effects-cache=false 3 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v21 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/dist/ 2 | **/.task/ 3 | **/.turbo/ 4 | **/.next/ 5 | /data/ 6 | pnpm-*.yaml 7 | **/.changeset/ 8 | -------------------------------------------------------------------------------- /.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | useTabs: true 2 | printWidth: 120 3 | semi: false 4 | singleQuote: false 5 | jsxSingleQuote: false 6 | quoteProps: as-needed 7 | trailingComma: es5 8 | bracketSpacing: true 9 | bracketSameLine: true 10 | arrowParens: avoid 11 | proseWrap: always 12 | 13 | plugins: 14 | - "prettier-plugin-astro" 15 | overrides: 16 | - files: "*.astro" 17 | options: 18 | parser: "astro" 19 | -------------------------------------------------------------------------------- /.vscode/project.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | // https://code.visualstudio.com/docs/editor/userdefinedsnippets#_create-your-own-snippets 3 | "Add notice without license": { 4 | "prefix": "noticeNoLicense", 5 | "body": [ 6 | "$LINE_COMMENT Part of the Prim+RPC project ( https://prim.doseofted.me/ )", 7 | "$LINE_COMMENT Copyright ${1:$CURRENT_YEAR} $2", 8 | "" 9 | ] 10 | }, 11 | "Add notice with open source license": { 12 | "prefix": "noticeLicense", 13 | "body": [ 14 | "$LINE_COMMENT Part of the Prim+RPC project ( https://prim.doseofted.me/ )", 15 | "$LINE_COMMENT Copyright ${1:$CURRENT_YEAR} $2", 16 | "$LINE_COMMENT SPDX-License-Identifier: ${3|Apache-2.0|}", 17 | "" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributions 2 | 3 | Prim+RPC is intended to become **a standard way to communicate between JavaScript environments**. This means Prim+RPC 4 | should be: 5 | 6 | - Easy to use for developers of all skill levels 7 | - Simple to integrate into your favorite server/client frameworks 8 | - Flexible enough that other frameworks can build on top of it 9 | - Stable, reliable, and very well documented 10 | 11 | It can be difficult to achieve all of these goals and your contributions can help make this possible. 12 | 13 | > [!WARNING] 14 | > 15 | > It is possible that a feature is already being or has been developed or that a feature may have already been rejected. 16 | > If you'd like to contribute to the project, [open an issue first](https://github.com/doseofted/prim-rpc/issues/new) 17 | > and describe what change that you would like to make. 18 | 19 | ## Setup 20 | 21 | See the [Documentation](https://prim.doseofted.me/) for usage instructions. These instructions refer to development of 22 | the project itself. 23 | 24 | - Install [Node](https://nodejs.org/) version given in [`.nvmrc`](./.nvmrc). 25 | - Install dependencies with `pnpm install` (run `corepack enable` to auto-install [pnpm](https://pnpm.io/)) 26 | - List all project commands with `pnpm task`. If Task is installed globally, you can just run `task`. 27 | 28 | # Guidelines 29 | 30 | - Follow the [Code of Conduct](./CODE_OF_CONDUCT.md). This project adopts the 31 | [Contributor Covenant](https://www.contributor-covenant.org/). 32 | - Contributions made to a Prim+RPC project require a [Contributor License Agreement](./CLA.md). 33 | - All projects in this repository follow [semantic versioning](https://semver.org/). 34 | - Every completed pull request should have an 35 | [associated changeset](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md). 36 | - All commits should be professional and include detailed messages (as a best effort). 37 | -------------------------------------------------------------------------------- /LICENSE-ASSETS.md: -------------------------------------------------------------------------------- 1 | # Assets Notice 2 | 3 | Copyright © 2023 [Ted Klingenberg](https://doseofted.me/) 4 | 5 | The "Prim+RPC" name and logo as well as the "Dose of Ted" name and logo (Assets) are proprietary. Assets are excluded 6 | from all licenses, regardless of where they are located in the project. Unauthorized usage of Assets outside of fair use 7 | is strictly prohibited. 8 | -------------------------------------------------------------------------------- /LICENSE-DOCS.md: -------------------------------------------------------------------------------- 1 | # Documentation Notice 2 | 3 | Copyright © 2023 [Ted Klingenberg](https://doseofted.me/) 4 | 5 | The documentation website and text (Documentation) are proprietary. Unauthorized usage of Documentation outside of fair 6 | use is strictly prohibited. 7 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | If a security issue is found then please either 4 | [report a vulnerability](https://github.com/doseofted/prim-rpc/security/advisories/new) on Github or 5 | [privately report the issue](mailto:ted@doseofted.com) to Ted. Prim+RPC is in early stages and, as it progresses, a more 6 | robust policy will be created. 7 | -------------------------------------------------------------------------------- /Taskfile.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | dotenv: 4 | - ".env" 5 | 6 | tasks: 7 | default: 8 | cmds: 9 | - "task --list" 10 | 11 | setup:node: 12 | desc: "Set the version of Node using pnpm, as specified in project's .nvmrc" 13 | vars: 14 | given_node_version: 15 | sh: "cat .nvmrc" 16 | cmds: 17 | - "pnpm env use --global {{.given_node_version}}" 18 | 19 | setup: 20 | desc: "Set up the project for development" 21 | cmds: 22 | - "pnpm install" 23 | - task: build 24 | 25 | upgrade: 26 | desc: "Interactively upgrade all dependencies in monorepo" 27 | cmds: 28 | - "pnpm upgrade -r --interactive --latest" 29 | 30 | cleanup: 31 | desc: "Remove various temporary files and directories created within project, for a clean run" 32 | ignore_error: true 33 | cmds: 34 | - "find . -name node_modules -type d -prune -exec rm -fr {} +" 35 | - 'find . -name dist -not -path "*/shiki/dist" -type d -prune -exec rm -fr {} +' 36 | - "find . -name .turbo -type d -prune -exec rm -fr {} +" 37 | - "rm -r ./apps/documentation/.astro/" 38 | - "rm -r ./apps/documentation/.vercel/" 39 | - "rm -fr .task" 40 | 41 | build: 42 | desc: "Build all parts of the project" 43 | cmds: 44 | - "pnpm turbo build" 45 | 46 | test: 47 | desc: "Run all project tests" 48 | cmds: 49 | - "pnpm turbo test" 50 | 51 | changeset: 52 | desc: "Add a changeset to a commit" 53 | cmds: 54 | - "pnpm changeset {{.CLI_ARGS}}" 55 | 56 | lint:check: 57 | desc: "Check for linting errors in project (ran prior to lint:fix task)" 58 | cmds: 59 | - cmd: "pnpm prettier . --check" 60 | ignore_error: true 61 | - cmd: "pnpm turbo run lint" 62 | ignore_error: true 63 | 64 | lint:fix: 65 | desc: "Lint project with ESLint and format with Prettier" 66 | cmds: 67 | - "pnpm prettier . --write" 68 | - "pnpm turbo run lint -- --fix" 69 | 70 | start:docs: 71 | desc: "Start the documentation server in development mode" 72 | cmds: 73 | - "pnpm --filter=./apps/documentation dev" 74 | 75 | start:example: 76 | desc: "Start the reference project to play with Prim+RPC on a server" 77 | cmds: 78 | - "pnpm --filter=./apps/example dev" 79 | -------------------------------------------------------------------------------- /apps/documentation/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | /** @type {import("eslint").ESLint.ConfigData} */ 3 | const config = { 4 | root: false, 5 | overrides: [], 6 | } 7 | 8 | module.exports = config 9 | -------------------------------------------------------------------------------- /apps/documentation/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | # generated types 4 | .astro/ 5 | 6 | # dependencies 7 | node_modules/ 8 | 9 | # logs 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | 16 | # environment variables 17 | .env 18 | .env.production 19 | 20 | # macOS-specific files 21 | .DS_Store 22 | 23 | # Vercel adaptor build output from Astro 24 | .vercel 25 | 26 | # This content folder is generated on project build and doesn't need to be committed 27 | src/content/api/v** 28 | -------------------------------------------------------------------------------- /apps/documentation/astro.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import { defineConfig } from "astro/config" 3 | import tailwind from "@astrojs/tailwind" 4 | import react from "@astrojs/react" 5 | import mdx from "@astrojs/mdx" 6 | import sitemap from "@astrojs/sitemap" 7 | import vercel from "@astrojs/vercel/serverless" 8 | import rehypePrettyCode from "rehype-pretty-code" 9 | import icon from "astro-icon" 10 | import rehypeExternalLinks from "rehype-external-links" 11 | 12 | /** @type {import('rehype-pretty-code').Options} */ 13 | const rehypePrettyOptions = { 14 | theme: "material-theme-palenight", 15 | defaultLang: { 16 | block: "typescript", 17 | inline: "typescript", 18 | }, 19 | keepBackground: false, 20 | } 21 | 22 | // https://astro.build/config 23 | export default defineConfig({ 24 | site: "https://prim.doseofted.me", 25 | markdown: { 26 | shikiConfig: { 27 | theme: "material-theme-palenight", 28 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 29 | // @ts-ignore 30 | langs: ["typescript", "javascript", "jsx", "tsx", "json", "json5", "shellscript", "console", "astro", "vue"], 31 | wrap: false, 32 | }, 33 | syntaxHighlight: false, // "shiki", 34 | remarkPlugins: [], 35 | rehypePlugins: [ 36 | [rehypePrettyCode, rehypePrettyOptions], 37 | [rehypeExternalLinks, { target: "_blank" }], 38 | ], 39 | }, 40 | integrations: [ 41 | tailwind(), 42 | react({ 43 | include: "src/**/*.react.tsx", 44 | }), 45 | mdx(), 46 | sitemap({ filter: page => !page.startsWith("/tests/") }), 47 | icon({ 48 | include: { 49 | ph: ["*"], 50 | "simple-icons": ["*"], 51 | }, 52 | }), 53 | ], 54 | output: "hybrid", 55 | adapter: vercel({ 56 | functionPerRoute: false, 57 | }), 58 | redirects: { 59 | // List of short URLs 60 | "/docs": { destination: "/docs/learn/introduction", status: 302 }, 61 | // Redirects from old documentation website 62 | "/docs/setup": { destination: "/docs/learn/setup", status: 301 }, 63 | "/docs/examples": { destination: "/docs/learn/examples", status: 301 }, 64 | "/docs/security": { destination: "/docs/learn/security", status: 301 }, 65 | "/docs/comparisons": { destination: "/docs/learn/comparisons", status: 301 }, 66 | "/docs/limitations": { destination: "/docs/learn/limitations", status: 301 }, 67 | "/docs/reference/configuration": { destination: "/docs/reference/config", status: 301 }, 68 | "/docs/plugins/create": { destination: "/docs/reference/create", status: 301 }, 69 | "/docs/plugins/server": { destination: "/docs/reference/plugins", status: 301 }, 70 | "/docs/plugins/client": { destination: "/docs/reference/plugins", status: 301 }, 71 | "/docs/plugins/ipc": { destination: "/docs/reference/plugins", status: 301 }, 72 | }, 73 | }) 74 | -------------------------------------------------------------------------------- /apps/documentation/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@doseofted/prim-documentation-website", 3 | "version": "0.1.0-alpha.26", 4 | "description": "Prim+RPC website that houses the Prim+RPC documentation project.", 5 | "license": "UNLICENSED", 6 | "private": true, 7 | "author": { 8 | "name": "Ted Klingenberg", 9 | "email": "ted@doseofted.com", 10 | "url": "https://doseofted.me/" 11 | }, 12 | "contributors": [], 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/doseofted/prim-rpc.git", 16 | "directory": "apps/documentation" 17 | }, 18 | "homepage": "https://prim.doseofted.me/", 19 | "keywords": [ 20 | "api", 21 | "json", 22 | "ipc", 23 | "rpc" 24 | ], 25 | "bugs": { 26 | "url": "https://github.com/doseofted/prim-rpc/issues" 27 | }, 28 | "scripts": { 29 | "dev": "astro dev", 30 | "start": "astro dev", 31 | "build": "astro build", 32 | "preview": "astro preview", 33 | "astro": "astro", 34 | "check": "tsc --noEmit", 35 | "lint": "eslint ." 36 | }, 37 | "type": "module", 38 | "devDependencies": { 39 | "@ark-ui/react": "2.2.2", 40 | "@astrojs/mdx": "^2.1.0", 41 | "@astrojs/react": "^3.0.9", 42 | "@astrojs/sitemap": "^3.0.5", 43 | "@astrojs/tailwind": "^5.1.0", 44 | "@astrojs/vercel": "^7.3.4", 45 | "@doseofted/prim-example": "workspace:*", 46 | "@doseofted/prim-rpc": "workspace:*", 47 | "@doseofted/prim-rpc-plugins": "workspace:*", 48 | "@doseofted/prim-rpc-tooling": "workspace:*", 49 | "@fontsource-variable/fira-code": "^5.0.16", 50 | "@fontsource-variable/montserrat": "^5.0.17", 51 | "@fontsource-variable/plus-jakarta-sans": "^5.0.19", 52 | "@formkit/auto-animate": "^0.8.1", 53 | "@iconify-json/ph": "^1.1.10", 54 | "@iconify-json/simple-icons": "^1.1.93", 55 | "@iconify/react": "^4.1.1", 56 | "@nanostores/react": "^0.7.1", 57 | "@studio-freight/lenis": "^1.0.39", 58 | "@tailwindcss/forms": "^0.5.7", 59 | "@tailwindcss/typography": "^0.5.10", 60 | "@tweakpane/core": "^2.0.3", 61 | "@tweakpane/plugin-essentials": "^0.2.1", 62 | "@types/common-tags": "^1.8.4", 63 | "@types/react": "^18.2.61", 64 | "@types/react-dom": "^18.2.18", 65 | "astro": "^4.4.9", 66 | "astro-icon": "1.1.0", 67 | "astro-seo": "^0.8.0", 68 | "color2k": "^2.0.3", 69 | "common-tags": "^1.8.2", 70 | "consola": "^3.2.3", 71 | "daisyui": "4.7.2", 72 | "defu": "^6.1.4", 73 | "framer-motion": "^11.0.8", 74 | "just-safe-get": "^4.2.0", 75 | "just-safe-set": "^4.2.1", 76 | "just-shuffle": "^4.2.0", 77 | "mermaid": "^10.7.0", 78 | "mitt": "^3.0.1", 79 | "motion": "^10.17.0", 80 | "nanostores": "^0.10.0", 81 | "pts": "^0.11.6", 82 | "query-string": "^9.0.0", 83 | "react": "^18.0.0", 84 | "react-dom": "^18.0.0", 85 | "rehype-external-links": "^3.0.0", 86 | "rehype-pretty-code": "0.13.0", 87 | "shiki": "1.1.7", 88 | "tailwind-merge": "^2.2.1", 89 | "tailwind-scrollbar": "^3.0.5", 90 | "tailwindcss": "^3.4.1", 91 | "tweakpane": "^4.0.3", 92 | "zod": "^3.22.4" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /apps/documentation/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | "postcss-import": {}, 4 | "tailwindcss/nesting": {}, 5 | tailwindcss: {}, 6 | autoprefixer: {}, 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /apps/documentation/public/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doseofted/prim-rpc/8b9c9c1e91fe8443cf1216847575e40d3e5136c1/apps/documentation/public/placeholder.png -------------------------------------------------------------------------------- /apps/documentation/public/prim-doseofted-attribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doseofted/prim-rpc/8b9c9c1e91fe8443cf1216847575e40d3e5136c1/apps/documentation/public/prim-doseofted-attribution.png -------------------------------------------------------------------------------- /apps/documentation/public/prim-nav-doseofted-attribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doseofted/prim-rpc/8b9c9c1e91fe8443cf1216847575e40d3e5136c1/apps/documentation/public/prim-nav-doseofted-attribution.png -------------------------------------------------------------------------------- /apps/documentation/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | 4 | Sitemap: https://prim.doseofted.me/sitemap-index.xml 5 | -------------------------------------------------------------------------------- /apps/documentation/public/social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doseofted/prim-rpc/8b9c9c1e91fe8443cf1216847575e40d3e5136c1/apps/documentation/public/social.png -------------------------------------------------------------------------------- /apps/documentation/src/client.ts: -------------------------------------------------------------------------------- 1 | import { createPrimClient } from "@doseofted/prim-rpc" 2 | import { createMethodPlugin } from "@doseofted/prim-rpc-plugins/browser" 3 | import type * as Functions from "@/server" 4 | 5 | const endpoint = import.meta.env.SSR ? "" : "/prim" 6 | const module = import.meta.env.SSR ? import("@/server") : null 7 | const methodPlugin = createMethodPlugin() 8 | export const client = createPrimClient>({ endpoint, module, methodPlugin }) 9 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Code/Code.astro: -------------------------------------------------------------------------------- 1 | --- 2 | interface Props { 3 | /** "astro" is generally used in components, "rehype" always from mdx (the default) */ 4 | provider?: "astro" | "rehype" 5 | classOverride?: string 6 | } 7 | const { provider: provider = "rehype", classOverride } = Astro.props 8 | --- 9 | 10 |
16 | 17 |
18 | 19 | 24 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Code/CodeFile.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from "astro-icon/components" 3 | import Code from "./Code.astro" 4 | 5 | interface Props { 6 | /** A single filepath, separated by "/" */ 7 | filename?: string 8 | overrideClass?: string 9 | /** "astro" is generally used in components, "rehype" always from mdx (the default) */ 10 | codeProvider?: "astro" | "rehype" 11 | } 12 | const { filename, overrideClass, codeProvider = "rehype" } = Astro.props 13 | --- 14 | 15 |
16 | { 17 | filename && ( 18 | 31 | ) 32 | } 33 | 34 | 35 | 36 |
37 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Code/CodeTabs.react.tsx: -------------------------------------------------------------------------------- 1 | import { Tabs } from "@ark-ui/react" 2 | import { Icon } from "@iconify/react" 3 | import type { CSSProperties } from "react" 4 | 5 | // Slot key names need to be named for usage in Astro 6 | type CodeTabsList = { 7 | [key in `$tab${0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9}`]: React.ReactHTMLElement 8 | } 9 | export type CodeTabsProps = CodeTabsList & { 10 | details?: { name: string; icon: string }[] 11 | className?: string 12 | } 13 | 14 | export function CodeTabs(props: CodeTabsProps) { 15 | const { details, className } = props 16 | const tabs = Object.entries(props) 17 | .filter(([key]) => key.startsWith("$tab")) 18 | .sort((a, b) => (a[0] > b[0] ? 1 : -1)) 19 | .map(([_, tab]) => tab as React.ReactHTMLElement) 20 | return ( 21 | 24 | 25 | {details?.map(({ name, icon }, index) => ( 26 | 30 | 31 | {name} 32 | 33 | ))} 34 | 35 | 36 | {tabs.map((tab, index) => ( 37 | 38 | {tab} 39 | 40 | ))} 41 | 42 | ) 43 | } 44 | export default CodeTabs 45 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Columns.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { twMerge } from "tailwind-merge" 3 | 4 | interface Props { 5 | className?: string 6 | hideGrid?: boolean 7 | } 8 | const { className, hideGrid } = Astro.props 9 | const column12 = Array.from(Array(12).keys()) 10 | --- 11 | 12 |
13 | { 14 | !hideGrid && ( 15 |
20 | {column12.map(i => ( 21 |
= 6 ? "hidden lg:block" : ""]} 23 | style={`grid-column-start: ${i + 1}`} 24 | /> 25 | ))} 26 |
27 | ) 28 | } 29 |
30 | 31 |
32 |
33 | 34 | 48 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Container.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { twMerge } from "tailwind-merge" 3 | 4 | interface Props { 5 | className?: string 6 | } 7 | const { className } = Astro.props 8 | --- 9 | 10 |
11 |
12 | 13 |
14 |
15 | 16 |
17 |
18 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Documentation/NavigationDocs.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import type { TableOfContents } from "@/content/config" 3 | interface Props { 4 | tableOfContents: TableOfContents 5 | } 6 | const { tableOfContents } = Astro.props 7 | const path = Astro.url.pathname 8 | --- 9 | 10 | 30 | 31 | 37 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Documentation/VersionSelection.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { versionsAvailable, type TableOfContents } from "@/content/config" 3 | import { Icon } from "astro-icon/components" 4 | 5 | const path = Astro.url.pathname 6 | const selectedVersion = versionsAvailable?.find(v => !v.subdomain) 7 | const versionName = selectedVersion?.aliases[0] ? `${selectedVersion.name} (${selectedVersion?.aliases[0]})` : "" 8 | --- 9 | 10 | 31 | -------------------------------------------------------------------------------- /apps/documentation/src/components/FeatureCard.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from "astro-icon/components" 3 | 4 | interface Prop { 5 | title: string 6 | icon: string 7 | details: string 8 | } 9 | const { title, icon, details } = Astro.props 10 | --- 11 | 12 |
19 |

20 | {title} 21 | 22 |

23 |

{details}

24 |
25 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Footer.astro: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | 5 | Prim+RPC 6 | : a project by 7 | Ted Klingenberg 8 |

9 |
10 | 11 | Dose of Ted 12 | 13 |
14 | -------------------------------------------------------------------------------- /apps/documentation/src/components/IntroText.react.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react" 2 | import { animate, stagger } from "motion" 3 | import { easeOutExpo as easing } from "@/utils/easings" 4 | import { $navigationHappened } from "@/utils/store" 5 | 6 | interface IntroTextProps { 7 | text: string | string[] 8 | className?: string 9 | stagger?: number 10 | delay?: number 11 | duration?: number 12 | } 13 | export function IntroText(props: IntroTextProps) { 14 | const { text, stagger: staggerAmount = 0.5, delay: start = 0.5, duration = 0.6 } = props 15 | const textLines = typeof text === "string" ? [text] : text 16 | const elements: (HTMLSpanElement | null)[] = [] 17 | useEffect(() => { 18 | const elementsOnly = elements.filter((e): e is HTMLSpanElement => !!e) 19 | const keyframes = { 20 | y: ["100%", "0%"], 21 | opacity: [0.3, 1], 22 | } 23 | const options = { duration, delay: stagger(staggerAmount, { start }), easing } 24 | const animated = animate(elementsOnly, keyframes, options) 25 | return () => animated.stop() 26 | }, []) 27 | return ( 28 | <> 29 | {textLines.map((text, index) => ( 30 | 31 | 32 | elements.push(span)} className="inline-block" style={{ opacity: 0 }}> 33 | {text} 34 | 35 | 36 | {index !== textLines.length - 1 ?
: null} 37 |
38 | ))} 39 | 40 | ) 41 | } 42 | 43 | export function HomepageIntro(props: IntroTextProps) { 44 | const homeProps: IntroTextProps = { 45 | ...props, 46 | delay: 0, 47 | duration: 0.9, 48 | stagger: $navigationHappened.value ? 0.2 : 0.8, 49 | } 50 | return 51 | } 52 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Lights.astro: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 | 11 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/Aside.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from "astro-icon/components" 3 | 4 | interface Props { 5 | href?: string 6 | type?: "success" | "info" | "warning" | "error" 7 | actionText?: string 8 | onAction?: string 9 | } 10 | const types = { 11 | success: "alert-success bg-success/40 border-success", 12 | info: "alert-info bg-info/40 border-info", 13 | warning: "alert-warning bg-warning/40 border-warning", 14 | error: "alert-error bg-error/40 border-error", 15 | } 16 | const icons = { 17 | success: "ph:check-circle-duotone", 18 | info: "ph:info-duotone", 19 | warning: "ph:warning-circle-duotone", 20 | error: "ph:x-circle-duotone", 21 | } 22 | const { href, type: alertType, actionText, onAction } = Astro.props 23 | --- 24 | 25 |
26 | 27 |
28 | { 29 | href && ( 30 | 35 | ) 36 | } 37 |
38 | 39 | 50 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/Button.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from "astro-icon/components" 3 | import { twJoin } from "tailwind-merge" 4 | twJoin 5 | interface Props { 6 | href?: string 7 | icon?: `ph:${string}` | `simple-icons:${string}` | `/${string}` | (string & {}) 8 | block?: boolean 9 | classes?: string 10 | disabled?: boolean 11 | } 12 | const { href, icon, block, classes, disabled } = Astro.props 13 | const target = href?.startsWith("http") ? "_blank" : undefined 14 | const rel = href?.startsWith("http") ? "nofollow" : undefined 15 | const isIconComponent = !(icon && icon.startsWith("/")) 16 | --- 17 | 18 | 29 | {icon && (isIconComponent ? : )} 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/ButtonGroup.astro: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/Collapse.astro: -------------------------------------------------------------------------------- 1 | --- 2 | interface Props { 3 | title: string 4 | collapseId?: string 5 | checked?: boolean 6 | } 7 | const { title, collapseId, checked } = Astro.props 8 | --- 9 | 10 |
11 | 12 |
13 | {title} 14 |
15 |
16 | 17 |
18 |
19 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/DataList.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Collapse from "./Collapse.astro" 3 | import DataListItem from "./DataListItem.astro" 4 | 5 | interface Props { 6 | title?: string 7 | data?: Record 8 | } 9 | const { title = "Data", data } = Astro.props 10 | 11 | const contentsGiven = Astro.slots.has("default") 12 | --- 13 | 14 | 15 |
    16 | { 17 | contentsGiven ? ( 18 | 19 | ) : ( 20 | Object.entries(data ?? {}).map(([key, value]) => ) 21 | ) 22 | } 23 |
24 |
25 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/DataListItem.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from "astro-icon/components" 3 | import defu from "defu" 4 | interface Props { 5 | type?: "slot" | "text" | "boolean" | "link" 6 | keyName: string 7 | value?: string | string[] | boolean | number | { name: string; href: string }[] 8 | name?: string 9 | mappings?: Record<"truthy" | "falsey", string> 10 | horizontal?: boolean 11 | } 12 | const { keyName: keyName, value, type, name, mappings: mappingsGiven, horizontal = false } = Astro.props 13 | const mappings = defu(mappingsGiven, { 14 | truthy: "Yes", 15 | falsey: "No", 16 | link: " Link", 17 | }) 18 | const valueAsArray = Array.isArray(value) ? value : [value] 19 | --- 20 | 21 |
  • 22 |
    {keyName}:
    23 | { 24 | type === "text" ? ( 25 |
    {value}
    26 | ) : type === "boolean" ? ( 27 |
    28 | 32 | {mappings[value ? "truthy" : "falsey"]} 33 |
    34 | ) : type === "link" ? ( 35 |
    36 | {valueAsArray.map((value, index, { length }) => ( 37 | <> 38 | 42 | {typeof value === "object" ? value.name : name} 43 | {typeof value === "object" && value.href.startsWith("http") && ( 44 | 45 | )} 46 | 47 | {index < length - 1 && ", "} 48 | 49 | ))} 50 |
    51 | ) : ( 52 |
    53 | 54 |
    55 | ) 56 | } 57 |
  • 58 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/DataListOptions.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import DataListItem from "./DataListItem.astro" 3 | 4 | interface Props { 5 | synced?: boolean 6 | } 7 | 8 | const { synced = false } = Astro.props 9 | --- 10 | 11 |
      12 | 13 |
    14 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/DataListPlugin.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import type { PluginType, TransportType } from "@/content/config" 3 | import DataList from "./DataList.astro" 4 | import DataListItem from "./DataListItem.astro" 5 | 6 | interface Props { 7 | data?: Record 8 | } 9 | const { data: given = {} } = Astro.props 10 | 11 | const typeMappings: Record = { 12 | "callback-handler": "Callback Handler", 13 | "method-handler": "Method Handler", 14 | "callback-plugin": "Callback Plugin", 15 | "method-plugin": "Method Plugin", 16 | "json-handler": "JSON Handler", 17 | validator: "Validation Tool", 18 | } satisfies Record 19 | const type = typeMappings["type" in given ? String(given.type) : ""] 20 | 21 | const transportMappings: Record = { 22 | inapplicable: "Inapplicable", 23 | http: "HTTP", 24 | ws: "WebSocket", 25 | node: "Node", 26 | "socket-io": "Socket.io", 27 | worker: "Web Worker", 28 | event: "Event handler", 29 | electron: "Electron", 30 | } satisfies Record 31 | const transport = transportMappings["transport" in given ? String(given.transport) : "inapplicable"] 32 | 33 | const links = Array.isArray(given.links) ? given.links : [] 34 | --- 35 | 36 | 37 | 38 | 39 | {links.length > 0 && } 40 | 41 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/Heading/H2.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Heading from "./Heading.astro" 3 | interface Props { 4 | id: string 5 | } 6 | const props = Astro.props 7 | --- 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/Heading/H3.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Heading from "./Heading.astro" 3 | interface Props { 4 | id: string 5 | } 6 | const props = Astro.props 7 | --- 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/Heading/Heading.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from "astro-icon/components" 3 | 4 | interface Props { 5 | id: string 6 | level: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" 7 | } 8 | const { id, level: HeadingType } = Astro.props 9 | --- 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/LinkButton.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from "astro-icon/components" 3 | interface Props { 4 | icon?: string 5 | name?: string 6 | href?: string 7 | block?: boolean 8 | /** Search is appended to given `href` and does not overrride existing query */ 9 | search?: Record 10 | hash?: string 11 | } 12 | const { name, href = Astro.url.toString(), icon, block, search = {}, hash: overrideHash } = Astro.props 13 | const urlGiven = new URL(href, Astro.site) 14 | const givenParams = new URLSearchParams(urlGiven.search) 15 | const newParams = new URLSearchParams(search) 16 | const uniqueParamMap = new Map([...givenParams, ...newParams]) 17 | const searchParams = new URLSearchParams(Array.from(uniqueParamMap)) 18 | const { origin, pathname, hash: givenHash } = urlGiven 19 | const newHref = [pathname, "?", searchParams.toString(), overrideHash || givenHash].join("") 20 | 21 | const linkIsActive = Astro.url.toString() === newHref.replace(/#[\w-_]+$/g, "") 22 | const linkIncludesSearch = Object.entries(search) 23 | .map(([key, value]) => givenParams.get(key) === value) 24 | .every(b => b) 25 | const active = linkIsActive || linkIncludesSearch 26 | --- 27 | 28 | 31 | {icon && } 32 | {name} 33 | 34 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/ListGrid.astro: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/PluginChoices.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Button from "./Button.astro" 3 | import ListGrid from "./ListGrid.astro" 4 | import { getCollection } from "astro:content" 5 | 6 | interface Props { 7 | type?: string 8 | transport?: string 9 | } 10 | const { type: givenType = "all", transport: givenTransport = "all" } = Astro.props 11 | 12 | const plugins = await getCollection("plugins") 13 | const pluginsSorted = plugins.sort((a, b) => (a.data.title > b.data.title ? 1 : -1)) 14 | --- 15 | 16 | 17 | { 18 | pluginsSorted 19 | .filter(plugin => givenType === "all" || plugin.data.type === givenType) 20 | .filter(plugin => givenTransport === "all" || plugin.data.transport === givenTransport) 21 | .map(plugin => ( 22 | 29 | )) 30 | } 31 | 32 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Markdown/Table.astro: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 |
    5 |
    6 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Marquee.astro: -------------------------------------------------------------------------------- 1 | --- 2 | interface Props { 3 | direction?: "left" | "right" 4 | speed?: `${number}s` | `${number}ms` 5 | } 6 | const { direction = "left", speed = "100s" } = Astro.props 7 | --- 8 | 9 |
    10 |
    11 | 12 |
    13 | 16 |
    17 | 18 | 53 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Navigation.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Prim from "@/components/Prim.astro" 3 | import NavigationItem from "./NavigationItem.astro" 4 | import Container from "./Container.astro" 5 | 6 | interface Props { 7 | brand?: string 8 | } 9 | const { brand = "RPC" } = Astro.props 10 | 11 | const navigation = [ 12 | { link: "/docs/learn/introduction", text: "Docs" }, 13 | { link: "https://doseofted.me/", text: "Dose of Ted", icon: "/prim-nav-doseofted-attribution.png" }, 14 | { link: "https://www.threads.net/@doseofted", text: "Threads", icon: "simple-icons:threads" }, 15 | { link: "https://github.com/doseofted/prim-rpc", text: "GitHub", icon: "simple-icons:github" }, 16 | ] 17 | --- 18 | 19 | 40 | 41 | 42 | 43 |
    44 |
    46 |
    47 | 48 | 49 | 50 | {navigation.filter(nav => !nav.icon).map(item => )} 51 |
    52 | {navigation.filter(nav => nav.icon).map(item => )} 53 |
    54 |
    55 |
    56 |
    57 |
    58 | 59 |
    60 |
    61 | 62 | 80 | -------------------------------------------------------------------------------- /apps/documentation/src/components/NavigationItem.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from "astro-icon/components" 3 | import { twMerge } from "tailwind-merge" 4 | 5 | interface Props { 6 | icon?: string 7 | text?: string 8 | link?: string 9 | type?: "a" | "button" | "div" 10 | className?: string 11 | onclick?: string 12 | rounded?: "all" | "bottom" 13 | } 14 | const { type: ElemType = "a", rounded = "all", ...item } = Astro.props 15 | --- 16 | 17 | g).join("-"), 20 | "navigation-item flex justify-center items-center relative z-10 p-4 h-full font-semibold uppercase text-sm", 21 | item.icon ? "px-4" : "px-6", 22 | item.className, 23 | ])} 24 | href={item.link} 25 | target={item.link?.startsWith("/") ? "_self" : "_blank"} 26 | aria-label={item.text} 27 | onclick={item.onclick}> 28 | { 29 | item.icon ? ( 30 | <> 31 | {item.icon.startsWith("/") ? ( 32 | 33 | ) : ( 34 | 35 | )} 36 |
    40 | 41 | ) : ( 42 | {item.text} 43 | ) 44 | } 45 | 46 | 47 | 81 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Prerelease.astro: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | 5 | 24 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Prim.astro: -------------------------------------------------------------------------------- 1 | 2 |

    4 | Prim+ 5 | 6 | 7 | 8 |

    9 |
    10 | -------------------------------------------------------------------------------- /apps/documentation/src/components/ReportIssue.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Icon } from "astro-icon/components" 3 | import queryString from "query-string" 4 | 5 | interface Props { 6 | type?: string 7 | title: string 8 | href: string 9 | } 10 | const { type = "Documentation", title, href } = Astro.props 11 | 12 | const reportIssueUrl = [ 13 | "https://github.com/doseofted/prim-rpc/issues/new", 14 | queryString.stringify({ 15 | title: `${type} Issue: ${title}`, 16 | body: `**Link**: [${href}](${href})\n\n**What's happening:**\n\n`, 17 | }), 18 | ].join("?") 19 | --- 20 | 21 | 25 | 26 | Report an Issue 27 | 28 | -------------------------------------------------------------------------------- /apps/documentation/src/components/Snippets/ServerNotice.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Aside from "../Markdown/Aside.astro" 3 | --- 4 | 5 | 11 | -------------------------------------------------------------------------------- /apps/documentation/src/components/TableOfContents.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import type { MarkdownHeading } from "astro" 3 | import { Icon } from "astro-icon/components" 4 | 5 | interface Props { 6 | /** 7 | * Note that all headings are given at same level regardless of given depth. 8 | * If deeper depths are needed, consider simplifying the page instead. 9 | */ 10 | headings: MarkdownHeading[] 11 | } 12 | const { headings: allHeadings = [] } = Astro.props 13 | const path = Astro.url.pathname 14 | 15 | const headings = allHeadings.filter(({ depth }) => depth > 1) 16 | --- 17 | 18 | { 19 | headings.length > 0 ? ( 20 | 34 | ) : ( 35 |
    36 |

    No sections available.

    37 |
    38 | ) 39 | } 40 |
    41 | 45 |
    46 | 47 | 53 | -------------------------------------------------------------------------------- /apps/documentation/src/components/ToggleEffects.astro: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | 5 | 34 | -------------------------------------------------------------------------------- /apps/documentation/src/content/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doseofted/prim-rpc/8b9c9c1e91fe8443cf1216847575e40d3e5136c1/apps/documentation/src/content/api/.gitkeep -------------------------------------------------------------------------------- /apps/documentation/src/content/config.ts: -------------------------------------------------------------------------------- 1 | import { defineCollection, type getCollection, z } from "astro:content" 2 | 3 | export interface TableOfContentsSection { 4 | name: string 5 | link?: string 6 | sections?: TableOfContentsSection[] 7 | } 8 | export type TableOfContents = TableOfContentsSection[] 9 | 10 | export const versionsAvailable = [ 11 | { 12 | name: "v0", 13 | aliases: ["latest"], 14 | subdomain: "", // not on a subdomain 15 | available: true, 16 | }, 17 | ] 18 | export const latestVersion = "v0" 19 | export const documentationCollections = ["docs", "plugins"] as const 20 | 21 | /** Table of Contents for Documentation pages */ 22 | export const documentationContents = (collection = "docs"): TableOfContents => [ 23 | { 24 | name: "Learning", 25 | sections: [ 26 | { name: "Introduction", link: `/${collection}/learn/introduction` }, 27 | { name: "Setup", link: `/${collection}/learn/setup` }, 28 | { name: "Advanced", link: `/${collection}/learn/advanced` }, 29 | { name: "Examples", link: `/${collection}/learn/examples` }, 30 | { name: "Security", link: `/${collection}/learn/security` }, 31 | { name: "Limitations", link: `/${collection}/learn/limitations` }, 32 | { name: "Comparisons", link: `/${collection}/learn/comparisons` }, 33 | ], 34 | }, 35 | { 36 | name: "Reference", 37 | sections: [ 38 | { name: "Core API", link: `/${collection}/reference/api` }, 39 | { name: "Configuration", link: `/${collection}/reference/config` }, 40 | { name: "Browse Plugins", link: `/${collection}/reference/plugins` }, 41 | { name: "Create Plugin", link: `/${collection}/reference/create` }, 42 | { name: "RPC Structure", link: `/${collection}/reference/structure` }, 43 | ], 44 | }, 45 | { 46 | name: "Tooling", 47 | sections: [ 48 | { name: "Documentation", link: `/${collection}/tooling/docs` }, 49 | { name: "Prevent Build", link: `/${collection}/tooling/build` }, 50 | ], 51 | }, 52 | ] 53 | 54 | const pluginTypes = z.enum([ 55 | "method-handler", 56 | "method-plugin", 57 | "callback-handler", 58 | "callback-plugin", 59 | "json-handler", 60 | "validator", 61 | ]) 62 | export type PluginType = z.infer 63 | 64 | export type DocumentationCollection = (typeof documentationCollections)[number] 65 | export type CollectionType = Awaited>>[number] 66 | 67 | const transportTypes = z.enum(["http", "ws", "event", "worker", "socket-io", "electron", "node", "inapplicable"]) 68 | export type TransportType = z.infer 69 | 70 | export const collections = { 71 | docs: defineCollection({ 72 | type: "content", 73 | schema: z.object({ 74 | title: z.string(), 75 | description: z.string().optional(), 76 | }), 77 | }), 78 | plugins: defineCollection({ 79 | type: "content", 80 | schema: z.object({ 81 | title: z.string(), 82 | icon: z.string().optional(), 83 | type: pluginTypes, 84 | transport: transportTypes, 85 | features: z.array(z.string()).optional(), 86 | status: z.enum(["planned", "available", "deprecated"]), 87 | links: z.object({ name: z.string(), href: z.string() }).array().optional(), 88 | }), 89 | }), 90 | api: defineCollection({ 91 | type: "data", 92 | }), 93 | } 94 | -------------------------------------------------------------------------------- /apps/documentation/src/content/docs/learn/limitations.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Limitations 3 | --- 4 | 5 | # {frontmatter.title} 6 | 7 | Prim+RPC allows functions on the server to be called from the client. This is possible because all function calls are 8 | captured on the client, processed on the server, and sent back to the client. But there are some limitations. 9 | 10 | ## Results are Promised 11 | 12 | All functions on the server, whether async or not, are considered async on the client and type definitions will reflect 13 | that your function results are wrapped in a Promise. This is because while it appears that you are calling the function 14 | directly, your function is being requested from another environment where it may take time to receive the result (for 15 | example, over a network) or that result may not be received in some circumstances (i.e. when network access is lost). 16 | 17 | It's also worth noting that if your function is requested over a network and the network is lost, your client's method 18 | plugin may error. The thrown error will be forwarded to your function's caller. This is the default behavior of 19 | client-side plugins unless you enable options to silence the error or repeat the request on a failure. 20 | 21 | ## Keep Data Serializable 22 | 23 | Since function calls are not answered on the same client and must be sent somewhere else, the data passed to and 24 | received from functions must be serializable by your chosen JSON handler. Most of the time, this will be the 25 | [JSON object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) (or 26 | [structured cloning](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), if 27 | used with Web Workers) unless you choose to override it in Prim+RPC's options. 28 | 29 | ## Function Context is Set 30 | 31 | Prim+RPC sets the context of your function, the `this` object, to your chosen handler's context. This allows 32 | server-specific details to be passed to your function easily and optionally. 33 | 34 | However it means that methods on an instantiated object may not be called directly without potential errors. The easy 35 | workaround for this is to wrap your method in another function. The wrapper function will have the server's context and 36 | the contained function will keep its original context. 37 | 38 | **This behavior may change prior to official release.** If the behavior is changed then the original context will be 39 | kept by default unless server context is explicitly set on your chosen handler (currently the context is `undefined` if 40 | not explicitly set from the server). 41 | 42 | ## Prerelease Limitations 43 | 44 | Prim+RPC is currently in prerelease mode and some features are intended to be supported but are not yet implemented: 45 | 46 | - Functions can't be returned from functions yet (no currying) 47 | - Callbacks can't return values back to function yet 48 | - Files and callbacks can't be passed together on the same function yet 49 | 50 | There are also some features that won't be available in the first official release: 51 | 52 | - Generator functions are unsupported 53 | - Method chaining is unsupported (partially depends on ability to curry) 54 | 55 | It is still possible that these features will be added in the future but since these features are difficult to support, 56 | unlikely to be used, and Prim+RPC is gearing up for a stable release, they are considered low priority for version one. 57 | -------------------------------------------------------------------------------- /apps/documentation/src/content/docs/reference/plugins.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: All Plugins 3 | --- 4 | 5 | import PluginChoices from "@/components/Markdown/PluginChoices.astro" 6 | import Aside from "@/components/Markdown/Aside.astro" 7 | 8 | # {frontmatter.title} 9 | 10 | Prim+RPC works with many frameworks though plugins on the client and handlers on the server. See the 11 | [Setup Guide](/docs/learn/setup) to learn more about how Prim+RPC works and how it interacts with plugins. 12 | 13 | 19 | 20 | ## Server Handlers 21 | 22 | **Method Handlers**: allow methods on the server to be called 23 | 24 | 25 | 26 | **Callback Handlers**: allow callbacks given to the server (optional) 27 | 28 | 29 | 30 | ## Client Plugins 31 | 32 | **Method Plugins**: allow method usage on the client 33 | 34 | 35 | 36 | **Callback Plugins**: allow callback usage on the client (optional) 37 | 38 | 39 | 40 | ## Additional 41 | 42 | You may customize how Prim+RPC works by swapping out the serialization library or adding validation with your favorite 43 | libraries. 44 | 45 | 46 | -------------------------------------------------------------------------------- /apps/documentation/src/content/docs/tooling/build.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Prevent Build Utility 3 | --- 4 | 5 | # {frontmatter.title} 6 | 7 | import CodeFile from "@/components/Code/CodeFile.astro" 8 | import Aside from "@/components/Markdown/Aside.astro" 9 | 10 | 15 | 16 | The "Prevent Build" utility is a simple way of preventing a build using popular bundlers if server-specific code is 17 | accidentally imported. This is not required and often times is not needed as server and client are typically located in 18 | separate parts of a project but it can provide additional peace of mind that a developer doesn't import server code in 19 | the client. 20 | 21 | The utility is built with [unplugin](https://github.com/unjs/unplugin#readme) which means it can support the most 22 | popular bundlers used with JavaScript. Below is an example of how it may be used in Vite: 23 | 24 | 25 | 26 | ```typescript 27 | import path from "node:path" 28 | import { defineConfig } from "vite" 29 | import preventImport, { BuildModifyMethod } from "@doseofted/prim-rpc-tooling/build" 30 | 31 | export default defineConfig({ 32 | plugins: [ 33 | preventImport.vite({ 34 | name: path.join(__dirname, "server"), 35 | method: BuildModifyMethod.BuildTimeEmptyExport, 36 | }), 37 | ], 38 | }) 39 | ``` 40 | 41 | 42 | 43 | You may also use this plugin with Webpack or Rollup, among others. 44 | 45 | This example blocks imports from the `./server{:txt}` directory by replacing the contents of the imported file with an 46 | empty export. There are several methods to block imports: 47 | 48 | - `BuildModifyMethod.BuildTimeEmptyExport` happens at **build-time** and replaces imported server code with an empty 49 | export 50 | - `BuildModifyMethod.RunTimeProcessCheck` happens at **run-time** and prepends a statement that throws an error if 51 | server code is imported by checking `process.server`. This is useful for flagging such errors in testing frameworks. 52 | - `BuildModifyMethod.RunTimeWindowCheck` also happens at **run-time** and is similar to the last option except instead 53 | of checking `process.server` it checks if the `typeof window === "undefined"`. 54 | -------------------------------------------------------------------------------- /apps/documentation/src/content/docs/tooling/docs.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Documentation Generation 3 | --- 4 | 5 | # {frontmatter.title} 6 | 7 | import CodeFile from "@/components/Code/CodeFile.astro" 8 | import Aside from "@/components/Markdown/Aside.astro" 9 | 10 | 15 | 16 | Prim+RPC includes tools to generate RPC-specific documentation. It does this by reusing your existing 17 | [TypeDoc documentation](https://github.com/TypeStrong/typedoc#typedoc) for your TypeScript or JavaScript code and 18 | converts this into a simpler version that documents functions as it relates to RPC. 19 | 20 | The first step is to generate TypeDoc documentation for your code. This can be done by running the following command in 21 | your project: 22 | 23 | 24 | 25 | ```zsh 26 | npx typedoc src/index.ts --json dist/docs.json 27 | ``` 28 | 29 | 30 | 31 | Now you may execute this utility on the result: 32 | 33 | 34 | 35 | ```typescript 36 | import { createDocsForModule } from "@doseofted/prim-rpc-tooling/docs" 37 | import typeDoc from "./dist/docs.json" 38 | 39 | const rpcDocs = createDocsForModule(typeDoc) 40 | ``` 41 | 42 | 43 | 44 | The resulting documentation is a simpler version of the TypeDoc that relates to RPC. This output could be used for a 45 | documentation website or fed to another tool like [HTTPsnippet](https://github.com/Kong/httpsnippet#readme) to generate 46 | requests for other clients outside of JavaScript. 47 | 48 | 55 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/additional/json-handlers.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: JSON Handlers 3 | icon: ph:globe-bold 4 | type: json-handler 5 | transport: inapplicable 6 | features: [] 7 | status: available 8 | --- 9 | 10 | import CodeFile from "@/components/Code/CodeFile.astro" 11 | 12 | Prim+RPC by default will serialize messages passed to it using the default JSON "stringify" method to serialize RPC and 13 | the [destr](https://github.com/unjs/destr#readme) library to deserialize RPC. This JSON handler implementation can be 14 | swapped out with any other library to support advanced types like Dates, Maps, Sets, or others. 15 | 16 | We can provide our own JSON handler that resembles the default JSON handler (with a few optional additions). See the 17 | [configuration page for the JSON Handler](/docs/reference/config#-json-handler) for more details on setting up your own 18 | or browse popular examples on this page. 19 | 20 | **In all cases**, the JSON handler must be the same on both the client and server. This list is non-exhaustive and you 21 | may choose to implement your own JSON handler. 22 | 23 | ## SuperJSON 24 | 25 | [SuperJSON](https://github.com/blitz-js/superjson#readme) allows additional types to be used with Prim+RPC. The JSON 26 | handler will look like this: 27 | 28 | 29 | 30 | ```typescript 31 | import jsonHandler from "superjson" 32 | 33 | createPrimClient({ jsonHandler }) 34 | createPrimServer({ jsonHandler }) 35 | ``` 36 | 37 | 38 | 39 | ## MsgPack 40 | 41 | [MsgPack](https://github.com/msgpack/msgpack-javascript#readme) supports additional types including ArrayBuffer types. 42 | While it is not JSON, it can be used with Prim+RPC. There are also several implementations of MsgPack and you may choose 43 | one that best suits your needs. 44 | 45 | We'll add a few additional options to the handler to allow Prim+RPC plugins to better work with binary data: 46 | 47 | 48 | 49 | ```typescript 50 | import { encode as stringify, decode as parse } from "@msgpack/msgpack" 51 | 52 | const jsonHandler = { 53 | stringify, 54 | parse, 55 | mediaType: "application/octet-stream", 56 | binary: true, 57 | } 58 | 59 | createPrimClient({ jsonHandler }) 60 | createPrimServer({ jsonHandler }) 61 | ``` 62 | 63 | 64 | 65 | ## devalue 66 | 67 | Like the SuperJSON example, [devalue](https://github.com/Rich-Harris/devalue#readme) may be used to support additional 68 | types with Prim+RPC. The JSON handler can be set up like so: 69 | 70 | 71 | 72 | ```typescript 73 | import jsonHandler from "devalue" 74 | 75 | createPrimClient({ jsonHandler }) 76 | createPrimServer({ jsonHandler }) 77 | ``` 78 | 79 | 80 | 81 | ## YAML 82 | 83 | [YAML](https://github.com/eemeli/yaml#readme) may be used with Prim+RPC and may be a more readable alternative to JSON. 84 | The JSON-like handler can be set up like so: 85 | 86 | 87 | 88 | ```typescript 89 | import yaml from "yaml" 90 | 91 | const jsonHandler = { 92 | parse: yaml.parse, 93 | stringify: yaml.stringify, 94 | mediaType: "application/yaml", 95 | } 96 | 97 | createPrimClient({ jsonHandler }) 98 | createPrimServer({ jsonHandler }) 99 | ``` 100 | 101 | 102 | 103 | ## Others 104 | 105 | These are some popular examples but Prim+RPC can be configured to use other JSON or JSON-like handlers. 106 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/client/axios.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Axios 3 | icon: simple-icons:axios 4 | type: method-plugin 5 | transport: http 6 | features: [] 7 | status: planned 8 | links: 9 | - name: Axios 10 | href: https://github.com/axios/axios#readme 11 | --- 12 | 13 | **Status**: {frontmatter.status} 14 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/client/browser-fetch.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fetch API 3 | icon: simple-icons:javascript 4 | type: method-plugin 5 | transport: http 6 | features: [] 7 | status: available 8 | links: 9 | - name: Fetch API 10 | href: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API 11 | --- 12 | 13 | import CodeFile from "@/components/Code/CodeFile.astro" 14 | import Aside from "@/components/Markdown/Aside.astro" 15 | 16 | 20 | 21 | Prim+RPC supports the Fetch API as implemented in all modern browsers. 22 | 23 | 24 | 25 | ```typescript {2,5-6} 26 | import { createPrimClient } from "@doseofted/prim-rpc" 27 | import { createMethodPlugin } from "@doseofted/prim-rpc-plugins/browser-fetch" 28 | 29 | export const client = createPrimClient({ 30 | endpoint: "http://localhost:3000/prim", 31 | methodPlugin: createMethodPlugin(), 32 | }) 33 | ``` 34 | 35 | 36 | 37 | Your endpoint may look different depending on your server selection. Check with your server for the correct endpoint. 38 | 39 | You may also add types to your client by passing them as a type argument to the client. **Always ensure that only types 40 | are passed to the client, not the module itself.** 41 | 42 | 43 | 44 | ```typescript {3} // 45 | import { createPrimClient } from "@doseofted/prim-rpc" 46 | import { createMethodPlugin } from "@doseofted/prim-rpc-plugins/browser-fetch" 47 | import type * as Module from "./functions" 48 | 49 | export const client = createPrimClient({ 50 | endpoint: "http://localhost:3000/prim", 51 | methodPlugin: createMethodPlugin(), 52 | }) 53 | ``` 54 | 55 | 56 | 57 | The imported types given here is an example and your import will depend on where your types are exported from the 58 | server. 59 | 60 | Now you may use this client anywhere in your project: 61 | 62 | 63 | 64 | ```typescript 65 | import { client } from "./client" 66 | 67 | const greeting = await client.hello() 68 | console.log(greeting) 69 | ``` 70 | 71 | 72 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/client/browser-websocket.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: WebSocket 3 | icon: simple-icons:javascript 4 | type: "callback-plugin" 5 | transport: "ws" 6 | features: [] 7 | status: available 8 | links: 9 | - name: WebSocket API 10 | href: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket 11 | --- 12 | 13 | import CodeFile from "@/components/Code/CodeFile.astro" 14 | 15 | Prim+RPC can be used with the WebSocket API as implemented in all modern browsers. This plugin will allow Prim+RPC to 16 | [communicate with a callback handler](/docs/reference/plugins#server-handlers) used with the Prim+RPC server. 17 | 18 | We can set up a client like so: 19 | 20 | 21 | 22 | ```typescript 23 | import { createPrimClient } from "@doseofted/prim-rpc" 24 | import { createCallbackPlugin } from "@doseofted/prim-rpc-plugins/browser-websocket" 25 | import type * as Module from "./module" 26 | 27 | const callbackPlugin = createCallbackPlugin() 28 | const client = createPrimClient({ 29 | wsEndpoint: "ws://localhost:3000/prim" 30 | callbackPlugin 31 | }) 32 | ``` 33 | 34 | 35 | 36 | You may also use this plugin [alongside a method plugin](/docs/reference/plugins#client-plugins): Prim+RPC will know 37 | when to use the callback plugin versus the method plugin. 38 | 39 | If you are using the callback plugin alongside a method plugin, ensure that the WebSocket endpoint is correct as this 40 | server may share the same port as your HTTP server. This will depend on how you choose to configure your WebSockets. 41 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/client/capacitor-http.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Capacitor 3 | icon: simple-icons:capacitor 4 | type: method-plugin 5 | transport: http 6 | features: [] 7 | status: planned 8 | links: 9 | - name: Capacitor HTTP 10 | href: https://capacitorjs.com/docs/apis/http 11 | --- 12 | 13 | **Status**: {frontmatter.status} 14 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/client/child-process.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Child Process 3 | icon: simple-icons:nodedotjs 4 | type: method-plugin 5 | transport: node 6 | features: [] 7 | status: planned 8 | links: 9 | - name: Child Process 10 | href: https://nodejs.org/api/child_process.html#child-process 11 | --- 12 | 13 | **Status**: {frontmatter.status} 14 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/client/electron.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Electron 3 | icon: simple-icons:electron 4 | type: method-plugin 5 | transport: electron 6 | features: [] 7 | status: planned 8 | links: 9 | - name: Electron 10 | href: https://github.com/electron/electron#readme 11 | --- 12 | 13 | **Status**: {frontmatter.status} 14 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/client/socket-io.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Socket.io 3 | icon: simple-icons:socketdotio 4 | type: callback-plugin 5 | transport: socket-io 6 | features: [] 7 | status: planned 8 | links: 9 | - name: Socket.io 10 | href: https://github.com/socketio/socket.io#readme 11 | --- 12 | 13 | **Status**: {frontmatter.status} 14 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/client/testing.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Testing 3 | icon: ph:test-tube-fill 4 | type: method-plugin 5 | transport: event 6 | features: [] 7 | status: available 8 | links: 9 | - name: Vitest 10 | href: https://github.com/vitest-dev/vitest#readme 11 | - name: Jest 12 | href: https://github.com/jestjs/jest#readme 13 | --- 14 | 15 | import Aside from "@/components/Markdown/Aside.astro" 16 | 17 | 23 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/client/web-worker.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Web Worker 3 | icon: simple-icons:javascript 4 | type: method-plugin 5 | transport: worker 6 | features: [] 7 | status: available 8 | links: 9 | - name: Web Worker 10 | href: https://developer.mozilla.org/en-US/docs/Web/API/Worker 11 | - name: Shared Worker 12 | href: https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker 13 | --- 14 | 15 | import Aside from "@/components/Markdown/Aside.astro" 16 | 17 | 22 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/server/astro.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Astro 3 | icon: simple-icons:astro 4 | type: method-handler 5 | transport: http 6 | features: [] 7 | status: available 8 | links: 9 | - name: Astro 10 | href: https://github.com/withastro/astro#readme 11 | --- 12 | 13 | import CodeFile from "@/components/Code/CodeFile.astro" 14 | 15 | Prim+RPC supports 16 | [Astro in SSR mode](https://docs.astro.build/en/guides/server-side-rendering/#enabling-ssr-in-your-project). 17 | 18 | Let's say that you have a module like so (you can place functions wherever you'd like): 19 | 20 | 21 | 22 | ```typescript 23 | export function hello() { 24 | return "Hi from Prim+RPC!" 25 | } 26 | hello.rpc = true 27 | 28 | export default hello 29 | ``` 30 | 31 | 32 | 33 | You may configure Prim+RPC with Astro's Server Endpoints by using a catch-all route in your pages directory: 34 | 35 | 36 | 37 | ```typescript 38 | import { createPrimServer } from "@doseofted/prim-rpc" 39 | import { defineAstroPrimHandler } from "@doseofted/prim-rpc-plugins/astro" 40 | import * as module from "../../server" 41 | 42 | const prim = createPrimServer({ module }) 43 | 44 | // Astro 3+ 45 | export const { GET, POST } = defineAstroPrimHandler({ prim }) 46 | // Only if Astro <=3 (exported method names were lowercase) 47 | export const { GET: get, POST: post } = defineAstroPrimHandler({ prim }) 48 | ``` 49 | 50 | 51 | 52 | Your Prim+RPC server is now set up! Astro is a fullstack framework that runs on both server and client, which means the 53 | Prim+RPC client may be called on the server. 54 | 55 | On the server, you can avoid a network request from the client by conditionally passing the module. Below is an example 56 | of how you may do so, using the Fetch API method plugin: 57 | 58 | 59 | 60 | ```typescript 61 | import { createPrimClient } from "@doseofted/prim-rpc" 62 | import { createMethodPlugin } from "@doseofted/prim-rpc-plugins/browser" 63 | import type * as Module from "./server" 64 | 65 | const endpoint = import.meta.env.SSR ? "" : "/prim" 66 | const module = import.meta.env.SSR ? import("./server") : null 67 | const methodPlugin = createMethodPlugin() 68 | export const client = createPrimClient>({ endpoint, module, methodPlugin }) 69 | ``` 70 | 71 | 72 | 73 | Now this exported client may used from anywhere in your project: 74 | 75 | 76 | 77 | ```astro 78 | --- 79 | import { client } from "../client" 80 | const greeting = await client.hello() 81 | --- 82 | 83 |

    Server rendered: {greeting}

    84 |

    Client rendered:

    85 | 86 | 91 | ``` 92 | 93 |
    94 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/server/child-process.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Child Process 3 | icon: simple-icons:nodedotjs 4 | type: method-handler 5 | transport: node 6 | features: [] 7 | status: planned 8 | links: 9 | - name: Child Process 10 | href: https://nodejs.org/api/child_process.html#child-process 11 | --- 12 | 13 | **Status**: {frontmatter.status} 14 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/server/electron.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Electron 3 | icon: simple-icons:electron 4 | type: method-handler 5 | transport: electron 6 | features: [] 7 | status: planned 8 | links: 9 | - name: Electron 10 | href: https://github.com/electron/electron#readme 11 | --- 12 | 13 | **Status**: {frontmatter.status} 14 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/server/express.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Express 3 | icon: simple-icons:express 4 | type: method-handler 5 | transport: http 6 | features: [] 7 | status: available 8 | links: 9 | - name: Express 10 | href: https://github.com/expressjs/express#readme 11 | --- 12 | 13 | import CodeFile from "@/components/Code/CodeFile.astro" 14 | 15 | The Prim+RPC server can be configured with Express. First, create some module to be shared with server 16 | 17 | 18 | 19 | ```typescript 20 | export function hello() { 21 | return "Hi from Prim+RPC!" 22 | } 23 | hello.rpc = "idempotent" 24 | 25 | export default hello 26 | ``` 27 | 28 | 29 | 30 | Below is a simple example of how to use this module with Express: 31 | 32 | 33 | 34 | ```typescript 35 | import { createPrimServer } from "@doseofted/prim-rpc" 36 | import { createMethodHandler } from "@doseofted/prim-rpc-plugins/express" 37 | import express from "express" 38 | import * as module from "./functions" 39 | 40 | const app = express() 41 | 42 | const methodHandler = createMethodHandler({ app }) 43 | createPrimServer({ module, methodHandler }) 44 | 45 | app.listen(3000) 46 | ``` 47 | 48 | 49 | 50 | This configuration does not yet support Files and Blobs but we can do so by adding new Express middleware. First, 51 | install both `formidable{:txt}` and `form-data{:txt}` using your chosen package manager. Then you can configure it like 52 | so: 53 | 54 | 55 | 56 | ```typescript {4-5} /multipartPlugin, formDataHandler/ 57 | import { createPrimServer } from "@doseofted/prim-rpc" 58 | import { createMethodHandler } from "@doseofted/prim-rpc-plugins/express" 59 | import express from "express" 60 | import multipartPlugin from "formidable" 61 | import formDataHandler from "form-data" 62 | 63 | const app = express() 64 | 65 | const methodHandler = createMethodHandler({ app, multipartPlugin, formDataHandler }) 66 | createPrimServer({ module, methodHandler }) 67 | 68 | app.listen(3000) 69 | ``` 70 | 71 | 72 | 73 | Now we can test this out with a simple call from the command line: 74 | 75 | 76 | 77 | ```zsh 78 | curl "http://localhost:3000/prim" 79 | ``` 80 | 81 | 82 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/server/fastify.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Fastify 3 | icon: simple-icons:fastify 4 | type: method-handler 5 | transport: http 6 | features: [] 7 | status: available 8 | links: 9 | - name: Fastify 10 | href: https://github.com/fastify/fastify#readme 11 | --- 12 | 13 | import CodeFile from "@/components/Code/CodeFile.astro" 14 | 15 | The Prim+RPC server can be configured with Fastify. First, create some module to be shared with server 16 | 17 | 18 | 19 | ```typescript 20 | export function hello() { 21 | return "Hi from Prim+RPC!" 22 | } 23 | hello.rpc = "idempotent" 24 | 25 | export default hello 26 | ``` 27 | 28 | 29 | 30 | Below is a simple example of how to use this module with Fastify: 31 | 32 | 33 | 34 | ```typescript 35 | import { createPrimServer } from "@doseofted/prim-rpc" 36 | import { createMethodHandler } from "@doseofted/prim-rpc-plugins/fastify" 37 | import Fastify from "fastify" 38 | import * as module from "./functions" 39 | 40 | const fastify = Fastify() 41 | 42 | const methodHandler = createMethodHandler({ fastify }) 43 | createPrimServer({ module, methodHandler }) 44 | 45 | fastify.listen({ port: 3000 }) 46 | ``` 47 | 48 | 49 | 50 | This configuration does not yet support Files and Blobs but we can do so by adding new Fastify plugins. First, install 51 | both `@fastify/multipart{:txt}` and `form-data{:txt}` using your chosen package manager. Then you can configure it like 52 | so: 53 | 54 | 55 | 56 | ```typescript {4-5} /multipartPlugin, formDataHandler/ 57 | import { createPrimServer } from "@doseofted/prim-rpc" 58 | import { createMethodHandler } from "@doseofted/prim-rpc-plugins/fastify" 59 | import Fastify from "fastify" 60 | import multipartPlugin from "@fastify/multipart" 61 | import formDataHandler from "form-data" 62 | 63 | const fastify = Fastify() 64 | 65 | const methodHandler = createMethodHandler({ fastify, multipartPlugin, formDataHandler }) 66 | createPrimServer({ module, methodHandler }) 67 | 68 | fastify.listen({ port: 3000 }) 69 | ``` 70 | 71 | 72 | 73 | Now we can test this out with a simple call from the command line: 74 | 75 | 76 | 77 | ```zsh 78 | curl "http://localhost:3000/prim" 79 | ``` 80 | 81 | 82 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/server/hono.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Hono 3 | icon: ph:globe-bold 4 | type: method-handler 5 | transport: http 6 | features: [] 7 | status: available 8 | links: 9 | - name: Hono 10 | href: https://github.com/honojs/hono#readme 11 | --- 12 | 13 | import CodeFile from "@/components/Code/CodeFile.astro" 14 | 15 | Prim+RPC supports Hono and is very easy to set up. First, let's set up our functions to be used on the server: 16 | 17 | 18 | 19 | ```typescript 20 | export function hello() { 21 | return "Hi from Prim+RPC!" 22 | } 23 | hello.rpc = "idempotent" 24 | 25 | export default hello 26 | ``` 27 | 28 | 29 | 30 | We can expose these functions to the client by setting up Hono and Prim+RPC: 31 | 32 | 33 | 34 | ```typescript 35 | import { createPrimServer } from "@doseofted/prim-rpc" 36 | import { createMethodHandler } from "@doseofted/prim-rpc-plugins/hono" 37 | import { Hono } from "hono" 38 | import * as module from "./functions" 39 | 40 | const app = new Hono() 41 | 42 | const methodHandler = createMethodHandler({ app }) 43 | createPrimServer({ module, methodHandler }) 44 | 45 | export default app 46 | ``` 47 | 48 | 49 | 50 | This example shows how Hono may be used from a serverless environment but you may reference Hono's documentation to 51 | learn how to set it up in frameworks like Node and others. 52 | 53 | We can test that this example is working by making a call over the command line (note that your server address will need 54 | to be changed): 55 | 56 | 57 | 58 | ```zsh 59 | curl "http://localhost:3000/prim" 60 | ``` 61 | 62 | 63 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/server/socket-io.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Socket.io 3 | icon: simple-icons:socketdotio 4 | type: callback-handler 5 | transport: socket-io 6 | features: [] 7 | status: planned 8 | links: 9 | - name: Socket.io 10 | href: https://github.com/socketio/socket.io#readme 11 | --- 12 | 13 | **Status**: {frontmatter.status} 14 | -------------------------------------------------------------------------------- /apps/documentation/src/content/plugins/server/testing.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Testing 3 | icon: ph:test-tube-fill 4 | type: method-handler 5 | transport: event 6 | features: [] 7 | status: available 8 | links: 9 | - name: Vitest 10 | href: https://github.com/vitest-dev/vitest#readme 11 | - name: Jest 12 | href: https://github.com/jestjs/jest#readme 13 | --- 14 | 15 | import CodeFile from "@/components/Code/CodeFile.astro" 16 | 17 | Prim+RPC includes testing utilities to test itself over a generic event handler within the same file but while 18 | undergoing all of the typical events and transformations involved in sending RPC between two separated environments. 19 | This is useful for testing environments to ensure that functions can be used as RPC without the need to polyfill or set 20 | up real servers. 21 | 22 | First, we'll set up some module that we want to use with Prim+RPC: 23 | 24 | 25 | 26 | ```typescript 27 | export function hello() { 28 | return "Hi from Prim+RPC!" 29 | } 30 | hello.rpc = true 31 | 32 | export default hello 33 | ``` 34 | 35 | 36 | 37 | And now we can set up our tests (we'll use Vitest as an example): 38 | 39 | 40 | 41 | ```typescript 42 | import { createPrimServer, createPrimClient, testing } from "@doseofted/prim-rpc" 43 | import * as module from "./index" 44 | import { test, expect } from "vitest" 45 | 46 | const plugins = testing.createPrimTestingPlugins() 47 | 48 | const { methodHandler, callbackHandler } = plugins 49 | const server = createPrimServer({ module, methodHandler, callbackHandler }) 50 | 51 | const { methodPlugin, callbackPlugin } = plugins 52 | const client = createPrimClient({ methodPlugin, callbackPlugin }) 53 | 54 | test("RPC result equals local result", () => { 55 | const greeting = client.hello() 56 | const expected = module.hello() 57 | expect(greeting).resolves.toEqual(expected) 58 | }) 59 | ``` 60 | 61 | 62 | 63 | That's all there is to it! 64 | -------------------------------------------------------------------------------- /apps/documentation/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /apps/documentation/src/layouts/Default.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import "./Default.css" 3 | import "@fontsource-variable/plus-jakarta-sans" 4 | import "@fontsource-variable/montserrat" 5 | import "@fontsource-variable/fira-code" 6 | import { SEO } from "astro-seo" 7 | import Columns from "@/components/Columns.astro" 8 | import Navigation from "@/components/Navigation.astro" 9 | import Container from "@/components/Container.astro" 10 | import { ViewTransitions } from "astro:transitions" 11 | import Lights from "@/components/Lights.astro" 12 | import Footer from "@/components/Footer.astro" 13 | 14 | interface Props { 15 | brand?: string 16 | title?: string 17 | description?: string 18 | fullscreen?: boolean 19 | className?: string 20 | } 21 | const { brand, title = "", fullscreen, description, className } = Astro.props 22 | 23 | const siteName = "Prim+RPC" 24 | const image = `${Astro.site}/social.png` 25 | --- 26 | 27 | 28 | 29 | 33 | 34 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 69 | 70 | 71 |
    72 | 73 |
    74 | { 75 | !fullscreen ? ( 76 | <> 77 | 78 | 79 | 80 | 81 |
    82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |