Content Platform
This example is for teams building a content-heavy product surface: editorial pages, docs, media assets, search, and hybrid SSR or SSG delivery. It shows how Slingshot’s content, rendering, and runtime packages fit together instead of documenting them as separate islands.
Source-backed example app: examples/content-platform/
What this demonstrates
Section titled “What this demonstrates”- content and community features backed by the same platform
- uploaded assets plus image-aware delivery
- search over content records
- SSR for request-time pages and SSG for pre-rendered routes
- worker-friendly hosting with KV-backed ISR
- registry-backed search sync and realtime delivery policy
Install
Section titled “Install”bun add @lastshotlabs/slingshot \ @lastshotlabs/slingshot-assets \ @lastshotlabs/slingshot-auth \ @lastshotlabs/slingshot-community \ @lastshotlabs/slingshot-deep-links \ @lastshotlabs/slingshot-notifications \ @lastshotlabs/slingshot-permissions \ @lastshotlabs/slingshot-search \ @lastshotlabs/slingshot-ssg \ @lastshotlabs/slingshot-ssr \ @lastshotlabs/slingshot-runtime-edgeApp composition
Section titled “App composition”import { defineApp } from '@lastshotlabs/slingshot';import { createAssetsPackage } from '@lastshotlabs/slingshot-assets';import { createAuthPlugin } from '@lastshotlabs/slingshot-auth';import { createCommunityPackage } from '@lastshotlabs/slingshot-community';import { createDeepLinksPlugin } from '@lastshotlabs/slingshot-deep-links';import { createNotificationsPackage } from '@lastshotlabs/slingshot-notifications';import { createPermissionsPackage } from '@lastshotlabs/slingshot-permissions';import { createSearchPackage } from '@lastshotlabs/slingshot-search';import { createSsrPackage, type SlingshotSsrRenderer } from '@lastshotlabs/slingshot-ssr';import { edgeRuntime } from '@lastshotlabs/slingshot-runtime-edge';import { createKvIsrCache, type KvNamespace } from '@lastshotlabs/slingshot-runtime-edge/kv';
declare const renderer: SlingshotSsrRenderer;declare const ISR_CACHE: KvNamespace;
export default defineApp({ runtime: edgeRuntime({ fileStore: async (_path: string) => null, }), port: 3000, security: { signing: { secret: process.env.JWT_SECRET! } }, plugins: [ createAuthPlugin({ auth: { roles: ['user', 'editor', 'admin'], defaultRole: 'user' }, db: { auth: 'memory', sessions: 'memory', oauthState: 'memory' }, }), createDeepLinksPlugin({ fallbackBaseUrl: 'https://content.example.com', fallbackRedirects: { '/open/*': '/articles/:id', }, }), ], packages: [ createNotificationsPackage({ dispatcher: { enabled: false, intervalMs: 30_000, maxPerTick: 500 }, }), createPermissionsPackage(), createCommunityPackage({ containerCreation: 'admin' }), createAssetsPackage({ storage: { adapter: 'memory' }, presignedUrls: true, image: { allowedOrigins: ['assets.example.com'] }, }), createSearchPackage({ providers: { default: { provider: 'db-native' }, }, }), createSsrPackage({ renderer, serverRoutesDir: `${import.meta.dir}/server/routes`, assetsManifest: `${import.meta.dir}/dist/client/.vite/manifest.json`, staticDir: `${import.meta.dir}/dist/static`, draftModeSecret: process.env.DRAFT_MODE_SECRET!, isr: { adapter: createKvIsrCache(ISR_CACHE) }, }), ],});import { collectSsgRoutes, renderSsgPages } from '@lastshotlabs/slingshot-ssg';import type { SlingshotSsrRenderer } from '@lastshotlabs/slingshot-ssr';
declare const renderer: SlingshotSsrRenderer;
const config = { serverRoutesDir: `${import.meta.dir}/../src/server/routes`, assetsManifest: `${import.meta.dir}/../dist/client/.vite/manifest.json`, outDir: `${import.meta.dir}/../dist/static`, concurrency: 4,};
const paths = await collectSsgRoutes(config);await renderSsgPages(paths, renderer, config);Why this composition matters
Section titled “Why this composition matters”| Capability | Package path |
|---|---|
| Authenticated editorial and admin surface | slingshot-auth |
| Permission evaluation for community workflows | slingshot-permissions |
| Notification runtime for community activity | slingshot-notifications |
| Community discussion alongside content | slingshot-community |
| Asset metadata, uploads, and image-aware serving | slingshot-assets |
| Search over content records | slingshot-search |
| Request-time page rendering, metadata, draft mode, and ISR | slingshot-ssr |
| Build-time pre-rendering for stable routes | slingshot-ssg |
| Mobile and browser entry routing | slingshot-deep-links |
| Worker-host deployment and KV ISR | runtime-edge |
Delivery model
Section titled “Delivery model”- Use SSR for pages that depend on auth state, draft mode, or frequently changing data.
- Use SSG for routes that can be generated ahead of time from stable content.
- Use ISR when a page is mostly static but still needs cheap background revalidation.
- Use
runtime-edgewhen the deployment target is a worker host and you want bundled file reads plus shared ISR invalidation.
What users see
Section titled “What users see”- editorial pages rendered through
slingshot-ssr - pre-generated landing pages and docs pages emitted by
slingshot-ssg - uploads and media served through
slingshot-assets - search endpoints powering site-wide discovery
- entity-driven indexing and sync policy owned by the shared event registry
- optional community discussion layered into article or docs pages
Where to go next
Section titled “Where to go next”- SaaS Foundations for the tenant and permissions story
- runtime-edge package for worker-host constraints
- slingshot-ssr for route loaders, draft mode, and ISR details
- slingshot-ssg for static collection and rendering behavior