├── .npmrc ├── docs ├── README.md ├── public │ └── make-scrollable-code-focusable.js ├── src │ ├── content │ │ ├── docs │ │ │ ├── install.mdx │ │ │ ├── sponsors.mdx │ │ │ ├── contributors.mdx │ │ │ ├── response.mdx │ │ │ ├── pipe.mdx │ │ │ ├── introduction.mdx │ │ │ ├── solid │ │ │ │ ├── query-provider.mdx │ │ │ │ ├── reuseable.mdx │ │ │ │ ├── install.mdx │ │ │ │ ├── mutation.mdx │ │ │ │ └── query.mdx │ │ │ ├── prpc-client-error.mdx │ │ │ ├── error.mdx │ │ │ ├── middleware.mdx │ │ │ └── hideRequest.mdx │ │ └── config.ts │ ├── pages │ │ ├── index.astro │ │ └── [...slug].astro │ ├── env.d.ts │ ├── components │ │ ├── Footer │ │ │ ├── Footer.astro │ │ │ └── AvatarList.astro │ │ ├── Header │ │ │ ├── SkipToContent.astro │ │ │ ├── LanguageSelect.css │ │ │ ├── SidebarToggle.tsx │ │ │ ├── AstroLogo.astro │ │ │ ├── LanguageSelect.tsx │ │ │ ├── Search.css │ │ │ ├── Search.tsx │ │ │ └── Header.astro │ │ ├── RightSidebar │ │ │ ├── RightSidebar.astro │ │ │ ├── ThemeToggleButton.css │ │ │ ├── MoreMenu.astro │ │ │ ├── ThemeToggleButton.tsx │ │ │ └── TableOfContents.tsx │ │ ├── PageContent │ │ │ └── PageContent.astro │ │ ├── HeadCommon.astro │ │ ├── HeadSEO.astro │ │ └── LeftSidebar │ │ │ └── LeftSidebar.astro │ ├── languages.ts │ ├── consts.ts │ ├── layouts │ │ └── MainLayout.astro │ └── styles │ │ └── theme.css ├── tsconfig.json ├── .gitignore ├── astro.config.mjs └── package.json ├── .github ├── FUNDING.yml ├── pr-labeler.yml ├── changeset-version.js └── workflows │ └── release.yml ├── packages ├── vite │ ├── pridepack.json │ ├── README.md │ ├── vitest.config.ts │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── src │ │ └── index.ts │ ├── package.json │ ├── .gitignore │ ├── test │ │ └── plugin.test.ts │ └── CHANGELOG.md ├── compiler │ ├── pridepack.json │ ├── README.md │ ├── .eslintrc.json │ ├── src │ │ └── index.ts │ ├── tsconfig.json │ ├── package.json │ ├── .gitignore │ └── CHANGELOG.md ├── unplugin │ ├── pridepack.json │ ├── README.md │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── src │ │ └── index.ts │ ├── package.json │ ├── .gitignore │ └── CHANGELOG.md ├── core │ ├── README.md │ ├── .gitignore │ ├── src │ │ ├── index.ts │ │ ├── error.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── .eslintrc.json │ ├── tsup.config.js │ ├── tsconfig.json │ ├── package.json │ └── CHANGELOG.md ├── create │ ├── templates │ │ └── SolidStart │ │ │ ├── src │ │ │ ├── root.css │ │ │ ├── entry-client.tsx │ │ │ ├── entry-server.tsx │ │ │ ├── server │ │ │ │ └── queries.ts │ │ │ ├── root.tsx │ │ │ └── routes │ │ │ │ └── index.tsx │ │ │ ├── public │ │ │ └── favicon.ico │ │ │ ├── postcss.config.cjs │ │ │ ├── tailwind.config.cjs │ │ │ ├── vite.config.ts │ │ │ ├── _gitignore │ │ │ ├── .eslintrc.json │ │ │ ├── tsconfig.json │ │ │ ├── README.MD │ │ │ └── package.json │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── src │ │ ├── types.ts │ │ ├── index.ts │ │ └── utils │ │ │ ├── files.ts │ │ │ ├── helpers.ts │ │ │ └── project.ts │ ├── package.json │ └── CHANGELOG.md └── solid │ ├── .gitignore │ ├── .eslintrc.json │ ├── src │ ├── QueryProvider.tsx │ ├── index.tsx │ ├── reuseable.ts │ ├── query.ts │ └── mutation.ts │ ├── tsconfig.json │ ├── README.md │ └── package.json ├── pnpm-workspace.yaml ├── examples ├── solidstart │ ├── src │ │ ├── root.css │ │ ├── entry-client.tsx │ │ ├── routes │ │ │ ├── reached-10.tsx │ │ │ ├── index.tsx │ │ │ ├── query.tsx │ │ │ ├── mutation.tsx │ │ │ └── query-same.tsx │ │ ├── entry-server.tsx │ │ ├── server │ │ │ ├── middleware.ts │ │ │ ├── mutations.ts │ │ │ └── queries.ts │ │ └── root.tsx │ ├── public │ │ └── favicon.ico │ ├── postcss.config.cjs │ ├── tailwind.config.cjs │ ├── vite.config.ts │ ├── .gitignore │ ├── .eslintrc.json │ ├── tsconfig.json │ ├── README.MD │ └── package.json └── README.md ├── .husky └── pre-commit.sh ├── .prettierrc ├── tsconfig.json ├── .eslintignore ├── tsconfig.base.json ├── tsup.config.js ├── .changeset ├── config.json └── README.md ├── .gitignore ├── turbo.json ├── .eslintrc.cjs ├── README.MD └── package.json /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers=true -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # pRPC Docs 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [orjdev] 2 | -------------------------------------------------------------------------------- /packages/vite/pridepack.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": "es2017" 3 | } -------------------------------------------------------------------------------- /packages/compiler/pridepack.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": "es2017" 3 | } -------------------------------------------------------------------------------- /packages/unplugin/pridepack.json: -------------------------------------------------------------------------------- 1 | { 2 | "target": "es2017" 3 | } -------------------------------------------------------------------------------- /.github/pr-labeler.yml: -------------------------------------------------------------------------------- 1 | '🔒 core': 2 | - any: ['packages/core/**'] 3 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # @prpc/core 2 | 3 | Core package for @prpc. 4 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "docs" 3 | - "packages/*" 4 | - "examples/*" -------------------------------------------------------------------------------- /packages/core/.gitignore: -------------------------------------------------------------------------------- 1 | **/*.d.ts 2 | **/*.js 3 | !tsup.config.js 4 | !scripts/**/*.js 5 | -------------------------------------------------------------------------------- /packages/vite/README.md: -------------------------------------------------------------------------------- 1 | # @prpc/vite 2 | 3 | Vite plugin for [pRPC](https://prpc.vercel.app) 4 | -------------------------------------------------------------------------------- /examples/solidstart/src/root.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /packages/compiler/README.md: -------------------------------------------------------------------------------- 1 | # @prpc/vite 2 | 3 | Vite plugin for [pRPC](https://prpc.vercel.app) 4 | -------------------------------------------------------------------------------- /packages/unplugin/README.md: -------------------------------------------------------------------------------- 1 | # @prpc/vite 2 | 3 | Vite plugin for [pRPC](https://prpc.vercel.app) 4 | -------------------------------------------------------------------------------- /.husky/pre-commit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | pnpm lint-staged 5 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | export * from './utils' 3 | export * from './error' 4 | -------------------------------------------------------------------------------- /examples/solidstart/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrJDev/prpc/HEAD/examples/solidstart/public/favicon.ico -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/src/root.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /packages/vite/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | 3 | export default defineConfig({ 4 | test: {}, 5 | }) 6 | -------------------------------------------------------------------------------- /examples/solidstart/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; -------------------------------------------------------------------------------- /examples/solidstart/src/entry-client.tsx: -------------------------------------------------------------------------------- 1 | import { mount, StartClient } from "solid-start/entry-client"; 2 | 3 | mount(() => , document); 4 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OrJDev/prpc/HEAD/packages/create/templates/SolidStart/public/favicon.ico -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/prettierrc", 3 | "semi": false, 4 | "singleQuote": true, 5 | "jsxSingleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /docs/public/make-scrollable-code-focusable.js: -------------------------------------------------------------------------------- 1 | Array.from(document.getElementsByTagName('pre')).forEach((element) => { 2 | element.setAttribute('tabindex', '0'); 3 | }); 4 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/src/entry-client.tsx: -------------------------------------------------------------------------------- 1 | import { mount, StartClient } from "solid-start/entry-client"; 2 | 3 | mount(() => , document); 4 | -------------------------------------------------------------------------------- /docs/src/content/docs/install.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Install' 3 | description: 'Install pRPC' 4 | --- 5 | 6 | **Install pRPC** 7 | 8 | ## SolidStart 9 | 10 | [Read More Here Regarding SolidStart](/solid/install) 11 | -------------------------------------------------------------------------------- /examples/solidstart/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{js,ts,jsx,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strictest", 3 | "compilerOptions": { 4 | "jsx": "preserve", 5 | "skipLibCheck": true, 6 | "strictNullChecks": true, 7 | "jsxImportSource": "solid-js" 8 | } 9 | } -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | ### Examples 2 | 3 | Examples app for testing prpc in this monorepo 4 | 5 | If you want to see all projects build using prpc, check [this out](https://github.com/OrJDev/prpc/tree/main/packages/create/templates) 6 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{js,ts,jsx,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /docs/src/pages/index.astro: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /examples/solidstart/src/routes/reached-10.tsx: -------------------------------------------------------------------------------- 1 | import type { VoidComponent } from 'solid-js' 2 | 3 | const Reached10: VoidComponent = () => { 4 | return

Reached 10

