From 6e3cba4308211c2c5ab2c1e4a726006d43b54d32 Mon Sep 17 00:00:00 2001 From: makearmy Date: Mon, 29 Sep 2025 11:10:26 -0400 Subject: [PATCH] added Schema Bot --- .env.local | 1 + lib/directus.ts | 50 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/.env.local b/.env.local index 7c42d042..5558d126 100644 --- a/.env.local +++ b/.env.local @@ -5,4 +5,5 @@ NEXT_PUBLIC_API_BASE_URL=https://forms.lasereverything.net DIRECTUS_URL=https://forms.lasereverything.net DIRECTUS_TOKEN_SUBMIT=2uD5w9sFLgPtTtjqfUft8i_pLZRzCSTu DIRECTUS_TOKEN_ADMIN_REGISTER=l_QqNXKpi--Dt-hHDncHyBX0eiHNYZr7 +DIRECTUS_TOKEN_SCHEMA_READ=BCaWlfTkuVIYyEnwBCXujLTIY6lScZbF DIRECTUS_ROLE_MEMBER_ID=296a28bc-60ab-4251-8bef-27f6dfb67948 diff --git a/lib/directus.ts b/lib/directus.ts index a5740286..d8c03fdb 100644 --- a/lib/directus.ts +++ b/lib/directus.ts @@ -4,6 +4,7 @@ const BASE = process.env.DIRECTUS_URL!; const TOKEN_SUBMIT = process.env.DIRECTUS_TOKEN_SUBMIT!; const TOKEN_ADMIN_REGISTER = process.env.DIRECTUS_TOKEN_ADMIN_REGISTER || ""; +const TOKEN_SCHEMA_READ = process.env.DIRECTUS_TOKEN_SCHEMA_READ || ""; // ← new (schema-bot) const ROLE_MEMBER_ID_ENV = process.env.DIRECTUS_ROLE_MEMBER_ID || ""; const ROLE_MEMBER_NAME_ENV = process.env.DIRECTUS_ROLE_MEMBER_NAME || "Users"; @@ -12,7 +13,14 @@ process.env.DIRECTUS_PROJECTS_COLLECTION || "projects"; if (!BASE) console.warn("[directus] Missing DIRECTUS_URL"); if (!TOKEN_SUBMIT) console.warn("[directus] Missing DIRECTUS_TOKEN_SUBMIT"); -if (!TOKEN_ADMIN_REGISTER) console.warn("[directus] Missing DIRECTUS_TOKEN_ADMIN_REGISTER (used for registration)"); +if (!TOKEN_ADMIN_REGISTER) + console.warn( + "[directus] Missing DIRECTUS_TOKEN_ADMIN_REGISTER (used for registration)" + ); +if (!TOKEN_SCHEMA_READ) + console.warn( + "[directus] Missing DIRECTUS_TOKEN_SCHEMA_READ (used for schema reads)" + ); export function bytesFromMB(mb: number) { return Math.round(mb * 1024 * 1024); @@ -76,6 +84,30 @@ export async function directusAdminFetch( return (json ?? {}) as T; } +/** Schema-safe fetch: prefers schema-bot token, falls back to admin-register, then submit */ +export async function directusSchemaFetch( + path: string, + init?: RequestInit +): Promise { + const token = + TOKEN_SCHEMA_READ || TOKEN_ADMIN_REGISTER || TOKEN_SUBMIT; + + const res = await fetch(`${BASE}${path}`, { + ...init, + headers: { + Accept: "application/json", + Authorization: `Bearer ${token}`, + ...(init?.headers || {}), + }, + }); + + const { json, text } = await parseJsonSafe(res); + if (!res.ok) { + throw new Error(`Directus error ${res.status}: ${text || res.statusText}`); + } + return (json ?? {}) as T; +} + /* ───────────────────────────────────────────────────────────── * On-the-fly folder lookup by "path" = "/" * Caches results in-memory. If lookup is forbidden (403) or not found, @@ -120,7 +152,10 @@ async function getFolderIdByPath(path: string): Promise { return undefined; } - const parts = path.split("/").map((s) => s.trim()).filter(Boolean); + const parts = path + .split("/") + .map((s) => s.trim()) + .filter(Boolean); const [parentName, childName] = parts; const eq = (a?: string | null, b?: string | null) => @@ -179,10 +214,9 @@ export async function uploadFile( const { json, text } = await parseJsonSafe(res); if (!res.ok) { throw new Error( - `File upload failed: status=${res.status} ${res.statusText} body=${(text || "").slice( - 0, - 400 - ) || ""}` + `File upload failed: status=${res.status} ${res.statusText} body=${ + (text || "").slice(0, 400) || "" + }` ); } @@ -284,7 +318,9 @@ export async function createDirectusUser(input: { } /** Find user's email by username (returns null if not found) */ -export async function emailForUsername(username: string): Promise { +export async function emailForUsername( + username: string +): Promise { const q = `/users?filter[username][_eq]=${encodeURIComponent( username )}&fields=email&limit=1`;