Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | 2x 2x 3x 3x 3x 2x 1x 2x 11x 11x 11x 11x 5x 6x 6x 1x 5x 5x 4x 1x 2x 3x 3x 3x 3x 3x 3x 3x 1x 2x 1x 1x 2x 2x 2x 2x 2x 2x 1x 1x 2x 2x 2x 2x 2x 1x 1x | import { Hono } from "hono";
import type { Dal } from "../../../dal";
import { error, handleError, success } from "../../../lib/response";
import { requireWhatsAppClient } from "../../../lib/whatsapp/client";
import type { WhatsAppTemplateCreateRequest } from "../../../lib/whatsapp/types";
import type { Services } from "../../../services";
type Env = {
Bindings: CloudflareBindings;
Variables: {
user: { id: string; name: string; email: string } | null;
session: unknown;
dal: Dal;
services: Services;
};
};
const templates = new Hono<Env>();
// GET / - List all templates
templates.get("/", async (c) => {
try {
const services = c.get("services");
const items = await services.waTemplate.list();
return success(c, { templates: items });
} catch (err) {
return handleError(c, err);
}
});
// POST / - Create template
templates.post("/", async (c) => {
try {
const services = c.get("services");
const body = await c.req.json<{
name?: string;
language?: string;
category?: string;
components?: unknown[];
}>();
if (
!body.name ||
!body.language ||
!body.category ||
!Array.isArray(body.components) ||
body.components.length === 0
) {
return error(
c,
"VALIDATION_ERROR",
"name, language, category, and components (non-empty array) are required",
400,
);
}
const validCategories = ["MARKETING", "UTILITY", "AUTHENTICATION"];
if (!validCategories.includes(body.category)) {
return error(
c,
"VALIDATION_ERROR",
`category must be one of: ${validCategories.join(", ")}`,
400,
);
}
const client = requireWhatsAppClient(c.env);
const template = await services.waTemplate.create(
body as WhatsAppTemplateCreateRequest,
client,
);
return success(c, { template }, 201);
} catch (err) {
return handleError(c, err);
}
});
// PUT /:id - Edit template (only components can be updated after creation)
//
// KEPT DELIBERATELY, AND API-ONLY. The portal's `whatsappApi.updateTemplate`
// client method had no caller — no hook, no edit affordance on the templates
// page — and is being removed. The route is not, because it is the only way to
// amend a submitted template's components, and a template already sent to Meta
// is otherwise immutable from our side.
//
// Verified before keeping it: template SYNC does not go through here. `POST
// /sync` calls `services.waTemplate.sync()`, which upserts via
// `dal.waTemplates.upsertByName` and never touches `services.waTemplate
// .update()`. The Meta status webhook likewise writes through the DAL
// directly. So this handler has exactly one entry point — a direct API call —
// and deleting it would remove a capability rather than dead weight.
templates.put("/:id", async (c) => {
try {
const services = c.get("services");
const id = Number(c.req.param("id"));
const body = await c.req.json<{ components?: unknown[] }>();
const allowed: Record<string, unknown> = {};
if (body.components !== undefined) allowed.components = body.components;
if (Object.keys(allowed).length === 0) {
return error(c, "VALIDATION_ERROR", "No updatable fields provided", 400);
}
const template = await services.waTemplate.update(id, allowed);
return success(c, { template });
} catch (err) {
return handleError(c, err);
}
});
// DELETE /:id - Delete template
templates.delete("/:id", async (c) => {
try {
const services = c.get("services");
const id = Number(c.req.param("id"));
const client = requireWhatsAppClient(c.env);
await services.waTemplate.delete(id, client);
return success(c, { message: "Template deleted" });
} catch (err) {
return handleError(c, err);
}
});
// POST /sync - Force sync from Meta API
templates.post("/sync", async (c) => {
try {
const services = c.get("services");
const client = requireWhatsAppClient(c.env);
const synced = await services.waTemplate.sync(client);
return success(c, { synced });
} catch (err) {
return handleError(c, err);
}
});
export default templates;
|