@vaia-lab/sdk 0.1.2 → 0.2.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 +49 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +49 -16
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
package/dist/index.cjs
CHANGED
|
@@ -198,14 +198,28 @@ __export(jwt_exports, {
|
|
|
198
198
|
|
|
199
199
|
// src/jwt-utils.ts
|
|
200
200
|
var enc2 = new TextEncoder();
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
var utf8Strict = new TextDecoder("utf-8", { fatal: true });
|
|
202
|
+
var utf8Loose = new TextDecoder("utf-8");
|
|
203
|
+
var latin1 = new TextDecoder("latin1");
|
|
204
|
+
var JWT_PAYLOAD_VERSION = 2;
|
|
205
|
+
function bytesToB64url(bytes) {
|
|
206
|
+
let bin = "";
|
|
207
|
+
const CHUNK = 32768;
|
|
208
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
209
|
+
bin += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
|
|
210
|
+
}
|
|
211
|
+
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
204
212
|
}
|
|
205
|
-
function
|
|
213
|
+
function b64urlToBytes(str2) {
|
|
206
214
|
const padded = str2.replace(/-/g, "+").replace(/_/g, "/");
|
|
207
215
|
const pad = padded.length % 4;
|
|
208
|
-
|
|
216
|
+
const bin = atob(pad ? padded + "=".repeat(4 - pad) : padded);
|
|
217
|
+
const out = new Uint8Array(new ArrayBuffer(bin.length));
|
|
218
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
219
|
+
return out;
|
|
220
|
+
}
|
|
221
|
+
function textToB64url(text) {
|
|
222
|
+
return bytesToB64url(enc2.encode(text));
|
|
209
223
|
}
|
|
210
224
|
async function importHMACKey2(secret) {
|
|
211
225
|
return crypto.subtle.importKey(
|
|
@@ -216,13 +230,33 @@ async function importHMACKey2(secret) {
|
|
|
216
230
|
["sign", "verify"]
|
|
217
231
|
);
|
|
218
232
|
}
|
|
219
|
-
var HEADER =
|
|
233
|
+
var HEADER = textToB64url(JSON.stringify({ alg: "HS256", typ: "JWT" }));
|
|
220
234
|
async function jwtSign(payload, secret) {
|
|
221
|
-
const body =
|
|
235
|
+
const body = textToB64url(JSON.stringify({ ...payload, v: JWT_PAYLOAD_VERSION }));
|
|
222
236
|
const unsigned = `${HEADER}.${body}`;
|
|
223
237
|
const key = await importHMACKey2(secret);
|
|
224
238
|
const sig = await crypto.subtle.sign("HMAC", key, enc2.encode(unsigned));
|
|
225
|
-
return `${unsigned}.${
|
|
239
|
+
return `${unsigned}.${bytesToB64url(new Uint8Array(sig))}`;
|
|
240
|
+
}
|
|
241
|
+
function decodePayload(body) {
|
|
242
|
+
const bytes = b64urlToBytes(body);
|
|
243
|
+
let sonda;
|
|
244
|
+
try {
|
|
245
|
+
sonda = JSON.parse(latin1.decode(bytes));
|
|
246
|
+
} catch {
|
|
247
|
+
throw new VAIAError("JWT payload inv\xE1lido", "JWT_PAYLOAD_INVALID", 401);
|
|
248
|
+
}
|
|
249
|
+
const version = typeof sonda["v"] === "number" ? sonda["v"] : 1;
|
|
250
|
+
if (version < 2) return sonda;
|
|
251
|
+
try {
|
|
252
|
+
return JSON.parse(utf8Strict.decode(bytes));
|
|
253
|
+
} catch {
|
|
254
|
+
try {
|
|
255
|
+
return JSON.parse(utf8Loose.decode(bytes));
|
|
256
|
+
} catch {
|
|
257
|
+
throw new VAIAError("JWT payload inv\xE1lido", "JWT_PAYLOAD_INVALID", 401);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
226
260
|
}
|
|
227
261
|
async function jwtVerify(token, secret) {
|
|
228
262
|
const parts = token.split(".");
|
|
@@ -232,17 +266,16 @@ async function jwtVerify(token, secret) {
|
|
|
232
266
|
const [header, body, sig] = parts;
|
|
233
267
|
const unsigned = `${header}.${body}`;
|
|
234
268
|
const key = await importHMACKey2(secret);
|
|
235
|
-
|
|
236
|
-
const valid = await crypto.subtle.verify("HMAC", key, sigBytes, enc2.encode(unsigned));
|
|
237
|
-
if (!valid) {
|
|
238
|
-
throw new VAIAError("Firma JWT inv\xE1lida", "JWT_SIGNATURE_INVALID", 401);
|
|
239
|
-
}
|
|
240
|
-
let payload;
|
|
269
|
+
let valid;
|
|
241
270
|
try {
|
|
242
|
-
|
|
271
|
+
valid = await crypto.subtle.verify("HMAC", key, b64urlToBytes(sig), enc2.encode(unsigned));
|
|
243
272
|
} catch {
|
|
244
|
-
throw new VAIAError("JWT
|
|
273
|
+
throw new VAIAError("JWT malformado", "JWT_MALFORMED", 401);
|
|
274
|
+
}
|
|
275
|
+
if (!valid) {
|
|
276
|
+
throw new VAIAError("Firma JWT inv\xE1lida", "JWT_SIGNATURE_INVALID", 401);
|
|
245
277
|
}
|
|
278
|
+
const payload = decodePayload(body);
|
|
246
279
|
if (typeof payload.exp === "number" && Date.now() / 1e3 > payload.exp) {
|
|
247
280
|
throw new VAIAError("JWT expirado", "JWT_EXPIRED", 401);
|
|
248
281
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/gandia/index.ts","../src/crypto.ts","../src/types.ts","../src/gandia/verify.ts","../src/gandia/jwt.ts","../src/jwt-utils.ts","../src/gandia/respond.ts","../src/gandia/permissions.ts","../src/handeia/index.ts","../src/handeia/verify.ts","../src/handeia/jwt.ts","../src/define.ts"],"sourcesContent":["/**\n * @vaia/sdk — VAIA Platform Integration SDK\n *\n * Provides two namespaces:\n * gandia → Gandia-7 (institutional platform)\n * handeia → Handeia (personal platform)\n *\n * Quick start:\n * import { gandia, handeia, defineCapability, VAIAError } from '@vaia/sdk'\n */\n\n// ─── Platform namespaces ──────────────────────────────────────────────────────\n\nimport * as _gandia from './gandia/index.js'\nimport * as _handeia from './handeia/index.js'\n\nexport const gandia = _gandia\nexport const handeia = _handeia\n\n// ─── defineCapability + manifest ─────────────────────────────────────────────\n\nexport { defineCapability, toManifest } from './define.js'\nexport type { CapabilityConfig, VAIAManifest } from './define.js'\n\n// ─── Shared error class ───────────────────────────────────────────────────────\n\nexport { VAIAError } from './types.js'\n\n// ─── All types (re-exported for consumer convenience) ─────────────────────────\n\nexport type {\n // Core enums\n PublishType,\n EcoTarget,\n NodeType,\n Risk,\n Surface,\n OutputType,\n\n // Contexts\n GandiaContext,\n GandiaTenant,\n GandiaUser,\n HandeiaContext,\n HandeiaUser,\n\n // JWT claims\n GandiaJWTClaims,\n HandeiaJWTClaims,\n\n // Response payloads\n CardPayload,\n TablePayload,\n WidgetPayload,\n ActionPayload,\n AuditRecord,\n RespondOpts,\n SurfaceHandlers,\n\n // Response types\n VAIAResponse,\n CardResponse,\n TableResponse,\n TextResponse,\n WidgetResponse,\n ActionResponse,\n DataResponse,\n ErrorResponse,\n} from './types.js'\n","/**\n * gandia — integration namespace for Gandia-7 (institutional platform).\n *\n * Quick start:\n * import { gandia } from '@vaia/sdk'\n *\n * export async function POST(req: Request) {\n * try {\n * const { ctx } = await gandia.verify(req, process.env.GANDIA_KEY_SECRET!)\n * gandia.require(ctx, 'read:students')\n * const data = await myDb.getStudents(ctx.tenant.id)\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Total alumnos', value: data.length }),\n * table: () => ({ columns: ['nombre', 'riesgo'], rows: data }),\n * text: () => `${data.length} alumnos en ${ctx.tenant.name}`,\n * })\n * } catch (err) {\n * if (err instanceof VAIAError) return gandia.respond.error(err.message, err.status)\n * throw err\n * }\n * }\n */\n\nexport { verify, isProbe, type VerifyResult } from './verify.js'\nexport * as jwt from './jwt.js'\nexport { respond, make } from './respond.js'\nexport { can, canAll, canAny, require, requireAll } from './permissions.js'\n","/**\n * HMAC-SHA256 utilities using the Web Crypto API.\n * Zero dependencies — works in Node 18+, Edge, Bun, Deno, browsers.\n */\n\nconst enc = new TextEncoder()\n\nfunction hexToBytes(hex: string): Uint8Array {\n if (hex.length % 2 !== 0) throw new Error('Invalid hex string')\n const bytes = new Uint8Array(hex.length / 2)\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16)\n }\n return bytes\n}\n\nasync function importHMACKey(secret: string): Promise<CryptoKey> {\n return crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n )\n}\n\n/** Signs `data` with HMAC-SHA256, returns lowercase hex. */\nexport async function hmacSign(secret: string, data: string): Promise<string> {\n const key = await importHMACKey(secret)\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(data))\n return Array.from(new Uint8Array(sig))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Constant-time HMAC-SHA256 verification.\n * Uses Web Crypto `verify` to avoid timing attacks.\n */\nexport async function hmacVerify(secret: string, data: string, hexSignature: string): Promise<boolean> {\n try {\n const key = await importHMACKey(secret)\n const sigBytes = hexToBytes(hexSignature)\n return await crypto.subtle.verify('HMAC', key, sigBytes, enc.encode(data))\n } catch {\n return false\n }\n}\n","// ─── Core enums ───────────────────────────────────────────────────────────────\n\nexport type PublishType = 'app' | 'ia' | 'skill' | 'eco'\nexport type EcoTarget = 'gandia' | 'handeia' | 'both'\nexport type NodeType = 'widget' | 'artefacto' | 'espacio' | 'skill' | 'agente'\nexport type Risk = 'low' | 'medium' | 'high'\nexport type Surface = 'card' | 'table' | 'text' | 'widget' | 'action' | 'data'\nexport type OutputType = Surface\n\n// ─── Gandia context ───────────────────────────────────────────────────────────\n\nexport interface GandiaTenant {\n id: string\n name: string\n sector: string\n}\n\nexport interface GandiaUser {\n id: string\n role: string\n email?: string | undefined\n}\n\n/** Context injected by GAIA on every invoke call to the developer's server. */\nexport interface GandiaContext {\n capability_id: string\n call_id: string\n tenant: GandiaTenant\n user: GandiaUser\n permissions: string[]\n trigger: 'user_query' | 'gaia_invoke' | 'event'\n /** Surface HAIA wants to render — determines which respond.* to use. */\n surface: Surface\n query?: string | undefined\n}\n\n// ─── Handeia context ──────────────────────────────────────────────────────────\n\nexport interface HandeiaUser {\n id: string\n email?: string | undefined\n name?: string | undefined\n}\n\n/** Context injected by HAIA on every invoke call to the developer's server. */\nexport interface HandeiaContext {\n capability_id: string\n call_id: string\n user: HandeiaUser\n permissions: string[]\n trigger: 'user_action' | 'haia_invoke' | 'schedule'\n /** Surface HAIA wants to render. */\n surface: Surface\n query?: string | undefined\n}\n\n// ─── JWT claims ───────────────────────────────────────────────────────────────\n\nexport interface GandiaJWTClaims {\n sub: string // user_id\n tenant_id: string\n email?: string | undefined\n role?: string | undefined\n permissions: string[]\n iat: number\n exp: number\n}\n\nexport interface HandeiaJWTClaims {\n sub: string // user_id\n email?: string | undefined\n name?: string | undefined\n permissions: string[]\n iat: number\n exp: number\n}\n\n// ─── Response payloads ────────────────────────────────────────────────────────\n\nexport interface AuditRecord {\n data_sources?: string[] | undefined\n records_accessed?: number | undefined\n [key: string]: unknown\n}\n\nexport interface RespondOpts {\n call_id?: string | undefined\n audit?: AuditRecord | undefined\n}\n\nexport interface CardPayload {\n title: string\n value?: string | number | undefined\n unit?: string | undefined\n trend?: 'up' | 'down' | 'neutral' | undefined\n icon?: string | undefined\n subtitle?: string | undefined\n color?: string | undefined\n [key: string]: unknown\n}\n\nexport interface TablePayload {\n columns: string[] | Array<{ key: string; label: string; type?: string | undefined }>\n rows: Array<Record<string, unknown>>\n total?: number | undefined\n page?: number | undefined\n per_page?: number | undefined\n}\n\nexport interface WidgetPayload {\n url: string\n height?: number | string | undefined\n width?: number | string | undefined\n meta?: Record<string, unknown> | undefined\n}\n\nexport interface ActionPayload {\n type: string\n label?: string | undefined\n params?: Record<string, unknown> | undefined\n confirm?: boolean | undefined\n destructive?: boolean | undefined\n}\n\n// ─── Typed VAIA response objects (returned by make.*) ────────────────────────\n\ninterface BaseVAIAResponse {\n ok: true\n call_id?: string | undefined\n audit?: AuditRecord | undefined\n}\n\nexport type CardResponse = BaseVAIAResponse & { output_type: 'card'; data: CardPayload }\nexport type TableResponse = BaseVAIAResponse & { output_type: 'table'; data: TablePayload }\nexport type TextResponse = BaseVAIAResponse & { output_type: 'text'; text: string; markdown?: boolean | undefined }\nexport type WidgetResponse = BaseVAIAResponse & { output_type: 'widget'; data: WidgetPayload }\nexport type ActionResponse = BaseVAIAResponse & { output_type: 'action'; data: ActionPayload }\nexport type DataResponse = BaseVAIAResponse & { output_type: 'data'; data: Record<string, unknown> }\nexport type ErrorResponse = { ok: false; error: string; code?: string | undefined }\n\nexport type VAIAResponse =\n | CardResponse\n | TableResponse\n | TextResponse\n | WidgetResponse\n | ActionResponse\n | DataResponse\n\n// ─── Surface handler map ──────────────────────────────────────────────────────\n\nexport type SurfaceHandlers = Partial<{\n card: () => CardPayload | Promise<CardPayload>\n table: () => TablePayload | Promise<TablePayload>\n text: () => string | Promise<string>\n widget: () => WidgetPayload | Promise<WidgetPayload>\n action: () => ActionPayload | Promise<ActionPayload>\n data: () => Record<string, unknown> | Promise<Record<string, unknown>>\n}>\n\n// ─── Capability definition ────────────────────────────────────────────────────\n\nexport interface SurfaceConfig {\n endpoint: string\n description?: string | undefined\n}\n\nexport interface CapabilityConfig {\n /** Unique capability ID — reverse domain: 'mx.mi-capacidad' */\n id: string\n name: string\n version: string\n /** Which VAIA platform(s) this capability targets. */\n target: EcoTarget\n type: PublishType\n level?: 'widget' | 'artefacto' | 'espacio' | undefined\n sector: string\n /** Which surfaces the capability can respond to, and their invoke endpoint. */\n surfaces: Partial<Record<Surface, SurfaceConfig>>\n permissions: string[]\n risk: Risk\n description?: string | undefined\n tags?: string[] | undefined\n /** Set to true if your app has its own login (triggers JWT bypass flow). */\n has_own_auth?: boolean | undefined\n stores_data?: boolean | undefined\n trains_models?: boolean | undefined\n requires_consent?: boolean | undefined\n}\n\n// ─── Errors ───────────────────────────────────────────────────────────────────\n\nexport class VAIAError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly status: number = 500,\n ) {\n super(message)\n this.name = 'VAIAError'\n }\n}\n","/**\n * gandia.verify — verifies an incoming invoke call from Gandia-7.\n *\n * Checks:\n * 1. X-Gandia-Signature (HMAC-SHA256 over timestamp + \".\" + raw body)\n * 2. X-Gandia-Timestamp within ±5 minutes (replay attack prevention)\n * 3. Parses and types the body as GandiaContext\n *\n * Usage:\n * const { ctx } = await verify(request, process.env.GANDIA_KEY_SECRET!)\n */\n\nimport { hmacVerify } from '../crypto.js'\nimport { VAIAError, type GandiaContext, type Surface } from '../types.js'\n\nconst REPLAY_WINDOW_MS = 5 * 60 * 1000 // 5 minutes\nconst PROBE_HEADER = 'x-gandia-probe'\n\n/** Raw body of the invoke call. Returned alongside ctx so you don't re-read the stream. */\nexport interface VerifyResult {\n ctx: GandiaContext\n raw: string\n}\n\n/**\n * Call at the top of your `/api/gandia/invoke` route handler.\n * Throws VAIAError if the signature is invalid or the timestamp is stale.\n */\nexport async function verify(request: Request, secret: string): Promise<VerifyResult> {\n const rawBody = await request.text()\n const headers = request.headers\n\n const sigHeader = headers.get('x-gandia-signature') ?? ''\n const tsHeader = headers.get('x-gandia-timestamp') ?? ''\n const callId = headers.get('x-gandia-call-id') ?? ''\n\n // Health probe from test-connection — no signature required\n if (headers.get(PROBE_HEADER) === '1') {\n return { ctx: buildProbeCtx(callId), raw: rawBody }\n }\n\n if (!sigHeader || !tsHeader) {\n throw new VAIAError(\n 'Faltan headers de autenticación (X-Gandia-Signature, X-Gandia-Timestamp)',\n 'MISSING_AUTH_HEADERS',\n 401,\n )\n }\n\n // Replay attack check\n const ts = parseInt(tsHeader, 10)\n if (isNaN(ts) || Math.abs(Date.now() - ts) > REPLAY_WINDOW_MS) {\n throw new VAIAError('Timestamp fuera de ventana (±5 min)', 'TIMESTAMP_OUT_OF_RANGE', 401)\n }\n\n // Strip \"sha256=\" prefix if present\n const hexSig = sigHeader.startsWith('sha256=') ? sigHeader.slice(7) : sigHeader\n\n // HMAC verification — constant-time via Web Crypto\n const signedData = `${tsHeader}.${rawBody}`\n const valid = await hmacVerify(secret, signedData, hexSig)\n if (!valid) {\n throw new VAIAError('Firma HMAC inválida', 'HMAC_INVALID', 401)\n }\n\n // Parse body\n let body: unknown\n try {\n body = JSON.parse(rawBody)\n } catch {\n throw new VAIAError('Body no es JSON válido', 'BODY_PARSE_ERROR', 400)\n }\n\n const ctx = parseContext(body, callId)\n return { ctx, raw: rawBody }\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction parseContext(body: unknown, fallbackCallId: string): GandiaContext {\n if (typeof body !== 'object' || body === null) {\n throw new VAIAError('Body inválido', 'BODY_INVALID', 400)\n }\n\n const b = body as Record<string, unknown>\n\n return {\n capability_id: str(b, 'capability_id'),\n call_id: str(b, 'call_id', fallbackCallId),\n tenant: {\n id: nestedStr(b, 'tenant', 'id'),\n name: nestedStr(b, 'tenant', 'name'),\n sector: nestedStr(b, 'tenant', 'sector'),\n },\n user: {\n id: nestedStr(b, 'user', 'id'),\n role: nestedStr(b, 'user', 'role'),\n email: nestedStrOpt(b, 'user', 'email'),\n },\n permissions: arr(b, 'permissions'),\n trigger: str(b, 'context.trigger', 'gaia_invoke') as GandiaContext['trigger'],\n surface: str(b, 'context.surface', 'data') as Surface,\n query: nestedStrOpt(b, 'context', 'query'),\n }\n}\n\nfunction buildProbeCtx(callId: string): GandiaContext {\n return {\n capability_id: '__probe__',\n call_id: callId || crypto.randomUUID(),\n tenant: { id: '__probe__', name: '__probe__', sector: '__probe__' },\n user: { id: '__probe__', role: '__probe__' },\n permissions: [],\n trigger: 'gaia_invoke',\n surface: 'data',\n }\n}\n\nfunction str(obj: Record<string, unknown>, key: string, fallback = ''): string {\n // Support dot notation: 'context.trigger'\n const parts = key.split('.')\n let cur: unknown = obj\n for (const part of parts) {\n if (typeof cur !== 'object' || cur === null) return fallback\n cur = (cur as Record<string, unknown>)[part]\n }\n return typeof cur === 'string' ? cur : fallback\n}\n\nfunction nestedStr(\n obj: Record<string, unknown>,\n parent: string,\n key: string,\n fallback = '',\n): string {\n const p = obj[parent]\n if (typeof p !== 'object' || p === null) return fallback\n const v = (p as Record<string, unknown>)[key]\n return typeof v === 'string' ? v : fallback\n}\n\nfunction nestedStrOpt(\n obj: Record<string, unknown>,\n parent: string,\n key: string,\n): string | undefined {\n const p = obj[parent]\n if (typeof p !== 'object' || p === null) return undefined\n const v = (p as Record<string, unknown>)[key]\n return typeof v === 'string' ? v : undefined\n}\n\nfunction arr(obj: Record<string, unknown>, key: string): string[] {\n const v = obj[key]\n if (!Array.isArray(v)) return []\n return v.filter((x): x is string => typeof x === 'string')\n}\n\n/** Quick check — use before calling verify() if you want to short-circuit probes. */\nexport function isProbe(request: Request): boolean {\n return request.headers.get(PROBE_HEADER) === '1'\n}\n","/**\n * gandia.jwt — JWT helpers for iframe auth bypass.\n *\n * When Gandia-7 opens a developer's app as an iframe, it appends:\n * ?gandia_token=<signed_jwt>\n *\n * The developer verifies the token, extracts the user/tenant claims,\n * and creates a session — skipping their own login page.\n *\n * Usage (server-side):\n * const claims = await gandia.jwt.verify(token, process.env.GANDIA_KEY_SECRET!)\n * // → { sub, tenant_id, email, role, permissions, exp, iat }\n *\n * Usage (VAIA-side, when generating tokens for developer iframes):\n * const token = await gandia.jwt.sign({ sub: userId, tenant_id, ... }, secret, { expiresIn: 3600 })\n */\n\nimport { jwtSign, jwtVerify } from '../jwt-utils.js'\nimport type { GandiaJWTClaims } from '../types.js'\n\nexport interface GandiaJWTSignInput {\n sub: string // user_id\n tenant_id: string\n email?: string | undefined\n role?: string | undefined\n permissions?: string[] | undefined\n}\n\nexport interface SignOpts {\n /** Seconds until expiry. Default: 3600 (1 hour). */\n expiresIn?: number | undefined\n}\n\nconst DEFAULT_EXPIRES_IN = 3600\n\n/** Signs a new Gandia iframe JWT. Typically called by Gandia-7, not by the developer. */\nexport async function sign(\n input: GandiaJWTSignInput,\n secret: string,\n opts: SignOpts = {},\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n return jwtSign(\n {\n ...input,\n permissions: input.permissions ?? [],\n iat: now,\n exp: now + (opts.expiresIn ?? DEFAULT_EXPIRES_IN),\n },\n secret,\n )\n}\n\n/** Verifies a Gandia iframe JWT and returns its claims. Throws VAIAError on failure. */\nexport async function verify(token: string, secret: string): Promise<GandiaJWTClaims> {\n return jwtVerify<GandiaJWTClaims>(token, secret)\n}\n\n/**\n * Extracts `gandia_token` from a URL and verifies it.\n * Convenience for iframe entry-point routes.\n *\n * const claims = await gandia.jwt.fromUrl(request.url, secret)\n */\nexport async function fromUrl(url: string | URL, secret: string): Promise<GandiaJWTClaims> {\n const u = typeof url === 'string' ? new URL(url) : url\n const token = u.searchParams.get('gandia_token')\n if (!token) {\n throw new Error('gandia_token no encontrado en la URL')\n }\n return verify(token, secret)\n}\n","/**\n * Minimal HS256 JWT implementation using Web Crypto.\n * No third-party dependencies.\n */\n\nimport { VAIAError } from './types.js'\n\nconst enc = new TextEncoder()\n\nfunction b64urlEncode(data: ArrayBuffer | string): string {\n const str =\n typeof data === 'string'\n ? data\n : String.fromCharCode(...new Uint8Array(data))\n return btoa(str).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\nfunction b64urlDecode(str: string): string {\n const padded = str.replace(/-/g, '+').replace(/_/g, '/')\n const pad = padded.length % 4\n return atob(pad ? padded + '='.repeat(4 - pad) : padded)\n}\n\nasync function importHMACKey(secret: string): Promise<CryptoKey> {\n return crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n )\n}\n\nconst HEADER = b64urlEncode(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))\n\n/** Creates a signed HS256 JWT. */\nexport async function jwtSign(\n payload: Record<string, unknown>,\n secret: string,\n): Promise<string> {\n const body = b64urlEncode(JSON.stringify(payload))\n const unsigned = `${HEADER}.${body}`\n const key = await importHMACKey(secret)\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(unsigned))\n return `${unsigned}.${b64urlEncode(sig)}`\n}\n\n/** Verifies an HS256 JWT and returns its payload. Throws VAIAError on failure. */\nexport async function jwtVerify<T extends object>(\n token: string,\n secret: string,\n): Promise<T> {\n const parts = token.split('.')\n if (parts.length !== 3) {\n throw new VAIAError('JWT malformado', 'JWT_MALFORMED', 401)\n }\n\n const [header, body, sig] = parts as [string, string, string]\n const unsigned = `${header}.${body}`\n\n const key = await importHMACKey(secret)\n const sigBytes = Uint8Array.from(b64urlDecode(sig), c => c.charCodeAt(0))\n const valid = await crypto.subtle.verify('HMAC', key, sigBytes, enc.encode(unsigned))\n\n if (!valid) {\n throw new VAIAError('Firma JWT inválida', 'JWT_SIGNATURE_INVALID', 401)\n }\n\n let payload: T & { exp?: number; iat?: number }\n try {\n payload = JSON.parse(b64urlDecode(body)) as T & { exp?: number; iat?: number }\n } catch {\n throw new VAIAError('JWT payload inválido', 'JWT_PAYLOAD_INVALID', 401)\n }\n\n if (typeof payload.exp === 'number' && Date.now() / 1000 > payload.exp) {\n throw new VAIAError('JWT expirado', 'JWT_EXPIRED', 401)\n }\n\n return payload as T\n}\n","/**\n * gandia.respond — typed response builders.\n *\n * Each method returns a Web API Response with the correct VAIA envelope.\n * HAIA reads `output_type` to decide how to render the result.\n *\n * For non-Response frameworks (Express, Fastify), use gandia.make.* instead.\n *\n * Usage:\n * // Returns Web API Response\n * return gandia.respond.card({ title: 'Riesgo', value: 72, unit: '%' })\n *\n * // Multi-surface: GAIA tells you which surface it wants via ctx.surface\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Riesgo', value: 72 }),\n * table: () => ({ columns: ['alumno', 'score'], rows }),\n * text: () => `El riesgo del grupo es ${risk}%`,\n * })\n */\n\nimport type {\n CardPayload,\n TablePayload,\n WidgetPayload,\n ActionPayload,\n RespondOpts,\n Surface,\n SurfaceHandlers,\n VAIAResponse,\n CardResponse,\n TableResponse,\n TextResponse,\n WidgetResponse,\n ActionResponse,\n DataResponse,\n} from '../types.js'\nimport { VAIAError } from '../types.js'\n\n// ─── JSON helpers ─────────────────────────────────────────────────────────────\n\nconst JSON_HEADERS = { 'Content-Type': 'application/json' }\n\nfunction toResponse(body: VAIAResponse | { ok: false; error: string }, status = 200): Response {\n return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS })\n}\n\n// ─── make.* — plain objects (framework-agnostic) ─────────────────────────────\n\nexport const make = {\n card(payload: CardPayload, opts: RespondOpts = {}): CardResponse {\n return { ok: true, output_type: 'card', data: payload, ...opts }\n },\n\n table(payload: TablePayload, opts: RespondOpts = {}): TableResponse {\n return { ok: true, output_type: 'table', data: payload, ...opts }\n },\n\n text(content: string, opts: RespondOpts & { markdown?: boolean } = {}): TextResponse {\n const { markdown, ...rest } = opts\n return { ok: true, output_type: 'text', text: content, markdown, ...rest }\n },\n\n widget(payload: WidgetPayload, opts: RespondOpts = {}): WidgetResponse {\n return { ok: true, output_type: 'widget', data: payload, ...opts }\n },\n\n action(payload: ActionPayload, opts: RespondOpts = {}): ActionResponse {\n return { ok: true, output_type: 'action', data: payload, ...opts }\n },\n\n data(payload: Record<string, unknown>, opts: RespondOpts = {}): DataResponse {\n return { ok: true, output_type: 'data', data: payload, ...opts }\n },\n} as const\n\n// ─── respond.* — Web API Response ────────────────────────────────────────────\n\nexport const respond = {\n /** A compact card: title, value, unit, trend, etc. */\n card(payload: CardPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.card(payload, opts))\n },\n\n /** Tabular data with columns + rows. */\n table(payload: TablePayload, opts: RespondOpts = {}): Response {\n return toResponse(make.table(payload, opts))\n },\n\n /** Plain text or markdown — shown in chat or narrative views. */\n text(content: string, opts: RespondOpts & { markdown?: boolean } = {}): Response {\n return toResponse(make.text(content, opts))\n },\n\n /** An iframe pointing to the developer's own UI. */\n widget(payload: WidgetPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.widget(payload, opts))\n },\n\n /** Trigger an action (mutation, navigation, confirm dialog). */\n action(payload: ActionPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.action(payload, opts))\n },\n\n /** Arbitrary JSON — HAIA decides how to render based on shape. */\n data(payload: Record<string, unknown>, opts: RespondOpts = {}): Response {\n return toResponse(make.data(payload, opts))\n },\n\n /** Simple 200 OK — useful for probe responses. */\n ok(opts: RespondOpts = {}): Response {\n return toResponse(make.data({ status: 'ok' }, opts))\n },\n\n /** Returns a 4xx/5xx error response. */\n error(message: string, status = 500, code?: string): Response {\n return toResponse({ ok: false, error: message, ...(code ? { code } : {}) }, status)\n },\n\n /**\n * Multi-surface responder.\n * GAIA sends `ctx.surface` telling you what to render.\n * Map each surface to its handler and this picks the right one.\n *\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Riesgo', value: 72, unit: '%' }),\n * table: () => ({ columns: [...], rows: [...] }),\n * text: () => `El riesgo es 72%`,\n * }, opts)\n */\n async surface(\n surface: Surface,\n handlers: SurfaceHandlers,\n opts: RespondOpts = {},\n ): Promise<Response> {\n const handler = handlers[surface]\n\n if (!handler) {\n // Fallback cascade: data > text > first available handler\n const fallback =\n handlers.data ?? handlers.text ?? Object.values(handlers).find(Boolean)\n if (!fallback) {\n throw new VAIAError(\n `Surface '${surface}' no soportada por esta capacidad`,\n 'SURFACE_NOT_SUPPORTED',\n 422,\n )\n }\n return respond.surface(\n handlers.data ? 'data' : handlers.text ? 'text' : (Object.keys(handlers)[0] as Surface),\n handlers,\n opts,\n )\n }\n\n switch (surface) {\n case 'card': return respond.card(await (handlers.card!)(), opts)\n case 'table': return respond.table(await (handlers.table!)(), opts)\n case 'text': return respond.text(await (handlers.text!)(), opts)\n case 'widget': return respond.widget(await (handlers.widget!)(), opts)\n case 'action': return respond.action(await (handlers.action!)(), opts)\n case 'data': return respond.data(await (handlers.data!)(), opts)\n default: return respond.data(await (handlers.data ?? handlers.text ?? (() => ({})))(), opts)\n }\n },\n} as const\n","/**\n * gandia.can / gandia.require — permission helpers.\n *\n * Usage:\n * if (!gandia.can(ctx, 'read:students')) return gandia.respond.error('Forbidden', 403)\n * gandia.require(ctx, 'write:alerts') // throws VAIAError 403 if missing\n *\n * Supports wildcard scopes:\n * 'read:*' — matches all read permissions\n * 'read:students' — exact match\n */\n\nimport { VAIAError, type GandiaContext } from '../types.js'\n\nfunction matches(permission: string, granted: string[]): boolean {\n if (granted.includes(permission)) return true\n // wildcard: 'read:*' grants 'read:students'\n const [action] = permission.split(':')\n return granted.includes(`${action}:*`)\n}\n\n/** Returns true if the context has the given permission. */\nexport function can(ctx: Pick<GandiaContext, 'permissions'>, permission: string): boolean {\n return matches(permission, ctx.permissions)\n}\n\n/** Returns true if the context has ALL listed permissions. */\nexport function canAll(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): boolean {\n return permissions.every(p => matches(p, ctx.permissions))\n}\n\n/** Returns true if the context has ANY of the listed permissions. */\nexport function canAny(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): boolean {\n return permissions.some(p => matches(p, ctx.permissions))\n}\n\n/** Throws VAIAError 403 if the context does NOT have the given permission. */\nexport function require(ctx: Pick<GandiaContext, 'permissions'>, permission: string): void {\n if (!matches(permission, ctx.permissions)) {\n throw new VAIAError(\n `Permiso requerido: ${permission}`,\n 'PERMISSION_DENIED',\n 403,\n )\n }\n}\n\n/** Throws VAIAError 403 if the context does NOT have ALL listed permissions. */\nexport function requireAll(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): void {\n const missing = permissions.filter(p => !matches(p, ctx.permissions))\n if (missing.length > 0) {\n throw new VAIAError(\n `Permisos requeridos: ${missing.join(', ')}`,\n 'PERMISSION_DENIED',\n 403,\n )\n }\n}\n","/**\n * handeia — integration namespace for Handeia (personal platform).\n *\n * Quick start:\n * import { handeia } from '@vaia/sdk'\n *\n * export async function POST(req: Request) {\n * try {\n * const { ctx } = await handeia.verify(req, process.env.HANDEIA_KEY_SECRET!)\n * const profile = await myDb.getProfile(ctx.user.id)\n * return handeia.respond.surface(ctx.surface, {\n * card: () => ({ title: profile.name, subtitle: profile.role }),\n * text: () => `Hola ${profile.name}`,\n * })\n * } catch (err) {\n * if (err instanceof VAIAError) return handeia.respond.error(err.message, err.status)\n * throw err\n * }\n * }\n */\n\nexport { verify, isProbe, type HandeiaVerifyResult } from './verify.js'\nexport * as jwt from './jwt.js'\n\n// handeia shares the same respond/make API as gandia\nexport { respond, make } from '../gandia/respond.js'\n\n// Permission helpers (work the same — ctx.permissions is always a string[])\nexport { can, canAll, canAny, require, requireAll } from '../gandia/permissions.js'\n","/**\n * handeia.verify — verifies an incoming invoke call from Handeia.\n * Same HMAC protocol as gandia.verify but with Handeia-specific headers\n * and a HandeiaContext (user personal, no tenant).\n */\n\nimport { hmacVerify } from '../crypto.js'\nimport { VAIAError, type HandeiaContext, type Surface } from '../types.js'\n\nconst REPLAY_WINDOW_MS = 5 * 60 * 1000\nconst PROBE_HEADER = 'x-handeia-probe'\n\nexport interface HandeiaVerifyResult {\n ctx: HandeiaContext\n raw: string\n}\n\n/**\n * Call at the top of your `/api/handeia/invoke` route handler.\n * Throws VAIAError if the signature is invalid or the timestamp is stale.\n */\nexport async function verify(request: Request, secret: string): Promise<HandeiaVerifyResult> {\n const rawBody = await request.text()\n const headers = request.headers\n\n const sigHeader = headers.get('x-handeia-signature') ?? ''\n const tsHeader = headers.get('x-handeia-timestamp') ?? ''\n const callId = headers.get('x-handeia-call-id') ?? ''\n\n if (headers.get(PROBE_HEADER) === '1') {\n return { ctx: buildProbeCtx(callId), raw: rawBody }\n }\n\n if (!sigHeader || !tsHeader) {\n throw new VAIAError(\n 'Faltan headers de autenticación (X-Handeia-Signature, X-Handeia-Timestamp)',\n 'MISSING_AUTH_HEADERS',\n 401,\n )\n }\n\n const ts = parseInt(tsHeader, 10)\n if (isNaN(ts) || Math.abs(Date.now() - ts) > REPLAY_WINDOW_MS) {\n throw new VAIAError('Timestamp fuera de ventana (±5 min)', 'TIMESTAMP_OUT_OF_RANGE', 401)\n }\n\n const hexSig = sigHeader.startsWith('sha256=') ? sigHeader.slice(7) : sigHeader\n const signedData = `${tsHeader}.${rawBody}`\n const valid = await hmacVerify(secret, signedData, hexSig)\n\n if (!valid) {\n throw new VAIAError('Firma HMAC inválida', 'HMAC_INVALID', 401)\n }\n\n let body: unknown\n try {\n body = JSON.parse(rawBody)\n } catch {\n throw new VAIAError('Body no es JSON válido', 'BODY_PARSE_ERROR', 400)\n }\n\n const ctx = parseContext(body, callId)\n return { ctx, raw: rawBody }\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction parseContext(body: unknown, fallbackCallId: string): HandeiaContext {\n if (typeof body !== 'object' || body === null) {\n throw new VAIAError('Body inválido', 'BODY_INVALID', 400)\n }\n\n const b = body as Record<string, unknown>\n const user = (b['user'] ?? {}) as Record<string, unknown>\n const ctx = (b['context'] ?? {}) as Record<string, unknown>\n\n return {\n capability_id: s(b['capability_id']),\n call_id: s(b['call_id'], fallbackCallId),\n user: {\n id: s(user['id']),\n email: sOpt(user['email']),\n name: sOpt(user['name']),\n },\n permissions: arr(b['permissions']),\n trigger: s(ctx['trigger'], 'haia_invoke') as HandeiaContext['trigger'],\n surface: s(ctx['surface'], 'data') as Surface,\n query: sOpt(ctx['query']),\n }\n}\n\nfunction buildProbeCtx(callId: string): HandeiaContext {\n return {\n capability_id: '__probe__',\n call_id: callId || crypto.randomUUID(),\n user: { id: '__probe__' },\n permissions: [],\n trigger: 'haia_invoke',\n surface: 'data',\n }\n}\n\nfunction s(v: unknown, fallback = ''): string {\n return typeof v === 'string' ? v : fallback\n}\nfunction sOpt(v: unknown): string | undefined {\n return typeof v === 'string' ? v : undefined\n}\nfunction arr(v: unknown): string[] {\n return Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string') : []\n}\n\nexport function isProbe(request: Request): boolean {\n return request.headers.get(PROBE_HEADER) === '1'\n}\n","/**\n * handeia.jwt — JWT helpers for Handeia iframe auth bypass.\n * Same pattern as gandia.jwt but for personal context (no tenant).\n */\n\nimport { jwtSign, jwtVerify } from '../jwt-utils.js'\nimport type { HandeiaJWTClaims } from '../types.js'\n\nexport interface HandeiaJWTSignInput {\n sub: string // user_id\n email?: string | undefined\n name?: string | undefined\n permissions?: string[] | undefined\n}\n\nexport interface SignOpts {\n expiresIn?: number | undefined\n}\n\nconst DEFAULT_EXPIRES_IN = 3600\n\nexport async function sign(\n input: HandeiaJWTSignInput,\n secret: string,\n opts: SignOpts = {},\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n return jwtSign(\n {\n ...input,\n permissions: input.permissions ?? [],\n iat: now,\n exp: now + (opts.expiresIn ?? DEFAULT_EXPIRES_IN),\n },\n secret,\n )\n}\n\nexport async function verify(token: string, secret: string): Promise<HandeiaJWTClaims> {\n return jwtVerify<HandeiaJWTClaims>(token, secret)\n}\n\n/** Extracts and verifies `handeia_token` from a URL. */\nexport async function fromUrl(url: string | URL, secret: string): Promise<HandeiaJWTClaims> {\n const u = typeof url === 'string' ? new URL(url) : url\n const token = u.searchParams.get('handeia_token')\n if (!token) throw new Error('handeia_token no encontrado en la URL')\n return verify(token, secret)\n}\n","/**\n * defineCapability — declares a VAIA capability in code.\n *\n * This is both a type-safety layer (catches config errors at compile time)\n * and the source of truth for `npx vaia manifest` (generates gandia.manifest.json).\n *\n * The Shazam engine detects `defineCapability` in your code and reads the\n * config with 100% confidence — no manual confirmation needed in the portal.\n *\n * Usage (vaia.config.ts in project root):\n * import { defineCapability } from '@vaia/sdk'\n *\n * export default defineCapability({\n * id: 'mx.monitor-riesgo-academico',\n * name: 'Monitor de Riesgo Académico',\n * version: '1.0.0',\n * target: 'gandia',\n * type: 'app',\n * level: 'artefacto',\n * sector: 'educacion',\n * surfaces: {\n * card: { endpoint: '/api/gandia/invoke' },\n * table: { endpoint: '/api/gandia/invoke' },\n * text: { endpoint: '/api/gandia/invoke' },\n * },\n * permissions: ['read:students', 'read:grades', 'write:alerts'],\n * risk: 'medium',\n * })\n */\n\nimport type { CapabilityConfig, EcoTarget, Risk, Surface } from './types.js'\n\nexport type { CapabilityConfig }\n\nexport interface VAIAManifest {\n schema: '1.0'\n capability_id: string\n name: string\n version: string\n target: EcoTarget | EcoTarget[]\n type: string\n level?: string | undefined\n sector: string\n surfaces: string[]\n permissions: string[]\n risk: Risk\n has_own_auth: boolean\n stores_data: boolean\n trains_models: boolean\n requires_consent: boolean\n description?: string | undefined\n tags?: string[] | undefined\n linked: boolean\n generated_by: '@vaia/sdk'\n generated_at: string\n}\n\n/** Validates and returns the capability config. Throws if required fields are missing. */\nexport function defineCapability(config: CapabilityConfig): CapabilityConfig {\n const required: Array<keyof CapabilityConfig> = ['id', 'name', 'version', 'target', 'type', 'sector', 'permissions', 'risk']\n for (const key of required) {\n if (config[key] === undefined || config[key] === '') {\n throw new Error(`[@vaia/sdk] defineCapability: campo requerido faltante: '${key}'`)\n }\n }\n\n if (!config.id.includes('.')) {\n throw new Error(\n `[@vaia/sdk] defineCapability: 'id' debe usar formato reverse-domain (ej. 'mx.mi-capacidad'). Recibido: '${config.id}'`,\n )\n }\n\n if (Object.keys(config.surfaces).length === 0) {\n throw new Error(`[@vaia/sdk] defineCapability: 'surfaces' no puede estar vacío. Define al menos un surface con su endpoint.`)\n }\n\n return config\n}\n\n/** Converts a CapabilityConfig to a gandia.manifest.json object. */\nexport function toManifest(config: CapabilityConfig): VAIAManifest {\n const surfaces = Object.keys(config.surfaces) as Surface[]\n\n return {\n schema: '1.0',\n capability_id: config.id,\n name: config.name,\n version: config.version,\n target: config.target === 'both' ? ['gandia', 'handeia'] : config.target,\n type: config.type,\n level: config.level,\n sector: config.sector,\n surfaces,\n permissions: config.permissions,\n risk: config.risk,\n has_own_auth: config.has_own_auth ?? false,\n stores_data: config.stores_data ?? false,\n trains_models: config.trains_models ?? false,\n requires_consent: config.requires_consent ?? false,\n description: config.description,\n tags: config.tags,\n linked: config.target === 'both',\n generated_by: '@vaia/sdk',\n generated_at: new Date().toISOString(),\n }\n}\n"],"mappings":"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","names":["require","verify","enc","str","importHMACKey","verify","require","isProbe","jwt_exports","require","verify","REPLAY_WINDOW_MS","PROBE_HEADER","verify","buildProbeCtx","parseContext","arr","isProbe","jwt_exports","fromUrl","sign","verify","DEFAULT_EXPIRES_IN","sign","verify","fromUrl"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/gandia/index.ts","../src/crypto.ts","../src/types.ts","../src/gandia/verify.ts","../src/gandia/jwt.ts","../src/jwt-utils.ts","../src/gandia/respond.ts","../src/gandia/permissions.ts","../src/handeia/index.ts","../src/handeia/verify.ts","../src/handeia/jwt.ts","../src/define.ts"],"sourcesContent":["/**\n * @vaia/sdk — VAIA Platform Integration SDK\n *\n * Provides two namespaces:\n * gandia → Gandia-7 (institutional platform)\n * handeia → Handeia (personal platform)\n *\n * Quick start:\n * import { gandia, handeia, defineCapability, VAIAError } from '@vaia/sdk'\n */\n\n// ─── Platform namespaces ──────────────────────────────────────────────────────\n\nimport * as _gandia from './gandia/index.js'\nimport * as _handeia from './handeia/index.js'\n\nexport const gandia = _gandia\nexport const handeia = _handeia\n\n// ─── defineCapability + manifest ─────────────────────────────────────────────\n\nexport { defineCapability, toManifest } from './define.js'\nexport type { CapabilityConfig, VAIAManifest } from './define.js'\n\n// ─── Shared error class ───────────────────────────────────────────────────────\n\nexport { VAIAError } from './types.js'\n\n// ─── All types (re-exported for consumer convenience) ─────────────────────────\n\nexport type {\n // Core enums\n PublishType,\n EcoTarget,\n NodeType,\n Risk,\n Surface,\n OutputType,\n\n // Contexts\n GandiaContext,\n GandiaTenant,\n GandiaUser,\n HandeiaContext,\n HandeiaUser,\n\n // JWT claims\n GandiaJWTClaims,\n HandeiaJWTClaims,\n\n // Response payloads\n CardPayload,\n TablePayload,\n WidgetPayload,\n ActionPayload,\n AuditRecord,\n RespondOpts,\n SurfaceHandlers,\n\n // Response types\n VAIAResponse,\n CardResponse,\n TableResponse,\n TextResponse,\n WidgetResponse,\n ActionResponse,\n DataResponse,\n ErrorResponse,\n} from './types.js'\n","/**\n * gandia — integration namespace for Gandia-7 (institutional platform).\n *\n * Quick start:\n * import { gandia } from '@vaia/sdk'\n *\n * export async function POST(req: Request) {\n * try {\n * const { ctx } = await gandia.verify(req, process.env.GANDIA_KEY_SECRET!)\n * gandia.require(ctx, 'read:students')\n * const data = await myDb.getStudents(ctx.tenant.id)\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Total alumnos', value: data.length }),\n * table: () => ({ columns: ['nombre', 'riesgo'], rows: data }),\n * text: () => `${data.length} alumnos en ${ctx.tenant.name}`,\n * })\n * } catch (err) {\n * if (err instanceof VAIAError) return gandia.respond.error(err.message, err.status)\n * throw err\n * }\n * }\n */\n\nexport { verify, isProbe, type VerifyResult } from './verify.js'\nexport * as jwt from './jwt.js'\nexport { respond, make } from './respond.js'\nexport { can, canAll, canAny, require, requireAll } from './permissions.js'\n","/**\n * HMAC-SHA256 utilities using the Web Crypto API.\n * Zero dependencies — works in Node 18+, Edge, Bun, Deno, browsers.\n */\n\nconst enc = new TextEncoder()\n\nfunction hexToBytes(hex: string): Uint8Array {\n if (hex.length % 2 !== 0) throw new Error('Invalid hex string')\n const bytes = new Uint8Array(hex.length / 2)\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16)\n }\n return bytes\n}\n\nasync function importHMACKey(secret: string): Promise<CryptoKey> {\n return crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n )\n}\n\n/** Signs `data` with HMAC-SHA256, returns lowercase hex. */\nexport async function hmacSign(secret: string, data: string): Promise<string> {\n const key = await importHMACKey(secret)\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(data))\n return Array.from(new Uint8Array(sig))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Constant-time HMAC-SHA256 verification.\n * Uses Web Crypto `verify` to avoid timing attacks.\n */\nexport async function hmacVerify(secret: string, data: string, hexSignature: string): Promise<boolean> {\n try {\n const key = await importHMACKey(secret)\n const sigBytes = hexToBytes(hexSignature)\n return await crypto.subtle.verify('HMAC', key, sigBytes, enc.encode(data))\n } catch {\n return false\n }\n}\n","// ─── Core enums ───────────────────────────────────────────────────────────────\n\nexport type PublishType = 'app' | 'ia' | 'skill' | 'eco'\nexport type EcoTarget = 'gandia' | 'handeia' | 'both'\nexport type NodeType = 'widget' | 'artefacto' | 'espacio' | 'skill' | 'agente'\nexport type Risk = 'low' | 'medium' | 'high'\nexport type Surface = 'card' | 'table' | 'text' | 'widget' | 'action' | 'data'\nexport type OutputType = Surface\n\n// ─── Gandia context ───────────────────────────────────────────────────────────\n\nexport interface GandiaTenant {\n id: string\n name: string\n sector: string\n}\n\nexport interface GandiaUser {\n id: string\n role: string\n email?: string | undefined\n}\n\n/** Context injected by GAIA on every invoke call to the developer's server. */\nexport interface GandiaContext {\n capability_id: string\n call_id: string\n tenant: GandiaTenant\n user: GandiaUser\n permissions: string[]\n trigger: 'user_query' | 'gaia_invoke' | 'event'\n /** Surface HAIA wants to render — determines which respond.* to use. */\n surface: Surface\n query?: string | undefined\n}\n\n// ─── Handeia context ──────────────────────────────────────────────────────────\n\nexport interface HandeiaUser {\n id: string\n email?: string | undefined\n name?: string | undefined\n}\n\n/** Context injected by HAIA on every invoke call to the developer's server. */\nexport interface HandeiaContext {\n capability_id: string\n call_id: string\n user: HandeiaUser\n permissions: string[]\n trigger: 'user_action' | 'haia_invoke' | 'schedule'\n /** Surface HAIA wants to render. */\n surface: Surface\n query?: string | undefined\n}\n\n// ─── JWT claims ───────────────────────────────────────────────────────────────\n\nexport interface GandiaJWTClaims {\n sub: string // user_id\n tenant_id: string\n email?: string | undefined\n role?: string | undefined\n permissions: string[]\n iat: number\n exp: number\n}\n\nexport interface HandeiaJWTClaims {\n sub: string // user_id\n email?: string | undefined\n name?: string | undefined\n permissions: string[]\n iat: number\n exp: number\n}\n\n// ─── Response payloads ────────────────────────────────────────────────────────\n\nexport interface AuditRecord {\n data_sources?: string[] | undefined\n records_accessed?: number | undefined\n [key: string]: unknown\n}\n\nexport interface RespondOpts {\n call_id?: string | undefined\n audit?: AuditRecord | undefined\n}\n\nexport interface CardPayload {\n title: string\n value?: string | number | undefined\n unit?: string | undefined\n trend?: 'up' | 'down' | 'neutral' | undefined\n icon?: string | undefined\n subtitle?: string | undefined\n color?: string | undefined\n [key: string]: unknown\n}\n\nexport interface TablePayload {\n columns: string[] | Array<{ key: string; label: string; type?: string | undefined }>\n rows: Array<Record<string, unknown>>\n total?: number | undefined\n page?: number | undefined\n per_page?: number | undefined\n}\n\nexport interface WidgetPayload {\n url: string\n height?: number | string | undefined\n width?: number | string | undefined\n meta?: Record<string, unknown> | undefined\n}\n\nexport interface ActionPayload {\n type: string\n label?: string | undefined\n params?: Record<string, unknown> | undefined\n confirm?: boolean | undefined\n destructive?: boolean | undefined\n}\n\n// ─── Typed VAIA response objects (returned by make.*) ────────────────────────\n\ninterface BaseVAIAResponse {\n ok: true\n call_id?: string | undefined\n audit?: AuditRecord | undefined\n}\n\nexport type CardResponse = BaseVAIAResponse & { output_type: 'card'; data: CardPayload }\nexport type TableResponse = BaseVAIAResponse & { output_type: 'table'; data: TablePayload }\nexport type TextResponse = BaseVAIAResponse & { output_type: 'text'; text: string; markdown?: boolean | undefined }\nexport type WidgetResponse = BaseVAIAResponse & { output_type: 'widget'; data: WidgetPayload }\nexport type ActionResponse = BaseVAIAResponse & { output_type: 'action'; data: ActionPayload }\nexport type DataResponse = BaseVAIAResponse & { output_type: 'data'; data: Record<string, unknown> }\nexport type ErrorResponse = { ok: false; error: string; code?: string | undefined }\n\nexport type VAIAResponse =\n | CardResponse\n | TableResponse\n | TextResponse\n | WidgetResponse\n | ActionResponse\n | DataResponse\n\n// ─── Surface handler map ──────────────────────────────────────────────────────\n\nexport type SurfaceHandlers = Partial<{\n card: () => CardPayload | Promise<CardPayload>\n table: () => TablePayload | Promise<TablePayload>\n text: () => string | Promise<string>\n widget: () => WidgetPayload | Promise<WidgetPayload>\n action: () => ActionPayload | Promise<ActionPayload>\n data: () => Record<string, unknown> | Promise<Record<string, unknown>>\n}>\n\n// ─── Capability definition ────────────────────────────────────────────────────\n\nexport interface SurfaceConfig {\n endpoint: string\n description?: string | undefined\n}\n\nexport interface CapabilityConfig {\n /** Unique capability ID — reverse domain: 'mx.mi-capacidad' */\n id: string\n name: string\n version: string\n /** Which VAIA platform(s) this capability targets. */\n target: EcoTarget\n type: PublishType\n level?: 'widget' | 'artefacto' | 'espacio' | undefined\n sector: string\n /** Which surfaces the capability can respond to, and their invoke endpoint. */\n surfaces: Partial<Record<Surface, SurfaceConfig>>\n permissions: string[]\n risk: Risk\n description?: string | undefined\n tags?: string[] | undefined\n /** Set to true if your app has its own login (triggers JWT bypass flow). */\n has_own_auth?: boolean | undefined\n stores_data?: boolean | undefined\n trains_models?: boolean | undefined\n requires_consent?: boolean | undefined\n}\n\n// ─── Errors ───────────────────────────────────────────────────────────────────\n\nexport class VAIAError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly status: number = 500,\n ) {\n super(message)\n this.name = 'VAIAError'\n }\n}\n","/**\n * gandia.verify — verifies an incoming invoke call from Gandia-7.\n *\n * Checks:\n * 1. X-Gandia-Signature (HMAC-SHA256 over timestamp + \".\" + raw body)\n * 2. X-Gandia-Timestamp within ±5 minutes (replay attack prevention)\n * 3. Parses and types the body as GandiaContext\n *\n * Usage:\n * const { ctx } = await verify(request, process.env.GANDIA_KEY_SECRET!)\n */\n\nimport { hmacVerify } from '../crypto.js'\nimport { VAIAError, type GandiaContext, type Surface } from '../types.js'\n\nconst REPLAY_WINDOW_MS = 5 * 60 * 1000 // 5 minutes\nconst PROBE_HEADER = 'x-gandia-probe'\n\n/** Raw body of the invoke call. Returned alongside ctx so you don't re-read the stream. */\nexport interface VerifyResult {\n ctx: GandiaContext\n raw: string\n}\n\n/**\n * Call at the top of your `/api/gandia/invoke` route handler.\n * Throws VAIAError if the signature is invalid or the timestamp is stale.\n */\nexport async function verify(request: Request, secret: string): Promise<VerifyResult> {\n const rawBody = await request.text()\n const headers = request.headers\n\n const sigHeader = headers.get('x-gandia-signature') ?? ''\n const tsHeader = headers.get('x-gandia-timestamp') ?? ''\n const callId = headers.get('x-gandia-call-id') ?? ''\n\n // Health probe from test-connection — no signature required\n if (headers.get(PROBE_HEADER) === '1') {\n return { ctx: buildProbeCtx(callId), raw: rawBody }\n }\n\n if (!sigHeader || !tsHeader) {\n throw new VAIAError(\n 'Faltan headers de autenticación (X-Gandia-Signature, X-Gandia-Timestamp)',\n 'MISSING_AUTH_HEADERS',\n 401,\n )\n }\n\n // Replay attack check\n const ts = parseInt(tsHeader, 10)\n if (isNaN(ts) || Math.abs(Date.now() - ts) > REPLAY_WINDOW_MS) {\n throw new VAIAError('Timestamp fuera de ventana (±5 min)', 'TIMESTAMP_OUT_OF_RANGE', 401)\n }\n\n // Strip \"sha256=\" prefix if present\n const hexSig = sigHeader.startsWith('sha256=') ? sigHeader.slice(7) : sigHeader\n\n // HMAC verification — constant-time via Web Crypto\n const signedData = `${tsHeader}.${rawBody}`\n const valid = await hmacVerify(secret, signedData, hexSig)\n if (!valid) {\n throw new VAIAError('Firma HMAC inválida', 'HMAC_INVALID', 401)\n }\n\n // Parse body\n let body: unknown\n try {\n body = JSON.parse(rawBody)\n } catch {\n throw new VAIAError('Body no es JSON válido', 'BODY_PARSE_ERROR', 400)\n }\n\n const ctx = parseContext(body, callId)\n return { ctx, raw: rawBody }\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction parseContext(body: unknown, fallbackCallId: string): GandiaContext {\n if (typeof body !== 'object' || body === null) {\n throw new VAIAError('Body inválido', 'BODY_INVALID', 400)\n }\n\n const b = body as Record<string, unknown>\n\n return {\n capability_id: str(b, 'capability_id'),\n call_id: str(b, 'call_id', fallbackCallId),\n tenant: {\n id: nestedStr(b, 'tenant', 'id'),\n name: nestedStr(b, 'tenant', 'name'),\n sector: nestedStr(b, 'tenant', 'sector'),\n },\n user: {\n id: nestedStr(b, 'user', 'id'),\n role: nestedStr(b, 'user', 'role'),\n email: nestedStrOpt(b, 'user', 'email'),\n },\n permissions: arr(b, 'permissions'),\n trigger: str(b, 'context.trigger', 'gaia_invoke') as GandiaContext['trigger'],\n surface: str(b, 'context.surface', 'data') as Surface,\n query: nestedStrOpt(b, 'context', 'query'),\n }\n}\n\nfunction buildProbeCtx(callId: string): GandiaContext {\n return {\n capability_id: '__probe__',\n call_id: callId || crypto.randomUUID(),\n tenant: { id: '__probe__', name: '__probe__', sector: '__probe__' },\n user: { id: '__probe__', role: '__probe__' },\n permissions: [],\n trigger: 'gaia_invoke',\n surface: 'data',\n }\n}\n\nfunction str(obj: Record<string, unknown>, key: string, fallback = ''): string {\n // Support dot notation: 'context.trigger'\n const parts = key.split('.')\n let cur: unknown = obj\n for (const part of parts) {\n if (typeof cur !== 'object' || cur === null) return fallback\n cur = (cur as Record<string, unknown>)[part]\n }\n return typeof cur === 'string' ? cur : fallback\n}\n\nfunction nestedStr(\n obj: Record<string, unknown>,\n parent: string,\n key: string,\n fallback = '',\n): string {\n const p = obj[parent]\n if (typeof p !== 'object' || p === null) return fallback\n const v = (p as Record<string, unknown>)[key]\n return typeof v === 'string' ? v : fallback\n}\n\nfunction nestedStrOpt(\n obj: Record<string, unknown>,\n parent: string,\n key: string,\n): string | undefined {\n const p = obj[parent]\n if (typeof p !== 'object' || p === null) return undefined\n const v = (p as Record<string, unknown>)[key]\n return typeof v === 'string' ? v : undefined\n}\n\nfunction arr(obj: Record<string, unknown>, key: string): string[] {\n const v = obj[key]\n if (!Array.isArray(v)) return []\n return v.filter((x): x is string => typeof x === 'string')\n}\n\n/** Quick check — use before calling verify() if you want to short-circuit probes. */\nexport function isProbe(request: Request): boolean {\n return request.headers.get(PROBE_HEADER) === '1'\n}\n","/**\n * gandia.jwt — JWT helpers for iframe auth bypass.\n *\n * When Gandia-7 opens a developer's app as an iframe, it appends:\n * ?gandia_token=<signed_jwt>\n *\n * The developer verifies the token, extracts the user/tenant claims,\n * and creates a session — skipping their own login page.\n *\n * Usage (server-side):\n * const claims = await gandia.jwt.verify(token, process.env.GANDIA_KEY_SECRET!)\n * // → { sub, tenant_id, email, role, permissions, exp, iat }\n *\n * Usage (VAIA-side, when generating tokens for developer iframes):\n * const token = await gandia.jwt.sign({ sub: userId, tenant_id, ... }, secret, { expiresIn: 3600 })\n */\n\nimport { jwtSign, jwtVerify } from '../jwt-utils.js'\nimport type { GandiaJWTClaims } from '../types.js'\n\nexport interface GandiaJWTSignInput {\n sub: string // user_id\n tenant_id: string\n email?: string | undefined\n role?: string | undefined\n permissions?: string[] | undefined\n}\n\nexport interface SignOpts {\n /** Seconds until expiry. Default: 3600 (1 hour). */\n expiresIn?: number | undefined\n}\n\nconst DEFAULT_EXPIRES_IN = 3600\n\n/** Signs a new Gandia iframe JWT. Typically called by Gandia-7, not by the developer. */\nexport async function sign(\n input: GandiaJWTSignInput,\n secret: string,\n opts: SignOpts = {},\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n return jwtSign(\n {\n ...input,\n permissions: input.permissions ?? [],\n iat: now,\n exp: now + (opts.expiresIn ?? DEFAULT_EXPIRES_IN),\n },\n secret,\n )\n}\n\n/** Verifies a Gandia iframe JWT and returns its claims. Throws VAIAError on failure. */\nexport async function verify(token: string, secret: string): Promise<GandiaJWTClaims> {\n return jwtVerify<GandiaJWTClaims>(token, secret)\n}\n\n/**\n * Extracts `gandia_token` from a URL and verifies it.\n * Convenience for iframe entry-point routes.\n *\n * const claims = await gandia.jwt.fromUrl(request.url, secret)\n */\nexport async function fromUrl(url: string | URL, secret: string): Promise<GandiaJWTClaims> {\n const u = typeof url === 'string' ? new URL(url) : url\n const token = u.searchParams.get('gandia_token')\n if (!token) {\n throw new Error('gandia_token no encontrado en la URL')\n }\n return verify(token, secret)\n}\n","/**\n * Minimal HS256 JWT implementation using Web Crypto.\n * No third-party dependencies.\n *\n * CONTRATO DE CODIFICACIÓN (v2)\n * -----------------------------\n * El payload se serializa en UTF-8, como exige RFC 7519 §3. Esto importa\n * porque el token cruza fronteras de lenguaje: lo firma Gandia (TS), lo\n * verifica Nexus (TS) y lo reenvía a ACIPE (Python) — cualquier consumidor\n * que use una librería JWT estándar debe poder leerlo.\n *\n * Antes de v2 se usaba btoa()/atob(), que tratan cada carácter como UN byte\n * (latin1). Dos consecuencias:\n * - Caracteres 128..255 (é, Ñ) salían mal para cualquier lector estándar.\n * Entre piezas del propio SDK no se notaba, porque el error era simétrico.\n * - Caracteres >255 (CJK, emoji, U+FFFD) hacían LANZAR a btoa(), tumbando\n * la firma. Un estudiante con la Ñ corrupta en el nombre no pudo entrar a\n * su Espacio por esto, y el error salió reportado como \"servicio caído\".\n *\n * MIGRACIÓN: jwtVerify lee ambos formatos. Los tokens nuevos llevan el claim\n * `v: 2`; su ausencia significa v1 (latin1) y se decodifica como tal. Así la\n * transición no invalida ningún token en vuelo — ver CHANGELOG.\n */\n\nimport { VAIAError } from './types.js'\n\nconst enc = new TextEncoder()\n/** fatal:true = si los bytes no son UTF-8 válido, lanza en vez de meter U+FFFD\n * en silencio. Es justo ese \"en silencio\" el que escondió el bug original. */\nconst utf8Strict = new TextDecoder('utf-8', { fatal: true })\nconst utf8Loose = new TextDecoder('utf-8')\nconst latin1 = new TextDecoder('latin1')\n\n/** Versión del formato de payload. Los tokens la llevan como claim `v`. */\nexport const JWT_PAYLOAD_VERSION = 2\n\n// ── base64url ───────────────────────────────────────────────────────────────\n// Se separan bytes y texto a propósito. Tener UNA función para ambos fue la\n// causa de raíz: la firma (bytes crudos) y el payload (texto) necesitan\n// tratamientos distintos, y compartirlos forzó latin1 sobre el texto.\n\nfunction bytesToB64url(bytes: Uint8Array): string {\n // Se arma por trozos en vez de String.fromCharCode(...bytes): el spread de\n // un arreglo grande revienta la pila de llamadas.\n let bin = ''\n const CHUNK = 0x8000\n for (let i = 0; i < bytes.length; i += CHUNK) {\n bin += String.fromCharCode(...bytes.subarray(i, i + CHUNK))\n }\n return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\n// El ArrayBuffer se crea explícito para que el tipo sea Uint8Array<ArrayBuffer>\n// y no Uint8Array<ArrayBufferLike>: Web Crypto no acepta buffers compartidos.\nfunction b64urlToBytes(str: string): Uint8Array<ArrayBuffer> {\n const padded = str.replace(/-/g, '+').replace(/_/g, '/')\n const pad = padded.length % 4\n const bin = atob(pad ? padded + '='.repeat(4 - pad) : padded)\n const out = new Uint8Array(new ArrayBuffer(bin.length))\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\n/** Texto → base64url en UTF-8. Nunca lanza, sea cual sea el carácter. */\nfunction textToB64url(text: string): string {\n return bytesToB64url(enc.encode(text))\n}\n\nasync function importHMACKey(secret: string): Promise<CryptoKey> {\n return crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n )\n}\n\nconst HEADER = textToB64url(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))\n\n/** Creates a signed HS256 JWT. */\nexport async function jwtSign(\n payload: Record<string, unknown>,\n secret: string,\n): Promise<string> {\n const body = textToB64url(JSON.stringify({ ...payload, v: JWT_PAYLOAD_VERSION }))\n const unsigned = `${HEADER}.${body}`\n const key = await importHMACKey(secret)\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(unsigned))\n return `${unsigned}.${bytesToB64url(new Uint8Array(sig))}`\n}\n\n/**\n * Decodifica el payload aceptando ambos formatos (lector tolerante).\n *\n * Se lee primero en latin1 —que nunca lanza— solo para poder mirar el claim\n * `v` y decidir. Las llaves y la estructura del JSON son ASCII, así que\n * sobreviven a cualquiera de las dos lecturas; lo único que puede verse mal\n * en ese primer paso son los valores, y ese texto se descarta si resulta v2.\n */\nfunction decodePayload(body: string): Record<string, unknown> {\n const bytes = b64urlToBytes(body)\n\n let sonda: Record<string, unknown>\n try {\n sonda = JSON.parse(latin1.decode(bytes)) as Record<string, unknown>\n } catch {\n throw new VAIAError('JWT payload inválido', 'JWT_PAYLOAD_INVALID', 401)\n }\n\n const version = typeof sonda['v'] === 'number' ? (sonda['v'] as number) : 1\n if (version < 2) return sonda // v1: latin1 era el formato correcto entonces\n\n try {\n return JSON.parse(utf8Strict.decode(bytes)) as Record<string, unknown>\n } catch {\n // Marcado como v2 pero los bytes no son UTF-8 válido: se degrada a una\n // lectura permisiva antes que rechazarle el acceso a un usuario real.\n try {\n return JSON.parse(utf8Loose.decode(bytes)) as Record<string, unknown>\n } catch {\n throw new VAIAError('JWT payload inválido', 'JWT_PAYLOAD_INVALID', 401)\n }\n }\n}\n\n/** Verifies an HS256 JWT and returns its payload. Throws VAIAError on failure. */\nexport async function jwtVerify<T extends object>(\n token: string,\n secret: string,\n): Promise<T> {\n const parts = token.split('.')\n if (parts.length !== 3) {\n throw new VAIAError('JWT malformado', 'JWT_MALFORMED', 401)\n }\n\n const [header, body, sig] = parts as [string, string, string]\n const unsigned = `${header}.${body}`\n\n // La firma se valida SIEMPRE antes de tocar el payload: nada de lo que venga\n // dentro debe influir en cómo se decide verificarlo.\n const key = await importHMACKey(secret)\n let valid: boolean\n try {\n valid = await crypto.subtle.verify('HMAC', key, b64urlToBytes(sig), enc.encode(unsigned))\n } catch {\n throw new VAIAError('JWT malformado', 'JWT_MALFORMED', 401)\n }\n\n if (!valid) {\n throw new VAIAError('Firma JWT inválida', 'JWT_SIGNATURE_INVALID', 401)\n }\n\n const payload = decodePayload(body) as T & { exp?: number; iat?: number }\n\n if (typeof payload.exp === 'number' && Date.now() / 1000 > payload.exp) {\n throw new VAIAError('JWT expirado', 'JWT_EXPIRED', 401)\n }\n\n return payload as T\n}\n","/**\n * gandia.respond — typed response builders.\n *\n * Each method returns a Web API Response with the correct VAIA envelope.\n * HAIA reads `output_type` to decide how to render the result.\n *\n * For non-Response frameworks (Express, Fastify), use gandia.make.* instead.\n *\n * Usage:\n * // Returns Web API Response\n * return gandia.respond.card({ title: 'Riesgo', value: 72, unit: '%' })\n *\n * // Multi-surface: GAIA tells you which surface it wants via ctx.surface\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Riesgo', value: 72 }),\n * table: () => ({ columns: ['alumno', 'score'], rows }),\n * text: () => `El riesgo del grupo es ${risk}%`,\n * })\n */\n\nimport type {\n CardPayload,\n TablePayload,\n WidgetPayload,\n ActionPayload,\n RespondOpts,\n Surface,\n SurfaceHandlers,\n VAIAResponse,\n CardResponse,\n TableResponse,\n TextResponse,\n WidgetResponse,\n ActionResponse,\n DataResponse,\n} from '../types.js'\nimport { VAIAError } from '../types.js'\n\n// ─── JSON helpers ─────────────────────────────────────────────────────────────\n\nconst JSON_HEADERS = { 'Content-Type': 'application/json' }\n\nfunction toResponse(body: VAIAResponse | { ok: false; error: string }, status = 200): Response {\n return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS })\n}\n\n// ─── make.* — plain objects (framework-agnostic) ─────────────────────────────\n\nexport const make = {\n card(payload: CardPayload, opts: RespondOpts = {}): CardResponse {\n return { ok: true, output_type: 'card', data: payload, ...opts }\n },\n\n table(payload: TablePayload, opts: RespondOpts = {}): TableResponse {\n return { ok: true, output_type: 'table', data: payload, ...opts }\n },\n\n text(content: string, opts: RespondOpts & { markdown?: boolean } = {}): TextResponse {\n const { markdown, ...rest } = opts\n return { ok: true, output_type: 'text', text: content, markdown, ...rest }\n },\n\n widget(payload: WidgetPayload, opts: RespondOpts = {}): WidgetResponse {\n return { ok: true, output_type: 'widget', data: payload, ...opts }\n },\n\n action(payload: ActionPayload, opts: RespondOpts = {}): ActionResponse {\n return { ok: true, output_type: 'action', data: payload, ...opts }\n },\n\n data(payload: Record<string, unknown>, opts: RespondOpts = {}): DataResponse {\n return { ok: true, output_type: 'data', data: payload, ...opts }\n },\n} as const\n\n// ─── respond.* — Web API Response ────────────────────────────────────────────\n\nexport const respond = {\n /** A compact card: title, value, unit, trend, etc. */\n card(payload: CardPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.card(payload, opts))\n },\n\n /** Tabular data with columns + rows. */\n table(payload: TablePayload, opts: RespondOpts = {}): Response {\n return toResponse(make.table(payload, opts))\n },\n\n /** Plain text or markdown — shown in chat or narrative views. */\n text(content: string, opts: RespondOpts & { markdown?: boolean } = {}): Response {\n return toResponse(make.text(content, opts))\n },\n\n /** An iframe pointing to the developer's own UI. */\n widget(payload: WidgetPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.widget(payload, opts))\n },\n\n /** Trigger an action (mutation, navigation, confirm dialog). */\n action(payload: ActionPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.action(payload, opts))\n },\n\n /** Arbitrary JSON — HAIA decides how to render based on shape. */\n data(payload: Record<string, unknown>, opts: RespondOpts = {}): Response {\n return toResponse(make.data(payload, opts))\n },\n\n /** Simple 200 OK — useful for probe responses. */\n ok(opts: RespondOpts = {}): Response {\n return toResponse(make.data({ status: 'ok' }, opts))\n },\n\n /** Returns a 4xx/5xx error response. */\n error(message: string, status = 500, code?: string): Response {\n return toResponse({ ok: false, error: message, ...(code ? { code } : {}) }, status)\n },\n\n /**\n * Multi-surface responder.\n * GAIA sends `ctx.surface` telling you what to render.\n * Map each surface to its handler and this picks the right one.\n *\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Riesgo', value: 72, unit: '%' }),\n * table: () => ({ columns: [...], rows: [...] }),\n * text: () => `El riesgo es 72%`,\n * }, opts)\n */\n async surface(\n surface: Surface,\n handlers: SurfaceHandlers,\n opts: RespondOpts = {},\n ): Promise<Response> {\n const handler = handlers[surface]\n\n if (!handler) {\n // Fallback cascade: data > text > first available handler\n const fallback =\n handlers.data ?? handlers.text ?? Object.values(handlers).find(Boolean)\n if (!fallback) {\n throw new VAIAError(\n `Surface '${surface}' no soportada por esta capacidad`,\n 'SURFACE_NOT_SUPPORTED',\n 422,\n )\n }\n return respond.surface(\n handlers.data ? 'data' : handlers.text ? 'text' : (Object.keys(handlers)[0] as Surface),\n handlers,\n opts,\n )\n }\n\n switch (surface) {\n case 'card': return respond.card(await (handlers.card!)(), opts)\n case 'table': return respond.table(await (handlers.table!)(), opts)\n case 'text': return respond.text(await (handlers.text!)(), opts)\n case 'widget': return respond.widget(await (handlers.widget!)(), opts)\n case 'action': return respond.action(await (handlers.action!)(), opts)\n case 'data': return respond.data(await (handlers.data!)(), opts)\n default: return respond.data(await (handlers.data ?? handlers.text ?? (() => ({})))(), opts)\n }\n },\n} as const\n","/**\n * gandia.can / gandia.require — permission helpers.\n *\n * Usage:\n * if (!gandia.can(ctx, 'read:students')) return gandia.respond.error('Forbidden', 403)\n * gandia.require(ctx, 'write:alerts') // throws VAIAError 403 if missing\n *\n * Supports wildcard scopes:\n * 'read:*' — matches all read permissions\n * 'read:students' — exact match\n */\n\nimport { VAIAError, type GandiaContext } from '../types.js'\n\nfunction matches(permission: string, granted: string[]): boolean {\n if (granted.includes(permission)) return true\n // wildcard: 'read:*' grants 'read:students'\n const [action] = permission.split(':')\n return granted.includes(`${action}:*`)\n}\n\n/** Returns true if the context has the given permission. */\nexport function can(ctx: Pick<GandiaContext, 'permissions'>, permission: string): boolean {\n return matches(permission, ctx.permissions)\n}\n\n/** Returns true if the context has ALL listed permissions. */\nexport function canAll(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): boolean {\n return permissions.every(p => matches(p, ctx.permissions))\n}\n\n/** Returns true if the context has ANY of the listed permissions. */\nexport function canAny(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): boolean {\n return permissions.some(p => matches(p, ctx.permissions))\n}\n\n/** Throws VAIAError 403 if the context does NOT have the given permission. */\nexport function require(ctx: Pick<GandiaContext, 'permissions'>, permission: string): void {\n if (!matches(permission, ctx.permissions)) {\n throw new VAIAError(\n `Permiso requerido: ${permission}`,\n 'PERMISSION_DENIED',\n 403,\n )\n }\n}\n\n/** Throws VAIAError 403 if the context does NOT have ALL listed permissions. */\nexport function requireAll(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): void {\n const missing = permissions.filter(p => !matches(p, ctx.permissions))\n if (missing.length > 0) {\n throw new VAIAError(\n `Permisos requeridos: ${missing.join(', ')}`,\n 'PERMISSION_DENIED',\n 403,\n )\n }\n}\n","/**\n * handeia — integration namespace for Handeia (personal platform).\n *\n * Quick start:\n * import { handeia } from '@vaia/sdk'\n *\n * export async function POST(req: Request) {\n * try {\n * const { ctx } = await handeia.verify(req, process.env.HANDEIA_KEY_SECRET!)\n * const profile = await myDb.getProfile(ctx.user.id)\n * return handeia.respond.surface(ctx.surface, {\n * card: () => ({ title: profile.name, subtitle: profile.role }),\n * text: () => `Hola ${profile.name}`,\n * })\n * } catch (err) {\n * if (err instanceof VAIAError) return handeia.respond.error(err.message, err.status)\n * throw err\n * }\n * }\n */\n\nexport { verify, isProbe, type HandeiaVerifyResult } from './verify.js'\nexport * as jwt from './jwt.js'\n\n// handeia shares the same respond/make API as gandia\nexport { respond, make } from '../gandia/respond.js'\n\n// Permission helpers (work the same — ctx.permissions is always a string[])\nexport { can, canAll, canAny, require, requireAll } from '../gandia/permissions.js'\n","/**\n * handeia.verify — verifies an incoming invoke call from Handeia.\n * Same HMAC protocol as gandia.verify but with Handeia-specific headers\n * and a HandeiaContext (user personal, no tenant).\n */\n\nimport { hmacVerify } from '../crypto.js'\nimport { VAIAError, type HandeiaContext, type Surface } from '../types.js'\n\nconst REPLAY_WINDOW_MS = 5 * 60 * 1000\nconst PROBE_HEADER = 'x-handeia-probe'\n\nexport interface HandeiaVerifyResult {\n ctx: HandeiaContext\n raw: string\n}\n\n/**\n * Call at the top of your `/api/handeia/invoke` route handler.\n * Throws VAIAError if the signature is invalid or the timestamp is stale.\n */\nexport async function verify(request: Request, secret: string): Promise<HandeiaVerifyResult> {\n const rawBody = await request.text()\n const headers = request.headers\n\n const sigHeader = headers.get('x-handeia-signature') ?? ''\n const tsHeader = headers.get('x-handeia-timestamp') ?? ''\n const callId = headers.get('x-handeia-call-id') ?? ''\n\n if (headers.get(PROBE_HEADER) === '1') {\n return { ctx: buildProbeCtx(callId), raw: rawBody }\n }\n\n if (!sigHeader || !tsHeader) {\n throw new VAIAError(\n 'Faltan headers de autenticación (X-Handeia-Signature, X-Handeia-Timestamp)',\n 'MISSING_AUTH_HEADERS',\n 401,\n )\n }\n\n const ts = parseInt(tsHeader, 10)\n if (isNaN(ts) || Math.abs(Date.now() - ts) > REPLAY_WINDOW_MS) {\n throw new VAIAError('Timestamp fuera de ventana (±5 min)', 'TIMESTAMP_OUT_OF_RANGE', 401)\n }\n\n const hexSig = sigHeader.startsWith('sha256=') ? sigHeader.slice(7) : sigHeader\n const signedData = `${tsHeader}.${rawBody}`\n const valid = await hmacVerify(secret, signedData, hexSig)\n\n if (!valid) {\n throw new VAIAError('Firma HMAC inválida', 'HMAC_INVALID', 401)\n }\n\n let body: unknown\n try {\n body = JSON.parse(rawBody)\n } catch {\n throw new VAIAError('Body no es JSON válido', 'BODY_PARSE_ERROR', 400)\n }\n\n const ctx = parseContext(body, callId)\n return { ctx, raw: rawBody }\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction parseContext(body: unknown, fallbackCallId: string): HandeiaContext {\n if (typeof body !== 'object' || body === null) {\n throw new VAIAError('Body inválido', 'BODY_INVALID', 400)\n }\n\n const b = body as Record<string, unknown>\n const user = (b['user'] ?? {}) as Record<string, unknown>\n const ctx = (b['context'] ?? {}) as Record<string, unknown>\n\n return {\n capability_id: s(b['capability_id']),\n call_id: s(b['call_id'], fallbackCallId),\n user: {\n id: s(user['id']),\n email: sOpt(user['email']),\n name: sOpt(user['name']),\n },\n permissions: arr(b['permissions']),\n trigger: s(ctx['trigger'], 'haia_invoke') as HandeiaContext['trigger'],\n surface: s(ctx['surface'], 'data') as Surface,\n query: sOpt(ctx['query']),\n }\n}\n\nfunction buildProbeCtx(callId: string): HandeiaContext {\n return {\n capability_id: '__probe__',\n call_id: callId || crypto.randomUUID(),\n user: { id: '__probe__' },\n permissions: [],\n trigger: 'haia_invoke',\n surface: 'data',\n }\n}\n\nfunction s(v: unknown, fallback = ''): string {\n return typeof v === 'string' ? v : fallback\n}\nfunction sOpt(v: unknown): string | undefined {\n return typeof v === 'string' ? v : undefined\n}\nfunction arr(v: unknown): string[] {\n return Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string') : []\n}\n\nexport function isProbe(request: Request): boolean {\n return request.headers.get(PROBE_HEADER) === '1'\n}\n","/**\n * handeia.jwt — JWT helpers for Handeia iframe auth bypass.\n * Same pattern as gandia.jwt but for personal context (no tenant).\n */\n\nimport { jwtSign, jwtVerify } from '../jwt-utils.js'\nimport type { HandeiaJWTClaims } from '../types.js'\n\nexport interface HandeiaJWTSignInput {\n sub: string // user_id\n email?: string | undefined\n name?: string | undefined\n permissions?: string[] | undefined\n}\n\nexport interface SignOpts {\n expiresIn?: number | undefined\n}\n\nconst DEFAULT_EXPIRES_IN = 3600\n\nexport async function sign(\n input: HandeiaJWTSignInput,\n secret: string,\n opts: SignOpts = {},\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n return jwtSign(\n {\n ...input,\n permissions: input.permissions ?? [],\n iat: now,\n exp: now + (opts.expiresIn ?? DEFAULT_EXPIRES_IN),\n },\n secret,\n )\n}\n\nexport async function verify(token: string, secret: string): Promise<HandeiaJWTClaims> {\n return jwtVerify<HandeiaJWTClaims>(token, secret)\n}\n\n/** Extracts and verifies `handeia_token` from a URL. */\nexport async function fromUrl(url: string | URL, secret: string): Promise<HandeiaJWTClaims> {\n const u = typeof url === 'string' ? new URL(url) : url\n const token = u.searchParams.get('handeia_token')\n if (!token) throw new Error('handeia_token no encontrado en la URL')\n return verify(token, secret)\n}\n","/**\n * defineCapability — declares a VAIA capability in code.\n *\n * This is both a type-safety layer (catches config errors at compile time)\n * and the source of truth for `npx vaia manifest` (generates gandia.manifest.json).\n *\n * The Shazam engine detects `defineCapability` in your code and reads the\n * config with 100% confidence — no manual confirmation needed in the portal.\n *\n * Usage (vaia.config.ts in project root):\n * import { defineCapability } from '@vaia/sdk'\n *\n * export default defineCapability({\n * id: 'mx.monitor-riesgo-academico',\n * name: 'Monitor de Riesgo Académico',\n * version: '1.0.0',\n * target: 'gandia',\n * type: 'app',\n * level: 'artefacto',\n * sector: 'educacion',\n * surfaces: {\n * card: { endpoint: '/api/gandia/invoke' },\n * table: { endpoint: '/api/gandia/invoke' },\n * text: { endpoint: '/api/gandia/invoke' },\n * },\n * permissions: ['read:students', 'read:grades', 'write:alerts'],\n * risk: 'medium',\n * })\n */\n\nimport type { CapabilityConfig, EcoTarget, Risk, Surface } from './types.js'\n\nexport type { CapabilityConfig }\n\nexport interface VAIAManifest {\n schema: '1.0'\n capability_id: string\n name: string\n version: string\n target: EcoTarget | EcoTarget[]\n type: string\n level?: string | undefined\n sector: string\n surfaces: string[]\n permissions: string[]\n risk: Risk\n has_own_auth: boolean\n stores_data: boolean\n trains_models: boolean\n requires_consent: boolean\n description?: string | undefined\n tags?: string[] | undefined\n linked: boolean\n generated_by: '@vaia/sdk'\n generated_at: string\n}\n\n/** Validates and returns the capability config. Throws if required fields are missing. */\nexport function defineCapability(config: CapabilityConfig): CapabilityConfig {\n const required: Array<keyof CapabilityConfig> = ['id', 'name', 'version', 'target', 'type', 'sector', 'permissions', 'risk']\n for (const key of required) {\n if (config[key] === undefined || config[key] === '') {\n throw new Error(`[@vaia/sdk] defineCapability: campo requerido faltante: '${key}'`)\n }\n }\n\n if (!config.id.includes('.')) {\n throw new Error(\n `[@vaia/sdk] defineCapability: 'id' debe usar formato reverse-domain (ej. 'mx.mi-capacidad'). Recibido: '${config.id}'`,\n )\n }\n\n if (Object.keys(config.surfaces).length === 0) {\n throw new Error(`[@vaia/sdk] defineCapability: 'surfaces' no puede estar vacío. Define al menos un surface con su endpoint.`)\n }\n\n return config\n}\n\n/** Converts a CapabilityConfig to a gandia.manifest.json object. */\nexport function toManifest(config: CapabilityConfig): VAIAManifest {\n const surfaces = Object.keys(config.surfaces) as Surface[]\n\n return {\n schema: '1.0',\n capability_id: config.id,\n name: config.name,\n version: config.version,\n target: config.target === 'both' ? ['gandia', 'handeia'] : config.target,\n type: config.type,\n level: config.level,\n sector: config.sector,\n surfaces,\n permissions: config.permissions,\n risk: config.risk,\n has_own_auth: config.has_own_auth ?? false,\n stores_data: config.stores_data ?? false,\n trains_models: config.trains_models ?? false,\n requires_consent: config.requires_consent ?? false,\n description: config.description,\n tags: config.tags,\n linked: config.target === 'both',\n generated_by: '@vaia/sdk',\n generated_at: new Date().toISOString(),\n }\n}\n"],"mappings":"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","names":["require","verify","enc","str","importHMACKey","verify","require","isProbe","jwt_exports","require","verify","REPLAY_WINDOW_MS","PROBE_HEADER","verify","buildProbeCtx","parseContext","arr","isProbe","jwt_exports","fromUrl","sign","verify","DEFAULT_EXPIRES_IN","sign","verify","fromUrl"]}
|
package/dist/index.js
CHANGED
|
@@ -174,14 +174,28 @@ __export(jwt_exports, {
|
|
|
174
174
|
|
|
175
175
|
// src/jwt-utils.ts
|
|
176
176
|
var enc2 = new TextEncoder();
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
var utf8Strict = new TextDecoder("utf-8", { fatal: true });
|
|
178
|
+
var utf8Loose = new TextDecoder("utf-8");
|
|
179
|
+
var latin1 = new TextDecoder("latin1");
|
|
180
|
+
var JWT_PAYLOAD_VERSION = 2;
|
|
181
|
+
function bytesToB64url(bytes) {
|
|
182
|
+
let bin = "";
|
|
183
|
+
const CHUNK = 32768;
|
|
184
|
+
for (let i = 0; i < bytes.length; i += CHUNK) {
|
|
185
|
+
bin += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
|
|
186
|
+
}
|
|
187
|
+
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
180
188
|
}
|
|
181
|
-
function
|
|
189
|
+
function b64urlToBytes(str2) {
|
|
182
190
|
const padded = str2.replace(/-/g, "+").replace(/_/g, "/");
|
|
183
191
|
const pad = padded.length % 4;
|
|
184
|
-
|
|
192
|
+
const bin = atob(pad ? padded + "=".repeat(4 - pad) : padded);
|
|
193
|
+
const out = new Uint8Array(new ArrayBuffer(bin.length));
|
|
194
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
function textToB64url(text) {
|
|
198
|
+
return bytesToB64url(enc2.encode(text));
|
|
185
199
|
}
|
|
186
200
|
async function importHMACKey2(secret) {
|
|
187
201
|
return crypto.subtle.importKey(
|
|
@@ -192,13 +206,33 @@ async function importHMACKey2(secret) {
|
|
|
192
206
|
["sign", "verify"]
|
|
193
207
|
);
|
|
194
208
|
}
|
|
195
|
-
var HEADER =
|
|
209
|
+
var HEADER = textToB64url(JSON.stringify({ alg: "HS256", typ: "JWT" }));
|
|
196
210
|
async function jwtSign(payload, secret) {
|
|
197
|
-
const body =
|
|
211
|
+
const body = textToB64url(JSON.stringify({ ...payload, v: JWT_PAYLOAD_VERSION }));
|
|
198
212
|
const unsigned = `${HEADER}.${body}`;
|
|
199
213
|
const key = await importHMACKey2(secret);
|
|
200
214
|
const sig = await crypto.subtle.sign("HMAC", key, enc2.encode(unsigned));
|
|
201
|
-
return `${unsigned}.${
|
|
215
|
+
return `${unsigned}.${bytesToB64url(new Uint8Array(sig))}`;
|
|
216
|
+
}
|
|
217
|
+
function decodePayload(body) {
|
|
218
|
+
const bytes = b64urlToBytes(body);
|
|
219
|
+
let sonda;
|
|
220
|
+
try {
|
|
221
|
+
sonda = JSON.parse(latin1.decode(bytes));
|
|
222
|
+
} catch {
|
|
223
|
+
throw new VAIAError("JWT payload inv\xE1lido", "JWT_PAYLOAD_INVALID", 401);
|
|
224
|
+
}
|
|
225
|
+
const version = typeof sonda["v"] === "number" ? sonda["v"] : 1;
|
|
226
|
+
if (version < 2) return sonda;
|
|
227
|
+
try {
|
|
228
|
+
return JSON.parse(utf8Strict.decode(bytes));
|
|
229
|
+
} catch {
|
|
230
|
+
try {
|
|
231
|
+
return JSON.parse(utf8Loose.decode(bytes));
|
|
232
|
+
} catch {
|
|
233
|
+
throw new VAIAError("JWT payload inv\xE1lido", "JWT_PAYLOAD_INVALID", 401);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
202
236
|
}
|
|
203
237
|
async function jwtVerify(token, secret) {
|
|
204
238
|
const parts = token.split(".");
|
|
@@ -208,17 +242,16 @@ async function jwtVerify(token, secret) {
|
|
|
208
242
|
const [header, body, sig] = parts;
|
|
209
243
|
const unsigned = `${header}.${body}`;
|
|
210
244
|
const key = await importHMACKey2(secret);
|
|
211
|
-
|
|
212
|
-
const valid = await crypto.subtle.verify("HMAC", key, sigBytes, enc2.encode(unsigned));
|
|
213
|
-
if (!valid) {
|
|
214
|
-
throw new VAIAError("Firma JWT inv\xE1lida", "JWT_SIGNATURE_INVALID", 401);
|
|
215
|
-
}
|
|
216
|
-
let payload;
|
|
245
|
+
let valid;
|
|
217
246
|
try {
|
|
218
|
-
|
|
247
|
+
valid = await crypto.subtle.verify("HMAC", key, b64urlToBytes(sig), enc2.encode(unsigned));
|
|
219
248
|
} catch {
|
|
220
|
-
throw new VAIAError("JWT
|
|
249
|
+
throw new VAIAError("JWT malformado", "JWT_MALFORMED", 401);
|
|
250
|
+
}
|
|
251
|
+
if (!valid) {
|
|
252
|
+
throw new VAIAError("Firma JWT inv\xE1lida", "JWT_SIGNATURE_INVALID", 401);
|
|
221
253
|
}
|
|
254
|
+
const payload = decodePayload(body);
|
|
222
255
|
if (typeof payload.exp === "number" && Date.now() / 1e3 > payload.exp) {
|
|
223
256
|
throw new VAIAError("JWT expirado", "JWT_EXPIRED", 401);
|
|
224
257
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/gandia/index.ts","../src/crypto.ts","../src/types.ts","../src/gandia/verify.ts","../src/gandia/jwt.ts","../src/jwt-utils.ts","../src/gandia/respond.ts","../src/gandia/permissions.ts","../src/handeia/index.ts","../src/handeia/verify.ts","../src/handeia/jwt.ts","../src/define.ts","../src/index.ts"],"sourcesContent":["/**\n * gandia — integration namespace for Gandia-7 (institutional platform).\n *\n * Quick start:\n * import { gandia } from '@vaia/sdk'\n *\n * export async function POST(req: Request) {\n * try {\n * const { ctx } = await gandia.verify(req, process.env.GANDIA_KEY_SECRET!)\n * gandia.require(ctx, 'read:students')\n * const data = await myDb.getStudents(ctx.tenant.id)\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Total alumnos', value: data.length }),\n * table: () => ({ columns: ['nombre', 'riesgo'], rows: data }),\n * text: () => `${data.length} alumnos en ${ctx.tenant.name}`,\n * })\n * } catch (err) {\n * if (err instanceof VAIAError) return gandia.respond.error(err.message, err.status)\n * throw err\n * }\n * }\n */\n\nexport { verify, isProbe, type VerifyResult } from './verify.js'\nexport * as jwt from './jwt.js'\nexport { respond, make } from './respond.js'\nexport { can, canAll, canAny, require, requireAll } from './permissions.js'\n","/**\n * HMAC-SHA256 utilities using the Web Crypto API.\n * Zero dependencies — works in Node 18+, Edge, Bun, Deno, browsers.\n */\n\nconst enc = new TextEncoder()\n\nfunction hexToBytes(hex: string): Uint8Array {\n if (hex.length % 2 !== 0) throw new Error('Invalid hex string')\n const bytes = new Uint8Array(hex.length / 2)\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16)\n }\n return bytes\n}\n\nasync function importHMACKey(secret: string): Promise<CryptoKey> {\n return crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n )\n}\n\n/** Signs `data` with HMAC-SHA256, returns lowercase hex. */\nexport async function hmacSign(secret: string, data: string): Promise<string> {\n const key = await importHMACKey(secret)\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(data))\n return Array.from(new Uint8Array(sig))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Constant-time HMAC-SHA256 verification.\n * Uses Web Crypto `verify` to avoid timing attacks.\n */\nexport async function hmacVerify(secret: string, data: string, hexSignature: string): Promise<boolean> {\n try {\n const key = await importHMACKey(secret)\n const sigBytes = hexToBytes(hexSignature)\n return await crypto.subtle.verify('HMAC', key, sigBytes, enc.encode(data))\n } catch {\n return false\n }\n}\n","// ─── Core enums ───────────────────────────────────────────────────────────────\n\nexport type PublishType = 'app' | 'ia' | 'skill' | 'eco'\nexport type EcoTarget = 'gandia' | 'handeia' | 'both'\nexport type NodeType = 'widget' | 'artefacto' | 'espacio' | 'skill' | 'agente'\nexport type Risk = 'low' | 'medium' | 'high'\nexport type Surface = 'card' | 'table' | 'text' | 'widget' | 'action' | 'data'\nexport type OutputType = Surface\n\n// ─── Gandia context ───────────────────────────────────────────────────────────\n\nexport interface GandiaTenant {\n id: string\n name: string\n sector: string\n}\n\nexport interface GandiaUser {\n id: string\n role: string\n email?: string | undefined\n}\n\n/** Context injected by GAIA on every invoke call to the developer's server. */\nexport interface GandiaContext {\n capability_id: string\n call_id: string\n tenant: GandiaTenant\n user: GandiaUser\n permissions: string[]\n trigger: 'user_query' | 'gaia_invoke' | 'event'\n /** Surface HAIA wants to render — determines which respond.* to use. */\n surface: Surface\n query?: string | undefined\n}\n\n// ─── Handeia context ──────────────────────────────────────────────────────────\n\nexport interface HandeiaUser {\n id: string\n email?: string | undefined\n name?: string | undefined\n}\n\n/** Context injected by HAIA on every invoke call to the developer's server. */\nexport interface HandeiaContext {\n capability_id: string\n call_id: string\n user: HandeiaUser\n permissions: string[]\n trigger: 'user_action' | 'haia_invoke' | 'schedule'\n /** Surface HAIA wants to render. */\n surface: Surface\n query?: string | undefined\n}\n\n// ─── JWT claims ───────────────────────────────────────────────────────────────\n\nexport interface GandiaJWTClaims {\n sub: string // user_id\n tenant_id: string\n email?: string | undefined\n role?: string | undefined\n permissions: string[]\n iat: number\n exp: number\n}\n\nexport interface HandeiaJWTClaims {\n sub: string // user_id\n email?: string | undefined\n name?: string | undefined\n permissions: string[]\n iat: number\n exp: number\n}\n\n// ─── Response payloads ────────────────────────────────────────────────────────\n\nexport interface AuditRecord {\n data_sources?: string[] | undefined\n records_accessed?: number | undefined\n [key: string]: unknown\n}\n\nexport interface RespondOpts {\n call_id?: string | undefined\n audit?: AuditRecord | undefined\n}\n\nexport interface CardPayload {\n title: string\n value?: string | number | undefined\n unit?: string | undefined\n trend?: 'up' | 'down' | 'neutral' | undefined\n icon?: string | undefined\n subtitle?: string | undefined\n color?: string | undefined\n [key: string]: unknown\n}\n\nexport interface TablePayload {\n columns: string[] | Array<{ key: string; label: string; type?: string | undefined }>\n rows: Array<Record<string, unknown>>\n total?: number | undefined\n page?: number | undefined\n per_page?: number | undefined\n}\n\nexport interface WidgetPayload {\n url: string\n height?: number | string | undefined\n width?: number | string | undefined\n meta?: Record<string, unknown> | undefined\n}\n\nexport interface ActionPayload {\n type: string\n label?: string | undefined\n params?: Record<string, unknown> | undefined\n confirm?: boolean | undefined\n destructive?: boolean | undefined\n}\n\n// ─── Typed VAIA response objects (returned by make.*) ────────────────────────\n\ninterface BaseVAIAResponse {\n ok: true\n call_id?: string | undefined\n audit?: AuditRecord | undefined\n}\n\nexport type CardResponse = BaseVAIAResponse & { output_type: 'card'; data: CardPayload }\nexport type TableResponse = BaseVAIAResponse & { output_type: 'table'; data: TablePayload }\nexport type TextResponse = BaseVAIAResponse & { output_type: 'text'; text: string; markdown?: boolean | undefined }\nexport type WidgetResponse = BaseVAIAResponse & { output_type: 'widget'; data: WidgetPayload }\nexport type ActionResponse = BaseVAIAResponse & { output_type: 'action'; data: ActionPayload }\nexport type DataResponse = BaseVAIAResponse & { output_type: 'data'; data: Record<string, unknown> }\nexport type ErrorResponse = { ok: false; error: string; code?: string | undefined }\n\nexport type VAIAResponse =\n | CardResponse\n | TableResponse\n | TextResponse\n | WidgetResponse\n | ActionResponse\n | DataResponse\n\n// ─── Surface handler map ──────────────────────────────────────────────────────\n\nexport type SurfaceHandlers = Partial<{\n card: () => CardPayload | Promise<CardPayload>\n table: () => TablePayload | Promise<TablePayload>\n text: () => string | Promise<string>\n widget: () => WidgetPayload | Promise<WidgetPayload>\n action: () => ActionPayload | Promise<ActionPayload>\n data: () => Record<string, unknown> | Promise<Record<string, unknown>>\n}>\n\n// ─── Capability definition ────────────────────────────────────────────────────\n\nexport interface SurfaceConfig {\n endpoint: string\n description?: string | undefined\n}\n\nexport interface CapabilityConfig {\n /** Unique capability ID — reverse domain: 'mx.mi-capacidad' */\n id: string\n name: string\n version: string\n /** Which VAIA platform(s) this capability targets. */\n target: EcoTarget\n type: PublishType\n level?: 'widget' | 'artefacto' | 'espacio' | undefined\n sector: string\n /** Which surfaces the capability can respond to, and their invoke endpoint. */\n surfaces: Partial<Record<Surface, SurfaceConfig>>\n permissions: string[]\n risk: Risk\n description?: string | undefined\n tags?: string[] | undefined\n /** Set to true if your app has its own login (triggers JWT bypass flow). */\n has_own_auth?: boolean | undefined\n stores_data?: boolean | undefined\n trains_models?: boolean | undefined\n requires_consent?: boolean | undefined\n}\n\n// ─── Errors ───────────────────────────────────────────────────────────────────\n\nexport class VAIAError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly status: number = 500,\n ) {\n super(message)\n this.name = 'VAIAError'\n }\n}\n","/**\n * gandia.verify — verifies an incoming invoke call from Gandia-7.\n *\n * Checks:\n * 1. X-Gandia-Signature (HMAC-SHA256 over timestamp + \".\" + raw body)\n * 2. X-Gandia-Timestamp within ±5 minutes (replay attack prevention)\n * 3. Parses and types the body as GandiaContext\n *\n * Usage:\n * const { ctx } = await verify(request, process.env.GANDIA_KEY_SECRET!)\n */\n\nimport { hmacVerify } from '../crypto.js'\nimport { VAIAError, type GandiaContext, type Surface } from '../types.js'\n\nconst REPLAY_WINDOW_MS = 5 * 60 * 1000 // 5 minutes\nconst PROBE_HEADER = 'x-gandia-probe'\n\n/** Raw body of the invoke call. Returned alongside ctx so you don't re-read the stream. */\nexport interface VerifyResult {\n ctx: GandiaContext\n raw: string\n}\n\n/**\n * Call at the top of your `/api/gandia/invoke` route handler.\n * Throws VAIAError if the signature is invalid or the timestamp is stale.\n */\nexport async function verify(request: Request, secret: string): Promise<VerifyResult> {\n const rawBody = await request.text()\n const headers = request.headers\n\n const sigHeader = headers.get('x-gandia-signature') ?? ''\n const tsHeader = headers.get('x-gandia-timestamp') ?? ''\n const callId = headers.get('x-gandia-call-id') ?? ''\n\n // Health probe from test-connection — no signature required\n if (headers.get(PROBE_HEADER) === '1') {\n return { ctx: buildProbeCtx(callId), raw: rawBody }\n }\n\n if (!sigHeader || !tsHeader) {\n throw new VAIAError(\n 'Faltan headers de autenticación (X-Gandia-Signature, X-Gandia-Timestamp)',\n 'MISSING_AUTH_HEADERS',\n 401,\n )\n }\n\n // Replay attack check\n const ts = parseInt(tsHeader, 10)\n if (isNaN(ts) || Math.abs(Date.now() - ts) > REPLAY_WINDOW_MS) {\n throw new VAIAError('Timestamp fuera de ventana (±5 min)', 'TIMESTAMP_OUT_OF_RANGE', 401)\n }\n\n // Strip \"sha256=\" prefix if present\n const hexSig = sigHeader.startsWith('sha256=') ? sigHeader.slice(7) : sigHeader\n\n // HMAC verification — constant-time via Web Crypto\n const signedData = `${tsHeader}.${rawBody}`\n const valid = await hmacVerify(secret, signedData, hexSig)\n if (!valid) {\n throw new VAIAError('Firma HMAC inválida', 'HMAC_INVALID', 401)\n }\n\n // Parse body\n let body: unknown\n try {\n body = JSON.parse(rawBody)\n } catch {\n throw new VAIAError('Body no es JSON válido', 'BODY_PARSE_ERROR', 400)\n }\n\n const ctx = parseContext(body, callId)\n return { ctx, raw: rawBody }\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction parseContext(body: unknown, fallbackCallId: string): GandiaContext {\n if (typeof body !== 'object' || body === null) {\n throw new VAIAError('Body inválido', 'BODY_INVALID', 400)\n }\n\n const b = body as Record<string, unknown>\n\n return {\n capability_id: str(b, 'capability_id'),\n call_id: str(b, 'call_id', fallbackCallId),\n tenant: {\n id: nestedStr(b, 'tenant', 'id'),\n name: nestedStr(b, 'tenant', 'name'),\n sector: nestedStr(b, 'tenant', 'sector'),\n },\n user: {\n id: nestedStr(b, 'user', 'id'),\n role: nestedStr(b, 'user', 'role'),\n email: nestedStrOpt(b, 'user', 'email'),\n },\n permissions: arr(b, 'permissions'),\n trigger: str(b, 'context.trigger', 'gaia_invoke') as GandiaContext['trigger'],\n surface: str(b, 'context.surface', 'data') as Surface,\n query: nestedStrOpt(b, 'context', 'query'),\n }\n}\n\nfunction buildProbeCtx(callId: string): GandiaContext {\n return {\n capability_id: '__probe__',\n call_id: callId || crypto.randomUUID(),\n tenant: { id: '__probe__', name: '__probe__', sector: '__probe__' },\n user: { id: '__probe__', role: '__probe__' },\n permissions: [],\n trigger: 'gaia_invoke',\n surface: 'data',\n }\n}\n\nfunction str(obj: Record<string, unknown>, key: string, fallback = ''): string {\n // Support dot notation: 'context.trigger'\n const parts = key.split('.')\n let cur: unknown = obj\n for (const part of parts) {\n if (typeof cur !== 'object' || cur === null) return fallback\n cur = (cur as Record<string, unknown>)[part]\n }\n return typeof cur === 'string' ? cur : fallback\n}\n\nfunction nestedStr(\n obj: Record<string, unknown>,\n parent: string,\n key: string,\n fallback = '',\n): string {\n const p = obj[parent]\n if (typeof p !== 'object' || p === null) return fallback\n const v = (p as Record<string, unknown>)[key]\n return typeof v === 'string' ? v : fallback\n}\n\nfunction nestedStrOpt(\n obj: Record<string, unknown>,\n parent: string,\n key: string,\n): string | undefined {\n const p = obj[parent]\n if (typeof p !== 'object' || p === null) return undefined\n const v = (p as Record<string, unknown>)[key]\n return typeof v === 'string' ? v : undefined\n}\n\nfunction arr(obj: Record<string, unknown>, key: string): string[] {\n const v = obj[key]\n if (!Array.isArray(v)) return []\n return v.filter((x): x is string => typeof x === 'string')\n}\n\n/** Quick check — use before calling verify() if you want to short-circuit probes. */\nexport function isProbe(request: Request): boolean {\n return request.headers.get(PROBE_HEADER) === '1'\n}\n","/**\n * gandia.jwt — JWT helpers for iframe auth bypass.\n *\n * When Gandia-7 opens a developer's app as an iframe, it appends:\n * ?gandia_token=<signed_jwt>\n *\n * The developer verifies the token, extracts the user/tenant claims,\n * and creates a session — skipping their own login page.\n *\n * Usage (server-side):\n * const claims = await gandia.jwt.verify(token, process.env.GANDIA_KEY_SECRET!)\n * // → { sub, tenant_id, email, role, permissions, exp, iat }\n *\n * Usage (VAIA-side, when generating tokens for developer iframes):\n * const token = await gandia.jwt.sign({ sub: userId, tenant_id, ... }, secret, { expiresIn: 3600 })\n */\n\nimport { jwtSign, jwtVerify } from '../jwt-utils.js'\nimport type { GandiaJWTClaims } from '../types.js'\n\nexport interface GandiaJWTSignInput {\n sub: string // user_id\n tenant_id: string\n email?: string | undefined\n role?: string | undefined\n permissions?: string[] | undefined\n}\n\nexport interface SignOpts {\n /** Seconds until expiry. Default: 3600 (1 hour). */\n expiresIn?: number | undefined\n}\n\nconst DEFAULT_EXPIRES_IN = 3600\n\n/** Signs a new Gandia iframe JWT. Typically called by Gandia-7, not by the developer. */\nexport async function sign(\n input: GandiaJWTSignInput,\n secret: string,\n opts: SignOpts = {},\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n return jwtSign(\n {\n ...input,\n permissions: input.permissions ?? [],\n iat: now,\n exp: now + (opts.expiresIn ?? DEFAULT_EXPIRES_IN),\n },\n secret,\n )\n}\n\n/** Verifies a Gandia iframe JWT and returns its claims. Throws VAIAError on failure. */\nexport async function verify(token: string, secret: string): Promise<GandiaJWTClaims> {\n return jwtVerify<GandiaJWTClaims>(token, secret)\n}\n\n/**\n * Extracts `gandia_token` from a URL and verifies it.\n * Convenience for iframe entry-point routes.\n *\n * const claims = await gandia.jwt.fromUrl(request.url, secret)\n */\nexport async function fromUrl(url: string | URL, secret: string): Promise<GandiaJWTClaims> {\n const u = typeof url === 'string' ? new URL(url) : url\n const token = u.searchParams.get('gandia_token')\n if (!token) {\n throw new Error('gandia_token no encontrado en la URL')\n }\n return verify(token, secret)\n}\n","/**\n * Minimal HS256 JWT implementation using Web Crypto.\n * No third-party dependencies.\n */\n\nimport { VAIAError } from './types.js'\n\nconst enc = new TextEncoder()\n\nfunction b64urlEncode(data: ArrayBuffer | string): string {\n const str =\n typeof data === 'string'\n ? data\n : String.fromCharCode(...new Uint8Array(data))\n return btoa(str).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\nfunction b64urlDecode(str: string): string {\n const padded = str.replace(/-/g, '+').replace(/_/g, '/')\n const pad = padded.length % 4\n return atob(pad ? padded + '='.repeat(4 - pad) : padded)\n}\n\nasync function importHMACKey(secret: string): Promise<CryptoKey> {\n return crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n )\n}\n\nconst HEADER = b64urlEncode(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))\n\n/** Creates a signed HS256 JWT. */\nexport async function jwtSign(\n payload: Record<string, unknown>,\n secret: string,\n): Promise<string> {\n const body = b64urlEncode(JSON.stringify(payload))\n const unsigned = `${HEADER}.${body}`\n const key = await importHMACKey(secret)\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(unsigned))\n return `${unsigned}.${b64urlEncode(sig)}`\n}\n\n/** Verifies an HS256 JWT and returns its payload. Throws VAIAError on failure. */\nexport async function jwtVerify<T extends object>(\n token: string,\n secret: string,\n): Promise<T> {\n const parts = token.split('.')\n if (parts.length !== 3) {\n throw new VAIAError('JWT malformado', 'JWT_MALFORMED', 401)\n }\n\n const [header, body, sig] = parts as [string, string, string]\n const unsigned = `${header}.${body}`\n\n const key = await importHMACKey(secret)\n const sigBytes = Uint8Array.from(b64urlDecode(sig), c => c.charCodeAt(0))\n const valid = await crypto.subtle.verify('HMAC', key, sigBytes, enc.encode(unsigned))\n\n if (!valid) {\n throw new VAIAError('Firma JWT inválida', 'JWT_SIGNATURE_INVALID', 401)\n }\n\n let payload: T & { exp?: number; iat?: number }\n try {\n payload = JSON.parse(b64urlDecode(body)) as T & { exp?: number; iat?: number }\n } catch {\n throw new VAIAError('JWT payload inválido', 'JWT_PAYLOAD_INVALID', 401)\n }\n\n if (typeof payload.exp === 'number' && Date.now() / 1000 > payload.exp) {\n throw new VAIAError('JWT expirado', 'JWT_EXPIRED', 401)\n }\n\n return payload as T\n}\n","/**\n * gandia.respond — typed response builders.\n *\n * Each method returns a Web API Response with the correct VAIA envelope.\n * HAIA reads `output_type` to decide how to render the result.\n *\n * For non-Response frameworks (Express, Fastify), use gandia.make.* instead.\n *\n * Usage:\n * // Returns Web API Response\n * return gandia.respond.card({ title: 'Riesgo', value: 72, unit: '%' })\n *\n * // Multi-surface: GAIA tells you which surface it wants via ctx.surface\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Riesgo', value: 72 }),\n * table: () => ({ columns: ['alumno', 'score'], rows }),\n * text: () => `El riesgo del grupo es ${risk}%`,\n * })\n */\n\nimport type {\n CardPayload,\n TablePayload,\n WidgetPayload,\n ActionPayload,\n RespondOpts,\n Surface,\n SurfaceHandlers,\n VAIAResponse,\n CardResponse,\n TableResponse,\n TextResponse,\n WidgetResponse,\n ActionResponse,\n DataResponse,\n} from '../types.js'\nimport { VAIAError } from '../types.js'\n\n// ─── JSON helpers ─────────────────────────────────────────────────────────────\n\nconst JSON_HEADERS = { 'Content-Type': 'application/json' }\n\nfunction toResponse(body: VAIAResponse | { ok: false; error: string }, status = 200): Response {\n return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS })\n}\n\n// ─── make.* — plain objects (framework-agnostic) ─────────────────────────────\n\nexport const make = {\n card(payload: CardPayload, opts: RespondOpts = {}): CardResponse {\n return { ok: true, output_type: 'card', data: payload, ...opts }\n },\n\n table(payload: TablePayload, opts: RespondOpts = {}): TableResponse {\n return { ok: true, output_type: 'table', data: payload, ...opts }\n },\n\n text(content: string, opts: RespondOpts & { markdown?: boolean } = {}): TextResponse {\n const { markdown, ...rest } = opts\n return { ok: true, output_type: 'text', text: content, markdown, ...rest }\n },\n\n widget(payload: WidgetPayload, opts: RespondOpts = {}): WidgetResponse {\n return { ok: true, output_type: 'widget', data: payload, ...opts }\n },\n\n action(payload: ActionPayload, opts: RespondOpts = {}): ActionResponse {\n return { ok: true, output_type: 'action', data: payload, ...opts }\n },\n\n data(payload: Record<string, unknown>, opts: RespondOpts = {}): DataResponse {\n return { ok: true, output_type: 'data', data: payload, ...opts }\n },\n} as const\n\n// ─── respond.* — Web API Response ────────────────────────────────────────────\n\nexport const respond = {\n /** A compact card: title, value, unit, trend, etc. */\n card(payload: CardPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.card(payload, opts))\n },\n\n /** Tabular data with columns + rows. */\n table(payload: TablePayload, opts: RespondOpts = {}): Response {\n return toResponse(make.table(payload, opts))\n },\n\n /** Plain text or markdown — shown in chat or narrative views. */\n text(content: string, opts: RespondOpts & { markdown?: boolean } = {}): Response {\n return toResponse(make.text(content, opts))\n },\n\n /** An iframe pointing to the developer's own UI. */\n widget(payload: WidgetPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.widget(payload, opts))\n },\n\n /** Trigger an action (mutation, navigation, confirm dialog). */\n action(payload: ActionPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.action(payload, opts))\n },\n\n /** Arbitrary JSON — HAIA decides how to render based on shape. */\n data(payload: Record<string, unknown>, opts: RespondOpts = {}): Response {\n return toResponse(make.data(payload, opts))\n },\n\n /** Simple 200 OK — useful for probe responses. */\n ok(opts: RespondOpts = {}): Response {\n return toResponse(make.data({ status: 'ok' }, opts))\n },\n\n /** Returns a 4xx/5xx error response. */\n error(message: string, status = 500, code?: string): Response {\n return toResponse({ ok: false, error: message, ...(code ? { code } : {}) }, status)\n },\n\n /**\n * Multi-surface responder.\n * GAIA sends `ctx.surface` telling you what to render.\n * Map each surface to its handler and this picks the right one.\n *\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Riesgo', value: 72, unit: '%' }),\n * table: () => ({ columns: [...], rows: [...] }),\n * text: () => `El riesgo es 72%`,\n * }, opts)\n */\n async surface(\n surface: Surface,\n handlers: SurfaceHandlers,\n opts: RespondOpts = {},\n ): Promise<Response> {\n const handler = handlers[surface]\n\n if (!handler) {\n // Fallback cascade: data > text > first available handler\n const fallback =\n handlers.data ?? handlers.text ?? Object.values(handlers).find(Boolean)\n if (!fallback) {\n throw new VAIAError(\n `Surface '${surface}' no soportada por esta capacidad`,\n 'SURFACE_NOT_SUPPORTED',\n 422,\n )\n }\n return respond.surface(\n handlers.data ? 'data' : handlers.text ? 'text' : (Object.keys(handlers)[0] as Surface),\n handlers,\n opts,\n )\n }\n\n switch (surface) {\n case 'card': return respond.card(await (handlers.card!)(), opts)\n case 'table': return respond.table(await (handlers.table!)(), opts)\n case 'text': return respond.text(await (handlers.text!)(), opts)\n case 'widget': return respond.widget(await (handlers.widget!)(), opts)\n case 'action': return respond.action(await (handlers.action!)(), opts)\n case 'data': return respond.data(await (handlers.data!)(), opts)\n default: return respond.data(await (handlers.data ?? handlers.text ?? (() => ({})))(), opts)\n }\n },\n} as const\n","/**\n * gandia.can / gandia.require — permission helpers.\n *\n * Usage:\n * if (!gandia.can(ctx, 'read:students')) return gandia.respond.error('Forbidden', 403)\n * gandia.require(ctx, 'write:alerts') // throws VAIAError 403 if missing\n *\n * Supports wildcard scopes:\n * 'read:*' — matches all read permissions\n * 'read:students' — exact match\n */\n\nimport { VAIAError, type GandiaContext } from '../types.js'\n\nfunction matches(permission: string, granted: string[]): boolean {\n if (granted.includes(permission)) return true\n // wildcard: 'read:*' grants 'read:students'\n const [action] = permission.split(':')\n return granted.includes(`${action}:*`)\n}\n\n/** Returns true if the context has the given permission. */\nexport function can(ctx: Pick<GandiaContext, 'permissions'>, permission: string): boolean {\n return matches(permission, ctx.permissions)\n}\n\n/** Returns true if the context has ALL listed permissions. */\nexport function canAll(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): boolean {\n return permissions.every(p => matches(p, ctx.permissions))\n}\n\n/** Returns true if the context has ANY of the listed permissions. */\nexport function canAny(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): boolean {\n return permissions.some(p => matches(p, ctx.permissions))\n}\n\n/** Throws VAIAError 403 if the context does NOT have the given permission. */\nexport function require(ctx: Pick<GandiaContext, 'permissions'>, permission: string): void {\n if (!matches(permission, ctx.permissions)) {\n throw new VAIAError(\n `Permiso requerido: ${permission}`,\n 'PERMISSION_DENIED',\n 403,\n )\n }\n}\n\n/** Throws VAIAError 403 if the context does NOT have ALL listed permissions. */\nexport function requireAll(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): void {\n const missing = permissions.filter(p => !matches(p, ctx.permissions))\n if (missing.length > 0) {\n throw new VAIAError(\n `Permisos requeridos: ${missing.join(', ')}`,\n 'PERMISSION_DENIED',\n 403,\n )\n }\n}\n","/**\n * handeia — integration namespace for Handeia (personal platform).\n *\n * Quick start:\n * import { handeia } from '@vaia/sdk'\n *\n * export async function POST(req: Request) {\n * try {\n * const { ctx } = await handeia.verify(req, process.env.HANDEIA_KEY_SECRET!)\n * const profile = await myDb.getProfile(ctx.user.id)\n * return handeia.respond.surface(ctx.surface, {\n * card: () => ({ title: profile.name, subtitle: profile.role }),\n * text: () => `Hola ${profile.name}`,\n * })\n * } catch (err) {\n * if (err instanceof VAIAError) return handeia.respond.error(err.message, err.status)\n * throw err\n * }\n * }\n */\n\nexport { verify, isProbe, type HandeiaVerifyResult } from './verify.js'\nexport * as jwt from './jwt.js'\n\n// handeia shares the same respond/make API as gandia\nexport { respond, make } from '../gandia/respond.js'\n\n// Permission helpers (work the same — ctx.permissions is always a string[])\nexport { can, canAll, canAny, require, requireAll } from '../gandia/permissions.js'\n","/**\n * handeia.verify — verifies an incoming invoke call from Handeia.\n * Same HMAC protocol as gandia.verify but with Handeia-specific headers\n * and a HandeiaContext (user personal, no tenant).\n */\n\nimport { hmacVerify } from '../crypto.js'\nimport { VAIAError, type HandeiaContext, type Surface } from '../types.js'\n\nconst REPLAY_WINDOW_MS = 5 * 60 * 1000\nconst PROBE_HEADER = 'x-handeia-probe'\n\nexport interface HandeiaVerifyResult {\n ctx: HandeiaContext\n raw: string\n}\n\n/**\n * Call at the top of your `/api/handeia/invoke` route handler.\n * Throws VAIAError if the signature is invalid or the timestamp is stale.\n */\nexport async function verify(request: Request, secret: string): Promise<HandeiaVerifyResult> {\n const rawBody = await request.text()\n const headers = request.headers\n\n const sigHeader = headers.get('x-handeia-signature') ?? ''\n const tsHeader = headers.get('x-handeia-timestamp') ?? ''\n const callId = headers.get('x-handeia-call-id') ?? ''\n\n if (headers.get(PROBE_HEADER) === '1') {\n return { ctx: buildProbeCtx(callId), raw: rawBody }\n }\n\n if (!sigHeader || !tsHeader) {\n throw new VAIAError(\n 'Faltan headers de autenticación (X-Handeia-Signature, X-Handeia-Timestamp)',\n 'MISSING_AUTH_HEADERS',\n 401,\n )\n }\n\n const ts = parseInt(tsHeader, 10)\n if (isNaN(ts) || Math.abs(Date.now() - ts) > REPLAY_WINDOW_MS) {\n throw new VAIAError('Timestamp fuera de ventana (±5 min)', 'TIMESTAMP_OUT_OF_RANGE', 401)\n }\n\n const hexSig = sigHeader.startsWith('sha256=') ? sigHeader.slice(7) : sigHeader\n const signedData = `${tsHeader}.${rawBody}`\n const valid = await hmacVerify(secret, signedData, hexSig)\n\n if (!valid) {\n throw new VAIAError('Firma HMAC inválida', 'HMAC_INVALID', 401)\n }\n\n let body: unknown\n try {\n body = JSON.parse(rawBody)\n } catch {\n throw new VAIAError('Body no es JSON válido', 'BODY_PARSE_ERROR', 400)\n }\n\n const ctx = parseContext(body, callId)\n return { ctx, raw: rawBody }\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction parseContext(body: unknown, fallbackCallId: string): HandeiaContext {\n if (typeof body !== 'object' || body === null) {\n throw new VAIAError('Body inválido', 'BODY_INVALID', 400)\n }\n\n const b = body as Record<string, unknown>\n const user = (b['user'] ?? {}) as Record<string, unknown>\n const ctx = (b['context'] ?? {}) as Record<string, unknown>\n\n return {\n capability_id: s(b['capability_id']),\n call_id: s(b['call_id'], fallbackCallId),\n user: {\n id: s(user['id']),\n email: sOpt(user['email']),\n name: sOpt(user['name']),\n },\n permissions: arr(b['permissions']),\n trigger: s(ctx['trigger'], 'haia_invoke') as HandeiaContext['trigger'],\n surface: s(ctx['surface'], 'data') as Surface,\n query: sOpt(ctx['query']),\n }\n}\n\nfunction buildProbeCtx(callId: string): HandeiaContext {\n return {\n capability_id: '__probe__',\n call_id: callId || crypto.randomUUID(),\n user: { id: '__probe__' },\n permissions: [],\n trigger: 'haia_invoke',\n surface: 'data',\n }\n}\n\nfunction s(v: unknown, fallback = ''): string {\n return typeof v === 'string' ? v : fallback\n}\nfunction sOpt(v: unknown): string | undefined {\n return typeof v === 'string' ? v : undefined\n}\nfunction arr(v: unknown): string[] {\n return Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string') : []\n}\n\nexport function isProbe(request: Request): boolean {\n return request.headers.get(PROBE_HEADER) === '1'\n}\n","/**\n * handeia.jwt — JWT helpers for Handeia iframe auth bypass.\n * Same pattern as gandia.jwt but for personal context (no tenant).\n */\n\nimport { jwtSign, jwtVerify } from '../jwt-utils.js'\nimport type { HandeiaJWTClaims } from '../types.js'\n\nexport interface HandeiaJWTSignInput {\n sub: string // user_id\n email?: string | undefined\n name?: string | undefined\n permissions?: string[] | undefined\n}\n\nexport interface SignOpts {\n expiresIn?: number | undefined\n}\n\nconst DEFAULT_EXPIRES_IN = 3600\n\nexport async function sign(\n input: HandeiaJWTSignInput,\n secret: string,\n opts: SignOpts = {},\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n return jwtSign(\n {\n ...input,\n permissions: input.permissions ?? [],\n iat: now,\n exp: now + (opts.expiresIn ?? DEFAULT_EXPIRES_IN),\n },\n secret,\n )\n}\n\nexport async function verify(token: string, secret: string): Promise<HandeiaJWTClaims> {\n return jwtVerify<HandeiaJWTClaims>(token, secret)\n}\n\n/** Extracts and verifies `handeia_token` from a URL. */\nexport async function fromUrl(url: string | URL, secret: string): Promise<HandeiaJWTClaims> {\n const u = typeof url === 'string' ? new URL(url) : url\n const token = u.searchParams.get('handeia_token')\n if (!token) throw new Error('handeia_token no encontrado en la URL')\n return verify(token, secret)\n}\n","/**\n * defineCapability — declares a VAIA capability in code.\n *\n * This is both a type-safety layer (catches config errors at compile time)\n * and the source of truth for `npx vaia manifest` (generates gandia.manifest.json).\n *\n * The Shazam engine detects `defineCapability` in your code and reads the\n * config with 100% confidence — no manual confirmation needed in the portal.\n *\n * Usage (vaia.config.ts in project root):\n * import { defineCapability } from '@vaia/sdk'\n *\n * export default defineCapability({\n * id: 'mx.monitor-riesgo-academico',\n * name: 'Monitor de Riesgo Académico',\n * version: '1.0.0',\n * target: 'gandia',\n * type: 'app',\n * level: 'artefacto',\n * sector: 'educacion',\n * surfaces: {\n * card: { endpoint: '/api/gandia/invoke' },\n * table: { endpoint: '/api/gandia/invoke' },\n * text: { endpoint: '/api/gandia/invoke' },\n * },\n * permissions: ['read:students', 'read:grades', 'write:alerts'],\n * risk: 'medium',\n * })\n */\n\nimport type { CapabilityConfig, EcoTarget, Risk, Surface } from './types.js'\n\nexport type { CapabilityConfig }\n\nexport interface VAIAManifest {\n schema: '1.0'\n capability_id: string\n name: string\n version: string\n target: EcoTarget | EcoTarget[]\n type: string\n level?: string | undefined\n sector: string\n surfaces: string[]\n permissions: string[]\n risk: Risk\n has_own_auth: boolean\n stores_data: boolean\n trains_models: boolean\n requires_consent: boolean\n description?: string | undefined\n tags?: string[] | undefined\n linked: boolean\n generated_by: '@vaia/sdk'\n generated_at: string\n}\n\n/** Validates and returns the capability config. Throws if required fields are missing. */\nexport function defineCapability(config: CapabilityConfig): CapabilityConfig {\n const required: Array<keyof CapabilityConfig> = ['id', 'name', 'version', 'target', 'type', 'sector', 'permissions', 'risk']\n for (const key of required) {\n if (config[key] === undefined || config[key] === '') {\n throw new Error(`[@vaia/sdk] defineCapability: campo requerido faltante: '${key}'`)\n }\n }\n\n if (!config.id.includes('.')) {\n throw new Error(\n `[@vaia/sdk] defineCapability: 'id' debe usar formato reverse-domain (ej. 'mx.mi-capacidad'). Recibido: '${config.id}'`,\n )\n }\n\n if (Object.keys(config.surfaces).length === 0) {\n throw new Error(`[@vaia/sdk] defineCapability: 'surfaces' no puede estar vacío. Define al menos un surface con su endpoint.`)\n }\n\n return config\n}\n\n/** Converts a CapabilityConfig to a gandia.manifest.json object. */\nexport function toManifest(config: CapabilityConfig): VAIAManifest {\n const surfaces = Object.keys(config.surfaces) as Surface[]\n\n return {\n schema: '1.0',\n capability_id: config.id,\n name: config.name,\n version: config.version,\n target: config.target === 'both' ? ['gandia', 'handeia'] : config.target,\n type: config.type,\n level: config.level,\n sector: config.sector,\n surfaces,\n permissions: config.permissions,\n risk: config.risk,\n has_own_auth: config.has_own_auth ?? false,\n stores_data: config.stores_data ?? false,\n trains_models: config.trains_models ?? false,\n requires_consent: config.requires_consent ?? false,\n description: config.description,\n tags: config.tags,\n linked: config.target === 'both',\n generated_by: '@vaia/sdk',\n generated_at: new Date().toISOString(),\n }\n}\n","/**\n * @vaia/sdk — VAIA Platform Integration SDK\n *\n * Provides two namespaces:\n * gandia → Gandia-7 (institutional platform)\n * handeia → Handeia (personal platform)\n *\n * Quick start:\n * import { gandia, handeia, defineCapability, VAIAError } from '@vaia/sdk'\n */\n\n// ─── Platform namespaces ──────────────────────────────────────────────────────\n\nimport * as _gandia from './gandia/index.js'\nimport * as _handeia from './handeia/index.js'\n\nexport const gandia = _gandia\nexport const handeia = _handeia\n\n// ─── defineCapability + manifest ─────────────────────────────────────────────\n\nexport { defineCapability, toManifest } from './define.js'\nexport type { CapabilityConfig, VAIAManifest } from './define.js'\n\n// ─── Shared error class ───────────────────────────────────────────────────────\n\nexport { VAIAError } from './types.js'\n\n// ─── All types (re-exported for consumer convenience) ─────────────────────────\n\nexport type {\n // Core enums\n PublishType,\n EcoTarget,\n NodeType,\n Risk,\n Surface,\n OutputType,\n\n // Contexts\n GandiaContext,\n GandiaTenant,\n GandiaUser,\n HandeiaContext,\n HandeiaUser,\n\n // JWT claims\n GandiaJWTClaims,\n HandeiaJWTClaims,\n\n // Response payloads\n CardPayload,\n TablePayload,\n WidgetPayload,\n ActionPayload,\n AuditRecord,\n RespondOpts,\n SurfaceHandlers,\n\n // Response types\n VAIAResponse,\n CardResponse,\n TableResponse,\n TextResponse,\n WidgetResponse,\n ActionResponse,\n DataResponse,\n ErrorResponse,\n} from './types.js'\n"],"mappings":"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","names":["require","verify","enc","str","importHMACKey","verify","require","isProbe","jwt_exports","require","verify","REPLAY_WINDOW_MS","PROBE_HEADER","verify","buildProbeCtx","parseContext","arr","isProbe","jwt_exports","fromUrl","sign","verify","DEFAULT_EXPIRES_IN","sign","verify","fromUrl"]}
|
|
1
|
+
{"version":3,"sources":["../src/gandia/index.ts","../src/crypto.ts","../src/types.ts","../src/gandia/verify.ts","../src/gandia/jwt.ts","../src/jwt-utils.ts","../src/gandia/respond.ts","../src/gandia/permissions.ts","../src/handeia/index.ts","../src/handeia/verify.ts","../src/handeia/jwt.ts","../src/define.ts","../src/index.ts"],"sourcesContent":["/**\n * gandia — integration namespace for Gandia-7 (institutional platform).\n *\n * Quick start:\n * import { gandia } from '@vaia/sdk'\n *\n * export async function POST(req: Request) {\n * try {\n * const { ctx } = await gandia.verify(req, process.env.GANDIA_KEY_SECRET!)\n * gandia.require(ctx, 'read:students')\n * const data = await myDb.getStudents(ctx.tenant.id)\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Total alumnos', value: data.length }),\n * table: () => ({ columns: ['nombre', 'riesgo'], rows: data }),\n * text: () => `${data.length} alumnos en ${ctx.tenant.name}`,\n * })\n * } catch (err) {\n * if (err instanceof VAIAError) return gandia.respond.error(err.message, err.status)\n * throw err\n * }\n * }\n */\n\nexport { verify, isProbe, type VerifyResult } from './verify.js'\nexport * as jwt from './jwt.js'\nexport { respond, make } from './respond.js'\nexport { can, canAll, canAny, require, requireAll } from './permissions.js'\n","/**\n * HMAC-SHA256 utilities using the Web Crypto API.\n * Zero dependencies — works in Node 18+, Edge, Bun, Deno, browsers.\n */\n\nconst enc = new TextEncoder()\n\nfunction hexToBytes(hex: string): Uint8Array {\n if (hex.length % 2 !== 0) throw new Error('Invalid hex string')\n const bytes = new Uint8Array(hex.length / 2)\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16)\n }\n return bytes\n}\n\nasync function importHMACKey(secret: string): Promise<CryptoKey> {\n return crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n )\n}\n\n/** Signs `data` with HMAC-SHA256, returns lowercase hex. */\nexport async function hmacSign(secret: string, data: string): Promise<string> {\n const key = await importHMACKey(secret)\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(data))\n return Array.from(new Uint8Array(sig))\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Constant-time HMAC-SHA256 verification.\n * Uses Web Crypto `verify` to avoid timing attacks.\n */\nexport async function hmacVerify(secret: string, data: string, hexSignature: string): Promise<boolean> {\n try {\n const key = await importHMACKey(secret)\n const sigBytes = hexToBytes(hexSignature)\n return await crypto.subtle.verify('HMAC', key, sigBytes, enc.encode(data))\n } catch {\n return false\n }\n}\n","// ─── Core enums ───────────────────────────────────────────────────────────────\n\nexport type PublishType = 'app' | 'ia' | 'skill' | 'eco'\nexport type EcoTarget = 'gandia' | 'handeia' | 'both'\nexport type NodeType = 'widget' | 'artefacto' | 'espacio' | 'skill' | 'agente'\nexport type Risk = 'low' | 'medium' | 'high'\nexport type Surface = 'card' | 'table' | 'text' | 'widget' | 'action' | 'data'\nexport type OutputType = Surface\n\n// ─── Gandia context ───────────────────────────────────────────────────────────\n\nexport interface GandiaTenant {\n id: string\n name: string\n sector: string\n}\n\nexport interface GandiaUser {\n id: string\n role: string\n email?: string | undefined\n}\n\n/** Context injected by GAIA on every invoke call to the developer's server. */\nexport interface GandiaContext {\n capability_id: string\n call_id: string\n tenant: GandiaTenant\n user: GandiaUser\n permissions: string[]\n trigger: 'user_query' | 'gaia_invoke' | 'event'\n /** Surface HAIA wants to render — determines which respond.* to use. */\n surface: Surface\n query?: string | undefined\n}\n\n// ─── Handeia context ──────────────────────────────────────────────────────────\n\nexport interface HandeiaUser {\n id: string\n email?: string | undefined\n name?: string | undefined\n}\n\n/** Context injected by HAIA on every invoke call to the developer's server. */\nexport interface HandeiaContext {\n capability_id: string\n call_id: string\n user: HandeiaUser\n permissions: string[]\n trigger: 'user_action' | 'haia_invoke' | 'schedule'\n /** Surface HAIA wants to render. */\n surface: Surface\n query?: string | undefined\n}\n\n// ─── JWT claims ───────────────────────────────────────────────────────────────\n\nexport interface GandiaJWTClaims {\n sub: string // user_id\n tenant_id: string\n email?: string | undefined\n role?: string | undefined\n permissions: string[]\n iat: number\n exp: number\n}\n\nexport interface HandeiaJWTClaims {\n sub: string // user_id\n email?: string | undefined\n name?: string | undefined\n permissions: string[]\n iat: number\n exp: number\n}\n\n// ─── Response payloads ────────────────────────────────────────────────────────\n\nexport interface AuditRecord {\n data_sources?: string[] | undefined\n records_accessed?: number | undefined\n [key: string]: unknown\n}\n\nexport interface RespondOpts {\n call_id?: string | undefined\n audit?: AuditRecord | undefined\n}\n\nexport interface CardPayload {\n title: string\n value?: string | number | undefined\n unit?: string | undefined\n trend?: 'up' | 'down' | 'neutral' | undefined\n icon?: string | undefined\n subtitle?: string | undefined\n color?: string | undefined\n [key: string]: unknown\n}\n\nexport interface TablePayload {\n columns: string[] | Array<{ key: string; label: string; type?: string | undefined }>\n rows: Array<Record<string, unknown>>\n total?: number | undefined\n page?: number | undefined\n per_page?: number | undefined\n}\n\nexport interface WidgetPayload {\n url: string\n height?: number | string | undefined\n width?: number | string | undefined\n meta?: Record<string, unknown> | undefined\n}\n\nexport interface ActionPayload {\n type: string\n label?: string | undefined\n params?: Record<string, unknown> | undefined\n confirm?: boolean | undefined\n destructive?: boolean | undefined\n}\n\n// ─── Typed VAIA response objects (returned by make.*) ────────────────────────\n\ninterface BaseVAIAResponse {\n ok: true\n call_id?: string | undefined\n audit?: AuditRecord | undefined\n}\n\nexport type CardResponse = BaseVAIAResponse & { output_type: 'card'; data: CardPayload }\nexport type TableResponse = BaseVAIAResponse & { output_type: 'table'; data: TablePayload }\nexport type TextResponse = BaseVAIAResponse & { output_type: 'text'; text: string; markdown?: boolean | undefined }\nexport type WidgetResponse = BaseVAIAResponse & { output_type: 'widget'; data: WidgetPayload }\nexport type ActionResponse = BaseVAIAResponse & { output_type: 'action'; data: ActionPayload }\nexport type DataResponse = BaseVAIAResponse & { output_type: 'data'; data: Record<string, unknown> }\nexport type ErrorResponse = { ok: false; error: string; code?: string | undefined }\n\nexport type VAIAResponse =\n | CardResponse\n | TableResponse\n | TextResponse\n | WidgetResponse\n | ActionResponse\n | DataResponse\n\n// ─── Surface handler map ──────────────────────────────────────────────────────\n\nexport type SurfaceHandlers = Partial<{\n card: () => CardPayload | Promise<CardPayload>\n table: () => TablePayload | Promise<TablePayload>\n text: () => string | Promise<string>\n widget: () => WidgetPayload | Promise<WidgetPayload>\n action: () => ActionPayload | Promise<ActionPayload>\n data: () => Record<string, unknown> | Promise<Record<string, unknown>>\n}>\n\n// ─── Capability definition ────────────────────────────────────────────────────\n\nexport interface SurfaceConfig {\n endpoint: string\n description?: string | undefined\n}\n\nexport interface CapabilityConfig {\n /** Unique capability ID — reverse domain: 'mx.mi-capacidad' */\n id: string\n name: string\n version: string\n /** Which VAIA platform(s) this capability targets. */\n target: EcoTarget\n type: PublishType\n level?: 'widget' | 'artefacto' | 'espacio' | undefined\n sector: string\n /** Which surfaces the capability can respond to, and their invoke endpoint. */\n surfaces: Partial<Record<Surface, SurfaceConfig>>\n permissions: string[]\n risk: Risk\n description?: string | undefined\n tags?: string[] | undefined\n /** Set to true if your app has its own login (triggers JWT bypass flow). */\n has_own_auth?: boolean | undefined\n stores_data?: boolean | undefined\n trains_models?: boolean | undefined\n requires_consent?: boolean | undefined\n}\n\n// ─── Errors ───────────────────────────────────────────────────────────────────\n\nexport class VAIAError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly status: number = 500,\n ) {\n super(message)\n this.name = 'VAIAError'\n }\n}\n","/**\n * gandia.verify — verifies an incoming invoke call from Gandia-7.\n *\n * Checks:\n * 1. X-Gandia-Signature (HMAC-SHA256 over timestamp + \".\" + raw body)\n * 2. X-Gandia-Timestamp within ±5 minutes (replay attack prevention)\n * 3. Parses and types the body as GandiaContext\n *\n * Usage:\n * const { ctx } = await verify(request, process.env.GANDIA_KEY_SECRET!)\n */\n\nimport { hmacVerify } from '../crypto.js'\nimport { VAIAError, type GandiaContext, type Surface } from '../types.js'\n\nconst REPLAY_WINDOW_MS = 5 * 60 * 1000 // 5 minutes\nconst PROBE_HEADER = 'x-gandia-probe'\n\n/** Raw body of the invoke call. Returned alongside ctx so you don't re-read the stream. */\nexport interface VerifyResult {\n ctx: GandiaContext\n raw: string\n}\n\n/**\n * Call at the top of your `/api/gandia/invoke` route handler.\n * Throws VAIAError if the signature is invalid or the timestamp is stale.\n */\nexport async function verify(request: Request, secret: string): Promise<VerifyResult> {\n const rawBody = await request.text()\n const headers = request.headers\n\n const sigHeader = headers.get('x-gandia-signature') ?? ''\n const tsHeader = headers.get('x-gandia-timestamp') ?? ''\n const callId = headers.get('x-gandia-call-id') ?? ''\n\n // Health probe from test-connection — no signature required\n if (headers.get(PROBE_HEADER) === '1') {\n return { ctx: buildProbeCtx(callId), raw: rawBody }\n }\n\n if (!sigHeader || !tsHeader) {\n throw new VAIAError(\n 'Faltan headers de autenticación (X-Gandia-Signature, X-Gandia-Timestamp)',\n 'MISSING_AUTH_HEADERS',\n 401,\n )\n }\n\n // Replay attack check\n const ts = parseInt(tsHeader, 10)\n if (isNaN(ts) || Math.abs(Date.now() - ts) > REPLAY_WINDOW_MS) {\n throw new VAIAError('Timestamp fuera de ventana (±5 min)', 'TIMESTAMP_OUT_OF_RANGE', 401)\n }\n\n // Strip \"sha256=\" prefix if present\n const hexSig = sigHeader.startsWith('sha256=') ? sigHeader.slice(7) : sigHeader\n\n // HMAC verification — constant-time via Web Crypto\n const signedData = `${tsHeader}.${rawBody}`\n const valid = await hmacVerify(secret, signedData, hexSig)\n if (!valid) {\n throw new VAIAError('Firma HMAC inválida', 'HMAC_INVALID', 401)\n }\n\n // Parse body\n let body: unknown\n try {\n body = JSON.parse(rawBody)\n } catch {\n throw new VAIAError('Body no es JSON válido', 'BODY_PARSE_ERROR', 400)\n }\n\n const ctx = parseContext(body, callId)\n return { ctx, raw: rawBody }\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction parseContext(body: unknown, fallbackCallId: string): GandiaContext {\n if (typeof body !== 'object' || body === null) {\n throw new VAIAError('Body inválido', 'BODY_INVALID', 400)\n }\n\n const b = body as Record<string, unknown>\n\n return {\n capability_id: str(b, 'capability_id'),\n call_id: str(b, 'call_id', fallbackCallId),\n tenant: {\n id: nestedStr(b, 'tenant', 'id'),\n name: nestedStr(b, 'tenant', 'name'),\n sector: nestedStr(b, 'tenant', 'sector'),\n },\n user: {\n id: nestedStr(b, 'user', 'id'),\n role: nestedStr(b, 'user', 'role'),\n email: nestedStrOpt(b, 'user', 'email'),\n },\n permissions: arr(b, 'permissions'),\n trigger: str(b, 'context.trigger', 'gaia_invoke') as GandiaContext['trigger'],\n surface: str(b, 'context.surface', 'data') as Surface,\n query: nestedStrOpt(b, 'context', 'query'),\n }\n}\n\nfunction buildProbeCtx(callId: string): GandiaContext {\n return {\n capability_id: '__probe__',\n call_id: callId || crypto.randomUUID(),\n tenant: { id: '__probe__', name: '__probe__', sector: '__probe__' },\n user: { id: '__probe__', role: '__probe__' },\n permissions: [],\n trigger: 'gaia_invoke',\n surface: 'data',\n }\n}\n\nfunction str(obj: Record<string, unknown>, key: string, fallback = ''): string {\n // Support dot notation: 'context.trigger'\n const parts = key.split('.')\n let cur: unknown = obj\n for (const part of parts) {\n if (typeof cur !== 'object' || cur === null) return fallback\n cur = (cur as Record<string, unknown>)[part]\n }\n return typeof cur === 'string' ? cur : fallback\n}\n\nfunction nestedStr(\n obj: Record<string, unknown>,\n parent: string,\n key: string,\n fallback = '',\n): string {\n const p = obj[parent]\n if (typeof p !== 'object' || p === null) return fallback\n const v = (p as Record<string, unknown>)[key]\n return typeof v === 'string' ? v : fallback\n}\n\nfunction nestedStrOpt(\n obj: Record<string, unknown>,\n parent: string,\n key: string,\n): string | undefined {\n const p = obj[parent]\n if (typeof p !== 'object' || p === null) return undefined\n const v = (p as Record<string, unknown>)[key]\n return typeof v === 'string' ? v : undefined\n}\n\nfunction arr(obj: Record<string, unknown>, key: string): string[] {\n const v = obj[key]\n if (!Array.isArray(v)) return []\n return v.filter((x): x is string => typeof x === 'string')\n}\n\n/** Quick check — use before calling verify() if you want to short-circuit probes. */\nexport function isProbe(request: Request): boolean {\n return request.headers.get(PROBE_HEADER) === '1'\n}\n","/**\n * gandia.jwt — JWT helpers for iframe auth bypass.\n *\n * When Gandia-7 opens a developer's app as an iframe, it appends:\n * ?gandia_token=<signed_jwt>\n *\n * The developer verifies the token, extracts the user/tenant claims,\n * and creates a session — skipping their own login page.\n *\n * Usage (server-side):\n * const claims = await gandia.jwt.verify(token, process.env.GANDIA_KEY_SECRET!)\n * // → { sub, tenant_id, email, role, permissions, exp, iat }\n *\n * Usage (VAIA-side, when generating tokens for developer iframes):\n * const token = await gandia.jwt.sign({ sub: userId, tenant_id, ... }, secret, { expiresIn: 3600 })\n */\n\nimport { jwtSign, jwtVerify } from '../jwt-utils.js'\nimport type { GandiaJWTClaims } from '../types.js'\n\nexport interface GandiaJWTSignInput {\n sub: string // user_id\n tenant_id: string\n email?: string | undefined\n role?: string | undefined\n permissions?: string[] | undefined\n}\n\nexport interface SignOpts {\n /** Seconds until expiry. Default: 3600 (1 hour). */\n expiresIn?: number | undefined\n}\n\nconst DEFAULT_EXPIRES_IN = 3600\n\n/** Signs a new Gandia iframe JWT. Typically called by Gandia-7, not by the developer. */\nexport async function sign(\n input: GandiaJWTSignInput,\n secret: string,\n opts: SignOpts = {},\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n return jwtSign(\n {\n ...input,\n permissions: input.permissions ?? [],\n iat: now,\n exp: now + (opts.expiresIn ?? DEFAULT_EXPIRES_IN),\n },\n secret,\n )\n}\n\n/** Verifies a Gandia iframe JWT and returns its claims. Throws VAIAError on failure. */\nexport async function verify(token: string, secret: string): Promise<GandiaJWTClaims> {\n return jwtVerify<GandiaJWTClaims>(token, secret)\n}\n\n/**\n * Extracts `gandia_token` from a URL and verifies it.\n * Convenience for iframe entry-point routes.\n *\n * const claims = await gandia.jwt.fromUrl(request.url, secret)\n */\nexport async function fromUrl(url: string | URL, secret: string): Promise<GandiaJWTClaims> {\n const u = typeof url === 'string' ? new URL(url) : url\n const token = u.searchParams.get('gandia_token')\n if (!token) {\n throw new Error('gandia_token no encontrado en la URL')\n }\n return verify(token, secret)\n}\n","/**\n * Minimal HS256 JWT implementation using Web Crypto.\n * No third-party dependencies.\n *\n * CONTRATO DE CODIFICACIÓN (v2)\n * -----------------------------\n * El payload se serializa en UTF-8, como exige RFC 7519 §3. Esto importa\n * porque el token cruza fronteras de lenguaje: lo firma Gandia (TS), lo\n * verifica Nexus (TS) y lo reenvía a ACIPE (Python) — cualquier consumidor\n * que use una librería JWT estándar debe poder leerlo.\n *\n * Antes de v2 se usaba btoa()/atob(), que tratan cada carácter como UN byte\n * (latin1). Dos consecuencias:\n * - Caracteres 128..255 (é, Ñ) salían mal para cualquier lector estándar.\n * Entre piezas del propio SDK no se notaba, porque el error era simétrico.\n * - Caracteres >255 (CJK, emoji, U+FFFD) hacían LANZAR a btoa(), tumbando\n * la firma. Un estudiante con la Ñ corrupta en el nombre no pudo entrar a\n * su Espacio por esto, y el error salió reportado como \"servicio caído\".\n *\n * MIGRACIÓN: jwtVerify lee ambos formatos. Los tokens nuevos llevan el claim\n * `v: 2`; su ausencia significa v1 (latin1) y se decodifica como tal. Así la\n * transición no invalida ningún token en vuelo — ver CHANGELOG.\n */\n\nimport { VAIAError } from './types.js'\n\nconst enc = new TextEncoder()\n/** fatal:true = si los bytes no son UTF-8 válido, lanza en vez de meter U+FFFD\n * en silencio. Es justo ese \"en silencio\" el que escondió el bug original. */\nconst utf8Strict = new TextDecoder('utf-8', { fatal: true })\nconst utf8Loose = new TextDecoder('utf-8')\nconst latin1 = new TextDecoder('latin1')\n\n/** Versión del formato de payload. Los tokens la llevan como claim `v`. */\nexport const JWT_PAYLOAD_VERSION = 2\n\n// ── base64url ───────────────────────────────────────────────────────────────\n// Se separan bytes y texto a propósito. Tener UNA función para ambos fue la\n// causa de raíz: la firma (bytes crudos) y el payload (texto) necesitan\n// tratamientos distintos, y compartirlos forzó latin1 sobre el texto.\n\nfunction bytesToB64url(bytes: Uint8Array): string {\n // Se arma por trozos en vez de String.fromCharCode(...bytes): el spread de\n // un arreglo grande revienta la pila de llamadas.\n let bin = ''\n const CHUNK = 0x8000\n for (let i = 0; i < bytes.length; i += CHUNK) {\n bin += String.fromCharCode(...bytes.subarray(i, i + CHUNK))\n }\n return btoa(bin).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '')\n}\n\n// El ArrayBuffer se crea explícito para que el tipo sea Uint8Array<ArrayBuffer>\n// y no Uint8Array<ArrayBufferLike>: Web Crypto no acepta buffers compartidos.\nfunction b64urlToBytes(str: string): Uint8Array<ArrayBuffer> {\n const padded = str.replace(/-/g, '+').replace(/_/g, '/')\n const pad = padded.length % 4\n const bin = atob(pad ? padded + '='.repeat(4 - pad) : padded)\n const out = new Uint8Array(new ArrayBuffer(bin.length))\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)\n return out\n}\n\n/** Texto → base64url en UTF-8. Nunca lanza, sea cual sea el carácter. */\nfunction textToB64url(text: string): string {\n return bytesToB64url(enc.encode(text))\n}\n\nasync function importHMACKey(secret: string): Promise<CryptoKey> {\n return crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign', 'verify'],\n )\n}\n\nconst HEADER = textToB64url(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))\n\n/** Creates a signed HS256 JWT. */\nexport async function jwtSign(\n payload: Record<string, unknown>,\n secret: string,\n): Promise<string> {\n const body = textToB64url(JSON.stringify({ ...payload, v: JWT_PAYLOAD_VERSION }))\n const unsigned = `${HEADER}.${body}`\n const key = await importHMACKey(secret)\n const sig = await crypto.subtle.sign('HMAC', key, enc.encode(unsigned))\n return `${unsigned}.${bytesToB64url(new Uint8Array(sig))}`\n}\n\n/**\n * Decodifica el payload aceptando ambos formatos (lector tolerante).\n *\n * Se lee primero en latin1 —que nunca lanza— solo para poder mirar el claim\n * `v` y decidir. Las llaves y la estructura del JSON son ASCII, así que\n * sobreviven a cualquiera de las dos lecturas; lo único que puede verse mal\n * en ese primer paso son los valores, y ese texto se descarta si resulta v2.\n */\nfunction decodePayload(body: string): Record<string, unknown> {\n const bytes = b64urlToBytes(body)\n\n let sonda: Record<string, unknown>\n try {\n sonda = JSON.parse(latin1.decode(bytes)) as Record<string, unknown>\n } catch {\n throw new VAIAError('JWT payload inválido', 'JWT_PAYLOAD_INVALID', 401)\n }\n\n const version = typeof sonda['v'] === 'number' ? (sonda['v'] as number) : 1\n if (version < 2) return sonda // v1: latin1 era el formato correcto entonces\n\n try {\n return JSON.parse(utf8Strict.decode(bytes)) as Record<string, unknown>\n } catch {\n // Marcado como v2 pero los bytes no son UTF-8 válido: se degrada a una\n // lectura permisiva antes que rechazarle el acceso a un usuario real.\n try {\n return JSON.parse(utf8Loose.decode(bytes)) as Record<string, unknown>\n } catch {\n throw new VAIAError('JWT payload inválido', 'JWT_PAYLOAD_INVALID', 401)\n }\n }\n}\n\n/** Verifies an HS256 JWT and returns its payload. Throws VAIAError on failure. */\nexport async function jwtVerify<T extends object>(\n token: string,\n secret: string,\n): Promise<T> {\n const parts = token.split('.')\n if (parts.length !== 3) {\n throw new VAIAError('JWT malformado', 'JWT_MALFORMED', 401)\n }\n\n const [header, body, sig] = parts as [string, string, string]\n const unsigned = `${header}.${body}`\n\n // La firma se valida SIEMPRE antes de tocar el payload: nada de lo que venga\n // dentro debe influir en cómo se decide verificarlo.\n const key = await importHMACKey(secret)\n let valid: boolean\n try {\n valid = await crypto.subtle.verify('HMAC', key, b64urlToBytes(sig), enc.encode(unsigned))\n } catch {\n throw new VAIAError('JWT malformado', 'JWT_MALFORMED', 401)\n }\n\n if (!valid) {\n throw new VAIAError('Firma JWT inválida', 'JWT_SIGNATURE_INVALID', 401)\n }\n\n const payload = decodePayload(body) as T & { exp?: number; iat?: number }\n\n if (typeof payload.exp === 'number' && Date.now() / 1000 > payload.exp) {\n throw new VAIAError('JWT expirado', 'JWT_EXPIRED', 401)\n }\n\n return payload as T\n}\n","/**\n * gandia.respond — typed response builders.\n *\n * Each method returns a Web API Response with the correct VAIA envelope.\n * HAIA reads `output_type` to decide how to render the result.\n *\n * For non-Response frameworks (Express, Fastify), use gandia.make.* instead.\n *\n * Usage:\n * // Returns Web API Response\n * return gandia.respond.card({ title: 'Riesgo', value: 72, unit: '%' })\n *\n * // Multi-surface: GAIA tells you which surface it wants via ctx.surface\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Riesgo', value: 72 }),\n * table: () => ({ columns: ['alumno', 'score'], rows }),\n * text: () => `El riesgo del grupo es ${risk}%`,\n * })\n */\n\nimport type {\n CardPayload,\n TablePayload,\n WidgetPayload,\n ActionPayload,\n RespondOpts,\n Surface,\n SurfaceHandlers,\n VAIAResponse,\n CardResponse,\n TableResponse,\n TextResponse,\n WidgetResponse,\n ActionResponse,\n DataResponse,\n} from '../types.js'\nimport { VAIAError } from '../types.js'\n\n// ─── JSON helpers ─────────────────────────────────────────────────────────────\n\nconst JSON_HEADERS = { 'Content-Type': 'application/json' }\n\nfunction toResponse(body: VAIAResponse | { ok: false; error: string }, status = 200): Response {\n return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS })\n}\n\n// ─── make.* — plain objects (framework-agnostic) ─────────────────────────────\n\nexport const make = {\n card(payload: CardPayload, opts: RespondOpts = {}): CardResponse {\n return { ok: true, output_type: 'card', data: payload, ...opts }\n },\n\n table(payload: TablePayload, opts: RespondOpts = {}): TableResponse {\n return { ok: true, output_type: 'table', data: payload, ...opts }\n },\n\n text(content: string, opts: RespondOpts & { markdown?: boolean } = {}): TextResponse {\n const { markdown, ...rest } = opts\n return { ok: true, output_type: 'text', text: content, markdown, ...rest }\n },\n\n widget(payload: WidgetPayload, opts: RespondOpts = {}): WidgetResponse {\n return { ok: true, output_type: 'widget', data: payload, ...opts }\n },\n\n action(payload: ActionPayload, opts: RespondOpts = {}): ActionResponse {\n return { ok: true, output_type: 'action', data: payload, ...opts }\n },\n\n data(payload: Record<string, unknown>, opts: RespondOpts = {}): DataResponse {\n return { ok: true, output_type: 'data', data: payload, ...opts }\n },\n} as const\n\n// ─── respond.* — Web API Response ────────────────────────────────────────────\n\nexport const respond = {\n /** A compact card: title, value, unit, trend, etc. */\n card(payload: CardPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.card(payload, opts))\n },\n\n /** Tabular data with columns + rows. */\n table(payload: TablePayload, opts: RespondOpts = {}): Response {\n return toResponse(make.table(payload, opts))\n },\n\n /** Plain text or markdown — shown in chat or narrative views. */\n text(content: string, opts: RespondOpts & { markdown?: boolean } = {}): Response {\n return toResponse(make.text(content, opts))\n },\n\n /** An iframe pointing to the developer's own UI. */\n widget(payload: WidgetPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.widget(payload, opts))\n },\n\n /** Trigger an action (mutation, navigation, confirm dialog). */\n action(payload: ActionPayload, opts: RespondOpts = {}): Response {\n return toResponse(make.action(payload, opts))\n },\n\n /** Arbitrary JSON — HAIA decides how to render based on shape. */\n data(payload: Record<string, unknown>, opts: RespondOpts = {}): Response {\n return toResponse(make.data(payload, opts))\n },\n\n /** Simple 200 OK — useful for probe responses. */\n ok(opts: RespondOpts = {}): Response {\n return toResponse(make.data({ status: 'ok' }, opts))\n },\n\n /** Returns a 4xx/5xx error response. */\n error(message: string, status = 500, code?: string): Response {\n return toResponse({ ok: false, error: message, ...(code ? { code } : {}) }, status)\n },\n\n /**\n * Multi-surface responder.\n * GAIA sends `ctx.surface` telling you what to render.\n * Map each surface to its handler and this picks the right one.\n *\n * return gandia.respond.surface(ctx.surface, {\n * card: () => ({ title: 'Riesgo', value: 72, unit: '%' }),\n * table: () => ({ columns: [...], rows: [...] }),\n * text: () => `El riesgo es 72%`,\n * }, opts)\n */\n async surface(\n surface: Surface,\n handlers: SurfaceHandlers,\n opts: RespondOpts = {},\n ): Promise<Response> {\n const handler = handlers[surface]\n\n if (!handler) {\n // Fallback cascade: data > text > first available handler\n const fallback =\n handlers.data ?? handlers.text ?? Object.values(handlers).find(Boolean)\n if (!fallback) {\n throw new VAIAError(\n `Surface '${surface}' no soportada por esta capacidad`,\n 'SURFACE_NOT_SUPPORTED',\n 422,\n )\n }\n return respond.surface(\n handlers.data ? 'data' : handlers.text ? 'text' : (Object.keys(handlers)[0] as Surface),\n handlers,\n opts,\n )\n }\n\n switch (surface) {\n case 'card': return respond.card(await (handlers.card!)(), opts)\n case 'table': return respond.table(await (handlers.table!)(), opts)\n case 'text': return respond.text(await (handlers.text!)(), opts)\n case 'widget': return respond.widget(await (handlers.widget!)(), opts)\n case 'action': return respond.action(await (handlers.action!)(), opts)\n case 'data': return respond.data(await (handlers.data!)(), opts)\n default: return respond.data(await (handlers.data ?? handlers.text ?? (() => ({})))(), opts)\n }\n },\n} as const\n","/**\n * gandia.can / gandia.require — permission helpers.\n *\n * Usage:\n * if (!gandia.can(ctx, 'read:students')) return gandia.respond.error('Forbidden', 403)\n * gandia.require(ctx, 'write:alerts') // throws VAIAError 403 if missing\n *\n * Supports wildcard scopes:\n * 'read:*' — matches all read permissions\n * 'read:students' — exact match\n */\n\nimport { VAIAError, type GandiaContext } from '../types.js'\n\nfunction matches(permission: string, granted: string[]): boolean {\n if (granted.includes(permission)) return true\n // wildcard: 'read:*' grants 'read:students'\n const [action] = permission.split(':')\n return granted.includes(`${action}:*`)\n}\n\n/** Returns true if the context has the given permission. */\nexport function can(ctx: Pick<GandiaContext, 'permissions'>, permission: string): boolean {\n return matches(permission, ctx.permissions)\n}\n\n/** Returns true if the context has ALL listed permissions. */\nexport function canAll(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): boolean {\n return permissions.every(p => matches(p, ctx.permissions))\n}\n\n/** Returns true if the context has ANY of the listed permissions. */\nexport function canAny(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): boolean {\n return permissions.some(p => matches(p, ctx.permissions))\n}\n\n/** Throws VAIAError 403 if the context does NOT have the given permission. */\nexport function require(ctx: Pick<GandiaContext, 'permissions'>, permission: string): void {\n if (!matches(permission, ctx.permissions)) {\n throw new VAIAError(\n `Permiso requerido: ${permission}`,\n 'PERMISSION_DENIED',\n 403,\n )\n }\n}\n\n/** Throws VAIAError 403 if the context does NOT have ALL listed permissions. */\nexport function requireAll(ctx: Pick<GandiaContext, 'permissions'>, ...permissions: string[]): void {\n const missing = permissions.filter(p => !matches(p, ctx.permissions))\n if (missing.length > 0) {\n throw new VAIAError(\n `Permisos requeridos: ${missing.join(', ')}`,\n 'PERMISSION_DENIED',\n 403,\n )\n }\n}\n","/**\n * handeia — integration namespace for Handeia (personal platform).\n *\n * Quick start:\n * import { handeia } from '@vaia/sdk'\n *\n * export async function POST(req: Request) {\n * try {\n * const { ctx } = await handeia.verify(req, process.env.HANDEIA_KEY_SECRET!)\n * const profile = await myDb.getProfile(ctx.user.id)\n * return handeia.respond.surface(ctx.surface, {\n * card: () => ({ title: profile.name, subtitle: profile.role }),\n * text: () => `Hola ${profile.name}`,\n * })\n * } catch (err) {\n * if (err instanceof VAIAError) return handeia.respond.error(err.message, err.status)\n * throw err\n * }\n * }\n */\n\nexport { verify, isProbe, type HandeiaVerifyResult } from './verify.js'\nexport * as jwt from './jwt.js'\n\n// handeia shares the same respond/make API as gandia\nexport { respond, make } from '../gandia/respond.js'\n\n// Permission helpers (work the same — ctx.permissions is always a string[])\nexport { can, canAll, canAny, require, requireAll } from '../gandia/permissions.js'\n","/**\n * handeia.verify — verifies an incoming invoke call from Handeia.\n * Same HMAC protocol as gandia.verify but with Handeia-specific headers\n * and a HandeiaContext (user personal, no tenant).\n */\n\nimport { hmacVerify } from '../crypto.js'\nimport { VAIAError, type HandeiaContext, type Surface } from '../types.js'\n\nconst REPLAY_WINDOW_MS = 5 * 60 * 1000\nconst PROBE_HEADER = 'x-handeia-probe'\n\nexport interface HandeiaVerifyResult {\n ctx: HandeiaContext\n raw: string\n}\n\n/**\n * Call at the top of your `/api/handeia/invoke` route handler.\n * Throws VAIAError if the signature is invalid or the timestamp is stale.\n */\nexport async function verify(request: Request, secret: string): Promise<HandeiaVerifyResult> {\n const rawBody = await request.text()\n const headers = request.headers\n\n const sigHeader = headers.get('x-handeia-signature') ?? ''\n const tsHeader = headers.get('x-handeia-timestamp') ?? ''\n const callId = headers.get('x-handeia-call-id') ?? ''\n\n if (headers.get(PROBE_HEADER) === '1') {\n return { ctx: buildProbeCtx(callId), raw: rawBody }\n }\n\n if (!sigHeader || !tsHeader) {\n throw new VAIAError(\n 'Faltan headers de autenticación (X-Handeia-Signature, X-Handeia-Timestamp)',\n 'MISSING_AUTH_HEADERS',\n 401,\n )\n }\n\n const ts = parseInt(tsHeader, 10)\n if (isNaN(ts) || Math.abs(Date.now() - ts) > REPLAY_WINDOW_MS) {\n throw new VAIAError('Timestamp fuera de ventana (±5 min)', 'TIMESTAMP_OUT_OF_RANGE', 401)\n }\n\n const hexSig = sigHeader.startsWith('sha256=') ? sigHeader.slice(7) : sigHeader\n const signedData = `${tsHeader}.${rawBody}`\n const valid = await hmacVerify(secret, signedData, hexSig)\n\n if (!valid) {\n throw new VAIAError('Firma HMAC inválida', 'HMAC_INVALID', 401)\n }\n\n let body: unknown\n try {\n body = JSON.parse(rawBody)\n } catch {\n throw new VAIAError('Body no es JSON válido', 'BODY_PARSE_ERROR', 400)\n }\n\n const ctx = parseContext(body, callId)\n return { ctx, raw: rawBody }\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction parseContext(body: unknown, fallbackCallId: string): HandeiaContext {\n if (typeof body !== 'object' || body === null) {\n throw new VAIAError('Body inválido', 'BODY_INVALID', 400)\n }\n\n const b = body as Record<string, unknown>\n const user = (b['user'] ?? {}) as Record<string, unknown>\n const ctx = (b['context'] ?? {}) as Record<string, unknown>\n\n return {\n capability_id: s(b['capability_id']),\n call_id: s(b['call_id'], fallbackCallId),\n user: {\n id: s(user['id']),\n email: sOpt(user['email']),\n name: sOpt(user['name']),\n },\n permissions: arr(b['permissions']),\n trigger: s(ctx['trigger'], 'haia_invoke') as HandeiaContext['trigger'],\n surface: s(ctx['surface'], 'data') as Surface,\n query: sOpt(ctx['query']),\n }\n}\n\nfunction buildProbeCtx(callId: string): HandeiaContext {\n return {\n capability_id: '__probe__',\n call_id: callId || crypto.randomUUID(),\n user: { id: '__probe__' },\n permissions: [],\n trigger: 'haia_invoke',\n surface: 'data',\n }\n}\n\nfunction s(v: unknown, fallback = ''): string {\n return typeof v === 'string' ? v : fallback\n}\nfunction sOpt(v: unknown): string | undefined {\n return typeof v === 'string' ? v : undefined\n}\nfunction arr(v: unknown): string[] {\n return Array.isArray(v) ? v.filter((x): x is string => typeof x === 'string') : []\n}\n\nexport function isProbe(request: Request): boolean {\n return request.headers.get(PROBE_HEADER) === '1'\n}\n","/**\n * handeia.jwt — JWT helpers for Handeia iframe auth bypass.\n * Same pattern as gandia.jwt but for personal context (no tenant).\n */\n\nimport { jwtSign, jwtVerify } from '../jwt-utils.js'\nimport type { HandeiaJWTClaims } from '../types.js'\n\nexport interface HandeiaJWTSignInput {\n sub: string // user_id\n email?: string | undefined\n name?: string | undefined\n permissions?: string[] | undefined\n}\n\nexport interface SignOpts {\n expiresIn?: number | undefined\n}\n\nconst DEFAULT_EXPIRES_IN = 3600\n\nexport async function sign(\n input: HandeiaJWTSignInput,\n secret: string,\n opts: SignOpts = {},\n): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n return jwtSign(\n {\n ...input,\n permissions: input.permissions ?? [],\n iat: now,\n exp: now + (opts.expiresIn ?? DEFAULT_EXPIRES_IN),\n },\n secret,\n )\n}\n\nexport async function verify(token: string, secret: string): Promise<HandeiaJWTClaims> {\n return jwtVerify<HandeiaJWTClaims>(token, secret)\n}\n\n/** Extracts and verifies `handeia_token` from a URL. */\nexport async function fromUrl(url: string | URL, secret: string): Promise<HandeiaJWTClaims> {\n const u = typeof url === 'string' ? new URL(url) : url\n const token = u.searchParams.get('handeia_token')\n if (!token) throw new Error('handeia_token no encontrado en la URL')\n return verify(token, secret)\n}\n","/**\n * defineCapability — declares a VAIA capability in code.\n *\n * This is both a type-safety layer (catches config errors at compile time)\n * and the source of truth for `npx vaia manifest` (generates gandia.manifest.json).\n *\n * The Shazam engine detects `defineCapability` in your code and reads the\n * config with 100% confidence — no manual confirmation needed in the portal.\n *\n * Usage (vaia.config.ts in project root):\n * import { defineCapability } from '@vaia/sdk'\n *\n * export default defineCapability({\n * id: 'mx.monitor-riesgo-academico',\n * name: 'Monitor de Riesgo Académico',\n * version: '1.0.0',\n * target: 'gandia',\n * type: 'app',\n * level: 'artefacto',\n * sector: 'educacion',\n * surfaces: {\n * card: { endpoint: '/api/gandia/invoke' },\n * table: { endpoint: '/api/gandia/invoke' },\n * text: { endpoint: '/api/gandia/invoke' },\n * },\n * permissions: ['read:students', 'read:grades', 'write:alerts'],\n * risk: 'medium',\n * })\n */\n\nimport type { CapabilityConfig, EcoTarget, Risk, Surface } from './types.js'\n\nexport type { CapabilityConfig }\n\nexport interface VAIAManifest {\n schema: '1.0'\n capability_id: string\n name: string\n version: string\n target: EcoTarget | EcoTarget[]\n type: string\n level?: string | undefined\n sector: string\n surfaces: string[]\n permissions: string[]\n risk: Risk\n has_own_auth: boolean\n stores_data: boolean\n trains_models: boolean\n requires_consent: boolean\n description?: string | undefined\n tags?: string[] | undefined\n linked: boolean\n generated_by: '@vaia/sdk'\n generated_at: string\n}\n\n/** Validates and returns the capability config. Throws if required fields are missing. */\nexport function defineCapability(config: CapabilityConfig): CapabilityConfig {\n const required: Array<keyof CapabilityConfig> = ['id', 'name', 'version', 'target', 'type', 'sector', 'permissions', 'risk']\n for (const key of required) {\n if (config[key] === undefined || config[key] === '') {\n throw new Error(`[@vaia/sdk] defineCapability: campo requerido faltante: '${key}'`)\n }\n }\n\n if (!config.id.includes('.')) {\n throw new Error(\n `[@vaia/sdk] defineCapability: 'id' debe usar formato reverse-domain (ej. 'mx.mi-capacidad'). Recibido: '${config.id}'`,\n )\n }\n\n if (Object.keys(config.surfaces).length === 0) {\n throw new Error(`[@vaia/sdk] defineCapability: 'surfaces' no puede estar vacío. Define al menos un surface con su endpoint.`)\n }\n\n return config\n}\n\n/** Converts a CapabilityConfig to a gandia.manifest.json object. */\nexport function toManifest(config: CapabilityConfig): VAIAManifest {\n const surfaces = Object.keys(config.surfaces) as Surface[]\n\n return {\n schema: '1.0',\n capability_id: config.id,\n name: config.name,\n version: config.version,\n target: config.target === 'both' ? ['gandia', 'handeia'] : config.target,\n type: config.type,\n level: config.level,\n sector: config.sector,\n surfaces,\n permissions: config.permissions,\n risk: config.risk,\n has_own_auth: config.has_own_auth ?? false,\n stores_data: config.stores_data ?? false,\n trains_models: config.trains_models ?? false,\n requires_consent: config.requires_consent ?? false,\n description: config.description,\n tags: config.tags,\n linked: config.target === 'both',\n generated_by: '@vaia/sdk',\n generated_at: new Date().toISOString(),\n }\n}\n","/**\n * @vaia/sdk — VAIA Platform Integration SDK\n *\n * Provides two namespaces:\n * gandia → Gandia-7 (institutional platform)\n * handeia → Handeia (personal platform)\n *\n * Quick start:\n * import { gandia, handeia, defineCapability, VAIAError } from '@vaia/sdk'\n */\n\n// ─── Platform namespaces ──────────────────────────────────────────────────────\n\nimport * as _gandia from './gandia/index.js'\nimport * as _handeia from './handeia/index.js'\n\nexport const gandia = _gandia\nexport const handeia = _handeia\n\n// ─── defineCapability + manifest ─────────────────────────────────────────────\n\nexport { defineCapability, toManifest } from './define.js'\nexport type { CapabilityConfig, VAIAManifest } from './define.js'\n\n// ─── Shared error class ───────────────────────────────────────────────────────\n\nexport { VAIAError } from './types.js'\n\n// ─── All types (re-exported for consumer convenience) ─────────────────────────\n\nexport type {\n // Core enums\n PublishType,\n EcoTarget,\n NodeType,\n Risk,\n Surface,\n OutputType,\n\n // Contexts\n GandiaContext,\n GandiaTenant,\n GandiaUser,\n HandeiaContext,\n HandeiaUser,\n\n // JWT claims\n GandiaJWTClaims,\n HandeiaJWTClaims,\n\n // Response payloads\n CardPayload,\n TablePayload,\n WidgetPayload,\n ActionPayload,\n AuditRecord,\n RespondOpts,\n SurfaceHandlers,\n\n // Response types\n VAIAResponse,\n CardResponse,\n TableResponse,\n TextResponse,\n WidgetResponse,\n ActionResponse,\n DataResponse,\n ErrorResponse,\n} from './types.js'\n"],"mappings":"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","names":["require","verify","enc","str","importHMACKey","verify","require","isProbe","jwt_exports","require","verify","REPLAY_WINDOW_MS","PROBE_HEADER","verify","buildProbeCtx","parseContext","arr","isProbe","jwt_exports","fromUrl","sign","verify","DEFAULT_EXPIRES_IN","sign","verify","fromUrl"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaia-lab/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "VAIA SDK — platform integration for Gandia-7 and Handeia developers",
|
|
5
5
|
"author": "VAIA <hello@vaia.dev>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,16 +21,18 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"bin": {
|
|
24
|
-
"vaia-sdk": "
|
|
24
|
+
"vaia-sdk": "dist/cli.js"
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
27
|
"dist",
|
|
28
28
|
"README.md"
|
|
29
29
|
],
|
|
30
30
|
"scripts": {
|
|
31
|
-
"build": "tsup",
|
|
31
|
+
"build": "tsup && chmod +x dist/cli.js",
|
|
32
32
|
"dev": "tsup --watch",
|
|
33
|
-
"typecheck": "tsc --noEmit"
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"test": "npm run build && node --test test/*.test.js",
|
|
35
|
+
"prepublishOnly": "npm test"
|
|
34
36
|
},
|
|
35
37
|
"engines": {
|
|
36
38
|
"node": ">=18"
|