@auersperg/flare 0.3.16 → 0.3.18

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.
Files changed (21) hide show
  1. package/dist/cli/{chunk-xn3e3gev.js → chunk-6zw21b1h.js} +1 -1
  2. package/dist/cli/{chunk-8gzfscca.js → chunk-arads6c9.js} +1 -1
  3. package/dist/cli/{chunk-7ym0f672.js → chunk-k496964h.js} +6 -6
  4. package/dist/cli/{chunk-1yvbecac.js → chunk-twhp5nd5.js} +30 -4
  5. package/dist/cli/{chunk-yhvbksrm.js → chunk-xsqrjbhb.js} +1 -1
  6. package/dist/cli/flare.js +4 -4
  7. package/dist/platform/admin.js +1 -1
  8. package/dist/platform/dashboard/_astro/{ai-view.D6ouaMiL.js → ai-view.DcYKk5W_.js} +1 -1
  9. package/dist/platform/dashboard/_astro/{auth-view.0CuFK-xf.js → auth-view.KnVtTZYn.js} +1 -1
  10. package/dist/platform/dashboard/_astro/{data-view.jmNzQKhW.js → data-view.BFL2F3o9.js} +1 -1
  11. package/dist/platform/dashboard/_astro/{functions-view.Bqamd_KY.js → functions-view.vsmqlnUa.js} +1 -1
  12. package/dist/platform/dashboard/_astro/{index.astro_astro_type_script_index_0_lang.DlEchDEE.js → index.astro_astro_type_script_index_0_lang.DBs-yURk.js} +2 -2
  13. package/dist/platform/dashboard/_astro/{sdk-view.DuMOEfZu.js → sdk-view.BPVWrAC3.js} +1 -1
  14. package/dist/platform/dashboard/_astro/{services-view.B7BR4JD3.js → services-view.Dx1rjMWa.js} +1 -1
  15. package/dist/platform/dashboard/_astro/{settings-view.DM-igZ4O.js → settings-view.DPwEyqzv.js} +1 -1
  16. package/dist/platform/dashboard/index.html +1 -1
  17. package/dist/platform/manifest.json +26 -24
  18. package/dist/platform/runtime.js +128 -23
  19. package/dist/sdk/protocol.d.ts +2 -0
  20. package/dist/sdk/protocol.js +1 -1
  21. package/package.json +1 -1
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  storedToken2,
4
4
  connect2
