import { createApp, Utils } from 'cloudworker';
export default {
async fetch(request, env, ctx) {
const app = createApp();
app.use(Utils.cors());
app.use(Utils.logger());
app.get('/api/products', async (req, res) => {
const { keys } = await env.PRODUCTS_KV.list();
const products = await Promise.all(
keys.map(async (key) => {
const value = await env.PRODUCTS_KV.get(key.name);
return JSON.parse(value);
})
);
return res.json(products);
});
app.get('/api/products/:id', async (req, res) => {
const { id } = req.params;
const product = await env.PRODUCTS_KV.get(`product:${id}`);
if (!product) {
return res.status(404).json({ error: 'Product not found' });
}
return res.json(JSON.parse(product));
});
app.post('/api/products',
Utils.jwt(env.JWT_SECRET),
Utils.validate({
body: {
name: { type: 'string', required: true },
price: { type: 'number', required: true, min: 0 },
description: { type: 'string' }
}
}),
async (req, res) => {
const id = crypto.randomUUID();
const product = {
id,
...req.body,
createdAt: new Date().toISOString(),
createdBy: req.user.id
};
await env.PRODUCTS_KV.put(`product:${id}`, JSON.stringify(product));
return res.status(201).json(product);
}
);
app.delete('/api/products/:id',
Utils.jwt(env.JWT_SECRET),
Utils.authorize(['admin']),
async (req, res) => {
const { id } = req.params;
await env.PRODUCTS_KV.delete(`product:${id}`);
return res.status(204).send();
}
);
return app.fetch(request, env, ctx);
}
};
import { createApp, EJSEngine } from 'cloudworker';
export default {
async fetch(request, env, ctx) {
const app = createApp();
app.setTemplateEngine(new EJSEngine({
cache: true
}));
app.use(Utils.static({
bucket: 'ASSETS',
prefix: 'public',
maxAge: 86400
}));
app.get('/', async (req, res) => {
return res.render('index', {
title: 'CloudWorker Demo',
message: 'Hello, World!',
products: [
{ id: 1, name: 'Product 1', price: 19.99 },
{ id: 2, name: 'Product 2', price: 29.99 },
{ id: 3, name: 'Product 3', price: 39.99 }
]
});
});
app.get('/about', async (req, res) => {
return res.render('about', {
title: 'About Us',
content: 'Welcome to our website!'
});
});
app.get('/pages/:slug', async (req, res) => {
const { slug } = req.params;
const pageJson = await env.PAGES_KV.get(slug);
if (!pageJson) {
return res.status(404).render('404', {
title: 'Page Not Found',
path: req.url
});
}
const page = JSON.parse(pageJson);
return res.render('page', {
title: page.title,
content: page.content,
createdAt: new Date(page.createdAt).toLocaleDateString()
});
});
app.post('/contact',
Utils.validate({
body: {
name: { type: 'string', required: true },
email: { type: 'string', required: true },
message: { type: 'string', required: true }
}
}),
async (req, res) => {
const id = crypto.randomUUID();
await env.MESSAGES_KV.put(id, JSON.stringify({
id,
...req.body,
createdAt: new Date().toISOString()
}));
return res.redirect('/thank-you');
}
);
return app.fetch(request, env, ctx);
}
};
export class ChatRoom {
constructor(state, env) {
this.state = state;
this.sessions = new Map();
this.messages = [];
this.loadMessages();
}
async loadMessages() {
const storedMessages = await this.state.storage.get('messages');
if (storedMessages) {
this.messages = storedMessages;
}
}
async saveMessage(message) {
this.messages.push(message);
if (this.messages.length > 100) {
this.messages = this.messages.slice(-100);
}
await this.state.storage.put('messages', this.messages);
}
async fetch(request) {
if (request.headers.get('Upgrade') === 'websocket') {
const pair = new WebSocketPair();
const [client, server] = Object.values(pair);
server.accept();
const sessionId = crypto.randomUUID();
this.sessions.set(sessionId, {
socket: server,
name: null,
lastActivity: Date.now()
});
server.addEventListener('message', async event => {
try {
const message = JSON.parse(event.data);
const session = this.sessions.get(sessionId);
session.lastActivity = Date.now();
switch (message.type) {
case 'join':
session.name = message.name;
this.messages.forEach(msg => {
server.send(JSON.stringify(msg));
});
const joinMessage = {
id: crypto.randomUUID(),
type: 'system',
text: `${session.name} joined the chat`,
time: new Date().toISOString()
};
await this.saveMessage(joinMessage);
this.broadcast(joinMessage);
break;
case 'message':
if (!session.name) {
server.send(JSON.stringify({
type: 'error',
text: 'You must join with a name first'
}));
return;
}
const chatMessage = {
id: crypto.randomUUID(),
type: 'message',
from: session.name,
text: message.text,
time: new Date().toISOString()
};
await this.saveMessage(chatMessage);
this.broadcast(chatMessage);
break;
case 'typing':
if (!session.name) return;
this.broadcast({
type: 'typing',
from: session.name,
time: new Date().toISOString()
}, sessionId);
break;
}
} catch (error) {
console.error('Error handling message:', error);
}
});
server.addEventListener('close', () => {
const session = this.sessions.get(sessionId);
this.sessions.delete(sessionId);
if (session.name) {
const leaveMessage = {
id: crypto.randomUUID(),
type: 'system',
text: `${session.name} left the chat`,
time: new Date().toISOString()
};
this.saveMessage(leaveMessage);
this.broadcast(leaveMessage);
}
});
this.state.setAlarm(Date.now() + 60000);
return new Response(null, {
status: 101,
webSocket: client
});
}
const url = new URL(request.url);
if (url.pathname === '/stats') {
return new Response(JSON.stringify({
connections: this.sessions.size,
messages: this.messages.length
}), {
headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Not found', { status: 404 });
}
broadcast(message, excludeSessionId = null) {
const json = JSON.stringify(message);
for (const [id, session] of this.sessions.entries()) {
if (excludeSessionId === id) continue;
try {
session.socket.send(json);
} catch (error) {
console.error('Broadcast error:', error);
}
}
}
async alarm() {
const now = Date.now();
const timeout = 5 * 60 * 1000;
for (const [id, session] of this.sessions.entries()) {
if (now - session.lastActivity > timeout) {
try {
session.socket.close(1000, 'Session timed out');
this.sessions.delete(id);
if (session.name) {
const timeoutMessage = {
id: crypto.randomUUID(),
type: 'system',
text: `${session.name} timed out`,
time: new Date().toISOString()
};
await this.saveMessage(timeoutMessage);
this.broadcast(timeoutMessage);
}
} catch (error) {
console.error('Error closing inactive session:', error);
}
}
}
this.state.setAlarm(Date.now() + 60000);
}
}
import { createApp, ORM } from 'cloudworker';
export default {
async fetch(request, env, ctx) {
const app = createApp();
const orm = new ORM();
const userModel = orm.kv('users', {
id: { type: 'string', required: true },
username: { type: 'string', required: true, unique: true, index: true },
email: { type: 'string', required: true, pattern: '^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$' },
role: { type: 'string', enum: ['user', 'admin'], default: 'user', index: true },
createdAt: { type: 'date' }
});
const productModel = orm.d1('products', {
id: { type: 'string', required: true },
name: { type: 'string', required: true, index: true },
price: { type: 'number', required: true, min: 0 },
description: { type: 'string' },
category: { type: 'string', index: true },
isActive: { type: 'boolean', default: true },
createdAt: { type: 'date' }
});
await productModel.init(env.DB);
app.get('/users', async (req, res) => {
const users = await userModel.findAll(env.USERS_KV);
return res.json(users);
});
app.get('/users/:id', async (req, res) => {
const { id } = req.params;
const user = await userModel.findById(id, env.USERS_KV);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
return res.json(user);
});
app.post('/users', async (req, res) => {
try {
const user = await userModel.create({
id: crypto.randomUUID(),
...req.body,
createdAt: new Date().toISOString()
}, env.USERS_KV);
return res.status(201).json(user);
} catch (error) {
return res.status(400).json({ error: error.message });
}
});
app.put('/users/:id', async (req, res) => {
const { id } = req.params;
try {
const user = await userModel.update(id, {
...req.body,
updatedAt: new Date().toISOString()
}, env.USERS_KV);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
return res.json(user);
} catch (error) {
return res.status(400).json({ error: error.message });
}
});
app.get('/products', async (req, res) => {
const { category } = req.query;
let products;
if (category) {
products = await productModel.find({ category }, env.DB);
} else {
products = await productModel.findAll(env.DB);
}
return res.json(products);
});
app.get('/products/:id', async (req, res) => {
const { id } = req.params;
const product = await productModel.findById(id, env.DB);
if (!product) {
return res.status(404).json({ error: 'Product not found' });
}
return res.json(product);
});
app.post('/products', async (req, res) => {
try {
const product = await productModel.create({
id: crypto.randomUUID(),
...req.body,
createdAt: new Date().toISOString()
}, env.DB);
return res.status(201).json(product);
} catch (error) {
return res.status(400).json({ error: error.message });
}
});
app.get('/products/stats', async (req, res) => {
const stats = await env.DB.prepare(`
SELECT
category,
COUNT(*) as count,
AVG(price) as avgPrice,
MIN(price) as minPrice,
MAX(price) as maxPrice
FROM products
GROUP BY category
`).all();
return res.json(stats.results);
});
return app.fetch(request, env, ctx);
}
};
import { createApp, Utils } from 'cloudworker';
export default {
async fetch(request, env, ctx) {
const app = createApp({
security: {
helmet: true,
xssFilter: true,
noSniff: true,
frameOptions: 'DENY',
hsts: {
enabled: true,
maxAge: 15552000,
includeSubdomains: true
},
contentSecurityPolicy: {
directives: {
'default-src': ["'self'"],
'script-src': ["'self'", "'unsafe-inline'"],
'style-src': ["'self'", "'unsafe-inline'"],
'img-src': ["'self'", 'data:'],
'connect-src': ["'self'"]
}
},
referrerPolicy: 'no-referrer-when-downgrade'
}
});
app.use(Utils.cors({
origin: ['https://example.com', 'https://www.example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-Custom-Header'],
credentials: true,
maxAge: 86400
}));
app.use(Utils.rateLimit({
windowMs: 60 * 1000,
max: 100,
message: 'Too many requests, please try again later',
keyGenerator: req => req.ip || req.headers.get('cf-connecting-ip')
}));
app.use(Utils.csrf({
cookie: {
key: 'csrf-token',
path: '/',
secure: true,
sameSite: 'Strict'
},
ignoreMethods: ['GET', 'HEAD', 'OPTIONS']
}));
app.setSessionStore(new KVSessionStore(env.SESSIONS_KV));
app.get('/profile',
Utils.jwt(env.JWT_SECRET, {
algorithms: ['HS256'],
issuer: 'cloudworker-auth'
}),
async (req, res) => {
return res.json({
user: req.user,
message: 'This is a protected route'
});
}
);
app.post('/login',
Utils.validate({
body: {
username: { type: 'string', required: true },
password: { type: 'string', required: true }
}
}),
async (req, res) => {
const { username, password } = req.body;
const users = await env.USERS_KV.list({ prefix: `user:${username}:` });
if (users.keys.length === 0) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const userData = await env.USERS_KV.get(users.keys[0].name, 'json');
if (userData.password !== password) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const token = generateJWT(
{ id: userData.id, username, role: userData.role },
env.JWT_SECRET,
'1h'
);
if (req.session) {
req.session.data.userId = userData.id;
req.session.data.role = userData.role;
}
return res.json({
token,
user: {
id: userData.id,
username,
role: userData.role
}
});
}
);
app.get('/admin',
Utils.jwt(env.JWT_SECRET),
Utils.authorize(['admin']),
async (req, res) => {
return res.json({
message: 'Admin dashboard',
user: req.user
});
}
);
app.post('/upload',
Utils.jwt(env.JWT_SECRET),
Utils.upload({
maxFileSize: 5 * 1024 * 1024,
maxFiles: 3,
allowedMimeTypes: ['image/jpeg', 'image/png', 'image/gif'],
storage: {
type: 'r2',
r2: {
bucket: 'UPLOADS',
pathPrefix: 'user-uploads/'
}
}
}),
async (req, res) => {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).json({ error: 'No files uploaded' });
}
const uploadedFiles = [];
for (const [fieldName, file] of Object.entries(req.files)) {
uploadedFiles.push({
name: file.name,
size: file.size,
type: file.type,
path: file.path
});
}
return res.status(201).json({
message: 'Files uploaded successfully',
files: uploadedFiles
});
}
);
return app.fetch(request, env, ctx);
}
};
function generateJWT(payload, secret, expiresIn) {
const header = { alg: 'HS256', typ: 'JWT' };
const now = Math.floor(Date.now() / 1000);
let exp;
if (expiresIn === '1h') exp = now + 3600;
else if (expiresIn === '1d') exp = now + 86400;
else exp = now + parseInt(expiresIn) || now + 3600;
const jwtPayload = {
...payload,
iat: now,
exp
};
const encodedHeader = btoa(JSON.stringify(header));
const encodedPayload = btoa(JSON.stringify(jwtPayload));
const signature = btoa(`${secret}_${encodedHeader}_${encodedPayload}`);
return `${encodedHeader}.${encodedPayload}.${signature}`;
}