5 | } 6 | 7 | export default Reached10 8 | -------------------------------------------------------------------------------- /examples/solidstart/src/entry-server.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | StartServer, 3 | createHandler, 4 | renderAsync, 5 | } from "solid-start/entry-server"; 6 | 7 | export default createHandler( 8 | renderAsync((event) => ) 9 | ); 10 | -------------------------------------------------------------------------------- /docs/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | interface ImportMetaEnv { 5 | readonly GITHUB_TOKEN: string | undefined; 6 | } 7 | 8 | interface ImportMeta { 9 | readonly env: ImportMetaEnv; 10 | } 11 | -------------------------------------------------------------------------------- /examples/solidstart/vite.config.ts: -------------------------------------------------------------------------------- 1 | import solid from 'solid-start/vite' 2 | import { defineConfig } from 'vite' 3 | import prpc from '@prpc/vite' 4 | 5 | export default defineConfig(() => { 6 | return { 7 | plugins: [prpc(), solid({ ssr: true })], 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/src/entry-server.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | StartServer, 3 | createHandler, 4 | renderAsync, 5 | } from "solid-start/entry-server"; 6 | 7 | export default createHandler( 8 | renderAsync((event) => ) 9 | ); 10 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/vite.config.ts: -------------------------------------------------------------------------------- 1 | import solid from "solid-start/vite"; 2 | import { defineConfig } from "vite"; 3 | import prpc from "@prpc/vite"; 4 | 5 | export default defineConfig(() => { 6 | return { 7 | plugins: [prpc(), solid({ ssr: true })], 8 | }; 9 | }); 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "noErrorTruncation": true, 6 | "jsx": "preserve", 7 | "jsxImportSource": "solid-js" 8 | }, 9 | "exclude": ["node_modules", "examples/dev-solidstart", "dist"] 10 | } 11 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/dist 2 | **/.turbo 3 | 4 | # dependencies 5 | **/node_modules 6 | 7 | # IDEs and editors 8 | **/.idea 9 | **/.project 10 | **/.classpath 11 | **/*.launch 12 | **/.settings/ 13 | 14 | # Temp 15 | gitignore 16 | 17 | # System Files 18 | **/.DS_Store 19 | **/Thumbs.db 20 | 21 | .env 22 | .eslintrc.cjs -------------------------------------------------------------------------------- /packages/solid/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .solid 3 | .output 4 | .vercel 5 | .netlify 6 | netlify 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | *.launch 16 | .settings/ 17 | 18 | # Temp 19 | gitignore 20 | 21 | # System Files 22 | .DS_Store 23 | Thumbs.db 24 | 25 | .env -------------------------------------------------------------------------------- /docs/.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 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/src/server/queries.ts: -------------------------------------------------------------------------------- 1 | import { query$ } from '@prpc/solid' 2 | import { z } from 'zod' 3 | 4 | export const helloQuery = query$({ 5 | schema: z.object({ name: z.string() }), 6 | key: 'hello', 7 | queryFn: ({ payload }) => { 8 | return `server says hello: ${payload.name}` 9 | }, 10 | }) 11 | -------------------------------------------------------------------------------- /examples/solidstart/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .solid 3 | .output 4 | .vercel 5 | .netlify 6 | netlify 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | *.launch 16 | .settings/ 17 | 18 | # Temp 19 | gitignore 20 | 21 | # System Files 22 | .DS_Store 23 | Thumbs.db 24 | 25 | .env 26 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "allowSyntheticDefaultImports": true, 5 | "target": "esnext", 6 | "newLine": "LF", 7 | "moduleResolution": "Node", 8 | "strict": true, 9 | "module": "esnext", 10 | "types": ["node"] 11 | }, 12 | "exclude": ["node_modules", "dist"] 13 | } 14 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/_gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .solid 3 | .output 4 | .vercel 5 | .netlify 6 | netlify 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | *.launch 16 | .settings/ 17 | 18 | # Temp 19 | gitignore 20 | 21 | # System Files 22 | .DS_Store 23 | Thumbs.db 24 | 25 | .env 26 | -------------------------------------------------------------------------------- /tsup.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup-preset-solid' 2 | 3 | export default defineConfig( 4 | [ 5 | { 6 | entry: 'src/index.tsx', 7 | devEntry: true, 8 | serverEntry: true, 9 | }, 10 | ], 11 | { 12 | printInstructions: false, 13 | writePackageJson: true, 14 | dropConsole: false, 15 | cjs: true, 16 | } 17 | ) 18 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.2.0/schema.json", 3 | "changelog": ["@changesets/changelog-github", { "repo": "OrJDev/prpc" }], 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": ["dev-solidstart", "docs"] 11 | } 12 | -------------------------------------------------------------------------------- /docs/src/components/Footer/Footer.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import AvatarList from './AvatarList.astro'; 3 | type Props = { 4 | path: string; 5 | }; 6 | const { path } = Astro.props; 7 | --- 8 | 9 |
10 | 11 |
12 | 13 | 20 | -------------------------------------------------------------------------------- /packages/compiler/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | }, 6 | "plugins": ["@typescript-eslint"], 7 | "extends": [ 8 | "plugin:solid/typescript", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/consistent-type-imports": "warn" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/core/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | }, 6 | "plugins": ["@typescript-eslint"], 7 | "extends": [ 8 | "plugin:solid/typescript", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/consistent-type-imports": "warn" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/core/tsup.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig((options) => ({ 4 | entry: ['src/index.ts'], 5 | target: 'esnext', 6 | sourcemap: options.watch ? 'inline' : false, 7 | clean: true, 8 | minify: false, 9 | keepNames: false, 10 | tsconfig: './tsconfig.json', 11 | format: ['esm'], 12 | bundle: true, 13 | dts: true, 14 | })) 15 | -------------------------------------------------------------------------------- /packages/create/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | }, 6 | "plugins": ["@typescript-eslint"], 7 | "extends": [ 8 | "plugin:solid/typescript", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/consistent-type-imports": "warn" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/solid/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | }, 6 | "plugins": ["@typescript-eslint"], 7 | "extends": [ 8 | "plugin:solid/typescript", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/consistent-type-imports": "warn" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/unplugin/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | }, 6 | "plugins": ["@typescript-eslint"], 7 | "extends": [ 8 | "plugin:solid/typescript", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/consistent-type-imports": "warn" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/vite/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | }, 6 | "plugins": ["@typescript-eslint"], 7 | "extends": [ 8 | "plugin:solid/typescript", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/consistent-type-imports": "warn" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/solidstart/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | }, 6 | "plugins": ["@typescript-eslint"], 7 | "extends": [ 8 | "plugin:solid/typescript", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/consistent-type-imports": "warn" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "project": "./tsconfig.json" 5 | }, 6 | "plugins": ["@typescript-eslint"], 7 | "extends": [ 8 | "plugin:solid/typescript", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/consistent-type-imports": "warn" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/solidstart/src/routes/index.tsx: -------------------------------------------------------------------------------- 1 | import { type VoidComponent } from 'solid-js' 2 | import { A } from 'solid-start' 3 | 4 | const Home: VoidComponent = () => { 5 | return ( 6 |
7 | Mutation 8 | CSR Query 9 | Query 10 |
11 | ) 12 | } 13 | 14 | export default Home 15 | -------------------------------------------------------------------------------- /packages/create/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "baseUrl": "./", 6 | "paths": { 7 | "~*": ["./src/*"] 8 | }, 9 | "noEmit": false, 10 | "esModuleInterop": true, 11 | "strict": true, 12 | "noUnusedLocals": true, 13 | "outDir": "dist" 14 | }, 15 | "include": ["./src/"], 16 | "exclude": ["node_modules", "template"] 17 | } 18 | -------------------------------------------------------------------------------- /examples/solidstart/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "esModuleInterop": true, 5 | "strict": true, 6 | "target": "ESNext", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "jsxImportSource": "solid-js", 10 | "jsx": "preserve", 11 | "types": ["solid-start/env"], 12 | "baseUrl": "./", 13 | "paths": { 14 | "~/*": ["./src/*"] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "esModuleInterop": true, 5 | "strict": true, 6 | "target": "ESNext", 7 | "module": "ESNext", 8 | "moduleResolution": "node", 9 | "jsxImportSource": "solid-js", 10 | "jsx": "preserve", 11 | "types": ["solid-start/env"], 12 | "baseUrl": "./", 13 | "paths": { 14 | "~/*": ["./src/*"] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/solid/src/QueryProvider.tsx: -------------------------------------------------------------------------------- 1 | import { QueryClient, QueryClientProvider } from '@tanstack/solid-query' 2 | import type { ParentComponent } from 'solid-js' 3 | 4 | export const QueryProvider: ParentComponent<{ 5 | queryClient?: QueryClient 6 | }> = (props) => { 7 | const queryClient = () => props.queryClient ?? new QueryClient() 8 | return ( 9 | 10 | {props.children} 11 | 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /docs/src/content/docs/sponsors.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Sponsors' 3 | description: 'Sponsors of pRPC' 4 | --- 5 | 6 | **Sponsors of pRPC** 7 | 8 | Sponsors help us commit more time and resources into maintaining pRPC. pRPC is a new project and does not have any sponsors yet. Anyone who sponsors will be displayed here. If you are interested in sponsoring, you can learn more about it [here](https://github.com/OrJDev/prpc) 9 | 10 | ## Sponsor Individuals 11 | 12 | - [OrJDev](https://github.com/sponsors/OrJDev) 13 | -------------------------------------------------------------------------------- /docs/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "astro/config"; 2 | 3 | // https://astro.build/config 4 | import solidJs from "@astrojs/solid-js"; 5 | 6 | // https://astro.build/config 7 | import vercel from "@astrojs/vercel/static"; 8 | 9 | // https://astro.build/config 10 | import mdx from "@astrojs/mdx"; 11 | 12 | // https://astro.build/config 13 | export default defineConfig({ 14 | integrations: [solidJs(), mdx()], 15 | site: `https://astro.build`, 16 | output: "static", 17 | adapter: vercel() 18 | }); -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /packages/compiler/src/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import type babel from '@babel/core' 3 | import { type PRPCAdapter } from './babel' 4 | import { type FilterPattern } from '@rollup/pluginutils' 5 | export { compilepRRPC } from './babel' 6 | 7 | export interface PRPCPluginOptions { 8 | babel?: babel.TransformOptions 9 | adapter?: PRPCAdapter 10 | filter?: { 11 | include?: FilterPattern 12 | exclude?: FilterPattern 13 | } 14 | log?: boolean 15 | } 16 | 17 | export * from './babel' 18 | -------------------------------------------------------------------------------- /docs/src/languages.ts: -------------------------------------------------------------------------------- 1 | import { KNOWN_LANGUAGES, KNOWN_LANGUAGE_CODES } from './consts' 2 | export { KNOWN_LANGUAGES, KNOWN_LANGUAGE_CODES } 3 | 4 | export const langPathRegex = /\/([a-z]{2}-?[A-Z]{0,2})\// 5 | 6 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 7 | export function getLanguageFromURL(_pathname: string) { 8 | // const langCodeMatch = pathname.match(langPathRegex); 9 | // const langCode = langCodeMatch ? langCodeMatch[1] : 'en'; 10 | // return langCode as (typeof KNOWN_LANGUAGE_CODES)[number]; 11 | return 'en' 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # misc 12 | .DS_Store 13 | *.pem 14 | 15 | # debug 16 | npm-debug.log* 17 | yarn-debug.log* 18 | yarn-error.log* 19 | .pnpm-debug.log* 20 | 21 | 22 | # local env files 23 | .env.local 24 | .env.development.local 25 | .env.test.local 26 | .env.production.local 27 | *env 28 | 29 | 30 | # builds 31 | dist/ 32 | */.vercel/* 33 | 34 | # vscode 35 | */.vscode/* 36 | .turbo 37 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules"], 3 | "include": ["src"], 4 | "compilerOptions": { 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "importHelpers": true, 8 | "declaration": true, 9 | "sourceMap": true, 10 | "rootDir": "./src", 11 | "strict": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "moduleResolution": "node", 17 | "esModuleInterop": true, 18 | "target": "ES2017" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/vite/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules"], 3 | "include": ["src"], 4 | "compilerOptions": { 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "importHelpers": true, 8 | "declaration": true, 9 | "sourceMap": true, 10 | "rootDir": "./src", 11 | "strict": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "moduleResolution": "node", 17 | "jsx": "react", 18 | "esModuleInterop": true, 19 | "target": "ES2017" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/compiler/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules"], 3 | "include": ["src"], 4 | "compilerOptions": { 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "importHelpers": true, 8 | "declaration": true, 9 | "sourceMap": true, 10 | "rootDir": "./src", 11 | "strict": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "moduleResolution": "node", 17 | "jsx": "react", 18 | "esModuleInterop": true, 19 | "target": "ES2017" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/unplugin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules"], 3 | "include": ["src"], 4 | "compilerOptions": { 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "importHelpers": true, 8 | "declaration": true, 9 | "sourceMap": true, 10 | "rootDir": "./src", 11 | "strict": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "moduleResolution": "node", 17 | "jsx": "react", 18 | "esModuleInterop": true, 19 | "target": "ES2017" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /docs/src/content/docs/contributors.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Contributors' 3 | description: 'Contributors to pRPC' 4 | --- 5 | 6 | **Contributors/maintainers of pRPC** 7 | 8 | ## Core 9 | 10 | Core contributors to the project 11 | 12 | - [OrJDev](https://github.com/OrJDev) - Lead Maintainer 13 | - [Tanner-Scadden](https://github.com/Tanner-Scadden) - Previous Maintainer (Core, Docs) 14 | 15 | ## Other Contributors 16 | 17 | pRPC couldn't keep evolving without other advisors and contributors. 18 | 19 | Thank you to [all the other contributors](https://github.com/OrJDev/prpc/graphs/contributors) that have helped us 20 | -------------------------------------------------------------------------------- /examples/solidstart/README.MD: -------------------------------------------------------------------------------- 1 | This project was created using [Create JD App](https://github.com/OrJDev/create-jd-app) 2 | 3 | ## Start Dev Server 4 | 5 | ```bash 6 | pnpm dev 7 | ``` 8 | 9 | This will start a dev server on port `3000` and will watch for changes. 10 | 11 | ## Testing Production Build 12 | 13 | ### Build 14 | 15 | ```bash 16 | pnpm build 17 | ``` 18 | 19 | ### Start 20 | 21 | ```bash 22 | pnpm start 23 | ``` 24 | 25 | This will start a production server on port `3000`. 26 | 27 | ### Enviroment Variables 28 | 29 | 30 | 31 | [Sponsor Create JD App](https://github.com/sponsors/OrJDev) 32 | -------------------------------------------------------------------------------- /docs/src/pages/[...slug].astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { CollectionEntry, getCollection } from "astro:content"; 3 | import MainLayout from "../layouts/MainLayout.astro"; 4 | 5 | export async function getStaticPaths() { 6 | const docs = await getCollection("docs"); 7 | return docs.map((entry) => ({ 8 | params: { 9 | slug: entry.slug, 10 | }, 11 | props: entry, 12 | })); 13 | } 14 | type Props = CollectionEntry<"docs">; 15 | 16 | const post = Astro.props; 17 | const { Content, headings } = await post.render(); 18 | --- 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/README.MD: -------------------------------------------------------------------------------- 1 | This project was created using [Create JD App](https://github.com/OrJDev/create-jd-app) 2 | 3 | ## Start Dev Server 4 | 5 | ```bash 6 | pnpm dev 7 | ``` 8 | 9 | This will start a dev server on port `3000` and will watch for changes. 10 | 11 | ## Testing Production Build 12 | 13 | ### Build 14 | 15 | ```bash 16 | pnpm build 17 | ``` 18 | 19 | ### Start 20 | 21 | ```bash 22 | pnpm start 23 | ``` 24 | 25 | This will start a production server on port `3000`. 26 | 27 | ### Enviroment Variables 28 | 29 | 30 | 31 | [Sponsor Create JD App](https://github.com/sponsors/OrJDev) 32 | -------------------------------------------------------------------------------- /docs/src/content/config.ts: -------------------------------------------------------------------------------- 1 | import { defineCollection, z } from 'astro:content'; 2 | import { SITE } from '../consts'; 3 | 4 | const docs = defineCollection({ 5 | schema: z.object({ 6 | title: z.string().default(SITE.title), 7 | description: z.string().default(SITE.description), 8 | lang: z.literal('en-us').default(SITE.defaultLanguage), 9 | dir: z.union([z.literal('ltr'), z.literal('rtl')]).default('ltr'), 10 | image: z 11 | .object({ 12 | src: z.string(), 13 | alt: z.string(), 14 | }) 15 | .optional(), 16 | ogLocale: z.string().optional(), 17 | }), 18 | }); 19 | 20 | export const collections = { docs }; 21 | -------------------------------------------------------------------------------- /packages/solid/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules"], 3 | "include": ["src"], 4 | "compilerOptions": { 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "importHelpers": true, 8 | "declaration": true, 9 | "sourceMap": true, 10 | "rootDir": "./src", 11 | "strict": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "noImplicitReturns": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "moduleResolution": "node", 17 | "jsx": "preserve", 18 | "jsxImportSource": "solid-js", 19 | "esModuleInterop": true, 20 | "target": "ES2017" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "pipeline": { 4 | "build": { 5 | "dependsOn": ["^build"], 6 | "outputs": ["dist/**", "build/**"] 7 | }, 8 | "dev": { 9 | "cache": false 10 | }, 11 | "clean": { 12 | "cache": false 13 | }, 14 | "ts:check": { 15 | "cache": false 16 | }, 17 | "lint": { 18 | "cache": false 19 | }, 20 | "test": { 21 | "cache": true, 22 | "outputs": [] 23 | }, 24 | "test:coverage": { 25 | "cache": false, 26 | "outputs": [] 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /docs/src/components/Header/SkipToContent.astro: -------------------------------------------------------------------------------- 1 | --- 2 | type Props = {}; 3 | --- 4 | 5 | 6 | 7 | 27 | -------------------------------------------------------------------------------- /.github/changeset-version.js: -------------------------------------------------------------------------------- 1 | // ORIGINALLY FROM CLOUDFLARE WRANGLER: 2 | // https://github.com/cloudflare/wrangler2/blob/main/.github/changeset-version.js 3 | 4 | import { exec } from 'child_process' 5 | // This script is used by the `release.yml` workflow to update the version of the packages being released. 6 | // The standard step is only to run `changeset version` but this does not update the package-lock.json file. 7 | // So we also run `npm install`, which does this update. 8 | // This is a workaround until this is handled automatically by `changeset version`. 9 | // See https://github.com/changesets/changesets/issues/421. 10 | exec('pnpm changeset version') 11 | exec('pnpm i --lockfile-only') 12 | -------------------------------------------------------------------------------- /packages/create/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { getUserPackageManager } from '~utils/helpers' 2 | 3 | export type IAppCtx = { 4 | userDir: string 5 | appName: string 6 | templateDir: string 7 | pkgManager: ReturnType 8 | template: ITemplate 9 | } 10 | 11 | export type INullAble = T | null 12 | 13 | export type IPromiseOrType = Promise | T 14 | 15 | export type IFile = { 16 | to: string 17 | content?: string 18 | type?: 'copy' | 'exec' | 'delete' | 'write' | 'append' 19 | path?: string 20 | sep?: boolean 21 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 22 | pass?: any 23 | } 24 | 25 | export type ITemplate = 'SolidStart' | 'React Bling' 26 | -------------------------------------------------------------------------------- /packages/create/src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import * as project from './utils/project' 4 | import { formatError } from './utils/helpers' 5 | import chalk from 'chalk' 6 | 7 | async function main() { 8 | const args = process.argv 9 | .slice(2) 10 | .filter((arg) => arg.startsWith('--')) 11 | .map((arg) => arg.slice(2).toLowerCase()) 12 | const ctx = await project.initApp(args) 13 | await project.copyTemplate(ctx) 14 | await project.modifyProject(ctx) 15 | await project.installDeps(ctx) 16 | project.finished(ctx) 17 | } 18 | 19 | main().catch((e) => { 20 | console.log( 21 | `\n ${chalk.blue('Something went wrong:')} ${chalk.red(formatError(e))}\n` 22 | ) 23 | process.exit(1) 24 | }) 25 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es2021: true, 5 | node: true, 6 | }, 7 | extends: [ 8 | 'eslint:recommended', 9 | 'plugin:@typescript-eslint/recommended', 10 | 'plugin:promise/recommended', 11 | 'prettier', 12 | ], 13 | parser: '@typescript-eslint/parser', 14 | plugins: ['@typescript-eslint'], 15 | root: true, 16 | 17 | parserOptions: { 18 | ecmaVersion: 'latest', 19 | sourceType: 'module', 20 | tsconfigRootDir: __dirname, 21 | project: [ 22 | './packages/*/tsconfig.json', 23 | './examples/*/tsconfig.json', 24 | './tsconfig.json', 25 | ], 26 | }, 27 | rules: { 28 | '@typescript-eslint/consistent-type-imports': 'warn', 29 | }, 30 | } 31 | -------------------------------------------------------------------------------- /packages/solid/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { isServer } from 'solid-js/web' 2 | import type { PageEvent } from 'solid-start' 3 | 4 | export * from './QueryProvider' 5 | export * from './mutation' 6 | export * from './query' 7 | export * from '@prpc/core' 8 | export * from './reuseable' 9 | 10 | export const genHandleResponse = (event: PageEvent) => { 11 | return (response: Response) => { 12 | if (isServer && event) { 13 | if (event.responseHeaders) { 14 | response.headers.forEach((value, key) => { 15 | if (key === 'content-type') return 16 | event.responseHeaders.set(key, value) 17 | }) 18 | } 19 | if (event.setStatusCode && response.status !== undefined) { 20 | event.setStatusCode(response.status) 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "description": "Docs for prpc", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "dev": "astro dev", 8 | "start": "astro dev", 9 | "build": "astro build", 10 | "preview": "astro preview", 11 | "astro": "astro", 12 | "clean": "rm -rf ./node_modules .turbo .astro .vercel", 13 | "ts:check": "tsc --noEmit --skipLibCheck" 14 | }, 15 | "dependencies": { 16 | "@algolia/client-search": "^4.13.1", 17 | "@astrojs/mdx": "^0.17.2", 18 | "@astrojs/solid-js": "^2.0.2", 19 | "@astrojs/vercel": "^3.1.3", 20 | "@docsearch/css": "^3.1.0", 21 | "@docsearch/js": "^3.1.0", 22 | "@types/node": "^18.0.0", 23 | "astro": "^2.0.15", 24 | "solid-js": "^1.4.3" 25 | }, 26 | "devDependencies": { 27 | "html-escaper": "^3.0.3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/src/components/RightSidebar/RightSidebar.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import type { MarkdownHeading } from 'astro'; 3 | import TableOfContents from './TableOfContents'; 4 | import MoreMenu from './MoreMenu.astro'; 5 | 6 | type Props = { 7 | headings: MarkdownHeading[]; 8 | githubEditUrl: string; 9 | }; 10 | 11 | const { headings, githubEditUrl } = Astro.props; 12 | --- 13 | 14 | 20 | 21 | 35 | -------------------------------------------------------------------------------- /packages/core/src/error.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import type { typeToFlattenedError } from 'zod' 3 | 4 | export class PRPCClientError extends Error { 5 | public cause?: typeToFlattenedError | Error | Record 6 | constructor( 7 | message: string, 8 | cause?: typeToFlattenedError | Error | Record 9 | ) { 10 | super(message) 11 | this.name = 'PRPCClientError' 12 | this.cause = cause 13 | } 14 | isZodError(): this is PRPCClientError & { 15 | cause: typeToFlattenedError 16 | } { 17 | return this.cause && typeof this.cause === 'object' 18 | ? 'fieldErrors' in this.cause 19 | : false 20 | } 21 | isError(): this is PRPCClientError & { cause: Error } { 22 | return this.cause ? this.cause instanceof Error : false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/src/components/RightSidebar/ThemeToggleButton.css: -------------------------------------------------------------------------------- 1 | .theme-toggle { 2 | display: inline-flex; 3 | align-items: center; 4 | gap: 0.25em; 5 | padding: 0.33em 0.67em; 6 | border-radius: 99em; 7 | background-color: var(--theme-code-inline-bg); 8 | } 9 | 10 | .theme-toggle > label:focus-within { 11 | outline: 2px solid transparent; 12 | box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white; 13 | } 14 | 15 | .theme-toggle > label { 16 | color: var(--theme-code-inline-text); 17 | position: relative; 18 | display: flex; 19 | align-items: center; 20 | justify-content: center; 21 | opacity: 0.5; 22 | } 23 | 24 | .theme-toggle .checked { 25 | color: var(--theme-accent); 26 | opacity: 1; 27 | } 28 | 29 | input[name='theme-toggle'] { 30 | position: absolute; 31 | opacity: 0; 32 | top: 0; 33 | right: 0; 34 | bottom: 0; 35 | left: 0; 36 | z-index: -1; 37 | } 38 | -------------------------------------------------------------------------------- /examples/solidstart/src/server/middleware.ts: -------------------------------------------------------------------------------- 1 | import { error$, middleware$, pipe$, reuseable$ } from '@prpc/solid' 2 | 3 | const reuseMw = middleware$(() => { 4 | console.log(`reuseMw called on ${typeof window}`) 5 | return { 6 | reuse: 'reuse' as const, 7 | } 8 | }) 9 | 10 | export const myProcedure = reuseable$(reuseMw) 11 | 12 | export const myMiddleware1 = middleware$(({ request$ }) => { 13 | console.log('ua', request$.headers.get('user-agent')) 14 | return { test: 'test' } 15 | }) 16 | 17 | const middleWare2 = pipe$(myMiddleware1, (ctx) => { 18 | if (!ctx.test || ctx.test === 'tes') { 19 | return error$(`Expected test to be "test" but got ${ctx.test}`) 20 | } 21 | return { 22 | test: ctx.test, 23 | o: 1, 24 | } 25 | }) 26 | 27 | export const middleware3 = pipe$(middleWare2, (ctx) => { 28 | return { 29 | ...ctx, 30 | b: 2, 31 | } 32 | }) 33 | -------------------------------------------------------------------------------- /docs/src/content/docs/response.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'response$' 3 | description: 'API for the response$ function' 4 | --- 5 | 6 | **API for the response$ function** 7 | 8 | This function is used to modify the response headers / cookies without affecting the return type of the function. 9 | 10 | ## Usage 11 | 12 | ```ts 13 | import { query$, response$ } from '@prpc/solid' 14 | import { z } from 'zod' 15 | 16 | export const add = query$( 17 | ({ payload, request$ }) => { 18 | const result = payload.a + payload.b 19 | console.log(request$.headers.get('user-agent')) 20 | return response$(result, { 21 | headers: { 22 | 'set-cookie': 'solid-testing=1', 23 | }, 24 | }) 25 | }, 26 | 'add', 27 | z.object({ 28 | a: z.number(), 29 | b: z.number(), 30 | }) 31 | ) 32 | ``` 33 | 34 | The return type of this function is still `number`, but the response headers / cookies are modified. 35 | -------------------------------------------------------------------------------- /packages/unplugin/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createUnplugin } from 'unplugin' 2 | import { createFilter } from '@rollup/pluginutils' 3 | import { compilepRRPC, type PRPCPluginOptions } from '@prpc/compiler' 4 | 5 | const DEFAULT_INCLUDE = 'src/**/*.{jsx,tsx,ts,js,mjs,cjs}' 6 | const DEFAULT_EXCLUDE = 'node_modules/**/*.{jsx,tsx,ts,js,mjs,cjs}' 7 | 8 | const prpcPlugin = createUnplugin((options: PRPCPluginOptions) => { 9 | const filter = createFilter( 10 | options.filter?.include || DEFAULT_INCLUDE, 11 | options.filter?.exclude || DEFAULT_EXCLUDE 12 | ) 13 | 14 | options.adapter ??= 'solid' 15 | 16 | return { 17 | name: 'prpc', 18 | vite: { 19 | enforce: 'pre', 20 | async transform(code, id) { 21 | return await compilepRRPC(code, id, options) 22 | }, 23 | }, 24 | transformInclude(id) { 25 | return filter(id) 26 | }, 27 | async transform(code, id) { 28 | return await compilepRRPC(code, id, options) 29 | }, 30 | } 31 | }) 32 | 33 | export default prpcPlugin 34 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "scripts": { 4 | "dev": "solid-start dev --port 3000", 5 | "start": "solid-start start --port 3000", 6 | "build": "solid-start build", 7 | "lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"" 8 | }, 9 | "type": "module", 10 | "devDependencies": { 11 | "solid-start-node": "^0.2.26", 12 | "typescript": "^4.9.5", 13 | "vite": "^4.1.2", 14 | "@typescript-eslint/eslint-plugin": "^5.52.0", 15 | "@typescript-eslint/parser": "^5.52.0", 16 | "eslint": "^8.34.0", 17 | "eslint-plugin-solid": "^0.9.4", 18 | "@types/node": "^18.14.0", 19 | "tailwindcss": "^3.2.7", 20 | "postcss": "^8.4.21", 21 | "autoprefixer": "^10.4.13" 22 | }, 23 | "dependencies": { 24 | "@solidjs/meta": "^0.28.2", 25 | "solid-js": "^1.7.9", 26 | "solid-start": "^0.2.30", 27 | "@solidjs/router": "^0.8.2", 28 | "undici": "5.20.0", 29 | "zod": "^3.20.6", 30 | "@prpc/solid": "^0.2.35", 31 | "@prpc/vite": "^0.3.21", 32 | "@tanstack/solid-query": "^5.0.0-beta.15" 33 | }, 34 | "engines": { 35 | "node": ">=16" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /examples/solidstart/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dev-solidstart", 3 | "private": true, 4 | "scripts": { 5 | "dev": "solid-start dev --port 3000", 6 | "start": "solid-start start --port 3000", 7 | "build": "solid-start build", 8 | "lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"" 9 | }, 10 | "type": "module", 11 | "devDependencies": { 12 | "@types/node": "^18.14.0", 13 | "@typescript-eslint/eslint-plugin": "^5.52.0", 14 | "@typescript-eslint/parser": "^5.52.0", 15 | "autoprefixer": "^10.4.13", 16 | "eslint": "^8.34.0", 17 | "eslint-plugin-solid": "^0.9.4", 18 | "postcss": "^8.4.21", 19 | "solid-start-node": "^0.2.26", 20 | "tailwindcss": "^3.2.7", 21 | "typescript": "^4.9.5", 22 | "vite": "^4.1.2" 23 | }, 24 | "dependencies": { 25 | "@prpc/solid": "workspace:*", 26 | "@prpc/vite": "workspace:*", 27 | "@solidjs/meta": "^0.28.2", 28 | "@tanstack/solid-query": "^5.0.0-beta.15", 29 | "solid-js": "^1.7.9", 30 | "solid-start": "^0.2.30", 31 | "@solidjs/router": "^0.8.2", 32 | "undici": "5.20.0", 33 | "zod": "^3.20.6" 34 | }, 35 | "engines": { 36 | "node": ">=16" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@prpc/core", 3 | "description": "Package for easily creating server rpc functions in solid-start with goodies baked in", 4 | "version": "0.3.15", 5 | "scripts": { 6 | "build": "tsup --config ./tsup.config.js", 7 | "clean": "rm -rf ./node_modules dist .turbo .solid", 8 | "dev": "rm -rf dist && tsup --config ./tsup.config.js --watch", 9 | "lint": "eslint . --fix --ext .ts,.tsx,.js,.jsx", 10 | "typecheck": "tsc --noEmit" 11 | }, 12 | "type": "module", 13 | "exports": { 14 | ".": { 15 | "types": "./dist/index.d.ts", 16 | "import": "./dist/index.js" 17 | } 18 | }, 19 | "main": "./dist/index.js", 20 | "types": "./dist/index.d.ts", 21 | "files": [ 22 | "dist", 23 | "README.md" 24 | ], 25 | "devDependencies": { 26 | "@types/node": "^18.7.14", 27 | "@typescript-eslint/parser": "^5.44.0", 28 | "typescript": "^4.8.2", 29 | "zod": "^3.20.6" 30 | }, 31 | "peerDependencies": { 32 | "zod": "^3.20.6" 33 | }, 34 | "peerDependenciesMeta": { 35 | "zod": { 36 | "optional": true 37 | } 38 | }, 39 | "engines": { 40 | "node": ">=16" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/create/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-prpc-app", 3 | "version": "0.1.19", 4 | "private": false, 5 | "scripts": { 6 | "build": "rm -rf dist && tsc -p . && tsc-alias -p tsconfig.json", 7 | "test:ts": "ts-node -r tsconfig-paths/register src", 8 | "test:js": "node dist/index.js", 9 | "lint": "eslint . --fix --ext .ts,.tsx,.js,.jsx" 10 | }, 11 | "files": [ 12 | "dist", 13 | "templates" 14 | ], 15 | "main": "dist/index.js", 16 | "bin": { 17 | "create-prpc-app": "dist/index.js" 18 | }, 19 | "dependencies": { 20 | "chalk": "^4.1.0", 21 | "fs-extra": "^10.1.0", 22 | "inquirer": "^8.2.4", 23 | "ora": "^5.4.0" 24 | }, 25 | "devDependencies": { 26 | "@types/fs-extra": "^9.0.13", 27 | "@types/inquirer": "^9.0.0", 28 | "@types/node": "^18.6.4", 29 | "@types/ora": "^3.2.0", 30 | "@typescript-eslint/parser": "^5.44.0", 31 | "ts-node": "^10.9.1", 32 | "tsc-alias": "^1.7.0", 33 | "tsconfig-paths": "^4.1.0", 34 | "typescript": "^4.9.4" 35 | }, 36 | "description": "Create brand new pRPC app within seconds", 37 | "keywords": [ 38 | "pRPC", 39 | "Bling", 40 | "SolidStart" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /docs/src/content/docs/pipe.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'pipe$' 3 | description: 'API for the pipe$ function' 4 | --- 5 | 6 | **API for the pipe$ function** 7 | 8 | This will modify the return type of an existing middleware, in a type safe way. 9 | 10 | ## Usage 11 | 12 | ```ts 13 | import { middleware$, pipe$, query$, response$, error$ } from '@prpc/solid' 14 | import { z } from 'zod' 15 | 16 | const myMiddleware1 = middleware$(({ request$ }) => { 17 | console.log('req', request$) 18 | return Math.random() > 0.5 ? { test: true } : { test: null } 19 | }) 20 | 21 | const middleWare2 = pipe$(myMiddleware1, (ctx) => { 22 | if (ctx.test === null) { 23 | return error$('test is null') 24 | } 25 | return { 26 | test: ctx.test, 27 | o: 1, 28 | } 29 | }) 30 | 31 | export const add = query$( 32 | ({ payload, ctx$ }) => { 33 | console.log({ ctx$ }) // { b: number; test: boolean; o: number} 34 | const result = payload.a + payload.b 35 | return response$( 36 | { result }, 37 | { 38 | headers: { 39 | 'set-cookie': 'solid-testing=1', 40 | }, 41 | } 42 | ) 43 | }, 44 | 'add', 45 | z.object({ 46 | a: z.number(), 47 | b: z.number(), 48 | }), 49 | middleware3 50 | ) 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/src/components/Header/LanguageSelect.css: -------------------------------------------------------------------------------- 1 | .language-select { 2 | flex-grow: 1; 3 | width: 48px; 4 | box-sizing: border-box; 5 | margin: 0; 6 | padding: 0.33em 0.5em; 7 | overflow: visible; 8 | font-weight: 500; 9 | font-size: 1rem; 10 | font-family: inherit; 11 | line-height: inherit; 12 | background-color: var(--theme-bg); 13 | border-color: var(--theme-text-lighter); 14 | color: var(--theme-text-light); 15 | border-style: solid; 16 | border-width: 1px; 17 | border-radius: 0.25rem; 18 | outline: 0; 19 | cursor: pointer; 20 | transition-timing-function: ease-out; 21 | transition-duration: 0.2s; 22 | transition-property: border-color, color; 23 | -webkit-font-smoothing: antialiased; 24 | padding-left: 30px; 25 | padding-right: 1rem; 26 | } 27 | .language-select-wrapper .language-select:hover, 28 | .language-select-wrapper .language-select:focus { 29 | color: var(--theme-text); 30 | border-color: var(--theme-text-light); 31 | } 32 | .language-select-wrapper { 33 | color: var(--theme-text-light); 34 | position: relative; 35 | } 36 | .language-select-wrapper > svg { 37 | position: absolute; 38 | top: 7px; 39 | left: 10px; 40 | pointer-events: none; 41 | } 42 | 43 | @media (min-width: 50em) { 44 | .language-select { 45 | width: 100%; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /docs/src/components/Header/SidebarToggle.tsx: -------------------------------------------------------------------------------- 1 | import type { Component } from "solid-js"; 2 | import { createEffect, createSignal } from "solid-js"; 3 | 4 | const MenuToggle: Component = () => { 5 | const [sidebarShown, setSidebarShown] = createSignal(false); 6 | 7 | createEffect(() => { 8 | const body = document.querySelector("body")!; 9 | if (sidebarShown()) { 10 | body.classList.add("mobile-sidebar-toggle"); 11 | } else { 12 | body.classList.remove("mobile-sidebar-toggle"); 13 | } 14 | }); 15 | 16 | return ( 17 | 40 | ); 41 | }; 42 | 43 | export default MenuToggle; 44 | -------------------------------------------------------------------------------- /examples/solidstart/src/root.tsx: -------------------------------------------------------------------------------- 1 | // @refresh reload 2 | import './root.css' 3 | import { Suspense } from 'solid-js' 4 | import { 5 | Body, 6 | ErrorBoundary, 7 | FileRoutes, 8 | Head, 9 | Html, 10 | Meta, 11 | Routes, 12 | Scripts, 13 | Title, 14 | Link, 15 | } from 'solid-start' 16 | import { QueryProvider } from '@prpc/solid' 17 | import { QueryClient } from '@tanstack/solid-query' 18 | 19 | const queryClient = new QueryClient() 20 | 21 | export default function Root() { 22 | return ( 23 | 24 | 25 | Create JD App 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | concurrency: ${{ github.workflow }}-${{ github.ref }} 8 | 9 | jobs: 10 | release: 11 | name: Release 12 | runs-on: ubuntu-latest 13 | env: 14 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} 15 | TURBO_TEAM: ${{ secrets.TURBO_TEAM }} 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | with: 20 | fetch-depth: 0 21 | 22 | - uses: pnpm/action-setup@v2.2.4 23 | with: 24 | version: 7 25 | 26 | - name: Setup Node.js 27 | uses: actions/setup-node@v3 28 | with: 29 | node-version: 16 30 | cache: 'pnpm' 31 | 32 | - name: Install dependencies 33 | run: pnpm install 34 | 35 | - name: Build 36 | run: pnpm build 37 | 38 | - name: Create Release 39 | uses: changesets/action@v1.4.1 40 | with: 41 | commit: 'chore(release): 📦 version packages' 42 | title: 'chore(release): 📦 version packages' 43 | version: node .github/changeset-version.js 44 | publish: pnpm changeset publish 45 | env: 46 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 47 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 48 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/src/root.tsx: -------------------------------------------------------------------------------- 1 | // @refresh reload 2 | import './root.css' 3 | import { Suspense } from 'solid-js' 4 | import { 5 | Body, 6 | ErrorBoundary, 7 | FileRoutes, 8 | Head, 9 | Html, 10 | Meta, 11 | Routes, 12 | Scripts, 13 | Title, 14 | Link, 15 | } from 'solid-start' 16 | import { QueryProvider } from '@prpc/solid' 17 | import { QueryClient } from '@tanstack/solid-query' 18 | 19 | const queryClient = new QueryClient() 20 | 21 | export default function Root() { 22 | return ( 23 | 24 | 25 | Create JD App 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /docs/src/components/PageContent/PageContent.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import type { MarkdownHeading } from 'astro' 3 | import MoreMenu from '../RightSidebar/MoreMenu.astro' 4 | import TableOfContents from '../RightSidebar/TableOfContents' 5 | 6 | type Props = { 7 | title: string 8 | headings: MarkdownHeading[] 9 | githubEditUrl: string 10 | } 11 | 12 | const { title, headings, githubEditUrl } = Astro.props 13 | --- 14 | 15 |
16 |
17 |

{title}

18 | 21 | 22 |
23 | 26 |
27 | 28 | 56 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | This repo is no longer under development, please use MediaKit - https://github.com/solidjs-community/mediakit/tree/main/packages/prpc 2 | 3 | # pRPC 4 | 5 | Write server code in frontend files with built in colocation, middlewares, schema validation and more, everything is type safed and works with SolidStart 6 | 7 | Read more at [our docs](https://prpc.vercel.app) 8 | 9 | ### Query Example 10 | 11 | ```ts 12 | import { middleware$, query$, response$, error$ } from '@prpc/solid' 13 | import { z } from 'zod' 14 | 15 | const testMw = middleware$(async ({ request$ }) => { 16 | const ua = request$.headers.get('user-agent') 17 | console.log('middleware called on server ', ua) 18 | if (ua?.includes('bot')) { 19 | return error$('Bots are not allowed') 20 | } 21 | return { 22 | ua, 23 | } 24 | }) 25 | 26 | const myQuery = query$({ 27 | queryFn: ({ request$, ctx$, payload }) => { 28 | console.log( 29 | 'queryFn called on server ', 30 | ctx$.ua === request$.headers.get('user-agent'), 31 | payload 32 | ) 33 | return response$(payload.num / 2) 34 | }, 35 | key: 'testQuery', 36 | middlewares: [testMw], 37 | schema: z.object({ 38 | num: z.number(), 39 | }), 40 | }) 41 | ``` 42 | 43 | ## SolidStart 44 | 45 | [Read More Here Regarding SolidStart](https://prpc.vercel.app/solid/install) 46 | -------------------------------------------------------------------------------- /docs/src/content/docs/introduction.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Introduction' 3 | description: 'Docs intro' 4 | --- 5 | 6 | **Welcome to pRPC!** 7 | 8 | pRPC is an open source[`SolidStart`](/solid/install) utility library to make working with `server$` easier. 9 | 10 | ### About 11 | 12 | Using pRPC you will be able to write server code in frontend files in SolidStart and connect your functions with tanstack `query` & `mutation` by default. For instance: 13 | 14 | ```tsx 15 | import { middleware$, query$, response$, error$ } from '@prpc/solid' 16 | import { type NextPage } from 'next' 17 | import { z } from 'zod' 18 | 19 | const testMw = middleware$(async ({ request$ }) => { 20 | const ua = request$.headers.get('user-agent') 21 | console.log('middleware called on server ', ua) 22 | if (ua?.includes('bot')) { 23 | return error$('Bots are not allowed') 24 | } 25 | return { 26 | ua, 27 | } 28 | }) 29 | 30 | const myQuery = query$({ 31 | queryFn: ({ request$, ctx$, payload }) => { 32 | console.log( 33 | 'queryFn called on server ', 34 | ctx$.ua === request$.headers.get('user-agent'), 35 | payload 36 | ) 37 | return response$(payload.num / 2) 38 | }, 39 | key: 'testQuery', 40 | middlewares: [testMw], 41 | schema: z.object({ 42 | num: z.number(), 43 | }), 44 | }) 45 | ``` 46 | 47 | ### Getting Started 48 | 49 | - [SolidStart](/solid/install) 50 | -------------------------------------------------------------------------------- /packages/vite/src/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import type { Plugin } from 'vite' 3 | import { createFilter } from '@rollup/pluginutils' 4 | import { compilepRRPC, type PRPCPluginOptions } from '@prpc/compiler' 5 | 6 | const DEFAULT_INCLUDE = 'src/**/*.{jsx,tsx,ts,js,mjs,cjs}' 7 | const DEFAULT_EXCLUDE = 'node_modules/**/*.{jsx,tsx,ts,js,mjs,cjs}' 8 | 9 | export default function prpc(opts?: PRPCPluginOptions): Plugin { 10 | const filter = createFilter( 11 | opts?.filter?.include || DEFAULT_INCLUDE, 12 | opts?.filter?.exclude || DEFAULT_EXCLUDE 13 | ) 14 | return { 15 | enforce: 'pre', 16 | name: 'prpc', 17 | async transform(code: string, id: string) { 18 | if (!filter(id)) { 19 | return code 20 | } 21 | if ( 22 | ((code.includes('query$(') || code.includes('mutation$(')) && 23 | id.endsWith('.ts')) || 24 | id.endsWith('.tsx') 25 | ) { 26 | return await compilepRRPC(code, id, opts) 27 | } 28 | return undefined 29 | }, 30 | } 31 | } 32 | 33 | export function astroPRPC(opts: PRPCPluginOptions) { 34 | return { 35 | name: 'prpc', 36 | hooks: { 37 | 'astro:config:setup': (config: any) => { 38 | config.updateConfig({ 39 | vite: { 40 | plugins: [prpc(opts)], 41 | }, 42 | }) 43 | }, 44 | }, 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/solidstart/src/server/mutations.ts: -------------------------------------------------------------------------------- 1 | import { mutation$ } from '@prpc/solid' 2 | import { z } from 'zod' 3 | import { myProcedure } from './middleware' 4 | 5 | export const add = mutation$( 6 | async ({ payload }) => { 7 | // eslint-disable-next-line promise/param-names 8 | await new Promise((res) => setTimeout(res, 250)) 9 | const result = payload.a + payload.b 10 | return result 11 | }, 12 | 'add', 13 | z.object({ 14 | a: z.number(), 15 | b: z.number(), 16 | }) 17 | ) 18 | 19 | export const decrease = mutation$( 20 | ({ payload }) => { 21 | const result = payload.a - payload.b 22 | return result 23 | }, 24 | 'decrease', 25 | z.object({ 26 | a: z.number(), 27 | b: z.number(), 28 | }) 29 | ) 30 | 31 | export const noInput = mutation$(() => { 32 | return 1 33 | }, 'decrease') 34 | 35 | export const cleanSyntaxMutation = mutation$({ 36 | mutationFn: ({ payload }) => { 37 | const result = payload.a - payload.b 38 | return result 39 | }, 40 | key: 'cleanSyntaxMutation', 41 | schema: z.object({ 42 | a: z.number(), 43 | b: z.number(), 44 | }), 45 | }) 46 | 47 | export const testReuseMutation = myProcedure.mutation$({ 48 | mutationFn: ({ payload, ctx$ }) => { 49 | return `${payload.a - payload.b}: ${ctx$.reuse}` 50 | }, 51 | key: 'testReuseMutation', 52 | schema: z.object({ 53 | a: z.number(), 54 | b: z.number(), 55 | }), 56 | }) 57 | -------------------------------------------------------------------------------- /examples/solidstart/src/routes/query.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | createSignal, 3 | Match, 4 | Suspense, 5 | Switch, 6 | type VoidComponent, 7 | } from 'solid-js' 8 | import { isServer } from 'solid-js/web' 9 | import { A } from 'solid-start' 10 | import { cleanSyntaxQuery } from '~/server/queries' 11 | 12 | const Query: VoidComponent = () => { 13 | const [num1, setNum1] = createSignal(1) 14 | 15 | const addRes = cleanSyntaxQuery( 16 | // eslint-disable-next-line solid/reactivity 17 | () => ({ 18 | a: num1(), 19 | b: 3, 20 | isServer, 21 | }), 22 | () => ({ 23 | placeholderData: (prev) => prev, 24 | retry: false, 25 | }) 26 | ) 27 | 28 | return ( 29 |
30 |
31 | Mutation 32 | Query 33 |
34 | 35 | 36 | Error: {addRes.error?.message} 37 | Result: {addRes.data?.result} 38 | 39 | 40 | 46 |
{addRes.error?.message ?? 'n error'}
47 |
48 | ) 49 | } 50 | 51 | export default Query 52 | -------------------------------------------------------------------------------- /docs/src/content/docs/solid/query-provider.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'QueryProvider' 3 | description: 'Overview of QueryProvider' 4 | --- 5 | 6 | **Overview of the QueryProvider** 7 | 8 | All projects must be wrapped in the QueryProvider. This provides context to `@tanstack/solid-query` 9 | 10 | ## Examples 11 | 12 | **root.tsx** 13 | 14 | ```tsx 15 | // @refresh reload 16 | import { QueryProvider } from '@prpc/solid' 17 | import { Suspense } from 'solid-js' 18 | import { 19 | Body, 20 | ErrorBoundary, 21 | FileRoutes, 22 | Head, 23 | Html, 24 | Link, 25 | Meta, 26 | Routes, 27 | Scripts, 28 | Title, 29 | } from 'solid-start' 30 | 31 | export default function Root() { 32 | return ( 33 | 34 | 35 | pRPC Basic 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | ) 56 | } 57 | ``` 58 | 59 | ## API 60 | 61 | TODO 62 | -------------------------------------------------------------------------------- /docs/src/components/Header/AstroLogo.astro: -------------------------------------------------------------------------------- 1 | --- 2 | type Props = { 3 | size: number; 4 | }; 5 | const { size } = Astro.props; 6 | --- 7 | 8 | 41 | -------------------------------------------------------------------------------- /docs/src/components/HeadCommon.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import '../styles/theme.css'; 3 | import '../styles/index.css'; 4 | --- 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 33 | 34 | 35 | 42 | -------------------------------------------------------------------------------- /docs/src/content/docs/prpc-client-error.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'PRPCClientError' 3 | description: 'API for the PRPCClientError instance' 4 | --- 5 | 6 | **API for the PRPCClientError instance** 7 | 8 | This is the error instance that pRPC will throw when ever it faces any issue. 9 | 10 | Assuming you have this query defined: 11 | 12 | ```ts 13 | export const add = query$( 14 | ({ payload }) => { 15 | const result = payload.a + payload.b 16 | return response$( 17 | { result }, 18 | { 19 | headers: { 20 | 'set-cookie': 'solid-testing=1', 21 | }, 22 | } 23 | ) 24 | }, 25 | 'add', 26 | z.object({ 27 | a: z.number().max(5), 28 | b: z.number().max(10), 29 | }) 30 | ) 31 | ``` 32 | 33 | You can handle errors thrown by zod on the client side like this: 34 | 35 | ```ts 36 | const addRes = add( 37 | () => ({ 38 | a: num1(), 39 | b: 3, 40 | }), 41 | () => ({ 42 | placeholderData: (prev) => prev, 43 | onError: (error) => { 44 | if (error.isZodError()) { 45 | const fieldErrors = error.cause.fieldErrors 46 | console.log(fieldErrors.a) 47 | console.log(fieldErrors.b) 48 | } 49 | }, 50 | retry: false, 51 | }) 52 | ) 53 | ``` 54 | 55 | Using `error.isZodError()` you can check if the error is a zod error and then you can access the `fieldErrors` property to get the errors for each field, in a type safe way ofc. 56 | 57 | You can also check if the error is a native `Error` instance using `error.isError()`, this will give you access to its `message` property. 58 | -------------------------------------------------------------------------------- /examples/solidstart/src/routes/mutation.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | createSignal, 3 | Match, 4 | Suspense, 5 | Switch, 6 | type VoidComponent, 7 | } from 'solid-js' 8 | import { A } from 'solid-start' 9 | import { testReuseMutation } from '~/server/mutations' 10 | 11 | const Mutation: VoidComponent = () => { 12 | const [num1, setNum1] = createSignal(1) 13 | const mutationRes = testReuseMutation() 14 | return ( 15 |
16 |
17 | Mutation 18 | Query 19 |
20 | 21 | 22 | 23 |
Result: {mutationRes.data}
24 |
25 | 26 |
Error {mutationRes.error?.message}
27 |
28 | 29 |
Loading...
30 |
31 |
32 | 38 |
39 | 50 |
51 | ) 52 | } 53 | 54 | export default Mutation 55 | -------------------------------------------------------------------------------- /docs/src/components/Header/LanguageSelect.tsx: -------------------------------------------------------------------------------- 1 | import { Component, For } from "solid-js"; 2 | import { KNOWN_LANGUAGES, langPathRegex } from "../../languages"; 3 | import "./LanguageSelect.css"; 4 | 5 | const LanguageSelect: Component<{ lang: string }> = ({ lang }) => { 6 | return ( 7 |
8 | 25 | 39 |
40 | ); 41 | }; 42 | 43 | export default LanguageSelect; 44 | -------------------------------------------------------------------------------- /examples/solidstart/src/routes/query-same.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable solid/reactivity */ 2 | import { query$ } from '@prpc/solid' 3 | import { 4 | createSignal, 5 | Match, 6 | Suspense, 7 | Switch, 8 | type VoidComponent, 9 | } from 'solid-js' 10 | import { z } from 'zod' 11 | 12 | const queryOnServer = query$({ 13 | queryFn: async ({ payload, request$ }) => { 14 | console.log('on server', request$.headers.get('user-agent')) 15 | return { result: payload.num / 2 } 16 | }, 17 | key: 'queryOnServer', 18 | schema: z.object({ 19 | num: z.number().max(5), 20 | }), 21 | }) 22 | 23 | const Query: VoidComponent = () => { 24 | const [num, setNum1] = createSignal(1) 25 | 26 | const queryRes = queryOnServer( 27 | () => ({ num: num() }), 28 | () => ({ 29 | placeholderData: (prev) => prev, 30 | onError: (error) => { 31 | if (error.isZodError()) { 32 | const fieldErrors = error.cause.fieldErrors 33 | console.log(fieldErrors.num) 34 | } 35 | }, 36 | retry: false, 37 | }) 38 | ) 39 | 40 | return ( 41 |
42 | 43 | 44 | Error: {queryRes.error?.message} 45 | Result: {queryRes.data?.result} 46 | 47 | 48 | 54 | {queryRes.error?.message &&
{queryRes.error?.message}
} 55 |
56 | ) 57 | } 58 | 59 | export default Query 60 | -------------------------------------------------------------------------------- /docs/src/content/docs/error.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'error$' 3 | description: 'API for the error$ function' 4 | --- 5 | 6 | **API for the error$ function** 7 | 8 | This function will be used from the server-side, in order to throw errors on the client side and break out of running middlewares. 9 | 10 | ## Usage 11 | 12 | ```ts 13 | import { 14 | error$, 15 | hideRequest, 16 | middleware$, 17 | pipe$, 18 | query$, 19 | response$, 20 | } from '@prpc/solid' 21 | import { z } from 'zod' 22 | 23 | const myMiddleware1 = middleware$(({ request$ }) => { 24 | console.log('ua', request$.headers.get('user-agent')) 25 | const random = Math.random() 26 | const test = random > 0.5 ? 'test' : null 27 | console.log({ test }) 28 | return { test } 29 | }) 30 | 31 | const middleWare2 = pipe$(myMiddleware1, (ctx) => { 32 | if (!ctx.test) { 33 | return error$('Expected test to be defined') 34 | // this will throw an error on the client side and will break out of the middlewares 35 | } 36 | return { 37 | test: ctx.test, 38 | o: 1, 39 | } 40 | }) 41 | 42 | const middleware3 = pipe$(middleWare2, (ctx) => { 43 | // ctx.test is inferred to be string because we checked it in the previous middleware 44 | return { 45 | ...ctx, 46 | b: 2, 47 | } 48 | }) 49 | 50 | export const add = query$( 51 | ({ payload, ctx$ }) => { 52 | console.log({ ctx$: hideRequest(ctx$) }) 53 | const result = payload.a + payload.b 54 | return response$( 55 | { result }, 56 | { 57 | headers: { 58 | 'set-cookie': 'solid-testing=1', 59 | }, 60 | } 61 | ) 62 | }, 63 | 'add', 64 | z.object({ 65 | a: z.number().max(5), 66 | b: z.number().max(10), 67 | }), 68 | middleware3 69 | ) 70 | ``` 71 | -------------------------------------------------------------------------------- /packages/unplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@prpc/unplugin", 3 | "version": "0.3.20", 4 | "type": "module", 5 | "files": [ 6 | "dist" 7 | ], 8 | "engines": { 9 | "node": ">=10" 10 | }, 11 | "keywords": [ 12 | "pRPC", 13 | "server$" 14 | ], 15 | "devDependencies": { 16 | "@types/node": "^18.13.0", 17 | "@typescript-eslint/parser": "^5.44.0", 18 | "eslint": "^8.33.0", 19 | "pridepack": "2.4.0", 20 | "tslib": "^2.5.0", 21 | "typescript": "^4.9.5" 22 | }, 23 | "dependencies": { 24 | "@prpc/compiler": "workspace:*", 25 | "unplugin": "^1.3.1", 26 | "@rollup/pluginutils": "^5.0.2" 27 | }, 28 | "scripts": { 29 | "prepublishOnly": "pridepack clean && pridepack build", 30 | "build": "pridepack build", 31 | "type-check": "pridepack check", 32 | "lint": "pridepack lint", 33 | "clean": "pridepack clean", 34 | "watch": "pridepack watch", 35 | "start": "pridepack start", 36 | "dev": "pridepack dev", 37 | "test": "vitest" 38 | }, 39 | "description": "Package for easily creating server rpc functions in solid-start with goodies baked in", 40 | "publishConfig": { 41 | "access": "public" 42 | }, 43 | "private": false, 44 | "types": "./dist/types/index.d.ts", 45 | "main": "./dist/cjs/production/index.cjs", 46 | "module": "./dist/esm/production/index.mjs", 47 | "exports": { 48 | ".": { 49 | "development": { 50 | "require": "./dist/cjs/development/index.cjs", 51 | "import": "./dist/esm/development/index.mjs" 52 | }, 53 | "require": "./dist/cjs/production/index.cjs", 54 | "import": "./dist/esm/production/index.mjs", 55 | "types": "./dist/types/index.d.ts" 56 | } 57 | }, 58 | "typesVersions": { 59 | "*": {} 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /docs/src/content/docs/solid/reuseable.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'reuseable$' 3 | description: 'API for the reuseable$ function' 4 | --- 5 | 6 | **API for the reuseable$ function** 7 | 8 | This function will be used to create a **reuseable** procedures, it will take up middlewares and then will use this middlewares for all of the created queries / mutations under it. 9 | 10 | ## Usage 11 | 12 | ```ts 13 | import { middleware$, reuseable$ } from '@prpc/solid' 14 | 15 | const reuseMw = middleware$(() => { 16 | return { 17 | reuse: 'reuse' as const, 18 | } 19 | }) 20 | 21 | export const myProcedure = reuseable$(reuseMw) 22 | 23 | export const testReuseQuery = myProcedure.query$({ 24 | queryFn: ({ ctx$ }) => { 25 | return `Hello ${ctx$.reuse}` 26 | }, 27 | key: 'testReuseQuery', 28 | }) 29 | ``` 30 | 31 | This can also be done from different files 32 | 33 | ```ts 34 | // file1.ts 35 | import { middleware$, reuseable$ } from '@prpc/solid' 36 | 37 | const reuseMw = middleware$(() => { 38 | return { 39 | reuse: 'reuse' as const, 40 | } 41 | }) 42 | 43 | export const myProcedure = reuseable$(reuseMw) 44 | ``` 45 | 46 | ```ts 47 | // file2.ts 48 | import { myProcedure } from './file1' 49 | 50 | export const testReuseQuery = myProcedure.query$({ 51 | queryFn: ({ ctx$ }) => { 52 | return `Hello ${ctx$.reuse}` 53 | }, 54 | key: 'testReuseQuery', 55 | }) 56 | ``` 57 | 58 | ```ts 59 | // file3.ts 60 | import { myProcedure } from './file1' 61 | import { z } from 'zod' 62 | 63 | export const testReuseMutation = myProcedure.mutation$({ 64 | mutationFn: ({ payload, ctx$ }) => { 65 | return `${payload.a - payload.b}: ${ctx$.reuse}` 66 | }, 67 | key: 'testReuseMutation', 68 | schema: z.object({ 69 | a: z.number(), 70 | b: z.number(), 71 | }), 72 | }) 73 | ``` 74 | -------------------------------------------------------------------------------- /docs/src/content/docs/middleware.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'middleware$' 3 | description: 'API for the middleware$ function' 4 | --- 5 | 6 | **API for the middleware$ function** 7 | 8 | Functions that will run before the query function. Useful for authentication, logging, etc. 9 | 10 | ## Usage 11 | 12 | ```ts 13 | import { middleware$, query$, response$ } from '@prpc/solid' 14 | import { z } from 'zod' 15 | 16 | const myMiddleware1 = middleware$(({ request$ }) => { 17 | console.log('req', request$) 18 | return Math.random() > 0.5 ? { test: true } : { test: null } 19 | }) 20 | 21 | export const add = query$( 22 | ({ payload, ctx$ }) => { 23 | console.log({ ctx$ }) // ctx$ is inferred to be { test: boolean | null } 24 | const result = payload.a + payload.b 25 | return response$( 26 | { result }, 27 | { 28 | headers: { 29 | 'set-cookie': 'solid-testing=1', 30 | }, 31 | } 32 | ) 33 | }, 34 | 'add', 35 | z.object({ 36 | a: z.number(), 37 | b: z.number(), 38 | }), 39 | myMiddleware1 40 | ) 41 | ``` 42 | 43 | ### Another Syntax 44 | 45 | ```ts 46 | import { middleware$, query$, response$ } from '@prpc/solid' 47 | import { z } from 'zod' 48 | 49 | export const cleanSyntaxQuery = query$({ 50 | queryFn: async ({ payload, request$, ctx$ }) => { 51 | ctx$.test 52 | ctx$.b 53 | console.log('called', request$.headers.get('user-agent')) 54 | return response$({ result: payload.a + payload.b }) 55 | }, 56 | key: 'cleanSyntaxQuery', 57 | schema: z.object({ 58 | a: z.number().max(5), 59 | b: z.number().max(10), 60 | }), 61 | // middleware3 was returned from `middleware$` 62 | middlewares: [middleware3], 63 | }) 64 | ``` 65 | 66 | If you want to pipe a middleware, check out the [pipe](/pipe) function. 67 | -------------------------------------------------------------------------------- /packages/compiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@prpc/compiler", 3 | "version": "0.3.20", 4 | "type": "module", 5 | "files": [ 6 | "dist" 7 | ], 8 | "engines": { 9 | "node": ">=10" 10 | }, 11 | "keywords": [ 12 | "pRPC", 13 | "server$" 14 | ], 15 | "devDependencies": { 16 | "@types/babel__core": "^7.20.0", 17 | "@types/node": "^18.13.0", 18 | "@typescript-eslint/parser": "^5.44.0", 19 | "eslint": "^8.33.0", 20 | "pridepack": "2.4.0", 21 | "tslib": "^2.5.0", 22 | "typescript": "^4.9.5", 23 | "@rollup/pluginutils": "^5.0.2" 24 | }, 25 | "dependencies": { 26 | "@babel/core": "^7.20.12", 27 | "@babel/preset-typescript": "^7.18.6" 28 | }, 29 | "scripts": { 30 | "prepublishOnly": "pridepack clean && pridepack build", 31 | "build": "pridepack build", 32 | "type-check": "pridepack check", 33 | "lint": "pridepack lint", 34 | "clean": "pridepack clean", 35 | "watch": "pridepack watch", 36 | "start": "pridepack start", 37 | "dev": "pridepack dev" 38 | }, 39 | "description": "Package for easily creating server rpc functions in solid-start with goodies baked in", 40 | "publishConfig": { 41 | "access": "public" 42 | }, 43 | "private": false, 44 | "types": "./dist/types/index.d.ts", 45 | "main": "./dist/cjs/production/index.cjs", 46 | "module": "./dist/esm/production/index.mjs", 47 | "exports": { 48 | ".": { 49 | "development": { 50 | "require": "./dist/cjs/development/index.cjs", 51 | "import": "./dist/esm/development/index.mjs" 52 | }, 53 | "require": "./dist/cjs/production/index.cjs", 54 | "import": "./dist/esm/production/index.mjs", 55 | "types": "./dist/types/index.d.ts" 56 | } 57 | }, 58 | "typesVersions": { 59 | "*": {} 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /packages/solid/README.md: -------------------------------------------------------------------------------- 1 | # @prpc/solid 2 | 3 | SolidSart adapter for pRPC. 4 | 5 | ### Install 6 | 7 | ```sh 8 | pnpm add @prpc/solid@latest @prpc/vite@latest @tanstack/solid-query@beta 9 | ``` 10 | 11 | ### Vite Plugin 12 | 13 | Add the following to your vite config 14 | 15 | ```ts 16 | import prpc from '@prpc/vite'; 17 | import solid from 'solid-start/vite'; 18 | ... 19 | export default defineConfig(() => { 20 | return { 21 | ... 22 | plugins: [ 23 | prpc(), // Important that this plugin runs before the solid one! 24 | solid() 25 | ] 26 | ... 27 | } 28 | }) 29 | ``` 30 | 31 | ### QueryProvider 32 | 33 | ```tsx 34 | // @refresh reload 35 | import { QueryProvider } from '@prpc/solid' 36 | import { Suspense } from 'solid-js' 37 | import { 38 | Body, 39 | ErrorBoundary, 40 | FileRoutes, 41 | Head, 42 | Html, 43 | Link, 44 | Meta, 45 | Routes, 46 | Scripts, 47 | Title, 48 | } from 'solid-start' 49 | 50 | export default function Root() { 51 | return ( 52 | 53 | 54 | pRPC Basic 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | ) 75 | } 76 | ``` 77 | 78 | Read more - [docs](https://prpc.vercel.app) 79 | -------------------------------------------------------------------------------- /packages/create/templates/SolidStart/src/routes/index.tsx: -------------------------------------------------------------------------------- 1 | import { type VoidComponent } from "solid-js"; 2 | import { A } from "solid-start"; 3 | import { helloQuery } from "../server/queries"; 4 | 5 | const Home: VoidComponent = () => { 6 | const hello = helloQuery(() => ({ 7 | name: "from pRPC", 8 | })); 9 | return ( 10 |
11 | 40 |
41 | ); 42 | }; 43 | 44 | export default Home; 45 | -------------------------------------------------------------------------------- /packages/vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@prpc/vite", 3 | "version": "0.3.21", 4 | "type": "module", 5 | "files": [ 6 | "dist" 7 | ], 8 | "engines": { 9 | "node": ">=10" 10 | }, 11 | "keywords": [ 12 | "pRPC", 13 | "server$" 14 | ], 15 | "devDependencies": { 16 | "@types/babel__core": "^7.20.0", 17 | "@types/node": "^18.13.0", 18 | "@typescript-eslint/parser": "^5.44.0", 19 | "eslint": "^8.33.0", 20 | "pridepack": "2.4.0", 21 | "tslib": "^2.5.0", 22 | "typescript": "^4.9.5", 23 | "vite": "^4.0.4", 24 | "vitest": "0.29.2" 25 | }, 26 | "dependencies": { 27 | "@babel/core": "^7.20.12", 28 | "@babel/preset-typescript": "^7.18.6", 29 | "@rollup/pluginutils": "^5.0.2", 30 | "@prpc/compiler": "workspace:*" 31 | }, 32 | "scripts": { 33 | "prepublishOnly": "pridepack clean && pridepack build", 34 | "build": "pridepack build", 35 | "type-check": "pridepack check", 36 | "lint": "pridepack lint", 37 | "clean": "pridepack clean", 38 | "watch": "pridepack watch", 39 | "start": "pridepack start", 40 | "dev": "pridepack dev", 41 | "test": "vitest" 42 | }, 43 | "description": "Package for easily creating server rpc functions in solid-start with goodies baked in", 44 | "publishConfig": { 45 | "access": "public" 46 | }, 47 | "private": false, 48 | "types": "./dist/types/index.d.ts", 49 | "main": "./dist/cjs/production/index.cjs", 50 | "module": "./dist/esm/production/index.mjs", 51 | "exports": { 52 | ".": { 53 | "development": { 54 | "require": "./dist/cjs/development/index.cjs", 55 | "import": "./dist/esm/development/index.mjs" 56 | }, 57 | "require": "./dist/cjs/production/index.cjs", 58 | "import": "./dist/esm/production/index.mjs", 59 | "types": "./dist/types/index.d.ts" 60 | } 61 | }, 62 | "typesVersions": { 63 | "*": {} 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prpc-mono", 3 | "description": "Workspace for prpc", 4 | "version": "0.0.0", 5 | "scripts": { 6 | "build": "turbo run build --filter=./packages/*", 7 | "dev": "turbo run dev --parallel --include-dependencies --no-deps", 8 | "clean": "turbo run clean --parallel && rm -rf node_modules pnpm-lock.yaml && pnpm install", 9 | "lint": "turbo run lint", 10 | "test": "turbo run test", 11 | "test:coverage": "turbo run test:coverage", 12 | "format": "prettier --write \"**.*.{ts,tsx,md}\"", 13 | "ts:check": "torbo run ts:check --continue", 14 | "dev:packages": "turbo run dev --filter=./packages/*", 15 | "prepare": "husky install" 16 | }, 17 | "type": "module", 18 | "engines": { 19 | "node": ">=16", 20 | "pnpm": ">=7" 21 | }, 22 | "lint-staged": { 23 | "*.{js,json}": "prettier --write", 24 | "packages/**/*.{js,jsx,ts,tsx}": [ 25 | "eslint --fix", 26 | "prettier --write" 27 | ], 28 | "examples/**/*.{js,jsx,ts,tsx}": [ 29 | "eslint --fix", 30 | "prettier --write" 31 | ], 32 | "package.json": "sort-package-json" 33 | }, 34 | "devDependencies": { 35 | "@changesets/changelog-github": "^0.4.7", 36 | "@changesets/cli": "^2.25.2", 37 | "@types/node": "^18.11.9", 38 | "@typescript-eslint/eslint-plugin": "^5.44.0", 39 | "@typescript-eslint/parser": "^5.44.0", 40 | "eslint": "^8.28.0", 41 | "eslint-config-prettier": "^8.5.0", 42 | "eslint-config-standard-with-typescript": "^23.0.0", 43 | "eslint-plugin-import": "^2.26.0", 44 | "eslint-plugin-n": "^15.5.1", 45 | "eslint-plugin-promise": "^6.1.1", 46 | "husky": "^8.0.0", 47 | "lint-staged": "^13.0.4", 48 | "prettier": "^2.8.0", 49 | "sort-package-json": "^2.1.0", 50 | "tslib": "^2.5.0", 51 | "tsup": "^6.5.0", 52 | "tsup-preset-solid": "0.1.8", 53 | "turbo": "1.2.4", 54 | "typescript": "^4.8.2" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/create/src/utils/files.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra' 2 | import ora from 'ora' 3 | import type { IAppCtx, IFile } from '~types' 4 | import { formatError } from './helpers' 5 | 6 | export async function execFiles(files: (IFile | undefined)[], ctx: IAppCtx) { 7 | const actualFiles = files.filter((f) => f !== undefined) as IFile[] 8 | // `sep` files are parent files, so they should be executed first ro resolve conflicts 9 | for (const file of actualFiles.filter((e) => e.sep)) { 10 | await execFile(file, ctx) 11 | } 12 | await Promise.all( 13 | actualFiles 14 | .filter((e) => !e.sep) 15 | .map(async (file) => { 16 | await execFile(file, ctx) 17 | }) 18 | ) 19 | } 20 | 21 | async function execFile(file: IFile, ctx: IAppCtx) { 22 | if (file.type && file.type !== 'copy') { 23 | if (file.type === 'exec') { 24 | if (!file.path) { 25 | return 26 | } 27 | const method = await import(file.path) 28 | await fs.outputFile(file.to, method.default(ctx, file.pass)) 29 | } else if (file.type === 'delete') { 30 | await fs.remove(file.to) 31 | } else if (file.type === 'write') { 32 | await fs.outputFile(file.to, file.content) 33 | } else if (file.type === 'append') { 34 | await fs.appendFile(file.to, file.content) 35 | } 36 | } else { 37 | if (!file.path) { 38 | return 39 | } 40 | await fs.copy(file.path, file.to) 41 | } 42 | } 43 | 44 | export async function existsOrCreate(path: string): Promise { 45 | try { 46 | await fs.access(path) 47 | return true 48 | } catch { 49 | await fs.mkdir(path) 50 | } 51 | return false 52 | } 53 | 54 | export async function overWriteFile(userDir: string) { 55 | const spinner = ora('Emptying directory').start() 56 | try { 57 | await fs.emptyDir(userDir) 58 | spinner.succeed('Emptied directory') 59 | } catch (e) { 60 | spinner.fail(`Couldn't empty directory: ${formatError(e)}`) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /docs/src/content/docs/solid/install.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Install' 3 | description: 'Installing pRPC' 4 | --- 5 | 6 | **Adding pRPC to solid-start** 7 | 8 | ### Create pRPC App 9 | 10 | You can use `create-prpc-app` to create a new pRPC app. 11 | 12 | ```sh 13 | npm create prpc-app@latest 14 | ``` 15 | 16 | Or do it manually 17 | 18 | ### Install 19 | 20 | ```sh 21 | pnpm add @prpc/solid@latest @tanstack/solid-query@beta @prpc/vite@latest 22 | ``` 23 | 24 | ### Vite Plugin 25 | 26 | Add the following to your vite config 27 | 28 | ```ts 29 | import prpc from '@prpc/vite'; 30 | import solid from 'solid-start/vite'; 31 | ... 32 | export default defineConfig(() => { 33 | return { 34 | ... 35 | plugins: [ 36 | prpc(), // Important that this plugin runs before the solid one! 37 | solid() 38 | ] 39 | ... 40 | } 41 | }) 42 | ``` 43 | 44 | ### QueryProvider 45 | 46 | ```tsx 47 | // @refresh reload 48 | import { QueryProvider } from '@prpc/solid' 49 | import { Suspense } from 'solid-js' 50 | import { 51 | Body, 52 | ErrorBoundary, 53 | FileRoutes, 54 | Head, 55 | Html, 56 | Link, 57 | Meta, 58 | Routes, 59 | Scripts, 60 | Title, 61 | } from 'solid-start' 62 | 63 | export default function Root() { 64 | return ( 65 | 66 | 67 | pRPC Basic 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | ) 88 | } 89 | ``` 90 | -------------------------------------------------------------------------------- /packages/create/src/utils/helpers.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra' 2 | import path from 'path' 3 | import { exec } from 'child_process' 4 | import { promisify } from 'util' 5 | import type { IAppCtx } from '~types' 6 | 7 | export const execa = promisify(exec) 8 | 9 | const DEFAULT_ERR = 'Something Went Wrong' 10 | 11 | const errCheck = (message?: string): string => 12 | message?.length ? message : DEFAULT_ERR 13 | 14 | export const formatError = (err: unknown): string => { 15 | if (typeof err === 'string') return errCheck(err) 16 | else if (typeof err === 'object') { 17 | if (Array.isArray(err)) { 18 | if (err.length) { 19 | return formatError(err.shift()) 20 | } else return errCheck() 21 | } else if (err && 'message' in err) { 22 | return formatError(err.message) 23 | } else if (err && 'stack' in err) { 24 | return formatError(err.stack) 25 | } 26 | } 27 | return errCheck() 28 | } 29 | 30 | export const validateName = (name: string) => { 31 | if (!name.length) return false 32 | return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(name) 33 | ? true 34 | : 'This is not a valid name' 35 | } 36 | 37 | export async function modifyJSON( 38 | userDir: string, 39 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 40 | cb: (json: any) => Promise 41 | ) { 42 | const json = await fs.readJSON(path.join(userDir, 'package.json')) 43 | const newJson = await cb({ ...json }) 44 | await fs.writeFile( 45 | path.join(userDir, 'package.json'), 46 | JSON.stringify(newJson, null, 2) 47 | ) 48 | return newJson 49 | } 50 | 51 | export const getUserPackageManager = () => { 52 | const userAgent = process.env.npm_config_user_agent 53 | if (userAgent?.startsWith('yarn')) return 'yarn' 54 | if (userAgent?.startsWith('pnpm')) return 'pnpm' 55 | return 'npm' 56 | } 57 | 58 | export const updateJson = async (ctx: IAppCtx) => { 59 | await modifyJSON(ctx.userDir, (json) => { 60 | json.name = ctx.appName 61 | return json 62 | }) 63 | } 64 | -------------------------------------------------------------------------------- /docs/src/components/Header/Search.css: -------------------------------------------------------------------------------- 1 | /** Style Algolia */ 2 | :root { 3 | --docsearch-primary-color: var(--theme-accent); 4 | --docsearch-logo-color: var(--theme-text); 5 | } 6 | .search-input { 7 | flex-grow: 1; 8 | box-sizing: border-box; 9 | width: 100%; 10 | margin: 0; 11 | padding: 0.33em 0.5em; 12 | overflow: visible; 13 | font-weight: 500; 14 | font-size: 1rem; 15 | font-family: inherit; 16 | line-height: inherit; 17 | background-color: var(--theme-divider); 18 | border-color: var(--theme-divider); 19 | color: var(--theme-text-light); 20 | border-style: solid; 21 | border-width: 1px; 22 | border-radius: 0.25rem; 23 | outline: 0; 24 | cursor: pointer; 25 | transition-timing-function: ease-out; 26 | transition-duration: 0.2s; 27 | transition-property: border-color, color; 28 | -webkit-font-smoothing: antialiased; 29 | } 30 | .search-input:hover, 31 | .search-input:focus { 32 | color: var(--theme-text); 33 | border-color: var(--theme-text-light); 34 | } 35 | .search-input:hover::placeholder, 36 | .search-input:focus::placeholder { 37 | color: var(--theme-text-light); 38 | } 39 | .search-input::placeholder { 40 | color: var(--theme-text-light); 41 | } 42 | .search-hint { 43 | position: absolute; 44 | top: 7px; 45 | right: 19px; 46 | padding: 3px 5px; 47 | display: none; 48 | align-items: center; 49 | justify-content: center; 50 | letter-spacing: 0.125em; 51 | font-size: 13px; 52 | font-family: var(--font-mono); 53 | pointer-events: none; 54 | border-color: var(--theme-text-lighter); 55 | color: var(--theme-text-light); 56 | border-style: solid; 57 | border-width: 1px; 58 | border-radius: 0.25rem; 59 | line-height: 14px; 60 | } 61 | 62 | @media (min-width: 50em) { 63 | .search-hint { 64 | display: flex; 65 | } 66 | } 67 | 68 | /* ------------------------------------------------------------ *\ 69 | DocSearch (Algolia) 70 | \* ------------------------------------------------------------ */ 71 | 72 | .DocSearch-Modal .DocSearch-Hit a { 73 | box-shadow: none; 74 | border: 1px solid var(--theme-accent); 75 | } 76 | -------------------------------------------------------------------------------- /docs/src/components/HeadSEO.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import type { CollectionEntry } from 'astro:content' 3 | import { SITE } from '../consts' 4 | 5 | type Props = { canonicalUrl: URL } & CollectionEntry<'docs'>['data'] 6 | 7 | const { 8 | ogLocale, 9 | // image, 10 | title, 11 | description, 12 | canonicalUrl, 13 | } = Astro.props 14 | const formattedContentTitle = `${title} | ${SITE.title}` 15 | // const imageSrc = image?.src ?? OPEN_GRAPH.image.src; 16 | // const canonicalImageSrc = new URL(imageSrc, Astro.site); 17 | // const imageAlt = image?.alt ?? OPEN_GRAPH.image.alt; 18 | --- 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 51 | -------------------------------------------------------------------------------- /docs/src/content/docs/hideRequest.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'hideRequest' 3 | description: 'API for the hideRequest function' 4 | --- 5 | 6 | **API for the hideRequest function** 7 | 8 | This function will be used to remove the `request$` object from the context passed to a function. 9 | 10 | ## Usage 11 | 12 | ```ts 13 | import { hideRequest, middleware$, pipe$, query$, response$ } from '@prpc/solid' 14 | import { z } from 'zod' 15 | 16 | const myMiddleware1 = middleware$(({ request$ }) => { 17 | console.log('ua', request$.headers.get('user-agent')) 18 | return { test: null } 19 | }) 20 | 21 | const middleWare2 = pipe$(myMiddleware1, (ctx) => { 22 | return { 23 | test: ctx.test, 24 | o: 1, 25 | } 26 | }) 27 | 28 | const middleware3 = pipe$(middleWare2, (ctx) => { 29 | return { 30 | ...ctx, 31 | b: 2, 32 | } 33 | }) 34 | 35 | export const add = query$( 36 | ({ payload, ctx$ }) => { 37 | console.log({ ctx$: hideRequest(ctx$) }) // this will print the context without the request$ 38 | const result = payload.a + payload.b 39 | return response$( 40 | { result }, 41 | { 42 | headers: { 43 | 'set-cookie': 'solid-testing=1', 44 | }, 45 | } 46 | ) 47 | }, 48 | 'add', 49 | z.object({ 50 | a: z.number(), 51 | b: z.number(), 52 | }), 53 | middleware3 54 | ) 55 | ``` 56 | 57 | ## Parameters 58 | 59 | `hideRequest` also takes in a second argument - `fully`, setting this to true will use the `delete` op to remove the request$ from the context, so you can use this a bit differently: 60 | 61 | ```ts 62 | export const add = query$( 63 | ({ payload, ctx$ }) => { 64 | hideRequest(ctx$, true) // using the delete op to remove the request$ object 65 | console.log({ ctx$ }) // this will print the context without the request$ 66 | const result = payload.a + payload.b 67 | return response$( 68 | { result }, 69 | { 70 | headers: { 71 | 'set-cookie': 'solid-testing=1', 72 | }, 73 | } 74 | ) 75 | }, 76 | 'add', 77 | z.object({ 78 | a: z.number(), 79 | b: z.number(), 80 | }), 81 | middleware3 82 | ) 83 | ``` 84 | -------------------------------------------------------------------------------- /packages/solid/src/reuseable.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import { 3 | callMiddleware$, 4 | getParams, 5 | type ExpectedFn, 6 | type IMiddleware, 7 | type ObjectParams, 8 | } from '@prpc/core' 9 | import { type ExpectedMutationReturn, mutation$ } from './mutation' 10 | import { type ExpectedQueryReturn, query$ } from './query' 11 | import type zod from 'zod' 12 | 13 | export function reuseable$(...mw: Mw) { 14 | return { 15 | callMw: async (req: Request) => await callMiddleware$(req, mw), 16 | query$: < 17 | Fn extends ExpectedFn< 18 | ZObj extends void | undefined 19 | ? void | undefined 20 | : ZObj extends zod.ZodSchema 21 | ? zod.infer 22 | : void | undefined, 23 | Mw 24 | >, 25 | ZObj extends zod.ZodSchema | void | undefined = void | undefined 26 | >( 27 | params: Omit, 'middlewares'>, 28 | ...rest: any[] 29 | ): ExpectedQueryReturn => { 30 | const { queryFn, key } = 31 | typeof params === 'object' 32 | ? params 33 | : getParams(false, [params, ...rest]) 34 | return (query$ as any)(queryFn, key, ...mw) 35 | }, 36 | mutation$: < 37 | Fn extends ExpectedFn< 38 | ZObj extends void | undefined 39 | ? void | undefined 40 | : ZObj extends zod.ZodSchema 41 | ? zod.infer 42 | : void | undefined, 43 | Mw 44 | >, 45 | ZObj extends zod.ZodSchema | void | undefined = void | undefined 46 | >( 47 | params: Omit, 'middlewares'>, 48 | ...rest: any[] 49 | ): ExpectedMutationReturn => { 50 | let queryFn 51 | let key 52 | if (typeof params === 'object') { 53 | queryFn = params.mutationFn 54 | key = params.key 55 | } else { 56 | const temp = getParams(true, [params, ...rest]) 57 | queryFn = temp.queryFn 58 | key = temp.key 59 | } 60 | return (mutation$ as any)(queryFn, key, ...mw) 61 | }, 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /docs/src/consts.ts: -------------------------------------------------------------------------------- 1 | export const SITE = { 2 | title: 'pRPC', 3 | description: 'pRPC documentation and examples', 4 | defaultLanguage: 'en-us', 5 | } as const 6 | 7 | // export const OPEN_GRAPH = { 8 | // image: { 9 | // src: 'https://github.com/withastro/astro/blob/main/assets/social/banner-minimal.png?raw=true', 10 | // alt: 11 | // 'astro logo on a starry expanse of space,' + 12 | // ' with a purple saturn-like planet floating in the right foreground', 13 | // }, 14 | // twitter: 'astrodotbuild', 15 | // } 16 | 17 | export const KNOWN_LANGUAGES = { 18 | English: 'en', 19 | } as const 20 | export const KNOWN_LANGUAGE_CODES = Object.values(KNOWN_LANGUAGES) 21 | 22 | export const GITHUB_EDIT_URL = `https://github.com/OrJDev/prpc/tree/main/docs` 23 | 24 | export const COMMUNITY_INVITE_URL = `https://github.com/OrJDev/prpc` 25 | 26 | // See "Algolia" section of the README for more information. 27 | export const ALGOLIA = { 28 | indexName: 'XXXXXXXXXX', 29 | appId: 'XXXXXXXXXX', 30 | apiKey: 'XXXXXXXXXX', 31 | } 32 | 33 | export type Sidebar = Record 34 | 35 | export const SIDEBAR: Sidebar = { 36 | Overview: [ 37 | { text: 'Introduction', link: 'introduction' }, 38 | { text: 'Install', link: 'install' }, 39 | ], 40 | Solid: [ 41 | { text: 'Install', link: 'solid/install' }, 42 | { text: 'query$', link: 'solid/query' }, 43 | { text: 'mutation$', link: 'solid/mutation' }, 44 | { text: 'reuseable$', link: 'solid/reuseable' }, 45 | { 46 | text: 'QueryProvider', 47 | link: 'solid/query-provider', 48 | }, 49 | ], 50 | 51 | API: [ 52 | { text: 'middleware$', link: 'middleware' }, 53 | { text: 'pipe$', link: 'pipe' }, 54 | { 55 | text: 'response$', 56 | link: 'response', 57 | }, 58 | { 59 | text: 'error$', 60 | link: 'error', 61 | }, 62 | { 63 | text: 'PRPCClientError', 64 | link: 'prpc-client-error', 65 | }, 66 | { 67 | text: 'hideRequest', 68 | link: 'hideRequest', 69 | }, 70 | ], 71 | References: [ 72 | { text: 'Contributors', link: 'contributors' }, 73 | { text: 'Sponsors', link: 'sponsors' }, 74 | ], 75 | } 76 | -------------------------------------------------------------------------------- /packages/compiler/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.production 74 | .env.development 75 | 76 | # parcel-bundler cache (https://parceljs.org/) 77 | .cache 78 | 79 | # Next.js build output 80 | .next 81 | 82 | # Nuxt.js build / generate output 83 | .nuxt 84 | dist 85 | 86 | # Gatsby files 87 | .cache/ 88 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 89 | # https://nextjs.org/blog/next-9-1#public-directory-support 90 | # public 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | 107 | .npmrc 108 | types -------------------------------------------------------------------------------- /packages/unplugin/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.production 74 | .env.development 75 | 76 | # parcel-bundler cache (https://parceljs.org/) 77 | .cache 78 | 79 | # Next.js build output 80 | .next 81 | 82 | # Nuxt.js build / generate output 83 | .nuxt 84 | dist 85 | 86 | # Gatsby files 87 | .cache/ 88 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 89 | # https://nextjs.org/blog/next-9-1#public-directory-support 90 | # public 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | 107 | .npmrc 108 | types -------------------------------------------------------------------------------- /packages/vite/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.production 74 | .env.development 75 | 76 | # parcel-bundler cache (https://parceljs.org/) 77 | .cache 78 | 79 | # Next.js build output 80 | .next 81 | 82 | # Nuxt.js build / generate output 83 | .nuxt 84 | dist 85 | 86 | # Gatsby files 87 | .cache/ 88 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 89 | # https://nextjs.org/blog/next-9-1#public-directory-support 90 | # public 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | 107 | .npmrc 108 | types -------------------------------------------------------------------------------- /examples/solidstart/src/server/queries.ts: -------------------------------------------------------------------------------- 1 | import { 2 | error$, 3 | hideRequest, 4 | middleware$, 5 | query$, 6 | response$, 7 | } from '@prpc/solid' 8 | import { z } from 'zod' 9 | import { middleware3, myMiddleware1, myProcedure } from './middleware' 10 | 11 | export const cleanSyntaxQuery = query$({ 12 | queryFn: async ({ payload, request$ }) => { 13 | console.log('called', request$.headers.get('user-agent'), payload.isServer) 14 | return response$( 15 | { result: payload.a + payload.b }, 16 | payload.isServer 17 | ? { 18 | headers: { 19 | 'set-cookie': 'solid-ssr-one=true', 20 | }, 21 | } 22 | : {} 23 | ) 24 | }, 25 | key: 'cleanSyntaxQuery', 26 | schema: z.object({ 27 | a: z.number().max(5), 28 | b: z.number().max(10), 29 | isServer: z.boolean().optional(), 30 | }), 31 | middlewares: [middleware3], 32 | }) 33 | 34 | export const authMw = middleware$(async () => { 35 | const session = {} as null | { user: Record | null } 36 | if (!session || !session.user) { 37 | return error$("You can't do that!") 38 | } 39 | return { 40 | session: { 41 | ...session, 42 | user: session.user, 43 | }, 44 | } 45 | }) 46 | 47 | export const add = query$( 48 | ({ payload, ctx$ }) => { 49 | console.log({ ctx$: hideRequest(ctx$) }) 50 | const result = payload.a + payload.b 51 | return response$( 52 | { result }, 53 | { 54 | headers: { 55 | 'set-cookie': 'solid-testing=1', 56 | }, 57 | } 58 | ) 59 | }, 60 | 'add', 61 | z.object({ 62 | a: z.number().max(5), 63 | b: z.number().max(10), 64 | }), 65 | middleware3 66 | ) 67 | 68 | export const decrease = query$( 69 | ({ payload }) => { 70 | const result = payload.a - payload.b 71 | return result 72 | }, 73 | 'decrease', 74 | z.object({ 75 | a: z.number(), 76 | b: z.number(), 77 | }) 78 | ) 79 | 80 | export const noInputQuery = query$( 81 | ({ ctx$ }) => { 82 | return `Hello ${ctx$.test}` 83 | }, 84 | 'noInputQuery', 85 | myMiddleware1 86 | ) 87 | 88 | export const testReuseQuery = myProcedure.query$({ 89 | queryFn: ({ ctx$ }) => { 90 | return `Hello ${ctx$.reuse}` 91 | }, 92 | key: 'testReuseQuery', 93 | }) 94 | -------------------------------------------------------------------------------- /docs/src/components/RightSidebar/MoreMenu.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import ThemeToggleButton from './ThemeToggleButton'; 3 | import { COMMUNITY_INVITE_URL } from '../../consts'; 4 | 5 | type Props = { 6 | editHref: string; 7 | }; 8 | 9 | const { editHref } = Astro.props; 10 | const showMoreSection = Boolean(COMMUNITY_INVITE_URL); 11 | --- 12 | 13 | {showMoreSection &&

More

} 14 | 68 |
69 | 70 |
71 | 72 | 80 | -------------------------------------------------------------------------------- /packages/core/src/types.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-types */ 2 | /* eslint-disable @typescript-eslint/no-explicit-any */ 3 | import type zod from 'zod' 4 | 5 | export type InferReturnType = T extends (...args: any[]) => infer R 6 | ? R extends Promise 7 | ? R2 8 | : R 9 | : never 10 | 11 | export type ValueOrAccessor = T extends undefined 12 | ? void | undefined 13 | : T | (() => T) 14 | 15 | export type FilterOutResponse = T extends Response 16 | ? never 17 | : T extends object 18 | ? { [K in keyof T]: FilterOutResponse } 19 | : T 20 | 21 | export type ExpectedInput = { 22 | payload: T 23 | request$: Request 24 | ctx$: Ctx 25 | } 26 | 27 | export type FlattenArray = T extends (infer U)[] ? U : T 28 | export type InferFinalMiddlware = 29 | (Mw extends [ 30 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 31 | ...infer _Start, 32 | infer Last 33 | ] 34 | ? InferReturnType 35 | : Mw extends IMiddleware 36 | ? InferReturnType 37 | : Mw extends any[] 38 | ? InferReturnType> 39 | : InferReturnType) & { 40 | request$: Request 41 | } 42 | 43 | export type ExpectedFn = ( 44 | props: ExpectedInput< 45 | T, 46 | FilterOutResponse>> 47 | > 48 | ) => any 49 | 50 | export type AsParam< 51 | Fn extends ExpectedFn, 52 | CAccessor extends boolean = true 53 | > = CAccessor extends true 54 | ? ValueOrAccessor[0]>> 55 | : UnwrapFnInput[0]> 56 | 57 | export type WithVoid = T extends undefined ? void | undefined : T 58 | export type UnwrapFnInput = WithVoid< 59 | T extends ExpectedInput ? B : T 60 | > 61 | 62 | export type OmitQueryData = Omit 63 | 64 | export type IMiddleware = (ctx$: T & { request$: Request }) => any 65 | 66 | export type ObjectParams< 67 | ZObj extends zod.ZodSchema | undefined | void, 68 | Mw extends IMiddleware[], 69 | Fn extends ExpectedFn< 70 | ZObj extends void | undefined 71 | ? void | undefined 72 | : ZObj extends zod.ZodSchema 73 | ? zod.infer 74 | : void | undefined, 75 | Mw 76 | >, 77 | isMutation extends boolean = false 78 | > = { 79 | key: string 80 | schema?: ZObj 81 | middlewares?: Mw 82 | } & (isMutation extends true 83 | ? { 84 | mutationFn: Fn 85 | } 86 | : { 87 | queryFn: Fn 88 | }) 89 | -------------------------------------------------------------------------------- /docs/src/components/RightSidebar/ThemeToggleButton.tsx: -------------------------------------------------------------------------------- 1 | import { Component, createEffect, createSignal, For } from "solid-js"; 2 | import "./ThemeToggleButton.css"; 3 | 4 | const themes = ["light", "dark"] as const; 5 | 6 | const icons = [ 7 | 14 | 19 | , 20 | 27 | 28 | , 29 | ]; 30 | 31 | const ThemeToggle: Component = () => { 32 | const [theme, setTheme] = createSignal<"light" | "dark">( 33 | ((): "light" | "dark" => { 34 | // @ts-ignore 35 | if (import.meta.env.SSR) { 36 | return "light"; 37 | } 38 | if (typeof localStorage !== undefined && localStorage.getItem("theme")) { 39 | return localStorage.getItem("theme") as "light" | "dark"; 40 | } 41 | if (window.matchMedia("(prefers-color-scheme: dark)").matches) { 42 | return "dark"; 43 | } 44 | return "light"; 45 | })() 46 | ); 47 | 48 | createEffect(() => { 49 | const root = document.documentElement; 50 | if (theme() === "light") { 51 | root.classList.remove("theme-dark"); 52 | } else { 53 | root.classList.add("theme-dark"); 54 | } 55 | }); 56 | 57 | return ( 58 |
59 | 60 | {(t, i) => { 61 | const icon = () => icons[i()]; 62 | const checked = () => t === theme(); 63 | return ( 64 | 79 | ); 80 | }} 81 | 82 |
83 | ); 84 | }; 85 | 86 | export default ThemeToggle; 87 | -------------------------------------------------------------------------------- /docs/src/content/docs/solid/mutation.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'mutation$' 3 | description: 'API for the mutation$ function' 4 | --- 5 | 6 | **API for the mutation$ function** 7 | 8 | Converts the function to be a `server$` function and will add in zod validation if there is a zod object in the 2nd argument. Returns a `createMutation` is from `@tanstack/solid-query`. 9 | 10 | If you want to modify the response headers / cookies, make sure to check out the [`response$`](/reply-with) docs. 11 | 12 | ## Syntax 13 | 14 | Currenly there are two ways to implement a mutation: 15 | 16 | ### Syntax 1 17 | 18 | ```ts 19 | import { mutation$ } from '@prpc/solid' 20 | import { z } from 'zod' 21 | export const cleanSyntaxMutation = mutation$({ 22 | mutationFn: ({ payload }) => { 23 | const result = payload.a - payload.b 24 | return result 25 | }, 26 | key: 'cleanSyntaxMutation', 27 | schema: z.object({ 28 | a: z.number(), 29 | b: z.number(), 30 | }), 31 | }) 32 | ``` 33 | 34 | ### Syntax 2 35 | 36 | ```ts 37 | import { mutation$ } from '@prpc/solid' 38 | import { z } from 'zod' 39 | import { isServer } from 'solid-js/web' 40 | 41 | export const decrease = mutation$( 42 | ({ payload }) => { 43 | const result = payload.a - payload.b 44 | console.log(isServer) 45 | console.log('add', result) 46 | return result 47 | }, 48 | 'decrease', // this will be used the mutation key 49 | z.object({ 50 | a: z.number(), 51 | b: z.number(), 52 | }) // this will be used as the input type and input validation 53 | ) 54 | ``` 55 | 56 | ### Client Usage 57 | 58 | ```ts 59 | import { 60 | createSignal, 61 | Match, 62 | Suspense, 63 | Switch, 64 | type VoidComponent, 65 | } from 'solid-js' 66 | import { decrease } from '~/server/mutations' 67 | 68 | const Mutation: VoidComponent = () => { 69 | const [num1, setNum1] = createSignal(1) 70 | const mutationRes = decrease() 71 | return ( 72 |
73 | 74 | 75 | 76 |
Num {mutationRes.data}
77 |
78 | 79 |
Error
80 |
81 |
82 | 85 |
86 | 96 |
97 | ) 98 | } 99 | ``` 100 | 101 | ## API 102 | 103 | ### Creation 104 | 105 | - First argument is the function to be wrapped with `server$` 106 | - Second argument is the mutation key for `@tanstack/solid-query` 107 | - Third argument is zod schema (optional) 108 | 109 | ### Usage 110 | 111 | Returns a `createMutation` from `@tanstack/solid-query` 112 | -------------------------------------------------------------------------------- /docs/src/components/Header/Search.tsx: -------------------------------------------------------------------------------- 1 | import "@docsearch/css"; 2 | import { createSignal, Show } from "solid-js"; 3 | import "./Search.css"; 4 | 5 | // import * as docSearchReact from '@docsearch/react'; 6 | 7 | /** FIXME: This is still kinda nasty, but DocSearch is not ESM ready. */ 8 | // const DocSearchModal = 9 | // docSearchReact.DocSearchModal || (docSearchReact as any).default.DocSearchModal; 10 | // const useDocSearchKeyboardEvents = 11 | // docSearchReact.useDocSearchKeyboardEvents || 12 | // (docSearchReact as any).default.useDocSearchKeyboardEvents; 13 | 14 | export default function Search() { 15 | const [isOpen, setIsOpen] = createSignal(false); 16 | const [initialQuery, setInitialQuery] = createSignal(""); 17 | 18 | let searchButtonRef: HTMLButtonElement | undefined; 19 | 20 | const onOpen = () => { 21 | setIsOpen(true); 22 | }; 23 | 24 | const onClose = () => { 25 | setIsOpen(false); 26 | }; 27 | 28 | const onInput = (e) => { 29 | setIsOpen(true); 30 | setInitialQuery(e.key); 31 | }; 32 | 33 | // useDocSearchKeyboardEvents({ 34 | // isOpen, 35 | // onOpen, 36 | // onClose, 37 | // onInput, 38 | // searchButtonRef, 39 | // }); 40 | 41 | return ( 42 | <> 43 | 69 | 70 | 71 | { 72 | // createPortal( 73 | // { 81 | // return items.map((item) => { 82 | // // We transform the absolute URL into a relative URL to 83 | // // work better on localhost, preview URLS. 84 | // const a = document.createElement('a'); 85 | // a.href = item.url; 86 | // const hash = a.hash === '#overview' ? '' : a.hash; 87 | // return { 88 | // ...item, 89 | // url: `${a.pathname}${hash}`, 90 | // }; 91 | // }); 92 | // }} 93 | // />, 94 | // document.body 95 | // )} 96 | } 97 | 98 | 99 | ); 100 | } 101 | -------------------------------------------------------------------------------- /docs/src/content/docs/solid/query.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'query$' 3 | description: 'API for the query$ function' 4 | --- 5 | 6 | **API for the query$ function** 7 | 8 | Converts the function to be a `server$` function and will add in zod validation if there is a zod object in the 2nd argument. Return object has `createQuery` method on it from `@tanstack/solid-query`. 9 | 10 | If you want to modify the response headers / cookies, make sure to check out the [`response$`](/reply-with) docs. 11 | 12 | ## Syntax 13 | 14 | Currently there are two ways to implement a query 15 | 16 | ### Syntax 1 17 | 18 | ```ts 19 | import { query$, response$ } from '@prpc/solid' 20 | import { z } from 'zod' 21 | export const cleanSyntaxQuery = query$({ 22 | queryFn: async ({ payload }) => { 23 | return { result: payload.a + payload.b } 24 | }, 25 | key: 'cleanSyntaxQuery', 26 | schema: z.object({ 27 | a: z.number().max(5), 28 | b: z.number().max(10), 29 | }), 30 | }) 31 | ``` 32 | 33 | ### Syntax 2 34 | 35 | ```ts 36 | import { query$, response$ } from '@prpc/solid' 37 | import { z } from 'zod' 38 | 39 | export const add = query$( 40 | ({ payload, request$ }) => { 41 | const result = payload.a + payload.b 42 | console.log(request$.headers.get('user-agent')) 43 | return response$(result, { 44 | headers: { 45 | 'set-cookie': 'solid-testing=1', 46 | }, 47 | }) 48 | }, 49 | 'add', 50 | z.object({ 51 | a: z.number(), 52 | b: z.number(), 53 | }) 54 | ) 55 | ``` 56 | 57 | ## Examples 58 | 59 | ```ts 60 | import { query$ } from '@prpc/solid' 61 | import { z } from 'zod' 62 | import { isServer } from 'solid-js/web' 63 | 64 | export const decrease = query$( 65 | ({ payload }) => { 66 | const result = payload.a - payload.b 67 | console.log(isServer) 68 | console.log('add', result) 69 | return result 70 | }, 71 | 'decrease', // this will be used as the query key (along with the input) 72 | z.object({ 73 | a: z.number(), 74 | b: z.number(), 75 | }) // this will be used as the input type and input validation 76 | ) 77 | ``` 78 | 79 | ### Client Usage 80 | 81 | ```ts 82 | import { createSignal, Suspense, type VoidComponent } from 'solid-js' 83 | import { decrease } from '~/server/queries' 84 | 85 | const Query: VoidComponent = () => { 86 | const [num1, setNum1] = createSignal(1) 87 | const addRes = decrease( 88 | () => ({ 89 | a: num1(), 90 | b: 2, 91 | }), 92 | () => ({ 93 | placeholderData: (prev) => prev, 94 | }) 95 | ) 96 | 97 | return ( 98 |
99 | 100 |

{addRes.data ? `Num: ${addRes.data}` : 'Pending'}

101 |
102 | 103 |
104 | ) 105 | } 106 | ``` 107 | 108 | ## API 109 | 110 | - First argument is the function to be wrapped with `server$` 111 | - Second argument is the mutation key for `@tanstack/solid-query` 112 | - Third argument is zod schema (optional) 113 | 114 | ### Usage 115 | 116 | Returns an object with `createQuery` from `@tanstack/solid-query` 117 | -------------------------------------------------------------------------------- /packages/vite/test/plugin.test.ts: -------------------------------------------------------------------------------- 1 | import { transform } from '@babel/core' 2 | import { expect, test } from 'vitest' 3 | import { transformpRPC$ } from '@prpc/core' 4 | 5 | const inputCode = ` 6 | export const add = query$( 7 | ({ payload, request$ }) => { 8 | const result = payload.a + payload.b 9 | console.log(isServer /* true */) 10 | console.log('add', result) 11 | console.log(request$.headers.get('user-agent')) 12 | return result 13 | }, 14 | 'add', 15 | z.object({ 16 | a: z.number(), 17 | b: z.number(), 18 | }) 19 | ) 20 | export const addM = mutation$( 21 | ({ payload, request$ }) => { 22 | const result = payload.a + payload.b 23 | console.log(isServer /* true */) 24 | console.log('add', result) 25 | console.log(request$.headers.get('user-agent')) 26 | return result 27 | }, 28 | 'add', 29 | z.object({ 30 | a: z.number(), 31 | b: z.number(), 32 | }) 33 | ) 34 | 35 | export const decrease = query$( 36 | ({ payload }) => { 37 | const result = payload.a - payload.b 38 | console.log(isServer) 39 | console.log('add', result) 40 | return result 41 | }, 'decrease') 42 | 43 | export const decreaseM = mutation$( 44 | ({ payload }) => { 45 | const result = payload.a - payload.b 46 | console.log(isServer) 47 | console.log('add', result) 48 | return result 49 | }, 'decrease')` 50 | 51 | const transformedCode = ` 52 | import { callMiddleware$ } from "@prpc/solid"; 53 | import server$ from "solid-start/server"; 54 | export const add = query$(server$(async ({ 55 | payload 56 | }) => { 57 | const schema = z.object({ 58 | a: z.number(), 59 | b: z.number() 60 | }); 61 | await schema.parseAsync(payload); 62 | const result = payload.a + payload.b; 63 | console.log(isServer /* true */); 64 | console.log('add', result); 65 | console.log(server$.request.headers.get('user-agent')); 66 | return result; 67 | }), 'add'); 68 | export const addM = mutation$(server$(async ({ 69 | payload 70 | }) => { 71 | const schema = z.object({ 72 | a: z.number(), 73 | b: z.number() 74 | }); 75 | await schema.parseAsync(payload); 76 | const result = payload.a + payload.b; 77 | console.log(isServer /* true */); 78 | console.log('add', result); 79 | console.log(server$.request.headers.get('user-agent')); 80 | return result; 81 | }), 'add'); 82 | export const decrease = query$(server$(async ({ 83 | payload 84 | }) => { 85 | const result = payload.a - payload.b; 86 | console.log(isServer); 87 | console.log('add', result); 88 | return result; 89 | }), 'decrease'); 90 | export const decreaseM = mutation$(server$(async ({ 91 | payload 92 | }) => { 93 | const result = payload.a - payload.b; 94 | console.log(isServer); 95 | console.log('add', result); 96 | return result; 97 | }), 'decrease'); 98 | ` 99 | 100 | test('transformpRPC$ transformations', () => { 101 | const output = transform(inputCode.trim(), { 102 | presets: ['@babel/preset-typescript'], 103 | plugins: [transformpRPC$], 104 | filename: 'testing', 105 | }) 106 | expect(output).not.toBeNull() 107 | // eslint-disable-next-line 108 | expect(output!.code).toEqual(transformedCode.trim()) 109 | }) 110 | -------------------------------------------------------------------------------- /docs/src/components/RightSidebar/TableOfContents.tsx: -------------------------------------------------------------------------------- 1 | import type { MarkdownHeading } from "astro"; 2 | import { unescape } from "html-escaper"; 3 | import { Component, createEffect, createSignal, For } from "solid-js"; 4 | 5 | type ItemOffsets = { 6 | id: string; 7 | topOffset: number; 8 | }; 9 | 10 | const TableOfContents: Component<{ headings: MarkdownHeading[] }> = ({ 11 | headings = [], 12 | }) => { 13 | let toc: HTMLUListElement | undefined; 14 | let itemOffsets: ItemOffsets[] = []; 15 | 16 | const onThisPageID = "on-this-page-heading"; 17 | const [currentID, setCurrentID] = createSignal("overview"); 18 | 19 | createEffect(() => { 20 | const getItemOffsets = () => { 21 | const titles = document.querySelectorAll("article :is(h1, h2, h3, h4)"); 22 | itemOffsets = Array.from(titles).map((title) => ({ 23 | id: title.id, 24 | topOffset: title.getBoundingClientRect().top + window.scrollY, 25 | })); 26 | }; 27 | 28 | getItemOffsets(); 29 | window.addEventListener("resize", getItemOffsets); 30 | 31 | return () => { 32 | window.removeEventListener("resize", getItemOffsets); 33 | }; 34 | }); 35 | 36 | createEffect(() => { 37 | if (!toc) return; 38 | 39 | const setCurrent: IntersectionObserverCallback = (entries) => { 40 | for (const entry of entries) { 41 | if (entry.isIntersecting) { 42 | const { id } = entry.target; 43 | if (id === onThisPageID) continue; 44 | setCurrentID(entry.target.id); 45 | break; 46 | } 47 | } 48 | }; 49 | 50 | const observerOptions: IntersectionObserverInit = { 51 | // Negative top margin accounts for `scroll-margin`. 52 | // Negative bottom margin means heading needs to be towards top of viewport to trigger intersection. 53 | rootMargin: "-100px 0% -66%", 54 | threshold: 1, 55 | }; 56 | 57 | const headingsObserver = new IntersectionObserver( 58 | setCurrent, 59 | observerOptions 60 | ); 61 | 62 | // Observe all the headings in the main page content. 63 | document 64 | .querySelectorAll("article :is(h1,h2,h3)") 65 | .forEach((h) => headingsObserver.observe(h)); 66 | 67 | // Stop observing when the component is unmounted. 68 | return () => headingsObserver.disconnect(); 69 | }); 70 | 71 | const onLinkClick = (e) => { 72 | setCurrentID(e.target.getAttribute("href").replace("#", "")); 73 | }; 74 | 75 | return ( 76 | <> 77 |

78 | On this page 79 |

80 | 95 | 96 | ); 97 | }; 98 | 99 | export default TableOfContents; 100 | -------------------------------------------------------------------------------- /docs/src/components/Header/Header.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { SITE } from '../../consts' 3 | import Search from './Search' 4 | import SidebarToggle from './SidebarToggle' 5 | import SkipToContent from './SkipToContent.astro' 6 | type Props = { 7 | currentPage: string 8 | } 9 | 10 | --- 11 | 12 |
13 | 14 | 29 |
30 | 31 | 139 | 140 | 145 | -------------------------------------------------------------------------------- /packages/solid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@prpc/solid", 3 | "description": "Package for easily creating server rpc functions in solid-start with goodies baked in", 4 | "version": "0.2.35", 5 | "scripts": { 6 | "build": "rm -rf dist && tsup --config ../../tsup.config.js", 7 | "clean": "rm -rf ./node_modules dist .turbo .solid", 8 | "dev": "rm -rf dist && tsup --config ../../tsup.config.js --watch", 9 | "lint": "eslint . --fix --ext .ts,.tsx,.js,.jsx", 10 | "typecheck": "tsc --noEmit" 11 | }, 12 | "type": "module", 13 | "exports": { 14 | "worker": { 15 | "solid": "./dist/server.jsx", 16 | "import": { 17 | "types": "./dist/index.d.ts", 18 | "default": "./dist/server.js" 19 | }, 20 | "require": "./dist/server.cjs" 21 | }, 22 | "browser": { 23 | "solid": { 24 | "development": "./dist/dev.jsx", 25 | "import": "./dist/index.jsx" 26 | }, 27 | "development": { 28 | "import": { 29 | "types": "./dist/index.d.ts", 30 | "default": "./dist/dev.js" 31 | }, 32 | "require": "./dist/dev.cjs" 33 | }, 34 | "import": { 35 | "types": "./dist/index.d.ts", 36 | "default": "./dist/index.js" 37 | }, 38 | "require": "./dist/index.cjs" 39 | }, 40 | "deno": { 41 | "solid": "./dist/server.jsx", 42 | "import": { 43 | "types": "./dist/index.d.ts", 44 | "default": "./dist/server.js" 45 | }, 46 | "require": "./dist/server.cjs" 47 | }, 48 | "node": { 49 | "solid": "./dist/server.jsx", 50 | "import": { 51 | "types": "./dist/index.d.ts", 52 | "default": "./dist/server.js" 53 | }, 54 | "require": "./dist/server.cjs" 55 | }, 56 | "solid": { 57 | "development": "./dist/dev.jsx", 58 | "import": "./dist/index.jsx" 59 | }, 60 | "development": { 61 | "import": { 62 | "types": "./dist/index.d.ts", 63 | "default": "./dist/dev.js" 64 | }, 65 | "require": "./dist/dev.cjs" 66 | }, 67 | "import": { 68 | "types": "./dist/index.d.ts", 69 | "default": "./dist/index.js" 70 | }, 71 | "require": "./dist/index.cjs" 72 | }, 73 | "main": "./dist/server.cjs", 74 | "types": "./dist/index.d.ts", 75 | "files": [ 76 | "dist", 77 | "README.md" 78 | ], 79 | "browser": { 80 | "./dist/server.js": "./dist/index.js", 81 | "./dist/server.cjs": "./dist/index.cjs" 82 | }, 83 | "devDependencies": { 84 | "@types/node": "^18.7.14", 85 | "@typescript-eslint/parser": "^5.44.0", 86 | "solid-js": "^1.7.9", 87 | "typescript": "^4.8.2", 88 | "zod": "^3.20.6", 89 | "@tanstack/solid-query": "^5.0.0-beta.15", 90 | "solid-start": "^0.2.30" 91 | }, 92 | "dependencies": { 93 | "@prpc/core": "workspace:*" 94 | }, 95 | "peerDependencies": { 96 | "@tanstack/solid-query": "^5.0.0-beta.15", 97 | "zod": "^3.20.6", 98 | "solid-start": "^0.2.30", 99 | "solid-js": "^1.7.9" 100 | }, 101 | "peerDependenciesMeta": { 102 | "zod": { 103 | "optional": true 104 | } 105 | }, 106 | "engines": { 107 | "node": ">=16" 108 | }, 109 | "typesVersions": {}, 110 | "module": "./dist/server.js" 111 | } 112 | -------------------------------------------------------------------------------- /docs/src/components/LeftSidebar/LeftSidebar.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { SIDEBAR } from '../../consts' 3 | 4 | type Props = { 5 | currentPage: string 6 | } 7 | 8 | const { currentPage } = Astro.props 9 | const currentPageMatch = currentPage.endsWith('/') 10 | ? currentPage.slice(1, -1) 11 | : currentPage.slice(1) 12 | const sidebar = SIDEBAR 13 | --- 14 | 15 | 45 | 46 | 54 | 55 | 122 | 123 | 128 | -------------------------------------------------------------------------------- /packages/solid/src/query.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import { 3 | createQuery, 4 | type FunctionedParams, 5 | type QueryKey, 6 | type CreateQueryResult, 7 | type SolidQueryOptions, 8 | } from '@tanstack/solid-query' 9 | import type zod from 'zod' 10 | import { 11 | type InferReturnType, 12 | type ExpectedFn, 13 | type AsParam, 14 | type IMiddleware, 15 | type OmitQueryData, 16 | type PRPCClientError, 17 | type ObjectParams, 18 | genQueryKey, 19 | tryAndWrap, 20 | unwrapValue, 21 | } from '@prpc/core' 22 | import { getParams } from '@prpc/core' 23 | import { useRequest } from 'solid-start/server' 24 | import { genHandleResponse } from '.' 25 | 26 | export type FCreateQueryOptions< 27 | TQueryFnData = unknown, 28 | TError = PRPCClientError, 29 | TData = TQueryFnData, 30 | TQueryKey extends QueryKey = QueryKey 31 | > = FunctionedParams< 32 | OmitQueryData> 33 | > 34 | 35 | export type ExpectedQueryReturn< 36 | Mw extends IMiddleware[], 37 | Fn extends ExpectedFn< 38 | ZObj extends void | undefined 39 | ? void | undefined 40 | : ZObj extends zod.ZodSchema 41 | ? zod.infer 42 | : void | undefined, 43 | Mw 44 | >, 45 | ZObj extends zod.ZodSchema | void | undefined = void | undefined 46 | > = ( 47 | input: AsParam, 48 | queryOpts?: FCreateQueryOptions< 49 | InferReturnType, 50 | PRPCClientError : any> 51 | > 52 | ) => CreateQueryResult< 53 | InferReturnType, 54 | PRPCClientError : any> 55 | > 56 | 57 | export function query$< 58 | Mw extends IMiddleware[], 59 | Fn extends ExpectedFn< 60 | ZObj extends void | undefined 61 | ? void | undefined 62 | : ZObj extends zod.ZodSchema 63 | ? zod.infer 64 | : void | undefined, 65 | Mw 66 | >, 67 | ZObj extends zod.ZodSchema | void | undefined = void | undefined 68 | >(params: ObjectParams): ExpectedQueryReturn 69 | 70 | export function query$< 71 | Mw extends IMiddleware[], 72 | Fn extends ExpectedFn 73 | >( 74 | queryFn: Fn, 75 | key: string, 76 | ..._middlewares: Mw 77 | ): ExpectedQueryReturn 78 | 79 | export function query$< 80 | ZObj extends zod.ZodSchema | void | undefined, 81 | Mw extends IMiddleware[], 82 | Fn extends ExpectedFn< 83 | ZObj extends void | undefined 84 | ? void | undefined 85 | : ZObj extends zod.ZodSchema 86 | ? zod.infer 87 | : void | undefined, 88 | Mw 89 | > 90 | >( 91 | queryFn: Fn, 92 | key: string, 93 | _schema?: ZObj, 94 | ..._middlewares: Mw 95 | ): ExpectedQueryReturn 96 | 97 | export function query$< 98 | ZObj extends zod.ZodSchema | undefined, 99 | Mw extends IMiddleware[], 100 | Fn extends ExpectedFn< 101 | ZObj extends zod.ZodSchema ? zod.infer : undefined, 102 | Mw 103 | > 104 | >(...args: any[]) { 105 | const { key, queryFn } = getParams(false, ...args) 106 | return ( 107 | input: AsParam, 108 | queryOpts?: FCreateQueryOptions< 109 | InferReturnType, 110 | PRPCClientError : any> 111 | > 112 | ) => { 113 | const event = useRequest() 114 | return createQuery(() => ({ 115 | queryKey: genQueryKey(key, unwrapValue(input)), 116 | queryFn: () => tryAndWrap(queryFn, input, genHandleResponse(event)), 117 | ...((queryOpts?.() || {}) as any), 118 | })) 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /packages/solid/src/mutation.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import { 3 | createMutation, 4 | type FunctionedParams, 5 | type SolidMutationOptions, 6 | type CreateMutationResult, 7 | } from '@tanstack/solid-query' 8 | import type zod from 'zod' 9 | import { 10 | type IMiddleware, 11 | type InferReturnType, 12 | type ExpectedFn, 13 | type AsParam, 14 | type OmitQueryData, 15 | type PRPCClientError, 16 | type ObjectParams, 17 | genQueryKey, 18 | tryAndWrap, 19 | getParams, 20 | } from '@prpc/core' 21 | import { useRequest } from 'solid-start/server' 22 | import { genHandleResponse } from '.' 23 | 24 | export type FCreateMutationOptions< 25 | TData = unknown, 26 | TError = PRPCClientError, 27 | TVariables = void, 28 | TContext = unknown 29 | > = FunctionedParams< 30 | OmitQueryData> 31 | > 32 | 33 | export type ExpectedMutationReturn< 34 | Mw extends IMiddleware[], 35 | Fn extends ExpectedFn< 36 | ZObj extends void | undefined 37 | ? void | undefined 38 | : ZObj extends zod.ZodSchema 39 | ? zod.infer 40 | : void | undefined, 41 | Mw 42 | >, 43 | ZObj extends zod.ZodSchema | void | undefined = void | undefined 44 | > = ( 45 | mutationOpts?: FCreateMutationOptions< 46 | InferReturnType, 47 | PRPCClientError : any>, 48 | AsParam 49 | > 50 | ) => CreateMutationResult< 51 | InferReturnType, 52 | PRPCClientError : any>, 53 | AsParam 54 | > 55 | 56 | export function mutation$< 57 | Mw extends IMiddleware[], 58 | Fn extends ExpectedFn< 59 | ZObj extends void | undefined 60 | ? void | undefined 61 | : ZObj extends zod.ZodSchema 62 | ? zod.infer 63 | : void | undefined, 64 | Mw 65 | >, 66 | ZObj extends zod.ZodSchema | void | undefined = void | undefined 67 | >( 68 | params: ObjectParams 69 | ): ExpectedMutationReturn 70 | 71 | export function mutation$< 72 | Mw extends IMiddleware[], 73 | Fn extends ExpectedFn 74 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 75 | >(queryFn: Fn, key: string, ..._middlewares: Mw): ExpectedMutationReturn 76 | 77 | export function mutation$< 78 | ZObj extends zod.ZodSchema | undefined, 79 | Mw extends IMiddleware[], 80 | Fn extends ExpectedFn< 81 | ZObj extends void | undefined 82 | ? void | undefined 83 | : ZObj extends zod.ZodSchema 84 | ? zod.infer 85 | : void | undefined, 86 | Mw 87 | > 88 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 89 | >( 90 | queryFn: Fn, 91 | key: string, 92 | _schema?: ZObj, 93 | ..._middlewares: Mw 94 | ): ExpectedMutationReturn 95 | 96 | export function mutation$< 97 | ZObj extends zod.ZodSchema | undefined, 98 | Mw extends IMiddleware[], 99 | Fn extends ExpectedFn< 100 | ZObj extends zod.ZodSchema ? zod.infer : undefined, 101 | Mw 102 | > 103 | >(...args: any[]) { 104 | const { key, queryFn } = getParams(true, ...args) 105 | return ( 106 | mutationOpts?: FCreateMutationOptions< 107 | InferReturnType, 108 | PRPCClientError : any>, 109 | AsParam 110 | > 111 | ) => { 112 | const event = useRequest() 113 | return createMutation(() => ({ 114 | mutationKey: genQueryKey(key, undefined, true), 115 | mutationFn: (input: AsParam) => 116 | tryAndWrap(queryFn, input, genHandleResponse(event)), 117 | ...((mutationOpts?.() || {}) as any), 118 | })) as CreateMutationResult< 119 | InferReturnType, 120 | PRPCClientError : any>, 121 | AsParam 122 | > 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /docs/src/layouts/MainLayout.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import type { MarkdownHeading } from 'astro' 3 | import type { CollectionEntry } from 'astro:content' 4 | import Footer from '../components/Footer/Footer.astro' 5 | import HeadCommon from '../components/HeadCommon.astro' 6 | import Header from '../components/Header/Header.astro' 7 | import HeadSEO from '../components/HeadSEO.astro' 8 | import LeftSidebar from '../components/LeftSidebar/LeftSidebar.astro' 9 | import PageContent from '../components/PageContent/PageContent.astro' 10 | import RightSidebar from '../components/RightSidebar/RightSidebar.astro' 11 | import { GITHUB_EDIT_URL, SITE } from '../consts' 12 | 13 | type Props = CollectionEntry<'docs'>['data'] & { 14 | headings: MarkdownHeading[] 15 | } 16 | 17 | const { headings, ...data } = Astro.props 18 | const canonicalURL = new URL(Astro.url.pathname, Astro.site) 19 | const currentPage = Astro.url.pathname 20 | const currentFile = `src/content/docs${currentPage.replace(/\/$/, '')}.mdx` 21 | const githubEditUrl = `${GITHUB_EDIT_URL}/${currentFile}` 22 | --- 23 | 24 | 25 | 26 | 27 | 28 | 29 | {`${data.title} | ${SITE.title}`} 30 | 31 | 32 | 106 | 121 | 122 | 123 | 124 |
125 |
126 | 129 |
130 | 135 | 136 | 137 |
138 | 141 |
142 |