@auersperg/flare 0.3.17 → 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 +25 -24
  18. package/dist/platform/runtime.js +122 -19
  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.17",
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.17",
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,6 +1,6 @@
1
1
  {
2
2
  "format": 1,
3
- "version": "0.3.17",
3
+ "version": "0.3.18",
4
4
  "stateFormat": 1,
5
5
  "protocol": 1,
6
6
  "runtimeAbi": 4,
@@ -8,23 +8,24 @@
8
8
  "wranglerVersion": "4.150.0",
9
9
  "upgradeFrom": [
10
10
  "0.3.13",
11
- "0.3.16"
11
+ "0.3.16",
12
+ "0.3.17"
12
13
  ],
13
14
  "files": [
14
15
  {
15
16
  "path": "admin.js",
16
17
  "bytes": 37491,
17
- "sha256": "9c707d386b230cd3725906aa18233b0fc29a7ef15598e953bc8b4ce02cc0eb42"
18
+ "sha256": "e4b0f4d69c2b3598e431ab44ab3779dfd4546acb140b18c5c22faac56a26fb33"
18
19
  },
19
20
  {
20
- "path": "dashboard/_astro/ai-view.D6ouaMiL.js",
21
- "bytes": 4493,
22
- "sha256": "a69f3e8a04bc93e965d982347ad598799655567b3fb471ac147d3f3f21a0b6e6"
21
+ "path": "dashboard/_astro/ai-view.DcYKk5W_.js",
22
+ "bytes": 4759,
23
+ "sha256": "991d1dbf4cbad8673bfdccc46498f0df6811018a9ec6ca20a82de27405545727"
23
24
  },
24
25
  {
25
- "path": "dashboard/_astro/auth-view.0CuFK-xf.js",
26
+ "path": "dashboard/_astro/auth-view.KnVtTZYn.js",
26
27
  "bytes": 3494,
27
- "sha256": "d426ac75739c5f891d53182fc5b313f8616e8f88f8cf57b04910a42ba0a68c2b"
28
+ "sha256": "845572dc334400d07bcdc1aaf6410b3b6d2fdce6ea4d1767418994053e411bf5"
28
29
  },
29
30
  {
30
31
  "path": "dashboard/_astro/cli-approval.emPTVRqn.js",
@@ -52,14 +53,14 @@
52
53
  "sha256": "d2313bf971c2c4e73f6ed7e5bd9f687c8ece4969f1405e8cc774cbc8885e335d"
53
54
  },
54
55
  {
55
- "path": "dashboard/_astro/data-view.jmNzQKhW.js",
56
+ "path": "dashboard/_astro/data-view.BFL2F3o9.js",
56
57
  "bytes": 5806,
57
- "sha256": "573bf762d37a3c0612237c7d17166129b4259cb09a3364393c0201fe3fe8ad84"
58
+ "sha256": "d48107a85f3552ad204581924e1368c84a5b9b75f08be0d55c80d454861cab80"
58
59
  },
59
60
  {
60
- "path": "dashboard/_astro/functions-view.Bqamd_KY.js",
61
+ "path": "dashboard/_astro/functions-view.vsmqlnUa.js",
61
62
  "bytes": 6206,
62
- "sha256": "62209c9bb9961d0e58476ffb32513f796e46618cfe289b9dcdd0f7cdf22db167"
63
+ "sha256": "ba7e2bfb5595d62ba6a88e662353988af9d7e5ae40ceae15941837b72e4719a3"
63
64
  },
64
65
  {
65
66
  "path": "dashboard/_astro/geist-cyrillic-ext-wght-normal.DjL33-gN.woff2",
@@ -92,9 +93,9 @@
92
93
  "sha256": "be7da729dc120b16d178fcd2606642e03a47fe2f1a2a1a8c4aa40cfcc59e848c"
93
94
  },
94
95
  {
95
- "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",
96
97
  "bytes": 37394,
97
- "sha256": "e80d96f895bb9dfe9b7aeae6be8884009b160865c8c0ba027f23a355f9d34b11"
98
+ "sha256": "004838343d2b988eed21ec4d1d60c24030e9ce58f033ecc0e4cc7502837c5ab1"
98
99
  },
99
100
  {
100
101
  "path": "dashboard/_astro/input-group.Dsc4z0iT.js",
@@ -102,19 +103,19 @@
102
103
  "sha256": "7ab083f8bbd656b2a49951f076afb10f008ca5630369955481018aeb27325c50"
103
104
  },
104
105
  {
105
- "path": "dashboard/_astro/sdk-view.DuMOEfZu.js",
106
+ "path": "dashboard/_astro/sdk-view.BPVWrAC3.js",
106
107
  "bytes": 3363,
107
- "sha256": "ec03ec190e89220b111971b456ae07c19b459716861e71a8573328a770207a21"
108
+ "sha256": "52190ae8162f76220eec548c2f4664459265528d6716a8c7b20701b521729e99"
108
109
  },
109
110
  {
110
- "path": "dashboard/_astro/services-view.B7BR4JD3.js",
111
+ "path": "dashboard/_astro/services-view.Dx1rjMWa.js",
111
112
  "bytes": 8249,
112
- "sha256": "bdf8a8b848d3cf02b8b624ecf805f6864519a7bf06385e1969fde75c14169429"
113
+ "sha256": "574adb9a4209902e8baf74580af21efe3336fdea999e456ca53ad82e4b0bafee"
113
114
  },
114
115
  {
115
- "path": "dashboard/_astro/settings-view.DM-igZ4O.js",
116
+ "path": "dashboard/_astro/settings-view.DPwEyqzv.js",
116
117
  "bytes": 10768,
117
- "sha256": "cca7f6d7c7aad8e6c087543b5aadf708fe87017ee42ac58d78b5b58bd7c0302a"
118
+ "sha256": "f5384854e892e4d3bf507f5ac48231ac259593bf94827a2676dd83e1ed89f38a"
118
119
  },
119
120
  {
120
121
  "path": "dashboard/_headers",
@@ -159,7 +160,7 @@
159
160
  {
160
161
  "path": "dashboard/index.html",
161
162
  "bytes": 1095,
162
- "sha256": "46d250d5c3461ccdf19b6f9e84ccc9d84744686e0480121462c0c1872c316f2a"
163
+ "sha256": "88767a2cd15669c2f765bbc68a3f666b3f26eb88586477d78fe55a2f3e7fb40c"
163
164
  },
164
165
  {
165
166
  "path": "migrations/0001.sql",
@@ -193,9 +194,9 @@
193
194
  },
194
195
  {
195
196
  "path": "runtime.js",
196
- "bytes": 1229488,
197
- "sha256": "700cd3ebb780cdcb894901de68a741c5b7ba43aa23df4170676899d9b11a2044"
197
+ "bytes": 1235276,
198
+ "sha256": "0732ed74b8ec8cdea7ca2a964973b744c0153e41cc0eb9b4dfd48edba87cf663"
198
199
  }
199
200
  ],
200
- "digest": "3d8ebc41c0b0b9c7e1c90490c923fd7788a873668d0513e43c40478e7d293330"
201
+ "digest": "0ca53e96e1f8606024eb7eed83fcfc5656a8448f1871f7ecc1c8b4ccd5eca518"
201
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)]),
@@ -24003,16 +24009,16 @@ class SearchStore {
24003
24009
  }
