{"_id":"@edsallrd/vite-plugin-gasforge","_rev":"3-ed9ba2dfc31f3826693b7bb5e7df844a","name":"@edsallrd/vite-plugin-gasforge","dist-tags":{"latest":"0.3.0"},"versions":{"0.2.2":{"name":"@edsallrd/vite-plugin-gasforge","version":"0.2.2","author":{"name":"Edsall Park","email":"https://github.com/EdsallRd"},"license":"MIT","_id":"@edsallrd/vite-plugin-gasforge@0.2.2","maintainers":[{"name":"imreallyliam","email":"liamryde@gmail.com"}],"homepage":"https://github.com/EdsallRd/vite-plugin-gasforge","bugs":{"url":"https://github.com/EdsallRd/vite-plugin-gasforge/issues"},"dist":{"shasum":"ffa192c098a9f7728d2410597810413985accef6","tarball":"https://registry.npmjs.org/@edsallrd/vite-plugin-gasforge/-/vite-plugin-gasforge-0.2.2.tgz","fileCount":6,"integrity":"sha512-p15ZYQLgv75T4s8mHgL0zoOkKLMu/09+QLbDfFobg4X0qa1haZCzk91sqllTJvpisNDa23AKDCRJywpxtxVV/g==","signatures":[{"sig":"MEUCIDg5a6aeEOh6C5i0EX3mBKmPuDIbdFd5D/qJvnN5uIwNAiEAgd76Z6LSRJGrlovzOj709jWCs8TzSCjAuCJAedZmfi4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":30245},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"c31f6ca358c9ad5632d7d4499ffcd5c0083cc2cf","scripts":{"dev":"tsup --watch","build":"tsup"},"_npmUser":{"name":"imreallyliam","email":"liamryde@gmail.com"},"repository":{"url":"git+https://github.com/EdsallRd/vite-plugin-gasforge.git","type":"git"},"_npmVersion":"11.12.1","description":"A Vite plugin for building Google Apps Script projects with type-safe server functions.","directories":{},"_nodeVersion":"24.15.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vite":"^8.1.3","typescript":"^6.0.3","@types/node":"^26.1.0","@standard-schema/spec":"^1.1.0","vite-plugin-singlefile":"^2.3.0"},"peerDependencies":{"vite":">=5.0.0","@standard-schema/spec":"^1.0.0","vite-plugin-singlefile":">=2.0.0"},"_npmOperationalInternal":{"tmp":"tmp/vite-plugin-gasforge_0.2.2_1783025473600_0.7264930364662396","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@edsallrd/vite-plugin-gasforge","version":"0.2.3","author":{"name":"Edsall Park","email":"https://github.com/EdsallRd"},"license":"MIT","_id":"@edsallrd/vite-plugin-gasforge@0.2.3","maintainers":[{"name":"imreallyliam","email":"liamryde@gmail.com"}],"homepage":"https://github.com/EdsallRd/vite-plugin-gasforge","bugs":{"url":"https://github.com/EdsallRd/vite-plugin-gasforge/issues"},"dist":{"shasum":"c24ee903c4eeac38cea65d1922f40cbf4b59fca9","tarball":"https://registry.npmjs.org/@edsallrd/vite-plugin-gasforge/-/vite-plugin-gasforge-0.2.3.tgz","fileCount":6,"integrity":"sha512-YSLQU0OkuVkdYBPM4QTY40Pug9+wbqt8eilsiDUrlXENKNbwsbNaCdN1yykm6tpOaTexIuOb7V5k5nCMJv7xJQ==","signatures":[{"sig":"MEQCIF36A7NAKjlQcGFxdDUMK0QS1PqRH90p2A8YBpVnwYCKAiAZzlrH6V0NfqS3+jmQ8sIxaHaqv/jZlDgZq7TrDpwFpw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":31353},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"4f947afd79a81770f3a8675af59854cd74bfd903","scripts":{"dev":"tsup --watch","build":"tsup"},"_npmUser":{"name":"imreallyliam","email":"liamryde@gmail.com"},"repository":{"url":"git+https://github.com/EdsallRd/vite-plugin-gasforge.git","type":"git"},"_npmVersion":"11.12.1","description":"A Vite plugin for building Google Apps Script projects with type-safe server functions.","directories":{},"_nodeVersion":"24.15.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vite":"^8.1.3","typescript":"^6.0.3","@types/node":"^26.1.0","@standard-schema/spec":"^1.1.0","vite-plugin-singlefile":"^2.3.0"},"peerDependencies":{"vite":">=5.0.0","@standard-schema/spec":"^1.0.0","vite-plugin-singlefile":">=2.0.0"},"_npmOperationalInternal":{"tmp":"tmp/vite-plugin-gasforge_0.2.3_1783030122317_0.717899333567382","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@edsallrd/vite-plugin-gasforge","version":"0.3.0","description":"A Vite plugin for building Google Apps Script projects with type-safe server functions.","author":{"name":"Edsall Park","email":"https://github.com/EdsallRd"},"repository":{"type":"git","url":"git+https://github.com/EdsallRd/vite-plugin-gasforge.git"},"homepage":"https://github.com/EdsallRd/vite-plugin-gasforge","license":"MIT","type":"module","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"peerDependencies":{"@standard-schema/spec":"^1.0.0","vite":">=5.0.0","vite-plugin-singlefile":">=2.0.0"},"devDependencies":{"@eslint/js":"^10.0.1","@standard-schema/spec":"^1.1.0","@types/acorn":"^4.0.6","@types/node":"^26.1.0","eslint":"^10.6.0","tsup":"^8.5.1","typescript":"^6.0.3","typescript-eslint":"^8.62.1","vite":"^8.1.3","vite-plugin-singlefile":"^2.3.0","vitest":"^4.1.9"},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","lint":"eslint .","lint:fix":"eslint . --fix"},"dependencies":{"superjson":"^2.2.6"},"gitHead":"378adb88fa6d34ff2e8b54b5c2553a891f470ce4","_id":"@edsallrd/vite-plugin-gasforge@0.3.0","bugs":{"url":"https://github.com/EdsallRd/vite-plugin-gasforge/issues"},"_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-8sPXSGaWKYaF909JT056jIgZnbtXtvvoSG21CGFpwiFMTTOR82tW1dgpErIEtJos6v20rIZTTuq5zbxCj/CLIQ==","shasum":"42905ee73dd9490efd7fb9ee8ff1e36d77cd88aa","tarball":"https://registry.npmjs.org/@edsallrd/vite-plugin-gasforge/-/vite-plugin-gasforge-0.3.0.tgz","fileCount":8,"unpackedSize":51627,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEHyRo4Gz2FCXGR9+1WL5r/5ftWzj7sFjjw2CYdmRFIaAiEAmTOByDPjxDxHFhQo9mM/yfzbCVJDItYIWP31M295moA="}]},"_npmUser":{"name":"imreallyliam","email":"liamryde@gmail.com"},"directories":{},"maintainers":[{"name":"imreallyliam","email":"liamryde@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/vite-plugin-gasforge_0.3.0_1783084294680_0.5425479512802582"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-02T20:51:13.325Z","modified":"2026-07-03T13:11:34.899Z","0.2.2":"2026-07-02T20:51:13.732Z","0.2.3":"2026-07-02T22:08:42.451Z","0.3.0":"2026-07-03T13:11:34.799Z"},"bugs":{"url":"https://github.com/EdsallRd/vite-plugin-gasforge/issues"},"author":{"name":"Edsall Park","email":"https://github.com/EdsallRd"},"license":"MIT","homepage":"https://github.com/EdsallRd/vite-plugin-gasforge","repository":{"type":"git","url":"git+https://github.com/EdsallRd/vite-plugin-gasforge.git"},"description":"A Vite plugin for building Google Apps Script projects with type-safe server functions.","maintainers":[{"name":"imreallyliam","email":"liamryde@gmail.com"}],"readme":"# vite-plugin-gasforge\n\nA Vite plugin for building Google Apps Script (GAS) projects with type-safe, validated RPC server functions. Write your server and client code in TypeScript, define validated functions using [Standard Schema](https://github.com/standard-schema/standard-schema), and let the plugin manage compilation, serialization, context injection, and tree-shaking.\n\n---\n\n## Key Features\n\n- **Type-Safe RPCs:** Call server-side GAS functions from client-side browser code with compile-time type safety.\n- **Standard Schema Validation:** Validate input parameters and output values using any Standard Schema v1 compatible library (Zod, Valibot, ArkType).\n- **Rich Serialization:** SuperJSON integration allows you to send JavaScript types like `Date`, `Map`, `Set`, `BigInt`, and `Uint8Array` directly over the RPC bridge.\n- **Middleware and Context API:** Inject execution context (such as active users, spreadsheet instances, or auth tokens) through composable middleware chains.\n- **TanStack Query Ready:** Every server function includes `.queryKey()` and `.queryOptions()` helper adapters for React Query or Vue Query compatibility.\n- **Structured Errors:** Errors thrown on the server are reconstructed into typed `GASForgeError` instances on the client, maintaining error codes and stack traces.\n\n---\n\n## Installation\n\n```bash\npnpm add vite-plugin-gasforge vite vite-plugin-singlefile @standard-schema/spec\n# or\nnpm install vite-plugin-gasforge vite vite-plugin-singlefile @standard-schema/spec\n```\n\n---\n\n## Setup\n\n### 1. `vite.config.ts`\n\nAdd the plugin to your Vite configuration:\n\n```ts\nimport { defineConfig } from \"vite\";\nimport gas from \"@edsallrd/vite-plugin-gasforge\";\n\nexport default defineConfig({\n  plugins: [gas()],\n});\n```\n\n### 2. Project Directory Structure\n\nOrganize your source code with folders for client and server entries:\n\n```text\nsrc/\n  server/\n    index.ts       # Server entry point\n  client/\n    index.html     # Client HTML entry point\n```\n\nCustomize these paths using plugin options:\n\n```ts\ngas({\n  server: \"src/server/index.ts\",\n  client: {\n    entry: \"src/client/index.html\",\n    plugins: [], // Additional client-side plugins (e.g. react(), vue())\n    rollupOptions: {}, // Custom Rollup configuration for the client bundle\n  },\n});\n```\n\n### 3. `tsconfig.json`\n\nInclude the type definitions to enable support for `google.script` globals, and add the auto-generated virtual types declarations file (`gasforge-virtual.d.ts`) to your compilation:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"@edsallrd/vite-plugin-gasforge/google.script\"]\n  },\n  \"include\": [\n    \"src\",\n    \"gasforge-virtual.d.ts\"\n  ]\n}\n```\n\n> [!NOTE]\n> The `gasforge-virtual.d.ts` file is automatically generated by the plugin in your project root during compilation/development. It dynamically registers TypeScript types for any server function you define.\n\n---\n\n## Guide and API Reference\n\n### Defining Server Functions\n\nUse `createServerFn` to declare typed endpoints. In client builds, the `handler` implementation is automatically stripped out, while in server builds, the validation and handler logic are preserved.\n\n```ts\nimport { createServerFn } from \"@edsallrd/vite-plugin-gasforge\";\nimport { z } from \"zod\";\n\nexport const getGreeting = createServerFn({\n  input: z.string(),\n  output: z.string(),\n  handler: async (name) => {\n    return `Hello, ${name}!`;\n  },\n});\n```\n\nCall the function directly from client-side code:\n\n```ts\nconst message = await getGreeting(\"World\");\n// => \"Hello, World!\"\n```\n\n#### Local Execution (Server-Side)\n\nIf you need to call your server functions locally from within other server-side logic (e.g., in unit tests or internal utility functions) without going through the RPC serialization bridge, you can use the `.local` method. This will still execute your input validation, middleware chain, handler, and output validation directly:\n\n```ts\nconst message = await getGreeting.local(\"World\");\n// => Executes validation + middleware + handler locally\n```\n\n---\n\n### Rich Data Serialization\n\nBy incorporating SuperJSON into the RPC bridge, you can transmit rich data structures (such as `Date`, `Map`, and `Set`) without degrading them to strings or empty objects:\n\n```ts\nimport { createServerFn } from \"@edsallrd/vite-plugin-gasforge\";\nimport { z } from \"zod\";\n\nexport const createTodo = createServerFn({\n  input: z.object({\n    title: z.string(),\n    tags: z.instanceof(Set),\n    dueDate: z.date(),\n  }),\n  output: z.object({\n    id: z.string(),\n    createdAt: z.date(),\n  }),\n  handler: async (todo) => {\n    return {\n      id: \"todo-99\",\n      createdAt: new Date(),\n    };\n  },\n});\n```\n\n---\n\n### Middleware and Context Injection\n\nDefine composable middleware to populate execution context (such as verifying spreadsheet permissions or fetching user credentials) before invoking the main handler:\n\n```ts\nimport {\n  createMiddleware,\n  createServerFn,\n} from \"@edsallrd/vite-plugin-gasforge\";\nimport { z } from \"zod\";\n\n// 1. Define middleware and context outputs\nconst authMiddleware = createMiddleware().handler(async () => {\n  const email = Session.getActiveUser().getEmail();\n  if (!email) {\n    throw new Error(\"Unauthorized access\");\n  }\n  return { userEmail: email };\n});\n\n// 2. Attach middleware to server functions\nexport const getUserPreferences = createServerFn({\n  middleware: [authMiddleware],\n  input: z.void(),\n  output: z.any(),\n  handler: async (input, ctx) => {\n    // ctx is fully typed and contains userEmail:\n    console.log(`Access by: ${ctx.userEmail}`);\n    return { theme: \"dark\" };\n  },\n});\n```\n\n---\n\n### TanStack Query Adapters\n\nEvery server function includes `.queryKey()` and `.queryOptions()` helper methods to integrate with `@tanstack/react-query` or `@tanstack/vue-query`. The query key returned is typed as a read-only tuple (`as const`):\n\n```ts\nimport { useQuery } from \"@tanstack/react-query\";\nimport { getGreeting } from \"./functions\";\n\n// getGreeting.queryKey(\"Alice\") => readonly [\"getGreeting\", \"Alice\"]\n// getGreeting.queryOptions(\"Alice\") => { queryKey: readonly [\"getGreeting\", \"Alice\"], queryFn: ... }\n\nfunction GreetingComponent() {\n  const { data, isLoading } = useQuery(getGreeting.queryOptions(\"Alice\"));\n\n  if (isLoading) return <div>Loading...</div>;\n  return <h1>{data}</h1>;\n}\n```\n\n---\n\n### Structured Error Handling\n\nAll thrown errors are caught and reconstructed into `GASForgeError` instances, providing type-safe code categorizations:\n\n```ts\nimport { GASForgeError } from \"@edsallrd/vite-plugin-gasforge\";\nimport { getGreeting } from \"./functions\";\n\ntry {\n  await getGreeting(123 as any); // Invalid type\n} catch (err) {\n  if (err instanceof GASForgeError) {\n    console.error(`Error Code: ${err.code}`); // e.g. \"INPUT_VALIDATION_FAILED\"\n    console.error(`Issues:`, err.issues); // Validation problems (only for validation failures)\n  }\n}\n```\n\n#### Error Codes\n\nThe `GASForgeError` object contains a `code` property indicating the type of failure:\n\n| Error Code | Description |\n|---|---|\n| `INPUT_VALIDATION_FAILED` | Thrown when client inputs do not conform to the defined `input` schema. |\n| `OUTPUT_VALIDATION_FAILED` | Thrown when server outputs do not conform to the defined `output` schema. |\n| `MIDDLEWARE_ERROR` | Thrown when an error occurs inside a middleware handler. |\n| `SERVER_ERROR` | Thrown when an unhandled exception occurs inside your function's handler. |\n| `RPC_ERROR` | Thrown when the called server function is not exported or defined on the Apps Script server (`google.script.run`). |\n\n---\n\n## Server Entry Point\n\nYour Google Apps Script server-side code should export all discovered endpoints by importing the virtual compilation file:\n\n```ts\n// src/server/index.ts\nexport * from \"virtual:gas/server-fns\";\n\n// Add global triggers or HTML sidebar logic\nfunction onOpen() {\n  SpreadsheetApp.getUi()\n    .createMenu(\"Sidebar Application\")\n    .addItem(\"Open App\", \"showSidebar\")\n    .addToUi();\n}\n\nfunction showSidebar() {\n  const html = HtmlService.createHtmlOutputFromFile(\"Client\");\n  SpreadsheetApp.getUi().showSidebar(html);\n}\n```\n\n---\n\n## Production Build\n\nRun the compilation script:\n\n```bash\npnpm vite build\n# or\nnpm run build\n```\n\nThis triggers the dual-build pipeline and generates the following flat bundle files:\n\n```text\ndist/\n  Server.js    # Deploy directly to Google Apps Script\n  Client.html  # Deploy directly to Google Apps Script\n```\n\n---\n\n## Plugin Options\n\n| Option                 | Type             | Default                   | Description                                   |\n| ---------------------- | ---------------- | ------------------------- | --------------------------------------------- |\n| `server`               | `string`         | `\"src/server/index.ts\"`   | File path of the server entry-point.          |\n| `client.entry`         | `string`         | `\"src/client/index.html\"` | File path of the client HTML entry-point.     |\n| `client.plugins`       | `PluginOption[]` | `[]`                      | Additional Vite plugins for the client build. |\n| `client.rollupOptions` | `object`         | `{}`                      | Custom Rollup build options for the client.   |\n\n---\n","readmeFilename":"README.md"}