Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.svg text
*.png binary
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: CI

on:
push:
pull_request:

jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- run: pnpm typecheck
- run: pnpm lint
- run: pnpm test
- run: pnpm build
14 changes: 14 additions & 0 deletions .github/workflows/template-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: Template Security Scan
on:
pull_request:
paths: ['templates/**']

jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- run: pnpm install
- name: AST Security Scan
run: node scripts/scan-template.mjs
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
node_modules
.pnpm-store
.turbo
dist
coverage
.wrangler
.next
.env
.env.*
!.env.example
.og-cache
.temp
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pnpm lint-staged
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20
6 changes: 6 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100
}
17 changes: 17 additions & 0 deletions apps/server-node/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@og-engine/server-node",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit",
"lint": "eslint src --ext .ts",
"test": "node -e \"console.log('no tests')\""
},
"dependencies": {
"@og-engine/adapter-node": "workspace:*",
"@og-engine/core": "workspace:*",
"express": "^4.21.2"
}
}
9 changes: 9 additions & 0 deletions apps/server-node/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import express, { type Request, type Response } from 'express';

const app = express();

app.get('/health', (_request: Request, response: Response) => {
response.json({ ok: true });
});

app.listen(process.env.PORT ?? 3000);
8 changes: 8 additions & 0 deletions apps/server-node/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
},
"include": ["src/**/*"]
}
15 changes: 15 additions & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "@og-engine/web",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit",
"lint": "eslint src --ext .ts,.tsx",
"test": "node -e \"console.log('no tests')\""
},
"dependencies": {
"@og-engine/types": "workspace:*"
}
}
1 change: 1 addition & 0 deletions apps/web/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL ?? 'http://localhost:8787';
8 changes: 8 additions & 0 deletions apps/web/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
},
"include": ["src/**/*"]
}
18 changes: 18 additions & 0 deletions apps/worker-cf/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@og-engine/worker-cf",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit",
"lint": "eslint src --ext .ts",
"test": "node -e \"console.log('no tests')\""
},
"dependencies": {
"@og-engine/adapter-cloudflare": "workspace:*",
"@og-engine/core": "workspace:*",
"@og-engine/types": "workspace:*",
"hono": "^4.7.2"
}
}
7 changes: 7 additions & 0 deletions apps/worker-cf/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Hono } from 'hono';

const app = new Hono();

app.get('/health', (context) => context.json({ ok: true }));

export default app;
8 changes: 8 additions & 0 deletions apps/worker-cf/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
},
"include": ["src/**/*"]
}
25 changes: 25 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import js from '@eslint/js';
import globals from 'globals';
import tseslint from 'typescript-eslint';
import eslintConfigPrettier from 'eslint-config-prettier';

export default tseslint.config(
js.configs.recommended,
...tseslint.configs.recommended,
{
files: ['**/*.{ts,tsx,js,mjs,cjs}'],
languageOptions: {
globals: {
...globals.node,
...globals.browser
}
},
rules: {
'no-eval': 'error',
'no-new-func': 'error',
'no-implied-eval': 'error',
'@typescript-eslint/no-namespace': 'off'
}
},
eslintConfigPrettier
);
37 changes: 37 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "og-engine",
"private": true,
"version": "0.1.0",
"packageManager": "pnpm@9.12.0",
"scripts": {
"dev": "turbo run dev",
"build": "turbo run build",
"lint": "turbo run lint",
"typecheck": "turbo run typecheck",
"test": "turbo run test",
"format": "prettier --write .",
"prepare": "husky"
},
"devDependencies": {
"@eslint/js": "^9.21.0",
"@types/express": "^5.0.6",
"@types/node": "^20.17.19",
"eslint": "^9.21.0",
"eslint-config-prettier": "^10.0.1",
"globals": "^15.15.0",
"husky": "^9.1.7",
"lint-staged": "^15.4.3",
"prettier": "^3.5.2",
"turbo": "^2.4.4",
"typescript": "^5.7.3",
"typescript-eslint": "^8.25.0"
},
"lint-staged": {
"*.{ts,tsx,js,mjs,cjs,json,md,yml,yaml}": [
"prettier --write"
],
"*.{ts,tsx,js,mjs,cjs}": [
"eslint --fix"
]
}
}
20 changes: 20 additions & 0 deletions packages/adapter-cloudflare/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@og-engine/adapter-cloudflare",
"version": "0.1.0",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit",
"lint": "eslint src --ext .ts",
"test": "node -e \"console.log('no tests')\""
},
"dependencies": {
"@cloudflare/workers-types": "^4.20250214.0",
"@og-engine/types": "workspace:*",
"@og-engine/template-dark": "workspace:*",
"@og-engine/template-minimal": "workspace:*",
"@og-engine/template-sunset": "workspace:*"
}
}
87 changes: 87 additions & 0 deletions packages/adapter-cloudflare/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import dark from '@og-engine/template-dark';
import minimal from '@og-engine/template-minimal';
import sunset from '@og-engine/template-sunset';
import type {
CacheAdapter,
OGTemplate,
PlatformAdapter,
StorageAdapter,
TemplateRegistryAdapter
} from '@og-engine/types';

const registryData = new Map<string, OGTemplate>([
[sunset.id, sunset],
[minimal.id, minimal],
[dark.id, dark]
]);

export const cloudflareStorage = (bucket: R2Bucket, publicBaseUrl: string): StorageAdapter => ({
async get(key) {
const object = await bucket.get(key);
if (!object) {
return null;
}
return Buffer.from(await object.arrayBuffer());
},
async put(key, value, options) {
await bucket.put(key, value, {
httpMetadata: { contentType: options?.contentType ?? 'image/png' }
});
},
async delete(key) {
await bucket.delete(key);
},
url(key) {
return `${publicBaseUrl}/${key}`;
}
});

export const cloudflareCache = (kv: KVNamespace): CacheAdapter => ({
async get(key) {
return kv.get(key);
},
async set(key, value, ttl) {
await kv.put(key, value, ttl ? { expirationTtl: ttl } : undefined);
},
async delete(key) {
await kv.delete(key);
}
});

export const cloudflareRegistry = (): TemplateRegistryAdapter => ({
async list() {
return [...registryData.values()].map((template) => ({
id: template.id,
name: template.name,
description: template.description,
author: template.author,
version: template.version,
tags: template.tags ?? [],
supportedSizes: template.supportedSizes
}));
},
async get(id) {
const template = registryData.get(id);
if (!template) {
throw new Error(`Template not found: ${id}`);
}
return template;
},
async exists(id) {
return registryData.has(id);
}
});

export interface CloudflareBindings {
KV: KVNamespace;
BUCKET: R2Bucket;
PUBLIC_BASE_URL: string;
}

export function cloudflareAdapter(bindings: CloudflareBindings): PlatformAdapter {
return {
storage: cloudflareStorage(bindings.BUCKET, bindings.PUBLIC_BASE_URL),
cache: cloudflareCache(bindings.KV),
registry: cloudflareRegistry()
};
}
9 changes: 9 additions & 0 deletions packages/adapter-cloudflare/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"types": ["@cloudflare/workers-types", "node"]
},
"include": ["src/**/*"]
}
19 changes: 19 additions & 0 deletions packages/adapter-node/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@og-engine/adapter-node",
"version": "0.1.0",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit",
"lint": "eslint src --ext .ts",
"test": "node -e \"console.log('no tests')\""
},
"dependencies": {
"@og-engine/types": "workspace:*",
"@og-engine/template-dark": "workspace:*",
"@og-engine/template-minimal": "workspace:*",
"@og-engine/template-sunset": "workspace:*"
}
}
Loading
Loading