services-as-software
Version:
Primitives for building AI-powered services that operate as software
475 lines (454 loc) • 11.1 kB
text/typescript
/**
* Helper functions for common service operations
*/
import type {
Notification,
Order,
Quote,
Subscription,
OKRDefinition,
KPIDefinition,
EntitlementDefinition,
SubscriptionPlan,
ServiceContext,
JSONSchema,
} from './types.js'
/**
* Ask a question (helper for creating ask endpoints)
*
* @example
* ```ts
* const askEndpoint = Endpoint({
* name: 'ask',
* handler: ask(async (question, context) => {
* // Your Q&A logic here
* return `Answer to: ${question}`
* }),
* })
* ```
*/
export function ask(
handler: (question: string, context?: unknown, serviceContext?: ServiceContext) => Promise<string>
) {
return async (
input: { question: string; context?: unknown },
serviceContext?: ServiceContext
): Promise<string> => {
return handler(input.question, input.context, serviceContext)
}
}
/**
* Deliver results (helper for creating deliver endpoints)
*
* @example
* ```ts
* const deliverEndpoint = Endpoint({
* name: 'deliver',
* handler: deliver(async (orderId, results) => {
* // Delivery logic here
* console.log(`Delivering order ${orderId}`)
* }),
* })
* ```
*/
export function deliver(
handler: (orderId: string, results: unknown, context?: ServiceContext) => Promise<void>
) {
return async (
input: { orderId: string; results: unknown },
context?: ServiceContext
): Promise<void> => {
return handler(input.orderId, input.results, context)
}
}
/**
* Execute a task (helper for creating do endpoints)
*
* @example
* ```ts
* const doEndpoint = Endpoint({
* name: 'do',
* handler: do(async (action, input) => {
* switch (action) {
* case 'process':
* return { status: 'processed' }
* default:
* throw new Error(`Unknown action: ${action}`)
* }
* }),
* })
* ```
*/
export function do_(
handler: (action: string, input?: unknown, context?: ServiceContext) => Promise<unknown>
) {
return async (
input: { action: string; input?: unknown },
context?: ServiceContext
): Promise<unknown> => {
return handler(input.action, input.input, context)
}
}
/**
* Generate content (helper for creating generate endpoints)
*
* @example
* ```ts
* const generateEndpoint = Endpoint({
* name: 'generate',
* handler: generate(async (prompt, options) => {
* // Generation logic here
* return { text: `Generated from: ${prompt}` }
* }),
* })
* ```
*/
export function generate(
handler: (prompt: string, options?: unknown, context?: ServiceContext) => Promise<unknown>
) {
return async (
input: { prompt: string; options?: unknown },
context?: ServiceContext
): Promise<unknown> => {
return handler(input.prompt, input.options, context)
}
}
/**
* Type checking/validation (helper for creating is endpoints)
*
* @example
* ```ts
* const isEndpoint = Endpoint({
* name: 'is',
* handler: is(async (value, type) => {
* // Validation logic here
* return typeof value === type
* }),
* })
* ```
*/
export function is(
handler: (value: unknown, type: string | JSONSchema, context?: ServiceContext) => Promise<boolean>
) {
return async (
input: { value: unknown; type: string | JSONSchema },
context?: ServiceContext
): Promise<boolean> => {
return handler(input.value, input.type, context)
}
}
/**
* Send notification (helper for creating notify endpoints)
*
* @example
* ```ts
* const notifyEndpoint = Endpoint({
* name: 'notify',
* handler: notify(async (notification) => {
* // Send notification via email, Slack, etc.
* console.log(`Sending notification: ${notification.subject}`)
* }),
* })
* ```
*/
export function notify(
handler: (notification: Notification, context?: ServiceContext) => Promise<void>
) {
return async (input: Notification, context?: ServiceContext): Promise<void> => {
return handler(input, context)
}
}
/**
* Event handler (helper for creating event handlers)
*
* @example
* ```ts
* service.on('order.created', on(async (order) => {
* console.log(`New order: ${order.id}`)
* }))
* ```
*/
export function on<TPayload>(
handler: (payload: TPayload, context?: ServiceContext) => void | Promise<void>
) {
return handler
}
/**
* Place an order (helper for creating order endpoints)
*
* @example
* ```ts
* const orderEndpoint = Endpoint({
* name: 'order',
* handler: order(async (product, quantity, context) => {
* const orderId = generateOrderId()
* return {
* id: orderId,
* customerId: context?.customerId || 'unknown',
* product,
* quantity,
* total: calculateTotal(product, quantity),
* currency: 'USD',
* status: 'pending',
* createdAt: new Date(),
* updatedAt: new Date(),
* }
* }),
* })
* ```
*/
export function order<TProduct>(
handler: (product: TProduct, quantity: number, context?: ServiceContext) => Promise<Order<TProduct>>
) {
return async (
input: { product: TProduct; quantity: number },
context?: ServiceContext
): Promise<Order<TProduct>> => {
return handler(input.product, input.quantity, context)
}
}
/**
* Queue processor (helper for queue handlers)
*
* @example
* ```ts
* service.queue('process-orders', queue(async (job) => {
* console.log(`Processing job: ${job.id}`)
* }))
* ```
*/
export function queue<TJob>(
handler: (job: TJob, context?: ServiceContext) => void | Promise<void>
) {
return handler
}
/**
* Request a quote (helper for creating quote endpoints)
*
* @example
* ```ts
* const quoteEndpoint = Endpoint({
* name: 'quote',
* handler: quote(async (product, quantity, context) => {
* const price = calculatePrice(product, quantity)
* return {
* id: generateQuoteId(),
* customerId: context?.customerId || 'unknown',
* product,
* quantity,
* price,
* currency: 'USD',
* expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // 30 days
* }
* }),
* })
* ```
*/
export function quote<TProduct>(
handler: (product: TProduct, quantity: number, context?: ServiceContext) => Promise<Quote<TProduct>>
) {
return async (
input: { product: TProduct; quantity: number },
context?: ServiceContext
): Promise<Quote<TProduct>> => {
return handler(input.product, input.quantity, context)
}
}
/**
* Subscribe to a plan (helper for creating subscribe endpoints)
*
* @example
* ```ts
* const subscribeEndpoint = Endpoint({
* name: 'subscribe',
* handler: subscribe(async (planId, context) => {
* const plan = findPlan(planId)
* return {
* id: generateSubscriptionId(),
* customerId: context?.customerId || 'unknown',
* planId,
* status: 'active',
* currentPeriodStart: new Date(),
* currentPeriodEnd: getNextBillingDate(plan.pricing.interval),
* }
* }),
* })
* ```
*/
export function subscribe(
handler: (planId: string, context?: ServiceContext) => Promise<Subscription>
) {
return async (input: { planId: string }, context?: ServiceContext): Promise<Subscription> => {
return handler(input.planId, context)
}
}
/**
* Scheduled task (helper for every/scheduled tasks)
*
* @example
* ```ts
* service.every('0 0 * * *', every(async () => {
* console.log('Running daily task')
* }))
* ```
*/
export function every(handler: (context?: ServiceContext) => void | Promise<void>) {
return handler
}
/**
* Get entitlements (helper for creating entitlements endpoints)
*
* @example
* ```ts
* const entitlementsEndpoint = Endpoint({
* name: 'entitlements',
* handler: entitlements(async (context) => {
* return context?.entitlements || []
* }),
* })
* ```
*/
export function entitlements(handler: (context?: ServiceContext) => Promise<string[]>) {
return async (_input: unknown, context?: ServiceContext): Promise<string[]> => {
return handler(context)
}
}
/**
* Get KPIs (helper for creating KPI endpoints)
*
* @example
* ```ts
* const kpisEndpoint = Endpoint({
* name: 'kpis',
* handler: kpis(async () => {
* return {
* 'revenue': 10000,
* 'customers': 150,
* 'satisfaction': 4.5,
* }
* }),
* })
* ```
*/
export function kpis(handler: (context?: ServiceContext) => Promise<Record<string, number | string>>) {
return async (_input: unknown, context?: ServiceContext): Promise<Record<string, number | string>> => {
return handler(context)
}
}
/**
* Get OKRs (helper for creating OKR endpoints)
*
* @example
* ```ts
* const okrsEndpoint = Endpoint({
* name: 'okrs',
* handler: okrs(async () => {
* return [{
* id: 'okr-1',
* objective: 'Improve customer satisfaction',
* keyResults: [
* {
* description: 'Increase NPS score',
* measure: async () => 8.5,
* target: 9.0,
* unit: 'score',
* },
* ],
* }]
* }),
* })
* ```
*/
export function okrs(handler: (context?: ServiceContext) => Promise<OKRDefinition[]>) {
return async (_input: unknown, context?: ServiceContext): Promise<OKRDefinition[]> => {
return handler(context)
}
}
/**
* Create a subscription plan
*
* @example
* ```ts
* const plan = Plan({
* id: 'pro',
* name: 'Pro Plan',
* description: 'For professional users',
* pricing: {
* model: 'subscription',
* basePrice: 49.99,
* currency: 'USD',
* interval: 'monthly',
* },
* entitlements: ['api-access', 'advanced-features'],
* features: ['Unlimited API calls', '24/7 support', 'Custom integrations'],
* limits: {
* 'api-calls': 100000,
* 'storage': 1000000000, // 1GB in bytes
* },
* })
* ```
*/
export function Plan(plan: SubscriptionPlan): SubscriptionPlan {
return plan
}
/**
* Create a KPI definition
*
* @example
* ```ts
* const kpi = KPI({
* id: 'monthly-revenue',
* name: 'Monthly Revenue',
* description: 'Total revenue for the current month',
* calculate: async () => {
* return await getMonthlyRevenue()
* },
* target: 100000,
* unit: 'USD',
* })
* ```
*/
export function KPI(kpi: KPIDefinition): KPIDefinition {
return kpi
}
/**
* Create an OKR definition
*
* @example
* ```ts
* const okr = OKR({
* id: 'q1-2024',
* objective: 'Grow user base by 50%',
* keyResults: [
* {
* description: 'Acquire 5000 new users',
* measure: async () => await getNewUserCount(),
* target: 5000,
* unit: 'users',
* },
* ],
* period: 'Q1 2024',
* owner: 'Growth Team',
* })
* ```
*/
export function OKR(okr: OKRDefinition): OKRDefinition {
return okr
}
/**
* Create an entitlement definition
*
* @example
* ```ts
* const entitlement = Entitlement({
* id: 'api-access',
* name: 'API Access',
* description: 'Access to the service API',
* resource: 'api',
* actions: ['read', 'write'],
* })
* ```
*/
export function Entitlement(entitlement: EntitlementDefinition): EntitlementDefinition {
return entitlement
}