{"_id":"@eleven-am/golem-render","name":"@eleven-am/golem-render","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@eleven-am/golem-render","version":"0.1.0","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc -p tsconfig.json","test":"jest --runInBand"},"dependencies":{"escape-html":"^1.0.3"},"peerDependencies":{"@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/core":"^10.0.0 || ^11.0.0","@nestjs/platform-express":"^10.0.0 || ^11.0.0","express":"^4.18.0 || ^5.0.0","rxjs":"^7.8.0"},"devDependencies":{"@nestjs/common":"^11.0.0","@nestjs/core":"^11.0.0","@nestjs/platform-express":"^11.0.0","@nestjs/testing":"^11.0.0","@types/escape-html":"^1.0.4","@types/express":"^5.0.0","@types/jest":"^29.5.14","@types/node":"^22.10.0","@types/supertest":"^6.0.2","express":"^5.0.0","jest":"^29.7.0","supertest":"^7.0.0","ts-jest":"^29.2.5","typescript":"^5.7.0"},"license":"GPL-3.0","author":{"name":"Roy OSSAI"},"engines":{"node":">=20"},"publishConfig":{"access":"public"},"description":"Nest-native SPA hosting and route metadata rendering for Golem applications","keywords":["golem","nestjs","spa","open-graph","rendering"],"repository":{"type":"git","url":"git+https://github.com/eleven-am/golem.git","directory":"packages/render"},"gitHead":"a58b6c30db007ffc533f37d68cd802fbec38a274","_id":"@eleven-am/golem-render@0.1.0","bugs":{"url":"https://github.com/eleven-am/golem/issues"},"homepage":"https://github.com/eleven-am/golem#readme","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-MUG4ajjg25HxeizFtaHMHv/FLlS0/IUCW5fcAhVeKqxZ929CumpGVxCXj259l73zQcAOueeTkM3nUEPDcARwZw==","shasum":"b2bfb714d89275c3d5c7e675a8c473cb9aecf1bf","tarball":"https://registry.npmjs.org/@eleven-am/golem-render/-/golem-render-0.1.0.tgz","fileCount":17,"unpackedSize":58986,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHvXD3REqJS9CfPMjp1Ibgx2hbqwvmkb/VV8h5wXiVSTAiAptoVRgybD9ZAzpSrl77922bdvDlaSVizuW5W6agW+1g=="}]},"_npmUser":{"name":"eleven-am","email":"maixperiyon@gmail.com"},"directories":{},"maintainers":[{"name":"eleven-am","email":"maixperiyon@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/golem-render_0.1.0_1784467715971_0.21404560648992788"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-19T13:28:35.839Z","0.1.0":"2026-07-19T13:28:36.103Z","modified":"2026-07-19T13:28:36.300Z"},"maintainers":[{"name":"eleven-am","email":"maixperiyon@gmail.com"}],"description":"Nest-native SPA hosting and route metadata rendering for Golem applications","homepage":"https://github.com/eleven-am/golem#readme","keywords":["golem","nestjs","spa","open-graph","rendering"],"repository":{"type":"git","url":"git+https://github.com/eleven-am/golem.git","directory":"packages/render"},"author":{"name":"Roy OSSAI"},"bugs":{"url":"https://github.com/eleven-am/golem/issues"},"license":"GPL-3.0","readme":"# @eleven-am/golem-render\n\nNest-native hosting for a compiled single-page application, with optional per-route Open Graph and Twitter metadata. It serves the frontend shell without taking over backend routes and lets ordinary Nest controllers resolve link-preview metadata.\n\n## Install\n\n```bash\nnpm install @eleven-am/golem-render\n```\n\nThe package currently targets Nest's Express adapter.\n\n## Host a frontend\n\n```ts\nimport { Module } from '@nestjs/common';\nimport { GolemRenderModule } from '@eleven-am/golem-render';\n\n@Module({\n  imports: [\n    GolemRenderModule.forRoot({\n      client: 'dist-web/client',\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n`client` can use any bundle layout; it only needs to contain `index.html`. The module:\n\n- serves existing static files without directory indexes, redirects, or dotfiles;\n- gives content-hashed assets a one-year immutable cache and other files `no-cache`;\n- serves the shell for deep browser routes and HEAD requests;\n- returns real 404s for missing assets, non-HTML requests, and non-GET requests;\n- leaves `/api` and `/graphql` to backend handlers by default;\n- fails at startup with the resolved absolute path when the bundle is missing.\n\nChange the reserved prefixes or index filename explicitly when necessary:\n\n```ts\nGolemRenderModule.forRoot({\n  client: 'frontend/output',\n  index: 'shell.html',\n  reserved: ['/api', '/graphql', '/health'],\n})\n```\n\n## Default metadata\n\n```ts\nGolemRenderModule.forRoot({\n  client: 'dist-web/client',\n  defaults: {\n    title: 'Readable',\n    description: 'Save anything. Read it later. Listen anywhere.',\n    image: '/og-default.png',\n  },\n})\n```\n\nThe index file is read and parsed once at startup but is never modified. Each shell response is rendered in memory and sent with `Cache-Control: no-cache`. Relative URLs pass through unchanged. Set `baseUrl` only when they should be expanded to absolute URLs.\n\n## Route metadata\n\n`@RenderRoute` is a real Nest GET route. Put it on a method in an ordinary controller and use Nest's own parameter decorators, pipes, guards, interceptors, filters, and request-scoped dependencies.\n\n```ts\nimport { Controller, Headers, Param } from '@nestjs/common';\nimport { GolemRenderModule, RenderRoute } from '@eleven-am/golem-render';\n\n@Controller()\nexport class ArticleRenderController {\n  constructor(private readonly prisma: PrismaService) {}\n\n  @RenderRoute('/article/:id')\n  async article(\n    @Param('id') id: string,\n    @Headers('user-agent') userAgent: string,\n  ) {\n    const article = await this.prisma.article.findUnique({\n      where: { id },\n      select: { title: true, excerpt: true, image: true, wideImage: true },\n    });\n    if (!article) return null;\n    return {\n      title: article.title,\n      description: article.excerpt,\n      image: /Twitterbot/i.test(userAgent ?? '') ? article.wideImage : article.image,\n    };\n  }\n}\n```\n\nThe application owns the query and its disclosure policy. Metadata routes do not add caller authorization or Golem policy scoping. This makes anonymous link unfurling possible; return only information that is safe for anyone holding the URL.\n\nReturning `null` or `undefined`, or throwing, renders the configured defaults. Errors are logged and never turn the shell into a 500 response. The SPA shell renders without authentication and handles its own application authentication after boot.\n\nMultiple URL patterns can share one method:\n\n```ts\n@RenderRoute('/m=:name')\n@RenderRoute('/movie/:name')\nmovie(@Param('name') name: string) {\n  return { title: name };\n}\n```\n\nNest owns route ordering. Declare wildcard routes last, as with any other Nest controller.\n\n## Custom metadata\n\n```ts\nreturn {\n  title: article.title,\n  description: article.excerpt,\n  image: article.image,\n  meta: {\n    'og:type': 'article',\n    'article:published_time': article.publishedAt.toISOString(),\n    'twitter:card': 'summary',\n    'og:description': null,\n  },\n};\n```\n\n`meta` is merged over the shorthand-generated tags. A `null` value deletes a tag. All names and values are HTML-escaped before interpolation. URL values are never derived from the request `Host` header.\n\n## License\n\nGPL-3.0\n","readmeFilename":"README.md","_rev":"1-a5db95441348323301d2928fd61ed100"}