5
- } from "./chunk-8gzfscca.js";
5
+ } from "./chunk-arads6c9.js";
6
6
  export {
7
7
  connect2 as connect,
8
8
  storedToken2 as storedToken
@@ -102,7 +102,7 @@ ${url}`);
102
102
  await writeFile(join(directory, key + ".json"), JSON.stringify({ token, expiresAt: result.expiresAt }) + `
103
103
  `, { mode: 384 });
104
104
  process.env.FLARE_DEPLOY_TOKEN = token;
105
- const { link } = await import("./chunk-7ym0f672.js");
105
+ const { link } = await import("./chunk-k496964h.js");
106
106
  return link({ platform, project: result.project });
107
107
  }
108
108
  throw Error("Login expired. Run flare dev again.");
@@ -26,7 +26,7 @@ async function request(platform, path, body) {
26
26
  return "null";
27
27
  }));
28
28
  if (config) {
29
- const { storedToken } = await import("./chunk-xn3e3gev.js");
29
+ const { storedToken } = await import("./chunk-6zw21b1h.js");
30
30
  token = await storedToken(platform, config.project);
31
31
  }
32
32
  }
@@ -107,7 +107,7 @@ async function deploy(options = {}) {
107
107
  }
108
108
  }
109
109
  const { prepare, generateApi } = await import("./chunk-fv98dfg5.js");
110
- const { buildApplication } = await import("./chunk-yhvbksrm.js");
110
+ const { buildApplication } = await import("./chunk-xsqrjbhb.js");
111
111
  const source = await prepare(), directory = resolve(".flare/releases/" + randomUUID());
112
112
  try {
113
113
  await buildApplication({ ...source, outdir: directory });
@@ -160,7 +160,7 @@ async function dev(options = {}) {
160
160
  } catch (e) {
161
161
  if (e.code !== "ENOENT")
162
162
  throw e;
163
- const { connect } = await import("./chunk-xn3e3gev.js");
163
+ const { connect } = await import("./chunk-6zw21b1h.js");
164
164
  await connect();
165
165
  }
166
166
  }
@@ -172,11 +172,11 @@ async function dev(options = {}) {
172
172
  } catch (e) {
173
173
  if (process.env.FLARE_DEPLOY_TOKEN || e.status !== 401 && !e.message.startsWith("Sign in"))
174
174
  throw e;
175
- const { connect } = await import("./chunk-xn3e3gev.js");
175
+ const { connect } = await import("./chunk-6zw21b1h.js");
176
176
  await connect();
177
177
  }
178
178
  }
179
- const { buildApplication } = await import("./chunk-yhvbksrm.js");
179
+ const { buildApplication } = await import("./chunk-xsqrjbhb.js");
180
180
  let busy = false, pending = false, timer, hash;
181
181
  const publish = async (initial = false) => {
182
182
  if (busy) {
@@ -308,7 +308,7 @@ async function releaseOperation(options, operation) {
308
308
  const bundle = await request(config.platform, `/api/projects/${config.project}/${source}/release-bundle?hash=${options.hash}`);
309
309
  if (bundle.release.hash !== options.hash)
310
310
  throw Error("Release hash mismatch");
311
- const { generateReferences } = await import("./chunk-yhvbksrm.js");
311
+ const { generateReferences } = await import("./chunk-xsqrjbhb.js");
312
312
  const { withGeneratedApi } = await import("./chunk-fv98dfg5.js");
313
313
  await mkdir(".flare", { recursive: true });
314
314
  const directory = await mkdtemp(resolve(".flare/release-contract-"));
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  storedToken2
4
- } from "./chunk-8gzfscca.js";
4
+ } from "./chunk-arads6c9.js";
5
5
 
6
6
  // packages/flare/src/cli/platform.mjs
7
7
  import { readFile as readFile4, mkdir as mkdir2, mkdtemp, writeFile as writeFile2, rm, cp } from "fs/promises";
@@ -297,8 +297,8 @@ import { randomUUID } from "crypto";
297
297
  import { readFile as readFile2 } from "fs/promises";
298
298
  function validatePlatformConfig(value = {}) {
299
299
  const object = (v) => v && typeof v === "object" && !Array.isArray(v);
300
- if (!object(value) || Object.keys(value).some((k) => !["capabilities", "secrets", "search", "codex"].includes(k)))
301
- throw Error("Platform config accepts only capabilities, secrets, search and codex references");
300
+ if (!object(value) || Object.keys(value).some((k) => !["capabilities", "secrets", "search", "codex", "mcpAuth"].includes(k)))
301
+ throw Error("Platform config accepts only capabilities, secrets, search, codex and mcpAuth references");
302
302
  const capabilities = value.capabilities ?? {}, secrets = value.secrets ?? [];
303
303
  if (!object(capabilities) || !Array.isArray(secrets) || secrets.length > 64)
304
304
  throw Error("Invalid platform capabilities/secrets references");
@@ -339,11 +339,28 @@ function validatePlatformConfig(value = {}) {
339
339
  codexServices.add(r.service);
340
340
  return { binding: r.binding, service: r.service, scope: r.scope };
341
341
  }).sort((a, b) => a.binding.localeCompare(b.binding));
342
+ const mcpAuth = value.mcpAuth ?? [];
343
+ if (!Array.isArray(mcpAuth) || mcpAuth.length > 16)
344
+ throw Error("Invalid MCP auth references");
345
+ const authNames = new Set, authServices = new Set, authIssuers = new Set;
346
+ const authReferences = mcpAuth.map((r) => {
347
+ if (!object(r) || Object.keys(r).sort().join() !== "binding,issuer,scope,service" || !/^APP_MCP_AUTH_[A-Z0-9_]{1,64}$/.test(r.binding) || !/^[a-z0-9][a-z0-9-]{0,62}$/.test(r.service) || !/^https:\/\/[a-z0-9]+(?:[.-][a-z0-9]+)*\.[a-z]{2,63}$/.test(r.issuer) || !/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\/(dev|prod)$/.test(r.scope) || authNames.has(r.binding) || authServices.has(r.service) || authIssuers.has(r.issuer))
348
+ throw Error("Invalid or duplicate MCP authorization reference");
349
+ authNames.add(r.binding);
350
+ authServices.add(r.service);
351
+ authIssuers.add(r.issuer);
352
+ return {
353
+ binding: r.binding,
354
+ service: r.service,
355
+ issuer: r.issuer,
356
+ scope: r.scope
357
+ };
358
+ }).sort((a, b) => a.binding.localeCompare(b.binding));
342
359
  const result = {};
343
360
  const used = new Set;
344
361
  for (const scope of Object.keys(capabilities).sort()) {
345
362
  const p = capabilities[scope];
346
- if (!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\/(dev|prod)$/.test(scope) || !object(p) || Object.keys(p).some((k) => !["outbound", "secrets", "search", "codex"].includes(k)))
363
+ if (!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\/(dev|prod)$/.test(scope) || !object(p) || Object.keys(p).some((k) => !["outbound", "secrets", "search", "codex", "mcpAuth"].includes(k)))
347
364
  throw Error("Invalid capability scope");
348
365
  const hosts = p.outbound ?? [], mapping = p.secrets ?? {};
349
366
  if (!Array.isArray(hosts) || hosts.length > 20 || !object(mapping) || Object.keys(mapping).length > 16)
@@ -360,7 +377,10 @@ function validatePlatformConfig(value = {}) {
360
377
  throw Error("Search grant must reference an instance owned by this environment");
361
378
  if (p.codex !== undefined && !codexReferences.some((r) => r.binding === p.codex && r.scope === scope))
362
379
  throw Error("Codex grant must reference a runner owned by this environment");
380
+ if (p.mcpAuth !== undefined && (!object(p.mcpAuth) || Object.keys(p.mcpAuth).sort().join() !== "binding,issuer" || !authReferences.some((r) => r.binding === p.mcpAuth.binding && r.issuer === p.mcpAuth.issuer && r.scope === scope)))
381
+ throw Error("MCP auth grant must reference its environment's authorization service");
363
382
  result[scope] = {
383
+ ...p.mcpAuth === undefined ? {} : { mcpAuth: { ...p.mcpAuth } },
364
384
  ...p.codex === undefined ? {} : { codex: p.codex },
365
385
  ...p.search === undefined ? {} : { search: p.search },
366
386
  outbound: [...new Set(hosts)].sort(),
@@ -373,6 +393,7 @@ function validatePlatformConfig(value = {}) {
373
393
  throw Error("Capabilities exceed 16 KiB");
374
394
  return {
375
395
  capabilities: result,
396
+ ...authReferences.length ? { mcpAuth: authReferences } : {},
376
397
  secrets: references,
377
398
  ...codexReferences.length ? { codex: codexReferences } : {},
378
399
  ...searchReferences.length ? { search: searchReferences } : {}
@@ -922,6 +943,11 @@ function workerConfiguration(state, release, role, bootstrap = false) {
922
943
  }
923
944
  ],
924
945
  services: bootstrap ? [] : [
946
+ ...(validatePlatformConfig(state.config).mcpAuth ?? []).map(({ binding, service }) => ({
947
+ binding,
948
+ service,
949
+ entrypoint: "McpAuthorization"
950
+ })),
925
951
  ...(validatePlatformConfig(state.config).codex ?? []).map(({ binding, service }) => ({
926
952
  binding,
927
953
  service,
@@ -80,7 +80,7 @@ function assertMcpTools(functions) {
80
80
  if (fn.mcp === undefined)
81
81
  continue;
82
82
  const m = fn.mcp;
83
- if (!m || typeof m !== "object" || Object.keys(m).sort().join() !== "description,name" || typeof m.name !== "string" || !/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(m.name) || typeof m.description !== "string" || !m.description.trim() || m.description.length > 1000 || names.has(m.name) || fn.auth === "internal" || fn.input.type !== "object")
83
+ if (!m || typeof m !== "object" || Object.keys(m).some((key) => !["name", "description", "readOnly"].includes(key)) || m.readOnly !== undefined && typeof m.readOnly !== "boolean" || fn.kind === "mutation" && m.readOnly === true || fn.kind === "query" && m.readOnly === false || typeof m.name !== "string" || !/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(m.name) || typeof m.description !== "string" || !m.description.trim() || m.description.length > 1000 || names.has(m.name) || fn.auth === "internal" || fn.input.type !== "object")
84
84
  throw new FlareError("INVALID_CONTRACT", "Invalid MCP tool contract");
85
85
  boundedJson({ mcp: m, input: fn.input }, 16384);
86
86
  names.add(m.name);
package/dist/cli/flare.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // packages/flare/package.json
4
4
  var package_default = {
5
5
  name: "@auersperg/flare",
6
- version: "0.3.16",
6
+ version: "0.3.18",
7
7
  license: "MIT",
8
8
  type: "module",
9
9
  description: "Flare client, server declarations and development CLI",
@@ -147,7 +147,7 @@ Uses the platform payload bundled with this CLI release. Never updates applicati
147
147
  options[key] = args[++i];
148
148
  }
149
149
  }
150
- const { platform } = await import("./chunk-1yvbecac.js");
150
+ const { platform } = await import("./chunk-twhp5nd5.js");
151
151
  console.log(JSON.stringify(await platform(options), null, 2));
152
152
  }
153
153
  } catch (error) {
@@ -187,12 +187,12 @@ Uses the platform payload bundled with this CLI release. Never updates applicati
187
187
  if (command === "build") {
188
188
  if (!options.entry || !options.outdir)
189
189
  throw Error("Required: --entry, --outdir");
190
- const { buildApplication } = await import("./chunk-yhvbksrm.js");
190
+ const { buildApplication } = await import("./chunk-xsqrjbhb.js");
191
191
  const x = await buildApplication(options);
192
192
  console.log(`Built immutable release ${x.hash}
193
193
  ${x.outdir}`);
194
194
  } else {
195
- const cloud = await import("./chunk-7ym0f672.js");
195
+ const cloud = await import("./chunk-k496964h.js");
196
196
  const x = await cloud[command](options);
197
197
  if (x)
198
198
  console.log(JSON.stringify(x, null, 2));
@@ -309,7 +309,7 @@ async function collectCatalog(database, now = Date.now()) {
309
309
  // packages/core/package.json
310
310
  var package_default = {
311
311
  name: "@flare/platform",
312
- version: "0.3.16",
312
+ version: "0.3.18",
313
313
  type: "module",
314
314
  license: "MIT",
315
315
  private: true,
@@ -1 +1 @@
1
- import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,g as r,j as i,m as a,p as o,pt as s,q as c,s as l,u}from"./common.9pujiaSZ.js";import{i as d,t as f}from"./client.BSf433s6.js";var p=e(t(),1),m=n();function h({project:e,env:t,session:n}){let h=r(e,t),g=u(h+`/ai`),[_,v]=(0,p.useState)(``),[y,b]=(0,p.useState)(``),[x,S]=(0,p.useState)(`{"query":""}`),[C,w]=(0,p.useState)(``),[T,E]=(0,p.useState)(``),[D,O]=(0,p.useState)(!1);(0,p.useEffect)(()=>{v(``),w(``),E(``)},[h]);async function k(){O(!0),E(``),w(``);let r=f({url:`${n.runtime}/p/${e.id}/${t}`,getToken:()=>_});try{let e=await r.action(d(y,`action`),JSON.parse(x));w(JSON.stringify(e,null,2))}catch(e){E(a(e))}finally{r.dispose(),O(!1)}}async function A(){if(confirm(`Exclude all indexed files in ${e.name}/${t}? Originals remain in Files. Provider cleanup is asynchronous.`)){O(!0),E(``);try{await o(h+`/search-clear`,t===`prod`?{confirm:e.id}:{}),g.refresh()}catch(e){E(a(e))}finally{O(!1)}}}return(0,m.jsxs)(`div`,{className:`space-y-6 p-6`,children:[(0,m.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,m.jsx)(`h1`,{className:`page-title`,children:`AI`}),(0,m.jsx)(s,{variant:`outline`,onClick:g.refresh,children:`Refresh`})]}),(0,m.jsx)(l,{loading:g.loading,error:g.error||T}),g.data&&(0,m.jsxs)(m.Fragment,{children:[(0,m.jsxs)(`section`,{className:`space-y-3`,children:[(0,m.jsx)(`h2`,{className:`text-lg font-medium`,children:`Search`}),(0,m.jsx)(`p`,{children:g.data.search.binding?`Binding: ${g.data.search.binding}`:`Not connected. Configure an existing AI Search instance through platform update --config. No resource is created here.`}),(0,m.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`TXT/PDF · up to 10 MiB · explicit file indexing from application actions. File permissions belong to your application.`}),(0,m.jsxs)(`p`,{children:[`Tracked index items: `,g.data.search.remaining]}),g.data.search.states.map(e=>(0,m.jsxs)(`p`,{children:[e.status,`: `,e.count]},e.status)),g.data.search.errors>0&&(0,m.jsxs)(`p`,{role:`alert`,children:[g.data.search.errors,` operations need attention. Retry indexing through the application; retry pending cleanup with Exclude all.`]}),(0,m.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Processing states are last observed, not a live provider status. Use action search.status(fileId) to refresh a document. Files, Functions and Logs remain in their existing sections.`}),n.role!==`viewer`&&g.data.search.remaining>0&&(0,m.jsx)(s,{variant:`outline`,disabled:D,onClick:A,children:`Exclude all / retry cleanup`})]}),(0,m.jsxs)(`section`,{className:`space-y-3`,children:[(0,m.jsx)(`h2`,{className:`text-lg font-medium`,children:`Test application search`}),(0,m.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Calls your existing search action with a real application session, not dashboard/admin identity. The application must authorize each result. Session is held only in this view, never saved. Dashboard origin must be allowed by the application.`}),(0,m.jsxs)(`label`,{className:`block`,children:[`Application session`,(0,m.jsx)(c,{type:`password`,autoComplete:`off`,value:_,onChange:e=>v(e.target.value),placeholder:`flared_session_…`})]}),(0,m.jsxs)(`label`,{className:`block`,children:[`Search action path`,(0,m.jsx)(c,{value:y,onChange:e=>b(e.target.value),placeholder:`documents/search`})]}),(0,m.jsxs)(`label`,{className:`block`,children:[`Arguments (JSON)`,(0,m.jsx)(i,{value:x,onChange:e=>S(e.target.value)})]}),(0,m.jsx)(s,{disabled:D||!_.startsWith(`flared_session_`)||!y||!g.data.search.binding,onClick:k,children:`Run once`}),C&&(0,m.jsx)(`pre`,{className:`whitespace-pre-wrap break-words text-sm`,children:C})]}),(0,m.jsxs)(`section`,{className:`space-y-3`,children:[(0,m.jsx)(`h2`,{className:`text-lg font-medium`,children:`MCP`}),(0,m.jsx)(`code`,{className:`break-all`,children:g.data.endpoint}),(0,m.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Stateless HTTP. Use a client supporting an Authorization: Bearer application-session header. No OAuth discovery. Admin, deploy and dev tokens are not accepted. Logout, expiry and disabling the user revoke access.`}),g.data.tools.length?g.data.tools.map(e=>(0,m.jsxs)(`p`,{children:[(0,m.jsx)(`strong`,{children:e.name}),` — `,e.description]},e.name)):(0,m.jsx)(`p`,{children:`No tools exposed. Add explicit mcp metadata to selected application functions and deploy that application.`})]})]})]})}export{h as default};
1
+ import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,g as r,j as i,m as a,p as o,pt as s,q as c,s as l,u}from"./common.9pujiaSZ.js";import{i as d,t as f}from"./client.BSf433s6.js";var p=e(t(),1),m=n();function h({project:e,env:t,session:n}){let h=r(e,t),g=u(h+`/ai`),[_,v]=(0,p.useState)(``),[y,b]=(0,p.useState)(``),[x,S]=(0,p.useState)(`{"query":""}`),[C,w]=(0,p.useState)(``),[T,E]=(0,p.useState)(``),[D,O]=(0,p.useState)(!1);(0,p.useEffect)(()=>{v(``),w(``),E(``)},[h]);async function k(){O(!0),E(``),w(``);let r=f({url:`${n.runtime}/p/${e.id}/${t}`,getToken:()=>_});try{let e=await r.action(d(y,`action`),JSON.parse(x));w(JSON.stringify(e,null,2))}catch(e){E(a(e))}finally{r.dispose(),O(!1)}}async function A(){if(confirm(`Exclude all indexed files in ${e.name}/${t}? Originals remain in Files. Provider cleanup is asynchronous.`)){O(!0),E(``);try{await o(h+`/search-clear`,t===`prod`?{confirm:e.id}:{}),g.refresh()}catch(e){E(a(e))}finally{O(!1)}}}return(0,m.jsxs)(`div`,{className:`space-y-6 p-6`,children:[(0,m.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,m.jsx)(`h1`,{className:`page-title`,children:`AI`}),(0,m.jsx)(s,{variant:`outline`,onClick:g.refresh,children:`Refresh`})]}),(0,m.jsx)(l,{loading:g.loading,error:g.error||T}),g.data&&(0,m.jsxs)(m.Fragment,{children:[(0,m.jsxs)(`section`,{className:`space-y-3`,children:[(0,m.jsx)(`h2`,{className:`text-lg font-medium`,children:`Search`}),(0,m.jsx)(`p`,{children:g.data.search.binding?`Binding: ${g.data.search.binding}`:`Not connected. Configure an existing AI Search instance through platform update --config. No resource is created here.`}),(0,m.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`TXT/PDF · up to 10 MiB · explicit file indexing from application actions. File permissions belong to your application.`}),(0,m.jsxs)(`p`,{children:[`Tracked index items: `,g.data.search.remaining]}),g.data.search.states.map(e=>(0,m.jsxs)(`p`,{children:[e.status,`: `,e.count]},e.status)),g.data.search.errors>0&&(0,m.jsxs)(`p`,{role:`alert`,children:[g.data.search.errors,` operations need attention. Retry indexing through the application; retry pending cleanup with Exclude all.`]}),(0,m.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Processing states are last observed, not a live provider status. Use action search.status(fileId) to refresh a document. Files, Functions and Logs remain in their existing sections.`}),n.role!==`viewer`&&g.data.search.remaining>0&&(0,m.jsx)(s,{variant:`outline`,disabled:D,onClick:A,children:`Exclude all / retry cleanup`})]}),(0,m.jsxs)(`section`,{className:`space-y-3`,children:[(0,m.jsx)(`h2`,{className:`text-lg font-medium`,children:`Test application search`}),(0,m.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:`Calls your existing search action with a real application session, not dashboard/admin identity. The application must authorize each result. Session is held only in this view, never saved. Dashboard origin must be allowed by the application.`}),(0,m.jsxs)(`label`,{className:`block`,children:[`Application session`,(0,m.jsx)(c,{type:`password`,autoComplete:`off`,value:_,onChange:e=>v(e.target.value),placeholder:`flared_session_…`})]}),(0,m.jsxs)(`label`,{className:`block`,children:[`Search action path`,(0,m.jsx)(c,{value:y,onChange:e=>b(e.target.value),placeholder:`documents/search`})]}),(0,m.jsxs)(`label`,{className:`block`,children:[`Arguments (JSON)`,(0,m.jsx)(i,{value:x,onChange:e=>S(e.target.value)})]}),(0,m.jsx)(s,{disabled:D||!_.startsWith(`flared_session_`)||!y||!g.data.search.binding,onClick:k,children:`Run once`}),C&&(0,m.jsx)(`pre`,{className:`whitespace-pre-wrap break-words text-sm`,children:C})]}),(0,m.jsxs)(`section`,{className:`space-y-3`,children:[(0,m.jsx)(`h2`,{className:`text-lg font-medium`,children:`MCP`}),(0,m.jsx)(`code`,{className:`break-all`,children:g.data.endpoint}),(0,m.jsxs)(`p`,{className:`text-sm text-muted-foreground`,children:[g.data.oauth?`OAuth enabled: ${g.data.oauth.authorization_servers[0]}. Connect this URL from an OAuth-capable MCP client. Read and write grants are separate; manage them in the application.`:`OAuth is not configured for this environment. Use a dedicated application-session Bearer header from a compatible MCP client.`,` `,`Admin, deploy and dev tokens are not accepted. Application logout ends that session, not independent OAuth connections. Disabling the user revokes both.`]}),g.data.tools.length?g.data.tools.map(e=>(0,m.jsxs)(`p`,{children:[(0,m.jsx)(`strong`,{children:e.name}),` — `,e.description]},e.name)):(0,m.jsx)(`p`,{children:`No tools exposed. Add explicit mcp metadata to selected application functions and deploy that application.`})]})]})]})}export{h as default};
@@ -1 +1 @@
1
- import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,S as r,_ as i,a,b as o,f as s,g as c,n as l,p as u,pt as d,s as f,u as p,v as m,x as h,y as g}from"./common.9pujiaSZ.js";import{o as _}from"./index.astro_astro_type_script_index_0_lang.DlEchDEE.js";var v=e(t(),1),y=n();function b(e){let t=c(e.project,e.env),[n,b]=(0,v.useState)(``),[x,S]=(0,v.useState)(),C=p(t+`/auth-users`+(n?`?cursor=`+encodeURIComponent(n):``)),w=p(t+`/auth-settings`),T=e.session.role===`owner`,E=(n,r,i,a=[])=>{S({title:r,description:`Passwords are never displayed. Changes revoke existing sessions.`,productionId:e.env===`prod`?e.project.id:void 0,fields:a,submit:async r=>{try{await u(t+`/`+n,{...i,...s(a,e=>new FormData(r).get(e)),confirm:e.project.id})}catch(e){throw e instanceof Error&&e.message===`INVALID_PASSWORD`?Error(`Password must contain 6–128 characters. Spaces are allowed; the password is not trimmed.`):e instanceof Error&&e.message===`REGISTRATION_UNAVAILABLE`?Error(`This login is already registered. Choose another login or manage the existing user.`):e}C.refresh(),w.refresh()}})},D={name:`password`,type:`password`,required:!0,description:`6–128 characters.`};return(0,y.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,y.jsx)(`h1`,{className:`page-title`,children:`Auth`}),(0,y.jsx)(f,{loading:C.loading||w.loading,error:C.error||w.error}),w.data&&(0,y.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,y.jsx)(_,{status:w.data.enabled?`Enabled`:`Disabled`}),(0,y.jsx)(_,{status:w.data.registration?`Public registration`:`Registration closed`}),T&&(0,y.jsx)(d,{variant:`outline`,onClick:()=>E(`auth-configure`,`Configure authentication`,{},[{name:`enabled`,type:`boolean`,value:w.data.enabled},{name:`registration`,type:`boolean`,value:w.data.registration}]),children:`Configure`}),T&&(0,y.jsx)(d,{onClick:()=>E(`auth-create`,`Create user`,{},[{name:`login`,type:`string`,required:!0},D]),children:`Create user`})]}),C.data&&(0,y.jsxs)(y.Fragment,{children:[(0,y.jsxs)(i,{children:[(0,y.jsx)(h,{children:(0,y.jsxs)(r,{children:[(0,y.jsx)(o,{children:`Login`}),(0,y.jsx)(o,{children:`User ID`}),(0,y.jsx)(o,{children:`Status`}),(0,y.jsx)(o,{children:`Created`}),(0,y.jsx)(o,{children:`Actions`})]})}),(0,y.jsx)(m,{children:C.data.users.map(e=>(0,y.jsxs)(r,{children:[(0,y.jsx)(g,{children:e.login}),(0,y.jsx)(g,{children:(0,y.jsx)(`code`,{children:e.id})}),(0,y.jsx)(g,{children:(0,y.jsx)(_,{status:e.disabled?`Blocked`:`Active`})}),(0,y.jsx)(g,{children:new Date(e.createdAt).toLocaleString()}),(0,y.jsx)(g,{children:(0,y.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:T&&(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(d,{variant:`outline`,size:`sm`,onClick:()=>E(`auth-password`,`Change user password`,{id:e.id},[D]),children:`Change password`}),(0,y.jsx)(d,{variant:`outline`,size:`sm`,onClick:()=>E(`auth-revoke`,`Revoke all sessions`,{id:e.id}),children:`Revoke sessions`}),(0,y.jsx)(d,{variant:`outline`,size:`sm`,onClick:()=>E(`auth-disable`,e.disabled?`Unblock user`:`Block user`,{id:e.id,disabled:!e.disabled}),children:e.disabled?`Unblock`:`Block`})]})})})]},e.id))})]}),!C.data.users.length&&(0,y.jsx)(l,{title:`No users`}),(0,y.jsxs)(`div`,{className:`flex gap-2`,children:[(0,y.jsx)(d,{variant:`outline`,disabled:!n,onClick:()=>b(``),children:`First page`}),(0,y.jsx)(d,{variant:`outline`,disabled:!C.data.next,onClick:()=>b(C.data.next),children:`Next page`})]})]}),x&&(0,y.jsx)(a,{modal:x,onClose:()=>S(void 0)})]})}export{b as default};
1
+ import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,S as r,_ as i,a,b as o,f as s,g as c,n as l,p as u,pt as d,s as f,u as p,v as m,x as h,y as g}from"./common.9pujiaSZ.js";import{o as _}from"./index.astro_astro_type_script_index_0_lang.DBs-yURk.js";var v=e(t(),1),y=n();function b(e){let t=c(e.project,e.env),[n,b]=(0,v.useState)(``),[x,S]=(0,v.useState)(),C=p(t+`/auth-users`+(n?`?cursor=`+encodeURIComponent(n):``)),w=p(t+`/auth-settings`),T=e.session.role===`owner`,E=(n,r,i,a=[])=>{S({title:r,description:`Passwords are never displayed. Changes revoke existing sessions.`,productionId:e.env===`prod`?e.project.id:void 0,fields:a,submit:async r=>{try{await u(t+`/`+n,{...i,...s(a,e=>new FormData(r).get(e)),confirm:e.project.id})}catch(e){throw e instanceof Error&&e.message===`INVALID_PASSWORD`?Error(`Password must contain 6–128 characters. Spaces are allowed; the password is not trimmed.`):e instanceof Error&&e.message===`REGISTRATION_UNAVAILABLE`?Error(`This login is already registered. Choose another login or manage the existing user.`):e}C.refresh(),w.refresh()}})},D={name:`password`,type:`password`,required:!0,description:`6–128 characters.`};return(0,y.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,y.jsx)(`h1`,{className:`page-title`,children:`Auth`}),(0,y.jsx)(f,{loading:C.loading||w.loading,error:C.error||w.error}),w.data&&(0,y.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,y.jsx)(_,{status:w.data.enabled?`Enabled`:`Disabled`}),(0,y.jsx)(_,{status:w.data.registration?`Public registration`:`Registration closed`}),T&&(0,y.jsx)(d,{variant:`outline`,onClick:()=>E(`auth-configure`,`Configure authentication`,{},[{name:`enabled`,type:`boolean`,value:w.data.enabled},{name:`registration`,type:`boolean`,value:w.data.registration}]),children:`Configure`}),T&&(0,y.jsx)(d,{onClick:()=>E(`auth-create`,`Create user`,{},[{name:`login`,type:`string`,required:!0},D]),children:`Create user`})]}),C.data&&(0,y.jsxs)(y.Fragment,{children:[(0,y.jsxs)(i,{children:[(0,y.jsx)(h,{children:(0,y.jsxs)(r,{children:[(0,y.jsx)(o,{children:`Login`}),(0,y.jsx)(o,{children:`User ID`}),(0,y.jsx)(o,{children:`Status`}),(0,y.jsx)(o,{children:`Created`}),(0,y.jsx)(o,{children:`Actions`})]})}),(0,y.jsx)(m,{children:C.data.users.map(e=>(0,y.jsxs)(r,{children:[(0,y.jsx)(g,{children:e.login}),(0,y.jsx)(g,{children:(0,y.jsx)(`code`,{children:e.id})}),(0,y.jsx)(g,{children:(0,y.jsx)(_,{status:e.disabled?`Blocked`:`Active`})}),(0,y.jsx)(g,{children:new Date(e.createdAt).toLocaleString()}),(0,y.jsx)(g,{children:(0,y.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:T&&(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(d,{variant:`outline`,size:`sm`,onClick:()=>E(`auth-password`,`Change user password`,{id:e.id},[D]),children:`Change password`}),(0,y.jsx)(d,{variant:`outline`,size:`sm`,onClick:()=>E(`auth-revoke`,`Revoke all sessions`,{id:e.id}),children:`Revoke sessions`}),(0,y.jsx)(d,{variant:`outline`,size:`sm`,onClick:()=>E(`auth-disable`,e.disabled?`Unblock user`:`Block user`,{id:e.id,disabled:!e.disabled}),children:e.disabled?`Unblock`:`Block`})]})})})]},e.id))})]}),!C.data.users.length&&(0,y.jsx)(l,{title:`No users`}),(0,y.jsxs)(`div`,{className:`flex gap-2`,children:[(0,y.jsx)(d,{variant:`outline`,disabled:!n,onClick:()=>b(``),children:`First page`}),(0,y.jsx)(d,{variant:`outline`,disabled:!C.data.next,onClick:()=>b(C.data.next),children:`Next page`})]})]}),x&&(0,y.jsx)(a,{modal:x,onClose:()=>S(void 0)})]})}export{b as default};
@@ -1 +1 @@
1
- import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,Ot as r,S as i,_ as a,a as o,b as s,d as c,g as l,h as u,l as d,n as f,p,pt as m,s as h,u as g,v as _,x as v,y}from"./common.9pujiaSZ.js";import{f as b,h as x,m as S,p as C,s as w}from"./index.astro_astro_type_script_index_0_lang.DlEchDEE.js";import{n as T,r as E,t as D}from"./input-group.Dsc4z0iT.js";var O={name:`chevron-right`,size:24,node:[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]};O.node;var k=r(O),A=e(t(),1),j=n();function M(e,t){return e.filter(e=>e.name!==`_id`&&e.name!==`_creationTime`).map(e=>{let n=c({properties:{[e.name]:e.schema??{type:/INT|REAL/i.test(e.type)?`number`:`string`}},required:e.notnull?[e.name]:[]})[0];return{...n,defaultMode:!t&&e.dflt_value!==null,value:t?t[e.name]:n.value}})}function N(e){let t=l(e.project,e.env),n=g(t+`/schema`),[r,i]=(0,A.useState)(``),[a,o]=(0,A.useState)(``),s=n.data?.tables??[],c=s.find(e=>e.name===r)?.name??s[0]?.name;return(0,j.jsxs)(`div`,{className:`flex h-full min-h-0`,children:[(0,j.jsxs)(`section`,{className:`explorer-sidebar overflow-y-auto`,"aria-label":`Application tables`,children:[(0,j.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,j.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,j.jsx)(`h1`,{className:`page-title`,children:`Data`}),(0,j.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[s.length,` tables`]})]}),(0,j.jsxs)(D,{children:[(0,j.jsx)(T,{children:(0,j.jsx)(b,{})}),(0,j.jsx)(E,{"aria-label":`Search tables`,placeholder:`Search tables…`,value:a,onChange:e=>o(e.target.value)})]})]}),(0,j.jsx)(`div`,{className:`space-y-1 px-2`,children:s.filter(e=>e.name.toLowerCase().includes(a.toLowerCase())).map(e=>(0,j.jsxs)(m,{variant:`ghost`,className:`w-full justify-start gap-2 ${c===e.name?`bg-accent`:``}`,onClick:()=>i(e.name),children:[(0,j.jsx)(x,{}),e.name]},e.name))}),(0,j.jsx)(`p`,{className:`p-4 text-xs text-muted-foreground`,children:`Tables are defined in code.`})]}),(0,j.jsxs)(`section`,{className:`flex min-h-0 min-w-0 flex-1 flex-col`,children:[(0,j.jsx)(h,{...n}),c?(0,j.jsx)(P,{...e,table:c},c):n.data?(0,j.jsx)(f,{title:`No application tables in this release`}):null]})]})}function P({project:e,env:t,session:n,table:r}){let[c,b]=(0,A.useState)(void 0),[x,T]=(0,A.useState)(),E=l(e,t),D=g(E+`/data?table=`+encodeURIComponent(r)+(c===void 0?``:`&cursor=`+encodeURIComponent(c))),O=D.data,N=O?.columns.find(e=>e.pk===1)?.name,P=n.role!==`viewer`,F=(n,i)=>{if(!O)return;let a=n===`delete`?void 0:M(O.columns,i);T({title:n===`insert`?`Add row`:n===`update`?`Edit row`:`Delete row`,description:n===`delete`?`This deletes the selected row. The change is audited.`:`Primary keys are immutable. NULL and defaults are explicit. Changes are revision-checked and audited.`,fields:a,productionId:t===`prod`?e.id:void 0,submit:async e=>{await p(E+`/edit`,{operation:n,table:r,key:i&&N?i[N]:void 0,values:a?d(e,a):void 0,expectedRevision:O.revision,confirm:t===`prod`?new FormData(e).get(`confirm`):void 0}),D.refresh()}})};return(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(`div`,{className:`detail-header`,children:[(0,j.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,j.jsx)(`h2`,{className:`font-mono text-sm font-semibold`,children:r}),O&&(0,j.jsxs)(w,{variant:`secondary`,children:[O.rows.length,` rows`]})]}),(0,j.jsxs)(`div`,{className:`flex gap-2`,children:[(0,j.jsx)(m,{variant:`ghost`,size:`icon-sm`,"aria-label":`Reload snapshot`,title:`Reload snapshot`,disabled:D.loading,onClick:D.refresh,children:(0,j.jsx)(C,{})}),P&&(0,j.jsxs)(m,{disabled:!O||D.loading,onClick:()=>F(`insert`),children:[(0,j.jsx)(S,{}),`Add row`]})]})]}),(0,j.jsxs)(`div`,{className:`flex justify-between border-b px-4 py-2 text-xs text-muted-foreground`,children:[(0,j.jsx)(`span`,{children:O?`${O.columns.length} columns · revision ${O.revision}`:`Loading table`}),(0,j.jsx)(`span`,{children:`Snapshot · updates after edits and when returning to this tab`})]}),(0,j.jsx)(h,{...D}),O&&(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-auto`,"aria-label":`Table rows`,role:`region`,tabIndex:0,children:[(0,j.jsxs)(a,{containerClassName:`overflow-visible`,children:[(0,j.jsx)(v,{className:`sticky top-0 z-10 bg-background`,children:(0,j.jsxs)(i,{children:[O.columns.map(e=>(0,j.jsxs)(s,{children:[(0,j.jsx)(`span`,{children:e.name}),(0,j.jsxs)(`small`,{className:`block font-normal text-muted-foreground`,children:[e.type.toLowerCase(),e.pk?` · primary`:``]})]},e.name)),P&&(0,j.jsx)(s,{children:`Actions`})]})}),(0,j.jsx)(_,{children:O.rows.map((e,t)=>(0,j.jsxs)(i,{children:[O.columns.map(t=>(0,j.jsx)(y,{className:`max-w-sm truncate font-mono`,title:u(e[t.name]),children:u(e[t.name])},t.name)),P&&(0,j.jsx)(y,{children:N?(0,j.jsxs)(`div`,{className:`flex gap-1`,children:[(0,j.jsx)(m,{size:`xs`,variant:`ghost`,onClick:()=>F(`update`,e),disabled:D.loading,children:`Edit`}),(0,j.jsx)(m,{size:`xs`,variant:`destructive`,onClick:()=>F(`delete`,e),disabled:D.loading,children:`Delete`})]}):`Read only`})]},N?String(e[N]):t))})]}),!O.rows.length&&(0,j.jsx)(f,{title:`No rows yet`,children:`Add a row or call a mutation from your app.`})]}),(0,j.jsxs)(`footer`,{className:`flex shrink-0 flex-wrap items-center justify-between gap-4 border-t p-4`,children:[(0,j.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`Up to 50 rows per page · changes are audited`}),(0,j.jsxs)(`div`,{className:`flex gap-2`,children:[(0,j.jsx)(m,{variant:`outline`,disabled:c===void 0||D.loading,onClick:()=>b(void 0),children:`First page`}),(0,j.jsxs)(m,{variant:`outline`,disabled:O.next===null||D.loading,onClick:()=>b(O.next??void 0),children:[`Next page`,(0,j.jsx)(k,{})]})]})]})]}),x&&(0,j.jsx)(o,{modal:x,onClose:()=>T(void 0)})]})}export{M as columnFields,N as default};
1
+ import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,Ot as r,S as i,_ as a,a as o,b as s,d as c,g as l,h as u,l as d,n as f,p,pt as m,s as h,u as g,v as _,x as v,y}from"./common.9pujiaSZ.js";import{f as b,h as x,m as S,p as C,s as w}from"./index.astro_astro_type_script_index_0_lang.DBs-yURk.js";import{n as T,r as E,t as D}from"./input-group.Dsc4z0iT.js";var O={name:`chevron-right`,size:24,node:[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]};O.node;var k=r(O),A=e(t(),1),j=n();function M(e,t){return e.filter(e=>e.name!==`_id`&&e.name!==`_creationTime`).map(e=>{let n=c({properties:{[e.name]:e.schema??{type:/INT|REAL/i.test(e.type)?`number`:`string`}},required:e.notnull?[e.name]:[]})[0];return{...n,defaultMode:!t&&e.dflt_value!==null,value:t?t[e.name]:n.value}})}function N(e){let t=l(e.project,e.env),n=g(t+`/schema`),[r,i]=(0,A.useState)(``),[a,o]=(0,A.useState)(``),s=n.data?.tables??[],c=s.find(e=>e.name===r)?.name??s[0]?.name;return(0,j.jsxs)(`div`,{className:`flex h-full min-h-0`,children:[(0,j.jsxs)(`section`,{className:`explorer-sidebar overflow-y-auto`,"aria-label":`Application tables`,children:[(0,j.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,j.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,j.jsx)(`h1`,{className:`page-title`,children:`Data`}),(0,j.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[s.length,` tables`]})]}),(0,j.jsxs)(D,{children:[(0,j.jsx)(T,{children:(0,j.jsx)(b,{})}),(0,j.jsx)(E,{"aria-label":`Search tables`,placeholder:`Search tables…`,value:a,onChange:e=>o(e.target.value)})]})]}),(0,j.jsx)(`div`,{className:`space-y-1 px-2`,children:s.filter(e=>e.name.toLowerCase().includes(a.toLowerCase())).map(e=>(0,j.jsxs)(m,{variant:`ghost`,className:`w-full justify-start gap-2 ${c===e.name?`bg-accent`:``}`,onClick:()=>i(e.name),children:[(0,j.jsx)(x,{}),e.name]},e.name))}),(0,j.jsx)(`p`,{className:`p-4 text-xs text-muted-foreground`,children:`Tables are defined in code.`})]}),(0,j.jsxs)(`section`,{className:`flex min-h-0 min-w-0 flex-1 flex-col`,children:[(0,j.jsx)(h,{...n}),c?(0,j.jsx)(P,{...e,table:c},c):n.data?(0,j.jsx)(f,{title:`No application tables in this release`}):null]})]})}function P({project:e,env:t,session:n,table:r}){let[c,b]=(0,A.useState)(void 0),[x,T]=(0,A.useState)(),E=l(e,t),D=g(E+`/data?table=`+encodeURIComponent(r)+(c===void 0?``:`&cursor=`+encodeURIComponent(c))),O=D.data,N=O?.columns.find(e=>e.pk===1)?.name,P=n.role!==`viewer`,F=(n,i)=>{if(!O)return;let a=n===`delete`?void 0:M(O.columns,i);T({title:n===`insert`?`Add row`:n===`update`?`Edit row`:`Delete row`,description:n===`delete`?`This deletes the selected row. The change is audited.`:`Primary keys are immutable. NULL and defaults are explicit. Changes are revision-checked and audited.`,fields:a,productionId:t===`prod`?e.id:void 0,submit:async e=>{await p(E+`/edit`,{operation:n,table:r,key:i&&N?i[N]:void 0,values:a?d(e,a):void 0,expectedRevision:O.revision,confirm:t===`prod`?new FormData(e).get(`confirm`):void 0}),D.refresh()}})};return(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(`div`,{className:`detail-header`,children:[(0,j.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,j.jsx)(`h2`,{className:`font-mono text-sm font-semibold`,children:r}),O&&(0,j.jsxs)(w,{variant:`secondary`,children:[O.rows.length,` rows`]})]}),(0,j.jsxs)(`div`,{className:`flex gap-2`,children:[(0,j.jsx)(m,{variant:`ghost`,size:`icon-sm`,"aria-label":`Reload snapshot`,title:`Reload snapshot`,disabled:D.loading,onClick:D.refresh,children:(0,j.jsx)(C,{})}),P&&(0,j.jsxs)(m,{disabled:!O||D.loading,onClick:()=>F(`insert`),children:[(0,j.jsx)(S,{}),`Add row`]})]})]}),(0,j.jsxs)(`div`,{className:`flex justify-between border-b px-4 py-2 text-xs text-muted-foreground`,children:[(0,j.jsx)(`span`,{children:O?`${O.columns.length} columns · revision ${O.revision}`:`Loading table`}),(0,j.jsx)(`span`,{children:`Snapshot · updates after edits and when returning to this tab`})]}),(0,j.jsx)(h,{...D}),O&&(0,j.jsxs)(j.Fragment,{children:[(0,j.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-auto`,"aria-label":`Table rows`,role:`region`,tabIndex:0,children:[(0,j.jsxs)(a,{containerClassName:`overflow-visible`,children:[(0,j.jsx)(v,{className:`sticky top-0 z-10 bg-background`,children:(0,j.jsxs)(i,{children:[O.columns.map(e=>(0,j.jsxs)(s,{children:[(0,j.jsx)(`span`,{children:e.name}),(0,j.jsxs)(`small`,{className:`block font-normal text-muted-foreground`,children:[e.type.toLowerCase(),e.pk?` · primary`:``]})]},e.name)),P&&(0,j.jsx)(s,{children:`Actions`})]})}),(0,j.jsx)(_,{children:O.rows.map((e,t)=>(0,j.jsxs)(i,{children:[O.columns.map(t=>(0,j.jsx)(y,{className:`max-w-sm truncate font-mono`,title:u(e[t.name]),children:u(e[t.name])},t.name)),P&&(0,j.jsx)(y,{children:N?(0,j.jsxs)(`div`,{className:`flex gap-1`,children:[(0,j.jsx)(m,{size:`xs`,variant:`ghost`,onClick:()=>F(`update`,e),disabled:D.loading,children:`Edit`}),(0,j.jsx)(m,{size:`xs`,variant:`destructive`,onClick:()=>F(`delete`,e),disabled:D.loading,children:`Delete`})]}):`Read only`})]},N?String(e[N]):t))})]}),!O.rows.length&&(0,j.jsx)(f,{title:`No rows yet`,children:`Add a row or call a mutation from your app.`})]}),(0,j.jsxs)(`footer`,{className:`flex shrink-0 flex-wrap items-center justify-between gap-4 border-t p-4`,children:[(0,j.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:`Up to 50 rows per page · changes are audited`}),(0,j.jsxs)(`div`,{className:`flex gap-2`,children:[(0,j.jsx)(m,{variant:`outline`,disabled:c===void 0||D.loading,onClick:()=>b(void 0),children:`First page`}),(0,j.jsxs)(m,{variant:`outline`,disabled:O.next===null||D.loading,onClick:()=>b(O.next??void 0),children:[`Next page`,(0,j.jsx)(k,{})]})]})]})]}),x&&(0,j.jsx)(o,{modal:x,onClose:()=>T(void 0)})]})}export{M as columnFields,N as default};
@@ -1 +1 @@
1
- import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,Ot as r,c as i,d as a,g as o,i as s,l as c,m as l,n as u,p as d,pt as f,r as p,s as m,u as h}from"./common.9pujiaSZ.js";import{a as g,c as _,d as v,f as y,g as b,l as x,o as S,u as C}from"./index.astro_astro_type_script_index_0_lang.DlEchDEE.js";import{i as w,t as T}from"./client.BSf433s6.js";import{n as E,r as D,t as O}from"./input-group.Dsc4z0iT.js";var k={name:`folder`,size:24,node:[[`path`,{d:`M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z`,key:`1kt360`}]]};k.node;var A=r(k),j={name:`play`,size:24,node:[[`path`,{d:`M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z`,key:`10ikf1`}]]};j.node;var M=r(j),N=e(t(),1),P=n();function F(e){let t=h(o(e.project,e.env)+`/functions`),[n,r]=(0,N.useState)(``),[i,a]=(0,N.useState)(``),s=Object.entries(t.data?.functions??{}),c=s.find(([e])=>e===i)??s[0],l=new Map;return s.filter(([e])=>e.toLowerCase().includes(n.toLowerCase())).forEach(e=>{let t=e[0].includes(`/`)?e[0].slice(0,e[0].lastIndexOf(`/`)):`Functions`,n=l.get(t)??[];n.push(e),l.set(t,n)}),(0,P.jsxs)(`div`,{className:`flex min-h-full`,children:[(0,P.jsxs)(`section`,{className:`explorer-sidebar`,"aria-label":`Deployed functions`,children:[(0,P.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,P.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,P.jsx)(`h1`,{className:`page-title`,children:`Functions`}),(0,P.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:s.length})]}),(0,P.jsxs)(O,{children:[(0,P.jsx)(E,{children:(0,P.jsx)(y,{})}),(0,P.jsx)(D,{"aria-label":`Search functions`,placeholder:`Search functions…`,value:n,onChange:e=>r(e.target.value)})]})]}),(0,P.jsx)(`div`,{className:`space-y-2 px-2`,children:[...l].map(([e,t])=>(0,P.jsxs)(`details`,{open:!0,children:[(0,P.jsxs)(`summary`,{className:`flex cursor-pointer items-center gap-2 px-2 py-2 text-xs text-muted-foreground`,children:[(0,P.jsx)(A,{className:`size-4`}),e]}),(0,P.jsx)(`div`,{className:`space-y-1`,children:t.map(([e,t])=>(0,P.jsxs)(f,{variant:`ghost`,onClick:()=>a(e),className:`w-full justify-between ${c?.[0]===e?`bg-accent`:``}`,children:[(0,P.jsx)(`span`,{className:`truncate`,children:e.split(`/`).pop()}),(0,P.jsx)(g,{kind:t.kind})]},e))})]},e))}),(0,P.jsxs)(`p`,{className:`p-4 text-xs text-muted-foreground`,children:[`Active release · `,e.env]})]}),(0,P.jsxs)(`section`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(m,{...t}),c?(0,P.jsx)(L,{...e,path:c[0],fn:c[1]},c[0]+`:`+JSON.stringify(c[1])):t.data?(0,P.jsx)(u,{title:`No deployed functions`}):null]})]})}function I(e,t,n){return e===`dev`&&t!==`viewer`&&[`query`,`mutation`,`action`].includes(n)}function L({project:e,env:t,session:n,path:r,fn:m}){let h=a(m.input),y=I(t,n.role,m.kind)&&m.auth!==`internal`,[E,D]=(0,N.useState)(!1),[O,k]=(0,N.useState)(``),[A,j]=(0,N.useState)(),[F,L]=(0,N.useState)(!1),[R,z]=(0,N.useState)(),B=(0,N.useRef)(!0),V=(0,N.useRef)(void 0),H=(0,N.useRef)(void 0);return(0,N.useEffect)(()=>(B.current=!0,()=>{B.current=!1,H.current?.abort(),V.current?.dispose()}),[]),(0,P.jsxs)(P.Fragment,{children:[(0,P.jsxs)(`div`,{className:`detail-header`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3`,children:[(0,P.jsx)(`h2`,{className:`font-mono text-sm font-semibold`,children:r}),(0,P.jsx)(g,{kind:m.kind}),(0,P.jsx)(S,{status:m.auth,children:m.auth===`required`?`Authentication required`:m.auth})]}),(0,P.jsxs)(f,{type:`submit`,form:`function-run`,disabled:!y||E,children:[(0,P.jsx)(M,{}),E?`Running…`:`Run Function`]})]}),(0,P.jsxs)(_,{defaultValue:`runner`,children:[(0,P.jsxs)(C,{variant:`line`,className:`mx-4 mt-4`,children:[(0,P.jsx)(v,{value:`runner`,children:`Function runner`}),(0,P.jsx)(v,{value:`contract`,children:`Contract`})]}),(0,P.jsx)(x,{value:`runner`,className:`mt-4`,children:(0,P.jsxs)(`div`,{className:`grid lg:grid-cols-2`,children:[(0,P.jsxs)(`section`,{className:`space-y-4 border-b p-4 lg:border-r lg:border-b-0`,children:[(0,P.jsxs)(`div`,{className:`flex justify-between`,children:[(0,P.jsx)(`h3`,{className:`text-sm font-medium`,children:`Arguments`}),(0,P.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[h.length,` fields`]})]}),(0,P.jsx)(`form`,{id:`function-run`,onSubmit:async n=>{if(n.preventDefault(),!y||E||H.current)return;let i=new AbortController;H.current=i,D(!0),k(``),z(void 0),j(void 0),L(!1);try{let a=c(n.currentTarget,h),s=await d(o(e,t)+`/dev-token`,{},i.signal);if(!B.current||i.signal.aborted)return;V.current=T({url:s.url,getToken:()=>s.token});let l=performance.now(),u=await V.current[m.kind](w(r,m.kind),a);B.current&&!i.signal.aborted&&(j(u),L(!0),z(Math.round(performance.now()-l)))}catch(e){B.current&&!i.signal.aborted&&k(l(e))}finally{V.current?.dispose(),H.current===i&&(H.current=void 0),B.current&&D(!1)}},children:(0,P.jsx)(s,{items:h})}),(0,P.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Development execution only. Mutations and actions can change data. Live subscriptions use the SDK. Writes are not automatically retried. Internal functions are called only by server capabilities or scheduled jobs, not this HTTP runner.`})]}),(0,P.jsxs)(`section`,{className:`space-y-4 p-4`,children:[(0,P.jsxs)(`div`,{className:`flex justify-between`,children:[(0,P.jsx)(`h3`,{className:`text-sm font-medium`,children:`Result`}),(0,P.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:E?`Running…`:O?`Failed`:R===void 0?`Not executed`:`Completed · ${R} ms round trip`})]}),O?(0,P.jsx)(p,{children:O}):F?(0,P.jsx)(i,{value:A}):(0,P.jsx)(u,{title:`Run this function to see its result`,children:(0,P.jsx)(b,{className:`mx-auto mt-3 size-7`})})]})]})}),(0,P.jsxs)(x,{value:`contract`,className:`space-y-4 p-4`,children:[(0,P.jsxs)(`section`,{className:`space-y-3`,children:[(0,P.jsx)(`h3`,{className:`text-sm font-medium`,children:`Input contract`}),(0,P.jsx)(i,{value:m.input})]}),(0,P.jsxs)(`section`,{className:`space-y-3`,children:[(0,P.jsx)(`h3`,{className:`text-sm font-medium`,children:`Output contract`}),(0,P.jsx)(i,{value:m.output})]})]})]})]})}export{I as canRun,F as default};
1
+ import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,Ot as r,c as i,d as a,g as o,i as s,l as c,m as l,n as u,p as d,pt as f,r as p,s as m,u as h}from"./common.9pujiaSZ.js";import{a as g,c as _,d as v,f as y,g as b,l as x,o as S,u as C}from"./index.astro_astro_type_script_index_0_lang.DBs-yURk.js";import{i as w,t as T}from"./client.BSf433s6.js";import{n as E,r as D,t as O}from"./input-group.Dsc4z0iT.js";var k={name:`folder`,size:24,node:[[`path`,{d:`M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z`,key:`1kt360`}]]};k.node;var A=r(k),j={name:`play`,size:24,node:[[`path`,{d:`M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z`,key:`10ikf1`}]]};j.node;var M=r(j),N=e(t(),1),P=n();function F(e){let t=h(o(e.project,e.env)+`/functions`),[n,r]=(0,N.useState)(``),[i,a]=(0,N.useState)(``),s=Object.entries(t.data?.functions??{}),c=s.find(([e])=>e===i)??s[0],l=new Map;return s.filter(([e])=>e.toLowerCase().includes(n.toLowerCase())).forEach(e=>{let t=e[0].includes(`/`)?e[0].slice(0,e[0].lastIndexOf(`/`)):`Functions`,n=l.get(t)??[];n.push(e),l.set(t,n)}),(0,P.jsxs)(`div`,{className:`flex min-h-full`,children:[(0,P.jsxs)(`section`,{className:`explorer-sidebar`,"aria-label":`Deployed functions`,children:[(0,P.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,P.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,P.jsx)(`h1`,{className:`page-title`,children:`Functions`}),(0,P.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:s.length})]}),(0,P.jsxs)(O,{children:[(0,P.jsx)(E,{children:(0,P.jsx)(y,{})}),(0,P.jsx)(D,{"aria-label":`Search functions`,placeholder:`Search functions…`,value:n,onChange:e=>r(e.target.value)})]})]}),(0,P.jsx)(`div`,{className:`space-y-2 px-2`,children:[...l].map(([e,t])=>(0,P.jsxs)(`details`,{open:!0,children:[(0,P.jsxs)(`summary`,{className:`flex cursor-pointer items-center gap-2 px-2 py-2 text-xs text-muted-foreground`,children:[(0,P.jsx)(A,{className:`size-4`}),e]}),(0,P.jsx)(`div`,{className:`space-y-1`,children:t.map(([e,t])=>(0,P.jsxs)(f,{variant:`ghost`,onClick:()=>a(e),className:`w-full justify-between ${c?.[0]===e?`bg-accent`:``}`,children:[(0,P.jsx)(`span`,{className:`truncate`,children:e.split(`/`).pop()}),(0,P.jsx)(g,{kind:t.kind})]},e))})]},e))}),(0,P.jsxs)(`p`,{className:`p-4 text-xs text-muted-foreground`,children:[`Active release · `,e.env]})]}),(0,P.jsxs)(`section`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(m,{...t}),c?(0,P.jsx)(L,{...e,path:c[0],fn:c[1]},c[0]+`:`+JSON.stringify(c[1])):t.data?(0,P.jsx)(u,{title:`No deployed functions`}):null]})]})}function I(e,t,n){return e===`dev`&&t!==`viewer`&&[`query`,`mutation`,`action`].includes(n)}function L({project:e,env:t,session:n,path:r,fn:m}){let h=a(m.input),y=I(t,n.role,m.kind)&&m.auth!==`internal`,[E,D]=(0,N.useState)(!1),[O,k]=(0,N.useState)(``),[A,j]=(0,N.useState)(),[F,L]=(0,N.useState)(!1),[R,z]=(0,N.useState)(),B=(0,N.useRef)(!0),V=(0,N.useRef)(void 0),H=(0,N.useRef)(void 0);return(0,N.useEffect)(()=>(B.current=!0,()=>{B.current=!1,H.current?.abort(),V.current?.dispose()}),[]),(0,P.jsxs)(P.Fragment,{children:[(0,P.jsxs)(`div`,{className:`detail-header`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3`,children:[(0,P.jsx)(`h2`,{className:`font-mono text-sm font-semibold`,children:r}),(0,P.jsx)(g,{kind:m.kind}),(0,P.jsx)(S,{status:m.auth,children:m.auth===`required`?`Authentication required`:m.auth})]}),(0,P.jsxs)(f,{type:`submit`,form:`function-run`,disabled:!y||E,children:[(0,P.jsx)(M,{}),E?`Running…`:`Run Function`]})]}),(0,P.jsxs)(_,{defaultValue:`runner`,children:[(0,P.jsxs)(C,{variant:`line`,className:`mx-4 mt-4`,children:[(0,P.jsx)(v,{value:`runner`,children:`Function runner`}),(0,P.jsx)(v,{value:`contract`,children:`Contract`})]}),(0,P.jsx)(x,{value:`runner`,className:`mt-4`,children:(0,P.jsxs)(`div`,{className:`grid lg:grid-cols-2`,children:[(0,P.jsxs)(`section`,{className:`space-y-4 border-b p-4 lg:border-r lg:border-b-0`,children:[(0,P.jsxs)(`div`,{className:`flex justify-between`,children:[(0,P.jsx)(`h3`,{className:`text-sm font-medium`,children:`Arguments`}),(0,P.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[h.length,` fields`]})]}),(0,P.jsx)(`form`,{id:`function-run`,onSubmit:async n=>{if(n.preventDefault(),!y||E||H.current)return;let i=new AbortController;H.current=i,D(!0),k(``),z(void 0),j(void 0),L(!1);try{let a=c(n.currentTarget,h),s=await d(o(e,t)+`/dev-token`,{},i.signal);if(!B.current||i.signal.aborted)return;V.current=T({url:s.url,getToken:()=>s.token});let l=performance.now(),u=await V.current[m.kind](w(r,m.kind),a);B.current&&!i.signal.aborted&&(j(u),L(!0),z(Math.round(performance.now()-l)))}catch(e){B.current&&!i.signal.aborted&&k(l(e))}finally{V.current?.dispose(),H.current===i&&(H.current=void 0),B.current&&D(!1)}},children:(0,P.jsx)(s,{items:h})}),(0,P.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Development execution only. Mutations and actions can change data. Live subscriptions use the SDK. Writes are not automatically retried. Internal functions are called only by server capabilities or scheduled jobs, not this HTTP runner.`})]}),(0,P.jsxs)(`section`,{className:`space-y-4 p-4`,children:[(0,P.jsxs)(`div`,{className:`flex justify-between`,children:[(0,P.jsx)(`h3`,{className:`text-sm font-medium`,children:`Result`}),(0,P.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:E?`Running…`:O?`Failed`:R===void 0?`Not executed`:`Completed · ${R} ms round trip`})]}),O?(0,P.jsx)(p,{children:O}):F?(0,P.jsx)(i,{value:A}):(0,P.jsx)(u,{title:`Run this function to see its result`,children:(0,P.jsx)(b,{className:`mx-auto mt-3 size-7`})})]})]})}),(0,P.jsxs)(x,{value:`contract`,className:`space-y-4 p-4`,children:[(0,P.jsxs)(`section`,{className:`space-y-3`,children:[(0,P.jsx)(`h3`,{className:`text-sm font-medium`,children:`Input contract`}),(0,P.jsx)(i,{value:m.input})]}),(0,P.jsxs)(`section`,{className:`space-y-3`,children:[(0,P.jsx)(`h3`,{className:`text-sm font-medium`,children:`Output contract`}),(0,P.jsx)(i,{value:m.output})]})]})]})]})}export{I as canRun,F as default};
@@ -1,3 +1,3 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["_astro/services-view.B7BR4JD3.js","_astro/client.BeKNsjPN.js","_astro/common.9pujiaSZ.js","_astro/client.BSf433s6.js","_astro/data-view.jmNzQKhW.js","_astro/input-group.Dsc4z0iT.js","_astro/functions-view.Bqamd_KY.js","_astro/ai-view.D6ouaMiL.js","_astro/auth-view.0CuFK-xf.js","_astro/settings-view.DM-igZ4O.js","_astro/sdk-view.DuMOEfZu.js","_astro/cli-approval.emPTVRqn.js"])))=>i.map(i=>d[i]);
2
- import{a as e,r as t,t as n}from"./client.BeKNsjPN.js";import{$ as r,A as i,At as a,B as o,C as s,Ct as c,D as l,Dt as u,E as d,Et as f,F as p,G as m,H as h,I as g,J as _,K as v,L as y,M as b,N as x,O as S,Ot as C,P as w,Q as T,S as E,St as D,T as O,Tt as k,U as A,V as j,W as M,X as N,Y as ee,Z as P,_ as F,_t as I,a as L,at as R,b as z,bt as te,dt as ne,et as B,ft as re,g as V,gt as H,h as ie,ht as ae,it as U,j as oe,k as se,kt as ce,lt as le,m as ue,mt as W,n as de,nt as fe,o as pe,ot as me,p as G,pt as K,q as he,r as ge,rt as _e,s as q,t as ve,tt as ye,u as J,ut as be,v as xe,vt as Se,w as Ce,wt as we,x as Te,xt as Ee,y as Y,yt as De,z as Oe}from"./common.9pujiaSZ.js";var ke={name:`activity`,size:24,node:[[`path`,{d:`M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2`,key:`169zse`}]]};ke.node;var Ae=C(ke),je={name:`box`,size:24,node:[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]};je.node;var Me=C(je),Ne={name:`code`,size:24,node:[[`path`,{d:`m16 18 6-6-6-6`,key:`eg8j8`}],[`path`,{d:`m8 6-6 6 6 6`,key:`ppft3o`}]]};Ne.node;var Pe=C(Ne),Fe={name:`database`,size:24,node:[[`ellipse`,{cx:`12`,cy:`5`,rx:`9`,ry:`3`,key:`msslwz`}],[`path`,{d:`M3 5V19A9 3 0 0 0 21 19V5`,key:`1wlel7`}],[`path`,{d:`M3 12A9 3 0 0 0 21 12`,key:`mv7ke4`}]]};Fe.node;var Ie=C(Fe),Le={name:`file`,size:24,node:[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}]]};Le.node;var Re=C(Le),ze={name:`logs`,size:24,node:[[`path`,{d:`M3 5h1`,key:`1mv5vm`}],[`path`,{d:`M3 12h1`,key:`lp3yf2`}],[`path`,{d:`M3 19h1`,key:`w6f3n9`}],[`path`,{d:`M8 5h1`,key:`1nxr5w`}],[`path`,{d:`M8 12h1`,key:`1con00`}],[`path`,{d:`M8 19h1`,key:`k7p10e`}],[`path`,{d:`M13 5h8`,key:`a7qcls`}],[`path`,{d:`M13 12h8`,key:`h98zly`}],[`path`,{d:`M13 19h8`,key:`c3s6r1`}]]};ze.node;var Be=C(ze),Ve={name:`panel-left-close`,size:24,node:[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M9 3v18`,key:`fh3hqa`}],[`path`,{d:`m16 15-3-3 3-3`,key:`14y99z`}]],aliases:[`sidebar-close`]};Ve.node;var He=C(Ve),Ue={name:`panel-left-open`,size:24,node:[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M9 3v18`,key:`fh3hqa`}],[`path`,{d:`m14 9 3 3-3 3`,key:`8010ee`}]],aliases:[`sidebar-open`]};Ue.node;var We=C(Ue),Ge={name:`plus`,size:24,node:[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]};Ge.node;var Ke=C(Ge),qe={name:`refresh-cw`,size:24,node:[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]};qe.node;var Je=C(qe),Ye={name:`search`,size:24,node:[[`path`,{d:`m21 21-4.34-4.34`,key:`14j7rj`}],[`circle`,{cx:`11`,cy:`11`,r:`8`,key:`4ej97u`}]]};Ye.node;var Xe=C(Ye),Ze={name:`settings`,size:24,node:[[`path`,{d:`M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915`,key:`1i5ecw`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]};Ze.node;var Qe=C(Ze),$e={name:`shield`,size:24,node:[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]};$e.node;var et=C($e),tt={name:`timer`,size:24,node:[[`line`,{x1:`10`,x2:`14`,y1:`2`,y2:`2`,key:`14vaq8`}],[`line`,{x1:`12`,x2:`15`,y1:`14`,y2:`11`,key:`17fdiu`}],[`circle`,{cx:`12`,cy:`14`,r:`8`,key:`1e1u0o`}]]};tt.node;var nt=C(tt),X=e(t(),1),rt=X.createContext(void 0);function it(){let e=X.useContext(rt);if(e===void 0)throw Error(we(64));return e}var at=`data-activation-direction`,ot={tabActivationDirection:e=>({[at]:e})},Z=a(),st=X.forwardRef(function(e,t){let{className:n,defaultValue:r=0,onValueChange:i,orientation:a=`horizontal`,render:o,value:s,style:c,...l}=e,d=e.defaultValue!==void 0,p=X.useRef([]),[h,g]=X.useState(()=>new Map),[y,b]=v({controlled:s,default:r,name:`Tabs`,state:`value`}),x=s!==void 0,[S,C]=X.useState(()=>new Map),w=X.useRef(void 0),E=X.useCallback(e=>ct(S,e),[S]),[D,O]=X.useState(()=>({previousValue:y,tabActivationDirection:`none`})),{previousValue:k,tabActivationDirection:A}=D,j=A,M=!1;k!==y&&(j=lt(k,y,a,S),M=k!=null&&y!=null&&E(y)==null);let P=M?k:y,F=k!==P||A!==j;f(()=>{F&&O({previousValue:P,tabActivationDirection:j})},[P,F,j]);let I=u((e,t)=>{t.activationDirection=lt(y,e,a,S),i?.(e,t),!t.isCanceled&&b(()=>e)}),L=u((e,t)=>{i?.(e,T(t,void 0,void 0,{activationDirection:`none`}))}),R=u((e,t)=>(g(n=>{let r=new Map(n);return r.set(e,t),r}),()=>{g(n=>{if(n.get(e)!==t)return n;let r=new Map(n);return r.delete(e),r})})),z=X.useCallback(e=>h.get(e),[h]),te=X.useCallback(e=>{for(let t of S.values())if(e===t.value)return t.id},[S]),ne=X.useMemo(()=>({getTabElementBySelectedValue:E,getTabIdByPanelValue:te,getTabPanelIdByValue:z,onValueChange:I,orientation:a,registerMountedTabPanel:R,setTabMap:C,tabActivationDirection:j,value:y}),[E,te,z,I,a,R,C,j,y]),B=X.useMemo(()=>{for(let e of S.values())if(e.value===y)return e},[S,y]),re=X.useMemo(()=>{for(let e of S.values())if(!e.disabled)return e.value},[S]),V=X.useRef(!d),ie=X.useRef(r),ae=X.useRef(d),U=X.useRef(!1);f(()=>{if(x)return;function e(e,t){b(()=>e),O({previousValue:e,tabActivationDirection:`none`}),L(e,t),V.current=!1}if(S.size===0){U.current&&y!==null&&!w.current?.isConnected&&e(null,N);return}U.current=!0,w.current=S.keys().next().value;let t=B?.disabled,n=B==null&&y!==null;if(!t&&y===ie.current&&(ae.current=!1),ae.current&&t&&y===ie.current)return;let r=V.current;if(t||n){let n=re??null;if(y===n){V.current=!1;return}let i=N;r?i=ee:t&&(i=_),e(n,i)}else r&&B!=null&&(L(y,ee),V.current=!1)},[re,x,L,B,b,S,y]);let oe=H(`div`,e,{state:{orientation:a,tabActivationDirection:j},ref:t,props:l,stateAttributesMapping:ot});return(0,Z.jsx)(rt.Provider,{value:ne,children:(0,Z.jsx)(m,{elementsRef:p,children:oe})})});function ct(e,t){for(let[n,r]of e.entries())if(t===r.value)return n;return null}function lt(e,t,n,r){if(e==null||t==null)return`none`;let[i,a,o]=n===`horizontal`?[`left`,`left`,`right`]:[`top`,`up`,`down`],s=ct(r,e),c=ct(r,t);if(s==null||c==null)return s!==c&&(typeof e==`number`||typeof e==`string`)&&typeof e==typeof t?t>e?o:a:`none`;let l=s.getBoundingClientRect()[i],u=c.getBoundingClientRect()[i];return u<l?a:u>l?o:`none`}var ut=`data-composite-item-active`;function dt(e={}){let{highlightItemOnHover:t,highlightedIndex:n,onHighlightedIndexChange:r}=c(),{ref:i,index:a}=M(e),o=n===a,s=X.useRef(null),l=De(i,s);return{compositeProps:{tabIndex:o?0:-1,onFocus(){r(a)},onMouseMove(){let e=s.current;if(!t||!e)return;let n=e.hasAttribute(`disabled`)||e.ariaDisabled===`true`;!o&&!n&&e.focus()}},compositeRef:l,index:a}}var ft=X.createContext(void 0);function pt(){let e=X.useContext(ft);if(e===void 0)throw Error(we(65));return e}var mt=X.forwardRef(function(e,t){let{className:n,disabled:r=!1,render:i,value:a,id:o,nativeButton:s=!0,style:l,...d}=e,{value:p,getTabPanelIdByValue:m,onValueChange:h,orientation:g,tabActivationDirection:_}=it(),{activateOnFocus:v,registerTabResizeObserverElement:y,tabsListElement:b}=pt(),{highlightedIndex:x,onHighlightedIndexChange:S}=c(),C=re(o),{compositeProps:w,compositeRef:E,index:D}=dt({metadata:X.useMemo(()=>({disabled:r,id:C,value:a}),[r,C,a])}),O=a===p,k=X.useRef(!1),A=X.useRef(null),j=u(e=>{A.current?.(),A.current=e?y(e):null});f(()=>{if(k.current){k.current=!1;return}if(!(O&&D>-1&&x!==D))return;let e=b;if(e!=null){let t=le(Ee(e));if(t&&be(e,t))return}r||S(D)},[O,D,x,S,r,b]);let{getButtonProps:M,buttonRef:N}=te({disabled:r,native:s,focusableWhenDisabled:!0}),ee=m(a),F=X.useRef(!1),I=X.useRef(!1);function L(e){h(a,T(P,e.nativeEvent,void 0,{activationDirection:`none`}))}function R(e){O||r||L(e)}function z(e){O||r||v&&(!F.current||I.current)&&L(e)}function ne(e){if(O||r)return;F.current=!0,I.current=e.button===0;let t=Ee(e.currentTarget);function n(){F.current=!1,I.current=!1,t.removeEventListener(`pointerup`,n),t.removeEventListener(`pointercancel`,n)}t.addEventListener(`pointerup`,n),t.addEventListener(`pointercancel`,n)}return H(`button`,e,{state:{disabled:r,active:O,orientation:g,tabActivationDirection:_},ref:[t,N,E,j],props:[w,{role:`tab`,"aria-controls":ee,"aria-selected":O,id:C,onClick:R,onFocus:z,onPointerDown:ne,[ut]:O?``:void 0,onKeyDownCapture(){k.current=!0}},d,M],stateAttributesMapping:ot})}),ht=`data-index`,gt={...ot,...me},_t=X.forwardRef(function(e,t){let{className:n,value:i,render:a,keepMounted:o=!1,style:s,...c}=e,{value:l,getTabIdByPanelValue:u,orientation:d,tabActivationDirection:p,registerMountedTabPanel:m}=it(),h=re(),{ref:g,index:_}=M(),v=i===l,{mounted:y,transitionStatus:b,setMounted:x}=r(v),S=!y,C=u(i),w={hidden:S,orientation:d,tabActivationDirection:p,transitionStatus:b},T=X.useRef(null),E=H(`div`,e,{state:w,ref:[t,g,T],props:[{"aria-labelledby":C,hidden:S,id:h,role:`tabpanel`,tabIndex:v?0:-1,inert:A(!v),[ht]:_},c],stateAttributesMapping:gt});return B({open:v,ref:T,onComplete(){v||x(!1)}}),f(()=>{if(!(h==null||S&&!o))return m(i,h)},[S,o,i,h,m]),o||y?E:null});function vt(e){let{loopFocus:t=!0,orientation:n=`both`,grid:r,onLoop:i,direction:a,highlightedIndex:s,onHighlightedIndexChange:c,rootRef:l,enableHomeAndEndKeys:d=!1,stopEventPropagation:m,disabledIndices:_,modifierKeys:v=I}=e,[b,S]=X.useState(0),C=r!=null,T=X.useRef(null),E=De(T,l),D=X.useRef([]),O=X.useRef(!1),k=X.useRef(null),A=s??b,M=u((e,t=!1)=>{if(k.current=D.current[e]??null,(c??S)(e),t){let t=D.current[e];j(T.current,t,a,n)}}),N=u(e=>{if(e.size===0)return;if(O.current){let e=D.current,t=e.indexOf(k.current);if(t===-1){let t=e[A];!t||R(e,A,_)?M(yt(e,_)):k.current=t}else t!==A&&M(t);return}O.current=!0;let t=Array.from(e.keys()),r=t.find(e=>e?.hasAttribute(`data-composite-item-active`))??null,i=r?e.get(r)?.index??-1:-1;if(i!==-1)M(i);else if(R(t,A,_)){let e=ye(t,{disabledIndices:_});U(t,e)||M(e)}j(T.current,r,a,n)});f(()=>{if(_==null||s!=null||!O.current)return;let e=D.current;if(R(e,A,_)){let t=ye(e,{disabledIndices:_});U(e,t)||M(t)}},[_,s,A,D,M]);let ee=u((e,t,n)=>i?i(e,t,n,D):n),P=u(e=>{let s=e.key===`Home`||e.key===`End`;if(!y.has(e.key)||!d&&s||bt(e,v)||!T.current)return;let c=a===`rtl`,l=c?w:p,u=c?p:w,f=n===`vertical`?x:l,b=n===`vertical`?g:u,S=ne(e.nativeEvent);if(S!=null&&o(S)&&!h(S)){let t=S.selectionStart,n=S.selectionEnd,r=S.value;if(t==null||e.shiftKey||t!==n||e.key!==b&&t<r.length||e.key!==f&&t>0)return}let E=A,O=_e(D,_),k=fe(D,_);r!=null&&(E=r({disabledIndices:_,elementsRef:D,event:e,highlightedIndex:A,loopFocus:t,maxIndex:k,minIndex:O,onLoop:ee,orientation:n,rtl:c}));let j=n!==`vertical`&&e.key===l||n!==`horizontal`&&e.key===`ArrowDown`,N=n!==`vertical`&&e.key===u||n!==`horizontal`&&e.key===`ArrowUp`;d&&(e.key===`Home`?E=O:e.key===`End`&&(E=k)),E===A&&(j||N)&&(t&&E===k&&j?(E=O,i&&(E=i(e,A,E,D))):t&&E===O&&N?(E=k,i&&(E=i(e,A,E,D))):E=ye(D.current,{startingIndex:E,decrement:N,disabledIndices:_})),E!==A&&!U(D.current,E)&&(m&&e.stopPropagation(),(C||s||j||N)&&e.preventDefault(),M(E,!0),queueMicrotask(()=>{D.current[E]?.focus()}))});return{props:{ref:E,onFocus(e){let t=T.current,n=ne(e.nativeEvent);t&&n!=null&&o(n)&&n.setSelectionRange(0,n.value.length)},onKeyDown:P},highlightedIndex:A,onHighlightedIndexChange:M,elementsRef:D,onMapChange:N,relayKeyboardEvent:P}}function yt(e,t){let n=-1;for(let r=0;r<e.length;r+=1){let i=e[r];if(i&&!R(e,r,t)){if(i.hasAttribute(`data-composite-item-active`))return r;n===-1&&(n=r)}}return Math.max(n,0)}function bt(e,t){for(let n of Oe)if(!t.includes(n)&&e.getModifierState(n))return!0;return!1}function xt(e){let{render:t,className:n,style:r,refs:i=I,props:a=I,state:o=Se,stateAttributesMapping:s,highlightedIndex:c,onHighlightedIndexChange:l,orientation:u,grid:d,loopFocus:f,onLoop:p,enableHomeAndEndKeys:h,onMapChange:g,stopEventPropagation:_=!0,rootRef:v,disabledIndices:y,modifierKeys:x,highlightItemOnHover:S=!1,tag:C=`div`,...w}=e,{props:T,highlightedIndex:E,onHighlightedIndexChange:O,elementsRef:k,onMapChange:A,relayKeyboardEvent:j}=vt({grid:d,loopFocus:f,onLoop:p,orientation:u,highlightedIndex:c,onHighlightedIndexChange:l,rootRef:v,stopEventPropagation:_,enableHomeAndEndKeys:h,direction:b(),disabledIndices:y,modifierKeys:x}),M=H(C,e,{state:o,ref:i,props:[T,...a,w],stateAttributesMapping:s}),N=X.useMemo(()=>({highlightedIndex:E,onHighlightedIndexChange:O,highlightItemOnHover:S,relayKeyboardEvent:j}),[E,O,S,j]);return(0,Z.jsx)(D.Provider,{value:N,children:(0,Z.jsx)(m,{elementsRef:k,onMapChange:e=>{g?.(e),A(e)},children:M})})}var St=X.forwardRef(function(e,t){let{activateOnFocus:n=!1,className:r,loopFocus:i=!0,render:a,style:o,...s}=e,{orientation:c,setTabMap:l,tabActivationDirection:d}=it(),[p,m]=X.useState(0),[h,g]=X.useState(null),_=X.useRef(new Set),v=X.useRef(new Set),y=X.useRef(null);f(()=>{if(typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>{_.current.forEach(e=>{e()})});return y.current=e,h&&e.observe(h),v.current.forEach(t=>{e.observe(t)}),()=>{e.disconnect(),y.current=null}},[h]);let b=u(e=>(_.current.add(e),()=>{_.current.delete(e)})),x=u(e=>(v.current.add(e),y.current?.observe(e),()=>{v.current.delete(e),y.current?.unobserve(e)})),S={orientation:c,tabActivationDirection:d},C={"aria-orientation":c===`vertical`?`vertical`:void 0,role:`tablist`},w=X.useMemo(()=>({activateOnFocus:n,registerIndicatorUpdateListener:b,registerTabResizeObserverElement:x,tabsListElement:h}),[n,b,x,h]);return(0,Z.jsx)(ft.Provider,{value:w,children:(0,Z.jsx)(xt,{render:a,className:r,style:o,state:S,refs:[t,g],props:[C,s],stateAttributesMapping:ot,highlightedIndex:p,enableHomeAndEndKeys:!0,loopFocus:i,orientation:c,onHighlightedIndexChange:m,onMapChange:l,disabledIndices:I})})}),Ct=n();function wt({className:e,orientation:t=`horizontal`,...n}){return(0,Z.jsx)(st,{"data-slot":`tabs`,"data-orientation":t,className:W(`group/tabs flex gap-2 data-horizontal:flex-col`,e),...n})}var Tt=ae(`group/tabs-list inline-flex w-fit items-center justify-center rounded-none p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none`,{variants:{variant:{default:`bg-muted`,line:`gap-1 bg-transparent`}},defaultVariants:{variant:`default`}});function Et({className:e,variant:t=`default`,...n}){return(0,Z.jsx)(St,{"data-slot":`tabs-list`,"data-variant":t,className:W(Tt({variant:t}),e),...n})}function Dt({className:e,...t}){return(0,Z.jsx)(mt,{"data-slot":`tabs-trigger`,className:W(`relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-none border border-transparent px-1.5 py-0.5 text-xs font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start group-data-vertical/tabs:py-[calc(--spacing(1.25))] hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,`group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent`,`data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground`,`after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100`,e),...t})}function Ot({className:e,...t}){return(0,Z.jsx)(_t,{"data-slot":`tabs-content`,className:W(`flex-1 text-xs/relaxed outline-none`,e),...t})}function kt(e){return H(e.defaultTagName??`div`,e,e)}var At=ae(`group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-none border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!`,{variants:{variant:{default:`bg-primary text-primary-foreground [a]:hover:bg-primary/80`,secondary:`bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80`,success:`border-emerald-600/20 bg-emerald-100/50 text-emerald-700 dark:border-emerald-400/20 dark:bg-emerald-900/50 dark:text-emerald-200`,warning:`border-amber-600/20 bg-amber-100/50 text-amber-700 dark:border-amber-400/20 dark:bg-amber-900/50 dark:text-amber-200`,info:`border-blue-600/20 bg-blue-100/50 text-blue-700 dark:border-blue-400/20 dark:bg-blue-900/50 dark:text-blue-200`,destructive:`bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20`,outline:`border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground`,ghost:`hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50`,link:`text-primary underline-offset-4 hover:underline`}},defaultVariants:{variant:`default`}});function jt({className:e,variant:t=`default`,render:n,...r}){return kt({defaultTagName:`span`,props:k({className:W(At({variant:t}),e)},r),render:n,state:{slot:`badge`,variant:t}})}var Mt=new Map([...[`ready`,`active`,`enabled`,`ok`,`completed`,`development`].map(e=>[e,`success`]),...[`pending`,`paused`,`activating`,`restoring`,`incomplete`,`required`].map(e=>[e,`warning`]),...[`uploading`,`running`,`queued`,`enqueued`,`production`,`public registration`,`public`].map(e=>[e,`info`]),...[`error`,`failed`,`blocked`,`unavailable`].map(e=>[e,`destructive`])]);function Q({status:e,children:t}){return(0,Z.jsx)(jt,{variant:Mt.get(e.toLowerCase())??`secondary`,children:t??e})}var Nt={query:`bg-yellow-100/50 text-yellow-700 dark:bg-yellow-900/50 dark:text-yellow-200`,mutation:`bg-blue-100/50 text-blue-700 dark:bg-blue-900/50 dark:text-blue-200`,action:`bg-purple-100/50 text-purple-700 dark:bg-purple-900/50 dark:text-purple-200`};function Pt({kind:e}){return(0,Z.jsx)(jt,{variant:`secondary`,className:Nt[e],children:e})}function Ft(e){let[t,n]=(0,X.useState)(!1);return(0,Z.jsxs)(`details`,{className:`rounded-lg border`,onToggle:e=>n(e.currentTarget.open),children:[(0,Z.jsx)(`summary`,{className:`cursor-pointer p-4 font-medium`,children:`Deployment history`}),t&&(0,Z.jsx)(`div`,{className:`p-4 pt-0`,children:(0,Z.jsx)(It,{...e})})]})}function It(e){let[t,n]=(0,X.useState)(),[r,i]=(0,X.useState)(),a=V(e.project,e.env),o=V(e.project,e.env),s=J(a+`/history`),c=e.session.role!==`viewer`,l=async(t,n)=>{let r=n?V(e.project,`prod`):o,a=await G(r+`/health`);i({title:n?`Promote backend to production`:`Rollback backend`,description:`Activate this exact backend hash after native schema/job validation. Data, files and settings stay unchanged. Frontend is not published by this button; use the CLI release flow for that.`,productionId:n||e.env===`prod`?e.project.id:void 0,submit:async()=>{await G(r+(n?`/release-promote`:`/release-rollback`),{hash:t,expected:a.active,confirm:e.project.id}),s.refresh(),e.refresh()}})},[u,d]=(0,X.useState)();return(0,Z.jsxs)(`div`,{className:`space-y-3`,children:[(0,Z.jsx)(q,{loading:s.loading,error:u||s.error}),(0,Z.jsxs)(F,{children:[(0,Z.jsx)(Te,{children:(0,Z.jsxs)(E,{children:[(0,Z.jsx)(z,{children:`First published`}),(0,Z.jsx)(z,{children:`Backend hash`}),(0,Z.jsx)(z,{children:`Actions`})]})}),(0,Z.jsx)(xe,{children:s.data?.map(t=>(0,Z.jsxs)(E,{children:[(0,Z.jsx)(Y,{children:new Date(t.at).toLocaleString()}),(0,Z.jsxs)(Y,{children:[(0,Z.jsx)(`code`,{className:`text-xs`,children:t.hash.slice(0,12)}),e.active===t.hash&&(0,Z.jsx)(Q,{status:`Active`})]}),(0,Z.jsx)(Y,{children:(0,Z.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,Z.jsx)(K,{variant:`outline`,size:`sm`,onClick:()=>n(t.hash),children:`View contracts`}),c&&e.active!==t.hash&&(0,Z.jsx)(K,{variant:`outline`,size:`sm`,onClick:()=>void l(t.hash,!1).catch(e=>d(e.message)),children:`Rollback backend`}),c&&e.env===`dev`&&(0,Z.jsx)(K,{variant:`outline`,size:`sm`,onClick:()=>void l(t.hash,!0).catch(e=>d(e.message)),children:`Promote backend`})]})})]},t.hash))})]}),t&&(0,Z.jsx)(Lt,{path:a,hash:t,close:()=>n(void 0)}),r&&(0,Z.jsx)(L,{modal:r,onClose:()=>i(void 0)})]})}function Lt({path:e,hash:t,close:n}){let r=J(e+`/release?hash=`+t);return(0,Z.jsx)(s,{open:!0,onOpenChange:e=>{e||n()},children:(0,Z.jsxs)(Ce,{className:`max-h-[80vh] overflow-auto`,children:[(0,Z.jsxs)(d,{children:[(0,Z.jsx)(l,{children:`Backend release`}),(0,Z.jsx)(O,{className:`break-all`,children:t})]}),(0,Z.jsx)(q,{...r}),r.data&&(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsx)(`h3`,{className:`font-medium`,children:`Tables`}),(0,Z.jsxs)(F,{children:[(0,Z.jsx)(Te,{children:(0,Z.jsxs)(E,{children:[(0,Z.jsx)(z,{children:`Table`}),(0,Z.jsx)(z,{children:`Fields`})]})}),(0,Z.jsx)(xe,{children:Object.entries(r.data.schema).map(([e,t])=>(0,Z.jsxs)(E,{children:[(0,Z.jsx)(Y,{children:e}),(0,Z.jsx)(Y,{children:Object.keys(t.document.properties??{}).join(`, `)||`No declared fields`})]},e))})]}),(0,Z.jsx)(`h3`,{className:`font-medium`,children:`Functions`}),(0,Z.jsxs)(F,{children:[(0,Z.jsx)(Te,{children:(0,Z.jsxs)(E,{children:[(0,Z.jsx)(z,{children:`Function`}),(0,Z.jsx)(z,{children:`Kind`}),(0,Z.jsx)(z,{children:`Access`})]})}),(0,Z.jsx)(xe,{children:Object.entries(r.data.manifest.functions).map(([e,t])=>(0,Z.jsxs)(E,{children:[(0,Z.jsx)(Y,{children:e}),(0,Z.jsx)(Y,{children:(0,Z.jsx)(Pt,{kind:t.kind})}),(0,Z.jsx)(Y,{children:(0,Z.jsx)(Q,{status:t.auth})})]},e))})]})]})]})})}function Rt({className:e,size:t=`default`,...n}){return(0,Z.jsx)(`div`,{"data-slot":`card`,"data-size":t,className:W(`group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-none bg-card py-(--card-spacing) text-xs/relaxed text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-none *:[img:last-child]:rounded-none`,e),...n})}function zt({className:e,...t}){return(0,Z.jsx)(`div`,{"data-slot":`card-header`,className:W(`group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-none px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)`,e),...t})}function Bt({className:e,...t}){return(0,Z.jsx)(`div`,{"data-slot":`card-title`,className:W(`font-heading text-sm font-medium group-data-[size=sm]/card:text-sm`,e),...t})}function Vt({className:e,...t}){return(0,Z.jsx)(`div`,{"data-slot":`card-content`,className:W(`px-(--card-spacing)`,e),...t})}function Ht({project:e,env:t,session:n,connect:r}){let i=J(V(e,t)+`/health`),a=J(V(e,t)+`/settings`);return(0,Z.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,Z.jsx)(`h1`,{className:`page-title`,children:`Health`}),(0,Z.jsx)(q,{loading:i.loading||a.loading,error:i.error||a.error}),i.data&&a.data&&(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsx)(`h2`,{className:`section-title`,children:`Summary`}),(0,Z.jsx)(Rt,{children:(0,Z.jsxs)(Vt,{className:`grid gap-4 md:grid-cols-2`,children:[(0,Z.jsxs)(`div`,{className:`space-y-3`,children:[(0,Z.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,Z.jsx)(Q,{status:t===`dev`?`Development`:`Production`}),(0,Z.jsx)(`strong`,{children:e.name})]}),(0,Z.jsx)(`p`,{className:`text-muted-foreground`,children:`Cloudflare · Durable Objects · SQLite`}),(0,Z.jsxs)(`p`,{className:`font-mono text-xs text-muted-foreground`,children:[`Release `,i.data.active?.slice(0,12)??`not deployed`]})]}),(0,Z.jsxs)(`div`,{className:`space-y-2`,children:[(0,Z.jsx)(`p`,{className:`text-muted-foreground`,children:`Cloud URL`}),(0,Z.jsx)(`code`,{className:`block select-all break-all text-xs`,children:a.data.url}),(0,Z.jsxs)(`div`,{className:`flex items-center gap-2 text-muted-foreground`,children:[(0,Z.jsx)(Q,{status:i.data.status}),i.data.connections,` connections · `,i.data.subscriptions,` `,`subscriptions`]})]})]})}),(0,Z.jsx)(Ft,{project:e,env:t,session:n,active:i.data.active,refresh:i.refresh}),(0,Z.jsx)(K,{variant:`outline`,onClick:r,children:`Connect SDK`})]})]})}function Ut({project:e,env:t}){let n=J(V(e,t)+`/schema`);return(0,Z.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,Z.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,Z.jsx)(`h1`,{className:`page-title`,children:`Schema`}),(0,Z.jsx)(`div`,{className:`flex gap-2`,children:(0,Z.jsx)(K,{variant:`ghost`,size:`icon-sm`,"aria-label":`Reload snapshot`,title:`Reload snapshot`,onClick:n.refresh,disabled:n.loading,children:(0,Z.jsx)(Je,{})})})]}),(0,Z.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Defined in code; validated documents and indexes activate atomically. System tables are hidden.`}),(0,Z.jsx)(q,{...n}),n.data?.tables.map(e=>(0,Z.jsxs)(Rt,{children:[(0,Z.jsx)(zt,{children:(0,Z.jsx)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:(0,Z.jsx)(Bt,{className:`font-mono`,children:e.name})})}),(0,Z.jsxs)(Vt,{className:`space-y-4`,children:[(0,Z.jsx)(pe,{rows:e.columns.map(e=>({Field:e.name,Type:e.type,Required:!!e.notnull,Primary:!!e.pk,Default:e.dflt_value})),columns:[`Field`,`Type`,`Required`,`Primary`,`Default`]}),(0,Z.jsx)(pe,{rows:Object.entries(e.indexes).map(([e,t])=>({Index:e,Fields:t.join(`, `)})),columns:[`Index`,`Fields`]}),(0,Z.jsxs)(`details`,{children:[(0,Z.jsx)(`summary`,{className:`cursor-pointer text-muted-foreground`,children:`Document contract`}),(0,Z.jsx)(`pre`,{className:`code-block mt-3`,children:JSON.stringify(e.document,null,2)})]})]})]},e.name)),n.data&&!n.data.tables.length&&(0,Z.jsx)(de,{title:`No application tables`})]})}function Wt({project:e,env:t}){let n=J(V(e,t)+`/logs`);return(0,Z.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,Z.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,Z.jsx)(`h1`,{className:`page-title`,children:`Logs`}),(0,Z.jsx)(K,{variant:`ghost`,size:`icon-sm`,"aria-label":`Reload snapshot`,title:`Reload snapshot`,onClick:n.refresh,disabled:n.loading,children:(0,Z.jsx)(Je,{})})]}),(0,Z.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Last 100 invocation summaries. Successful queries are held in memory and disappear on hibernation/restart; writes and failures are persisted. Not Cloudflare Tail logs or billing analytics.`}),(0,Z.jsx)(q,{...n}),n.data&&(n.data.length?(0,Z.jsx)(pe,{rows:n.data,renderCell:(e,t)=>e===`kind`&&[`query`,`mutation`,`action`].includes(String(t))?(0,Z.jsx)(Pt,{kind:t}):e===`status`?(0,Z.jsx)(Q,{status:t===`ok`?`ok`:`error`,children:ie(t)}):e===`at`&&typeof t==`number`?new Date(t).toLocaleString():ie(t),columns:[`at`,`path`,`kind`,`status`,`ms`],labels:{at:`Time`,path:`Function`,kind:`Type`,status:`Status`,ms:`Duration (ms)`}}):(0,Z.jsx)(de,{title:`No recent function calls`}))]})}var Gt=(function(){let e=typeof document<`u`&&document.createElement(`link`).relList;return e&&e.supports&&e.supports(`modulepreload`)?`modulepreload`:`preload`})(),Kt=function(e){return`/`+e},qt={},Jt=function(e){return e.pathname.endsWith(`.css`)},Yt=function(e,t,n){if(t in e)return e[t];let r=n();if(!r){e[t]=void 0;return}let i=r.then(()=>{e[t]=void 0},n=>{throw e[t]=void 0,n});return e[t]=i,i},$=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=function(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))},i=function(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)},a,o=document.querySelector(`meta[property=csp-nonce]`),s=o?.nonce||o?.getAttribute(`nonce`);r=e(t.map(e=>{e=Kt(e,n);let t=i(e),r=Jt(t);return Yt(qt,t.href,()=>{if(a===void 0){a={all:new Set,styles:new Set};let e=document.getElementsByTagName(`link`);for(let t=e.length-1;t>=0;t--){let n=e[t];a.all.add(n.href),n.rel===`stylesheet`&&a.styles.add(n.href)}}if((r?a.styles:a.all).has(t.href))return;let e=document.createElement(`link`);if(e.rel=r?`stylesheet`:Gt,r||(e.as=`script`),e.crossOrigin=``,e.href=t.href,s&&e.setAttribute(`nonce`,s),document.head.appendChild(e),r)return new Promise((n,r)=>{e.addEventListener(`load`,n),e.addEventListener(`error`,()=>r(Error(`Unable to preload CSS for ${t}`)))})})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},Xt=(0,X.lazy)(()=>$(()=>import(`./services-view.B7BR4JD3.js`).then(e=>({default:e.FilesView})),__vite__mapDeps([0,1,2,3]))),Zt=(0,X.lazy)(()=>$(()=>import(`./services-view.B7BR4JD3.js`).then(e=>({default:e.SchedulesView})),__vite__mapDeps([0,1,2,3]))),Qt=(0,X.lazy)(()=>$(()=>import(`./data-view.jmNzQKhW.js`),__vite__mapDeps([4,1,2,5]))),$t=(0,X.lazy)(()=>$(()=>import(`./functions-view.Bqamd_KY.js`),__vite__mapDeps([6,1,2,3,5]))),en=(0,X.lazy)(()=>$(()=>import(`./ai-view.D6ouaMiL.js`),__vite__mapDeps([7,1,2,3]))),tn=(0,X.lazy)(()=>$(()=>import(`./auth-view.0CuFK-xf.js`),__vite__mapDeps([8,1,2]))),nn=(0,X.lazy)(()=>$(()=>import(`./settings-view.DM-igZ4O.js`),__vite__mapDeps([9,1,2]))),rn=(0,X.lazy)(()=>$(()=>import(`./sdk-view.DuMOEfZu.js`),__vite__mapDeps([10,1,2]))),an=[{key:`health`,label:`Health`,icon:Ae},{key:`data`,label:`Data`,icon:Ie},{key:`schema`,label:`Schema`,icon:Me},{key:`functions`,label:`Functions`,icon:Pe},{key:`files`,label:`Files`,icon:Re},{key:`schedules`,label:`Schedules`,icon:nt},{key:`ai`,label:`AI`,icon:Xe},{key:`auth`,label:`Auth`,icon:et},{key:`logs`,label:`Logs`,icon:Be}],on=(0,X.lazy)(()=>$(()=>import(`./cli-approval.emPTVRqn.js`),__vite__mapDeps([11,1,2])));function sn(){return new URLSearchParams(location.search).has(`cli`)?(0,Z.jsx)(X.Suspense,{fallback:(0,Z.jsx)(`p`,{children:`Loading…`}),children:(0,Z.jsx)(on,{})}):(0,Z.jsx)(cn,{})}function cn(){let[e,t]=(0,X.useState)(),[n,r]=(0,X.useState)([]),[a,o]=(0,X.useState)(),[s,c]=(0,X.useState)(`dev`),[l,u]=(0,X.useState)(`health`),[d,f]=(0,X.useState)(``),[p,m]=(0,X.useState)(!0),[h,g]=(0,X.useState)(),[_,v]=(0,X.useState)(!1);(0,X.useEffect)(()=>{let e=new AbortController;return v(localStorage.getItem(`flare.sidebar`)===`collapsed`),Promise.all([G(`session`,void 0,e.signal),G(`projects`,void 0,e.signal)]).then(([n,i])=>{e.signal.aborted||(t(n),r(i),o(i.find(e=>e.id===localStorage.getItem(`flare.project`))??i[0]),m(!1))}).catch(t=>{e.signal.aborted||(f(ue(t)),m(!1))}),()=>e.abort()},[]);let y=e=>{let t=n.find(t=>t.id===e);t&&(o(t),c(`dev`),u(`health`),g(void 0),localStorage.setItem(`flare.project`,e))},b=()=>g({title:`Create project`,description:`Creates separate development and production environments.`,content:(0,Z.jsxs)(se,{children:[(0,Z.jsxs)(S,{children:[(0,Z.jsx)(i,{htmlFor:`project-name`,children:`Project name`}),(0,Z.jsx)(he,{id:`project-name`,name:`name`,required:!0,maxLength:100,placeholder:`CRM`})]}),(0,Z.jsxs)(S,{children:[(0,Z.jsx)(i,{htmlFor:`project-alias`,children:`Short URL name (optional)`}),(0,Z.jsx)(he,{id:`project-alias`,name:`alias`,maxLength:48,pattern:`[a-z][a-z0-9]*(?:-[a-z0-9]+)*`,placeholder:`crm`})]}),(0,Z.jsxs)(S,{children:[(0,Z.jsx)(i,{htmlFor:`project-origins`,children:`Allowed frontend origins · one per line`}),(0,Z.jsx)(oe,{id:`project-origins`,name:`origins`,placeholder:`http://127.0.0.1:5173`})]})]}),submit:async e=>{let t=new FormData(e),n=await G(`projects`,{name:t.get(`name`),alias:t.get(`alias`)||void 0,origins:[location.origin,...String(t.get(`origins`)).split(`
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["_astro/services-view.Dx1rjMWa.js","_astro/client.BeKNsjPN.js","_astro/common.9pujiaSZ.js","_astro/client.BSf433s6.js","_astro/data-view.BFL2F3o9.js","_astro/input-group.Dsc4z0iT.js","_astro/functions-view.vsmqlnUa.js","_astro/ai-view.DcYKk5W_.js","_astro/auth-view.KnVtTZYn.js","_astro/settings-view.DPwEyqzv.js","_astro/sdk-view.BPVWrAC3.js","_astro/cli-approval.emPTVRqn.js"])))=>i.map(i=>d[i]);
2
+ import{a as e,r as t,t as n}from"./client.BeKNsjPN.js";import{$ as r,A as i,At as a,B as o,C as s,Ct as c,D as l,Dt as u,E as d,Et as f,F as p,G as m,H as h,I as g,J as _,K as v,L as y,M as b,N as x,O as S,Ot as C,P as w,Q as T,S as E,St as D,T as O,Tt as k,U as A,V as j,W as M,X as N,Y as ee,Z as P,_ as F,_t as I,a as L,at as R,b as z,bt as te,dt as ne,et as B,ft as re,g as V,gt as H,h as ie,ht as ae,it as U,j as oe,k as se,kt as ce,lt as le,m as ue,mt as W,n as de,nt as fe,o as pe,ot as me,p as G,pt as K,q as he,r as ge,rt as _e,s as q,t as ve,tt as ye,u as J,ut as be,v as xe,vt as Se,w as Ce,wt as we,x as Te,xt as Ee,y as Y,yt as De,z as Oe}from"./common.9pujiaSZ.js";var ke={name:`activity`,size:24,node:[[`path`,{d:`M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2`,key:`169zse`}]]};ke.node;var Ae=C(ke),je={name:`box`,size:24,node:[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]};je.node;var Me=C(je),Ne={name:`code`,size:24,node:[[`path`,{d:`m16 18 6-6-6-6`,key:`eg8j8`}],[`path`,{d:`m8 6-6 6 6 6`,key:`ppft3o`}]]};Ne.node;var Pe=C(Ne),Fe={name:`database`,size:24,node:[[`ellipse`,{cx:`12`,cy:`5`,rx:`9`,ry:`3`,key:`msslwz`}],[`path`,{d:`M3 5V19A9 3 0 0 0 21 19V5`,key:`1wlel7`}],[`path`,{d:`M3 12A9 3 0 0 0 21 12`,key:`mv7ke4`}]]};Fe.node;var Ie=C(Fe),Le={name:`file`,size:24,node:[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}]]};Le.node;var Re=C(Le),ze={name:`logs`,size:24,node:[[`path`,{d:`M3 5h1`,key:`1mv5vm`}],[`path`,{d:`M3 12h1`,key:`lp3yf2`}],[`path`,{d:`M3 19h1`,key:`w6f3n9`}],[`path`,{d:`M8 5h1`,key:`1nxr5w`}],[`path`,{d:`M8 12h1`,key:`1con00`}],[`path`,{d:`M8 19h1`,key:`k7p10e`}],[`path`,{d:`M13 5h8`,key:`a7qcls`}],[`path`,{d:`M13 12h8`,key:`h98zly`}],[`path`,{d:`M13 19h8`,key:`c3s6r1`}]]};ze.node;var Be=C(ze),Ve={name:`panel-left-close`,size:24,node:[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M9 3v18`,key:`fh3hqa`}],[`path`,{d:`m16 15-3-3 3-3`,key:`14y99z`}]],aliases:[`sidebar-close`]};Ve.node;var He=C(Ve),Ue={name:`panel-left-open`,size:24,node:[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M9 3v18`,key:`fh3hqa`}],[`path`,{d:`m14 9 3 3-3 3`,key:`8010ee`}]],aliases:[`sidebar-open`]};Ue.node;var We=C(Ue),Ge={name:`plus`,size:24,node:[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]};Ge.node;var Ke=C(Ge),qe={name:`refresh-cw`,size:24,node:[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]};qe.node;var Je=C(qe),Ye={name:`search`,size:24,node:[[`path`,{d:`m21 21-4.34-4.34`,key:`14j7rj`}],[`circle`,{cx:`11`,cy:`11`,r:`8`,key:`4ej97u`}]]};Ye.node;var Xe=C(Ye),Ze={name:`settings`,size:24,node:[[`path`,{d:`M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915`,key:`1i5ecw`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]};Ze.node;var Qe=C(Ze),$e={name:`shield`,size:24,node:[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]};$e.node;var et=C($e),tt={name:`timer`,size:24,node:[[`line`,{x1:`10`,x2:`14`,y1:`2`,y2:`2`,key:`14vaq8`}],[`line`,{x1:`12`,x2:`15`,y1:`14`,y2:`11`,key:`17fdiu`}],[`circle`,{cx:`12`,cy:`14`,r:`8`,key:`1e1u0o`}]]};tt.node;var nt=C(tt),X=e(t(),1),rt=X.createContext(void 0);function it(){let e=X.useContext(rt);if(e===void 0)throw Error(we(64));return e}var at=`data-activation-direction`,ot={tabActivationDirection:e=>({[at]:e})},Z=a(),st=X.forwardRef(function(e,t){let{className:n,defaultValue:r=0,onValueChange:i,orientation:a=`horizontal`,render:o,value:s,style:c,...l}=e,d=e.defaultValue!==void 0,p=X.useRef([]),[h,g]=X.useState(()=>new Map),[y,b]=v({controlled:s,default:r,name:`Tabs`,state:`value`}),x=s!==void 0,[S,C]=X.useState(()=>new Map),w=X.useRef(void 0),E=X.useCallback(e=>ct(S,e),[S]),[D,O]=X.useState(()=>({previousValue:y,tabActivationDirection:`none`})),{previousValue:k,tabActivationDirection:A}=D,j=A,M=!1;k!==y&&(j=lt(k,y,a,S),M=k!=null&&y!=null&&E(y)==null);let P=M?k:y,F=k!==P||A!==j;f(()=>{F&&O({previousValue:P,tabActivationDirection:j})},[P,F,j]);let I=u((e,t)=>{t.activationDirection=lt(y,e,a,S),i?.(e,t),!t.isCanceled&&b(()=>e)}),L=u((e,t)=>{i?.(e,T(t,void 0,void 0,{activationDirection:`none`}))}),R=u((e,t)=>(g(n=>{let r=new Map(n);return r.set(e,t),r}),()=>{g(n=>{if(n.get(e)!==t)return n;let r=new Map(n);return r.delete(e),r})})),z=X.useCallback(e=>h.get(e),[h]),te=X.useCallback(e=>{for(let t of S.values())if(e===t.value)return t.id},[S]),ne=X.useMemo(()=>({getTabElementBySelectedValue:E,getTabIdByPanelValue:te,getTabPanelIdByValue:z,onValueChange:I,orientation:a,registerMountedTabPanel:R,setTabMap:C,tabActivationDirection:j,value:y}),[E,te,z,I,a,R,C,j,y]),B=X.useMemo(()=>{for(let e of S.values())if(e.value===y)return e},[S,y]),re=X.useMemo(()=>{for(let e of S.values())if(!e.disabled)return e.value},[S]),V=X.useRef(!d),ie=X.useRef(r),ae=X.useRef(d),U=X.useRef(!1);f(()=>{if(x)return;function e(e,t){b(()=>e),O({previousValue:e,tabActivationDirection:`none`}),L(e,t),V.current=!1}if(S.size===0){U.current&&y!==null&&!w.current?.isConnected&&e(null,N);return}U.current=!0,w.current=S.keys().next().value;let t=B?.disabled,n=B==null&&y!==null;if(!t&&y===ie.current&&(ae.current=!1),ae.current&&t&&y===ie.current)return;let r=V.current;if(t||n){let n=re??null;if(y===n){V.current=!1;return}let i=N;r?i=ee:t&&(i=_),e(n,i)}else r&&B!=null&&(L(y,ee),V.current=!1)},[re,x,L,B,b,S,y]);let oe=H(`div`,e,{state:{orientation:a,tabActivationDirection:j},ref:t,props:l,stateAttributesMapping:ot});return(0,Z.jsx)(rt.Provider,{value:ne,children:(0,Z.jsx)(m,{elementsRef:p,children:oe})})});function ct(e,t){for(let[n,r]of e.entries())if(t===r.value)return n;return null}function lt(e,t,n,r){if(e==null||t==null)return`none`;let[i,a,o]=n===`horizontal`?[`left`,`left`,`right`]:[`top`,`up`,`down`],s=ct(r,e),c=ct(r,t);if(s==null||c==null)return s!==c&&(typeof e==`number`||typeof e==`string`)&&typeof e==typeof t?t>e?o:a:`none`;let l=s.getBoundingClientRect()[i],u=c.getBoundingClientRect()[i];return u<l?a:u>l?o:`none`}var ut=`data-composite-item-active`;function dt(e={}){let{highlightItemOnHover:t,highlightedIndex:n,onHighlightedIndexChange:r}=c(),{ref:i,index:a}=M(e),o=n===a,s=X.useRef(null),l=De(i,s);return{compositeProps:{tabIndex:o?0:-1,onFocus(){r(a)},onMouseMove(){let e=s.current;if(!t||!e)return;let n=e.hasAttribute(`disabled`)||e.ariaDisabled===`true`;!o&&!n&&e.focus()}},compositeRef:l,index:a}}var ft=X.createContext(void 0);function pt(){let e=X.useContext(ft);if(e===void 0)throw Error(we(65));return e}var mt=X.forwardRef(function(e,t){let{className:n,disabled:r=!1,render:i,value:a,id:o,nativeButton:s=!0,style:l,...d}=e,{value:p,getTabPanelIdByValue:m,onValueChange:h,orientation:g,tabActivationDirection:_}=it(),{activateOnFocus:v,registerTabResizeObserverElement:y,tabsListElement:b}=pt(),{highlightedIndex:x,onHighlightedIndexChange:S}=c(),C=re(o),{compositeProps:w,compositeRef:E,index:D}=dt({metadata:X.useMemo(()=>({disabled:r,id:C,value:a}),[r,C,a])}),O=a===p,k=X.useRef(!1),A=X.useRef(null),j=u(e=>{A.current?.(),A.current=e?y(e):null});f(()=>{if(k.current){k.current=!1;return}if(!(O&&D>-1&&x!==D))return;let e=b;if(e!=null){let t=le(Ee(e));if(t&&be(e,t))return}r||S(D)},[O,D,x,S,r,b]);let{getButtonProps:M,buttonRef:N}=te({disabled:r,native:s,focusableWhenDisabled:!0}),ee=m(a),F=X.useRef(!1),I=X.useRef(!1);function L(e){h(a,T(P,e.nativeEvent,void 0,{activationDirection:`none`}))}function R(e){O||r||L(e)}function z(e){O||r||v&&(!F.current||I.current)&&L(e)}function ne(e){if(O||r)return;F.current=!0,I.current=e.button===0;let t=Ee(e.currentTarget);function n(){F.current=!1,I.current=!1,t.removeEventListener(`pointerup`,n),t.removeEventListener(`pointercancel`,n)}t.addEventListener(`pointerup`,n),t.addEventListener(`pointercancel`,n)}return H(`button`,e,{state:{disabled:r,active:O,orientation:g,tabActivationDirection:_},ref:[t,N,E,j],props:[w,{role:`tab`,"aria-controls":ee,"aria-selected":O,id:C,onClick:R,onFocus:z,onPointerDown:ne,[ut]:O?``:void 0,onKeyDownCapture(){k.current=!0}},d,M],stateAttributesMapping:ot})}),ht=`data-index`,gt={...ot,...me},_t=X.forwardRef(function(e,t){let{className:n,value:i,render:a,keepMounted:o=!1,style:s,...c}=e,{value:l,getTabIdByPanelValue:u,orientation:d,tabActivationDirection:p,registerMountedTabPanel:m}=it(),h=re(),{ref:g,index:_}=M(),v=i===l,{mounted:y,transitionStatus:b,setMounted:x}=r(v),S=!y,C=u(i),w={hidden:S,orientation:d,tabActivationDirection:p,transitionStatus:b},T=X.useRef(null),E=H(`div`,e,{state:w,ref:[t,g,T],props:[{"aria-labelledby":C,hidden:S,id:h,role:`tabpanel`,tabIndex:v?0:-1,inert:A(!v),[ht]:_},c],stateAttributesMapping:gt});return B({open:v,ref:T,onComplete(){v||x(!1)}}),f(()=>{if(!(h==null||S&&!o))return m(i,h)},[S,o,i,h,m]),o||y?E:null});function vt(e){let{loopFocus:t=!0,orientation:n=`both`,grid:r,onLoop:i,direction:a,highlightedIndex:s,onHighlightedIndexChange:c,rootRef:l,enableHomeAndEndKeys:d=!1,stopEventPropagation:m,disabledIndices:_,modifierKeys:v=I}=e,[b,S]=X.useState(0),C=r!=null,T=X.useRef(null),E=De(T,l),D=X.useRef([]),O=X.useRef(!1),k=X.useRef(null),A=s??b,M=u((e,t=!1)=>{if(k.current=D.current[e]??null,(c??S)(e),t){let t=D.current[e];j(T.current,t,a,n)}}),N=u(e=>{if(e.size===0)return;if(O.current){let e=D.current,t=e.indexOf(k.current);if(t===-1){let t=e[A];!t||R(e,A,_)?M(yt(e,_)):k.current=t}else t!==A&&M(t);return}O.current=!0;let t=Array.from(e.keys()),r=t.find(e=>e?.hasAttribute(`data-composite-item-active`))??null,i=r?e.get(r)?.index??-1:-1;if(i!==-1)M(i);else if(R(t,A,_)){let e=ye(t,{disabledIndices:_});U(t,e)||M(e)}j(T.current,r,a,n)});f(()=>{if(_==null||s!=null||!O.current)return;let e=D.current;if(R(e,A,_)){let t=ye(e,{disabledIndices:_});U(e,t)||M(t)}},[_,s,A,D,M]);let ee=u((e,t,n)=>i?i(e,t,n,D):n),P=u(e=>{let s=e.key===`Home`||e.key===`End`;if(!y.has(e.key)||!d&&s||bt(e,v)||!T.current)return;let c=a===`rtl`,l=c?w:p,u=c?p:w,f=n===`vertical`?x:l,b=n===`vertical`?g:u,S=ne(e.nativeEvent);if(S!=null&&o(S)&&!h(S)){let t=S.selectionStart,n=S.selectionEnd,r=S.value;if(t==null||e.shiftKey||t!==n||e.key!==b&&t<r.length||e.key!==f&&t>0)return}let E=A,O=_e(D,_),k=fe(D,_);r!=null&&(E=r({disabledIndices:_,elementsRef:D,event:e,highlightedIndex:A,loopFocus:t,maxIndex:k,minIndex:O,onLoop:ee,orientation:n,rtl:c}));let j=n!==`vertical`&&e.key===l||n!==`horizontal`&&e.key===`ArrowDown`,N=n!==`vertical`&&e.key===u||n!==`horizontal`&&e.key===`ArrowUp`;d&&(e.key===`Home`?E=O:e.key===`End`&&(E=k)),E===A&&(j||N)&&(t&&E===k&&j?(E=O,i&&(E=i(e,A,E,D))):t&&E===O&&N?(E=k,i&&(E=i(e,A,E,D))):E=ye(D.current,{startingIndex:E,decrement:N,disabledIndices:_})),E!==A&&!U(D.current,E)&&(m&&e.stopPropagation(),(C||s||j||N)&&e.preventDefault(),M(E,!0),queueMicrotask(()=>{D.current[E]?.focus()}))});return{props:{ref:E,onFocus(e){let t=T.current,n=ne(e.nativeEvent);t&&n!=null&&o(n)&&n.setSelectionRange(0,n.value.length)},onKeyDown:P},highlightedIndex:A,onHighlightedIndexChange:M,elementsRef:D,onMapChange:N,relayKeyboardEvent:P}}function yt(e,t){let n=-1;for(let r=0;r<e.length;r+=1){let i=e[r];if(i&&!R(e,r,t)){if(i.hasAttribute(`data-composite-item-active`))return r;n===-1&&(n=r)}}return Math.max(n,0)}function bt(e,t){for(let n of Oe)if(!t.includes(n)&&e.getModifierState(n))return!0;return!1}function xt(e){let{render:t,className:n,style:r,refs:i=I,props:a=I,state:o=Se,stateAttributesMapping:s,highlightedIndex:c,onHighlightedIndexChange:l,orientation:u,grid:d,loopFocus:f,onLoop:p,enableHomeAndEndKeys:h,onMapChange:g,stopEventPropagation:_=!0,rootRef:v,disabledIndices:y,modifierKeys:x,highlightItemOnHover:S=!1,tag:C=`div`,...w}=e,{props:T,highlightedIndex:E,onHighlightedIndexChange:O,elementsRef:k,onMapChange:A,relayKeyboardEvent:j}=vt({grid:d,loopFocus:f,onLoop:p,orientation:u,highlightedIndex:c,onHighlightedIndexChange:l,rootRef:v,stopEventPropagation:_,enableHomeAndEndKeys:h,direction:b(),disabledIndices:y,modifierKeys:x}),M=H(C,e,{state:o,ref:i,props:[T,...a,w],stateAttributesMapping:s}),N=X.useMemo(()=>({highlightedIndex:E,onHighlightedIndexChange:O,highlightItemOnHover:S,relayKeyboardEvent:j}),[E,O,S,j]);return(0,Z.jsx)(D.Provider,{value:N,children:(0,Z.jsx)(m,{elementsRef:k,onMapChange:e=>{g?.(e),A(e)},children:M})})}var St=X.forwardRef(function(e,t){let{activateOnFocus:n=!1,className:r,loopFocus:i=!0,render:a,style:o,...s}=e,{orientation:c,setTabMap:l,tabActivationDirection:d}=it(),[p,m]=X.useState(0),[h,g]=X.useState(null),_=X.useRef(new Set),v=X.useRef(new Set),y=X.useRef(null);f(()=>{if(typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>{_.current.forEach(e=>{e()})});return y.current=e,h&&e.observe(h),v.current.forEach(t=>{e.observe(t)}),()=>{e.disconnect(),y.current=null}},[h]);let b=u(e=>(_.current.add(e),()=>{_.current.delete(e)})),x=u(e=>(v.current.add(e),y.current?.observe(e),()=>{v.current.delete(e),y.current?.unobserve(e)})),S={orientation:c,tabActivationDirection:d},C={"aria-orientation":c===`vertical`?`vertical`:void 0,role:`tablist`},w=X.useMemo(()=>({activateOnFocus:n,registerIndicatorUpdateListener:b,registerTabResizeObserverElement:x,tabsListElement:h}),[n,b,x,h]);return(0,Z.jsx)(ft.Provider,{value:w,children:(0,Z.jsx)(xt,{render:a,className:r,style:o,state:S,refs:[t,g],props:[C,s],stateAttributesMapping:ot,highlightedIndex:p,enableHomeAndEndKeys:!0,loopFocus:i,orientation:c,onHighlightedIndexChange:m,onMapChange:l,disabledIndices:I})})}),Ct=n();function wt({className:e,orientation:t=`horizontal`,...n}){return(0,Z.jsx)(st,{"data-slot":`tabs`,"data-orientation":t,className:W(`group/tabs flex gap-2 data-horizontal:flex-col`,e),...n})}var Tt=ae(`group/tabs-list inline-flex w-fit items-center justify-center rounded-none p-[3px] text-muted-foreground group-data-horizontal/tabs:h-8 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none`,{variants:{variant:{default:`bg-muted`,line:`gap-1 bg-transparent`}},defaultVariants:{variant:`default`}});function Et({className:e,variant:t=`default`,...n}){return(0,Z.jsx)(St,{"data-slot":`tabs-list`,"data-variant":t,className:W(Tt({variant:t}),e),...n})}function Dt({className:e,...t}){return(0,Z.jsx)(mt,{"data-slot":`tabs-trigger`,className:W(`relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-none border border-transparent px-1.5 py-0.5 text-xs font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start group-data-vertical/tabs:py-[calc(--spacing(1.25))] hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 aria-disabled:pointer-events-none aria-disabled:opacity-50 dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,`group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent`,`data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground`,`after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-right-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100`,e),...t})}function Ot({className:e,...t}){return(0,Z.jsx)(_t,{"data-slot":`tabs-content`,className:W(`flex-1 text-xs/relaxed outline-none`,e),...t})}function kt(e){return H(e.defaultTagName??`div`,e,e)}var At=ae(`group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-none border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!`,{variants:{variant:{default:`bg-primary text-primary-foreground [a]:hover:bg-primary/80`,secondary:`bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80`,success:`border-emerald-600/20 bg-emerald-100/50 text-emerald-700 dark:border-emerald-400/20 dark:bg-emerald-900/50 dark:text-emerald-200`,warning:`border-amber-600/20 bg-amber-100/50 text-amber-700 dark:border-amber-400/20 dark:bg-amber-900/50 dark:text-amber-200`,info:`border-blue-600/20 bg-blue-100/50 text-blue-700 dark:border-blue-400/20 dark:bg-blue-900/50 dark:text-blue-200`,destructive:`bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20`,outline:`border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground`,ghost:`hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50`,link:`text-primary underline-offset-4 hover:underline`}},defaultVariants:{variant:`default`}});function jt({className:e,variant:t=`default`,render:n,...r}){return kt({defaultTagName:`span`,props:k({className:W(At({variant:t}),e)},r),render:n,state:{slot:`badge`,variant:t}})}var Mt=new Map([...[`ready`,`active`,`enabled`,`ok`,`completed`,`development`].map(e=>[e,`success`]),...[`pending`,`paused`,`activating`,`restoring`,`incomplete`,`required`].map(e=>[e,`warning`]),...[`uploading`,`running`,`queued`,`enqueued`,`production`,`public registration`,`public`].map(e=>[e,`info`]),...[`error`,`failed`,`blocked`,`unavailable`].map(e=>[e,`destructive`])]);function Q({status:e,children:t}){return(0,Z.jsx)(jt,{variant:Mt.get(e.toLowerCase())??`secondary`,children:t??e})}var Nt={query:`bg-yellow-100/50 text-yellow-700 dark:bg-yellow-900/50 dark:text-yellow-200`,mutation:`bg-blue-100/50 text-blue-700 dark:bg-blue-900/50 dark:text-blue-200`,action:`bg-purple-100/50 text-purple-700 dark:bg-purple-900/50 dark:text-purple-200`};function Pt({kind:e}){return(0,Z.jsx)(jt,{variant:`secondary`,className:Nt[e],children:e})}function Ft(e){let[t,n]=(0,X.useState)(!1);return(0,Z.jsxs)(`details`,{className:`rounded-lg border`,onToggle:e=>n(e.currentTarget.open),children:[(0,Z.jsx)(`summary`,{className:`cursor-pointer p-4 font-medium`,children:`Deployment history`}),t&&(0,Z.jsx)(`div`,{className:`p-4 pt-0`,children:(0,Z.jsx)(It,{...e})})]})}function It(e){let[t,n]=(0,X.useState)(),[r,i]=(0,X.useState)(),a=V(e.project,e.env),o=V(e.project,e.env),s=J(a+`/history`),c=e.session.role!==`viewer`,l=async(t,n)=>{let r=n?V(e.project,`prod`):o,a=await G(r+`/health`);i({title:n?`Promote backend to production`:`Rollback backend`,description:`Activate this exact backend hash after native schema/job validation. Data, files and settings stay unchanged. Frontend is not published by this button; use the CLI release flow for that.`,productionId:n||e.env===`prod`?e.project.id:void 0,submit:async()=>{await G(r+(n?`/release-promote`:`/release-rollback`),{hash:t,expected:a.active,confirm:e.project.id}),s.refresh(),e.refresh()}})},[u,d]=(0,X.useState)();return(0,Z.jsxs)(`div`,{className:`space-y-3`,children:[(0,Z.jsx)(q,{loading:s.loading,error:u||s.error}),(0,Z.jsxs)(F,{children:[(0,Z.jsx)(Te,{children:(0,Z.jsxs)(E,{children:[(0,Z.jsx)(z,{children:`First published`}),(0,Z.jsx)(z,{children:`Backend hash`}),(0,Z.jsx)(z,{children:`Actions`})]})}),(0,Z.jsx)(xe,{children:s.data?.map(t=>(0,Z.jsxs)(E,{children:[(0,Z.jsx)(Y,{children:new Date(t.at).toLocaleString()}),(0,Z.jsxs)(Y,{children:[(0,Z.jsx)(`code`,{className:`text-xs`,children:t.hash.slice(0,12)}),e.active===t.hash&&(0,Z.jsx)(Q,{status:`Active`})]}),(0,Z.jsx)(Y,{children:(0,Z.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,Z.jsx)(K,{variant:`outline`,size:`sm`,onClick:()=>n(t.hash),children:`View contracts`}),c&&e.active!==t.hash&&(0,Z.jsx)(K,{variant:`outline`,size:`sm`,onClick:()=>void l(t.hash,!1).catch(e=>d(e.message)),children:`Rollback backend`}),c&&e.env===`dev`&&(0,Z.jsx)(K,{variant:`outline`,size:`sm`,onClick:()=>void l(t.hash,!0).catch(e=>d(e.message)),children:`Promote backend`})]})})]},t.hash))})]}),t&&(0,Z.jsx)(Lt,{path:a,hash:t,close:()=>n(void 0)}),r&&(0,Z.jsx)(L,{modal:r,onClose:()=>i(void 0)})]})}function Lt({path:e,hash:t,close:n}){let r=J(e+`/release?hash=`+t);return(0,Z.jsx)(s,{open:!0,onOpenChange:e=>{e||n()},children:(0,Z.jsxs)(Ce,{className:`max-h-[80vh] overflow-auto`,children:[(0,Z.jsxs)(d,{children:[(0,Z.jsx)(l,{children:`Backend release`}),(0,Z.jsx)(O,{className:`break-all`,children:t})]}),(0,Z.jsx)(q,{...r}),r.data&&(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsx)(`h3`,{className:`font-medium`,children:`Tables`}),(0,Z.jsxs)(F,{children:[(0,Z.jsx)(Te,{children:(0,Z.jsxs)(E,{children:[(0,Z.jsx)(z,{children:`Table`}),(0,Z.jsx)(z,{children:`Fields`})]})}),(0,Z.jsx)(xe,{children:Object.entries(r.data.schema).map(([e,t])=>(0,Z.jsxs)(E,{children:[(0,Z.jsx)(Y,{children:e}),(0,Z.jsx)(Y,{children:Object.keys(t.document.properties??{}).join(`, `)||`No declared fields`})]},e))})]}),(0,Z.jsx)(`h3`,{className:`font-medium`,children:`Functions`}),(0,Z.jsxs)(F,{children:[(0,Z.jsx)(Te,{children:(0,Z.jsxs)(E,{children:[(0,Z.jsx)(z,{children:`Function`}),(0,Z.jsx)(z,{children:`Kind`}),(0,Z.jsx)(z,{children:`Access`})]})}),(0,Z.jsx)(xe,{children:Object.entries(r.data.manifest.functions).map(([e,t])=>(0,Z.jsxs)(E,{children:[(0,Z.jsx)(Y,{children:e}),(0,Z.jsx)(Y,{children:(0,Z.jsx)(Pt,{kind:t.kind})}),(0,Z.jsx)(Y,{children:(0,Z.jsx)(Q,{status:t.auth})})]},e))})]})]})]})})}function Rt({className:e,size:t=`default`,...n}){return(0,Z.jsx)(`div`,{"data-slot":`card`,"data-size":t,className:W(`group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-none bg-card py-(--card-spacing) text-xs/relaxed text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-none *:[img:last-child]:rounded-none`,e),...n})}function zt({className:e,...t}){return(0,Z.jsx)(`div`,{"data-slot":`card-header`,className:W(`group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-none px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)`,e),...t})}function Bt({className:e,...t}){return(0,Z.jsx)(`div`,{"data-slot":`card-title`,className:W(`font-heading text-sm font-medium group-data-[size=sm]/card:text-sm`,e),...t})}function Vt({className:e,...t}){return(0,Z.jsx)(`div`,{"data-slot":`card-content`,className:W(`px-(--card-spacing)`,e),...t})}function Ht({project:e,env:t,session:n,connect:r}){let i=J(V(e,t)+`/health`),a=J(V(e,t)+`/settings`);return(0,Z.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,Z.jsx)(`h1`,{className:`page-title`,children:`Health`}),(0,Z.jsx)(q,{loading:i.loading||a.loading,error:i.error||a.error}),i.data&&a.data&&(0,Z.jsxs)(Z.Fragment,{children:[(0,Z.jsx)(`h2`,{className:`section-title`,children:`Summary`}),(0,Z.jsx)(Rt,{children:(0,Z.jsxs)(Vt,{className:`grid gap-4 md:grid-cols-2`,children:[(0,Z.jsxs)(`div`,{className:`space-y-3`,children:[(0,Z.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,Z.jsx)(Q,{status:t===`dev`?`Development`:`Production`}),(0,Z.jsx)(`strong`,{children:e.name})]}),(0,Z.jsx)(`p`,{className:`text-muted-foreground`,children:`Cloudflare · Durable Objects · SQLite`}),(0,Z.jsxs)(`p`,{className:`font-mono text-xs text-muted-foreground`,children:[`Release `,i.data.active?.slice(0,12)??`not deployed`]})]}),(0,Z.jsxs)(`div`,{className:`space-y-2`,children:[(0,Z.jsx)(`p`,{className:`text-muted-foreground`,children:`Cloud URL`}),(0,Z.jsx)(`code`,{className:`block select-all break-all text-xs`,children:a.data.url}),(0,Z.jsxs)(`div`,{className:`flex items-center gap-2 text-muted-foreground`,children:[(0,Z.jsx)(Q,{status:i.data.status}),i.data.connections,` connections · `,i.data.subscriptions,` `,`subscriptions`]})]})]})}),(0,Z.jsx)(Ft,{project:e,env:t,session:n,active:i.data.active,refresh:i.refresh}),(0,Z.jsx)(K,{variant:`outline`,onClick:r,children:`Connect SDK`})]})]})}function Ut({project:e,env:t}){let n=J(V(e,t)+`/schema`);return(0,Z.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,Z.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,Z.jsx)(`h1`,{className:`page-title`,children:`Schema`}),(0,Z.jsx)(`div`,{className:`flex gap-2`,children:(0,Z.jsx)(K,{variant:`ghost`,size:`icon-sm`,"aria-label":`Reload snapshot`,title:`Reload snapshot`,onClick:n.refresh,disabled:n.loading,children:(0,Z.jsx)(Je,{})})})]}),(0,Z.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Defined in code; validated documents and indexes activate atomically. System tables are hidden.`}),(0,Z.jsx)(q,{...n}),n.data?.tables.map(e=>(0,Z.jsxs)(Rt,{children:[(0,Z.jsx)(zt,{children:(0,Z.jsx)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:(0,Z.jsx)(Bt,{className:`font-mono`,children:e.name})})}),(0,Z.jsxs)(Vt,{className:`space-y-4`,children:[(0,Z.jsx)(pe,{rows:e.columns.map(e=>({Field:e.name,Type:e.type,Required:!!e.notnull,Primary:!!e.pk,Default:e.dflt_value})),columns:[`Field`,`Type`,`Required`,`Primary`,`Default`]}),(0,Z.jsx)(pe,{rows:Object.entries(e.indexes).map(([e,t])=>({Index:e,Fields:t.join(`, `)})),columns:[`Index`,`Fields`]}),(0,Z.jsxs)(`details`,{children:[(0,Z.jsx)(`summary`,{className:`cursor-pointer text-muted-foreground`,children:`Document contract`}),(0,Z.jsx)(`pre`,{className:`code-block mt-3`,children:JSON.stringify(e.document,null,2)})]})]})]},e.name)),n.data&&!n.data.tables.length&&(0,Z.jsx)(de,{title:`No application tables`})]})}function Wt({project:e,env:t}){let n=J(V(e,t)+`/logs`);return(0,Z.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,Z.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,Z.jsx)(`h1`,{className:`page-title`,children:`Logs`}),(0,Z.jsx)(K,{variant:`ghost`,size:`icon-sm`,"aria-label":`Reload snapshot`,title:`Reload snapshot`,onClick:n.refresh,disabled:n.loading,children:(0,Z.jsx)(Je,{})})]}),(0,Z.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Last 100 invocation summaries. Successful queries are held in memory and disappear on hibernation/restart; writes and failures are persisted. Not Cloudflare Tail logs or billing analytics.`}),(0,Z.jsx)(q,{...n}),n.data&&(n.data.length?(0,Z.jsx)(pe,{rows:n.data,renderCell:(e,t)=>e===`kind`&&[`query`,`mutation`,`action`].includes(String(t))?(0,Z.jsx)(Pt,{kind:t}):e===`status`?(0,Z.jsx)(Q,{status:t===`ok`?`ok`:`error`,children:ie(t)}):e===`at`&&typeof t==`number`?new Date(t).toLocaleString():ie(t),columns:[`at`,`path`,`kind`,`status`,`ms`],labels:{at:`Time`,path:`Function`,kind:`Type`,status:`Status`,ms:`Duration (ms)`}}):(0,Z.jsx)(de,{title:`No recent function calls`}))]})}var Gt=(function(){let e=typeof document<`u`&&document.createElement(`link`).relList;return e&&e.supports&&e.supports(`modulepreload`)?`modulepreload`:`preload`})(),Kt=function(e){return`/`+e},qt={},Jt=function(e){return e.pathname.endsWith(`.css`)},Yt=function(e,t,n){if(t in e)return e[t];let r=n();if(!r){e[t]=void 0;return}let i=r.then(()=>{e[t]=void 0},n=>{throw e[t]=void 0,n});return e[t]=i,i},$=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=function(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))},i=function(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)},a,o=document.querySelector(`meta[property=csp-nonce]`),s=o?.nonce||o?.getAttribute(`nonce`);r=e(t.map(e=>{e=Kt(e,n);let t=i(e),r=Jt(t);return Yt(qt,t.href,()=>{if(a===void 0){a={all:new Set,styles:new Set};let e=document.getElementsByTagName(`link`);for(let t=e.length-1;t>=0;t--){let n=e[t];a.all.add(n.href),n.rel===`stylesheet`&&a.styles.add(n.href)}}if((r?a.styles:a.all).has(t.href))return;let e=document.createElement(`link`);if(e.rel=r?`stylesheet`:Gt,r||(e.as=`script`),e.crossOrigin=``,e.href=t.href,s&&e.setAttribute(`nonce`,s),document.head.appendChild(e),r)return new Promise((n,r)=>{e.addEventListener(`load`,n),e.addEventListener(`error`,()=>r(Error(`Unable to preload CSS for ${t}`)))})})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},Xt=(0,X.lazy)(()=>$(()=>import(`./services-view.Dx1rjMWa.js`).then(e=>({default:e.FilesView})),__vite__mapDeps([0,1,2,3]))),Zt=(0,X.lazy)(()=>$(()=>import(`./services-view.Dx1rjMWa.js`).then(e=>({default:e.SchedulesView})),__vite__mapDeps([0,1,2,3]))),Qt=(0,X.lazy)(()=>$(()=>import(`./data-view.BFL2F3o9.js`),__vite__mapDeps([4,1,2,5]))),$t=(0,X.lazy)(()=>$(()=>import(`./functions-view.vsmqlnUa.js`),__vite__mapDeps([6,1,2,3,5]))),en=(0,X.lazy)(()=>$(()=>import(`./ai-view.DcYKk5W_.js`),__vite__mapDeps([7,1,2,3]))),tn=(0,X.lazy)(()=>$(()=>import(`./auth-view.KnVtTZYn.js`),__vite__mapDeps([8,1,2]))),nn=(0,X.lazy)(()=>$(()=>import(`./settings-view.DPwEyqzv.js`),__vite__mapDeps([9,1,2]))),rn=(0,X.lazy)(()=>$(()=>import(`./sdk-view.BPVWrAC3.js`),__vite__mapDeps([10,1,2]))),an=[{key:`health`,label:`Health`,icon:Ae},{key:`data`,label:`Data`,icon:Ie},{key:`schema`,label:`Schema`,icon:Me},{key:`functions`,label:`Functions`,icon:Pe},{key:`files`,label:`Files`,icon:Re},{key:`schedules`,label:`Schedules`,icon:nt},{key:`ai`,label:`AI`,icon:Xe},{key:`auth`,label:`Auth`,icon:et},{key:`logs`,label:`Logs`,icon:Be}],on=(0,X.lazy)(()=>$(()=>import(`./cli-approval.emPTVRqn.js`),__vite__mapDeps([11,1,2])));function sn(){return new URLSearchParams(location.search).has(`cli`)?(0,Z.jsx)(X.Suspense,{fallback:(0,Z.jsx)(`p`,{children:`Loading…`}),children:(0,Z.jsx)(on,{})}):(0,Z.jsx)(cn,{})}function cn(){let[e,t]=(0,X.useState)(),[n,r]=(0,X.useState)([]),[a,o]=(0,X.useState)(),[s,c]=(0,X.useState)(`dev`),[l,u]=(0,X.useState)(`health`),[d,f]=(0,X.useState)(``),[p,m]=(0,X.useState)(!0),[h,g]=(0,X.useState)(),[_,v]=(0,X.useState)(!1);(0,X.useEffect)(()=>{let e=new AbortController;return v(localStorage.getItem(`flare.sidebar`)===`collapsed`),Promise.all([G(`session`,void 0,e.signal),G(`projects`,void 0,e.signal)]).then(([n,i])=>{e.signal.aborted||(t(n),r(i),o(i.find(e=>e.id===localStorage.getItem(`flare.project`))??i[0]),m(!1))}).catch(t=>{e.signal.aborted||(f(ue(t)),m(!1))}),()=>e.abort()},[]);let y=e=>{let t=n.find(t=>t.id===e);t&&(o(t),c(`dev`),u(`health`),g(void 0),localStorage.setItem(`flare.project`,e))},b=()=>g({title:`Create project`,description:`Creates separate development and production environments.`,content:(0,Z.jsxs)(se,{children:[(0,Z.jsxs)(S,{children:[(0,Z.jsx)(i,{htmlFor:`project-name`,children:`Project name`}),(0,Z.jsx)(he,{id:`project-name`,name:`name`,required:!0,maxLength:100,placeholder:`CRM`})]}),(0,Z.jsxs)(S,{children:[(0,Z.jsx)(i,{htmlFor:`project-alias`,children:`Short URL name (optional)`}),(0,Z.jsx)(he,{id:`project-alias`,name:`alias`,maxLength:48,pattern:`[a-z][a-z0-9]*(?:-[a-z0-9]+)*`,placeholder:`crm`})]}),(0,Z.jsxs)(S,{children:[(0,Z.jsx)(i,{htmlFor:`project-origins`,children:`Allowed frontend origins · one per line`}),(0,Z.jsx)(oe,{id:`project-origins`,name:`origins`,placeholder:`http://127.0.0.1:5173`})]})]}),submit:async e=>{let t=new FormData(e),n=await G(`projects`,{name:t.get(`name`),alias:t.get(`alias`)||void 0,origins:[location.origin,...String(t.get(`origins`)).split(`
3
3
  `).map(e=>e.trim()).filter(Boolean)]}),i=await G(`projects`);r(i),o(i.find(e=>e.id===n.id)??i[0]),c(`dev`),u(`health`)}}),x=a&&e?{project:a,env:s,session:e}:null,C=()=>{let e=n.filter(e=>e.id!==a?.id);r(e),o(e[0]),c(`dev`),u(`health`),e[0]?localStorage.setItem(`flare.project`,e[0].id):localStorage.removeItem(`flare.project`)},w=e=>{g(void 0),u(e)};return(0,Z.jsxs)(`div`,{className:`flex h-dvh min-h-0 flex-col overflow-hidden text-sm`,children:[(0,Z.jsxs)(`header`,{className:`flex h-14 shrink-0 items-center justify-between gap-3 border-b bg-sidebar px-4`,children:[(0,Z.jsxs)(`div`,{className:`flex min-w-0 items-center gap-3`,children:[(0,Z.jsx)(ve,{label:`Select project`,value:a?.id??``,onChange:y,items:n.map(e=>({value:e.id,label:e.name})),className:`max-w-48`}),x&&(0,Z.jsx)(wt,{value:s,onValueChange:e=>{(e===`dev`||e===`prod`)&&(c(e),g(void 0))},"aria-label":`Select environment`,children:(0,Z.jsxs)(Et,{children:[(0,Z.jsx)(Dt,{value:`dev`,children:`Dev`}),(0,Z.jsx)(Dt,{value:`prod`,children:`Production`})]})})]}),(0,Z.jsxs)(`div`,{className:`flex items-center gap-2`,children:[e?.role!==`viewer`&&e&&(0,Z.jsx)(K,{"aria-label":`Create project`,size:`icon-sm`,variant:`ghost`,onClick:b,children:(0,Z.jsx)(Ke,{})}),x&&(0,Z.jsx)(K,{"aria-label":`Project settings`,size:`icon-sm`,variant:`ghost`,onClick:()=>w(`settings`),children:(0,Z.jsx)(Qe,{})}),e&&(0,Z.jsx)(`span`,{className:`flex size-7 items-center justify-center rounded-full bg-muted text-xs font-medium`,title:e.email,"aria-label":`Signed in as ${e.email}`,children:e.email.slice(0,2).toUpperCase()})]})]}),(0,Z.jsxs)(`div`,{className:`flex min-h-0 flex-1`,children:[(0,Z.jsxs)(`aside`,{className:`flex shrink-0 flex-col border-r bg-sidebar px-2 py-3 ${_?`w-12`:`w-36`}`,children:[(0,Z.jsx)(`nav`,{"aria-label":`Deployment`,className:`flex flex-col gap-1`,children:an.map(({key:e,label:t,icon:n})=>(0,Z.jsxs)(K,{variant:`ghost`,disabled:!x,"aria-current":l===e?`page`:void 0,title:_?t:void 0,"aria-label":_?t:void 0,className:`w-full justify-start ${l===e?`bg-sidebar-accent text-sidebar-accent-foreground`:`text-muted-foreground`}`,onClick:()=>w(e),children:[(0,Z.jsx)(n,{className:`size-4`}),!_&&t]},e))}),(0,Z.jsxs)(K,{"aria-label":_?`Expand sidebar`:`Collapse sidebar`,className:`mt-auto justify-start text-muted-foreground`,variant:`ghost`,onClick:()=>v(e=>(localStorage.setItem(`flare.sidebar`,e?`expanded`:`collapsed`),!e)),children:[_?(0,Z.jsx)(We,{}):(0,Z.jsx)(He,{}),!_&&`Collapse`]})]}),(0,Z.jsxs)(`main`,{className:`min-h-0 min-w-0 flex-1 ${l===`data`?`overflow-hidden`:`overflow-auto`}`,"aria-label":`Deployment content`,children:[d&&(0,Z.jsx)(`div`,{className:`p-4`,children:(0,Z.jsx)(ge,{children:d})}),p?(0,Z.jsx)(q,{loading:!0}):x?(0,Z.jsx)(ce,{scope:`projects/${a.id}/${s}`,children:(0,Z.jsx)(X.Suspense,{fallback:(0,Z.jsx)(q,{loading:!0}),children:(0,Z.jsx)(`div`,{className:l===`data`?`h-full min-h-0`:`min-h-full`,children:l===`health`?(0,Z.jsx)(Ht,{...x,connect:()=>w(`sdk`)}):l===`data`?(0,Z.jsx)(Qt,{...x}):l===`schema`?(0,Z.jsx)(Ut,{...x}):l===`functions`?(0,Z.jsx)($t,{...x}):l===`files`?(0,Z.jsx)(Xt,{...x}):l===`schedules`?(0,Z.jsx)(Zt,{...x}):l===`ai`?(0,Z.jsx)(en,{...x}):l===`auth`?(0,Z.jsx)(tn,{...x}):l===`logs`?(0,Z.jsx)(Wt,{...x}):l===`settings`?(0,Z.jsx)(nn,{...x,onDeleted:C}):(0,Z.jsx)(rn,{...x})},`${a.id}/${s}/${l}`)})},`${a.id}/${s}`):d?null:(0,Z.jsxs)(`div`,{className:`p-4`,children:[(0,Z.jsx)(`h1`,{className:`page-title`,children:`Select a project`}),(0,Z.jsx)(`p`,{className:`mt-2 text-muted-foreground`,children:`Create a project to get started.`}),e?.role!==`viewer`&&(0,Z.jsxs)(K,{className:`mt-4`,onClick:b,children:[(0,Z.jsx)(Ke,{}),`New project`]})]})]})]}),h&&(0,Z.jsx)(L,{modal:h,onClose:()=>g(void 0)})]})}var ln=document.getElementById(`flare-dashboard`);if(!ln)throw Error(`Dashboard mount missing`);(0,Ct.createRoot)(ln).render((0,X.createElement)(sn));export{Pt as a,wt as c,Dt as d,Xe as f,Pe as g,Ie as h,Bt as i,Ot as l,Ke as m,Vt as n,Q as o,Je as p,zt as r,jt as s,Rt as t,Et as u};
@@ -1 +1 @@
1
- import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,Ot as r,g as i,m as a,p as o,pt as s,r as c,s as l,u}from"./common.9pujiaSZ.js";import{i as d,n as f,r as p,t as m}from"./index.astro_astro_type_script_index_0_lang.DlEchDEE.js";var h={name:`key-round`,size:24,node:[[`path`,{d:`M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z`,key:`1s6t7t`}],[`circle`,{cx:`16.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`w0ekpg`}]]};h.node;var g=r(h),_=e(t(),1),v=n();function y({project:e,env:t,session:n}){let r=i(e,t),h=u(r+`/settings`),[y,b]=(0,_.useState)(),[x,S]=(0,_.useState)(``),[C,w]=(0,_.useState)(!1),T=(0,_.useRef)(void 0);(0,_.useEffect)(()=>()=>T.current?.abort(),[]);let E=async()=>{if(C||t!==`dev`||n.role===`viewer`)return;let e=new AbortController;T.current=e,w(!0),S(``),b(void 0);try{let t=await o(r+`/dev-token`,{},e.signal);e.signal.aborted||b(t)}catch(t){e.signal.aborted||S(a(t))}finally{e.signal.aborted||w(!1)}};return(0,v.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,v.jsx)(`h1`,{className:`page-title`,children:`SDK · Live`}),(0,v.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`One environment URL for browser, server and mobile clients. Use the generated API references from your application build.`}),(0,v.jsx)(l,{...h}),h.data&&(0,v.jsxs)(m,{children:[(0,v.jsx)(p,{children:(0,v.jsx)(d,{children:`Connect your application`})}),(0,v.jsxs)(f,{className:`space-y-4`,children:[(0,v.jsx)(`pre`,{className:`code-block`,children:`import { createClient } from '@auersperg/flare';\nimport { api } from './flare/_generated/api';\n\nconst client = createClient({\n url: '${h.data.url}',\n getToken: () => yourUserAccessToken,\n});\n\n// Use your generated query / mutation / action references.\n// Example: replace this path with your own query:\nconst stop = client.onUpdate(api.tasks.list, { limit: 50 },\n tasks => console.log(tasks));\n\n// On logout: client.refreshAuth().\n// On teardown: stop(); client.dispose();`}),(0,v.jsx)(`p`,{className:`text-muted-foreground`,children:`The task function is an illustrative name, not a requirement for other projects. Run your app locally to test live updates; this page opens no background subscription and does not write application data.`})]})]}),(0,v.jsxs)(m,{children:[(0,v.jsx)(p,{children:(0,v.jsx)(d,{children:t===`dev`?`Local developer session`:`Production authentication`})}),(0,v.jsxs)(f,{className:`space-y-4`,children:[(0,v.jsx)(`p`,{className:`text-muted-foreground`,children:t===`dev`?`A 15-minute identity for this project's development environment. Keep it in a git-ignored local file, never in a bundle or commit. Request a new token after expiry.`:`Use enabled built-in password authentication or a configured OIDC provider. Developer identities cannot access production; application handlers enforce record permissions.`}),t===`dev`&&n.role!==`viewer`&&(0,v.jsxs)(s,{variant:`outline`,onClick:E,disabled:C,children:[(0,v.jsx)(g,{}),C?`Requesting…`:`Get developer session`]}),x&&(0,v.jsx)(c,{children:x}),y&&(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(`pre`,{className:`code-block`,children:JSON.stringify(y,null,2)}),(0,v.jsx)(s,{variant:`ghost`,onClick:()=>b(void 0),children:`Clear from view`})]})]})]})]})}export{y as default};
1
+ import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,Ot as r,g as i,m as a,p as o,pt as s,r as c,s as l,u}from"./common.9pujiaSZ.js";import{i as d,n as f,r as p,t as m}from"./index.astro_astro_type_script_index_0_lang.DBs-yURk.js";var h={name:`key-round`,size:24,node:[[`path`,{d:`M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z`,key:`1s6t7t`}],[`circle`,{cx:`16.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`w0ekpg`}]]};h.node;var g=r(h),_=e(t(),1),v=n();function y({project:e,env:t,session:n}){let r=i(e,t),h=u(r+`/settings`),[y,b]=(0,_.useState)(),[x,S]=(0,_.useState)(``),[C,w]=(0,_.useState)(!1),T=(0,_.useRef)(void 0);(0,_.useEffect)(()=>()=>T.current?.abort(),[]);let E=async()=>{if(C||t!==`dev`||n.role===`viewer`)return;let e=new AbortController;T.current=e,w(!0),S(``),b(void 0);try{let t=await o(r+`/dev-token`,{},e.signal);e.signal.aborted||b(t)}catch(t){e.signal.aborted||S(a(t))}finally{e.signal.aborted||w(!1)}};return(0,v.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,v.jsx)(`h1`,{className:`page-title`,children:`SDK · Live`}),(0,v.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`One environment URL for browser, server and mobile clients. Use the generated API references from your application build.`}),(0,v.jsx)(l,{...h}),h.data&&(0,v.jsxs)(m,{children:[(0,v.jsx)(p,{children:(0,v.jsx)(d,{children:`Connect your application`})}),(0,v.jsxs)(f,{className:`space-y-4`,children:[(0,v.jsx)(`pre`,{className:`code-block`,children:`import { createClient } from '@auersperg/flare';\nimport { api } from './flare/_generated/api';\n\nconst client = createClient({\n url: '${h.data.url}',\n getToken: () => yourUserAccessToken,\n});\n\n// Use your generated query / mutation / action references.\n// Example: replace this path with your own query:\nconst stop = client.onUpdate(api.tasks.list, { limit: 50 },\n tasks => console.log(tasks));\n\n// On logout: client.refreshAuth().\n// On teardown: stop(); client.dispose();`}),(0,v.jsx)(`p`,{className:`text-muted-foreground`,children:`The task function is an illustrative name, not a requirement for other projects. Run your app locally to test live updates; this page opens no background subscription and does not write application data.`})]})]}),(0,v.jsxs)(m,{children:[(0,v.jsx)(p,{children:(0,v.jsx)(d,{children:t===`dev`?`Local developer session`:`Production authentication`})}),(0,v.jsxs)(f,{className:`space-y-4`,children:[(0,v.jsx)(`p`,{className:`text-muted-foreground`,children:t===`dev`?`A 15-minute identity for this project's development environment. Keep it in a git-ignored local file, never in a bundle or commit. Request a new token after expiry.`:`Use enabled built-in password authentication or a configured OIDC provider. Developer identities cannot access production; application handlers enforce record permissions.`}),t===`dev`&&n.role!==`viewer`&&(0,v.jsxs)(s,{variant:`outline`,onClick:E,disabled:C,children:[(0,v.jsx)(g,{}),C?`Requesting…`:`Get developer session`]}),x&&(0,v.jsx)(c,{children:x}),y&&(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(`pre`,{className:`code-block`,children:JSON.stringify(y,null,2)}),(0,v.jsx)(s,{variant:`ghost`,onClick:()=>b(void 0),children:`Clear from view`})]})]})]})]})}export{y as default};
@@ -1 +1 @@
1
- import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,Ot as r,S as i,_ as a,b as o,g as s,h as c,m as l,n as u,o as d,p as f,pt as p,q as m,s as h,u as g,v as _,x as v,y}from"./common.9pujiaSZ.js";import{c as b,d as x,l as S,o as C,p as w,u as T}from"./index.astro_astro_type_script_index_0_lang.DlEchDEE.js";import{n as E,r as D}from"./client.BSf433s6.js";var O={name:`download`,size:24,node:[[`path`,{d:`M12 15V3`,key:`m9g1x1`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}],[`path`,{d:`m7 10 5 5 5-5`,key:`brsn70`}]]};O.node;var k=r(O),A={name:`trash`,size:24,node:[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]],aliases:[`trash-2`]};A.node;var j=r(A),M=e(t(),1),N=n();function P({project:e,env:t,session:n}){let[r,c]=(0,M.useState)([null]),d=r.at(-1),b=s(e,t),x=g(b+`/files`+(d?`?cursor=`+encodeURIComponent(d):``)),S=(0,M.useRef)(null),[T,O]=(0,M.useState)(!1),[A,P]=(0,M.useState)(!1),[F,I]=(0,M.useState)(``),[L,R]=(0,M.useState)(``),z=n.role!==`viewer`;async function B(){let n=S.current?.files?.[0];if(!n)return;O(!0),I(``),R(``);let r=!1;try{let i=E(n);if(t===`prod`&&!confirm(`Upload to production ${e.name}?`))return;R(`Preparing upload…`),r=!0;let a=await f(b+`/file-upload`,{...i,...t===`prod`?{confirm:e.id}:{}});R(`Uploading ${n.name}…`),await D(a,n),S.current&&(S.current.value=``),P(!1),R(`Upload complete`)}catch(e){R(``),I(l(e)+(r?`. Check the refreshed list before retrying. Incomplete uploads expire automatically; they are not queue jobs.`:``))}finally{O(!1),r&&x.refresh()}}async function V(e){I(``);try{let t=await f(b+`/file-download?id=`+encodeURIComponent(e)),n=document.createElement(`a`);n.href=t.url,n.rel=`noreferrer`,n.click()}catch(e){I(l(e))}}async function H(n){if(confirm(`Permanently delete this ${t} file?`)){O(!0),I(``);try{await f(b+`/file-delete`,{id:n,...t===`prod`?{confirm:e.id}:{}}),x.refresh()}catch(e){I(l(e))}finally{O(!1)}}}return(0,N.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,N.jsx)(`h1`,{className:`page-title`,children:`Files`}),(0,N.jsx)(p,{variant:`ghost`,size:`icon-sm`,"aria-label":`Reload snapshot`,title:`Reload snapshot`,onClick:x.refresh,disabled:x.loading,children:(0,N.jsx)(w,{})})]}),(0,N.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Private R2 storage · streaming uploads · maximum 10 MiB · download links expire after 5 minutes. 50 files per page.`}),(0,N.jsx)(h,{loading:x.loading,error:F||x.error}),L&&(0,N.jsx)(`p`,{role:`status`,className:`text-xs text-muted-foreground`,children:L}),z&&(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,N.jsx)(m,{ref:S,type:`file`,className:`max-w-sm`,disabled:T,"aria-label":`Choose file to upload`,onChange:e=>P(!!e.target.files?.length)}),(0,N.jsx)(p,{onClick:B,disabled:T||!A,children:`Upload file`})]}),x.data?.page.length?(0,N.jsxs)(a,{children:[(0,N.jsx)(v,{children:(0,N.jsx)(i,{children:[`Name`,`Type`,`Size`,`State`,`Created`,`Actions`].map(e=>(0,N.jsx)(o,{children:e},e))})}),(0,N.jsx)(_,{children:x.data.page.map(e=>(0,N.jsxs)(i,{children:[(0,N.jsx)(y,{children:e.name}),(0,N.jsx)(y,{children:e.type}),(0,N.jsx)(y,{children:e.size>=1048576?`${(e.size/1048576).toFixed(1)} MiB`:e.size<1024?`${e.size} B`:`${(e.size/1024).toFixed(1)} KiB`}),(0,N.jsx)(y,{children:(0,N.jsx)(C,{status:e.state,children:e.state===`pending`?`Awaiting upload`:e.state===`uploading`?`Uploading / recovering`:e.state})}),(0,N.jsx)(y,{children:new Date(e.createdAt).toLocaleString()}),(0,N.jsx)(y,{children:(0,N.jsxs)(`div`,{className:`flex gap-2`,children:[(0,N.jsx)(p,{size:`icon`,variant:`outline`,"aria-label":`Download ${e.name}`,disabled:e.state!==`ready`||T,onClick:()=>void V(e.id),children:(0,N.jsx)(k,{})}),z&&(0,N.jsx)(p,{size:`icon`,variant:`outline`,"aria-label":`Delete ${e.name}`,disabled:T,onClick:()=>void H(e.id),children:(0,N.jsx)(j,{})})]})})]},e.id))})]}):x.data&&(0,N.jsx)(u,{title:`No stored files`}),x.data&&(0,N.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,N.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`Page `,r.length,` · `,x.data.page.length,` files`]}),(0,N.jsxs)(`div`,{className:`flex gap-2`,children:[(0,N.jsx)(p,{variant:`outline`,disabled:x.loading||r.length===1,onClick:()=>c(e=>e.slice(0,-1)),children:`Previous`}),(0,N.jsx)(p,{variant:`outline`,disabled:x.loading||x.data.isDone,onClick:()=>{x.data?.continueCursor&&c(e=>[...e,x.data.continueCursor])},children:`Next`})]})]})]})}function F({project:e,env:t,session:n}){let r=s(e,t),m=g(r+`/jobs`),[E,D]=(0,M.useState)(``);async function O(n){if(t!==`prod`||confirm(`Pause production cron ${n}?`))try{await f(r+`/cron-cancel`,{name:n,...t===`prod`?{confirm:e.id}:{}}),m.refresh()}catch(e){D(l(e))}}async function k(n){if(t!==`prod`||confirm(`Cancel this pending production job?`)){D(``);try{(await f(r+`/job-cancel`,{id:n,...t===`prod`?{confirm:e.id}:{}})).cancelled||D(`This job is already enqueued; it cannot be cancelled here.`)}catch(e){D(l(e))}finally{m.refresh()}}}return(0,N.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,N.jsx)(`h1`,{className:`page-title`,children:`Schedules`}),(0,N.jsx)(p,{variant:`ghost`,size:`icon-sm`,"aria-label":`Reload snapshot`,title:`Reload snapshot`,onClick:m.refresh,disabled:m.loading,children:(0,N.jsx)(w,{})})]}),(0,N.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Durable scheduling → transactional outbox → Cloudflare Queues. At-least-once delivery; handlers must be idempotent. Times use UTC.`}),(0,N.jsx)(h,{loading:m.loading,error:m.error||E}),(0,N.jsxs)(b,{defaultValue:`scheduled`,children:[(0,N.jsxs)(T,{variant:`line`,children:[(0,N.jsx)(x,{value:`scheduled`,children:`Scheduled Functions`}),(0,N.jsx)(x,{value:`cron`,children:`Cron Jobs`})]}),(0,N.jsxs)(S,{value:`scheduled`,className:`space-y-4 pt-4`,children:[(0,N.jsx)(`h2`,{className:`section-title`,children:`Waiting to enqueue`}),m.data&&(m.data.pending.length?(0,N.jsxs)(a,{children:[(0,N.jsx)(v,{children:(0,N.jsx)(i,{children:[`Function`,`Due (UTC)`,`Job ID`,``].map((e,t)=>(0,N.jsx)(o,{children:e},t))})}),(0,N.jsx)(_,{children:m.data.pending.map(e=>(0,N.jsxs)(i,{children:[(0,N.jsx)(y,{className:`font-mono`,children:String(e.path)}),(0,N.jsx)(y,{children:new Date(Number(e.dueAt)).toISOString()}),(0,N.jsx)(y,{className:`font-mono`,children:String(e.id)}),(0,N.jsx)(y,{children:n.role!==`viewer`&&(0,N.jsx)(p,{variant:`outline`,disabled:m.loading,onClick:()=>void k(String(e.id)),children:`Cancel`})})]},String(e.id)))})]}):(0,N.jsx)(u,{title:`No delayed jobs`})),(0,N.jsx)(`h2`,{className:`section-title`,children:`Recent queue deliveries`}),m.data&&(m.data.recent.length?(0,N.jsx)(d,{rows:m.data.recent,columns:[`id`,`path`,`state`,`attempts`,`error`,`at`],renderCell:(e,t)=>e===`state`?(0,N.jsx)(C,{status:String(t)}):e===`at`&&typeof t==`number`?new Date(t).toLocaleString():c(t)}):(0,N.jsx)(u,{title:`No queue deliveries yet`}))]}),(0,N.jsxs)(S,{value:`cron`,className:`space-y-4 pt-4`,children:[m.data?.crons.length?(0,N.jsxs)(a,{children:[(0,N.jsx)(v,{children:(0,N.jsx)(i,{children:[`Name`,`Function`,`Cron (UTC)`,`State`,``].map((e,t)=>(0,N.jsx)(o,{children:e},t))})}),(0,N.jsx)(_,{children:m.data.crons.map(e=>(0,N.jsxs)(i,{children:[(0,N.jsx)(y,{children:e.name}),(0,N.jsx)(y,{className:`font-mono`,children:e.path}),(0,N.jsx)(y,{className:`font-mono`,children:e.cron}),(0,N.jsx)(y,{children:(0,N.jsx)(C,{status:e.enabled?`Enabled`:`Paused`})}),(0,N.jsx)(y,{children:n.role!==`viewer`&&e.enabled&&(0,N.jsx)(p,{variant:`outline`,onClick:()=>void O(e.name),children:`Pause`})})]},e.name))})]}):m.data&&(0,N.jsx)(u,{title:`No cron jobs`}),(0,N.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Define schedules through an application action using ctx.schedules.set(). Five-field cron expressions, minimum one minute, maximum 20 per environment. No permanent frontend timers.`})]})]})]})}export{P as FilesView,F as SchedulesView};
1
+ import{a as e,r as t}from"./client.BeKNsjPN.js";import{At as n,Ot as r,S as i,_ as a,b as o,g as s,h as c,m as l,n as u,o as d,p as f,pt as p,q as m,s as h,u as g,v as _,x as v,y}from"./common.9pujiaSZ.js";import{c as b,d as x,l as S,o as C,p as w,u as T}from"./index.astro_astro_type_script_index_0_lang.DBs-yURk.js";import{n as E,r as D}from"./client.BSf433s6.js";var O={name:`download`,size:24,node:[[`path`,{d:`M12 15V3`,key:`m9g1x1`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}],[`path`,{d:`m7 10 5 5 5-5`,key:`brsn70`}]]};O.node;var k=r(O),A={name:`trash`,size:24,node:[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]],aliases:[`trash-2`]};A.node;var j=r(A),M=e(t(),1),N=n();function P({project:e,env:t,session:n}){let[r,c]=(0,M.useState)([null]),d=r.at(-1),b=s(e,t),x=g(b+`/files`+(d?`?cursor=`+encodeURIComponent(d):``)),S=(0,M.useRef)(null),[T,O]=(0,M.useState)(!1),[A,P]=(0,M.useState)(!1),[F,I]=(0,M.useState)(``),[L,R]=(0,M.useState)(``),z=n.role!==`viewer`;async function B(){let n=S.current?.files?.[0];if(!n)return;O(!0),I(``),R(``);let r=!1;try{let i=E(n);if(t===`prod`&&!confirm(`Upload to production ${e.name}?`))return;R(`Preparing upload…`),r=!0;let a=await f(b+`/file-upload`,{...i,...t===`prod`?{confirm:e.id}:{}});R(`Uploading ${n.name}…`),await D(a,n),S.current&&(S.current.value=``),P(!1),R(`Upload complete`)}catch(e){R(``),I(l(e)+(r?`. Check the refreshed list before retrying. Incomplete uploads expire automatically; they are not queue jobs.`:``))}finally{O(!1),r&&x.refresh()}}async function V(e){I(``);try{let t=await f(b+`/file-download?id=`+encodeURIComponent(e)),n=document.createElement(`a`);n.href=t.url,n.rel=`noreferrer`,n.click()}catch(e){I(l(e))}}async function H(n){if(confirm(`Permanently delete this ${t} file?`)){O(!0),I(``);try{await f(b+`/file-delete`,{id:n,...t===`prod`?{confirm:e.id}:{}}),x.refresh()}catch(e){I(l(e))}finally{O(!1)}}}return(0,N.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,N.jsx)(`h1`,{className:`page-title`,children:`Files`}),(0,N.jsx)(p,{variant:`ghost`,size:`icon-sm`,"aria-label":`Reload snapshot`,title:`Reload snapshot`,onClick:x.refresh,disabled:x.loading,children:(0,N.jsx)(w,{})})]}),(0,N.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Private R2 storage · streaming uploads · maximum 10 MiB · download links expire after 5 minutes. 50 files per page.`}),(0,N.jsx)(h,{loading:x.loading,error:F||x.error}),L&&(0,N.jsx)(`p`,{role:`status`,className:`text-xs text-muted-foreground`,children:L}),z&&(0,N.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,N.jsx)(m,{ref:S,type:`file`,className:`max-w-sm`,disabled:T,"aria-label":`Choose file to upload`,onChange:e=>P(!!e.target.files?.length)}),(0,N.jsx)(p,{onClick:B,disabled:T||!A,children:`Upload file`})]}),x.data?.page.length?(0,N.jsxs)(a,{children:[(0,N.jsx)(v,{children:(0,N.jsx)(i,{children:[`Name`,`Type`,`Size`,`State`,`Created`,`Actions`].map(e=>(0,N.jsx)(o,{children:e},e))})}),(0,N.jsx)(_,{children:x.data.page.map(e=>(0,N.jsxs)(i,{children:[(0,N.jsx)(y,{children:e.name}),(0,N.jsx)(y,{children:e.type}),(0,N.jsx)(y,{children:e.size>=1048576?`${(e.size/1048576).toFixed(1)} MiB`:e.size<1024?`${e.size} B`:`${(e.size/1024).toFixed(1)} KiB`}),(0,N.jsx)(y,{children:(0,N.jsx)(C,{status:e.state,children:e.state===`pending`?`Awaiting upload`:e.state===`uploading`?`Uploading / recovering`:e.state})}),(0,N.jsx)(y,{children:new Date(e.createdAt).toLocaleString()}),(0,N.jsx)(y,{children:(0,N.jsxs)(`div`,{className:`flex gap-2`,children:[(0,N.jsx)(p,{size:`icon`,variant:`outline`,"aria-label":`Download ${e.name}`,disabled:e.state!==`ready`||T,onClick:()=>void V(e.id),children:(0,N.jsx)(k,{})}),z&&(0,N.jsx)(p,{size:`icon`,variant:`outline`,"aria-label":`Delete ${e.name}`,disabled:T,onClick:()=>void H(e.id),children:(0,N.jsx)(j,{})})]})})]},e.id))})]}):x.data&&(0,N.jsx)(u,{title:`No stored files`}),x.data&&(0,N.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,N.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[`Page `,r.length,` · `,x.data.page.length,` files`]}),(0,N.jsxs)(`div`,{className:`flex gap-2`,children:[(0,N.jsx)(p,{variant:`outline`,disabled:x.loading||r.length===1,onClick:()=>c(e=>e.slice(0,-1)),children:`Previous`}),(0,N.jsx)(p,{variant:`outline`,disabled:x.loading||x.data.isDone,onClick:()=>{x.data?.continueCursor&&c(e=>[...e,x.data.continueCursor])},children:`Next`})]})]})]})}function F({project:e,env:t,session:n}){let r=s(e,t),m=g(r+`/jobs`),[E,D]=(0,M.useState)(``);async function O(n){if(t!==`prod`||confirm(`Pause production cron ${n}?`))try{await f(r+`/cron-cancel`,{name:n,...t===`prod`?{confirm:e.id}:{}}),m.refresh()}catch(e){D(l(e))}}async function k(n){if(t!==`prod`||confirm(`Cancel this pending production job?`)){D(``);try{(await f(r+`/job-cancel`,{id:n,...t===`prod`?{confirm:e.id}:{}})).cancelled||D(`This job is already enqueued; it cannot be cancelled here.`)}catch(e){D(l(e))}finally{m.refresh()}}}return(0,N.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,N.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,N.jsx)(`h1`,{className:`page-title`,children:`Schedules`}),(0,N.jsx)(p,{variant:`ghost`,size:`icon-sm`,"aria-label":`Reload snapshot`,title:`Reload snapshot`,onClick:m.refresh,disabled:m.loading,children:(0,N.jsx)(w,{})})]}),(0,N.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Durable scheduling → transactional outbox → Cloudflare Queues. At-least-once delivery; handlers must be idempotent. Times use UTC.`}),(0,N.jsx)(h,{loading:m.loading,error:m.error||E}),(0,N.jsxs)(b,{defaultValue:`scheduled`,children:[(0,N.jsxs)(T,{variant:`line`,children:[(0,N.jsx)(x,{value:`scheduled`,children:`Scheduled Functions`}),(0,N.jsx)(x,{value:`cron`,children:`Cron Jobs`})]}),(0,N.jsxs)(S,{value:`scheduled`,className:`space-y-4 pt-4`,children:[(0,N.jsx)(`h2`,{className:`section-title`,children:`Waiting to enqueue`}),m.data&&(m.data.pending.length?(0,N.jsxs)(a,{children:[(0,N.jsx)(v,{children:(0,N.jsx)(i,{children:[`Function`,`Due (UTC)`,`Job ID`,``].map((e,t)=>(0,N.jsx)(o,{children:e},t))})}),(0,N.jsx)(_,{children:m.data.pending.map(e=>(0,N.jsxs)(i,{children:[(0,N.jsx)(y,{className:`font-mono`,children:String(e.path)}),(0,N.jsx)(y,{children:new Date(Number(e.dueAt)).toISOString()}),(0,N.jsx)(y,{className:`font-mono`,children:String(e.id)}),(0,N.jsx)(y,{children:n.role!==`viewer`&&(0,N.jsx)(p,{variant:`outline`,disabled:m.loading,onClick:()=>void k(String(e.id)),children:`Cancel`})})]},String(e.id)))})]}):(0,N.jsx)(u,{title:`No delayed jobs`})),(0,N.jsx)(`h2`,{className:`section-title`,children:`Recent queue deliveries`}),m.data&&(m.data.recent.length?(0,N.jsx)(d,{rows:m.data.recent,columns:[`id`,`path`,`state`,`attempts`,`error`,`at`],renderCell:(e,t)=>e===`state`?(0,N.jsx)(C,{status:String(t)}):e===`at`&&typeof t==`number`?new Date(t).toLocaleString():c(t)}):(0,N.jsx)(u,{title:`No queue deliveries yet`}))]}),(0,N.jsxs)(S,{value:`cron`,className:`space-y-4 pt-4`,children:[m.data?.crons.length?(0,N.jsxs)(a,{children:[(0,N.jsx)(v,{children:(0,N.jsx)(i,{children:[`Name`,`Function`,`Cron (UTC)`,`State`,``].map((e,t)=>(0,N.jsx)(o,{children:e},t))})}),(0,N.jsx)(_,{children:m.data.crons.map(e=>(0,N.jsxs)(i,{children:[(0,N.jsx)(y,{children:e.name}),(0,N.jsx)(y,{className:`font-mono`,children:e.path}),(0,N.jsx)(y,{className:`font-mono`,children:e.cron}),(0,N.jsx)(y,{children:(0,N.jsx)(C,{status:e.enabled?`Enabled`:`Paused`})}),(0,N.jsx)(y,{children:n.role!==`viewer`&&e.enabled&&(0,N.jsx)(p,{variant:`outline`,onClick:()=>void O(e.name),children:`Pause`})})]},e.name))})]}):m.data&&(0,N.jsx)(u,{title:`No cron jobs`}),(0,N.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Define schedules through an application action using ctx.schedules.set(). Five-field cron expressions, minimum one minute, maximum 20 per environment. No permanent frontend timers.`})]})]})]})}export{P as FilesView,F as SchedulesView};
@@ -1,3 +1,3 @@
1
- import{a as e,r as t}from"./client.BeKNsjPN.js";import{A as n,At as r,O as i,S as a,_ as o,a as s,b as c,g as l,j as u,k as d,m as f,p,pt as m,q as h,r as g,s as _,u as v,v as y,x as b,y as x}from"./common.9pujiaSZ.js";import{i as S,n as C,o as w,r as T,t as E}from"./index.astro_astro_type_script_index_0_lang.DlEchDEE.js";var D=e(t(),1),O=r();function k(e){return(0,O.jsxs)(`div`,{className:`space-y-3 p-4 pt-0`,children:[(0,O.jsx)(`p`,{className:`text-muted-foreground`,children:`On-demand data, user accounts, files and backend code snapshots. Restore only into an empty environment. Sessions, secrets and schedules are not copied. No background polling.`}),(0,O.jsx)(A,{...e})]})}function A(e){let[t,n]=(0,D.useState)(e.env),[r,i]=(0,D.useState)(null),[u,d]=(0,D.useState)(),f=l(e.project,t),h=l(e.project,e.env),g=v(f+`/backups`+(r?`?cursor=${encodeURIComponent(r)}`:``)),S=v(h+`/backup-status`),C=e.session.role===`owner`,T=(t,n,r,i)=>d({title:t,description:n,productionId:e.project.id,submit:async()=>{await p(r,{...i,confirm:e.project.id}),g.refresh(),S.refresh()}});return(0,O.jsxs)(`div`,{className:`space-y-3`,children:[(0,O.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Limits: 10,000 documents / 4 MiB data; 100 files / 100 MiB. Pause cron and drain jobs before creating a backup. Partial restores stay closed; retry the same backup ID.`}),S.data?.status===`restoring`&&(0,O.jsxs)(`p`,{role:`alert`,children:[(0,O.jsx)(w,{status:`restoring`,children:`Restore in progress`}),`:`,` `,S.data.id,`. Select its source environment and retry Restore to finish.`]}),(0,O.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[[`dev`,`prod`].map(e=>(0,O.jsxs)(m,{variant:t===e?`secondary`:`outline`,onClick:()=>{n(e),i(null)},children:[e===`dev`?`Development`:`Production`,` backups`]},e)),C&&(0,O.jsxs)(m,{onClick:()=>{let t=crypto.randomUUID();T(`Create backup`,`Snapshot ${e.env}. Backup ID: ${t}. No data will be deleted.`,h+`/backup-create`,{id:t})},children:[`Create `,e.env,` backup`]})]}),(0,O.jsx)(_,{loading:g.loading||S.loading,error:g.error||S.error}),g.data&&(0,O.jsxs)(`p`,{role:`status`,className:`text-xs text-muted-foreground`,children:[`Recovery point: `,g.data.recoveryPoint,`.`,` `,g.data.latest&&`Latest completed: ${new Date(g.data.latest.at).toLocaleString()} (${Math.floor((g.data.ageMs??0)/36e5)} hours old).`,` `,`Manual daily backup required for the 24-hour objective; no automatic schedule.`,g.data.inventory===`partial`&&(0,O.jsx)(m,{variant:`outline`,onClick:()=>{i(null),g.refresh()},children:`Continue inventory`})]}),g.data&&(0,O.jsxs)(o,{children:[(0,O.jsx)(b,{children:(0,O.jsxs)(a,{children:[(0,O.jsx)(c,{children:`Created`}),(0,O.jsx)(c,{children:`Backup / release`}),(0,O.jsx)(c,{children:`Documents`}),(0,O.jsx)(c,{children:`Files`}),(0,O.jsx)(c,{children:`Actions`})]})}),(0,O.jsxs)(y,{children:[g.data.page.map(n=>(0,O.jsxs)(a,{children:[(0,O.jsx)(x,{children:n.at?new Date(n.at).toLocaleString():(0,O.jsx)(w,{status:`Incomplete`})}),(0,O.jsxs)(x,{children:[(0,O.jsx)(`code`,{className:`text-xs select-all`,children:n.id}),(0,O.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:n.hash?.slice(0,12)??`Not restorable`})]}),(0,O.jsx)(x,{children:n.rows??`—`}),(0,O.jsx)(x,{children:n.files??`—`}),(0,O.jsx)(x,{children:(0,O.jsxs)(`div`,{className:`flex gap-2`,children:[C&&t!==e.env&&n.hash&&(0,O.jsxs)(m,{variant:`outline`,size:`sm`,onClick:()=>T(`Restore backup`,`Restore ${n.id} from ${t} into empty ${e.env}. Existing data will never be overwritten. Origin/auth settings stay unchanged.`,h+`/backup-restore`,{id:n.id,sourceEnv:t}),children:[`Restore into `,e.env]}),C&&(0,O.jsx)(m,{variant:`outline`,size:`sm`,onClick:()=>T(`Delete backup`,`Permanently delete snapshot ${n.id}. Live application data is not affected. Do not delete a backup needed by an unfinished restore.`,f+`/backup-delete`,{id:n.id}),children:`Delete`})]})})]},n.id)),!g.data.page.length&&(0,O.jsx)(a,{children:(0,O.jsx)(x,{colSpan:5,children:`No backups.`})})]})]}),(0,O.jsxs)(`div`,{className:`flex gap-2`,children:[(0,O.jsx)(m,{variant:`outline`,disabled:!r,onClick:()=>i(null),children:`First page`}),(0,O.jsx)(m,{variant:`outline`,disabled:!g.data?.cursor,onClick:()=>i(g.data?.cursor??null),children:`Next page`})]}),u&&(0,O.jsx)(s,{modal:u,onClose:()=>d(void 0)})]})}function j({onDeleted:e,...t}){let n=l(t.project,t.env),r=v(n+`/settings`),[i,a]=(0,D.useState)(!1);return(0,O.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,O.jsx)(`h1`,{className:`page-title`,children:`Settings`}),(0,O.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Environment identity and frontend permissions.`}),(0,O.jsx)(_,{...r}),r.data&&(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(N,{...t,settings:r.data,refresh:r.refresh}),(0,O.jsxs)(`details`,{className:`rounded-lg border`,onToggle:e=>a(e.currentTarget.open),children:[(0,O.jsx)(`summary`,{className:`cursor-pointer p-4 font-medium`,children:`Backups`}),i&&(0,O.jsx)(k,{...t})]})]}),t.session.role===`owner`&&(0,O.jsx)(M,{...t,onDeleted:e})]})}function M({project:e,onDeleted:t}){let[r,a]=(0,D.useState)();return(0,O.jsxs)(O.Fragment,{children:[(0,O.jsxs)(E,{children:[(0,O.jsx)(T,{children:(0,O.jsx)(S,{children:`Delete project`})}),(0,O.jsxs)(C,{className:`space-y-3`,children:[(0,O.jsx)(`p`,{className:`text-muted-foreground`,children:`Permanently delete both development and production: data, users, files, releases, backups and schedules. This cannot be undone.`}),e.deleting?(0,O.jsx)(`p`,{role:`alert`,children:`Deletion was started. Retry to finish cleanup.`}):null,(0,O.jsx)(m,{variant:`destructive`,onClick:()=>a({title:`Delete project`,description:`Delete ${e.name} and both environments permanently? The short URL stays reserved; other projects are not affected.`,destructive:!0,submitLabel:`Delete project`,content:(0,O.jsxs)(i,{children:[(0,O.jsxs)(n,{htmlFor:`delete-project-name`,children:[`Type the project name: `,e.name]}),(0,O.jsx)(h,{id:`delete-project-name`,name:`name`,required:!0,autoComplete:`off`,maxLength:100})]}),submit:async n=>{let r=new FormData(n).get(`name`);if(r!==e.name)throw Error(`Project name does not match`);try{await p(`projects/${e.id}/delete`,{name:r,confirm:e.id})}catch(t){if(f(t)!==`NOT_FOUND`||(await p(`projects`)).some(t=>t.id===e.id))throw t}t()}}),children:`Delete project`})]})]}),r&&(0,O.jsx)(s,{modal:r,onClose:()=>a(void 0)})]})}function N({project:e,env:t,session:r,settings:a,refresh:o}){let c=l(e,t),_=r.role!==`viewer`,[v,y]=(0,D.useState)(),[b,x]=(0,D.useState)(``),[w,k]=(0,D.useState)(``),[A,j]=(0,D.useState)(!1),M=async e=>{if(!A){j(!0),k(``);try{await e()}catch(e){k(f(e))}finally{j(!1)}}},N=(n,r,i)=>y({title:n,description:r,productionId:t===`prod`?e.id:void 0,submit:async e=>i(t===`prod`?String(new FormData(e).get(`confirm`)):void 0)});return(0,O.jsxs)(O.Fragment,{children:[w&&(0,O.jsx)(g,{children:w}),(0,O.jsxs)(E,{children:[(0,O.jsx)(T,{children:(0,O.jsx)(S,{children:`Cloud URL`})}),(0,O.jsxs)(C,{className:`space-y-3`,children:[(0,O.jsx)(`code`,{className:`block select-all break-all`,children:a.url}),(0,O.jsx)(`p`,{className:`text-muted-foreground`,children:`Permanent project name. Existing UUID URLs remain valid.`}),!a.alias&&r.role===`owner`&&(0,O.jsxs)(`form`,{className:`flex gap-2`,onSubmit:t=>{t.preventDefault();let n=new FormData(t.currentTarget).get(`alias`);M(async()=>{await p(`projects/${e.id}/alias`,{alias:n}),o()})},children:[(0,O.jsx)(h,{name:`alias`,"aria-label":`Short URL name`,required:!0,maxLength:48,pattern:`[a-z][a-z0-9]*(?:-[a-z0-9]+)*`,placeholder:`crm`}),(0,O.jsx)(m,{type:`submit`,disabled:A,children:`Set short URL`})]})]})]}),(0,O.jsxs)(E,{children:[(0,O.jsx)(T,{children:(0,O.jsx)(S,{children:`Environment access`})}),(0,O.jsx)(C,{children:(0,O.jsx)(`form`,{className:`max-w-xl`,onSubmit:e=>{if(e.preventDefault(),!_)return;let t=new FormData(e.currentTarget),n={origins:String(t.get(`origins`)).split(`
1
+ import{a as e,r as t}from"./client.BeKNsjPN.js";import{A as n,At as r,O as i,S as a,_ as o,a as s,b as c,g as l,j as u,k as d,m as f,p,pt as m,q as h,r as g,s as _,u as v,v as y,x as b,y as x}from"./common.9pujiaSZ.js";import{i as S,n as C,o as w,r as T,t as E}from"./index.astro_astro_type_script_index_0_lang.DBs-yURk.js";var D=e(t(),1),O=r();function k(e){return(0,O.jsxs)(`div`,{className:`space-y-3 p-4 pt-0`,children:[(0,O.jsx)(`p`,{className:`text-muted-foreground`,children:`On-demand data, user accounts, files and backend code snapshots. Restore only into an empty environment. Sessions, secrets and schedules are not copied. No background polling.`}),(0,O.jsx)(A,{...e})]})}function A(e){let[t,n]=(0,D.useState)(e.env),[r,i]=(0,D.useState)(null),[u,d]=(0,D.useState)(),f=l(e.project,t),h=l(e.project,e.env),g=v(f+`/backups`+(r?`?cursor=${encodeURIComponent(r)}`:``)),S=v(h+`/backup-status`),C=e.session.role===`owner`,T=(t,n,r,i)=>d({title:t,description:n,productionId:e.project.id,submit:async()=>{await p(r,{...i,confirm:e.project.id}),g.refresh(),S.refresh()}});return(0,O.jsxs)(`div`,{className:`space-y-3`,children:[(0,O.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Limits: 10,000 documents / 4 MiB data; 100 files / 100 MiB. Pause cron and drain jobs before creating a backup. Partial restores stay closed; retry the same backup ID.`}),S.data?.status===`restoring`&&(0,O.jsxs)(`p`,{role:`alert`,children:[(0,O.jsx)(w,{status:`restoring`,children:`Restore in progress`}),`:`,` `,S.data.id,`. Select its source environment and retry Restore to finish.`]}),(0,O.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[[`dev`,`prod`].map(e=>(0,O.jsxs)(m,{variant:t===e?`secondary`:`outline`,onClick:()=>{n(e),i(null)},children:[e===`dev`?`Development`:`Production`,` backups`]},e)),C&&(0,O.jsxs)(m,{onClick:()=>{let t=crypto.randomUUID();T(`Create backup`,`Snapshot ${e.env}. Backup ID: ${t}. No data will be deleted.`,h+`/backup-create`,{id:t})},children:[`Create `,e.env,` backup`]})]}),(0,O.jsx)(_,{loading:g.loading||S.loading,error:g.error||S.error}),g.data&&(0,O.jsxs)(`p`,{role:`status`,className:`text-xs text-muted-foreground`,children:[`Recovery point: `,g.data.recoveryPoint,`.`,` `,g.data.latest&&`Latest completed: ${new Date(g.data.latest.at).toLocaleString()} (${Math.floor((g.data.ageMs??0)/36e5)} hours old).`,` `,`Manual daily backup required for the 24-hour objective; no automatic schedule.`,g.data.inventory===`partial`&&(0,O.jsx)(m,{variant:`outline`,onClick:()=>{i(null),g.refresh()},children:`Continue inventory`})]}),g.data&&(0,O.jsxs)(o,{children:[(0,O.jsx)(b,{children:(0,O.jsxs)(a,{children:[(0,O.jsx)(c,{children:`Created`}),(0,O.jsx)(c,{children:`Backup / release`}),(0,O.jsx)(c,{children:`Documents`}),(0,O.jsx)(c,{children:`Files`}),(0,O.jsx)(c,{children:`Actions`})]})}),(0,O.jsxs)(y,{children:[g.data.page.map(n=>(0,O.jsxs)(a,{children:[(0,O.jsx)(x,{children:n.at?new Date(n.at).toLocaleString():(0,O.jsx)(w,{status:`Incomplete`})}),(0,O.jsxs)(x,{children:[(0,O.jsx)(`code`,{className:`text-xs select-all`,children:n.id}),(0,O.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:n.hash?.slice(0,12)??`Not restorable`})]}),(0,O.jsx)(x,{children:n.rows??`—`}),(0,O.jsx)(x,{children:n.files??`—`}),(0,O.jsx)(x,{children:(0,O.jsxs)(`div`,{className:`flex gap-2`,children:[C&&t!==e.env&&n.hash&&(0,O.jsxs)(m,{variant:`outline`,size:`sm`,onClick:()=>T(`Restore backup`,`Restore ${n.id} from ${t} into empty ${e.env}. Existing data will never be overwritten. Origin/auth settings stay unchanged.`,h+`/backup-restore`,{id:n.id,sourceEnv:t}),children:[`Restore into `,e.env]}),C&&(0,O.jsx)(m,{variant:`outline`,size:`sm`,onClick:()=>T(`Delete backup`,`Permanently delete snapshot ${n.id}. Live application data is not affected. Do not delete a backup needed by an unfinished restore.`,f+`/backup-delete`,{id:n.id}),children:`Delete`})]})})]},n.id)),!g.data.page.length&&(0,O.jsx)(a,{children:(0,O.jsx)(x,{colSpan:5,children:`No backups.`})})]})]}),(0,O.jsxs)(`div`,{className:`flex gap-2`,children:[(0,O.jsx)(m,{variant:`outline`,disabled:!r,onClick:()=>i(null),children:`First page`}),(0,O.jsx)(m,{variant:`outline`,disabled:!g.data?.cursor,onClick:()=>i(g.data?.cursor??null),children:`Next page`})]}),u&&(0,O.jsx)(s,{modal:u,onClose:()=>d(void 0)})]})}function j({onDeleted:e,...t}){let n=l(t.project,t.env),r=v(n+`/settings`),[i,a]=(0,D.useState)(!1);return(0,O.jsxs)(`div`,{className:`space-y-4 p-4`,children:[(0,O.jsx)(`h1`,{className:`page-title`,children:`Settings`}),(0,O.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`Environment identity and frontend permissions.`}),(0,O.jsx)(_,{...r}),r.data&&(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(N,{...t,settings:r.data,refresh:r.refresh}),(0,O.jsxs)(`details`,{className:`rounded-lg border`,onToggle:e=>a(e.currentTarget.open),children:[(0,O.jsx)(`summary`,{className:`cursor-pointer p-4 font-medium`,children:`Backups`}),i&&(0,O.jsx)(k,{...t})]})]}),t.session.role===`owner`&&(0,O.jsx)(M,{...t,onDeleted:e})]})}function M({project:e,onDeleted:t}){let[r,a]=(0,D.useState)();return(0,O.jsxs)(O.Fragment,{children:[(0,O.jsxs)(E,{children:[(0,O.jsx)(T,{children:(0,O.jsx)(S,{children:`Delete project`})}),(0,O.jsxs)(C,{className:`space-y-3`,children:[(0,O.jsx)(`p`,{className:`text-muted-foreground`,children:`Permanently delete both development and production: data, users, files, releases, backups and schedules. This cannot be undone.`}),e.deleting?(0,O.jsx)(`p`,{role:`alert`,children:`Deletion was started. Retry to finish cleanup.`}):null,(0,O.jsx)(m,{variant:`destructive`,onClick:()=>a({title:`Delete project`,description:`Delete ${e.name} and both environments permanently? The short URL stays reserved; other projects are not affected.`,destructive:!0,submitLabel:`Delete project`,content:(0,O.jsxs)(i,{children:[(0,O.jsxs)(n,{htmlFor:`delete-project-name`,children:[`Type the project name: `,e.name]}),(0,O.jsx)(h,{id:`delete-project-name`,name:`name`,required:!0,autoComplete:`off`,maxLength:100})]}),submit:async n=>{let r=new FormData(n).get(`name`);if(r!==e.name)throw Error(`Project name does not match`);try{await p(`projects/${e.id}/delete`,{name:r,confirm:e.id})}catch(t){if(f(t)!==`NOT_FOUND`||(await p(`projects`)).some(t=>t.id===e.id))throw t}t()}}),children:`Delete project`})]})]}),r&&(0,O.jsx)(s,{modal:r,onClose:()=>a(void 0)})]})}function N({project:e,env:t,session:r,settings:a,refresh:o}){let c=l(e,t),_=r.role!==`viewer`,[v,y]=(0,D.useState)(),[b,x]=(0,D.useState)(``),[w,k]=(0,D.useState)(``),[A,j]=(0,D.useState)(!1),M=async e=>{if(!A){j(!0),k(``);try{await e()}catch(e){k(f(e))}finally{j(!1)}}},N=(n,r,i)=>y({title:n,description:r,productionId:t===`prod`?e.id:void 0,submit:async e=>i(t===`prod`?String(new FormData(e).get(`confirm`)):void 0)});return(0,O.jsxs)(O.Fragment,{children:[w&&(0,O.jsx)(g,{children:w}),(0,O.jsxs)(E,{children:[(0,O.jsx)(T,{children:(0,O.jsx)(S,{children:`Cloud URL`})}),(0,O.jsxs)(C,{className:`space-y-3`,children:[(0,O.jsx)(`code`,{className:`block select-all break-all`,children:a.url}),(0,O.jsx)(`p`,{className:`text-muted-foreground`,children:`Permanent project name. Existing UUID URLs remain valid.`}),!a.alias&&r.role===`owner`&&(0,O.jsxs)(`form`,{className:`flex gap-2`,onSubmit:t=>{t.preventDefault();let n=new FormData(t.currentTarget).get(`alias`);M(async()=>{await p(`projects/${e.id}/alias`,{alias:n}),o()})},children:[(0,O.jsx)(h,{name:`alias`,"aria-label":`Short URL name`,required:!0,maxLength:48,pattern:`[a-z][a-z0-9]*(?:-[a-z0-9]+)*`,placeholder:`crm`}),(0,O.jsx)(m,{type:`submit`,disabled:A,children:`Set short URL`})]})]})]}),(0,O.jsxs)(E,{children:[(0,O.jsx)(T,{children:(0,O.jsx)(S,{children:`Environment access`})}),(0,O.jsx)(C,{children:(0,O.jsx)(`form`,{className:`max-w-xl`,onSubmit:e=>{if(e.preventDefault(),!_)return;let t=new FormData(e.currentTarget),n={origins:String(t.get(`origins`)).split(`
2
2
  `).map(e=>e.trim()).filter(Boolean),oidc:[`issuer`,`audience`,`jwks`].some(e=>String(t.get(e)).trim())?Object.fromEntries([`issuer`,`audience`,`jwks`].map(e=>[e,String(t.get(e)).trim()])):null};N(`Save environment`,`Updates frontend origins and user token verification. Existing applications continue to use this environment.`,async e=>{await p(c+`/settings`,{...n,confirm:e}),o()})},children:(0,O.jsxs)(d,{children:[(0,O.jsxs)(i,{children:[(0,O.jsx)(n,{htmlFor:`settings-origins`,children:`Frontend origins · one per line`}),(0,O.jsx)(u,{id:`settings-origins`,name:`origins`,defaultValue:a.origins.join(`
3
3
  `),disabled:!_})]}),(0,O.jsx)(`h3`,{className:`text-sm font-medium`,children:`Authentication · OIDC / RS256`}),(0,O.jsxs)(i,{children:[(0,O.jsx)(n,{htmlFor:`settings-issuer`,children:`Issuer`}),(0,O.jsx)(h,{id:`settings-issuer`,type:`url`,name:`issuer`,defaultValue:a.oidc?.issuer??``,disabled:!_,placeholder:`https://your-provider.example`})]}),(0,O.jsxs)(i,{children:[(0,O.jsx)(n,{htmlFor:`settings-audience`,children:`Audience`}),(0,O.jsx)(h,{id:`settings-audience`,name:`audience`,defaultValue:a.oidc?.audience??``,disabled:!_})]}),(0,O.jsxs)(i,{children:[(0,O.jsx)(n,{htmlFor:`settings-jwks`,children:`JWKS URL`}),(0,O.jsx)(h,{id:`settings-jwks`,type:`url`,name:`jwks`,defaultValue:a.oidc?.jwks??``,disabled:!_,placeholder:`https://your-provider.example/.well-known/jwks.json`})]}),(0,O.jsx)(`p`,{className:`text-muted-foreground`,children:`Leave all three empty to disable OIDC. Protected production functions remain closed.`}),_&&(0,O.jsx)(m,{type:`submit`,children:`Save environment`})]})})})]}),(0,O.jsxs)(E,{children:[(0,O.jsx)(T,{children:(0,O.jsx)(S,{children:`CLI access`})}),(0,O.jsxs)(C,{className:`space-y-4`,children:[(0,O.jsx)(`p`,{children:`Project-scoped deploy credential, valid for 30 days. Never put it in frontend code. Keep it in your shell or CI secret store.`}),r.role===`owner`&&(0,O.jsxs)(`div`,{className:`flex gap-2`,children:[(0,O.jsx)(m,{variant:`outline`,onClick:()=>N(`Issue CLI credential`,`The token is shown once. It grants deployment rights only for this project.`,async t=>{let n=await p(c+`/credential`,{confirm:t});x(`export FLARE_DEPLOY_TOKEN=${n.token}\nflare link --platform ${n.platform} --project ${e.id}\nflare deploy --env dev --release ./release`)}),children:`Issue credential`}),(0,O.jsx)(m,{variant:`destructive`,onClick:()=>N(`Revoke project credentials`,`All existing CLI credentials for this project will stop working.`,async e=>{await p(c+`/revoke-credentials`,{confirm:e}),x(`Credentials revoked.`)}),children:`Revoke credentials`})]}),b&&(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(`pre`,{className:`code-block`,children:b}),(0,O.jsx)(m,{variant:`ghost`,onClick:()=>x(``),children:`Clear from view`})]})]})]}),v&&(0,O.jsx)(s,{modal:v,onClose:()=>y(void 0)})]})}export{j as default};
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="en" class="dark"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="robots" content="noindex,nofollow"><title>Flare · Dashboard</title><meta http-equiv="content-security-policy" content="script-src 'self' 'sha256-xIb/Pa7FUshAu4ihwjchYcQpyCI8eS8kt40GpOAYCz8=' 'sha256-1BvDVWLr3QCC20uHhUDi27eDFVJpk1uMQJGIWKUks2I=' 'sha256-kmZE/W8I1iuTnl1b3yqzv9/DQZenPngd3NjSKMQl7y0=' 'sha256-Y8t0ntteBwH+PqGKUyjWW3CAk+BNJKSoQc0xZ68FjhM=' 'sha256-0O7iB6zr9x0r6X6eWYITC9V5q+yWCGAoFvcysBGbY9Q=' 'sha256-tQIkdAw2vqfQ1PjgUE4ML2A4pIV8SByQ1Seeehy6UIc=' 'sha256-4f86GpVBksx63uHEB4f15jGyhnVEOKjwqYxwnfDVOik='; style-src 'self' 'sha256-vv9IoKo7BSLbWcUHr3tNmfNVmm5L/9Cfn2H6LMk7/ow=' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=';"><link rel="stylesheet" href="/_astro/index.CDrYoVkO.css"></head><body><div id="flare-dashboard"><div class="p-6 text-sm text-muted-foreground" role="status">Loading Flare…</div></div><script type="module" src="/_astro/index.astro_astro_type_script_index_0_lang.DlEchDEE.js"></script></body></html>
1
+ <!DOCTYPE html><html lang="en" class="dark"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="robots" content="noindex,nofollow"><title>Flare · Dashboard</title><meta http-equiv="content-security-policy" content="script-src 'self' 'sha256-xIb/Pa7FUshAu4ihwjchYcQpyCI8eS8kt40GpOAYCz8=' 'sha256-1BvDVWLr3QCC20uHhUDi27eDFVJpk1uMQJGIWKUks2I=' 'sha256-kmZE/W8I1iuTnl1b3yqzv9/DQZenPngd3NjSKMQl7y0=' 'sha256-Y8t0ntteBwH+PqGKUyjWW3CAk+BNJKSoQc0xZ68FjhM=' 'sha256-0O7iB6zr9x0r6X6eWYITC9V5q+yWCGAoFvcysBGbY9Q=' 'sha256-tQIkdAw2vqfQ1PjgUE4ML2A4pIV8SByQ1Seeehy6UIc=' 'sha256-4f86GpVBksx63uHEB4f15jGyhnVEOKjwqYxwnfDVOik='; style-src 'self' 'sha256-vv9IoKo7BSLbWcUHr3tNmfNVmm5L/9Cfn2H6LMk7/ow=' 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=';"><link rel="stylesheet" href="/_astro/index.CDrYoVkO.css"></head><body><div id="flare-dashboard"><div class="p-6 text-sm text-muted-foreground" role="status">Loading Flare…</div></div><script type="module" src="/_astro/index.astro_astro_type_script_index_0_lang.DBs-yURk.js"></script></body></html>
@@ -1,29 +1,31 @@
1
1
  {
2
2
  "format": 1,
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "stateFormat": 1,
5
5
  "protocol": 1,
6
6
  "runtimeAbi": 4,
7
7
  "compatibilityDate": "2026-10-10",
8
8
  "wranglerVersion": "4.150.0",
9
9
  "upgradeFrom": [
10
- "0.3.13"
10
+ "0.3.13",
11
+ "0.3.16",
12
+ "0.3.17"
11
13
  ],
12
14
  "files": [
13
15
  {
14
16
  "path": "admin.js",
15
17
  "bytes": 37491,
16
- "sha256": "fcaef75247dc5d828127e1f1a28cbd98796375370b5f57cc106af9843c63f81b"
18
+ "sha256": "e4b0f4d69c2b3598e431ab44ab3779dfd4546acb140b18c5c22faac56a26fb33"
17
19
  },
18
20
  {
19
- "path": "dashboard/_astro/ai-view.D6ouaMiL.js",
20
- "bytes": 4493,
21
- "sha256": "a69f3e8a04bc93e965d982347ad598799655567b3fb471ac147d3f3f21a0b6e6"
21
+ "path": "dashboard/_astro/ai-view.DcYKk5W_.js",
22
+ "bytes": 4759,
23
+ "sha256": "991d1dbf4cbad8673bfdccc46498f0df6811018a9ec6ca20a82de27405545727"
22
24
  },
23
25
  {
24
- "path": "dashboard/_astro/auth-view.0CuFK-xf.js",
26
+ "path": "dashboard/_astro/auth-view.KnVtTZYn.js",
25
27
  "bytes": 3494,
26
- "sha256": "d426ac75739c5f891d53182fc5b313f8616e8f88f8cf57b04910a42ba0a68c2b"
28
+ "sha256": "845572dc334400d07bcdc1aaf6410b3b6d2fdce6ea4d1767418994053e411bf5"
27
29
  },
28
30
  {
29
31
  "path": "dashboard/_astro/cli-approval.emPTVRqn.js",
@@ -51,14 +53,14 @@
51
53
  "sha256": "d2313bf971c2c4e73f6ed7e5bd9f687c8ece4969f1405e8cc774cbc8885e335d"
52
54
  },
53
55
  {
54
- "path": "dashboard/_astro/data-view.jmNzQKhW.js",
56
+ "path": "dashboard/_astro/data-view.BFL2F3o9.js",
55
57
  "bytes": 5806,
56
- "sha256": "573bf762d37a3c0612237c7d17166129b4259cb09a3364393c0201fe3fe8ad84"
58
+ "sha256": "d48107a85f3552ad204581924e1368c84a5b9b75f08be0d55c80d454861cab80"
57
59
  },
58
60
  {
59
- "path": "dashboard/_astro/functions-view.Bqamd_KY.js",
61
+ "path": "dashboard/_astro/functions-view.vsmqlnUa.js",
60
62
  "bytes": 6206,
61
- "sha256": "62209c9bb9961d0e58476ffb32513f796e46618cfe289b9dcdd0f7cdf22db167"
63
+ "sha256": "ba7e2bfb5595d62ba6a88e662353988af9d7e5ae40ceae15941837b72e4719a3"
62
64
  },
63
65
  {
64
66
  "path": "dashboard/_astro/geist-cyrillic-ext-wght-normal.DjL33-gN.woff2",
@@ -91,9 +93,9 @@
91
93
  "sha256": "be7da729dc120b16d178fcd2606642e03a47fe2f1a2a1a8c4aa40cfcc59e848c"
92
94
  },
93
95
  {
94
- "path": "dashboard/_astro/index.astro_astro_type_script_index_0_lang.DlEchDEE.js",
96
+ "path": "dashboard/_astro/index.astro_astro_type_script_index_0_lang.DBs-yURk.js",
95
97
  "bytes": 37394,
96
- "sha256": "e80d96f895bb9dfe9b7aeae6be8884009b160865c8c0ba027f23a355f9d34b11"
98
+ "sha256": "004838343d2b988eed21ec4d1d60c24030e9ce58f033ecc0e4cc7502837c5ab1"
97
99
  },
98
100
  {
99
101
  "path": "dashboard/_astro/input-group.Dsc4z0iT.js",
@@ -101,19 +103,19 @@
101
103
  "sha256": "7ab083f8bbd656b2a49951f076afb10f008ca5630369955481018aeb27325c50"
102
104
  },
103
105
  {
104
- "path": "dashboard/_astro/sdk-view.DuMOEfZu.js",
106
+ "path": "dashboard/_astro/sdk-view.BPVWrAC3.js",
105
107
  "bytes": 3363,
106
- "sha256": "ec03ec190e89220b111971b456ae07c19b459716861e71a8573328a770207a21"
108
+ "sha256": "52190ae8162f76220eec548c2f4664459265528d6716a8c7b20701b521729e99"
107
109
  },
108
110
  {
109
- "path": "dashboard/_astro/services-view.B7BR4JD3.js",
111
+ "path": "dashboard/_astro/services-view.Dx1rjMWa.js",
110
112
  "bytes": 8249,
111
- "sha256": "bdf8a8b848d3cf02b8b624ecf805f6864519a7bf06385e1969fde75c14169429"
113
+ "sha256": "574adb9a4209902e8baf74580af21efe3336fdea999e456ca53ad82e4b0bafee"
112
114
  },
113
115
  {
114
- "path": "dashboard/_astro/settings-view.DM-igZ4O.js",
116
+ "path": "dashboard/_astro/settings-view.DPwEyqzv.js",
115
117
  "bytes": 10768,
116
- "sha256": "cca7f6d7c7aad8e6c087543b5aadf708fe87017ee42ac58d78b5b58bd7c0302a"
118
+ "sha256": "f5384854e892e4d3bf507f5ac48231ac259593bf94827a2676dd83e1ed89f38a"
117
119
  },
118
120
  {
119
121
  "path": "dashboard/_headers",
@@ -158,7 +160,7 @@
158
160
  {
159
161
  "path": "dashboard/index.html",
160
162
  "bytes": 1095,
161
- "sha256": "46d250d5c3461ccdf19b6f9e84ccc9d84744686e0480121462c0c1872c316f2a"
163
+ "sha256": "88767a2cd15669c2f765bbc68a3f666b3f26eb88586477d78fe55a2f3e7fb40c"
162
164
  },
163
165
  {
164
166
  "path": "migrations/0001.sql",
@@ -192,9 +194,9 @@
192
194
  },
193
195
  {
194
196
  "path": "runtime.js",
195
- "bytes": 1229444,
196
- "sha256": "4e9b195ffe4fcfb1f31404f1017d5d4e243a2b5abd24e40f60a04f2d56cb1202"
197
+ "bytes": 1235276,
198
+ "sha256": "0732ed74b8ec8cdea7ca2a964973b744c0153e41cc0eb9b4dfd48edba87cf663"
197
199
  }
198
200
  ],
199
- "digest": "d6b7bdc282bc48d1f1a1588ae450a8c1ce2f4ec6b1ecb094f7ee82f930195b39"
201
+ "digest": "0ca53e96e1f8606024eb7eed83fcfc5656a8448f1871f7ecc1c8b4ccd5eca518"
200
202
  }
@@ -22956,7 +22956,7 @@ function assertMcpTools(functions) {
22956
22956
  if (fn.mcp === undefined)
22957
22957
  continue;
22958
22958
  const m = fn.mcp;
22959
- if (!m || typeof m !== "object" || Object.keys(m).sort().join() !== "description,name" || typeof m.name !== "string" || !/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(m.name) || typeof m.description !== "string" || !m.description.trim() || m.description.length > 1000 || names.has(m.name) || fn.auth === "internal" || fn.input.type !== "object")
22959
+ if (!m || typeof m !== "object" || Object.keys(m).some((key) => !["name", "description", "readOnly"].includes(key)) || m.readOnly !== undefined && typeof m.readOnly !== "boolean" || fn.kind === "mutation" && m.readOnly === true || fn.kind === "query" && m.readOnly === false || typeof m.name !== "string" || !/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(m.name) || typeof m.description !== "string" || !m.description.trim() || m.description.length > 1000 || names.has(m.name) || fn.auth === "internal" || fn.input.type !== "object")
22960
22960
  throw new FlareError("INVALID_CONTRACT", "Invalid MCP tool contract");
22961
22961
  boundedJson({ mcp: m, input: fn.input }, 16384);
22962
22962
  names.add(m.name);
@@ -22975,7 +22975,7 @@ function appPolicy(env, scope) {
22975
22975
  throw new FlareError("INVALID_CONFIG", "Invalid app capabilities");
22976
22976
  cached = Object.create(null);
22977
22977
  for (const [key, value] of Object.entries(raw)) {
22978
- if (!/^[0-9a-f-]{36}\/(dev|prod)$/.test(key) || !value || Object.keys(value).some((k) => !["outbound", "secrets", "search", "codex"].includes(k)))
22978
+ if (!/^[0-9a-f-]{36}\/(dev|prod)$/.test(key) || !value || Object.keys(value).some((k) => !["outbound", "secrets", "search", "codex", "mcpAuth"].includes(k)))
22979
22979
  throw new FlareError("INVALID_CONFIG", "Invalid capability scope");
22980
22980
  const outbound = value.outbound ?? [], secrets = value.secrets ?? {};
22981
22981
  if (!Array.isArray(outbound) || outbound.length > 20 || !secrets || Array.isArray(secrets) || typeof secrets !== "object" || Object.keys(secrets).length > 16)
@@ -22990,7 +22990,13 @@ function appPolicy(env, scope) {
22990
22990
  throw new FlareError("INVALID_CONFIG", "Invalid search binding");
22991
22991
  if (value.codex !== undefined && (typeof value.codex !== "string" || !/^APP_CODEX_[A-Z0-9_]{1,64}$/.test(value.codex)))
22992
22992
  throw new FlareError("INVALID_CONFIG", "Invalid Codex binding");
22993
+ if (value.mcpAuth !== undefined) {
22994
+ const a = value.mcpAuth;
22995
+ if (!a || Object.keys(a).sort().join() !== "binding,issuer" || !/^APP_MCP_AUTH_[A-Z0-9_]{1,64}$/.test(a.binding) || typeof a.issuer !== "string" || !/^https:\/\/[a-z0-9.-]+$/.test(a.issuer))
22996
+ throw new FlareError("INVALID_CONFIG", "Invalid MCP authorization binding");
22997
+ }
22993
22998
  cached[key] = Object.freeze({
22999
+ ...value.mcpAuth === undefined ? {} : { mcpAuth: Object.freeze({ ...value.mcpAuth }) },
22994
23000
  ...value.codex === undefined ? {} : { codex: value.codex },
22995
23001
  ...value.search === undefined ? {} : { search: value.search },
22996
23002
  outbound: Object.freeze([...new Set(outbound)]),
@@ -23985,11 +23991,13 @@ class SearchStore {
23985
23991
  continue;
23986
23992
  }
23987
23993
  this.storage.sql.exec("UPDATE search_items SET status='sending',uncertain=1,version=? WHERE id=? AND wanted=1", object?.version ?? row.version, row.id);
23988
- this.updateInfo(row, await instance.items.uploadAndPoll(row.key, content, {
23989
- timeoutMs: 30000,
23990
- pollIntervalMs: 2000,
23994
+ const uploaded = await instance.items.upload(row.key, content, {
23991
23995
  ...row.metadata ? { metadata: JSON.parse(row.metadata) } : {}
23992
- }));
23996
+ });
23997
+ this.updateInfo(row, {
23998
+ ...uploaded,
23999
+ status: uploaded.status ?? "queued"
24000
+ });
23993
24001
  }
23994
24002
  } catch (error) {
23995
24003
  this.storage.sql.exec("UPDATE search_items SET error=?,status=CASE WHEN attempts>=3 THEN 'error' ELSE 'pending' END WHERE id=?", errorCode(error) === "SEARCH_RECONCILE_REQUIRED" ? "SEARCH_RECONCILE_REQUIRED" : "SEARCH_UNAVAILABLE", row.id);
@@ -24001,16 +24009,16 @@ class SearchStore {
24001
24009
  }
24002
24010
 
24003
24011
  // packages/core/src/mcp.ts
24004
- function mcpTools(manifest) {
24005
- return Object.values(manifest.functions).flatMap((fn) => fn.mcp && fn.auth !== "internal" ? [
24012
+ function mcpTools(manifest, scopes) {
24013
+ return Object.values(manifest.functions).flatMap((fn) => fn.mcp && fn.auth !== "internal" && (!scopes || scopes.includes("mcp:write") || fn.kind === "query" || fn.mcp.readOnly === true) ? [
24006
24014
  {
24007
24015
  name: fn.mcp.name,
24008
24016
  description: fn.mcp.description,
24009
24017
  inputSchema: fn.input,
24010
24018
  annotations: {
24011
- readOnlyHint: fn.kind === "query",
24012
- destructiveHint: fn.kind !== "query",
24013
- idempotentHint: fn.kind === "query",
24019
+ readOnlyHint: fn.kind === "query" || fn.mcp.readOnly === true,
24020
+ destructiveHint: fn.kind !== "query" && fn.mcp.readOnly !== true,
24021
+ idempotentHint: fn.kind === "query" || fn.mcp.readOnly === true,
24014
24022
  openWorldHint: fn.kind === "action"
24015
24023
  }
24016
24024
  }
@@ -24085,6 +24093,38 @@ async function mcpResponse(request, supervisor) {
24085
24093
  return out;
24086
24094
  }
24087
24095
 
24096
+ // packages/core/src/mcp-auth.ts
24097
+ function mcpResource(env, scope) {
24098
+ return `${env.RUNTIME_URL}/p/${scope}/v1/mcp`;
24099
+ }
24100
+ function mcpMetadata(env, scope) {
24101
+ const configured = appPolicy(env, scope).mcpAuth;
24102
+ if (!configured)
24103
+ return null;
24104
+ return {
24105
+ resource: mcpResource(env, scope),
24106
+ authorization_servers: [configured.issuer],
24107
+ scopes_supported: ["mcp:read"],
24108
+ bearer_methods_supported: ["header"],
24109
+ resource_name: "Flare application MCP"
24110
+ };
24111
+ }
24112
+ function mcpChallenge(env, scope) {
24113
+ return `Bearer resource_metadata="${env.RUNTIME_URL}/.well-known/oauth-protected-resource/p/${scope}/v1/mcp", scope="mcp:read"`;
24114
+ }
24115
+ async function validateMcpToken(env, scope, token) {
24116
+ const configured = appPolicy(env, scope).mcpAuth;
24117
+ if (!configured || !token || token.length > 8192)
24118
+ fail("UNAUTHORIZED");
24119
+ const binding = env[configured.binding];
24120
+ if (!binding?.validateToken)
24121
+ fail("UNAUTHORIZED");
24122
+ const validated = await binding.validateToken(mcpResource(env, scope), token);
24123
+ if (!validated || validated.audience !== mcpResource(env, scope) || !Number.isFinite(validated.expiresAt) || validated.expiresAt * 1000 <= Date.now() || !Array.isArray(validated.scope) || !validated.scope.includes("mcp:read") || typeof validated.clientId !== "string" || !validated.clientId || !validated.props || validated.props.scope !== scope || typeof validated.props.userId !== "string" || validated.props.userId !== validated.userId || typeof validated.props.epoch !== "string")
24124
+ fail("UNAUTHORIZED");
24125
+ return validated;
24126
+ }
24127
+
24088
24128
  // packages/core/src/auth.ts
24089
24129
  import { Buffer as Buffer2 } from "node:buffer";
24090
24130
  import { scrypt, timingSafeEqual } from "node:crypto";
@@ -24153,7 +24193,8 @@ class PasswordAuth {
24153
24193
  "CREATE INDEX IF NOT EXISTS auth_sessions_expires ON auth_sessions(expires)",
24154
24194
  "CREATE TABLE IF NOT EXISTS auth_config (id INTEGER PRIMARY KEY,enabled INTEGER NOT NULL DEFAULT 0,registration INTEGER NOT NULL DEFAULT 0)",
24155
24195
  "INSERT OR IGNORE INTO auth_config VALUES (1,0,0)",
24156
- "CREATE TABLE IF NOT EXISTS auth_limits (id TEXT PRIMARY KEY,at INTEGER NOT NULL,count INTEGER NOT NULL)"
24196
+ "CREATE TABLE IF NOT EXISTS auth_limits (id TEXT PRIMARY KEY,at INTEGER NOT NULL,count INTEGER NOT NULL)",
24197
+ "CREATE TABLE IF NOT EXISTS auth_delegations (userId TEXT PRIMARY KEY,epoch TEXT NOT NULL)"
24157
24198
  ])
24158
24199
  storage.sql.exec(sql);
24159
24200
  }
@@ -24173,6 +24214,7 @@ class PasswordAuth {
24173
24214
  validateAuthBackup(users);
24174
24215
  this.storage.transactionSync(() => {
24175
24216
  this.storage.sql.exec("DELETE FROM auth_sessions");
24217
+ this.storage.sql.exec("DELETE FROM auth_delegations");
24176
24218
  this.storage.sql.exec("DELETE FROM auth_users");
24177
24219
  for (const u of users)
24178
24220
  this.storage.sql.exec("INSERT INTO auth_users VALUES (?,?,?,?,?)", u.id, u.login, u.password, u.disabled, u.createdAt);
@@ -24238,7 +24280,35 @@ class PasswordAuth {
24238
24280
  claims: { flaredSession: id, login: String(row.login) }
24239
24281
  };
24240
24282
  }
24283
+ async delegation(userId) {
24284
+ this.storage.sql.exec("INSERT OR IGNORE INTO auth_delegations VALUES (?,?)", userId, crypto.randomUUID());
24285
+ const epoch = String(this.storage.sql.exec("SELECT epoch FROM auth_delegations WHERE userId=?", userId).one().epoch);
24286
+ await this.storage.sync();
24287
+ return { userId, epoch, login: this.user(userId).login, scope: this.scope };
24288
+ }
24289
+ delegated(userId, epoch, expiresAt, clientId) {
24290
+ if (!this.settings().enabled || !Number.isFinite(expiresAt) || expiresAt <= Date.now())
24291
+ fail("UNAUTHORIZED");
24292
+ const row = this.storage.sql.exec("SELECT u.login FROM auth_users u JOIN auth_delegations d ON d.userId=u.id WHERE u.id=? AND d.epoch=? AND u.disabled=0", userId, epoch).toArray()[0];
24293
+ if (!row)
24294
+ fail("UNAUTHORIZED");
24295
+ return {
24296
+ subject: userId,
24297
+ issuer: this.issuer + "/auth/" + this.scope,
24298
+ expiresAt,
24299
+ claims: {
24300
+ login: String(row.login),
24301
+ flaredDelegation: epoch,
24302
+ flaredMcp: true,
24303
+ flaredMcpClient: clientId
24304
+ }
24305
+ };
24306
+ }
24241
24307
  assert(auth) {
24308
+ if (typeof auth?.claims.flaredDelegation === "string") {
24309
+ this.delegated(auth.subject, auth.claims.flaredDelegation, auth.expiresAt, String(auth.claims.flaredMcpClient ?? ""));
24310
+ return;
24311
+ }
24242
24312
  const session = auth?.claims.flaredSession;
24243
24313
  if (typeof session !== "string")
24244
24314
  return;
@@ -24248,7 +24318,7 @@ class PasswordAuth {
24248
24318
  async public(op, input, token) {
24249
24319
  if (!this.settings().enabled)
24250
24320
  fail("AUTH_DISABLED");
24251
- if (op === "register" || op === "login") {
24321
+ if (op === "register" || op === "login" || op === "delegate") {
24252
24322
  this.limit("global", 30);
24253
24323
  const login = loginName(input.login);
24254
24324
  this.limit("login:" + login, 5);
@@ -24262,11 +24332,15 @@ class PasswordAuth {
24262
24332
  const valid = await verifyPassword(input.password, row ? String(row.password) : undefined);
24263
24333
  if (!valid || !row || row.disabled)
24264
24334
  fail("UNAUTHORIZED");
24335
+ if (op === "delegate")
24336
+ return this.delegation(String(row.id));
24265
24337
  return this.issue(String(row.id));
24266
24338
  }
24267
24339
  if (!token)
24268
24340
  fail("UNAUTHORIZED");
24269
24341
  const auth = await this.authenticate(token);
24342
+ if (op === "mcp-identity")
24343
+ return this.delegation(auth.subject);
24270
24344
  if (op === "me")
24271
24345
  return this.user(auth.subject);
24272
24346
  if (op === "logout") {
@@ -24290,6 +24364,7 @@ class PasswordAuth {
24290
24364
  this.storage.transactionSync(() => {
24291
24365
  this.storage.sql.exec("UPDATE auth_users SET password=? WHERE id=?", hash, id);
24292
24366
  this.storage.sql.exec("DELETE FROM auth_sessions WHERE userId=?", id);
24367
+ this.storage.sql.exec("DELETE FROM auth_delegations WHERE userId=?", id);
24293
24368
  });
24294
24369
  }
24295
24370
  async admin(op, input) {
@@ -24300,8 +24375,10 @@ class PasswordAuth {
24300
24375
  fail("INVALID_INPUT");
24301
24376
  this.storage.transactionSync(() => {
24302
24377
  this.storage.sql.exec("UPDATE auth_config SET enabled=?,registration=? WHERE id=1", +input.enabled, +input.registration);
24303
- if (!input.enabled)
24378
+ if (!input.enabled) {
24304
24379
  this.storage.sql.exec("DELETE FROM auth_sessions");
24380
+ this.storage.sql.exec("DELETE FROM auth_delegations");
24381
+ }
24305
24382
  });
24306
24383
  await this.storage.sync();
24307
24384
  return this.settings();
@@ -24331,6 +24408,7 @@ class PasswordAuth {
24331
24408
  this.storage.sql.exec("UPDATE auth_users SET disabled=? WHERE id=?", +input.disabled, input.id);
24332
24409
  }
24333
24410
  this.storage.sql.exec("DELETE FROM auth_sessions WHERE userId=?", input.id);
24411
+ this.storage.sql.exec("DELETE FROM auth_delegations WHERE userId=?", input.id);
24334
24412
  });
24335
24413
  } else
24336
24414
  fail("INVALID_OPERATION");
@@ -24349,7 +24427,7 @@ function dashboardIdentity(value) {
24349
24427
  // packages/core/package.json
24350
24428
  var package_default = {
24351
24429
  name: "@flare/platform",
24352
- version: "0.3.16",
24430
+ version: "0.3.18",
24353
24431
  type: "module",
24354
24432
  license: "MIT",
24355
24433
  private: true,
@@ -31359,8 +31437,8 @@ function projectAlias(value) {
31359
31437
  return value;
31360
31438
  }
31361
31439
  function applicationRoute(path) {
31362
- const old = path.match(/^\/p\/([^/]+)\/(dev|prod)\/v1\/(call|codex\/events|mcp|auth\/(?:register|login|logout|me|change-password)|live(?:\/ticket)?|files\/(?:upload|download))$/);
31363
- const short = old ? null : path.match(/^\/([^/]+)\/(dev|prod)\/v1\/(call|codex\/events|mcp|auth\/(?:register|login|logout|me|change-password)|live(?:\/ticket)?|files\/(?:upload|download))$/);
31440
+ const old = path.match(/^\/p\/([^/]+)\/(dev|prod)\/v1\/(call|codex\/events|mcp|auth\/(?:register|login|logout|me|change-password|delegate|mcp-identity)|live(?:\/ticket)?|files\/(?:upload|download))$/);
31441
+ const short = old ? null : path.match(/^\/([^/]+)\/(dev|prod)\/v1\/(call|codex\/events|mcp|auth\/(?:register|login|logout|me|change-password|delegate|mcp-identity)|live(?:\/ticket)?|files\/(?:upload|download))$/);
31364
31442
  try {
31365
31443
  if (old)
31366
31444
  return {
@@ -32160,6 +32238,8 @@ class EnvironmentSupervisor extends DurableObject {
32160
32238
  allowedOrigin = input.origin;
32161
32239
  if (input.operation === "preflight")
32162
32240
  return null;
32241
+ if (["delegate", "mcp-identity"].includes(input.operation) && !appPolicy(this.env, this.config().scope).mcpAuth)
32242
+ fail("FORBIDDEN");
32163
32243
  if (input.authorization && !input.authorization.startsWith("Bearer "))
32164
32244
  fail("UNAUTHORIZED");
32165
32245
  const auth = await this.authenticate(input.authorization?.slice(7) ?? null);
@@ -32197,16 +32277,26 @@ class EnvironmentSupervisor extends DurableObject {
32197
32277
  if (input.origin && !this.config().origins.includes(input.origin))
32198
32278
  fail("FORBIDDEN");
32199
32279
  const token = input.authorization;
32200
- if (!token?.startsWith("Bearer flared_session_"))
32280
+ if (!token?.startsWith("Bearer "))
32201
32281
  fail("UNAUTHORIZED");
32202
- const auth = await this.passwords().authenticate(token.slice(7));
32282
+ let auth, scopes;
32283
+ if (token.startsWith("Bearer flared_session_"))
32284
+ auth = await this.passwords().authenticate(token.slice(7));
32285
+ else {
32286
+ const validated = await validateMcpToken(this.env, this.config().scope, token.slice(7));
32287
+ auth = this.passwords().delegated(validated.props.userId, validated.props.epoch, validated.expiresAt * 1000, validated.clientId);
32288
+ scopes = validated.scope;
32289
+ }
32290
+ const tools = mcpTools(this.metadata().manifest, scopes);
32203
32291
  if (input.name === undefined)
32204
- return mcpTools(this.metadata().manifest);
32292
+ return tools;
32293
+ if (!tools.some((tool) => tool.name === input.name))
32294
+ fail("FORBIDDEN");
32205
32295
  const result = await this.call({
32206
32296
  path: "mcp",
32207
32297
  kind: "query",
32208
32298
  args: input.args ?? {},
32209
- auth,
32299
+ auth: { ...auth, claims: { ...auth.claims, flaredMcp: true } },
32210
32300
  mcp: input.name
32211
32301
  });
32212
32302
  this.checkPasswordSession(auth);
@@ -32226,7 +32316,7 @@ class EnvironmentSupervisor extends DurableObject {
32226
32316
  return this.passwordAuth ??= new PasswordAuth(this.ctx.storage, this.config().scope, this.env.RUNTIME_URL);
32227
32317
  }
32228
32318
  checkPasswordSession(auth) {
32229
- if (typeof auth?.claims.flaredSession === "string")
32319
+ if (typeof auth?.claims.flaredSession === "string" || typeof auth?.claims.flaredDelegation === "string")
32230
32320
  this.passwords().assert(auth);
32231
32321
  }
32232
32322
  closeRevokedSockets() {
@@ -32631,6 +32721,7 @@ class EnvironmentSupervisor extends DurableObject {
32631
32721
  search: this.search().summary(),
32632
32722
  tools: mcpTools(this.metadata().manifest).map(({ name, description }) => ({ name, description })),
32633
32723
  auth: "app-session",
32724
+ oauth: mcpMetadata(this.env, this.config().scope),
32634
32725
  endpoint: `${this.env.RUNTIME_URL}/p/${this.config().scope}/v1/mcp`
32635
32726
  };
32636
32727
  if (op === "search-clear")
@@ -33100,7 +33191,9 @@ var runtime_default = {
33100
33191
  target.pathname = target.pathname.slice("/control".length);
33101
33192
  return env.ADMIN_API.request(new Request(target, request));
33102
33193
  }
33103
- const route = applicationRoute(url.pathname);
33194
+ const metadataPrefix = "/.well-known/oauth-protected-resource";
33195
+ const metadataRequest = url.pathname.startsWith(metadataPrefix + "/");
33196
+ const route = applicationRoute(metadataRequest ? url.pathname.slice(metadataPrefix.length) : url.pathname);
33104
33197
  if (!route)
33105
33198
  return new Response("Not found", { status: 404 });
33106
33199
  if (!await env.RATE_LIMITER.limit({
@@ -33114,6 +33207,17 @@ var runtime_default = {
33114
33207
  if (!projectId)
33115
33208
  return new Response("Not found", { status: 404 });
33116
33209
  scope = `${projectId}/${route.env}`;
33210
+ if (metadataRequest) {
33211
+ const metadata = route.operation === "mcp" && mcpMetadata(env, scope);
33212
+ if (!metadata || request.method !== "GET")
33213
+ return new Response("Not found", { status: 404 });
33214
+ return Response.json(metadata, {
33215
+ headers: {
33216
+ "cache-control": "no-store",
33217
+ "access-control-allow-origin": "*"
33218
+ }
33219
+ });
33220
+ }
33117
33221
  const supervisor = getSupervisor(env, scope);
33118
33222
  const requestedOrigin = request.headers.get("origin");
33119
33223
  if (route.operation === "mcp")
@@ -33210,6 +33314,7 @@ var runtime_default = {
33210
33314
  status: out.status,
33211
33315
  headers: {
33212
33316
  "cache-control": "no-store",
33317
+ ...route.operation === "mcp" && scope && out.status === 401 && mcpMetadata(env, scope) ? { "www-authenticate": mcpChallenge(env, scope) } : {},
33213
33318
  ...origin ? { "access-control-allow-origin": origin, vary: "Origin" } : {}
33214
33319
  }
33215
33320
  });
@@ -37,6 +37,8 @@ export declare function boundedJson(value: unknown, maxBytes: number): string;
37
37
  export type McpTool = {
38
38
  name: string;
39
39
  description: string;
40
+ /** A reviewed action may be read-only even though it performs external I/O. Not an authorization grant. */
41
+ readOnly?: boolean;
40
42
  };
41
43
  export declare function assertMcpTools(functions: Record<string, FunctionContract>): void;
42
44
  export interface FunctionContract {
@@ -80,7 +80,7 @@ export function assertMcpTools(functions) {
80
80
  if (fn.mcp === undefined)
81
81
  continue;
82
82
  const m = fn.mcp;
83
- if (!m || typeof m !== "object" || Object.keys(m).sort().join() !== "description,name" || typeof m.name !== "string" || !/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(m.name) || typeof m.description !== "string" || !m.description.trim() || m.description.length > 1000 || names.has(m.name) || fn.auth === "internal" || fn.input.type !== "object")
83
+ if (!m || typeof m !== "object" || Object.keys(m).some((key) => !["name", "description", "readOnly"].includes(key)) || m.readOnly !== undefined && typeof m.readOnly !== "boolean" || fn.kind === "mutation" && m.readOnly === true || fn.kind === "query" && m.readOnly === false || typeof m.name !== "string" || !/^[A-Za-z][A-Za-z0-9_.-]{0,63}$/.test(m.name) || typeof m.description !== "string" || !m.description.trim() || m.description.length > 1000 || names.has(m.name) || fn.auth === "internal" || fn.input.type !== "object")
84
84
  throw new FlareError("INVALID_CONTRACT", "Invalid MCP tool contract");
85
85
  boundedJson({ mcp: m, input: fn.input }, 16384);
86
86
  names.add(m.name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@auersperg/flare",
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Flare client, server declarations and development CLI",