@palbase/backend 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,342 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ HttpError: () => HttpError,
24
+ auth: () => auth,
25
+ defineEndpoint: () => defineEndpoint,
26
+ defineJob: () => defineJob,
27
+ defineMiddleware: () => defineMiddleware,
28
+ defineWebhook: () => defineWebhook,
29
+ defineWorker: () => defineWorker,
30
+ documents: () => documents,
31
+ storage: () => storage,
32
+ z: () => import_zod.z
33
+ });
34
+ module.exports = __toCommonJS(src_exports);
35
+
36
+ // src/endpoint.ts
37
+ function defineEndpoint(config) {
38
+ return config;
39
+ }
40
+
41
+ // src/middleware.ts
42
+ function defineMiddleware(fn) {
43
+ return fn;
44
+ }
45
+
46
+ // src/errors.ts
47
+ var HttpError = class extends Error {
48
+ status;
49
+ error;
50
+ errorDescription;
51
+ constructor(status, error, errorDescription) {
52
+ super(errorDescription);
53
+ this.name = "HttpError";
54
+ this.status = status;
55
+ this.error = error;
56
+ this.errorDescription = errorDescription;
57
+ }
58
+ /**
59
+ * Serialize to the standard Palbase error response format.
60
+ * The `requestId` is injected by the runtime layer from the request context.
61
+ * When called without arguments (e.g. JSON.stringify), request_id is omitted.
62
+ */
63
+ toJSON(requestId) {
64
+ const result = {
65
+ error: this.error,
66
+ error_description: this.errorDescription,
67
+ status: this.status
68
+ };
69
+ if (requestId) {
70
+ result.request_id = requestId;
71
+ }
72
+ return result;
73
+ }
74
+ };
75
+
76
+ // src/worker.ts
77
+ var VALID_WORKER_NAME = /^[a-zA-Z0-9_-]+$/;
78
+ var WORKER_DEFAULTS = {
79
+ retry: 3,
80
+ timeout: 30,
81
+ backoff: "exponential"
82
+ };
83
+ function defineWorker(config) {
84
+ if (!config.name || config.name.trim() === "") {
85
+ throw new Error("Worker name is required");
86
+ }
87
+ if (!VALID_WORKER_NAME.test(config.name)) {
88
+ throw new Error(
89
+ `Invalid worker name "${config.name}": must match [a-zA-Z0-9_-]+`
90
+ );
91
+ }
92
+ if (config.retry !== void 0 && (config.retry < 0 || !Number.isInteger(config.retry))) {
93
+ throw new Error("Worker retry must be a non-negative integer");
94
+ }
95
+ if (config.timeout !== void 0 && config.timeout <= 0) {
96
+ throw new Error("Worker timeout must be a positive number");
97
+ }
98
+ if (config.backoff !== void 0 && !["exponential", "linear", "fixed"].includes(config.backoff)) {
99
+ throw new Error(`Invalid backoff strategy: ${config.backoff}`);
100
+ }
101
+ return {
102
+ name: config.name,
103
+ retry: config.retry ?? WORKER_DEFAULTS.retry,
104
+ timeout: config.timeout ?? WORKER_DEFAULTS.timeout,
105
+ backoff: config.backoff ?? WORKER_DEFAULTS.backoff,
106
+ handler: config.handler
107
+ };
108
+ }
109
+
110
+ // src/job.ts
111
+ var VALID_JOB_NAME = /^[a-zA-Z0-9_-]+$/;
112
+ var MAX_TIMEOUT_SECONDS = 300;
113
+ var JOB_DEFAULTS = {
114
+ timeout: 30
115
+ };
116
+ function validateCronExpression(expression) {
117
+ const trimmed = expression.trim();
118
+ if (trimmed === "") {
119
+ return "Cron expression is required";
120
+ }
121
+ const parts = trimmed.split(/\s+/);
122
+ if (parts.length !== 5) {
123
+ return `Invalid cron expression "${trimmed}": expected 5 fields (minute hour day month weekday), got ${parts.length}`;
124
+ }
125
+ const fieldNames = ["minute", "hour", "day of month", "month", "day of week"];
126
+ const fieldRanges = [
127
+ [0, 59],
128
+ [0, 23],
129
+ [1, 31],
130
+ [1, 12],
131
+ [0, 7]
132
+ ];
133
+ for (let i = 0; i < 5; i++) {
134
+ const field = parts[i];
135
+ const name = fieldNames[i];
136
+ const [min, max] = fieldRanges[i];
137
+ const error = validateCronField(field, name, min, max);
138
+ if (error !== null) {
139
+ return error;
140
+ }
141
+ }
142
+ return null;
143
+ }
144
+ function validateCronField(field, name, min, max) {
145
+ const listParts = field.split(",");
146
+ for (const part of listParts) {
147
+ const stepParts = part.split("/");
148
+ if (stepParts.length > 2) {
149
+ return `Invalid ${name} field: "${field}"`;
150
+ }
151
+ const base = stepParts[0];
152
+ const step = stepParts[1];
153
+ if (step !== void 0) {
154
+ const stepNum = Number(step);
155
+ if (!Number.isInteger(stepNum) || stepNum < 1) {
156
+ return `Invalid step value in ${name} field: "${field}"`;
157
+ }
158
+ }
159
+ if (base === "*") {
160
+ continue;
161
+ }
162
+ if (base.includes("-")) {
163
+ const rangeParts = base.split("-");
164
+ if (rangeParts.length !== 2) {
165
+ return `Invalid range in ${name} field: "${field}"`;
166
+ }
167
+ const rangeStart = Number(rangeParts[0]);
168
+ const rangeEnd = Number(rangeParts[1]);
169
+ if (!Number.isInteger(rangeStart) || !Number.isInteger(rangeEnd) || rangeStart < min || rangeEnd > max || rangeStart > rangeEnd) {
170
+ return `Invalid range in ${name} field: "${field}"`;
171
+ }
172
+ continue;
173
+ }
174
+ const num = Number(base);
175
+ if (!Number.isInteger(num) || num < min || num > max) {
176
+ return `Invalid value in ${name} field: "${field}"`;
177
+ }
178
+ }
179
+ return null;
180
+ }
181
+ function defineJob(config) {
182
+ if (!config.name || config.name.trim() === "") {
183
+ throw new Error("Job name is required");
184
+ }
185
+ if (!VALID_JOB_NAME.test(config.name)) {
186
+ throw new Error(
187
+ `Invalid job name "${config.name}": must match [a-zA-Z0-9_-]+`
188
+ );
189
+ }
190
+ if (!config.schedule || config.schedule.trim() === "") {
191
+ throw new Error("Job schedule is required");
192
+ }
193
+ const cronError = validateCronExpression(config.schedule);
194
+ if (cronError !== null) {
195
+ throw new Error(cronError);
196
+ }
197
+ if (!config.handler) {
198
+ throw new Error("Job handler is required");
199
+ }
200
+ if (config.timeout !== void 0 && config.timeout <= 0) {
201
+ throw new Error("Job timeout must be a positive number");
202
+ }
203
+ if (config.timeout !== void 0 && !Number.isInteger(config.timeout)) {
204
+ throw new Error("Job timeout must be an integer");
205
+ }
206
+ if (config.timeout !== void 0 && config.timeout > MAX_TIMEOUT_SECONDS) {
207
+ throw new Error(
208
+ `Job timeout ${config.timeout}s exceeds maximum ${MAX_TIMEOUT_SECONDS}s`
209
+ );
210
+ }
211
+ return {
212
+ name: config.name,
213
+ schedule: config.schedule.trim(),
214
+ timeout: config.timeout ?? JOB_DEFAULTS.timeout,
215
+ handler: config.handler
216
+ };
217
+ }
218
+
219
+ // src/webhook.ts
220
+ var VALID_WEBHOOK_PATH = /^\/[a-zA-Z0-9/_-]+$/;
221
+ function defineWebhook(config) {
222
+ if ("provider" in config) {
223
+ return validateProviderWebhook(config);
224
+ }
225
+ return validateCustomWebhook(config);
226
+ }
227
+ function validateProviderWebhook(config) {
228
+ if (!config.provider) {
229
+ throw new Error("Webhook provider is required");
230
+ }
231
+ const validProviders = [
232
+ "stripe",
233
+ "github",
234
+ "twilio",
235
+ "sendgrid",
236
+ "slack",
237
+ "discord",
238
+ "livekit"
239
+ ];
240
+ if (!validProviders.includes(config.provider)) {
241
+ throw new Error(
242
+ `Invalid webhook provider "${config.provider}": must be one of ${validProviders.join(", ")}`
243
+ );
244
+ }
245
+ if (!config.secret) {
246
+ throw new Error('Webhook secret is required (use { env: "SECRET_NAME" })');
247
+ }
248
+ if (typeof config.secret.env !== "string" || config.secret.env.trim() === "") {
249
+ throw new Error("Webhook secret env name must be a non-empty string");
250
+ }
251
+ if (!config.events || Object.keys(config.events).length === 0) {
252
+ throw new Error("At least one event handler is required");
253
+ }
254
+ for (const [eventName, handler] of Object.entries(config.events)) {
255
+ if (typeof handler !== "function") {
256
+ throw new Error(`Event handler for "${eventName}" must be a function`);
257
+ }
258
+ }
259
+ return {
260
+ type: "provider",
261
+ provider: config.provider,
262
+ secret: config.secret,
263
+ events: config.events
264
+ };
265
+ }
266
+ function validateCustomWebhook(config) {
267
+ if (!config.path || config.path.trim() === "") {
268
+ throw new Error("Webhook path is required");
269
+ }
270
+ if (!VALID_WEBHOOK_PATH.test(config.path)) {
271
+ throw new Error(
272
+ `Invalid webhook path "${config.path}": must start with / and contain only alphanumeric, hyphen, underscore, slash`
273
+ );
274
+ }
275
+ if (!config.handler) {
276
+ throw new Error("Webhook handler is required");
277
+ }
278
+ if (typeof config.handler !== "function") {
279
+ throw new Error("Webhook handler must be a function");
280
+ }
281
+ if (config.verify !== void 0 && typeof config.verify !== "function") {
282
+ throw new Error("Webhook verify must be a function");
283
+ }
284
+ return {
285
+ type: "custom",
286
+ path: config.path,
287
+ verify: config.verify,
288
+ handler: config.handler
289
+ };
290
+ }
291
+
292
+ // src/hooks.ts
293
+ var auth = {
294
+ onUserCreated(handler) {
295
+ return { module: "auth", event: "user.created", handler };
296
+ },
297
+ onSignIn(handler) {
298
+ return { module: "auth", event: "user.sign_in", handler };
299
+ },
300
+ onSignOut(handler) {
301
+ return { module: "auth", event: "user.sign_out", handler };
302
+ },
303
+ onPasswordReset(handler) {
304
+ return { module: "auth", event: "user.password_reset", handler };
305
+ }
306
+ };
307
+ var storage = {
308
+ onFileUploaded(handler) {
309
+ return { module: "storage", event: "file.uploaded", handler };
310
+ },
311
+ onFileDeleted(handler) {
312
+ return { module: "storage", event: "file.deleted", handler };
313
+ }
314
+ };
315
+ var documents = {
316
+ onDocumentCreated(handler) {
317
+ return { module: "documents", event: "document.created", handler };
318
+ },
319
+ onDocumentUpdated(handler) {
320
+ return { module: "documents", event: "document.updated", handler };
321
+ },
322
+ onDocumentDeleted(handler) {
323
+ return { module: "documents", event: "document.deleted", handler };
324
+ }
325
+ };
326
+
327
+ // src/index.ts
328
+ var import_zod = require("zod");
329
+ // Annotate the CommonJS export names for ESM import in node:
330
+ 0 && (module.exports = {
331
+ HttpError,
332
+ auth,
333
+ defineEndpoint,
334
+ defineJob,
335
+ defineMiddleware,
336
+ defineWebhook,
337
+ defineWorker,
338
+ documents,
339
+ storage,
340
+ z
341
+ });
342
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/endpoint.ts","../src/middleware.ts","../src/errors.ts","../src/worker.ts","../src/job.ts","../src/webhook.ts","../src/hooks.ts"],"sourcesContent":["export { defineEndpoint } from \"./endpoint.js\";\nexport type {\n EndpointConfig,\n EndpointContext,\n RateLimitConfig,\n DBClient,\n Logger,\n CacheClient,\n PalbaseBindings,\n Middleware,\n} from \"./endpoint.js\";\nexport { defineMiddleware } from \"./middleware.js\";\nexport type { MiddlewareContext, MiddlewareHandler } from \"./middleware.js\";\nexport type { User, HttpMethod, AuthConfig } from \"./types.js\";\nexport { HttpError } from \"./errors.js\";\nexport { defineWorker } from \"./worker.js\";\nexport type {\n WorkerConfig,\n ResolvedWorkerConfig,\n BackoffStrategy,\n} from \"./worker.js\";\nexport { defineJob } from \"./job.js\";\nexport type { JobConfig, ResolvedJobConfig, JobContext } from \"./job.js\";\nexport { defineWebhook } from \"./webhook.js\";\nexport type {\n WebhookProvider,\n WebhookContext,\n EnvSecretRef,\n ProviderWebhookConfig,\n CustomWebhookConfig,\n ResolvedProviderWebhook,\n ResolvedCustomWebhook,\n ResolvedWebhookConfig,\n WebhookEventHandler,\n WebhookRequest,\n ProviderEventMap,\n} from \"./webhook.js\";\nexport { auth, storage, documents } from \"./hooks.js\";\nexport type {\n HookContext,\n HookHandler,\n ResolvedHook,\n UserCreatedEvent,\n SignInEvent,\n SignOutEvent,\n PasswordResetEvent,\n FileUploadedEvent,\n FileDeletedEvent,\n DocumentCreatedEvent,\n DocumentUpdatedEvent,\n DocumentDeletedEvent,\n} from \"./hooks.js\";\nexport { z } from \"zod\";\n","import type { ZodSchema, z } from \"zod\";\nimport type { AuthConfig, HttpMethod, User } from \"./types.js\";\nimport type { MiddlewareContext } from \"./middleware.js\";\n\n/** Rate limit configuration for an endpoint. */\nexport interface RateLimitConfig {\n /** Maximum number of requests in the window. */\n max: number;\n /** Window duration in seconds. */\n window: number;\n}\n\n/** Database client interface injected into endpoint context. */\nexport interface DBClient {\n insert(table: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;\n update(table: string, id: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;\n delete(table: string, id: string): Promise<void>;\n findById(table: string, id: string): Promise<Record<string, unknown> | null>;\n findMany(table: string, query?: Record<string, unknown>): Promise<Record<string, unknown>[]>;\n}\n\n/** Logger interface injected into endpoint context. */\nexport interface Logger {\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n debug(message: string, ...args: unknown[]): void;\n}\n\n/** Cache client interface injected into endpoint context. */\nexport interface CacheClient {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, ttl?: number): Promise<void>;\n del(key: string): Promise<void>;\n incr(key: string): Promise<number>;\n}\n\n/** Palbase service bindings for accessing other modules. */\nexport interface PalbaseBindings {\n auth: Record<string, unknown>;\n storage: Record<string, unknown>;\n}\n\n/** Endpoint context — injected into every handler. */\nexport interface EndpointContext<TInput = unknown> {\n input: TInput;\n params: Record<string, string>;\n query: Record<string, string>;\n headers: Record<string, string>;\n user: User | null;\n db: DBClient;\n env: Record<string, string>;\n log: Logger;\n cache: CacheClient;\n palbase: PalbaseBindings;\n requestId: string;\n projectId: string;\n environmentId: string;\n}\n\n/** Middleware function signature — uses MiddlewareContext (no input, not yet validated). */\nexport type Middleware = (\n ctx: MiddlewareContext,\n next: () => Promise<void>,\n) => Promise<void>;\n\n/** Configuration for defining an endpoint. */\nexport interface EndpointConfig<\n TInputSchema extends ZodSchema = ZodSchema,\n TOutputSchema extends ZodSchema = ZodSchema,\n> {\n method: HttpMethod;\n auth?: Partial<AuthConfig>;\n rateLimit?: RateLimitConfig;\n input?: TInputSchema;\n output?: TOutputSchema;\n middleware?: Middleware[];\n handler: (ctx: EndpointContext<z.infer<TInputSchema>>) => Promise<z.infer<TOutputSchema>>;\n}\n\n/** Define a type-safe endpoint. Input schema infers the ctx.input type. */\nexport function defineEndpoint<\n TInputSchema extends ZodSchema,\n TOutputSchema extends ZodSchema,\n>(config: EndpointConfig<TInputSchema, TOutputSchema>): EndpointConfig<TInputSchema, TOutputSchema> {\n return config;\n}\n","import type { DBClient, Logger, CacheClient, PalbaseBindings } from \"./endpoint.js\";\nimport type { User } from \"./types.js\";\n\n/** Middleware context — subset of EndpointContext without input (not yet validated). */\nexport interface MiddlewareContext {\n params: Record<string, string>;\n query: Record<string, string>;\n headers: Record<string, string>;\n user: User | null;\n db: DBClient;\n env: Record<string, string>;\n log: Logger;\n cache: CacheClient;\n palbase: PalbaseBindings;\n requestId: string;\n projectId: string;\n environmentId: string;\n}\n\n/** Middleware function signature — receives context and next function. */\nexport type MiddlewareHandler = (\n ctx: MiddlewareContext,\n next: () => Promise<void>,\n) => Promise<void>;\n\n/**\n * Define a middleware function for use in the middleware/ directory or\n * as endpoint-specific middleware.\n *\n * Middleware runs before the handler. Call `next()` to pass control\n * to the next middleware or handler. If `next()` is not called, the\n * handler will not execute.\n *\n * Errors thrown in middleware are caught by the pipeline and returned\n * as error responses.\n */\nexport function defineMiddleware(fn: MiddlewareHandler): MiddlewareHandler {\n return fn;\n}\n","/** HTTP error with structured error response format. */\nexport class HttpError extends Error {\n public readonly status: number;\n public readonly error: string;\n public readonly errorDescription: string;\n\n constructor(status: number, error: string, errorDescription: string) {\n super(errorDescription);\n this.name = \"HttpError\";\n this.status = status;\n this.error = error;\n this.errorDescription = errorDescription;\n }\n\n /**\n * Serialize to the standard Palbase error response format.\n * The `requestId` is injected by the runtime layer from the request context.\n * When called without arguments (e.g. JSON.stringify), request_id is omitted.\n */\n toJSON(requestId?: string): { error: string; error_description: string; status: number; request_id?: string } {\n const result: { error: string; error_description: string; status: number; request_id?: string } = {\n error: this.error,\n error_description: this.errorDescription,\n status: this.status,\n };\n if (requestId) {\n result.request_id = requestId;\n }\n return result;\n }\n}\n","import type { EndpointContext } from \"./endpoint.js\";\n\n/** Backoff strategy for worker retries. */\nexport type BackoffStrategy = \"exponential\" | \"linear\" | \"fixed\";\n\n/** Configuration for a background worker. */\nexport interface WorkerConfig<TPayload = unknown> {\n /** Worker name — must be unique across the project. */\n name: string;\n /** Maximum number of retries before sending to dead letter queue. Defaults to 3. */\n retry?: number;\n /** Execution timeout in seconds. Defaults to 30. */\n timeout?: number;\n /** Backoff strategy between retries. Defaults to \"exponential\". */\n backoff?: BackoffStrategy;\n /** Handler function that processes the job payload. */\n handler: (\n ctx: Omit<EndpointContext<TPayload>, \"input\" | \"params\" | \"query\" | \"headers\">,\n payload: TPayload,\n ) => Promise<void>;\n}\n\n/** Resolved worker configuration with defaults applied. */\nexport interface ResolvedWorkerConfig<TPayload = unknown> {\n name: string;\n retry: number;\n timeout: number;\n backoff: BackoffStrategy;\n handler: (\n ctx: Omit<EndpointContext<TPayload>, \"input\" | \"params\" | \"query\" | \"headers\">,\n payload: TPayload,\n ) => Promise<void>;\n}\n\n/** Valid worker name pattern: alphanumeric, underscore, hyphen only.\n * Prevents Redis key injection via colons or path separators. */\nconst VALID_WORKER_NAME = /^[a-zA-Z0-9_-]+$/;\n\n/** Default values for worker configuration. */\nconst WORKER_DEFAULTS = {\n retry: 3,\n timeout: 30,\n backoff: \"exponential\" as BackoffStrategy,\n} as const;\n\n/**\n * Define a background worker that processes jobs from the queue.\n *\n * Workers are placed in the `workers/` directory and auto-discovered at deploy time.\n *\n * @example\n * ```ts\n * export default defineWorker({\n * name: \"send-email\",\n * retry: 5,\n * timeout: 60,\n * backoff: \"exponential\",\n * handler: async (ctx, payload: { to: string; subject: string }) => {\n * await sendEmail(payload.to, payload.subject);\n * },\n * });\n * ```\n */\nexport function defineWorker<TPayload = unknown>(\n config: WorkerConfig<TPayload>,\n): ResolvedWorkerConfig<TPayload> {\n if (!config.name || config.name.trim() === \"\") {\n throw new Error(\"Worker name is required\");\n }\n\n if (!VALID_WORKER_NAME.test(config.name)) {\n throw new Error(\n `Invalid worker name \"${config.name}\": must match [a-zA-Z0-9_-]+`,\n );\n }\n\n if (config.retry !== undefined && (config.retry < 0 || !Number.isInteger(config.retry))) {\n throw new Error(\"Worker retry must be a non-negative integer\");\n }\n\n if (config.timeout !== undefined && config.timeout <= 0) {\n throw new Error(\"Worker timeout must be a positive number\");\n }\n\n if (\n config.backoff !== undefined &&\n ![\"exponential\", \"linear\", \"fixed\"].includes(config.backoff)\n ) {\n throw new Error(`Invalid backoff strategy: ${config.backoff}`);\n }\n\n return {\n name: config.name,\n retry: config.retry ?? WORKER_DEFAULTS.retry,\n timeout: config.timeout ?? WORKER_DEFAULTS.timeout,\n backoff: config.backoff ?? WORKER_DEFAULTS.backoff,\n handler: config.handler,\n };\n}\n","import type { DBClient, Logger, CacheClient, PalbaseBindings } from \"./endpoint.js\";\n\n/** Context injected into job handlers — subset of EndpointContext without request-specific fields. */\nexport interface JobContext {\n db: DBClient;\n env: Record<string, string>;\n log: Logger;\n cache: CacheClient;\n queue: {\n enqueue(workerName: string, payload: unknown): Promise<string>;\n };\n palbase: PalbaseBindings;\n projectId: string;\n environmentId: string;\n}\n\n/** Configuration for defining a scheduled job. */\nexport interface JobConfig {\n /** Unique job name — alphanumeric, underscore, hyphen only. */\n name: string;\n /** Cron expression (e.g., \"0 3 * * *\"). */\n schedule: string;\n /** Execution timeout in seconds. Defaults to 30. */\n timeout?: number;\n /** Job handler function. */\n handler: (ctx: JobContext) => Promise<void>;\n}\n\n/** Resolved job configuration with defaults applied. */\nexport interface ResolvedJobConfig {\n name: string;\n schedule: string;\n timeout: number;\n handler: (ctx: JobContext) => Promise<void>;\n}\n\n/** Valid job name pattern: alphanumeric, underscore, hyphen only. */\nconst VALID_JOB_NAME = /^[a-zA-Z0-9_-]+$/;\n\n/** Maximum allowed timeout in seconds (5 minutes, matching sandbox limits). */\nconst MAX_TIMEOUT_SECONDS = 300;\n\n/** Default values for job configuration. */\nconst JOB_DEFAULTS = {\n timeout: 30,\n} as const;\n\n/**\n * Cron expression validation.\n * Supports standard 5-field cron: minute hour day-of-month month day-of-week.\n * Each field allows: number, *, ranges (1-5), steps (star/2), lists (1,3,5).\n */\nfunction validateCronExpression(expression: string): string | null {\n const trimmed = expression.trim();\n if (trimmed === \"\") {\n return \"Cron expression is required\";\n }\n\n const parts = trimmed.split(/\\s+/);\n if (parts.length !== 5) {\n return `Invalid cron expression \"${trimmed}\": expected 5 fields (minute hour day month weekday), got ${parts.length}`;\n }\n\n const fieldNames = [\"minute\", \"hour\", \"day of month\", \"month\", \"day of week\"];\n const fieldRanges: [number, number][] = [\n [0, 59],\n [0, 23],\n [1, 31],\n [1, 12],\n [0, 7],\n ];\n\n for (let i = 0; i < 5; i++) {\n const field = parts[i]!;\n const name = fieldNames[i]!;\n const [min, max] = fieldRanges[i]!;\n\n const error = validateCronField(field, name, min, max);\n if (error !== null) {\n return error;\n }\n }\n\n return null;\n}\n\nfunction validateCronField(\n field: string,\n name: string,\n min: number,\n max: number,\n): string | null {\n // Split by comma for lists\n const listParts = field.split(\",\");\n for (const part of listParts) {\n // Check for step: */2, 1-5/2\n const stepParts = part.split(\"/\");\n if (stepParts.length > 2) {\n return `Invalid ${name} field: \"${field}\"`;\n }\n\n const base = stepParts[0]!;\n const step = stepParts[1];\n\n if (step !== undefined) {\n const stepNum = Number(step);\n if (!Number.isInteger(stepNum) || stepNum < 1) {\n return `Invalid step value in ${name} field: \"${field}\"`;\n }\n }\n\n if (base === \"*\") {\n continue;\n }\n\n // Check for range: 1-5\n if (base.includes(\"-\")) {\n const rangeParts = base.split(\"-\");\n if (rangeParts.length !== 2) {\n return `Invalid range in ${name} field: \"${field}\"`;\n }\n const rangeStart = Number(rangeParts[0]);\n const rangeEnd = Number(rangeParts[1]);\n if (\n !Number.isInteger(rangeStart) ||\n !Number.isInteger(rangeEnd) ||\n rangeStart < min ||\n rangeEnd > max ||\n rangeStart > rangeEnd\n ) {\n return `Invalid range in ${name} field: \"${field}\"`;\n }\n continue;\n }\n\n // Single number\n const num = Number(base);\n if (!Number.isInteger(num) || num < min || num > max) {\n return `Invalid value in ${name} field: \"${field}\"`;\n }\n }\n\n return null;\n}\n\n/**\n * Define a scheduled cron job.\n *\n * Jobs are placed in the `jobs/` directory and auto-discovered at deploy time.\n *\n * @example\n * ```ts\n * export default defineJob({\n * name: \"cleanup-expired\",\n * schedule: \"0 3 * * *\", // every day at 3 AM\n * timeout: 60,\n * handler: async (ctx) => {\n * await ctx.db.delete(\"sessions\", \"expired < NOW()\");\n * ctx.log.info(\"Cleaned up expired sessions\");\n * },\n * });\n * ```\n */\nexport function defineJob(config: JobConfig): ResolvedJobConfig {\n if (!config.name || config.name.trim() === \"\") {\n throw new Error(\"Job name is required\");\n }\n\n if (!VALID_JOB_NAME.test(config.name)) {\n throw new Error(\n `Invalid job name \"${config.name}\": must match [a-zA-Z0-9_-]+`,\n );\n }\n\n if (!config.schedule || config.schedule.trim() === \"\") {\n throw new Error(\"Job schedule is required\");\n }\n\n const cronError = validateCronExpression(config.schedule);\n if (cronError !== null) {\n throw new Error(cronError);\n }\n\n if (!config.handler) {\n throw new Error(\"Job handler is required\");\n }\n\n if (config.timeout !== undefined && config.timeout <= 0) {\n throw new Error(\"Job timeout must be a positive number\");\n }\n\n if (config.timeout !== undefined && !Number.isInteger(config.timeout)) {\n throw new Error(\"Job timeout must be an integer\");\n }\n\n if (config.timeout !== undefined && config.timeout > MAX_TIMEOUT_SECONDS) {\n throw new Error(\n `Job timeout ${config.timeout}s exceeds maximum ${MAX_TIMEOUT_SECONDS}s`,\n );\n }\n\n return {\n name: config.name,\n schedule: config.schedule.trim(),\n timeout: config.timeout ?? JOB_DEFAULTS.timeout,\n handler: config.handler,\n };\n}\n","import type { DBClient, Logger, CacheClient, PalbaseBindings } from \"./endpoint.js\";\n\n/** Supported webhook provider types. */\nexport type WebhookProvider =\n | \"stripe\"\n | \"github\"\n | \"twilio\"\n | \"sendgrid\"\n | \"slack\"\n | \"discord\"\n | \"livekit\";\n\n/** Context injected into webhook handlers — no user (webhooks are machine-to-machine). */\nexport interface WebhookContext {\n db: DBClient;\n env: Record<string, string>;\n log: Logger;\n cache: CacheClient;\n queue: {\n enqueue(workerName: string, payload: unknown): Promise<string>;\n };\n palbase: PalbaseBindings;\n projectId: string;\n environmentId: string;\n requestId: string;\n}\n\n/** Secret reference — resolves from environment variables at runtime. */\nexport interface EnvSecretRef {\n env: string;\n}\n\n/** Provider-specific event maps for type-safe event handlers. */\nexport interface ProviderEventMap {\n stripe: {\n \"checkout.session.completed\": Record<string, unknown>;\n \"payment_intent.succeeded\": Record<string, unknown>;\n \"payment_intent.payment_failed\": Record<string, unknown>;\n \"customer.subscription.created\": Record<string, unknown>;\n \"customer.subscription.updated\": Record<string, unknown>;\n \"customer.subscription.deleted\": Record<string, unknown>;\n \"invoice.paid\": Record<string, unknown>;\n \"invoice.payment_failed\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n github: {\n push: Record<string, unknown>;\n pull_request: Record<string, unknown>;\n issues: Record<string, unknown>;\n \"pull_request.opened\": Record<string, unknown>;\n \"pull_request.closed\": Record<string, unknown>;\n \"pull_request.merged\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n twilio: {\n \"message.received\": Record<string, unknown>;\n \"message.sent\": Record<string, unknown>;\n \"call.completed\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n sendgrid: {\n delivered: Record<string, unknown>;\n bounce: Record<string, unknown>;\n open: Record<string, unknown>;\n click: Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n slack: {\n url_verification: Record<string, unknown>;\n event_callback: Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n discord: {\n PING: Record<string, unknown>;\n MESSAGE_CREATE: Record<string, unknown>;\n INTERACTION_CREATE: Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n livekit: {\n \"room.started\": Record<string, unknown>;\n \"room.finished\": Record<string, unknown>;\n \"participant.joined\": Record<string, unknown>;\n \"participant.left\": Record<string, unknown>;\n [key: string]: Record<string, unknown>;\n };\n}\n\n/** Event handler function type. */\nexport type WebhookEventHandler<TEvent = Record<string, unknown>> = (\n ctx: WebhookContext,\n event: TEvent,\n) => Promise<void>;\n\n/** Provider-based webhook configuration. */\nexport interface ProviderWebhookConfig<P extends WebhookProvider = WebhookProvider> {\n provider: P;\n secret: EnvSecretRef;\n events: {\n [K in keyof ProviderEventMap[P]]?: WebhookEventHandler<ProviderEventMap[P][K]>;\n };\n}\n\n/** Incoming request representation for custom verify functions. */\nexport interface WebhookRequest {\n headers: Record<string, string>;\n body: string;\n method: string;\n url: string;\n}\n\n/** Custom webhook configuration. */\nexport interface CustomWebhookConfig {\n path: string;\n verify?: (req: WebhookRequest) => Promise<boolean> | boolean;\n handler: (ctx: WebhookContext, payload: Record<string, unknown>) => Promise<void>;\n}\n\n/** Resolved provider webhook (internal). */\nexport interface ResolvedProviderWebhook<P extends WebhookProvider = WebhookProvider> {\n type: \"provider\";\n provider: P;\n secret: EnvSecretRef;\n events: Record<string, WebhookEventHandler>;\n}\n\n/** Resolved custom webhook (internal). */\nexport interface ResolvedCustomWebhook {\n type: \"custom\";\n path: string;\n verify?: (req: WebhookRequest) => Promise<boolean> | boolean;\n handler: (ctx: WebhookContext, payload: Record<string, unknown>) => Promise<void>;\n}\n\n/** Union of resolved webhook types. */\nexport type ResolvedWebhookConfig = ResolvedProviderWebhook | ResolvedCustomWebhook;\n\n/** Valid webhook path pattern: starts with /, alphanumeric + hyphen + slash. */\nconst VALID_WEBHOOK_PATH = /^\\/[a-zA-Z0-9/_-]+$/;\n\n/**\n * Define a provider-based webhook.\n *\n * @example\n * ```ts\n * export default defineWebhook({\n * provider: \"stripe\",\n * secret: { env: \"STRIPE_WEBHOOK_SECRET\" },\n * events: {\n * \"checkout.session.completed\": async (ctx, event) => {\n * await ctx.db.insert(\"orders\", { status: \"paid\" });\n * },\n * },\n * });\n * ```\n */\nexport function defineWebhook<P extends WebhookProvider>(\n config: ProviderWebhookConfig<P>,\n): ResolvedProviderWebhook<P>;\n\n/**\n * Define a custom webhook with optional verification.\n *\n * @example\n * ```ts\n * export default defineWebhook({\n * path: \"/webhooks/livekit\",\n * verify: async (req) => req.headers[\"x-api-key\"] === \"secret\",\n * handler: async (ctx, payload) => {\n * ctx.log.info(\"Received webhook\", payload);\n * },\n * });\n * ```\n */\nexport function defineWebhook(config: CustomWebhookConfig): ResolvedCustomWebhook;\n\nexport function defineWebhook(\n config: ProviderWebhookConfig | CustomWebhookConfig,\n): ResolvedWebhookConfig {\n if (\"provider\" in config) {\n return validateProviderWebhook(config);\n }\n return validateCustomWebhook(config);\n}\n\nfunction validateProviderWebhook<P extends WebhookProvider>(\n config: ProviderWebhookConfig<P>,\n): ResolvedProviderWebhook<P> {\n if (!config.provider) {\n throw new Error(\"Webhook provider is required\");\n }\n\n const validProviders: WebhookProvider[] = [\n \"stripe\", \"github\", \"twilio\", \"sendgrid\", \"slack\", \"discord\", \"livekit\",\n ];\n if (!validProviders.includes(config.provider)) {\n throw new Error(\n `Invalid webhook provider \"${config.provider}\": must be one of ${validProviders.join(\", \")}`,\n );\n }\n\n if (!config.secret) {\n throw new Error(\"Webhook secret is required (use { env: \\\"SECRET_NAME\\\" })\");\n }\n\n if (typeof config.secret.env !== \"string\" || config.secret.env.trim() === \"\") {\n throw new Error(\"Webhook secret env name must be a non-empty string\");\n }\n\n if (!config.events || Object.keys(config.events).length === 0) {\n throw new Error(\"At least one event handler is required\");\n }\n\n for (const [eventName, handler] of Object.entries(config.events)) {\n if (typeof handler !== \"function\") {\n throw new Error(`Event handler for \"${eventName}\" must be a function`);\n }\n }\n\n return {\n type: \"provider\",\n provider: config.provider,\n secret: config.secret,\n events: config.events as Record<string, WebhookEventHandler>,\n };\n}\n\nfunction validateCustomWebhook(config: CustomWebhookConfig): ResolvedCustomWebhook {\n if (!config.path || config.path.trim() === \"\") {\n throw new Error(\"Webhook path is required\");\n }\n\n if (!VALID_WEBHOOK_PATH.test(config.path)) {\n throw new Error(\n `Invalid webhook path \"${config.path}\": must start with / and contain only alphanumeric, hyphen, underscore, slash`,\n );\n }\n\n if (!config.handler) {\n throw new Error(\"Webhook handler is required\");\n }\n\n if (typeof config.handler !== \"function\") {\n throw new Error(\"Webhook handler must be a function\");\n }\n\n if (config.verify !== undefined && typeof config.verify !== \"function\") {\n throw new Error(\"Webhook verify must be a function\");\n }\n\n return {\n type: \"custom\",\n path: config.path,\n verify: config.verify,\n handler: config.handler,\n };\n}\n","import type { DBClient, Logger, CacheClient, PalbaseBindings } from \"./endpoint.js\";\n\n/** Context injected into hook handlers. */\nexport interface HookContext {\n db: DBClient;\n env: Record<string, string>;\n log: Logger;\n cache: CacheClient;\n queue: {\n enqueue(workerName: string, payload: unknown): Promise<string>;\n };\n palbase: PalbaseBindings;\n projectId: string;\n environmentId: string;\n}\n\n// --- Auth Event Payloads ---\n\n/** Payload for auth.onUserCreated hook. */\nexport interface UserCreatedEvent {\n user: {\n id: string;\n email: string;\n role: string;\n metadata: Record<string, unknown>;\n createdAt: string;\n };\n}\n\n/** Payload for auth.onSignIn hook. */\nexport interface SignInEvent {\n user: {\n id: string;\n email: string;\n role: string;\n };\n provider: string;\n timestamp: string;\n}\n\n/** Payload for auth.onSignOut hook. */\nexport interface SignOutEvent {\n user: {\n id: string;\n email: string;\n };\n timestamp: string;\n}\n\n/** Payload for auth.onPasswordReset hook. */\nexport interface PasswordResetEvent {\n user: {\n id: string;\n email: string;\n };\n timestamp: string;\n}\n\n// --- Storage Event Payloads ---\n\n/** Payload for storage.onFileUploaded hook. */\nexport interface FileUploadedEvent {\n file: {\n id: string;\n name: string;\n bucket: string;\n path: string;\n size: number;\n contentType: string;\n };\n}\n\n/** Payload for storage.onFileDeleted hook. */\nexport interface FileDeletedEvent {\n file: {\n id: string;\n name: string;\n bucket: string;\n path: string;\n };\n}\n\n// --- Documents Event Payloads ---\n\n/** Payload for documents.onDocumentCreated hook. */\nexport interface DocumentCreatedEvent {\n document: {\n id: string;\n collection: string;\n data: Record<string, unknown>;\n };\n}\n\n/** Payload for documents.onDocumentUpdated hook. */\nexport interface DocumentUpdatedEvent {\n document: {\n id: string;\n collection: string;\n data: Record<string, unknown>;\n previousData: Record<string, unknown>;\n };\n}\n\n/** Payload for documents.onDocumentDeleted hook. */\nexport interface DocumentDeletedEvent {\n document: {\n id: string;\n collection: string;\n data: Record<string, unknown>;\n };\n}\n\n// --- Hook Handler Types ---\n\nexport type HookHandler<TEvent> = (ctx: HookContext, event: TEvent) => Promise<void>;\n\n/** Resolved hook configuration (internal). */\nexport interface ResolvedHook<TEvent = unknown> {\n module: string;\n event: string;\n handler: HookHandler<TEvent>;\n}\n\n// --- Auth Hooks ---\n\nexport const auth = {\n onUserCreated(handler: HookHandler<UserCreatedEvent>): ResolvedHook<UserCreatedEvent> {\n return { module: \"auth\", event: \"user.created\", handler };\n },\n\n onSignIn(handler: HookHandler<SignInEvent>): ResolvedHook<SignInEvent> {\n return { module: \"auth\", event: \"user.sign_in\", handler };\n },\n\n onSignOut(handler: HookHandler<SignOutEvent>): ResolvedHook<SignOutEvent> {\n return { module: \"auth\", event: \"user.sign_out\", handler };\n },\n\n onPasswordReset(handler: HookHandler<PasswordResetEvent>): ResolvedHook<PasswordResetEvent> {\n return { module: \"auth\", event: \"user.password_reset\", handler };\n },\n};\n\n// --- Storage Hooks ---\n\nexport const storage = {\n onFileUploaded(handler: HookHandler<FileUploadedEvent>): ResolvedHook<FileUploadedEvent> {\n return { module: \"storage\", event: \"file.uploaded\", handler };\n },\n\n onFileDeleted(handler: HookHandler<FileDeletedEvent>): ResolvedHook<FileDeletedEvent> {\n return { module: \"storage\", event: \"file.deleted\", handler };\n },\n};\n\n// --- Documents Hooks ---\n\nexport const documents = {\n onDocumentCreated(handler: HookHandler<DocumentCreatedEvent>): ResolvedHook<DocumentCreatedEvent> {\n return { module: \"documents\", event: \"document.created\", handler };\n },\n\n onDocumentUpdated(handler: HookHandler<DocumentUpdatedEvent>): ResolvedHook<DocumentUpdatedEvent> {\n return { module: \"documents\", event: \"document.updated\", handler };\n },\n\n onDocumentDeleted(handler: HookHandler<DocumentDeletedEvent>): ResolvedHook<DocumentDeletedEvent> {\n return { module: \"documents\", event: \"document.deleted\", handler };\n },\n};\n"],"mappings":"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","names":[]}