├── .nvmrc ├── packages ├── .gitkeep └── javascript │ └── node │ ├── jsr.json │ ├── tsconfig.json │ ├── src │ ├── lib │ │ ├── limiter │ │ │ ├── host │ │ │ │ ├── index.ts │ │ │ │ ├── adapters │ │ │ │ │ └── storage │ │ │ │ │ │ ├── redis │ │ │ │ │ │ └── UpstashRedisAdapter.ts │ │ │ │ │ │ └── StorageAdapter.ts │ │ │ │ ├── algorithms.ts │ │ │ │ ├── limiter.ts │ │ │ │ └── limiter.spec.ts │ │ │ ├── utils.ts │ │ │ ├── tokens.ts │ │ │ ├── types.ts │ │ │ └── limiter.ts │ │ ├── client.spec.ts │ │ ├── client.ts │ │ └── utils.ts │ └── index.ts │ ├── vite.config.ts │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ ├── package.json │ └── README.md ├── apps ├── docs │ ├── .gitignore │ ├── src │ │ └── app │ │ │ ├── globals.css │ │ │ ├── favicon.ico │ │ │ ├── favicon.png │ │ │ ├── twitter-image.png │ │ │ ├── opengraph-image.png │ │ │ ├── _meta.ts │ │ │ ├── limiter │ │ │ ├── integrations │ │ │ │ ├── page.mdx │ │ │ │ ├── _meta.ts │ │ │ │ └── supabase │ │ │ │ │ └── page.mdx │ │ │ ├── _meta.ts │ │ │ ├── page.mdx │ │ │ ├── algorithms │ │ │ │ └── page.mdx │ │ │ ├── self-hosting │ │ │ │ └── page.mdx │ │ │ └── quick-start │ │ │ │ └── page.mdx │ │ │ ├── favicon.svg │ │ │ ├── page.mdx │ │ │ └── layout.tsx │ ├── postcss.config.mjs │ ├── index.d.ts │ ├── next-env.d.ts │ ├── mdx-components.js │ ├── package.json │ ├── next.config.ts │ ├── .swcrc │ ├── public │ │ └── logo.svg │ └── tsconfig.json ├── cli │ ├── src │ │ ├── lib.rs │ │ ├── main.rs │ │ └── start │ │ │ ├── lib │ │ │ ├── mod.rs │ │ │ ├── download_template.rs │ │ │ ├── prompt.rs │ │ │ ├── utils.rs │ │ │ └── install_template.rs │ │ │ └── mod.rs │ ├── Cargo.toml │ └── project.json └── README.md ├── .prettierrc ├── .cargo └── config.toml ├── .prettierignore ├── .vscode ├── extensions.json └── settings.json ├── Cargo.toml ├── vitest.workspace.ts ├── vercel.json ├── tsconfig.json ├── tsconfig.base.json ├── .gitignore ├── LICENSE ├── package.json ├── .github └── workflows │ └── ci.yml ├── nx.json ├── README.md └── Cargo.lock /.nvmrc: -------------------------------------------------------------------------------- 1 | 22.14.0 -------------------------------------------------------------------------------- /packages/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/docs/.gitignore: -------------------------------------------------------------------------------- 1 | _pagefind/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": false 3 | } 4 | -------------------------------------------------------------------------------- /apps/docs/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target-dir = 'dist/target' 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /coverage 3 | /.nx/cache 4 | /.nx/workspace-data 5 | 6 | package-lock.json 7 | **/*.mdx -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["esbenp.prettier-vscode", "denoland.vscode-deno"] 3 | } 4 | -------------------------------------------------------------------------------- /apps/docs/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/borrowdev/borrow/HEAD/apps/docs/src/app/favicon.ico -------------------------------------------------------------------------------- /apps/docs/src/app/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/borrowdev/borrow/HEAD/apps/docs/src/app/favicon.png -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [workspace] 3 | resolver = '2' 4 | members = ['apps/cli'] 5 | 6 | [profile.release] 7 | lto = true 8 | -------------------------------------------------------------------------------- /apps/docs/src/app/twitter-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/borrowdev/borrow/HEAD/apps/docs/src/app/twitter-image.png -------------------------------------------------------------------------------- /apps/docs/src/app/opengraph-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/borrowdev/borrow/HEAD/apps/docs/src/app/opengraph-image.png -------------------------------------------------------------------------------- /vitest.workspace.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | "**/vite.config.{mjs,js,ts,mts}", 3 | "**/vitest.config.{mjs,js,ts,mts}", 4 | ]; 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "prettier.prettierPath": "node_modules/prettier", 3 | "prettier.ignorePath": ".prettierignore" 4 | } 5 | -------------------------------------------------------------------------------- /apps/docs/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | const config = { 2 | plugins: { 3 | "@tailwindcss/postcss": {}, 4 | }, 5 | }; 6 | export default config; 7 | -------------------------------------------------------------------------------- /apps/docs/index.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | declare module "*.svg" { 3 | const content: any; 4 | export const ReactComponent: any; 5 | export default content; 6 | } 7 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://openapi.vercel.sh/vercel.json", 3 | "buildCommand": "npx nx build docs --prod && npx nx run docs:postbuild", 4 | "outputDirectory": "apps/docs/.next", 5 | "framework": "nextjs" 6 | } 7 | -------------------------------------------------------------------------------- /apps/docs/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compileOnSave": false, 4 | "files": [], 5 | "references": [ 6 | { 7 | "path": "./packages/javascript/node" 8 | }, 9 | { 10 | "path": "./apps/docs" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/javascript/node/jsr.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@borrow/node", 3 | "version": "0.2.0", 4 | "exports": "./dist/index.d.ts", 5 | "license": "MIT", 6 | "include": ["jsr.json", "./dist/**/*", "README.md"], 7 | "publish": { 8 | "exclude": ["!dist"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /apps/docs/src/app/_meta.ts: -------------------------------------------------------------------------------- 1 | import type { MetaRecord } from "nextra"; 2 | const meta: MetaRecord = { 3 | index: { 4 | href: "/", 5 | title: "Introduction", 6 | }, 7 | limiter: { 8 | href: "/limiter", 9 | title: "Limiter", 10 | }, 11 | }; 12 | export default meta; 13 | -------------------------------------------------------------------------------- /apps/docs/src/app/limiter/integrations/page.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Borrow | Integrations Overview 3 | description: Overview for Borrow integrations 4 | --- 5 | 6 | # Integrations 7 | 8 | Hi there! You're probably looking for one of the more [specific](/limiter/integrations/supabase) integration pages. -------------------------------------------------------------------------------- /apps/cli/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::path::PathBuf; 2 | 3 | use dirs::data_dir; 4 | 5 | pub fn get_root_data_dir() -> PathBuf { 6 | let data_dir = data_dir(); 7 | match data_dir { 8 | Some(path) => path.join("borrow"), 9 | None => PathBuf::from("./.borrow"), 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/javascript/node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "files": [], 4 | "include": [], 5 | "references": [ 6 | { 7 | "path": "./tsconfig.lib.json" 8 | }, 9 | { 10 | "path": "./tsconfig.spec.json" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/javascript/node/src/lib/limiter/host/index.ts: -------------------------------------------------------------------------------- 1 | import { UpstashRedisAdapter } from "./adapters/storage/redis/UpstashRedisAdapter.js"; 2 | import { StorageAdapter } from "./adapters/storage/StorageAdapter.js"; 3 | import { limiter } from "./limiter.js"; 4 | 5 | export { limiter, StorageAdapter, UpstashRedisAdapter }; 6 | -------------------------------------------------------------------------------- /apps/docs/src/app/limiter/integrations/_meta.ts: -------------------------------------------------------------------------------- 1 | import type { MetaRecord } from "nextra"; 2 | const meta: MetaRecord = { 3 | index: { 4 | href: "/limiter/integrations", 5 | title: "Overview", 6 | }, 7 | supabase: { 8 | href: "/limiter/integrations/supabase", 9 | title: "Supabase", 10 | }, 11 | }; 12 | export default meta; 13 | -------------------------------------------------------------------------------- /apps/docs/mdx-components.js: -------------------------------------------------------------------------------- 1 | import { useMDXComponents as getThemeComponents } from "nextra-theme-docs"; // nextra-theme-blog or your custom theme 2 | 3 | // Get the default MDX components 4 | const themeComponents = getThemeComponents(); 5 | 6 | // Merge components 7 | export function useMDXComponents(components) { 8 | return { 9 | ...themeComponents, 10 | ...components, 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@borrowdev/docs", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "postbuild": "pagefind --site .next/server/app --output-path public/_pagefind" 7 | }, 8 | "dependencies": { 9 | "@tailwindcss/postcss": "^4.1.4", 10 | "next": "^15", 11 | "nextra": "^4.2.17", 12 | "nextra-theme-docs": "^4.2.17", 13 | "postcss": "^8.5.3", 14 | "react": "19.0.0", 15 | "react-dom": "19.0.0", 16 | "tailwindcss": "^4.1.4" 17 | }, 18 | "devDependencies": { 19 | "pagefind": "^1.3.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "declarationMap": true, 5 | "emitDeclarationOnly": true, 6 | "importHelpers": true, 7 | "isolatedModules": true, 8 | "lib": ["es2022"], 9 | "module": "ES6", 10 | "moduleResolution": "bundler", 11 | "noEmitOnError": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "noImplicitOverride": true, 14 | "noImplicitReturns": true, 15 | "noUnusedLocals": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "es2022", 19 | "customConditions": ["development"] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /apps/docs/next.config.ts: -------------------------------------------------------------------------------- 1 | import { composePlugins, withNx } from "@nx/next"; 2 | import nextra from "nextra"; 3 | import type { WithNxOptions } from "@nx/next/plugins/with-nx"; 4 | 5 | const nextConfig: WithNxOptions = { 6 | nx: { 7 | svgr: false, 8 | }, 9 | basePath: "/docs", 10 | assetPrefix: "/docs", 11 | }; 12 | 13 | const withNextra = nextra({ 14 | codeHighlight: true, 15 | defaultShowCopyCode: true, 16 | readingTime: false, 17 | search: { 18 | codeblocks: false, 19 | }, 20 | }); 21 | 22 | const plugins = [withNextra, withNx]; 23 | 24 | module.exports = composePlugins(...plugins)(nextConfig); 25 | -------------------------------------------------------------------------------- /packages/javascript/node/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | 3 | export default defineConfig(() => ({ 4 | root: __dirname, 5 | cacheDir: "../../../node_modules/.vite/packages/javascript/node", 6 | plugins: [], 7 | // Uncomment this if you are using workers. 8 | // worker: { 9 | // plugins: [ nxViteTsPaths() ], 10 | // }, 11 | test: { 12 | watch: false, 13 | globals: true, 14 | environment: "node", 15 | include: ["src/**/*.spec.ts"], 16 | reporters: ["default"], 17 | coverage: { 18 | reportsDirectory: "./test-output/vitest/coverage", 19 | provider: "v8" as const, 20 | }, 21 | }, 22 | })); 23 | -------------------------------------------------------------------------------- /apps/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "borrow-dev" 3 | version = "0.1.0" 4 | authors=["Lorenzo Bloedow "] 5 | license = "MIT" 6 | edition = "2024" 7 | description = "Official CLI for Borrow tools" 8 | homepage = "https://github.com/borrowdev/borrow" 9 | repository = "https://github.com/borrowdev/borrow" 10 | keywords = ["cli", "toolkit", "template", "boilerplate"] 11 | categories = ["command-line-utilities"] 12 | 13 | [[bin]] 14 | name = "borrow" 15 | path = "src/main.rs" 16 | 17 | [dependencies] 18 | clap = { version = "4.5.37", features = ["derive", "unicode", "wrap_help"] } 19 | inquire = "0.7.5" 20 | walkdir = "2" 21 | dirs = "6" 22 | git2 = "0.20.2" -------------------------------------------------------------------------------- /apps/docs/.swcrc: -------------------------------------------------------------------------------- 1 | { 2 | "jsc": { 3 | "target": "es2017", 4 | "parser": { 5 | "syntax": "typescript", 6 | "decorators": true, 7 | "dynamicImport": true 8 | }, 9 | "transform": { 10 | "decoratorMetadata": true, 11 | "legacyDecorator": true 12 | }, 13 | "keepClassNames": true, 14 | "externalHelpers": true, 15 | "loose": true 16 | }, 17 | "module": { 18 | "type": "commonjs" 19 | }, 20 | "sourceMaps": true, 21 | "exclude": [ 22 | "jest.config.ts", 23 | ".*\\.spec.tsx?$", 24 | ".*\\.test.tsx?$", 25 | "./src/jest-setup.ts$", 26 | "./**/jest-setup.ts$", 27 | ".*.js$", 28 | ".*.d.ts$" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /apps/docs/src/app/limiter/_meta.ts: -------------------------------------------------------------------------------- 1 | import type { MetaRecord } from "nextra"; 2 | const meta: MetaRecord = { 3 | index: { 4 | href: "/limiter", 5 | title: "Overview", 6 | }, 7 | "quick-start": { 8 | href: "/limiter/quick-start", 9 | title: "Quick Start", 10 | }, 11 | "self-hosting": { 12 | href: "/limiter/self-hosting", 13 | title: "Self-Hosting", 14 | }, 15 | algorithms: { 16 | href: "/limiter/algorithms", 17 | title: "Algorithms", 18 | }, 19 | integrations: { 20 | href: "/limiter/integrations", 21 | title: "Integrations", 22 | }, 23 | api: { 24 | href: "https://borrow.apidocumentation.com/reference", 25 | title: "API Reference", 26 | }, 27 | }; 28 | export default meta; 29 | -------------------------------------------------------------------------------- /packages/javascript/node/src/lib/limiter/host/adapters/storage/redis/UpstashRedisAdapter.ts: -------------------------------------------------------------------------------- 1 | import { Redis } from "@upstash/redis"; 2 | import { StorageAdapter } from "../StorageAdapter.js"; 3 | 4 | export class UpstashRedisAdapter extends StorageAdapter { 5 | private redis: Redis; 6 | 7 | constructor(redis: Redis) { 8 | super(); 9 | this.redis = redis; 10 | } 11 | 12 | override relative = async (key: string, field: string, amount: number) => { 13 | await this.redis.hincrby(key, field, amount); 14 | }; 15 | 16 | override get = (key: string) => { 17 | return this.redis.hgetall(key); 18 | }; 19 | 20 | override set = async (key: string, value: any) => { 21 | await this.redis.hset(key, value); 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /apps/cli/src/main.rs: -------------------------------------------------------------------------------- 1 | mod start; 2 | use start::{handle_start_command, StartCommand}; 3 | use clap::{Parser, Subcommand}; 4 | 5 | #[derive(Parser, Debug)] 6 | #[command(version, about, long_about = None, arg_required_else_help(true))] 7 | struct Cli { 8 | #[command(subcommand)] 9 | command: Command 10 | } 11 | 12 | #[derive(Subcommand, Debug)] 13 | enum Command { 14 | /// Scaffold projects and components with Borrow Start. 15 | #[command(name = "start", subcommand, arg_required_else_help(true))] 16 | StartCommand(StartCommand) 17 | } 18 | 19 | fn main() { 20 | let cli = Cli::parse(); 21 | match cli.command { 22 | Command::StartCommand(start_command) => { 23 | handle_start_command(start_command) 24 | } 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files for more about ignoring files. 2 | 3 | # compiled output 4 | dist 5 | tmp 6 | out-tsc 7 | 8 | # dependencies 9 | node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | 41 | .nx/cache 42 | .nx/workspace-data 43 | 44 | vite.config.*.timestamp* 45 | vitest.config.*.timestamp* 46 | **/.env.local 47 | 48 | # Next.js 49 | .next 50 | out 51 | .vercel 52 | template 53 | 54 | target 55 | -------------------------------------------------------------------------------- /packages/javascript/node/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@lib/*": ["./src/lib/*"] 7 | }, 8 | "rootDir": "src", 9 | "outDir": "dist", 10 | "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo", 11 | "emitDeclarationOnly": false, 12 | "module": "nodenext", 13 | "moduleResolution": "nodenext", 14 | "forceConsistentCasingInFileNames": true, 15 | "types": ["node"] 16 | }, 17 | "include": ["src/**/*.ts"], 18 | "references": [], 19 | "exclude": [ 20 | "vite.config.ts", 21 | "vite.config.mts", 22 | "vitest.config.ts", 23 | "vitest.config.mts", 24 | "src/**/*.test.ts", 25 | "src/**/*.spec.ts", 26 | "src/**/*.test.tsx", 27 | "src/**/*.spec.tsx", 28 | "src/**/*.test.js", 29 | "src/**/*.spec.js", 30 | "src/**/*.test.jsx", 31 | "src/**/*.spec.jsx" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /packages/javascript/node/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/vitest", 5 | "types": [ 6 | "vitest/globals", 7 | "vitest/importMeta", 8 | "vite/client", 9 | "node", 10 | "vitest" 11 | ], 12 | "module": "nodenext", 13 | "moduleResolution": "nodenext", 14 | "forceConsistentCasingInFileNames": true 15 | }, 16 | "include": [ 17 | "vite.config.ts", 18 | "vite.config.mts", 19 | "vitest.config.ts", 20 | "vitest.config.mts", 21 | "src/**/*.test.ts", 22 | "src/**/*.spec.ts", 23 | "src/**/*.test.tsx", 24 | "src/**/*.spec.tsx", 25 | "src/**/*.test.js", 26 | "src/**/*.spec.js", 27 | "src/**/*.test.jsx", 28 | "src/**/*.spec.jsx", 29 | "src/**/*.d.ts", 30 | "src/globals.d.ts" 31 | ], 32 | "references": [ 33 | { 34 | "path": "./tsconfig.lib.json" 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /apps/docs/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/README.md: -------------------------------------------------------------------------------- 1 | # Borrow CLI - The Developer Toolkit 2 | 3 | ## Install 4 | ```bash 5 | cargo install borrow-dev 6 | ``` 7 | 8 | ## Start 9 | Borrow Start is a command-line tool that helps you quickly set up common boilerplate code with pre-defined templates and placeholders. 10 | 11 | Templates are downloaded from the [Borrow registry](https://github.com/borrowdev/registry), or you can create your own templates 12 | and refer to them locally by using the `local:` prefix before `