veo-sdk 0.2.1 → 0.3.2
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/README.md +36 -0
- package/dist/builder-AGIBF67L.mjs +5 -0
- package/dist/builder-AGIBF67L.mjs.map +1 -0
- package/dist/builder.cjs +161 -20
- package/dist/builder.cjs.map +1 -1
- package/dist/builder.d.cts +23 -5
- package/dist/builder.d.ts +23 -5
- package/dist/builder.mjs +5 -444
- package/dist/builder.mjs.map +1 -1
- package/dist/chunk-7FVIFPGF.mjs +531 -0
- package/dist/chunk-7FVIFPGF.mjs.map +1 -0
- package/dist/{chunk-BBAA5BRS.mjs → chunk-GHP7ZJCW.mjs} +61 -1042
- package/dist/chunk-GHP7ZJCW.mjs.map +1 -0
- package/dist/chunk-PTG3BTJE.mjs +10 -0
- package/dist/chunk-PTG3BTJE.mjs.map +1 -0
- package/dist/chunk-R4E3LIDB.mjs +1042 -0
- package/dist/chunk-R4E3LIDB.mjs.map +1 -0
- package/dist/index.cjs +3452 -2590
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +50 -48
- package/dist/index.mjs.map +1 -1
- package/dist/next.cjs +90 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +108 -0
- package/dist/next.d.ts +108 -0
- package/dist/next.mjs +82 -0
- package/dist/next.mjs.map +1 -0
- package/dist/veo-builder.js +31 -6
- package/dist/veo-builder.js.map +1 -1
- package/dist/veo.js +2 -2
- package/dist/veo.js.map +1 -1
- package/package.json +6 -1
- package/dist/chunk-BBAA5BRS.mjs.map +0 -1
package/dist/next.cjs
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/core/builder-constants.ts
|
|
4
|
+
var BUILDER_TOKEN_PARAM = "veoBuilder";
|
|
5
|
+
var BUILDER_ORIGIN_PARAM = "veoBuilderOrigin";
|
|
6
|
+
|
|
7
|
+
// src/next.ts
|
|
8
|
+
var VEO_BUILDER_COOKIE = "veo-builder";
|
|
9
|
+
var VEO_BUILDER_ORIGIN_COOKIE = "veo-builder-origin";
|
|
10
|
+
function readVeoBuilderContext(request) {
|
|
11
|
+
const params = request.nextUrl.searchParams;
|
|
12
|
+
const fromParam = params.get(BUILDER_TOKEN_PARAM);
|
|
13
|
+
if (fromParam) {
|
|
14
|
+
return {
|
|
15
|
+
token: fromParam,
|
|
16
|
+
origin: params.get(BUILDER_ORIGIN_PARAM) ?? request.cookies.get(VEO_BUILDER_ORIGIN_COOKIE)?.value ?? null
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const fromCookie = request.cookies.get(VEO_BUILDER_COOKIE)?.value;
|
|
20
|
+
if (fromCookie) {
|
|
21
|
+
return {
|
|
22
|
+
token: fromCookie,
|
|
23
|
+
origin: request.cookies.get(VEO_BUILDER_ORIGIN_COOKIE)?.value ?? null
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
async function ensureVeoDesignSession(builder, auth, options = {}) {
|
|
29
|
+
if (!builder) return;
|
|
30
|
+
const email = options.email ?? readEnv("VEO_BUILDER_DEMO_EMAIL");
|
|
31
|
+
const password = options.password ?? readEnv("VEO_BUILDER_DEMO_PASSWORD");
|
|
32
|
+
if (!email || !password) return;
|
|
33
|
+
const {
|
|
34
|
+
data: { user }
|
|
35
|
+
} = await auth.getUser();
|
|
36
|
+
if (!user) await auth.signInWithPassword({ email, password });
|
|
37
|
+
}
|
|
38
|
+
function readEnv(key) {
|
|
39
|
+
try {
|
|
40
|
+
return typeof process !== "undefined" ? process.env?.[key] : void 0;
|
|
41
|
+
} catch {
|
|
42
|
+
return void 0;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function veoBuilderProxy(handler, options = {}) {
|
|
46
|
+
return async (request) => {
|
|
47
|
+
const builder = readVeoBuilderContext(request);
|
|
48
|
+
const response = await handler(request, { builder });
|
|
49
|
+
if (builder) {
|
|
50
|
+
repartitionCookies(response);
|
|
51
|
+
persistBuilderCookies(response, builder, options.cookieMaxAge ?? 1800);
|
|
52
|
+
applyFramingHeaders(response, builder, options.dashboardOrigins);
|
|
53
|
+
}
|
|
54
|
+
return response;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function repartitionCookies(response) {
|
|
58
|
+
for (const cookie of response.cookies.getAll()) {
|
|
59
|
+
response.cookies.set({ ...cookie, sameSite: "none", secure: true, partitioned: true });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function persistBuilderCookies(response, ctx, maxAge) {
|
|
63
|
+
const base = { path: "/", maxAge, sameSite: "none", secure: true, partitioned: true };
|
|
64
|
+
response.cookies.set({ name: VEO_BUILDER_COOKIE, value: ctx.token, httpOnly: true, ...base });
|
|
65
|
+
if (ctx.origin) {
|
|
66
|
+
response.cookies.set({
|
|
67
|
+
name: VEO_BUILDER_ORIGIN_COOKIE,
|
|
68
|
+
value: ctx.origin,
|
|
69
|
+
httpOnly: false,
|
|
70
|
+
...base
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function applyFramingHeaders(response, ctx, dashboardOrigins) {
|
|
75
|
+
const configured = (dashboardOrigins ?? []).map((s) => s.trim()).filter(Boolean);
|
|
76
|
+
const origins = configured.length > 0 ? configured : ctx.origin ? [ctx.origin] : [];
|
|
77
|
+
response.headers.delete("X-Frame-Options");
|
|
78
|
+
response.headers.set(
|
|
79
|
+
"Content-Security-Policy",
|
|
80
|
+
`frame-ancestors 'self' ${origins.join(" ")}`.trim()
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
exports.VEO_BUILDER_COOKIE = VEO_BUILDER_COOKIE;
|
|
85
|
+
exports.VEO_BUILDER_ORIGIN_COOKIE = VEO_BUILDER_ORIGIN_COOKIE;
|
|
86
|
+
exports.ensureVeoDesignSession = ensureVeoDesignSession;
|
|
87
|
+
exports.readVeoBuilderContext = readVeoBuilderContext;
|
|
88
|
+
exports.veoBuilderProxy = veoBuilderProxy;
|
|
89
|
+
//# sourceMappingURL=next.cjs.map
|
|
90
|
+
//# sourceMappingURL=next.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/builder-constants.ts","../src/next.ts"],"names":[],"mappings":"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","file":"next.cjs","sourcesContent":["/**\n * Nombres de los query params del puente builder. Constantes PURAS (sin DOM ni\n * `window`) para poder compartirlas entre el core (browser: `builder-token.ts`)\n * y el helper de servidor `veo-sdk/next` (`src/next.ts`), sin arrastrar código de\n * navegador al bundle de servidor.\n */\n\n/** Token de correlación del handshake. */\nexport const BUILDER_TOKEN_PARAM = 'veoBuilder';\n/** Origen del dashboard de Veo (para postMessage / frame-ancestors). */\nexport const BUILDER_ORIGIN_PARAM = 'veoBuilderOrigin';\n/** `1` → modo \"panel inyectado\": la app es top-level y el editor se inyecta encima. */\nexport const BUILDER_PANEL_PARAM = 'veoBuilderPanel';\n/** Path del panel del editor en el dashboard (default `/guides/design`). */\nexport const BUILDER_PANEL_PATH_PARAM = 'veoBuilderPanelPath';\n/** Id de la guía que se está editando (para cargar/guardar en el panel). */\nexport const BUILDER_GUIDE_PARAM = 'veoGuide';\n","/**\n * `veo-sdk/next` — helper de middleware para el \"modo diseño\" del editor visual.\n *\n * El editor de Veo embebe tu app en un `<iframe>` con `?veoBuilder=<token>`. Para\n * que tu app se deje diseñar hacen falta 3 cosas MECÁNICAS:\n * 1. permitir el embed (`frame-ancestors`, sacar `X-Frame-Options`),\n * 2. que las cookies de sesión viajen en el iframe cross-site\n * (`SameSite=None; Secure; Partitioned` — CHIPS),\n * 3. persistir el modo builder entre navegaciones (cookie particionada), así\n * sobrevive al redirect del guard de auth y a un login.\n *\n * Este wrapper hace las 3. Lo ÚNICO app-specific — qué sesión renderizás sin\n * login (usuario demo, etc.) — queda en tu handler, que recibe `{ builder }`.\n *\n * No depende de `next` (usa tipos estructurales), así el SDK sigue sin\n * dependencias de runtime. `NextRequest`/`NextResponse` son compatibles.\n *\n * @example\n * ```ts\n * // middleware.ts (o proxy.ts en Next 16)\n * import { veoBuilderProxy } from 'veo-sdk/next';\n *\n * export default veoBuilderProxy(\n * async (request, { builder }) => {\n * const { supabase, response } = createSupabaseMiddleware(request);\n * const { data: { user } } = await supabase.auth.getUser();\n * // Lo único tuyo: la sesión de diseño cuando estás embebido y sin login.\n * if (builder && !user) {\n * await supabase.auth.signInWithPassword({\n * email: process.env.VEO_BUILDER_DEMO_EMAIL!,\n * password: process.env.VEO_BUILDER_DEMO_PASSWORD!,\n * });\n * }\n * return response;\n * },\n * { dashboardOrigins: [process.env.VEO_DASHBOARD_ORIGINS ?? ''] },\n * );\n * ```\n */\nimport { BUILDER_ORIGIN_PARAM, BUILDER_TOKEN_PARAM } from './core/builder-constants';\n\n/** Cookie que persiste el token del builder (particionada, contexto embebido). */\nexport const VEO_BUILDER_COOKIE = 'veo-builder';\n/** Cookie que persiste el origen del dashboard de Veo. */\nexport const VEO_BUILDER_ORIGIN_COOKIE = 'veo-builder-origin';\n\n/** Sesión de builder activa (la app está embebida por el editor de Veo). */\nexport interface VeoBuilderContext {\n /** Token de correlación del handshake (idealmente firmado por el backend). */\n token: string;\n /** Origen del dashboard que embebe, para `frame-ancestors`. */\n origin: string | null;\n}\n\n// ── Tipos estructurales, compatibles con NextRequest/NextResponse ──\ninterface CookieLike {\n name: string;\n value: string;\n path?: string;\n domain?: string;\n maxAge?: number;\n expires?: Date | number;\n httpOnly?: boolean;\n sameSite?: boolean | 'lax' | 'strict' | 'none';\n secure?: boolean;\n partitioned?: boolean;\n priority?: 'low' | 'medium' | 'high';\n}\n\nexport interface VeoBuilderRequest {\n nextUrl: { searchParams: URLSearchParams };\n cookies: { get(name: string): { value: string } | undefined };\n}\n\nexport interface VeoBuilderResponse {\n headers: { set(name: string, value: string): void; delete(name: string): void };\n cookies: {\n set(cookie: CookieLike): void;\n getAll(): CookieLike[];\n };\n}\n\nexport interface VeoBuilderProxyOptions {\n /**\n * Orígenes autorizados a embeber la app (`frame-ancestors`), p.ej.\n * `['https://veo-dashboard-opal.vercel.app']`. Si se omite o queda vacío, se\n * usa el origen que envía el propio editor (`veoBuilderOrigin`).\n */\n dashboardOrigins?: string[];\n /** TTL de las cookies del modo builder, en segundos. Default 1800 (30 min). */\n cookieMaxAge?: number;\n}\n\n/**\n * Lee el contexto de builder del request: del query param (`?veoBuilder`, primer\n * arranque dentro del iframe) o de la cookie (sobrevive navegaciones SPA y\n * requests RSC que ya no llevan el param). `null` si la app corre en modo normal.\n */\nexport function readVeoBuilderContext(request: VeoBuilderRequest): VeoBuilderContext | null {\n const params = request.nextUrl.searchParams;\n const fromParam = params.get(BUILDER_TOKEN_PARAM);\n if (fromParam) {\n return {\n token: fromParam,\n origin:\n params.get(BUILDER_ORIGIN_PARAM) ??\n request.cookies.get(VEO_BUILDER_ORIGIN_COOKIE)?.value ??\n null,\n };\n }\n const fromCookie = request.cookies.get(VEO_BUILDER_COOKIE)?.value;\n if (fromCookie) {\n return {\n token: fromCookie,\n origin: request.cookies.get(VEO_BUILDER_ORIGIN_COOKIE)?.value ?? null,\n };\n }\n return null;\n}\n\n/** Cliente de auth mínimo para la sesión de diseño. Compatible con `supabase.auth`\n * y cualquier auth con la misma forma (tipos estructurales, sin acoplar el SDK). */\nexport interface DesignAuthClient {\n getUser(): Promise<{ data: { user: unknown } }>;\n signInWithPassword(credentials: { email: string; password: string }): Promise<unknown>;\n}\n\nexport interface DesignSessionOptions {\n /** Email del usuario demo. Default: env `VEO_BUILDER_DEMO_EMAIL`. */\n email?: string;\n /** Password del usuario demo. Default: env `VEO_BUILDER_DEMO_PASSWORD`. */\n password?: string;\n}\n\n/**\n * Establece la \"sesión de diseño\" cuando la app está embebida por el editor de\n * Veo y no hay login: entra como usuario DEMO (sin datos reales) para poder\n * navegar la app sin auth. No-op fuera de modo builder, si ya hay sesión, o si\n * faltan credenciales. Agnóstico del proveedor: funciona con `supabase.auth` y\n * cualquier cliente con `getUser` + `signInWithPassword`.\n *\n * @example\n * ```ts\n * await ensureVeoDesignSession(builder, supabase.auth);\n * ```\n */\nexport async function ensureVeoDesignSession(\n builder: VeoBuilderContext | null,\n auth: DesignAuthClient,\n options: DesignSessionOptions = {},\n): Promise<void> {\n if (!builder) return;\n const email = options.email ?? readEnv('VEO_BUILDER_DEMO_EMAIL');\n const password = options.password ?? readEnv('VEO_BUILDER_DEMO_PASSWORD');\n if (!email || !password) return;\n const {\n data: { user },\n } = await auth.getUser();\n if (!user) await auth.signInWithPassword({ email, password });\n}\n\nfunction readEnv(key: string): string | undefined {\n try {\n return typeof process !== 'undefined' ? process.env?.[key] : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Envuelve tu middleware de Next para habilitar el modo diseño de Veo. Cuando la\n * app está embebida (`?veoBuilder` o cookie), DESPUÉS de correr tu handler:\n * - reescribe TODAS las cookies de la respuesta a `SameSite=None; Secure;\n * Partitioned` (así la sesión viaja en el iframe cross-site),\n * - persiste token + origen en cookies particionadas,\n * - setea `frame-ancestors` y saca `X-Frame-Options`.\n *\n * Tu handler recibe `{ builder }` para decidir la sesión de diseño (lo único\n * app-specific). Fuera de modo builder es un passthrough exacto (no toca nada).\n */\nexport function veoBuilderProxy<Req extends VeoBuilderRequest, Res extends VeoBuilderResponse>(\n handler: (request: Req, ctx: { builder: VeoBuilderContext | null }) => Res | Promise<Res>,\n options: VeoBuilderProxyOptions = {},\n): (request: Req) => Promise<Res> {\n return async (request: Req): Promise<Res> => {\n const builder = readVeoBuilderContext(request);\n const response = await handler(request, { builder });\n if (builder) {\n repartitionCookies(response);\n persistBuilderCookies(response, builder, options.cookieMaxAge ?? 1800);\n applyFramingHeaders(response, builder, options.dashboardOrigins);\n }\n return response;\n };\n}\n\n/** Reescribe todas las cookies de la respuesta a particionadas (CHIPS). */\nfunction repartitionCookies(response: VeoBuilderResponse): void {\n for (const cookie of response.cookies.getAll()) {\n response.cookies.set({ ...cookie, sameSite: 'none', secure: true, partitioned: true });\n }\n}\n\nfunction persistBuilderCookies(\n response: VeoBuilderResponse,\n ctx: VeoBuilderContext,\n maxAge: number,\n): void {\n const base = { path: '/', maxAge, sameSite: 'none' as const, secure: true, partitioned: true };\n response.cookies.set({ name: VEO_BUILDER_COOKIE, value: ctx.token, httpOnly: true, ...base });\n if (ctx.origin) {\n response.cookies.set({\n name: VEO_BUILDER_ORIGIN_COOKIE,\n value: ctx.origin,\n httpOnly: false,\n ...base,\n });\n }\n}\n\nfunction applyFramingHeaders(\n response: VeoBuilderResponse,\n ctx: VeoBuilderContext,\n dashboardOrigins?: string[],\n): void {\n const configured = (dashboardOrigins ?? []).map((s) => s.trim()).filter(Boolean);\n const origins = configured.length > 0 ? configured : ctx.origin ? [ctx.origin] : [];\n response.headers.delete('X-Frame-Options');\n response.headers.set(\n 'Content-Security-Policy',\n `frame-ancestors 'self' ${origins.join(' ')}`.trim(),\n );\n}\n"]}
|
package/dist/next.d.cts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/** Cookie que persiste el token del builder (particionada, contexto embebido). */
|
|
2
|
+
declare const VEO_BUILDER_COOKIE = "veo-builder";
|
|
3
|
+
/** Cookie que persiste el origen del dashboard de Veo. */
|
|
4
|
+
declare const VEO_BUILDER_ORIGIN_COOKIE = "veo-builder-origin";
|
|
5
|
+
/** Sesión de builder activa (la app está embebida por el editor de Veo). */
|
|
6
|
+
interface VeoBuilderContext {
|
|
7
|
+
/** Token de correlación del handshake (idealmente firmado por el backend). */
|
|
8
|
+
token: string;
|
|
9
|
+
/** Origen del dashboard que embebe, para `frame-ancestors`. */
|
|
10
|
+
origin: string | null;
|
|
11
|
+
}
|
|
12
|
+
interface CookieLike {
|
|
13
|
+
name: string;
|
|
14
|
+
value: string;
|
|
15
|
+
path?: string;
|
|
16
|
+
domain?: string;
|
|
17
|
+
maxAge?: number;
|
|
18
|
+
expires?: Date | number;
|
|
19
|
+
httpOnly?: boolean;
|
|
20
|
+
sameSite?: boolean | 'lax' | 'strict' | 'none';
|
|
21
|
+
secure?: boolean;
|
|
22
|
+
partitioned?: boolean;
|
|
23
|
+
priority?: 'low' | 'medium' | 'high';
|
|
24
|
+
}
|
|
25
|
+
interface VeoBuilderRequest {
|
|
26
|
+
nextUrl: {
|
|
27
|
+
searchParams: URLSearchParams;
|
|
28
|
+
};
|
|
29
|
+
cookies: {
|
|
30
|
+
get(name: string): {
|
|
31
|
+
value: string;
|
|
32
|
+
} | undefined;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
interface VeoBuilderResponse {
|
|
36
|
+
headers: {
|
|
37
|
+
set(name: string, value: string): void;
|
|
38
|
+
delete(name: string): void;
|
|
39
|
+
};
|
|
40
|
+
cookies: {
|
|
41
|
+
set(cookie: CookieLike): void;
|
|
42
|
+
getAll(): CookieLike[];
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
interface VeoBuilderProxyOptions {
|
|
46
|
+
/**
|
|
47
|
+
* Orígenes autorizados a embeber la app (`frame-ancestors`), p.ej.
|
|
48
|
+
* `['https://veo-dashboard-opal.vercel.app']`. Si se omite o queda vacío, se
|
|
49
|
+
* usa el origen que envía el propio editor (`veoBuilderOrigin`).
|
|
50
|
+
*/
|
|
51
|
+
dashboardOrigins?: string[];
|
|
52
|
+
/** TTL de las cookies del modo builder, en segundos. Default 1800 (30 min). */
|
|
53
|
+
cookieMaxAge?: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Lee el contexto de builder del request: del query param (`?veoBuilder`, primer
|
|
57
|
+
* arranque dentro del iframe) o de la cookie (sobrevive navegaciones SPA y
|
|
58
|
+
* requests RSC que ya no llevan el param). `null` si la app corre en modo normal.
|
|
59
|
+
*/
|
|
60
|
+
declare function readVeoBuilderContext(request: VeoBuilderRequest): VeoBuilderContext | null;
|
|
61
|
+
/** Cliente de auth mínimo para la sesión de diseño. Compatible con `supabase.auth`
|
|
62
|
+
* y cualquier auth con la misma forma (tipos estructurales, sin acoplar el SDK). */
|
|
63
|
+
interface DesignAuthClient {
|
|
64
|
+
getUser(): Promise<{
|
|
65
|
+
data: {
|
|
66
|
+
user: unknown;
|
|
67
|
+
};
|
|
68
|
+
}>;
|
|
69
|
+
signInWithPassword(credentials: {
|
|
70
|
+
email: string;
|
|
71
|
+
password: string;
|
|
72
|
+
}): Promise<unknown>;
|
|
73
|
+
}
|
|
74
|
+
interface DesignSessionOptions {
|
|
75
|
+
/** Email del usuario demo. Default: env `VEO_BUILDER_DEMO_EMAIL`. */
|
|
76
|
+
email?: string;
|
|
77
|
+
/** Password del usuario demo. Default: env `VEO_BUILDER_DEMO_PASSWORD`. */
|
|
78
|
+
password?: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Establece la "sesión de diseño" cuando la app está embebida por el editor de
|
|
82
|
+
* Veo y no hay login: entra como usuario DEMO (sin datos reales) para poder
|
|
83
|
+
* navegar la app sin auth. No-op fuera de modo builder, si ya hay sesión, o si
|
|
84
|
+
* faltan credenciales. Agnóstico del proveedor: funciona con `supabase.auth` y
|
|
85
|
+
* cualquier cliente con `getUser` + `signInWithPassword`.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* await ensureVeoDesignSession(builder, supabase.auth);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
declare function ensureVeoDesignSession(builder: VeoBuilderContext | null, auth: DesignAuthClient, options?: DesignSessionOptions): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Envuelve tu middleware de Next para habilitar el modo diseño de Veo. Cuando la
|
|
95
|
+
* app está embebida (`?veoBuilder` o cookie), DESPUÉS de correr tu handler:
|
|
96
|
+
* - reescribe TODAS las cookies de la respuesta a `SameSite=None; Secure;
|
|
97
|
+
* Partitioned` (así la sesión viaja en el iframe cross-site),
|
|
98
|
+
* - persiste token + origen en cookies particionadas,
|
|
99
|
+
* - setea `frame-ancestors` y saca `X-Frame-Options`.
|
|
100
|
+
*
|
|
101
|
+
* Tu handler recibe `{ builder }` para decidir la sesión de diseño (lo único
|
|
102
|
+
* app-specific). Fuera de modo builder es un passthrough exacto (no toca nada).
|
|
103
|
+
*/
|
|
104
|
+
declare function veoBuilderProxy<Req extends VeoBuilderRequest, Res extends VeoBuilderResponse>(handler: (request: Req, ctx: {
|
|
105
|
+
builder: VeoBuilderContext | null;
|
|
106
|
+
}) => Res | Promise<Res>, options?: VeoBuilderProxyOptions): (request: Req) => Promise<Res>;
|
|
107
|
+
|
|
108
|
+
export { type DesignAuthClient, type DesignSessionOptions, VEO_BUILDER_COOKIE, VEO_BUILDER_ORIGIN_COOKIE, type VeoBuilderContext, type VeoBuilderProxyOptions, type VeoBuilderRequest, type VeoBuilderResponse, ensureVeoDesignSession, readVeoBuilderContext, veoBuilderProxy };
|
package/dist/next.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/** Cookie que persiste el token del builder (particionada, contexto embebido). */
|
|
2
|
+
declare const VEO_BUILDER_COOKIE = "veo-builder";
|
|
3
|
+
/** Cookie que persiste el origen del dashboard de Veo. */
|
|
4
|
+
declare const VEO_BUILDER_ORIGIN_COOKIE = "veo-builder-origin";
|
|
5
|
+
/** Sesión de builder activa (la app está embebida por el editor de Veo). */
|
|
6
|
+
interface VeoBuilderContext {
|
|
7
|
+
/** Token de correlación del handshake (idealmente firmado por el backend). */
|
|
8
|
+
token: string;
|
|
9
|
+
/** Origen del dashboard que embebe, para `frame-ancestors`. */
|
|
10
|
+
origin: string | null;
|
|
11
|
+
}
|
|
12
|
+
interface CookieLike {
|
|
13
|
+
name: string;
|
|
14
|
+
value: string;
|
|
15
|
+
path?: string;
|
|
16
|
+
domain?: string;
|
|
17
|
+
maxAge?: number;
|
|
18
|
+
expires?: Date | number;
|
|
19
|
+
httpOnly?: boolean;
|
|
20
|
+
sameSite?: boolean | 'lax' | 'strict' | 'none';
|
|
21
|
+
secure?: boolean;
|
|
22
|
+
partitioned?: boolean;
|
|
23
|
+
priority?: 'low' | 'medium' | 'high';
|
|
24
|
+
}
|
|
25
|
+
interface VeoBuilderRequest {
|
|
26
|
+
nextUrl: {
|
|
27
|
+
searchParams: URLSearchParams;
|
|
28
|
+
};
|
|
29
|
+
cookies: {
|
|
30
|
+
get(name: string): {
|
|
31
|
+
value: string;
|
|
32
|
+
} | undefined;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
interface VeoBuilderResponse {
|
|
36
|
+
headers: {
|
|
37
|
+
set(name: string, value: string): void;
|
|
38
|
+
delete(name: string): void;
|
|
39
|
+
};
|
|
40
|
+
cookies: {
|
|
41
|
+
set(cookie: CookieLike): void;
|
|
42
|
+
getAll(): CookieLike[];
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
interface VeoBuilderProxyOptions {
|
|
46
|
+
/**
|
|
47
|
+
* Orígenes autorizados a embeber la app (`frame-ancestors`), p.ej.
|
|
48
|
+
* `['https://veo-dashboard-opal.vercel.app']`. Si se omite o queda vacío, se
|
|
49
|
+
* usa el origen que envía el propio editor (`veoBuilderOrigin`).
|
|
50
|
+
*/
|
|
51
|
+
dashboardOrigins?: string[];
|
|
52
|
+
/** TTL de las cookies del modo builder, en segundos. Default 1800 (30 min). */
|
|
53
|
+
cookieMaxAge?: number;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Lee el contexto de builder del request: del query param (`?veoBuilder`, primer
|
|
57
|
+
* arranque dentro del iframe) o de la cookie (sobrevive navegaciones SPA y
|
|
58
|
+
* requests RSC que ya no llevan el param). `null` si la app corre en modo normal.
|
|
59
|
+
*/
|
|
60
|
+
declare function readVeoBuilderContext(request: VeoBuilderRequest): VeoBuilderContext | null;
|
|
61
|
+
/** Cliente de auth mínimo para la sesión de diseño. Compatible con `supabase.auth`
|
|
62
|
+
* y cualquier auth con la misma forma (tipos estructurales, sin acoplar el SDK). */
|
|
63
|
+
interface DesignAuthClient {
|
|
64
|
+
getUser(): Promise<{
|
|
65
|
+
data: {
|
|
66
|
+
user: unknown;
|
|
67
|
+
};
|
|
68
|
+
}>;
|
|
69
|
+
signInWithPassword(credentials: {
|
|
70
|
+
email: string;
|
|
71
|
+
password: string;
|
|
72
|
+
}): Promise<unknown>;
|
|
73
|
+
}
|
|
74
|
+
interface DesignSessionOptions {
|
|
75
|
+
/** Email del usuario demo. Default: env `VEO_BUILDER_DEMO_EMAIL`. */
|
|
76
|
+
email?: string;
|
|
77
|
+
/** Password del usuario demo. Default: env `VEO_BUILDER_DEMO_PASSWORD`. */
|
|
78
|
+
password?: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Establece la "sesión de diseño" cuando la app está embebida por el editor de
|
|
82
|
+
* Veo y no hay login: entra como usuario DEMO (sin datos reales) para poder
|
|
83
|
+
* navegar la app sin auth. No-op fuera de modo builder, si ya hay sesión, o si
|
|
84
|
+
* faltan credenciales. Agnóstico del proveedor: funciona con `supabase.auth` y
|
|
85
|
+
* cualquier cliente con `getUser` + `signInWithPassword`.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* await ensureVeoDesignSession(builder, supabase.auth);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
declare function ensureVeoDesignSession(builder: VeoBuilderContext | null, auth: DesignAuthClient, options?: DesignSessionOptions): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Envuelve tu middleware de Next para habilitar el modo diseño de Veo. Cuando la
|
|
95
|
+
* app está embebida (`?veoBuilder` o cookie), DESPUÉS de correr tu handler:
|
|
96
|
+
* - reescribe TODAS las cookies de la respuesta a `SameSite=None; Secure;
|
|
97
|
+
* Partitioned` (así la sesión viaja en el iframe cross-site),
|
|
98
|
+
* - persiste token + origen en cookies particionadas,
|
|
99
|
+
* - setea `frame-ancestors` y saca `X-Frame-Options`.
|
|
100
|
+
*
|
|
101
|
+
* Tu handler recibe `{ builder }` para decidir la sesión de diseño (lo único
|
|
102
|
+
* app-specific). Fuera de modo builder es un passthrough exacto (no toca nada).
|
|
103
|
+
*/
|
|
104
|
+
declare function veoBuilderProxy<Req extends VeoBuilderRequest, Res extends VeoBuilderResponse>(handler: (request: Req, ctx: {
|
|
105
|
+
builder: VeoBuilderContext | null;
|
|
106
|
+
}) => Res | Promise<Res>, options?: VeoBuilderProxyOptions): (request: Req) => Promise<Res>;
|
|
107
|
+
|
|
108
|
+
export { type DesignAuthClient, type DesignSessionOptions, VEO_BUILDER_COOKIE, VEO_BUILDER_ORIGIN_COOKIE, type VeoBuilderContext, type VeoBuilderProxyOptions, type VeoBuilderRequest, type VeoBuilderResponse, ensureVeoDesignSession, readVeoBuilderContext, veoBuilderProxy };
|
package/dist/next.mjs
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { BUILDER_TOKEN_PARAM, BUILDER_ORIGIN_PARAM } from './chunk-PTG3BTJE.mjs';
|
|
2
|
+
|
|
3
|
+
// src/next.ts
|
|
4
|
+
var VEO_BUILDER_COOKIE = "veo-builder";
|
|
5
|
+
var VEO_BUILDER_ORIGIN_COOKIE = "veo-builder-origin";
|
|
6
|
+
function readVeoBuilderContext(request) {
|
|
7
|
+
const params = request.nextUrl.searchParams;
|
|
8
|
+
const fromParam = params.get(BUILDER_TOKEN_PARAM);
|
|
9
|
+
if (fromParam) {
|
|
10
|
+
return {
|
|
11
|
+
token: fromParam,
|
|
12
|
+
origin: params.get(BUILDER_ORIGIN_PARAM) ?? request.cookies.get(VEO_BUILDER_ORIGIN_COOKIE)?.value ?? null
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const fromCookie = request.cookies.get(VEO_BUILDER_COOKIE)?.value;
|
|
16
|
+
if (fromCookie) {
|
|
17
|
+
return {
|
|
18
|
+
token: fromCookie,
|
|
19
|
+
origin: request.cookies.get(VEO_BUILDER_ORIGIN_COOKIE)?.value ?? null
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
async function ensureVeoDesignSession(builder, auth, options = {}) {
|
|
25
|
+
if (!builder) return;
|
|
26
|
+
const email = options.email ?? readEnv("VEO_BUILDER_DEMO_EMAIL");
|
|
27
|
+
const password = options.password ?? readEnv("VEO_BUILDER_DEMO_PASSWORD");
|
|
28
|
+
if (!email || !password) return;
|
|
29
|
+
const {
|
|
30
|
+
data: { user }
|
|
31
|
+
} = await auth.getUser();
|
|
32
|
+
if (!user) await auth.signInWithPassword({ email, password });
|
|
33
|
+
}
|
|
34
|
+
function readEnv(key) {
|
|
35
|
+
try {
|
|
36
|
+
return typeof process !== "undefined" ? process.env?.[key] : void 0;
|
|
37
|
+
} catch {
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function veoBuilderProxy(handler, options = {}) {
|
|
42
|
+
return async (request) => {
|
|
43
|
+
const builder = readVeoBuilderContext(request);
|
|
44
|
+
const response = await handler(request, { builder });
|
|
45
|
+
if (builder) {
|
|
46
|
+
repartitionCookies(response);
|
|
47
|
+
persistBuilderCookies(response, builder, options.cookieMaxAge ?? 1800);
|
|
48
|
+
applyFramingHeaders(response, builder, options.dashboardOrigins);
|
|
49
|
+
}
|
|
50
|
+
return response;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function repartitionCookies(response) {
|
|
54
|
+
for (const cookie of response.cookies.getAll()) {
|
|
55
|
+
response.cookies.set({ ...cookie, sameSite: "none", secure: true, partitioned: true });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function persistBuilderCookies(response, ctx, maxAge) {
|
|
59
|
+
const base = { path: "/", maxAge, sameSite: "none", secure: true, partitioned: true };
|
|
60
|
+
response.cookies.set({ name: VEO_BUILDER_COOKIE, value: ctx.token, httpOnly: true, ...base });
|
|
61
|
+
if (ctx.origin) {
|
|
62
|
+
response.cookies.set({
|
|
63
|
+
name: VEO_BUILDER_ORIGIN_COOKIE,
|
|
64
|
+
value: ctx.origin,
|
|
65
|
+
httpOnly: false,
|
|
66
|
+
...base
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function applyFramingHeaders(response, ctx, dashboardOrigins) {
|
|
71
|
+
const configured = (dashboardOrigins ?? []).map((s) => s.trim()).filter(Boolean);
|
|
72
|
+
const origins = configured.length > 0 ? configured : ctx.origin ? [ctx.origin] : [];
|
|
73
|
+
response.headers.delete("X-Frame-Options");
|
|
74
|
+
response.headers.set(
|
|
75
|
+
"Content-Security-Policy",
|
|
76
|
+
`frame-ancestors 'self' ${origins.join(" ")}`.trim()
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export { VEO_BUILDER_COOKIE, VEO_BUILDER_ORIGIN_COOKIE, ensureVeoDesignSession, readVeoBuilderContext, veoBuilderProxy };
|
|
81
|
+
//# sourceMappingURL=next.mjs.map
|
|
82
|
+
//# sourceMappingURL=next.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/next.ts"],"names":[],"mappings":"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","file":"next.mjs","sourcesContent":["/**\n * `veo-sdk/next` — helper de middleware para el \"modo diseño\" del editor visual.\n *\n * El editor de Veo embebe tu app en un `<iframe>` con `?veoBuilder=<token>`. Para\n * que tu app se deje diseñar hacen falta 3 cosas MECÁNICAS:\n * 1. permitir el embed (`frame-ancestors`, sacar `X-Frame-Options`),\n * 2. que las cookies de sesión viajen en el iframe cross-site\n * (`SameSite=None; Secure; Partitioned` — CHIPS),\n * 3. persistir el modo builder entre navegaciones (cookie particionada), así\n * sobrevive al redirect del guard de auth y a un login.\n *\n * Este wrapper hace las 3. Lo ÚNICO app-specific — qué sesión renderizás sin\n * login (usuario demo, etc.) — queda en tu handler, que recibe `{ builder }`.\n *\n * No depende de `next` (usa tipos estructurales), así el SDK sigue sin\n * dependencias de runtime. `NextRequest`/`NextResponse` son compatibles.\n *\n * @example\n * ```ts\n * // middleware.ts (o proxy.ts en Next 16)\n * import { veoBuilderProxy } from 'veo-sdk/next';\n *\n * export default veoBuilderProxy(\n * async (request, { builder }) => {\n * const { supabase, response } = createSupabaseMiddleware(request);\n * const { data: { user } } = await supabase.auth.getUser();\n * // Lo único tuyo: la sesión de diseño cuando estás embebido y sin login.\n * if (builder && !user) {\n * await supabase.auth.signInWithPassword({\n * email: process.env.VEO_BUILDER_DEMO_EMAIL!,\n * password: process.env.VEO_BUILDER_DEMO_PASSWORD!,\n * });\n * }\n * return response;\n * },\n * { dashboardOrigins: [process.env.VEO_DASHBOARD_ORIGINS ?? ''] },\n * );\n * ```\n */\nimport { BUILDER_ORIGIN_PARAM, BUILDER_TOKEN_PARAM } from './core/builder-constants';\n\n/** Cookie que persiste el token del builder (particionada, contexto embebido). */\nexport const VEO_BUILDER_COOKIE = 'veo-builder';\n/** Cookie que persiste el origen del dashboard de Veo. */\nexport const VEO_BUILDER_ORIGIN_COOKIE = 'veo-builder-origin';\n\n/** Sesión de builder activa (la app está embebida por el editor de Veo). */\nexport interface VeoBuilderContext {\n /** Token de correlación del handshake (idealmente firmado por el backend). */\n token: string;\n /** Origen del dashboard que embebe, para `frame-ancestors`. */\n origin: string | null;\n}\n\n// ── Tipos estructurales, compatibles con NextRequest/NextResponse ──\ninterface CookieLike {\n name: string;\n value: string;\n path?: string;\n domain?: string;\n maxAge?: number;\n expires?: Date | number;\n httpOnly?: boolean;\n sameSite?: boolean | 'lax' | 'strict' | 'none';\n secure?: boolean;\n partitioned?: boolean;\n priority?: 'low' | 'medium' | 'high';\n}\n\nexport interface VeoBuilderRequest {\n nextUrl: { searchParams: URLSearchParams };\n cookies: { get(name: string): { value: string } | undefined };\n}\n\nexport interface VeoBuilderResponse {\n headers: { set(name: string, value: string): void; delete(name: string): void };\n cookies: {\n set(cookie: CookieLike): void;\n getAll(): CookieLike[];\n };\n}\n\nexport interface VeoBuilderProxyOptions {\n /**\n * Orígenes autorizados a embeber la app (`frame-ancestors`), p.ej.\n * `['https://veo-dashboard-opal.vercel.app']`. Si se omite o queda vacío, se\n * usa el origen que envía el propio editor (`veoBuilderOrigin`).\n */\n dashboardOrigins?: string[];\n /** TTL de las cookies del modo builder, en segundos. Default 1800 (30 min). */\n cookieMaxAge?: number;\n}\n\n/**\n * Lee el contexto de builder del request: del query param (`?veoBuilder`, primer\n * arranque dentro del iframe) o de la cookie (sobrevive navegaciones SPA y\n * requests RSC que ya no llevan el param). `null` si la app corre en modo normal.\n */\nexport function readVeoBuilderContext(request: VeoBuilderRequest): VeoBuilderContext | null {\n const params = request.nextUrl.searchParams;\n const fromParam = params.get(BUILDER_TOKEN_PARAM);\n if (fromParam) {\n return {\n token: fromParam,\n origin:\n params.get(BUILDER_ORIGIN_PARAM) ??\n request.cookies.get(VEO_BUILDER_ORIGIN_COOKIE)?.value ??\n null,\n };\n }\n const fromCookie = request.cookies.get(VEO_BUILDER_COOKIE)?.value;\n if (fromCookie) {\n return {\n token: fromCookie,\n origin: request.cookies.get(VEO_BUILDER_ORIGIN_COOKIE)?.value ?? null,\n };\n }\n return null;\n}\n\n/** Cliente de auth mínimo para la sesión de diseño. Compatible con `supabase.auth`\n * y cualquier auth con la misma forma (tipos estructurales, sin acoplar el SDK). */\nexport interface DesignAuthClient {\n getUser(): Promise<{ data: { user: unknown } }>;\n signInWithPassword(credentials: { email: string; password: string }): Promise<unknown>;\n}\n\nexport interface DesignSessionOptions {\n /** Email del usuario demo. Default: env `VEO_BUILDER_DEMO_EMAIL`. */\n email?: string;\n /** Password del usuario demo. Default: env `VEO_BUILDER_DEMO_PASSWORD`. */\n password?: string;\n}\n\n/**\n * Establece la \"sesión de diseño\" cuando la app está embebida por el editor de\n * Veo y no hay login: entra como usuario DEMO (sin datos reales) para poder\n * navegar la app sin auth. No-op fuera de modo builder, si ya hay sesión, o si\n * faltan credenciales. Agnóstico del proveedor: funciona con `supabase.auth` y\n * cualquier cliente con `getUser` + `signInWithPassword`.\n *\n * @example\n * ```ts\n * await ensureVeoDesignSession(builder, supabase.auth);\n * ```\n */\nexport async function ensureVeoDesignSession(\n builder: VeoBuilderContext | null,\n auth: DesignAuthClient,\n options: DesignSessionOptions = {},\n): Promise<void> {\n if (!builder) return;\n const email = options.email ?? readEnv('VEO_BUILDER_DEMO_EMAIL');\n const password = options.password ?? readEnv('VEO_BUILDER_DEMO_PASSWORD');\n if (!email || !password) return;\n const {\n data: { user },\n } = await auth.getUser();\n if (!user) await auth.signInWithPassword({ email, password });\n}\n\nfunction readEnv(key: string): string | undefined {\n try {\n return typeof process !== 'undefined' ? process.env?.[key] : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Envuelve tu middleware de Next para habilitar el modo diseño de Veo. Cuando la\n * app está embebida (`?veoBuilder` o cookie), DESPUÉS de correr tu handler:\n * - reescribe TODAS las cookies de la respuesta a `SameSite=None; Secure;\n * Partitioned` (así la sesión viaja en el iframe cross-site),\n * - persiste token + origen en cookies particionadas,\n * - setea `frame-ancestors` y saca `X-Frame-Options`.\n *\n * Tu handler recibe `{ builder }` para decidir la sesión de diseño (lo único\n * app-specific). Fuera de modo builder es un passthrough exacto (no toca nada).\n */\nexport function veoBuilderProxy<Req extends VeoBuilderRequest, Res extends VeoBuilderResponse>(\n handler: (request: Req, ctx: { builder: VeoBuilderContext | null }) => Res | Promise<Res>,\n options: VeoBuilderProxyOptions = {},\n): (request: Req) => Promise<Res> {\n return async (request: Req): Promise<Res> => {\n const builder = readVeoBuilderContext(request);\n const response = await handler(request, { builder });\n if (builder) {\n repartitionCookies(response);\n persistBuilderCookies(response, builder, options.cookieMaxAge ?? 1800);\n applyFramingHeaders(response, builder, options.dashboardOrigins);\n }\n return response;\n };\n}\n\n/** Reescribe todas las cookies de la respuesta a particionadas (CHIPS). */\nfunction repartitionCookies(response: VeoBuilderResponse): void {\n for (const cookie of response.cookies.getAll()) {\n response.cookies.set({ ...cookie, sameSite: 'none', secure: true, partitioned: true });\n }\n}\n\nfunction persistBuilderCookies(\n response: VeoBuilderResponse,\n ctx: VeoBuilderContext,\n maxAge: number,\n): void {\n const base = { path: '/', maxAge, sameSite: 'none' as const, secure: true, partitioned: true };\n response.cookies.set({ name: VEO_BUILDER_COOKIE, value: ctx.token, httpOnly: true, ...base });\n if (ctx.origin) {\n response.cookies.set({\n name: VEO_BUILDER_ORIGIN_COOKIE,\n value: ctx.origin,\n httpOnly: false,\n ...base,\n });\n }\n}\n\nfunction applyFramingHeaders(\n response: VeoBuilderResponse,\n ctx: VeoBuilderContext,\n dashboardOrigins?: string[],\n): void {\n const configured = (dashboardOrigins ?? []).map((s) => s.trim()).filter(Boolean);\n const origins = configured.length > 0 ? configured : ctx.origin ? [ctx.origin] : [];\n response.headers.delete('X-Frame-Options');\n response.headers.set(\n 'Content-Security-Policy',\n `frame-ancestors 'self' ${origins.join(' ')}`.trim(),\n );\n}\n"]}
|