24004
24010
 
24005
24011
  // packages/core/src/mcp.ts
24006
- function mcpTools(manifest) {
24007
- 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) ? [
24008
24014
  {
24009
24015
  name: fn.mcp.name,
24010
24016
  description: fn.mcp.description,
24011
24017
  inputSchema: fn.input,
24012
24018
  annotations: {
24013
- readOnlyHint: fn.kind === "query",
24014
- destructiveHint: fn.kind !== "query",
24015
- 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,
24016
24022
  openWorldHint: fn.kind === "action"
24017
24023
  }
24018
24024
  }
@@ -24087,6 +24093,38 @@ async function mcpResponse(request, supervisor) {
24087
24093
  return out;
24088
24094
  }
24089
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
+
24090
24128
  // packages/core/src/auth.ts
24091
24129
  import { Buffer as Buffer2 } from "node:buffer";
24092
24130
  import { scrypt, timingSafeEqual } from "node:crypto";
@@ -24155,7 +24193,8 @@ class PasswordAuth {
24155
24193
  "CREATE INDEX IF NOT EXISTS auth_sessions_expires ON auth_sessions(expires)",
24156
24194
  "CREATE TABLE IF NOT EXISTS auth_config (id INTEGER PRIMARY KEY,enabled INTEGER NOT NULL DEFAULT 0,registration INTEGER NOT NULL DEFAULT 0)",
24157
24195
  "INSERT OR IGNORE INTO auth_config VALUES (1,0,0)",
24158
- "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)"
24159
24198
  ])
24160
24199
  storage.sql.exec(sql);
24161
24200
  }
@@ -24175,6 +24214,7 @@ class PasswordAuth {
24175
24214
  validateAuthBackup(users);
24176
24215
  this.storage.transactionSync(() => {
24177
24216
  this.storage.sql.exec("DELETE FROM auth_sessions");
24217
+ this.storage.sql.exec("DELETE FROM auth_delegations");
24178
24218
  this.storage.sql.exec("DELETE FROM auth_users");
24179
24219
  for (const u of users)
24180
24220
  this.storage.sql.exec("INSERT INTO auth_users VALUES (?,?,?,?,?)", u.id, u.login, u.password, u.disabled, u.createdAt);
@@ -24240,7 +24280,35 @@ class PasswordAuth {
24240
24280
  claims: { flaredSession: id, login: String(row.login) }
24241
24281
  };
24242
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
+ }
24243
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
+ }
24244
24312
  const session = auth?.claims.flaredSession;
24245
24313
  if (typeof session !== "string")
24246
24314
  return;
@@ -24250,7 +24318,7 @@ class PasswordAuth {
24250
24318
  async public(op, input, token) {
24251
24319
  if (!this.settings().enabled)
24252
24320
  fail("AUTH_DISABLED");
24253
- if (op === "register" || op === "login") {
24321
+ if (op === "register" || op === "login" || op === "delegate") {
24254
24322
  this.limit("global", 30);
24255
24323
  const login = loginName(input.login);
24256
24324
  this.limit("login:" + login, 5);
@@ -24264,11 +24332,15 @@ class PasswordAuth {
24264
24332
  const valid = await verifyPassword(input.password, row ? String(row.password) : undefined);
24265
24333
  if (!valid || !row || row.disabled)
24266
24334
  fail("UNAUTHORIZED");
24335
+ if (op === "delegate")
24336
+ return this.delegation(String(row.id));
24267
24337
  return this.issue(String(row.id));
24268
24338
  }
24269
24339
  if (!token)
24270
24340
  fail("UNAUTHORIZED");
24271
24341
  const auth = await this.authenticate(token);
24342
+ if (op === "mcp-identity")
24343
+ return this.delegation(auth.subject);
24272
24344
  if (op === "me")
24273
24345
  return this.user(auth.subject);
24274
24346
  if (op === "logout") {
@@ -24292,6 +24364,7 @@ class PasswordAuth {
24292
24364
  this.storage.transactionSync(() => {
24293
24365
  this.storage.sql.exec("UPDATE auth_users SET password=? WHERE id=?", hash, id);
24294
24366
  this.storage.sql.exec("DELETE FROM auth_sessions WHERE userId=?", id);
24367
+ this.storage.sql.exec("DELETE FROM auth_delegations WHERE userId=?", id);
24295
24368
  });
24296
24369
  }
24297
24370
  async admin(op, input) {
@@ -24302,8 +24375,10 @@ class PasswordAuth {
24302
24375
  fail("INVALID_INPUT");
24303
24376
  this.storage.transactionSync(() => {
24304
24377
  this.storage.sql.exec("UPDATE auth_config SET enabled=?,registration=? WHERE id=1", +input.enabled, +input.registration);
24305
- if (!input.enabled)
24378
+ if (!input.enabled) {
24306
24379
  this.storage.sql.exec("DELETE FROM auth_sessions");
24380
+ this.storage.sql.exec("DELETE FROM auth_delegations");
24381
+ }
24307
24382
  });
24308
24383
  await this.storage.sync();
24309
24384
  return this.settings();
@@ -24333,6 +24408,7 @@ class PasswordAuth {
24333
24408
  this.storage.sql.exec("UPDATE auth_users SET disabled=? WHERE id=?", +input.disabled, input.id);
24334
24409
  }
24335
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);
24336
24412
  });
24337
24413
  } else
24338
24414
  fail("INVALID_OPERATION");
@@ -24351,7 +24427,7 @@ function dashboardIdentity(value) {
24351
24427
  // packages/core/package.json
24352
24428
  var package_default = {
24353
24429
  name: "@flare/platform",
24354
- version: "0.3.17",
24430
+ version: "0.3.18",
24355
24431
  type: "module",
24356
24432
  license: "MIT",
24357
24433
  private: true,
@@ -31361,8 +31437,8 @@ function projectAlias(value) {
31361
31437
  return value;
31362
31438
  }
31363
31439
  function applicationRoute(path) {
31364
- const old = path.match(/^\/p\/([^/]+)\/(dev|prod)\/v1\/(call|codex\/events|mcp|auth\/(?:register|login|logout|me|change-password)|live(?:\/ticket)?|files\/(?:upload|download))$/);
31365
- 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))$/);
31366
31442
  try {
31367
31443
  if (old)
31368
31444
  return {
@@ -32162,6 +32238,8 @@ class EnvironmentSupervisor extends DurableObject {
32162
32238
  allowedOrigin = input.origin;
32163
32239
  if (input.operation === "preflight")
32164
32240
  return null;
32241
+ if (["delegate", "mcp-identity"].includes(input.operation) && !appPolicy(this.env, this.config().scope).mcpAuth)
32242
+ fail("FORBIDDEN");
32165
32243
  if (input.authorization && !input.authorization.startsWith("Bearer "))
32166
32244
  fail("UNAUTHORIZED");
32167
32245
  const auth = await this.authenticate(input.authorization?.slice(7) ?? null);
@@ -32199,16 +32277,26 @@ class EnvironmentSupervisor extends DurableObject {
32199
32277
  if (input.origin && !this.config().origins.includes(input.origin))
32200
32278
  fail("FORBIDDEN");
32201
32279
  const token = input.authorization;
32202
- if (!token?.startsWith("Bearer flared_session_"))
32280
+ if (!token?.startsWith("Bearer "))
32203
32281
  fail("UNAUTHORIZED");
32204
- 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);
32205
32291
  if (input.name === undefined)
32206
- return mcpTools(this.metadata().manifest);
32292
+ return tools;
32293
+ if (!tools.some((tool) => tool.name === input.name))
32294
+ fail("FORBIDDEN");
32207
32295
  const result = await this.call({
32208
32296
  path: "mcp",
32209
32297
  kind: "query",
32210
32298
  args: input.args ?? {},
32211
- auth,
32299
+ auth: { ...auth, claims: { ...auth.claims, flaredMcp: true } },
32212
32300
  mcp: input.name
32213
32301
  });
32214
32302
  this.checkPasswordSession(auth);
@@ -32228,7 +32316,7 @@ class EnvironmentSupervisor extends DurableObject {
32228
32316
  return this.passwordAuth ??= new PasswordAuth(this.ctx.storage, this.config().scope, this.env.RUNTIME_URL);
32229
32317
  }
32230
32318
  checkPasswordSession(auth) {
32231
- if (typeof auth?.claims.flaredSession === "string")
32319
+ if (typeof auth?.claims.flaredSession === "string" || typeof auth?.claims.flaredDelegation === "string")
32232
32320
  this.passwords().assert(auth);
32233
32321
  }
32234
32322
  closeRevokedSockets() {
@@ -32633,6 +32721,7 @@ class EnvironmentSupervisor extends DurableObject {
32633
32721
  search: this.search().summary(),
32634
32722
  tools: mcpTools(this.metadata().manifest).map(({ name, description }) => ({ name, description })),
32635
32723
  auth: "app-session",
32724
+ oauth: mcpMetadata(this.env, this.config().scope),
32636
32725
  endpoint: `${this.env.RUNTIME_URL}/p/${this.config().scope}/v1/mcp`
32637
32726
  };
32638
32727
  if (op === "search-clear")
@@ -33102,7 +33191,9 @@ var runtime_default = {
33102
33191
  target.pathname = target.pathname.slice("/control".length);
33103
33192
  return env.ADMIN_API.request(new Request(target, request));
33104
33193
  }
33105
- 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);
33106
33197
  if (!route)
33107
33198
  return new Response("Not found", { status: 404 });
33108
33199
  if (!await env.RATE_LIMITER.limit({
@@ -33116,6 +33207,17 @@ var runtime_default = {
33116
33207
  if (!projectId)
33117
33208
  return new Response("Not found", { status: 404 });
33118
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
+ }
33119
33221
  const supervisor = getSupervisor(env, scope);
33120
33222
  const requestedOrigin = request.headers.get("origin");
33121
33223
  if (route.operation === "mcp")
@@ -33212,6 +33314,7 @@ var runtime_default = {
33212
33314
  status: out.status,
33213
33315
  headers: {
33214
33316
  "cache-control": "no-store",
33317
+ ...route.operation === "mcp" && scope && out.status === 401 && mcpMetadata(env, scope) ? { "www-authenticate": mcpChallenge(env, scope) } : {},
33215
33318
  ...origin ? { "access-control-allow-origin": origin, vary: "Origin" } : {}
33216
33319
  }
33217
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.17",
3
+ "version": "0.3.18",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Flare client, server declarations and development CLI",