everyapp 0.2.2 → 0.3.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -77
  3. package/bin/everyapp.js +235 -0
  4. package/dist/access-LGEN3ABJ.js +1 -0
  5. package/dist/activity-RSD4D66F.js +12 -0
  6. package/dist/apps-4RCFXT74.js +13 -0
  7. package/dist/chunk-23HJ5I2A.js +2 -0
  8. package/dist/chunk-2Y5Q6A5K.js +6 -0
  9. package/dist/chunk-4JRIS6S6.js +1 -0
  10. package/dist/chunk-5PTNYZK6.js +4 -0
  11. package/dist/chunk-6OGVO7QK.js +6 -0
  12. package/dist/chunk-6PGUCTJ6.js +11 -0
  13. package/dist/chunk-AGTCKFRB.js +22 -0
  14. package/dist/chunk-BHMRY53V.js +2 -0
  15. package/dist/chunk-CB4U7H2G.js +4 -0
  16. package/dist/chunk-CCWBPAKH.js +4 -0
  17. package/dist/chunk-CZTEDWZ2.js +22 -0
  18. package/dist/chunk-CZXHKPRZ.js +2 -0
  19. package/dist/chunk-E3EPK27P.js +10 -0
  20. package/dist/chunk-EGEWRFVY.js +1 -0
  21. package/dist/chunk-ELK7QZ2M.js +1 -0
  22. package/dist/chunk-FJJSSVET.js +33 -0
  23. package/dist/chunk-GKBPYVP3.js +25 -0
  24. package/dist/chunk-H6QQMY7B.js +18 -0
  25. package/dist/chunk-H7PDL3X5.js +1 -0
  26. package/dist/chunk-HOUHG236.js +20 -0
  27. package/dist/chunk-IFCPALVC.js +46 -0
  28. package/dist/chunk-IUOBIB5M.js +30 -0
  29. package/dist/chunk-J35DDCNU.js +1 -0
  30. package/dist/chunk-J455FAEN.js +7 -0
  31. package/dist/chunk-JYKRUS5C.js +1 -0
  32. package/dist/chunk-LXYMDZER.js +1 -0
  33. package/dist/chunk-LYNBZ7RV.js +57 -0
  34. package/dist/chunk-M2QQ2UD7.js +132 -0
  35. package/dist/chunk-N4E5YE4X.js +5 -0
  36. package/dist/chunk-N5GQLGEC.js +2 -0
  37. package/dist/chunk-NFU4YFXB.js +1 -0
  38. package/dist/chunk-OM2HDWVP.js +1 -0
  39. package/dist/chunk-ONLNJXVQ.js +32 -0
  40. package/dist/chunk-OP4DYXYI.js +2 -0
  41. package/dist/chunk-PNLU5U3P.js +1 -0
  42. package/dist/chunk-PS7S74DG.js +6 -0
  43. package/dist/chunk-RMF4YGD6.js +98 -0
  44. package/dist/chunk-T2GD7RHS.js +10 -0
  45. package/dist/chunk-TLRM3P7V.js +15 -0
  46. package/dist/chunk-W3JCQHHU.js +1 -0
  47. package/dist/chunk-WOVS3GV5.js +10 -0
  48. package/dist/chunk-YHJZMJYZ.js +1 -0
  49. package/dist/chunk-ZECBN24L.js +15 -0
  50. package/dist/chunk-ZEXVHB22.js +2 -0
  51. package/dist/chunk-ZFCUH5PK.js +7 -0
  52. package/dist/configure-F7UZCJUG.js +8 -0
  53. package/dist/create-2E5HVWYK.js +22 -0
  54. package/dist/db-HEQVTDTM.js +9 -0
  55. package/dist/delete-XCSIQIRS.js +3 -0
  56. package/dist/deploy-3QOZEZHC.js +1 -0
  57. package/dist/dev-JL3ZP5BT.js +86 -0
  58. package/dist/email-RLZFUFUN.js +10 -0
  59. package/dist/events-2V5VRBWP.js +15 -0
  60. package/dist/groups-HDG5DVFY.js +8 -0
  61. package/dist/index.js +97 -1
  62. package/dist/install-Z5FYXUYM.js +1 -0
  63. package/dist/login-KHJBC64Z.js +1 -0
  64. package/dist/mcp-EFDUKJ5V.js +1 -0
  65. package/dist/provider-EOI5PTFH.js +13 -0
  66. package/dist/release-74J5ZIL3.js +1 -0
  67. package/dist/restore-FFGYV7NO.js +3 -0
  68. package/dist/secret-7FKKTLHB.js +1 -0
  69. package/dist/setup-PAKRCAFO.js +1 -0
  70. package/dist/signin-AP3D4XM4.js +12 -0
  71. package/dist/status-RMWNHOEK.js +4 -0
  72. package/dist/teardown-E4JNKAZJ.js +22 -0
  73. package/dist/update-DWVZFNPS.js +1 -0
  74. package/dist/workspace-CJC5I66L.js +21 -0
  75. package/package.json +19 -16
  76. package/skills/build-every-app/SKILL.md +199 -0
  77. package/skills/build-every-app/patterns.md +140 -0
  78. package/skills/everyapp/SKILL.md +292 -0
  79. package/skills/everyapp/mcp.md +350 -0
  80. package/skills/everyapp/security-review.md +61 -0
  81. package/skills/everyapp/setup/README.md +274 -0
  82. package/skills/everyapp/setup/access.md +178 -0
  83. package/skills/everyapp/setup/context.md +117 -0
  84. package/skills/everyapp/setup/dataforseo.md +287 -0
  85. package/skills/everyapp/setup/email.md +366 -0
  86. package/skills/everyapp/setup/gateway.md +243 -0
  87. package/skills/everyapp/setup/google.md +360 -0
  88. package/skills/everyapp/setup/microsoft-365.md +281 -0
  89. package/skills/everyapp/setup/openai.md +318 -0
  90. package/skills/everyapp/setup/openrouter.md +309 -0
  91. package/skills/everyapp/setup/providers.md +1253 -0
  92. package/skills/everyapp/setup/remote-mcp.md +199 -0
  93. package/skills/everyapp/setup/signin-apple.md +178 -0
  94. package/skills/everyapp/setup/signin-cloudflare.md +148 -0
  95. package/skills/everyapp/setup/signin-github.md +139 -0
  96. package/skills/everyapp/setup/signin-google.md +178 -0
  97. package/skills/everyapp/setup/signin-microsoft.md +183 -0
  98. package/skills/everyapp/setup/signin-oidc.md +163 -0
  99. package/skills/everyapp/setup/slack.md +344 -0
  100. package/skills/everyapp/setup/workers-ai.md +138 -0
  101. package/bin/__everyapp_bash_complete.js +0 -12
  102. package/dist/bash-complete.js +0 -3
  103. package/dist/chunk-7BOQJFI5.js +0 -8
  104. package/dist/chunk-7YVJFS4A.js +0 -1
  105. package/dist/chunk-BIXKPCDH.js +0 -2
  106. package/dist/chunk-DLGPLHBH.js +0 -47
  107. package/dist/chunk-FD6K2YA7.js +0 -9
  108. package/dist/chunk-GAJEQYJH.js +0 -39
  109. package/dist/chunk-O2KDOP5R.js +0 -13
  110. package/dist/chunk-OI2MBGBG.js +0 -4
  111. package/dist/chunk-POSDLD3G.js +0 -8
  112. package/dist/chunk-RB5D2R45.js +0 -1
  113. package/dist/chunk-U4LIQ5VR.js +0 -1
  114. package/dist/chunk-VEYSNPDH.js +0 -3
  115. package/dist/chunk-VP6SKW44.js +0 -7
  116. package/dist/chunk-WO3NE7ZU.js +0 -7
  117. package/dist/chunk-XTO2VTPY.js +0 -6
  118. package/dist/chunk-YJ2DKIZS.js +0 -1
  119. package/dist/create-DYQ3NBWJ.js +0 -22
  120. package/dist/deploy-PYTCMDGV.js +0 -7
  121. package/dist/deploy-RMAHOA4Z.js +0 -55
  122. package/dist/dev-SAE237FS.js +0 -0
  123. package/dist/generateConfig-46Z3ERF3.js +0 -1
  124. package/dist/login-B6EF3SMX.js +0 -1
  125. package/dist/logout-XMKZBLNV.js +0 -1
  126. package/dist/remoteD1Shell-A67JMO3H.js +0 -6
  127. package/dist/setupLocal-TZJUW5ES.js +0 -6
  128. package/gateway/every-app-gateway-build.tar.gz +0 -0
@@ -0,0 +1,132 @@
1
+ import{$ as L,B as J,C as V,W as ce,Z as l,y as Y}from"./chunk-RMF4YGD6.js";import{e as N}from"./chunk-NFU4YFXB.js";import{Bb as m,c as E,k as M}from"./chunk-LYNBZ7RV.js";var le=`SELECT users.id AS id, users.email AS email, users.name AS name, members.role AS role
2
+ FROM members JOIN users ON users.id = members.user_id
3
+ WHERE members.organization_id = ?1 AND lower(users.email) = ?2
4
+ LIMIT 1`,v=(e,n,a)=>`EXISTS (
5
+ SELECT 1 FROM members owners JOIN users owner ON owner.id = owners.user_id
6
+ WHERE owners.organization_id = ${e} AND owners.role = 'owner' AND owners.user_id <> ${n}
7
+ AND (owner.banned IS NULL OR owner.banned = 0 OR (owner.ban_expires IS NOT NULL AND owner.ban_expires <= ${a}))
8
+ )`;async function ra(e,n,a,t){let r=a.trim().toLowerCase(),i=Date.now(),[d=[],,p=[]]=await e.run([{sql:le,params:[n,r]},{sql:`UPDATE members SET role = ?3
9
+ WHERE organization_id = ?1
10
+ AND user_id = (SELECT id FROM users WHERE lower(email) = ?2 LIMIT 1)
11
+ AND role <> ?3
12
+ AND NOT (
13
+ role = 'owner' AND ?3 <> 'owner'
14
+ AND NOT ${v("?1","members.user_id","?4")}
15
+ )`,params:[n,r,t,i]},{sql:le,params:[n,r]}]),s=ue(d[0]);if(!s)return{kind:"not_found"};if(s.role===t)return{kind:"unchanged",member:s};let o=ue(p[0])??s;return o.role===t?{kind:"changed",member:o,previousRole:s.role}:{kind:"last_owner",member:s}}function ue(e){return e?{id:String(e.id),email:String(e.email),name:String(e.name??""),role:String(e.role)}:null}import{createHash as He,randomBytes as ae,randomUUID as D}from"node:crypto";async function qe(e){let n=await L(e);if(!n||!n.hasOwner)throw new m("WORKSPACE_NOT_CLAIMED",`The Gateway has no owner yet
16
+ The setup claim makes the workspace, named after its owner; rename it after.`,{fix:"open the Gateway in a browser and claim it, then run this again"});return n.organization}function ga(e,n){return ce(async()=>{let a=await qe(e),t=a.name!==n;return t&&await e.run([{sql:"UPDATE organizations SET name = ? WHERE id = ?",params:[n,a.id]}]),{organization:{...a,name:n},previousName:a.name,changed:t}})}var Ge=72*60*60*1e3,Be=60*60*1e3,Re=1e9,me=60,ge=255,ne=90,Ye=19,Je=e=>He("sha256").update(e).digest("hex"),x=e=>`((',' || replace(${e}, ' ', '') || ',') LIKE '%,owner,%')`,Oe=e=>`(NOT ${x(e)} OR ${v("?2","?1","?3")})`,z=`EXISTS (SELECT 1 FROM members m WHERE m.user_id = ?1 AND m.organization_id = ?2 AND ${Oe("m.role")})`,$=`EXISTS (SELECT 1 FROM members m WHERE m.user_id = ?1 AND m.organization_id = ?2)
17
+ AND NOT EXISTS (SELECT 1 FROM members mine WHERE mine.user_id = ?1 AND ${x("mine.role")}
18
+ AND NOT ${v("mine.organization_id","?1","?3")})`,Ve=e=>`(banned = 1 AND (ban_expires IS NULL OR ban_expires > ${e}))`;function F(e,n){let a=[];for(let t=0;t<e.length;t+=n)a.push(e.slice(t,t+n));return a}function Xe(e){let n=(e??"").split(",").map(a=>a.trim());return n.includes("owner")?"owner":n.includes("admin")?"admin":n.includes("member")?"member":null}var g=e=>Number(e??0);function H(e,n){let a=Number(e.banned??0)===1,t=e.ban_expires==null?null:Number(e.ban_expires);return{id:String(e.id),name:String(e.name??""),email:String(e.email),role:String(e.role??"member"),primaryRole:Xe(l(e.role)),deactivated:a&&(t===null||t>n),createdAt:g(e.created_at)}}function te(e,n){let a=String(e.status),t=g(e.expires_at);return{id:String(e.id),email:String(e.email),role:String(e.role??"member"),status:a,expiresAt:t,createdAt:g(e.created_at),live:a==="pending"&&t>n}}function Se(e){return{id:String(e.id),name:String(e.name),description:l(e.description),createdAt:g(e.created_at),memberCount:g(e.member_count),appCount:g(e.app_count)}}function re(e){return{id:String(e.id),appSlug:String(e.app_slug),name:String(e.name),description:String(e.description??""),status:String(e.status),scope:String(e.scope),tier:String(e.tier),hostname:l(e.hostname),everyone:Number(e.is_default??0)===1,manifest:l(e.manifest),secretNames:l(e.secret_names),accessCount:g(e.access_count)}}var q="u.id, u.name, u.email, m.role, u.banned, u.ban_expires, u.created_at",ie=`a.id, a.app_slug, a.name, a.description, a.status, a.scope, a.tier, a.hostname, a.is_default, a.manifest, a.secret_names,
19
+ (SELECT COUNT(DISTINCT g.user_id) FROM (
20
+ SELECT ua.user_id FROM user_app_access ua WHERE ua.app_row_id = a.id AND ua.organization_id = a.organization_id
21
+ UNION ALL
22
+ SELECT gm.user_id FROM group_app_access ga JOIN group_members gm ON gm.group_id = ga.group_id
23
+ WHERE ga.app_row_id = a.id AND ga.organization_id = a.organization_id AND gm.organization_id = a.organization_id
24
+ ) g JOIN members mm ON mm.user_id = g.user_id AND mm.organization_id = a.organization_id) AS access_count`,U=e=>({id:String(e.id),name:String(e.name),slug:String(e.slug)});async function Te(e,n){let a=n.trim(),[t=[],r=[]]=await e.run([{sql:`SELECT id, name, slug FROM organizations
25
+ WHERE id = ?1 OR slug = ?1 OR lower(name) = lower(?1)
26
+ ORDER BY created_at, id`,params:[a]},{sql:"SELECT id, name, slug FROM organizations ORDER BY created_at, id"}]),i=t.map(U),d=i.find(s=>s.id===a)??i.find(s=>s.slug===a);if(d)return d;if(i.length===1)return i[0];if(i.length>1)throw new m("ORG_AMBIGUOUS",`${i.length} organizations are named ${a}: ${M(i.map(s=>`${s.slug} (${s.id})`))}
27
+ A name isn't unique, and any owner or admin can rename their organization; a slug or id is one organization's.`,{fix:"name it by its slug or id with --org",data:{organizations:i}});let p=r.map(U);throw new m("ORGANIZATION_NOT_FOUND",`No organization named ${a} on this Gateway${p.length>0?`
28
+ The Gateway has: ${M(p.map(s=>`${s.slug} (${s.name})`))}.`:""}`,{fix:"name one by its slug, id or name with --org",data:{organizations:p}})}async function Ke(e,n){if(n.email===null)return{actor:n.actor,email:null,userId:null};let[a=[]]=await e.run([{sql:"SELECT id FROM users WHERE lower(email) = lower(?) AND email_verified = 1",params:[n.email]}]);return{actor:n.actor,email:n.email,userId:l(a[0]?.id)}}var De=()=>new m("ORGANIZATION_NOT_FOUND",`The Gateway has no organization yet
29
+ Its owner creates the first one by claiming it.`,{rerun:`${E} setup`,rerunNote:"prints the owner link"});async function _a(e,n){if(n!==void 0)return Te(e,n);let a=await L(e);if(!a)throw De();return a.organization}async function Ea(e,n,a={}){let[t,r]=await Promise.all([L(e),Ke(e,n)]);if(a.org===void 0&&!t)throw De();let i=a.org===void 0?t.organization:await Te(e,a.org);return{db:e,organization:i,installOrganizationId:t?.organization.id??null,operator:r,now:a.now??Date.now()}}async function k(e,n){let a=n.trim(),[t=[]]=await e.db.run([{sql:`SELECT ${q} FROM members m JOIN users u ON u.id = m.user_id
30
+ WHERE m.organization_id = ?1 AND (lower(u.email) = lower(?2) OR u.id = ?2)
31
+ ORDER BY (u.id = ?2) DESC LIMIT 1`,params:[e.organization.id,a]}]),r=t[0];if(!r)throw new m("USER_NOT_FOUND",`${a} isn't a member of ${e.organization.name}`,{rerun:`${E} workspace users`,rerunNote:"lists the members and invitations"});return H(r,e.now)}async function P(e,n,{callable:a=!1}={}){let t=n.trim(),[r=[]]=await e.db.run([{sql:`SELECT ${ie} FROM apps a
32
+ WHERE (a.organization_id = ?1${a?" OR a.scope = 'shared'":""}) AND a.status != '${N}'
33
+ AND (a.app_slug = ?2 OR a.id = ?2)
34
+ ORDER BY (a.organization_id = ?1) DESC, (a.id = ?2) DESC LIMIT 1`,params:[e.organization.id,t]}]),i=r[0];if(!i)throw new m("APP_NOT_FOUND",`No app named ${t} in ${e.organization.name}`,{rerun:`${E} workspace apps`,rerunNote:"lists them"});return re(i)}async function ke(e,n){let a=n.trim(),[t=[]]=await e.db.run([{sql:`${Ce} AND (g.id = ?2 OR lower(g.name) = lower(?2)) ORDER BY (g.id = ?2) DESC LIMIT 1`,params:[e.organization.id,a]}]),r=t[0];if(!r)throw new m("GROUP_NOT_FOUND",`No group named ${a} in ${e.organization.name}`,{rerun:`${E} workspace groups`,rerunNote:"lists them"});return Se(r)}async function he(e,n){let a=n.trim(),[t=[]]=await e.db.run([{sql:`SELECT id, email, role, status, expires_at, created_at FROM invitations
35
+ WHERE organization_id = ?1 AND status = 'pending' AND (id = ?2 OR lower(email) = lower(?2))
36
+ ORDER BY (id = ?2) DESC, created_at DESC LIMIT 1`,params:[e.organization.id,a]}]),r=t[0];if(!r)throw new m("INVITATION_NOT_PENDING",`No pending invitation for ${a} in ${e.organization.name}
37
+ It was accepted, canceled or never made.`,{rerun:`${E} workspace users`,rerunNote:"lists the pending invitations"});return te(r,e.now)}async function Na(e){let n=e.organization.id,[a=[],t=[]]=await e.db.run([{sql:`SELECT u.email FROM members m JOIN users u ON u.id = m.user_id
38
+ WHERE m.organization_id = ?1 AND ${x("m.role")} ORDER BY m.created_at, u.email`,params:[n]},{sql:`SELECT
39
+ (SELECT COUNT(*) FROM members WHERE organization_id = ?1) AS members,
40
+ (SELECT COUNT(*) FROM members m JOIN users u ON u.id = m.user_id WHERE m.organization_id = ?1 AND ${Ve("?2")}) AS deactivated,
41
+ (SELECT COUNT(*) FROM invitations WHERE organization_id = ?1 AND status = 'pending' AND expires_at > ?2) AS invitations,
42
+ (SELECT COUNT(*) FROM groups WHERE organization_id = ?1) AS groups,
43
+ (SELECT COUNT(*) FROM apps WHERE organization_id = ?1 AND status != '${N}') AS apps`,params:[n,e.now]}]),r=t[0]??{};return{organization:e.organization,owners:a.map(i=>String(i.email)),counts:{members:g(r.members),deactivated:g(r.deactivated),invitations:g(r.invitations),groups:g(r.groups),apps:g(r.apps)}}}async function ba(e){let[n=[],a=[]]=await e.db.run([{sql:`SELECT ${q} FROM members m JOIN users u ON u.id = m.user_id
44
+ WHERE m.organization_id = ?1 ORDER BY u.email`,params:[e.organization.id]},{sql:`SELECT id, email, role, status, expires_at, created_at FROM invitations
45
+ WHERE organization_id = ?1 AND status = 'pending' ORDER BY created_at DESC`,params:[e.organization.id]}]),t={owner:0,admin:1,member:2};return{members:n.map(r=>H(r,e.now)).sort((r,i)=>(t[r.primaryRole??"member"]??3)-(t[i.primaryRole??"member"]??3)||r.email.localeCompare(i.email)),invitations:a.map(r=>te(r,e.now))}}function Ie(){let e=`einv_${ae(32).toString("base64url")}`;return{token:e,hash:Je(e)}}var Aa=(e,n)=>`${e}/accept-invitation?token=${encodeURIComponent(n)}`,fa=(e,n)=>`${e}/reset-password?token=${encodeURIComponent(n)}`;async function Ra(e,n,a){let t=n.trim().toLowerCase(),r=await je(e,"invite");await _e(e,t);let i=D(),{token:d,hash:p}=Ie(),s=e.now+Ge,[,,o=[]]=await e.db.run([{sql:`INSERT INTO invitations (id, organization_id, email, role, status, expires_at, created_at, inviter_id)
46
+ SELECT ?1, ?2, ?3, ?4, 'pending', ?5, ?6, ?7
47
+ WHERE NOT EXISTS (SELECT 1 FROM members m JOIN users u ON u.id = m.user_id WHERE m.organization_id = ?2 AND lower(u.email) = ?3)
48
+ AND NOT EXISTS (SELECT 1 FROM invitations i WHERE i.organization_id = ?2 AND lower(i.email) = ?3 AND i.status = 'pending' AND i.expires_at > ?6)`,params:[i,e.organization.id,t,a,s,e.now,r]},{sql:`INSERT INTO invitation_link_tokens (id, invitation_id, token_hash, created_at)
49
+ SELECT ?1, ?2, ?3, ?4 WHERE EXISTS (SELECT 1 FROM invitations WHERE id = ?2)`,params:[D(),i,p,e.now]},{sql:"SELECT id, email, role, status, expires_at, created_at FROM invitations WHERE id = ?",params:[i]}]),u=o[0];if(!u)throw await _e(e,t),new m("ALREADY_INVITED",`${t} was invited meanwhile`,{retryable:!0});return{invitation:te(u,e.now),token:d}}async function je(e,n){let{operator:a}=e;if(a.userId!==null){let[r=[]]=await e.db.run([{sql:"SELECT 1 AS member FROM members WHERE user_id = ? AND organization_id = ?",params:[a.userId,e.organization.id]}]);if(r.length>0)return a.userId}let t=a.email===null?"An API token has no account on the Gateway":a.userId===null?`${a.email} has no account on this Gateway (a verified one)`:`${a.email} isn't a member of ${e.organization.name}`;throw new m("WORKSPACE_NOT_A_MEMBER",`Only a member can ${n}: an invitation records who sent it
50
+ ${t}.`,{fix:a.email===null?`log in with your Cloudflare account (${E} login), claim the Gateway (${E} setup) or get invited, or invite from Admin \u2192 Users`:`claim the Gateway (${E} setup) or get invited to ${e.organization.name}, or invite from Admin \u2192 Users`})}async function _e(e,n){let[a=[],t=[]]=await e.db.run([{sql:"SELECT u.email FROM members m JOIN users u ON u.id = m.user_id WHERE m.organization_id = ?1 AND lower(u.email) = ?2",params:[e.organization.id,n]},{sql:"SELECT id FROM invitations WHERE organization_id = ?1 AND lower(email) = ?2 AND status = 'pending' AND expires_at > ?3",params:[e.organization.id,n,e.now]}]);if(a.length>0)throw new m("ALREADY_MEMBER",`${n} is a member of ${e.organization.name} already`,{rerun:`${E} workspace users`,rerunNote:"lists the members"});if(t.length>0)throw new m("ALREADY_INVITED",`${n} has a pending invitation to ${e.organization.name} already`,{rerun:`${E} workspace invite-link ${n}`,rerunNote:"prints a new link for it"})}async function Oa(e,n){let a=await he(e,n);if(!a.live)throw new m("INVITATION_NOT_PENDING",`The invitation for ${a.email} expired on ${new Date(a.expiresAt).toISOString()}`,{rerun:`${E} workspace invite ${a.email}`,rerunNote:"makes a new one"});let{token:t,hash:r}=Ie(),[i=[]]=await e.db.run([{sql:`INSERT INTO invitation_link_tokens (id, invitation_id, token_hash, created_at)
51
+ SELECT ?1, ?2, ?3, ?4 WHERE EXISTS (SELECT 1 FROM invitations WHERE id = ?2 AND status = 'pending' AND expires_at > ?4)
52
+ RETURNING id`,params:[D(),a.id,r,e.now]}]);if(i.length===0)throw new m("INVITATION_NOT_PENDING",`The invitation for ${a.email} was used or canceled meanwhile`);return{invitation:a,token:t}}async function Sa(e,n){let a=await he(e,n),[t=[]]=await e.db.run([{sql:"UPDATE invitations SET status = 'canceled' WHERE id = ? AND organization_id = ? AND status = 'pending' RETURNING id",params:[a.id,e.organization.id]}]);if(t.length===0)throw new m("INVITATION_NOT_PENDING",`The invitation for ${a.email} was used or canceled meanwhile`);return{...a,status:"canceled",live:!1}}function Ee(e,n,a,t){let i=t.id===e.organization.id?`${n.email} is the last owner of ${t.name} who can act, so they can't be ${a}`:`${n.email} is the last owner of ${t.name} who can act, and a deactivation is account-wide: it would leave ${t.name} without one`,d=t.id===e.installOrganizationId?{rerun:`${E} workspace role <email> owner`,rerunNote:"for someone else, then this command again"}:{fix:`an owner of ${t.name} makes someone else an owner under Manage workspace \u2192 Users, then run this again`};return new m("LAST_OWNER",`${i}
53
+ Make someone else an owner of ${t.name} first, then try again.`,{...d,data:{organization:t,member:{id:n.id,email:n.email,name:n.name}}})}async function Ze(e,n,a){let[t=[]]=await e.db.run([{sql:`SELECT o.id, o.name, o.slug FROM members mine JOIN organizations o ON o.id = mine.organization_id
54
+ WHERE mine.user_id = ?1 AND ${a?"1":"mine.organization_id = ?3"} AND ${x("mine.role")}
55
+ AND NOT ${v("mine.organization_id","?1","?2")}
56
+ ORDER BY (mine.organization_id = ?3) DESC, o.created_at, o.id`,params:[n,e.now,e.organization.id]}]);return t.map(U)}async function C(e,n,a,t,{afterWrite:r=!1}={}){let i=r?await k(e,n.id):n,d=await Ze(e,i.id,t);if(d[0])throw Ee(e,i,a,d[0]);if(r)throw Ee(e,i,a,e.organization)}function ve(e,n,a){let t=[n.id,e.organization.id,e.now];return[{sql:`UPDATE users SET banned = 1, ban_reason = ?4, ban_expires = NULL, updated_at = ?3
57
+ WHERE id = ?1 AND ${$} RETURNING id`,params:[...t,a]},{sql:`DELETE FROM sessions WHERE user_id = ?1 AND ${$}`,params:t},{sql:`UPDATE user_access_tokens SET revoked_at = ?3, updated_at = ?3
58
+ WHERE user_id = ?1 AND revoked_at IS NULL AND ${$}`,params:t},{sql:`UPDATE mcp_connections SET revoked_at = ?3, revoked_reason = 'user_deactivated'
59
+ WHERE user_id = ?1 AND revoked_at IS NULL AND ${$}`,params:t}]}async function Ta(e,n){let a=await k(e,n);await C(e,a,"deactivated",!0);let[t=[]]=await e.db.run(ve(e,a,`Deactivated by ${e.operator.actor} (${E} workspace deactivate)`));return t.length===0&&await C(e,a,"deactivated",!0,{afterWrite:!0}),{member:{...a,deactivated:!0},already:a.deactivated}}async function Da(e,n){let a=await k(e,n);return await e.db.run([{sql:`UPDATE users SET banned = 0, ban_reason = NULL, ban_expires = NULL, updated_at = ?3
60
+ WHERE id = ?1 AND EXISTS (SELECT 1 FROM members m WHERE m.user_id = ?1 AND m.organization_id = ?2)`,params:[a.id,e.organization.id,e.now]}]),{member:{...a,deactivated:!1},already:!a.deactivated}}async function ka(e,n,a){let t=await k(e,n);await C(e,t,"removed",!1);let[r=[]]=await e.db.run([{sql:"SELECT COUNT(*) AS n FROM members WHERE user_id = ? AND organization_id != ?",params:[t.id,e.organization.id]}]),i=g(r[0]?.n);if(i===0&&await a.accessMayLetBackIn(t)){let[o=[]]=await e.db.run(ve(e,t,`Removed by ${e.operator.actor} (${E} workspace remove); deactivated instead, as Cloudflare Access would let them back in`));return o.length===0&&await C(e,t,"removed",!0,{afterWrite:!0}),{member:{...t,deactivated:!0},deactivatedInstead:!0,accountDeleted:!1,otherOrganizations:i}}let d=[t.id,e.organization.id,e.now],[,,,,p=[],s=[]]=await e.db.run([{sql:`DELETE FROM user_app_access WHERE user_id = ?1 AND organization_id = ?2 AND ${z}`,params:d},{sql:`DELETE FROM group_members WHERE user_id = ?1 AND organization_id = ?2 AND ${z}`,params:d},{sql:`UPDATE user_access_tokens SET revoked_at = ?3, updated_at = ?3
61
+ WHERE user_id = ?1 AND organization_id = ?2 AND revoked_at IS NULL AND ${z}`,params:d},{sql:`UPDATE mcp_connections SET revoked_at = ?3, revoked_reason = 'member_removed'
62
+ WHERE user_id = ?1 AND organization_id = ?2 AND revoked_at IS NULL AND ${z}`,params:d},{sql:`DELETE FROM members WHERE user_id = ?1 AND organization_id = ?2 AND ${Oe("role")} RETURNING id`,params:d},a.deleteAccounts?{sql:"DELETE FROM users WHERE id = ?1 AND NOT EXISTS (SELECT 1 FROM members WHERE user_id = ?1) RETURNING id",params:[t.id]}:{sql:"SELECT NULL AS id WHERE 0"}]);return p.length===0&&await C(e,t,"removed",!1,{afterWrite:!0}),{member:t,deactivatedInstead:!1,accountDeleted:s.length>0,otherOrganizations:i}}async function ha(e,n){let a=await k(e,n);if(a.deactivated)throw new m("PASSWORD_RESET_REQUIRES_ACTIVE_USER",`${a.email} is deactivated, and a password-reset link is only for an active account`,{rerun:`${E} workspace reactivate ${a.email}`,rerunNote:"first, if they should be back"});let[t=[]]=await e.db.run([{sql:`SELECT o.id, o.name, o.slug FROM members m JOIN organizations o ON o.id = m.organization_id
63
+ WHERE m.user_id = ?1 AND m.organization_id != ?2 ORDER BY o.created_at, o.id`,params:[a.id,e.organization.id]}]);if(t.length>0){let d=t.map(U);throw new m("USER_IN_OTHER_ORGANIZATION",`${a.email} also belongs to ${M(d.map(p=>p.name))}, and a password is account-wide
64
+ The Gateway's own rule: a password-reset link is never made for someone in another organization, since it would reach that one too.`,{fix:"they reset it themselves with Forgot password (the Gateway's email must be configured), or they are removed from the other organization first",data:{member:{id:a.id,email:a.email,name:a.name},organizations:d}})}let r=ae(24).toString("base64url"),i=e.now+Be;return await e.db.run([{sql:`INSERT INTO verifications (id, identifier, value, expires_at, created_at, updated_at)
65
+ VALUES (?1, ?2, ?3, ?4, ?5, ?5)`,params:[D(),`reset-password:${r}`,a.id,i,e.now]}]),{member:a,token:r,expiresAt:i}}var Ce=`SELECT g.id, g.name, g.description, g.created_at,
66
+ (SELECT COUNT(*) FROM group_members gm WHERE gm.group_id = g.id) AS member_count,
67
+ (SELECT COUNT(*) FROM group_app_access ga JOIN apps a ON a.id = ga.app_row_id AND a.status != '${N}' WHERE ga.group_id = g.id) AS app_count
68
+ FROM groups g WHERE g.organization_id = ?1`;async function Ia(e){let[n=[]]=await e.db.run([{sql:`${Ce} ORDER BY g.name`,params:[e.organization.id]}]);return n.map(Se)}function we(e){let n=e.trim();if(n.length<1||n.length>me)throw new m("GROUP_NAME_INVALID",`A group name is 1 to ${me} characters${n?` (${n.length} given)`:""}`);return n}function ye(e){return new m("GROUP_NAME_TAKEN",`A group named "${e}" exists already in this organization`,{rerun:`${E} workspace groups`,rerunNote:"lists them"})}var Qe=()=>`grp_${ae(8).toString("hex")}`;async function va(e,n){let a=we(n.name),t=n.description?.trim()||null,r=Qe(),[i=[]]=await e.db.run([{sql:`INSERT INTO groups (id, organization_id, name, description, created_at, created_by)
69
+ SELECT ?1, ?2, ?3, ?4, ?5, ?6
70
+ WHERE NOT EXISTS (SELECT 1 FROM groups WHERE organization_id = ?2 AND lower(name) = lower(?3))
71
+ RETURNING id`,params:[r,e.organization.id,a,t,e.now,e.operator.userId]}]);if(i.length===0)throw ye(a);return{id:r,name:a,description:t,createdAt:e.now,memberCount:0,appCount:0}}async function Ca(e,n,a){let t=await ke(e,n),r=a.name===void 0?t.name:we(a.name),i=a.description===void 0?t.description:a.description.trim()||null,[d=[]]=await e.db.run([{sql:`UPDATE groups SET name = ?3, description = ?4
72
+ WHERE id = ?1 AND organization_id = ?2
73
+ AND NOT EXISTS (SELECT 1 FROM groups WHERE organization_id = ?2 AND lower(name) = lower(?3) AND id != ?1)
74
+ RETURNING id`,params:[t.id,e.organization.id,r,i]}]);if(d.length===0)throw ye(r);return{...t,name:r,description:i}}async function wa(e,n){let a=await ke(e,n),t=[a.id,e.organization.id];return await e.db.run([{sql:"DELETE FROM group_app_access WHERE group_id = ?1 AND organization_id = ?2",params:t},{sql:"DELETE FROM group_members WHERE group_id = ?1 AND organization_id = ?2",params:t},{sql:"DELETE FROM groups WHERE id = ?1 AND organization_id = ?2",params:t}]),a}async function Ne(e,n){let[a=[]]=await e.db.run([{sql:`SELECT ${q}, (gm.user_id IS NOT NULL) AS in_group
75
+ FROM members m JOIN users u ON u.id = m.user_id
76
+ LEFT JOIN group_members gm ON gm.group_id = ?2 AND gm.user_id = u.id
77
+ WHERE m.organization_id = ?1 ORDER BY u.email`,params:[e.organization.id,n.id]}]);return a.map(t=>({...H(t,e.now),inGroup:Number(t.in_group)===1}))}function oe(e,n){let a=new Set(e);if(n.set){let i=new Set(n.set);return{add:[...i].filter(d=>!a.has(d)),remove:[...a].filter(d=>!i.has(d))}}let t=[...new Set(n.add??[])].filter(i=>!a.has(i)),r=[...new Set(n.remove??[])].filter(i=>a.has(i));return{add:t,remove:r}}async function T(e,n){let a=[];for(let t of n){let r=await k(e,t);a.some(i=>i.id===r.id)||a.push(r)}return a}async function X(e,n){let a=[];for(let t of n){let r=await P(e,t);a.some(i=>i.id===r.id)||a.push(r)}return a}async function ya(e,n,a){let[t,r,i]=await Promise.all([a.set?T(e,a.set):void 0,T(e,a.add??[]),T(e,a.remove??[])]),d=await Ne(e,n),p=d.filter(u=>u.inGroup).map(u=>u.id),s=oe(p,{set:t?.map(u=>u.id),add:r.map(u=>u.id),remove:i.map(u=>u.id)}),o=new Map(d.map(u=>[u.id,u]));return await e.db.run([...F(s.remove,ne).map(u=>({sql:`DELETE FROM group_members WHERE group_id = ? AND organization_id = ? AND user_id IN (${u.map(()=>"?").join(", ")})`,params:[n.id,e.organization.id,...u]})),...s.add.map(u=>({sql:`INSERT INTO group_members (group_id, user_id, organization_id, added_at, added_by)
78
+ SELECT ?1, ?2, ?3, ?4, ?5 WHERE EXISTS (SELECT 1 FROM members WHERE user_id = ?2 AND organization_id = ?3)
79
+ ON CONFLICT DO NOTHING`,params:[n.id,u,e.organization.id,e.now,e.operator.userId]}))]),{added:s.add.map(u=>o.get(u)),removed:s.remove.map(u=>o.get(u)),members:await Ne(e,n)}}async function be(e,n){let[a=[]]=await e.db.run([{sql:`SELECT ${ie}, (ga.group_id IS NOT NULL) AS granted FROM apps a
80
+ LEFT JOIN group_app_access ga ON ga.group_id = ?2 AND ga.app_row_id = a.id
81
+ WHERE a.organization_id = ?1 AND a.scope != 'shared' AND a.status != '${N}' ORDER BY a.name`,params:[e.organization.id,n.id]}]);return a.map(t=>({...re(t),granted:Number(t.granted)===1}))}function G(e){return new m("SHARED_APP_ACCESS",`${e.appSlug} is a shared app: every member of every organization can open it, so its access can't be changed`)}async function Wa(e,n,a){let[t,r,i]=await Promise.all([a.set?X(e,a.set):void 0,X(e,a.add??[]),X(e,a.remove??[])]);for(let o of[...t??[],...r])if(o.scope==="shared")throw G(o);let d=await be(e,n),p=oe(d.filter(o=>o.granted).map(o=>o.id),{set:t?.map(o=>o.id),add:r.map(o=>o.id),remove:i.map(o=>o.id)}),s=new Map(d.map(o=>[o.id,o]));return await e.db.run([...F(p.remove,ne).map(o=>({sql:`DELETE FROM group_app_access WHERE group_id = ? AND organization_id = ? AND app_row_id IN (${o.map(()=>"?").join(", ")})`,params:[n.id,e.organization.id,...o]})),...p.add.map(o=>({sql:`INSERT INTO group_app_access (group_id, app_row_id, organization_id, granted_at, granted_by)
82
+ SELECT ?1, ?2, ?3, ?4, ?5
83
+ WHERE EXISTS (SELECT 1 FROM apps WHERE id = ?2 AND organization_id = ?3 AND scope != 'shared' AND status != '${N}')
84
+ ON CONFLICT DO NOTHING`,params:[n.id,o,e.organization.id,e.now,e.operator.userId]}))]),{added:p.add.map(o=>s.get(o)),removed:p.remove.map(o=>s.get(o)),apps:await be(e,n)}}async function Ma(e){let[n=[]]=await e.db.run([{sql:`SELECT ${ie} FROM apps a WHERE a.organization_id = ?1 AND a.status != '${N}' ORDER BY a.name`,params:[e.organization.id]}]);return n.map(re)}function ea(e){let n=e.trim();if(n.length<1||n.length>ge)throw new m("APP_NAME_INVALID",`An app's name is 1 to ${ge} characters${n?` (${n.length} given)`:", not empty"}`,{fix:"give --name the name the app library should show, or leave --name off"});return n}async function La(e,n,a){let t=await P(e,n);if(a.name===void 0&&a.description===void 0&&a.everyone===void 0)throw new m("NOTHING_TO_SET","Nothing to set: give --name, --description or --everyone on|off");if(t.scope==="shared"&&a.everyone)throw G(t);let r=a.name===void 0?t.name:ea(a.name),i=a.description===void 0?t.description:a.description.trim(),d=a.everyone??t.everyone,p=[];if(d&&!t.everyone){let[o=[]]=await e.db.run([{sql:"SELECT user_id FROM members WHERE organization_id = ?",params:[e.organization.id]}]);for(let u of F(o,Ye))p.push({sql:`INSERT INTO user_app_access (id, user_id, app_row_id, organization_id, granted_by) VALUES ${u.map(()=>"(?, ?, ?, ?, ?)").join(", ")} ON CONFLICT DO NOTHING RETURNING id`,params:u.flatMap(R=>[D(),String(R.user_id),t.id,e.organization.id,e.operator.userId])})}let[,...s]=await e.db.run([{sql:`UPDATE apps SET name = ?3, description = ?4, is_default = ?5, updated_at = ?6
85
+ WHERE id = ?1 AND organization_id = ?2 AND status != '${N}'`,params:[t.id,e.organization.id,r,i,d?1:0,e.now]},...p]);return{app:await P(e,t.id),granted:s.reduce((o,u)=>o+u.length,0)}}async function Ae(e,n){if(n.scope==="shared")throw G(n);let[a=[]]=await e.db.run([{sql:`SELECT ${q},
86
+ (ua.id IS NOT NULL) AS direct,
87
+ (SELECT group_concat(g.name, char(31)) FROM group_app_access ga
88
+ JOIN group_members gm ON gm.group_id = ga.group_id AND gm.user_id = u.id
89
+ JOIN groups g ON g.id = ga.group_id
90
+ WHERE ga.app_row_id = ?2 AND ga.organization_id = ?1) AS via_groups
91
+ FROM members m JOIN users u ON u.id = m.user_id
92
+ LEFT JOIN user_app_access ua ON ua.app_row_id = ?2 AND ua.organization_id = ?1 AND ua.user_id = u.id
93
+ WHERE m.organization_id = ?1 ORDER BY u.email`,params:[e.organization.id,n.id]}]);return a.map(t=>({...H(t,e.now),direct:Number(t.direct)===1,viaGroups:l(t.via_groups)?.split("").sort()??[]}))}async function za(e,n,a){if(n.scope==="shared")throw G(n);let[t,r,i]=await Promise.all([a.set?T(e,a.set):void 0,T(e,a.add??[]),T(e,a.remove??[])]),d=await Ae(e,n),p=oe(d.filter(o=>o.direct).map(o=>o.id),{set:t?.map(o=>o.id),add:r.map(o=>o.id),remove:i.map(o=>o.id)}),s=new Map(d.map(o=>[o.id,o]));return await e.db.run([...F(p.remove,ne).map(o=>({sql:`DELETE FROM user_app_access WHERE app_row_id = ? AND organization_id = ? AND user_id IN (${o.map(()=>"?").join(", ")})`,params:[n.id,e.organization.id,...o]})),...p.add.map(o=>({sql:`INSERT INTO user_app_access (id, user_id, app_row_id, organization_id, granted_at, granted_by)
94
+ SELECT ?1, ?2, ?3, ?4, ?5, ?6 WHERE EXISTS (SELECT 1 FROM members WHERE user_id = ?2 AND organization_id = ?4)
95
+ ON CONFLICT DO NOTHING`,params:[D(),o,n.id,e.organization.id,e.now,e.operator.userId]}))]),{granted:p.add.map(o=>s.get(o)),revoked:p.remove.map(o=>s.get(o)),users:await Ae(e,n)}}function ee(e){return e.appCap!==null?{cap:e.appCap,source:"app"}:e.unlimited?{cap:null,source:null}:e.defaultCap!==null?{cap:e.defaultCap,source:"default"}:{cap:null,source:null}}var We=(e,n)=>e===null?n!==null:n===null||e>n,fe=new WeakMap;function Me(e){let n=fe.get(e);return n||(n=e.run([{sql:"PRAGMA table_info(org_settings)"},{sql:"PRAGMA table_info(org_app_settings)"}]).then(([a=[],t=[]])=>a.length>0&&t.some(r=>r.name==="unlimited")),fe.set(e,n)),n}async function se(e){if(!await Me(e))throw new m("GATEWAY_PREDATES_DEFAULT_CAPS",`The Gateway predates default caps
96
+ Its database has no workspace default cap and no no-cap override until the Gateway is updated to a release that has them.`,{rerun:`${E} update`,rerunNote:"then run this again"})}var Le=e=>e===null||Number.isInteger(e)&&e>=1&&e<=Re,ze=()=>new m("INVALID_CAP",`A monthly cap is a whole number from 1 to ${Re.toLocaleString("en-US")}, or off`);async function $a(e,n,a,t={}){let r=t.unlimited??!1,i=await P(e,n,{callable:!0});if(!Le(a))throw ze();if(a!==null&&r)throw new m("INVALID_CAP",`An app has a cap or no cap, not both
97
+ Give a number, off, or --unlimited.`);let d=await Me(e.db);r&&await se(e.db);let p=e.organization.id,[s=[],o=[]]=await e.db.run([{sql:`SELECT monthly_call_cap${d?", unlimited":""} FROM org_app_settings WHERE organization_id = ? AND app_row_id = ?`,params:[p,i.id]},...d?[{sql:"SELECT default_monthly_call_cap AS cap FROM org_settings WHERE organization_id = ?",params:[p]}]:[]]),u=s[0]?.monthly_call_cap==null?null:Number(s[0].monthly_call_cap),R=Number(s[0]?.unlimited??0)===1,w=o[0]?.cap==null?null:Number(o[0].cap),h=ee({appCap:u,unlimited:R,defaultCap:w}),I=ee({appCap:a,unlimited:r,defaultCap:w}),O=a===null?null:await V(e.db,{organizationId:p,deployer:e.operator,now:e.now}),y=We(I.cap,h.cap)?await J(e.db,{organizationId:p,type:"cap.raised",actor:Y(e.operator),data:{app:{id:i.appSlug,rowId:i.id,name:i.name},cap:I.cap,previousCap:h.cap,source:"app"},appRowId:i.id,now:e.now}):[],b=a===null&&!r?{sql:"DELETE FROM org_app_settings WHERE organization_id = ? AND app_row_id = ?",params:[p,i.id]}:d?{sql:`INSERT INTO org_app_settings (organization_id, app_row_id, monthly_call_cap, unlimited, updated_at, updated_by)
98
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6)
99
+ ON CONFLICT (organization_id, app_row_id) DO UPDATE SET monthly_call_cap = ?3, unlimited = ?4, updated_at = ?5, updated_by = ?6`,params:[p,i.id,a,r?1:0,e.now,e.operator.userId]}:{sql:`INSERT INTO org_app_settings (organization_id, app_row_id, monthly_call_cap, updated_at, updated_by)
100
+ VALUES (?1, ?2, ?3, ?4, ?5)
101
+ ON CONFLICT (organization_id, app_row_id) DO UPDATE SET monthly_call_cap = ?3, updated_at = ?4, updated_by = ?5`,params:[p,i.id,a,e.now,e.operator.userId]},B=await e.db.run([b,...O?[O]:[],...y]),S=O?l(B[1]?.[0]?.id):null;return{app:i,cap:a,unlimited:r,was:u,wasUnlimited:R,effective:I,before:h,capAlertsId:S}}async function Ua(e,n){if(!Le(n))throw ze();await se(e.db);let a=e.organization.id,[t=[]]=await e.db.run([{sql:"SELECT default_monthly_call_cap AS cap FROM org_settings WHERE organization_id = ?",params:[a]}]),r=t[0]?.cap==null?null:Number(t[0].cap),i=n===null?null:await V(e.db,{organizationId:a,deployer:e.operator,now:e.now}),d=We(n,r)?await J(e.db,{organizationId:a,type:"cap.raised",actor:Y(e.operator),data:{app:null,cap:n,previousCap:r,source:"default"},now:e.now}):[],p=await e.db.run([n===null?{sql:"DELETE FROM org_settings WHERE organization_id = ?",params:[a]}:{sql:`INSERT INTO org_settings (organization_id, default_monthly_call_cap, updated_at, updated_by)
102
+ VALUES (?1, ?2, ?3, ?4)
103
+ ON CONFLICT (organization_id) DO UPDATE SET default_monthly_call_cap = ?2, updated_at = ?3, updated_by = ?4`,params:[a,n,e.now,e.operator.userId]},...i?[i]:[],...d]),s=i?l(p[1]?.[0]?.id):null;return{cap:n,was:r,capAlertsId:s}}var aa=/^\d{4}-(0[1-9]|1[0-2])$/;function $e(e){return`${e.getUTCFullYear()}-${String(e.getUTCMonth()+1).padStart(2,"0")}`}function na(e,n){let[a,t]=e.split("-").map(Number);return $e(new Date(Date.UTC(a,t-1+n,1)))}var K=`COALESCE(SUM(d.calls), 0) AS calls, COALESCE(SUM(d.failures), 0) AS failures,
104
+ COALESCE(SUM(d.input_tokens), 0) AS input_tokens, COALESCE(SUM(d.output_tokens), 0) AS output_tokens,
105
+ COALESCE(SUM(d.cost_micros), 0) AS cost_micros`,j=e=>({calls:g(e.calls),failures:g(e.failures),inputTokens:g(e.input_tokens),outputTokens:g(e.output_tokens),costMicros:g(e.cost_micros)}),Z={calls:0,failures:0,inputTokens:0,outputTokens:0,costMicros:0},Q={monthlyCallCap:null,capUnlimited:!1,effectiveMonthlyCallCap:null,capSource:null,paused:!1};async function Pa(e,n){if(!aa.test(n))throw new m("INVALID_MONTH",`--month ${n} isn't a month: use YYYY-MM`);await se(e.db);let a=e.organization.id,t=`${n}-01`,r=`${na(n,1)}-01`,i=Date.parse(`${t}T00:00:00.000Z`),d=Date.parse(`${r}T00:00:00.000Z`),p="d.organization_id = ?1 AND d.day >= ?2 AND d.day < ?3",s="c.organization_id = ?1 AND c.decision = 'allowed' AND c.created_at >= ?2 AND c.created_at < ?3",[o=[],u=[],R=[],w=[],h=[],I=[],O=[]]=await e.db.run([{sql:`SELECT d.app_row_id, a.name, a.app_slug, ${K} FROM usage_daily d LEFT JOIN apps a ON a.id = d.app_row_id
106
+ WHERE ${p} GROUP BY d.app_row_id, a.name, a.app_slug`,params:[a,t,r]},{sql:`SELECT d.user_id, u.name, u.email, ${K} FROM usage_daily d
107
+ LEFT JOIN members m ON m.user_id = d.user_id AND m.organization_id = d.organization_id
108
+ LEFT JOIN users u ON u.id = m.user_id
109
+ WHERE ${p} GROUP BY d.user_id, u.name, u.email`,params:[a,t,r]},{sql:`SELECT d.kind, d.target, ${K} FROM usage_daily d WHERE ${p} GROUP BY d.kind, d.target`,params:[a,t,r]},{sql:`SELECT c.app_row_id, a.name, a.app_slug, COUNT(*) AS tool_calls FROM mcp_tool_calls c
110
+ LEFT JOIN apps a ON a.id = c.app_row_id WHERE ${s} GROUP BY c.app_row_id, a.name, a.app_slug`,params:[a,i,d]},{sql:`SELECT c.user_id, u.name, u.email, COUNT(*) AS tool_calls FROM mcp_tool_calls c
111
+ LEFT JOIN members m ON m.user_id = c.user_id AND m.organization_id = c.organization_id
112
+ LEFT JOIN users u ON u.id = m.user_id
113
+ WHERE ${s} GROUP BY c.user_id, u.name, u.email`,params:[a,i,d]},{sql:`SELECT a.id AS app_row_id, a.name, a.app_slug, s.monthly_call_cap, s.unlimited FROM apps a
114
+ LEFT JOIN org_app_settings s ON s.app_row_id = a.id AND s.organization_id = ?1
115
+ WHERE (a.organization_id = ?1 OR a.scope = 'shared') AND a.status != '${N}'`,params:[a]},{sql:"SELECT default_monthly_call_cap AS cap FROM org_settings WHERE organization_id = ?",params:[a]}]),y=O[0]?.cap==null?null:Number(O[0].cap),b=new Map;for(let c of o)b.set(String(c.app_row_id),{appRowId:String(c.app_row_id),appSlug:l(c.app_slug),name:l(c.name),...j(c),toolCalls:0,...Q,callable:!1});for(let c of w){let _=l(c.app_row_id);if(!_)continue;let A=b.get(_);A?A.toolCalls=g(c.tool_calls):b.set(_,{appRowId:_,appSlug:l(c.app_slug),name:l(c.name),...Z,toolCalls:g(c.tool_calls),...Q,callable:!1})}let B=n===$e(new Date(e.now));for(let c of I){let _=String(c.app_row_id),A=c.monthly_call_cap==null?null:Number(c.monthly_call_cap),pe=Number(c.unlimited??0)===1,W=ee({appCap:A,unlimited:pe,defaultCap:y}),f=b.get(_)??{appRowId:_,appSlug:l(c.app_slug),name:l(c.name),...Z,toolCalls:0,...Q,callable:!0};f.callable=!0,f.monthlyCallCap=A,f.capUnlimited=pe,f.effectiveMonthlyCallCap=W.cap,f.capSource=W.source,f.paused=B&&W.cap!==null&&f.calls>=W.cap,b.set(_,f)}let S=new Map;for(let c of u)S.set(String(c.user_id),{userId:String(c.user_id),name:l(c.name),email:l(c.email),...j(c),toolCalls:0});for(let c of h){let _=String(c.user_id),A=S.get(_);A?A.toolCalls=g(c.tool_calls):S.set(_,{userId:_,name:l(c.name),email:l(c.email),...Z,toolCalls:g(c.tool_calls)})}let de=(c,_)=>_.calls-c.calls||_.toolCalls-c.toolCalls;return{month:n,defaultMonthlyCallCap:y,byApp:[...b.values()].sort((c,_)=>de(c,_)||(c.name??c.appRowId).localeCompare(_.name??_.appRowId)),byMember:[...S.values()].sort(de),byTarget:R.map(c=>({kind:String(c.kind),target:String(c.target),...j(c)})).sort((c,_)=>_.calls-c.calls)}}var ta=200;async function xa(e,n){let a=Math.min(Math.max(1,Math.trunc(n.limit??50)||1),ta),t=["c.organization_id = ?"],r=[e.organization.id];n.before&&(t.push("(c.created_at < ? OR (c.created_at = ? AND c.id < ?))"),r.push(n.before.createdAt,n.before.createdAt,n.before.id));for(let[s,o]of[["c.app_row_id",n.appRowId],["c.user_id",n.userId],["c.decision",n.decision],["c.risk",n.risk]])o!==void 0&&(t.push(`${s} = ?`),r.push(o));n.since!==void 0&&(t.push("c.created_at >= ?"),r.push(n.since)),r.push(a+1);let[i=[]]=await e.db.run([{sql:`SELECT c.id, c.created_at, c.user_id, u.name AS user_name, u.email AS user_email,
116
+ c.credential_kind, c.client_name, c.client_info, c.app_row_id, c.app_slug, a.name AS app_name, a.status AS app_status,
117
+ c.tool_name, c.via, c.risk, c.decision, c.reason, c.outcome, c.duration_ms, c.result_bytes
118
+ FROM mcp_tool_calls c
119
+ LEFT JOIN apps a ON a.id = c.app_row_id
120
+ LEFT JOIN members m ON m.user_id = c.user_id AND m.organization_id = c.organization_id
121
+ LEFT JOIN users u ON u.id = m.user_id
122
+ WHERE ${t.join(" AND ")}
123
+ ORDER BY c.created_at DESC, c.id DESC LIMIT ?`,params:r}]),d=i.slice(0,a),p=d.at(-1);return{calls:d.map(s=>{let o=l(s.app_row_id),u=l(s.app_status);return{id:String(s.id),createdAt:g(s.created_at),user:{id:String(s.user_id),name:l(s.user_name),email:l(s.user_email)},credential:{kind:String(s.credential_kind),clientName:l(s.client_name),clientInfo:l(s.client_info)},app:{rowId:o,slug:l(s.app_slug),name:l(s.app_name),removed:o!==null&&(u===null||u===N)},tool:{name:String(s.tool_name),risk:l(s.risk),via:l(s.via)},decision:s.decision==="allowed"?"allowed":"blocked",reason:l(s.reason),outcome:String(s.outcome),durationMs:s.duration_ms==null?null:Number(s.duration_ms),resultBytes:s.result_bytes==null?null:Number(s.result_bytes)}}),nextBefore:i.length>a&&p?{createdAt:g(p.created_at),id:String(p.id)}:null}}var Ue=`SELECT t.id, t.user_id, u.email, t.name, t.token_prefix, t.app_row_id, a.app_slug, a.name AS app_name,
124
+ t.scopes, t.created_at, t.expires_at, t.last_used_at, t.revoked_at
125
+ FROM user_access_tokens t JOIN users u ON u.id = t.user_id
126
+ LEFT JOIN apps a ON a.id = t.app_row_id AND a.organization_id = t.organization_id
127
+ WHERE t.organization_id = ?1`;function Pe(e,n){let a=e.revoked_at==null?null:Number(e.revoked_at),t=g(e.expires_at),r=[];try{let i=JSON.parse(String(e.scopes??"[]"));r=Array.isArray(i)?i.map(String):[]}catch{r=[]}return{id:String(e.id),user:{id:String(e.user_id),email:String(e.email)},name:String(e.name),prefix:String(e.token_prefix),app:{rowId:l(e.app_row_id),slug:l(e.app_slug),name:l(e.app_name)},scopes:r,createdAt:g(e.created_at),expiresAt:t,lastUsedAt:e.last_used_at==null?null:Number(e.last_used_at),revokedAt:a,active:a===null&&t>n}}async function Fa(e,n){let[a=[]]=await e.db.run([{sql:`${Ue}${n?" AND t.user_id = ?2":""} ORDER BY t.created_at DESC`,params:n?[e.organization.id,n]:[e.organization.id]}]);return a.map(t=>Pe(t,e.now))}async function Ha(e,n){let[a=[]]=await e.db.run([{sql:`${Ue} AND t.id = ?2`,params:[e.organization.id,n.trim()]}]),t=a[0];if(!t)throw new m("TOKEN_NOT_FOUND",`No personal access token ${n.trim()} in ${e.organization.name}`,{rerun:`${E} workspace tokens`,rerunNote:"lists them by id"});let r=Pe(t,e.now);return r.revokedAt!==null?{token:r,already:!0}:(await e.db.run([{sql:"UPDATE user_access_tokens SET revoked_at = ?3, updated_at = ?3 WHERE id = ?1 AND organization_id = ?2 AND revoked_at IS NULL",params:[r.id,e.organization.id,e.now]}]),{token:{...r,revokedAt:e.now,active:!1},already:!1})}var xe=`SELECT c.id, c.user_id, u.email, c.client_name, c.client_domain, c.redirect_host, c.app_scope, c.access,
128
+ c.created_at, c.last_used_at, c.revoked_at, c.revoked_reason,
129
+ (SELECT group_concat(a.app_slug, char(31)) FROM mcp_connection_apps ca JOIN apps a ON a.id = ca.app_row_id WHERE ca.connection_id = c.id) AS app_slugs
130
+ FROM mcp_connections c JOIN users u ON u.id = c.user_id
131
+ WHERE c.organization_id = ?1`;function Fe(e){return{id:String(e.id),user:{id:String(e.user_id),email:String(e.email)},clientName:String(e.client_name),clientDomain:l(e.client_domain),redirectHost:String(e.redirect_host),apps:e.app_scope==="all"?"all":l(e.app_slugs)?.split("").sort()??[],access:e.access==="write"?"write":"read",createdAt:g(e.created_at),lastUsedAt:e.last_used_at==null?null:Number(e.last_used_at),revokedAt:e.revoked_at==null?null:Number(e.revoked_at),revokedReason:l(e.revoked_reason)}}async function qa(e,n){let[a=[]]=await e.db.run([{sql:`${xe} AND c.revoked_at IS NULL${n?" AND c.user_id = ?2":""} ORDER BY c.created_at DESC`,params:n?[e.organization.id,n]:[e.organization.id]}]);return a.map(Fe)}async function Ga(e,n){let[a=[]]=await e.db.run([{sql:`${xe} AND c.id = ?2`,params:[e.organization.id,n.trim()]}]),t=a[0];if(!t)throw new m("CONNECTION_NOT_FOUND",`No AI connection ${n.trim()} in ${e.organization.name}`,{rerun:`${E} workspace connections`,rerunNote:"lists them by id"});let r=Fe(t);return r.revokedAt!==null?{connection:r,already:!0}:(await e.db.run([{sql:`UPDATE mcp_connections SET revoked_at = ?3, revoked_by = ?4, revoked_reason = 'user'
132
+ WHERE id = ?1 AND organization_id = ?2 AND revoked_at IS NULL`,params:[r.id,e.organization.id,e.now,e.operator.userId]}]),{connection:{...r,revokedAt:e.now,revokedReason:"user"},already:!1})}export{ra as a,ga as b,Re as c,_a as d,Ea as e,k as f,P as g,ke as h,Na as i,ba as j,Aa as k,fa as l,Ra as m,Oa as n,Sa as o,Ta as p,Da as q,ka as r,ha as s,Ia as t,va as u,Ca as v,wa as w,Ne as x,ya as y,be as z,Wa as A,Ma as B,ea as C,La as D,Ae as E,za as F,$a as G,Ua as H,aa as I,$e as J,Pa as K,ta as L,xa as M,Fa as N,Ha as O,qa as P,Ga as Q};
@@ -0,0 +1,5 @@
1
+ import{createHash as c,randomBytes as d,randomUUID as l}from"node:crypto";import{setTimeout as p}from"node:timers/promises";import{execa as g}from"execa";var w=24*60*60*1e3,_=e=>c("sha256").update(e).digest("hex"),u=`SELECT users.email AS email, organizations.name AS organization_name, organizations.id AS organization_id
2
+ FROM members
3
+ JOIN users ON users.id = members.user_id
4
+ JOIN organizations ON organizations.id = members.organization_id
5
+ WHERE members.role = 'owner'`;function m(e){return!e||typeof e.email!="string"?null:{email:e.email,organizationName:String(e.organization_name??"")}}async function S(e){let[n=[]]=await e.run([{sql:`${u} ORDER BY organizations.created_at, organizations.id, members.created_at LIMIT 1`}]),t=m(n[0]);return t?{owner:t,organizationId:String(n[0].organization_id)}:null}async function O(e){return(await S(e))?.owner??null}async function x({db:e,gatewayUrl:n,now:t=Date.now()}){let r=`est_${d(32).toString("base64url")}`,i=l(),a=t+w,[s=[]]=await e.run([{sql:"SELECT id FROM owner_setup_tokens WHERE kind = 'claim' AND consumed_at IS NULL AND expires_at > ?1",params:[t]},{sql:"UPDATE owner_setup_tokens SET expires_at = ?1 WHERE kind = 'claim' AND consumed_at IS NULL AND expires_at > ?1",params:[t]},{sql:"INSERT INTO owner_setup_tokens (id, kind, token_hash, expires_at) VALUES (?, 'claim', ?, ?)",params:[i,_(r),a]}]);return{id:i,url:`${n.replace(/\/$/,"")}/setup#token=${r}`,expiresAt:new Date(a),replaced:s.length>0}}async function f(e,n,t=Date.now()){let[r=[],i=[]]=await e.run([{sql:"SELECT consumed_at, expires_at FROM owner_setup_tokens WHERE id = ?",params:[n]},{sql:`${u} AND members.user_id = (SELECT consumed_by FROM owner_setup_tokens WHERE id = ?) LIMIT 1`,params:[n]}]),a=r[0];return a&&a.consumed_at!==null&&a.consumed_at!==void 0?{status:"claimed",owner:m(i[0])}:!a||Number(a.expires_at)<=t?{status:"gone"}:{status:"waiting"}}var b=15*60*1e3,E=5e3;async function y({db:e,id:n,timeoutMs:t=b,intervalMs:r=E,sleep:i=p,now:a=Date.now}){let s=a()+t;for(;;){let o=await f(e,n,a());if(o.status!=="waiting"||a()>=s)return o;await i(r)}}function N({terminal:e=!!process.stdout.isTTY,relayed:n=!1}={}){return process.env.CI?!1:e||n}async function I(e){let[n,t]=process.platform==="darwin"?["open",[e]]:process.platform==="win32"?["cmd",["/c","start","",e]]:["xdg-open",[e]];try{await g(n,t,{stdio:"ignore"})}catch{}}export{S as a,O as b,x as c,y as d,N as e,I as f};
@@ -0,0 +1,2 @@
1
+ import{d}from"./chunk-W3JCQHHU.js";import{o as u,p as f}from"./chunk-JYKRUS5C.js";import{Bb as a,bc as i,cc as l,d as c}from"./chunk-LYNBZ7RV.js";function $(n,t,r){return i(n,{plane:"account",args:["dns","records","list","-z",t,"--name-exact",r,"--per-page","100"]},f)}async function v(n,t,r){await n.run({plane:"account",mode:"json",args:["dns","records","delete",r,"-z",t,"--force"]})}function y(n){return`*.${n.slice(n.indexOf(".")+1)}`}function z(n){return`${n.type}${n.content?` ${n.content}`:""}`}var p=50,g=20;function C(n){return`https://dash.cloudflare.com/${n}/domains/overview`}async function _(n,t,r){let o=d(t),e=await w(n,t,r);if(!e)throw new a("ZONE_NOT_FOUND",`No zone in this Cloudflare account holds ${t}
2
+ Looked for ${o.join(", ")}. Buy a domain in the dashboard (Domains, ${C(r)}), or add one you own and point its nameservers at Cloudflare.`,{fix:"use a domain that is on Cloudflare in this account"});if(e.status&&e.status!=="active")throw new a("ZONE_NOT_ACTIVE",`The Cloudflare zone ${e.name} is ${e.status}, not active`,{fix:`finish its nameserver setup (Cloudflare dashboard \u2192 ${e.name} \u2192 Overview)`,rerun:c()});return{id:e.id,name:e.name}}async function w(n,t,r){let e=(await Promise.all(d(t).map(async s=>(await i(n,{plane:"account",args:["zones","list","--name",s,"--account-id",r]},u)).find(m=>m.name.toLowerCase()===s)??null))).find(s=>s!==null);return e?{id:e.id,name:e.name.toLowerCase(),status:e.status??null}:null}function A(n,t){return`https://dash.cloudflare.com/${n}/${t}`}async function D(n,t){return(await l(n,["zones","list","--account-id",t],u,{perPage:p,maxPages:g})).map(o=>({id:o.id,name:o.name.toLowerCase(),status:o.status??null}))}export{$ as a,v as b,y as c,z as d,C as e,_ as f,w as g,A as h,D as i};
@@ -0,0 +1 @@
1
+ import{B as S,ca as u,da as z,ea as L,fa as E,ha as N,ja as w,ka as B,kb as j,la as V,lb as X,ma as K,mb as M,na as F,oa as G,pa as H,qa as J,ra as W,rb as v,ta as O,tb as T,ub as Y,vb as q,wb as Q,xb as k,yb as Z}from"./chunk-LYNBZ7RV.js";function de(e){if(!e)return null;try{let t=JSON.parse(e);return Array.isArray(t)&&t.every(r=>typeof r=="string")?t:null}catch{return null}}function le(e){return JSON.stringify([...new Set(e)].sort())}var b=class extends Error{constructor(r,n){super(`App "${r}" can't be routed: ${n}`);this.appId=r;this.name="UnroutableAppError"}};var D=class{byHostname=new Map;byAppId=new Map;byOrgApp=new Map;constructor(t=[]){for(let r of t)this.add(r)}add(t){this.byHostname.set(t.hostname.toLowerCase(),t),this.byAppId.set(t.appId,t),this.byOrgApp.set(ee(t.organizationId,t.appId),t)}async findByHostname(t){return this.byHostname.get(t.toLowerCase())??null}async hasAnyActiveApp(){return Array.from(this.byAppId.values()).some(t=>t.status==="active")}async findByAppId(t){return this.byAppId.get(t)??null}async findByOrgApp(t,r){return this.byOrgApp.get(ee(t,r))??null}};function ee(e,t){return JSON.stringify([e,t])}var p="deleted",o=class extends Error{status;code;constructor({status:t,code:r,message:n}){super(n),this.name="RegistrationError",this.status=t,this.code=r}},ce=/^(?=.{1,63}$)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/,re=12,ge=50;function ne(e){return e.toLowerCase().replace(/[^a-z0-9]/g,"").slice(0,re)||"org"}function ue(e){let t=ne(e);return Array.from({length:ge},(r,n)=>{let s=n===0?"":String(n+1);return`${t.slice(0,re-s.length)}${s}`})}function te(e,t){let r=e.trim().toLowerCase();if(!ce.test(r))throw new o({status:400,code:"INVALID_APP_HOSTNAME",message:`${t} must form a valid DNS label of at most 63 characters; received "${r}".`});return r}function se(e){let{appSlug:t,orgKey:r}=e;if(j(t))throw new o({status:400,code:"RESERVED_APP_ID",message:`The app id "${t}" is reserved for the platform.`});if(t.includes(T))throw new o({status:400,code:"INVALID_APP_ID",message:`App id "${t}" can't contain "${T}": it separates an app's Worker name from its resources' names. Choose another id.`});let n=e.existingApp?.workerName??Y({appId:t,orgKey:r}),s=e.appBaseDomain.trim().toLowerCase().replace(/\.$/,""),i=e.existingApp?.hostname??`${e.isInstallOrganization?te(t,"The app id"):te(`${t}-${r}`,"The app id and organization key")}.${s}`;if(!q({appId:t,orgKey:r,workerName:n}))throw new o({status:400,code:"INVALID_WORKER_NAME",message:n.length>v?`App id "${t}" is too long: its Worker name "${n}" would exceed ${v} characters.`:`App id "${t}" can't be registered: its Worker would be "${n}", which is reserved for the gateway or isn't the app's own.`});return{workerName:n,hostname:i}}function oe(e,t){let r;try{r=M(e)}catch(n){throw new o({status:400,code:"INVALID_MANIFEST",message:n instanceof X?n.message:"Invalid manifest"})}if(r.id!==t)throw new o({status:400,code:"INVALID_MANIFEST",message:`manifest.id "${r.id}" does not match appId "${t}"`});return r}function U(e){if(!e)return null;try{return M(JSON.parse(e))}catch{return null}}function ie(e,t){let r=(n,s=Q)=>Object.fromEntries((n??[]).map(i=>[i,s(e,i)]));return{d1:r(t?.resources?.d1),kv:r(t?.resources?.kv),r2:r(t?.resources?.r2,Z)}}function me(e){return e.workerName?ie(e.workerName,U(e.manifest)):{d1:{},kv:{},r2:{}}}var Ae={d1:"D1 database",kv:"KV namespace",r2:"R2 bucket"},fe=/^[a-z0-9][a-z0-9-]*[a-z0-9]$/;function Re(e){for(let[t,r]of Object.entries(e)){let n=new Map;for(let[s,i]of Object.entries(r)){let a=n.get(i);if(a!==void 0)throw new o({status:400,code:"RESOURCE_NAME_CONFLICT",message:`Bindings ${a} and ${s} would share the ${Ae[t]} "${i}". Rename one of them in everyapp.config.ts.`});if(t==="r2"&&(i.length>k||!fe.test(i)))throw new o({status:400,code:"INVALID_MANIFEST",message:`resources.r2: ${s} would be the R2 bucket "${i}", which Cloudflare refuses (at most ${k} lowercase letters, digits and hyphens, starting and ending with a letter or digit). Rename the binding in everyapp.config.ts.`});n.set(i,s)}}}function Ie(e){return(e??"").split(",").some(t=>["owner","admin"].includes(t.trim()))}function ye(e,t,r,n){if(t==="shared")return{isDefault:!1,grants:[]};let s=r.access==="everyone";return{isDefault:s,grants:e.members.filter(i=>s||i.id===e.deployerUserId||Ie(i.role)).map(i=>({id:crypto.randomUUID(),organizationId:e.organizationId,userId:i.id,appRowId:n,grantedBy:null}))}}function we(e){let{existingApp:t}=e,r=e.scope??(t?.scope==="shared"?"shared":"org");if(t&&(t.organizationId!==e.organizationId||t.appSlug!==e.appSlug))throw new Error("existingApp is another organization's or app's row.");if(r==="shared"&&!e.isInstallOrganization)throw new o({status:403,code:"SHARED_APP_NOT_PLATFORM",message:`Only the platform organization registers shared apps; "${e.appSlug}" can't be shared from another organization.`});if(t&&t.scope!==r)throw new o({status:409,code:"APP_SCOPE_MISMATCH",message:t.scope==="shared"?`App "${e.appSlug}" is a shared app, not this organization's own. Deploy it without asking for another scope, or give the organization's own app an id of its own.`:`App "${e.appSlug}" is this organization's own app, not a shared one. Shared apps need an app id of their own.`});let n=e.tier??"service_binding";if(n==="dispatch"&&r==="shared")throw new o({status:400,code:"APP_TIER_MISMATCH",message:`A shared app is reached over a service binding; "${e.appSlug}" can't be deployed through the hosted deploy API.`});if(t&&t.tier!==n)throw new o({status:409,code:"APP_TIER_MISMATCH",message:t.tier===u?`"${e.appSlug}" is the Gateway's MCP app of that name${t.status===p?" (turned off)":""}; give this app an id of its own.`:t.tier==="dispatch"?`App "${e.appSlug}" is deployed through the hosted deploy API; deploy it the same way, or give this app an id of its own.`:`App "${e.appSlug}" is reached over a service binding, not deployed through the hosted deploy API; give the third-party app an id of its own.`});let s=se(e),i=oe(e.manifest,e.appSlug),{workerName:a,hostname:d}=s;for(let[A,_,pe]of[[e.hostnameOwner,"hostname",d],[e.workerNameOwner,"workerName",a]])if(A&&A[_]!==pe)throw new Error(`The ${_} owner passed holds another ${_}.`);let m=A=>A!==null&&(A.organizationId!==e.organizationId||A.appSlug!==e.appSlug);if(m(e.hostnameOwner))throw new o({status:409,code:"HOSTNAME_TAKEN",message:`The hostname "${d}" is already registered to another app on this gateway.`});if(m(e.workerNameOwner))throw new o({status:409,code:"WORKER_NAME_TAKEN",message:`The worker name "${a}" is already registered to another app on this gateway. Choose a different app id.`});let f=ie(a,i);Re(f);let y={organizationId:e.organizationId,name:e.name,description:e.description,hostname:d,workerName:a},l={previousManifest:U(t?.manifest??null),versionId:t?.versionId??null,resources:f};if(t&&t.status!==p)return{kind:"existing",app:{...t,...y},grants:[],...l};let R=t?.id??crypto.randomUUID(),{isDefault:c,grants:h}=ye(e,r,i,R),g={...y,manifest:JSON.stringify(i),status:"pending",isDefault:c};return t?{kind:"revived",app:{...t,...g},grants:h,...l}:{kind:"new",app:{id:R,appSlug:e.appSlug,tier:n,scope:r,versionId:null,deployedAt:null,deployedByActor:null,...g},grants:h,...l}}function he(e){if(e.status===p)throw new o({status:404,code:"APP_NOT_FOUND",message:`No app "${e.appSlug}" is registered for this organization.`});if(!e.workerName||!e.hostname&&e.tier!=="dispatch")throw new o({status:409,code:"APP_NOT_REGISTERED",message:`App "${e.appSlug}" has no Worker or hostname yet; deploy it again.`})}function Ee(e,{versionId:t,manifest:r,actor:n,now:s=Date.now()}){return he(e),{manifest:JSON.stringify(oe(r,e.appSlug)),versionId:t,deployedAt:s,deployedByActor:n,status:e.status==="pending"?"binding":e.status}}function P(e){return e.status===p?null:{status:p,isDefault:!1,emailSenders:null,emailInbound:null,secretNames:null}}function Me(e){return(e??"").split(",").some(t=>["owner","admin"].includes(t.trim()))}function I(e,t){throw new o({status:400,code:e,message:t})}function Pe(e,t){let r=t&&typeof t=="object"&&!Array.isArray(t)?t:{kind:t??"none"},n=r.kind,s=(n==="bearer"||n==="header"||n==="basic")&&r.secret===void 0?{...r,secret:B(e)}:r,i=G(s);return i.ok||I("REMOTE_MCP_INVALID",i.problem),i.auth}function C(e){if(e.tier!==u||!e.manifest)return!1;try{return W(JSON.parse(e.manifest))}catch{return!1}}function $(e){return e.tier===u}function x(e){if(e.tier!==u||!e.manifest)return null;try{return J(JSON.parse(e.manifest))}catch{return null}}function _e(e,t,r){if(r&&(r.organizationId!==e||r.appSlug!==t))throw new Error("existingApp is another organization's or app's row.")}function Se(e,t){if(C(t))return;let r=t.tier===u?"the Gateway's built-in MCP app":`an app deployed to this Gateway${t.status===p?" (deleted, its names still its organization's)":""}`;throw new o({status:409,code:"APP_TIER_MISMATCH",message:`"${e}" is ${r}; a remote MCP server can't take its id.`})}function Ne(e){let t=e.url.trim(),r=F(t,e.env);r&&I("REMOTE_MCP_URL_REFUSED",r);let n=(e.id??"").trim()||K(t);n||I("REMOTE_MCP_INVALID","no app id could be read from the URL's host; give one with --name");let s=V(n);s&&I("REMOTE_MCP_INVALID",s);let i=e.sharedApp?.(n);if(i&&i.status!==p)throw new o({status:409,code:"APP_TIER_MISMATCH",message:`"${n}" is a shared app every organization sees; a remote MCP server can't take its id.`});let a=e.existingApp(n);_e(e.organizationId,n,a);let d=(e.risk??"annotations").trim();w.includes(d)||I("REMOTE_MCP_INVALID",`risk must be one of ${w.join(", ")}`);let m=Pe(n,e.auth);if("secret"in m&&e.secretUsedAt){let g=e.secretUsedAt(m.secret),A=new URL(t).origin;if(g&&g!==A)throw new o({status:409,code:"REMOTE_MCP_SECRET_TAKEN",message:`${m.secret} is the credential of an MCP app at ${g}; a server at ${A} takes another name (--secret <NAME>_MCP_TOKEN).`})}let f=a?x(a)?.rev??0:0,y={url:t,auth:m,risk:d,tools:{},rev:f+1},l=O({id:n,name:e.name,description:e.description,remote:y});if(a&&((E(n)||!C(a))&&Se(n,a),a.status!==p))throw new o({status:409,code:"REMOTE_MCP_EXISTS",message:`"${n}" is an MCP app on this Gateway already (${a.status==="active"?"on":"off"}); remove it first, or change it in place.`});let R=a?.id??crypto.randomUUID(),c={id:R,organizationId:e.organizationId,appSlug:n,name:l.name,description:l.description,hostname:null,workerName:null,tier:u,scope:"org",manifest:JSON.stringify(l),status:"active",versionId:null,deployedAt:e.now,deployedByActor:e.actor,isDefault:!1},h=e.members.filter(g=>g.id===e.actorUserId||Me(g.role)).map(g=>({id:crypto.randomUUID(),organizationId:e.organizationId,userId:g.id,appRowId:R,grantedBy:null}));return{kind:a?"revived":"new",id:n,app:c,grants:h,remote:y}}function Oe(e,t){let r=x(e);if(!r)throw new o({status:404,code:"APP_NOT_FOUND",message:`"${e.appSlug}" is not a remote MCP app.`});if(e.status===p)throw new o({status:404,code:"APP_NOT_FOUND",message:`"${e.appSlug}" was removed.`});let n=r.risk;t.risk!==void 0&&(w.includes(t.risk)||I("REMOTE_MCP_INVALID",`risk must be one of ${w.join(", ")}`),n=t.risk);let s={...r.tools};if(t.tools&&(s={...t.tools}),t.tool){let{name:l,override:R}=t.tool;if(l.trim()||I("REMOTE_MCP_INVALID","name the tool"),R===null)delete s[l];else{let c={...s[l],...R};c.risk===void 0&&delete c.risk,(c.enabled===void 0||c.enabled===!0)&&delete c.enabled,Object.keys(c).length===0?delete s[l]:s[l]=c}}let i=S({risk:n,tools:s})!==S({risk:r.risk,tools:r.tools}),a={...r,risk:n,tools:s,rev:i?r.rev+1:r.rev},d=H(a);d.ok||I("REMOTE_MCP_INVALID",d.problem);let m=JSON.parse(e.manifest??"{}"),f=O({id:e.appSlug,name:t.name===void 0?e.name:t.name,description:t.description===void 0?e.description:t.description,remote:a}),y={...m,...f};return{manifest:JSON.stringify(y),name:f.name,description:f.description,remote:a}}function ve(e,t){if(!$(e))throw new o({status:409,code:"APP_TIER_MISMATCH",message:`"${e.appSlug}" is an app deployed to this Gateway, not an MCP app.`});if(e.status===p)throw new o({status:404,code:"APP_NOT_FOUND",message:`"${e.appSlug}" was removed; add it again.`});return e.status===t?null:{status:t}}function Te(e){return!e||!$(e)?null:P(e)}function ke(e){return(e??"").split(",").some(t=>["owner","admin"].includes(t.trim()))}function ae(e){if(E(e))return e;throw new o({status:400,code:"PROVIDER_APP_UNKNOWN",message:`"${e}" is not an MCP app. The Gateway offers: ${L.join(", ")}.`})}function be(e,t){if(t.tier!==u)throw new o({status:409,code:"APP_TIER_MISMATCH",message:`"${e}" is an app deployed to this Gateway${t.status===p?" (deleted, its names still its organization's)":""}, not the MCP app; the MCP app can't take its id.`})}function De(e){let t=ae(e.id),{existingApp:r}=e;if(r&&(r.organizationId!==e.organizationId||r.appSlug!==t))throw new Error("existingApp is another organization's or app's row.");let n=z[t];if(r&&be(t,r),r&&r.status!==p)return{kind:"existing",app:{...r,name:n.name,description:n.description,manifest:JSON.stringify(N(t)),status:"active"},grants:[]};let s=r?.id??crypto.randomUUID(),i={id:s,organizationId:e.organizationId,appSlug:t,name:n.name,description:n.description,hostname:null,workerName:null,tier:u,scope:"org",manifest:JSON.stringify(N(t)),status:"active",versionId:null,deployedAt:e.now,deployedByActor:e.actor,isDefault:!1},a=e.members.filter(d=>d.id===e.actorUserId||ke(d.role)).map(d=>({id:crypto.randomUUID(),organizationId:e.organizationId,userId:d.id,appRowId:s,grantedBy:null}));return{kind:r?"revived":"new",app:i,grants:a}}export{de as a,le as b,b as c,D as d,p as e,o as f,ue as g,se as h,me as i,we as j,Ee as k,P as l,ae as m,De as n,C as o,x as p,Ne as q,Oe as r,ve as s,Te as t};
@@ -0,0 +1 @@
1
+ import{a as d}from"./chunk-4JRIS6S6.js";import{Aa as u,Ba as g,Ca as S,G as p,ba as f,c as l,pc as c,qb as m}from"./chunk-LYNBZ7RV.js";import a from"chalk";function $(e){return d(e,m)}async function C(e,n){return(await d(e,n)).filter(t=>!f(t))}function w(e,n=p){let t=n.unboundSettings?.();return t&&t.size>0?e.filter(r=>!t.has(r)):[...e]}function I(e){let n=e.lookup??p,t=e.gatewayNames===null?null:w(e.gatewayNames,n),r=g(u(e.manifest,n),(o,i)=>{let s=o==="gateway"?t:e.secretNames;return s===null?null:s.includes(i)});return{report:r,setup:S(r,{cli:l,appId:e.appId})}}function M(e,n=p){return u(e,n).some(t=>t.names.length>0)}function P(e,n=p){let t=new Set;for(let r of u(e,n))if(r.holder==="gateway")for(let o of[...r.names,...r.alsoReads])t.add(o);return[...t]}function O(e,n){let t=new Map,r=(o,i)=>{let s=t.get(o);s?s.required||=i:t.set(o,{name:o,required:i,set:n.includes(o)})};for(let o of e)if(o.holder==="gateway"){for(let i of o.names)r(i,o.need.kind!=="optional");for(let i of o.alsoReads)r(i,!1)}return[...t.values()]}function W(e,n){return e.filter(t=>t.holder==="gateway"&&t.blocking).flatMap(t=>t.names).filter((t,r,o)=>!n.includes(t)&&o.indexOf(t)===r)}var y=`${a.yellow("!")} not set`;function k(e){if(e.set===!0)return`${a.green("\u2713")} set`;if(e.set===null)return e.holder==="app"?`${a.yellow("!")} not recorded`:`${a.yellow("!")} couldn't check`;switch(e.need.kind){case"required":return y;case"optional":return a.dim("not set (optional)");case"anyOf":return e.blocking?y:a.dim(`not set (one of: ${e.need.group})`)}}function h(e){return e.names.join("+")}function A(e,n){return n.filter(t=>t.names.length>0).map(t=>({app:e,setting:h(t),where:t.holder==="gateway"?"Gateway":e,status:k(t)}))}function U(e,n,t){return A(e,t.filter(r=>r.holder==="app")).map(r=>({...r,where:`${n} helper`}))}function _(e,{app:n=!0}={}){return n?c(["APP","SETTING","WHERE","STATUS"],e.map(t=>[t.app,t.setting,t.where,t.status])):c(["SETTING","WHERE","STATUS"],e.map(t=>[t.setting,t.where,t.status]))}function b(e){let n=e.names.join(" and "),t=e.why??(e.label===n?void 0:n);return[t?`${e.label}: ${t}`:e.label,...e.hint?[e.hint]:[],...e.docs?[`Get it at ${e.docs}`]:[]]}var R=".claude/skills/everyapp";function N(e){return e.setup?`Guide: ${R}/${e.setup}`:e.kind==="capability"||e.kind==="provider"?`Guide: ${l} provider show ${e.id}`:null}function q(e){let n=new Set;return e.flatMap(t=>{let r=b(t),o=N(t);return!o||n.has(o)?r:(n.add(o),[...r,o])})}function j(e){let n=[],t=r=>{for(let o of r.names)n.includes(o)||n.push(o)};for(let r of e.unmet)r.need.kind==="required"&&t(r);for(let r of e.groups){if(r.met)continue;let o=e.unmet.find(i=>i.id===r.members[0]);o&&t(o)}return n}export{$ as a,C as b,w as c,I as d,M as e,P as f,O as g,W as h,k as i,A as j,U as k,_ as l,b as m,R as n,N as o,q as p,j as q};
@@ -0,0 +1,32 @@
1
+ import{createHash as I,createHmac as m}from"node:crypto";var _="https://gateway.dev.localhost";var u=`-----BEGIN PRIVATE KEY-----
2
+ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCHjTNZ/5Aresl0
3
+ xM2jL5cX2LJ1XmtpZJ4S3gNfJ5j3xzwhkdGPLZRdpph6PB55tGy/0DP5tm4vdx8n
4
+ QTuk4Z3hUI6JIbUGMmCWZMLXCFXgx3qqEsNU4/qLO1QlLEPCeVHzlS07I0ngbl1h
5
+ jpGsBaU8wxc9Jh0ZaoA/iflBcDD7u5MWYkx1bLVbwottOP/81IafcMKb4RkkgLyr
6
+ 3IOExJwzR6MmcFUKiW+nhPyTx23aRga7ZZ3t0Iyse/+XFSioPnxq+l0w7Ntpm3Cx
7
+ DsEBohqYh5DUArGacKPWenbe5a9hCahpmhy+6ktIAsrt9YZTJUNn5Fbge03kqrNn
8
+ Kl+LJnyRAgMBAAECggEABCi9GAB3URw3APgWarDHwS2vGRqU72KM1p2dCx8FCqpA
9
+ cjO+Ezd171Mwp8R/N2MFuLN32sxCEH8GU88kuDwLevm8q+C+xBJI5ChykYRCFU/t
10
+ l7kUaP8HRZ0kCXF0oUuVbATKYt+D8WjVgOwt1FJGhgki5geMukZKKdjvDtbVS+4D
11
+ qGRBV4/XT4Y5JDNrjnITwSV2xfMD6Yd92/NN375+V9vWFI4kaESPbE/YQ7yF1o66
12
+ DfhjRMSMmTgWEeoVDwFMlnXppo1nkdEXY8MXlgho0mDGre4PurAvQmZRYlU6VJ63
13
+ x7/NTaNPnQEJ7+FkUXvtOz8sCBjLzgtilGnBNwGqeQKBgQC7zA7kojSPYvlm7nbC
14
+ L2kO8iAL3p/B1vtS6XLTFiV0Wv2kT6Cy51ulVteUijwGMrDuCMdBqXfIocQvYhls
15
+ JzPR/DaFcE2qClCei9L4wxvdBLcqoQH7LsllGA9oHSoZNnzT0muNech0xuL75X6B
16
+ LLMpVtOyb/prd8N6hhBlcGElCQKBgQC4x8A9aDnFlcyztcutW2YQMfEyDEK+PcuC
17
+ n6cnSJ8MjmFEyulKZuklqKkhwMiNBm8xNhI6UdUtrFPfKmGqYifjEUX4D6xGLL8b
18
+ LNOZojkMAI3jtuD+IGzlpkSCy2TWXVb53TTi82LUD7Sbb5siYhL5uW0IRzbJt1aR
19
+ n2JNphvFSQKBgA1NPNjQ7GwjlIrH5T2H4ice20o78JDoS1DqHCn7bZe6QjD7OuSx
20
+ Inqplgd9axb9TC7wDD0IZeWeH6lDh41zkWYUOUBmXfnnVSKFwOHB4B1dkiPA18UU
21
+ 4Ur5002Kk0rJ4zmVs+yHbb1nwPgan0VDB0WsUr5W1CP8jaoGCO9GcHsRAoGAX6Xm
22
+ eOLupLx6DbxZBg99sXxoocN++QL7yU3jNI5+5fz9lKKESCMlJH09r18fcQCXph2b
23
+ Kd0aQF4nvCkwDQZqJzvVwCY8wsZ+1g5KKgizBudyiyErLeCS/f0nEZ0/QUdnskcz
24
+ DRd3XNYUYzFOWGnz8JhvPA3A6oGgqhiaxh7p2SECgYA+7s6WRfQLSad3dXuDNajQ
25
+ sBwG4E6M/yUbgdbNjnv+AuVYS8Uyvf6x/xaWH3zssluIXhod0Two22bjtkPGJ2nx
26
+ 1ZXmbxSdWVGwLZn3GYRoRu6X6VGTbFAaK1mb7KDfwjoaauV7G3A2mw6M5xxg4zx/
27
+ hsbx0DA4sMMIUEniw9W/YA==
28
+ -----END PRIVATE KEY-----
29
+ `;var o=Object.freeze({workerName:"every-hosted--sentinel",organizationId:"everyapp-hosted-deploy-sentinel",gatewayUrl:"https://every-hosted--sentinel.invalid",publicKey:`-----BEGIN PUBLIC KEY-----
30
+ EVERYAPPHOSTEDDEPLOYSENTINEL
31
+ -----END PUBLIC KEY-----
32
+ `});function s(t){return`${o.workerName}--${t}`}function a(t){let r=(e,c)=>Object.fromEntries((e??[]).map(i=>[i,c(s(i))])),{resources:n}=t;return{workerName:o.workerName,organizationId:o.organizationId,gatewayUrl:o.gatewayUrl,identityPublicKeys:[o.publicKey],resources:{d1:r(n?.d1,e=>({name:e,id:e})),kv:r(n?.kv,e=>({id:e})),hyperdrive:r(n?.hyperdrive?.map(e=>e.name),e=>({id:e})),r2:r(n?.r2,e=>({name:e}))}}}var l=Object.freeze({enabled:!0,headSamplingRate:1,redactQueryString:!0,logs:Object.freeze({enabled:!0,invocationLogs:!0,persist:!0,headSamplingRate:1}),traces:Object.freeze({enabled:!0,persist:!0,headSamplingRate:.1}),issues:Object.freeze({enabled:!0})});var E=63;function A(t,r){let n=`${t}--${r}`;if(n.length>E)throw new Error(`Helper Worker ${n} is longer than Cloudflare's ${E} characters; shorten its name in everyapp.config.ts.`);return n}function d(t,r){return`${t}--${r.toLowerCase().replaceAll("_","-")}`}function p(t,r){return I("sha256").update(`${t}:${r}`).digest("hex").slice(0,32)}export{_ as a,u as b,o as c,s as d,a as e,l as f,A as g,d as h,p as i};
@@ -0,0 +1,2 @@
1
+ import{q as d}from"./chunk-JYKRUS5C.js";import{Fb as u,Hb as l,cc as p}from"./chunk-LYNBZ7RV.js";var P=50,y=20;function g(t,r,e={}){return p(t,["ssl","certificate-packs","list","-z",r,...e.allStatuses?["--status","all"]:[]],d,{perPage:P,maxPages:y})}function m(t){return!t.status||t.status==="active"}function C(t){return(t.hosts??[]).map(r=>r.toLowerCase())}function w(t,r){let e=t.toLowerCase();if(e===r)return!0;if(!e.startsWith("*."))return!1;let[,...i]=r.split(".");return i.join(".")===e.slice(2)}async function b(t,r,e){let i=(await g(t,r)).filter(m);return e.map(o=>({host:o,ready:i.some(s=>(s.hosts??[]).some(n=>w(n,o.toLowerCase())))}))}function v(t,r){let e=r.toLowerCase(),i=new Set([e,`*.${e}`]),o=[...t],s=[];for(let n of t){if(n.type==="universal")continue;let a=C(n);if(!a.includes(e))continue;let f=o.filter(c=>c!==n&&m(c));a.every(c=>i.has(c)||f.some(k=>C(k).includes(c)))&&(o.splice(o.indexOf(n),1),s.push(n))}return s}var S=new Set(["pending_deletion","deleted","pending_cleanup"]);function R(t,r){let e=t.find(i=>i.id===r);return!e||S.has((e.status??"").toLowerCase())}async function h(t,r,e){await t.run({plane:"account",mode:"json",args:["ssl","certificate-packs","delete",e,"-z",r,"--force"]})}async function T({cf:t,out:r,zoneId:e,hostname:i}){let o="app.certificate",s=[];try{let n=v(await g(t,e),i);for(let a of n)try{await h(t,e,a.id),s.push(a.id)}catch(f){if(!l(f,"not_found"))throw f}}catch(n){return r.emit({type:"warning",code:"CERT_CLEANUP_FAILED",step:o,message:[`Couldn't remove ${i}'s certificate`,`It serves nothing now. Cloudflare said: ${u(n)}.`,"Optional: delete it in the Cloudflare dashboard (SSL/TLS \u2192 Edge Certificates)."].join(`
2
+ `)}),s}return s.length>0&&r.emit({type:"step",step:o,status:"ok",message:`Removed ${i}'s certificate.`,data:{hostname:i,certificatePacks:s}}),s}export{g as a,b,v as c,R as d,h as e,T as f};
@@ -0,0 +1 @@
1
+ import{m as r}from"./chunk-JYKRUS5C.js";import{bc as t}from"./chunk-LYNBZ7RV.js";var u=100;function c(e,n){return t(e,{plane:"account",args:["r2","buckets","list","--name-contains",n,"--per-page",String(u)]},r).then(o=>o.map(s=>s.name))}async function f(e,n){return(await c(e,n)).includes(n)}async function p(e,n){await e.run({plane:"account",mode:"json",args:["r2","buckets","create","--name",n]})}async function m(e,n){await e.run({plane:"account",mode:"json",args:["r2","buckets","delete",n,"--force"]})}export{c as a,f as b,p as c,m as d};
@@ -0,0 +1,6 @@
1
+ import{a as H,b as X,d as P,e as G,f as q,g as J,h as D,i as z,j as N,k as $,l as A}from"./chunk-YHJZMJYZ.js";import{a as F,f as x}from"./chunk-N5GQLGEC.js";import{b as B,c as U,f as K,g as j}from"./chunk-ZECBN24L.js";import{ma as W}from"./chunk-RMF4YGD6.js";import{b as L,d as Z}from"./chunk-CCWBPAKH.js";import{Bb as p,Hb as T,c as _}from"./chunk-LYNBZ7RV.js";function M(e){return`everyapp:${e}`}function O(e){if(!e)return null;if(e.startsWith("catch_all:"))return{kind:"catch_all",zoneId:e.slice(10)};let[n,t]=e.split("/");return n&&t?{kind:"rule",zoneId:n,ruleId:t}:null}function w(e){return e.slice(e.lastIndexOf("@")+1)}function b(e){return e.startsWith("*@")}async function ye({cf:e,gatewayDb:n,accountId:t,workerName:l,addresses:a,interactive:i,enableRouting:r=!1,confirm:s=L}){let d=(await B(n,l)).filter(o=>o.kind==="email-route"),m=d.filter(o=>!a.includes(o.binding));if(a.length===0)return d.length>0?{workerName:l,accountId:t,routes:[],enable:[],dropped:m}:null;let E=await U(n,"email-route");for(let o of a){let u=E.find(f=>f.name===o&&f.workerName!==l);if(u){let f=await W(n,u.workerName);throw new p("EMAIL_ADDRESS_TAKEN",`${o} already goes to another app${f?` (${f})`:""}`,{fix:`pick another address, or run ${_} email unset inbound in ${f?`${f}'s`:"that app's"} directory first`,data:{address:o,workerName:u.workerName,appId:f}})}}let R=new Map;for(let o of new Set(a.map(w)))R.set(o,await se(e,o,t));for(let o of a.filter(b)){let u=R.get(w(o));if(u.name!==w(o))throw new p("EMAIL_CATCH_ALL_NOT_APEX",`${o}: catch-alls only work on a zone's apex
2
+ ${w(o)} is a subdomain of ${u.name}.`,{fix:`list each address instead, e.g. --inbound support@${w(o)}`,data:{address:o,zone:u.name}})}let y=te(e),g=[];for(let[o,u]of R)await ne(e,u,o,await y.settings(u.id))||g.push({zone:u,domain:o});g.sort((o,u)=>+(o.domain!==o.zone.name)-+(u.domain!==u.zone.name));let S=new Set(d.flatMap(o=>{let u=O(o.resourceId);return u?.kind==="rule"?[u.ruleId]:[]})),k=o=>oe(o,l)||o.id!==null&&S.has(o.id),v=[];for(let o of a){let u=R.get(w(o));if(b(o)){let c=await y.catchAll(u.id),C=c.enabled&&c.actions.some(re=>re.type!=="drop");if(!k(c)&&C)throw new p("EMAIL_CATCH_ALL_TAKEN",`${u.name}'s catch-all already ${Y(c)}
3
+ ${o} would take it over.`,{fix:"set the catch-all back to Drop (Email Routing \u2192 Routing rules), or list addresses one by one",data:{address:o,zone:u.name,actions:c.actions}});v.push({address:o,zone:u,existing:k(c)?c:null});continue}let f=(await y.rules(u.id)).filter(c=>A(c)===o),h=f.find(c=>!k(c));if(h)throw new p("EMAIL_ADDRESS_TAKEN",`${o} already ${Y(h)}
4
+ The Email Routing rule ${h.name?`"${h.name}"`:h.id} on ${u.name} delivers it.`,{fix:"remove that rule, or pick another address",data:{address:o,zone:u.name,ruleId:h.id,actions:h.actions}});let I=f.find(c=>c.id!==null&&S.has(c.id))??f[0]??null;v.push({address:o,zone:u,existing:I})}if(g.length>0&&!r){let o=g.map(({domain:c})=>c),u=o.join(", "),h=`Turning it on locks ${o.length===1?"the domain's":"their"} MX and SPF records to Cloudflare.`,I=g.map(({zone:c,domain:C})=>`npx cf email-routing enable -z ${c.name} --name ${C}`);if(!i)throw new p("EMAIL_ROUTING_DISABLED",`Email Routing is off for ${u}
5
+ ${h} Nothing was changed.`,{data:{domains:o,commands:I}});await Z(s,`Turn on Email Routing for ${u}?`,{context:[`Email Routing is off for ${u}. ${h.replace("the domain's","its")}`]})}return{workerName:l,accountId:t,routes:v,enable:g,dropped:m}}async function be({cf:e,gatewayDb:n,plan:t,onProgress:l}){let{workerName:a}=t,i=!1,r=s=>{i=!0,l?.(s)};for(let{zone:s,domain:d}of t.enable)await X(e,s.id,d),r(`Turned on Email Routing for ${d}.`);for(let{address:s,zone:d,existing:m}of t.routes){let E=g=>ue(n,a,s,g);if(b(s)){let g=Q(a,{type:"all"});await E(`catch_all:${d.id}`),(!m||!V(m,g))&&(await N(e,d.id,g),r(`${d.name}'s catch-all sends mail to ${a}.`));continue}let R=Q(a,{type:"literal",field:"to",value:s});if(m?.id){await E(`${d.id}/${m.id}`),V(m,R)||(await J(e,d.id,m.id,R),r(`Updated the Email Routing rule for ${s}.`));continue}await E(null);let y=await q(e,d.id,R);await E(`${d.id}/${y}`),r(`Created the Email Routing rule for ${s}.`)}for(let s of t.dropped)await ie(e,n,a,t.accountId,s),r(`Removed the route for ${s.name}, which the app's inbound addresses no longer list.`);return{routed:t.routes.map(s=>s.address),removed:t.dropped.map(s=>s.name),changed:i}}function $e(e){let{appId:n,workerName:t,routed:l,removed:a}=e,i=a.length?` Removed the routes for ${a.join(", ")}.`:"";if(l.length===0)return`${n} receives no mail.${i}`;let r=e.sendersSettable?ae(l,e.senders):[],s=r.length===1,d=r.length?` To reply from ${r.join(", ")}, onboard ${s?"it":"them"} to Email Sending and list ${s?"it":"them"} with \`${_} email set --sender\` (docs/runbooks/email-sending-setup.md).`:"";return`Mail to ${l.join(", ")} goes to ${t}.${i}${d}`}function ae(e,n){return[...new Set(e.map(w))].filter(t=>!n.some(l=>l.endsWith(`@${t}`)))}async function Ae({cf:e,gatewayDb:n,accountId:t,workerName:l,routes:a}){let i=[];for(let r of a)await ie(e,n,l,t,r)&&i.push(b(r.name)?`the catch-all of ${w(r.name)} (it drops mail again)`:`the Email Routing rule for ${r.name}`);return i}async function ke(e,n){let t=te(e),l=[];for(let a of n){let i=R=>l.push({workerName:a.workerName,address:a.name,problem:R}),r=O(a.resourceId);if(!r){i("a deploy stopped before recording its rule");continue}let s=r.kind==="catch_all"?await t.catchAll(r.zoneId):await G(e,r.zoneId,r.ruleId);if(!s){i("its Email Routing rule is gone");continue}if(!s.enabled||$(s)!==a.workerName){i(r.kind==="catch_all"?`the catch-all ${s.enabled?`sends mail ${ee(s)}`:"is off"}`:`its rule ${s.enabled?`sends mail ${ee(s)}`:"is off"}`);continue}let d=await t.settings(r.zoneId),m=w(a.name),E={id:r.zoneId,name:d.name?.toLowerCase()??m};await ne(e,E,m,d)||i(`Email Routing is off for ${m}`)}return l}async function se(e,n,t){try{return await x(e,n,t)}catch(l){throw l instanceof p&&l.code==="ZONE_NOT_FOUND"?new p("EMAIL_ZONE_NOT_FOUND",`${n} isn't on Cloudflare DNS in this account
6
+ Email Routing needs the domain's zone in the Gateway's Cloudflare account.`,{fix:"add the domain (or its parent) to the account, or pick an address on another domain",data:{domain:n}}):l}}async function ne(e,n,t,l){return t===n.name?l.enabled:(await F(e,n.id,t)).some(i=>i.type==="MX"&&/\.mx\.cloudflare\.net\.?$/i.test(i.content??""))}function te(e){let n=new Map,t=new Map,l=new Map,a=(i,r,s)=>{let d=i.get(r);return d||(d=s(),i.set(r,d)),d};return{settings:i=>a(n,i,()=>H(e,i)),rules:i=>a(t,i,()=>P(e,i)),catchAll:i=>a(l,i,()=>z(e,i))}}function Q(e,n){return{name:M(e),enabled:!0,matchers:[n],actions:[{type:"worker",value:[e]}]}}var le={name:"",enabled:!1,matchers:[{type:"all"}],actions:[{type:"drop"}]};function oe(e,n){return e.name===M(n)||$(e)===n}function V(e,n){let t=n.matchers[0];return e.name===n.name&&e.enabled===n.enabled&&e.actions.length===1&&$(e)===n.actions[0].value[0]&&e.matchers.length===1&&e.matchers[0].type===t.type&&("value"in t?A(e)===t.value:!0)}function Y(e){let n=e.actions[0];return!n||n.type==="drop"?"drops mail":n.type==="forward"?`forwards to ${n.value?.[0]??"an address"}`:n.type==="worker"?"goes to another Worker":`sends mail to "${n.type}"`}function ee(e){let n=e.actions[0];if(!n)return"nowhere";let t=n.value?.[0];return n.type==="worker"?`to the Worker ${t??"(unnamed)"}`:n.type==="forward"?`to ${t??"an address"}`:`to "${n.type}"`}async function ue(e,n,t,l){try{await K(e,n,{kind:"email-route",binding:t,name:t,resourceId:l})}catch(a){throw a instanceof p&&a.code==="RESOURCE_OWNED"?new p("EMAIL_ADDRESS_TAKEN",`${t} was recorded for another app while this run was routing it`,{fix:"take another address, or remove it from that app first",data:{address:t}}):a}}async function ie(e,n,t,l,a){let i=O(a.resourceId),r=!1;try{if(i?.kind==="rule")r=await D(e,i.zoneId,i.ruleId);else if(i?.kind==="catch_all"){let s=await z(e,i.zoneId);oe(s,t)&&(await N(e,i.zoneId,le),r=!0)}else r=await de(e,t,l,a.name)}catch(s){if(!T(s,"not_found"))throw s}return await j(n,t,{kind:"email-route",binding:a.binding}),r}async function de(e,n,t,l){if(b(l))return!1;let a;try{a=(await x(e,w(l),t)).id}catch(r){if(r instanceof p)return!1;throw r}let i=!1;for(let r of await P(e,a))r.id&&r.name===M(n)&&A(r)===l&&(i=await D(e,a,r.id)||i);return i}function ve(e){return{sends:e.capabilities?.email?.access==="write",receives:e.email?.inbound===!0}}export{ye as a,be as b,$e as c,ae as d,Ae as e,ke as f,ve as g};
@@ -0,0 +1,98 @@
1
+ import{a as xe,b as V,e as E,f as C,g as $e,h as Ue,i as Me,j as ze,k as Ge,l as We}from"./chunk-NFU4YFXB.js";import{c as q,d as Pe}from"./chunk-T2GD7RHS.js";import{a as Ce,e as ke}from"./chunk-CCWBPAKH.js";import{a as De,c as be,d as Re,e as Te,f as Ae,g as Ne,h as ve,i as Se,j as Ie}from"./chunk-JYKRUS5C.js";import{Bb as l,Cb as L,Fa as $,Ha as v,Hb as S,Ka as U,La as me,Ma as M,Na as z,Oa as G,Pa as W,Qa as F,Ra as H,Ta as ge,Tb as ye,Va as _e,Wa as fe,Xa as Ee,ac as we,bc as f,c,ca as pe,cc as he,d as ce,e as A,ec as Oe,gc as Le,i as N}from"./chunk-LYNBZ7RV.js";import Fe from"node:path";function He(e,t){return{run:async(a,n)=>(await Ot(e,t,a,n)).map(r=>r.rows)}}var It=6e5;function An(e){let[,t=e,a]=/^([\s\S]*?)(?::\s*(SQLITE_[A-Z_]+))?(?:\s*\[code: \d+\])?$/.exec(e.trim())??[];return{problem:t,...a?{sqliteCode:a}:{}}}async function Ot(e,t,a,{timeoutMs:n}={}){let r=a.length===1?a[0]:{batch:a};return(await f(e,{plane:"account",...n?{timeoutMs:n}:{},args:s=>["d1","query",t,"--body",`@${s["query.json"]}`],files:{"query.json":r}},Ae)).map(s=>({rows:s.results??[],duration:s.meta?.duration??0,changes:s.meta?.changes??0}))}async function Nn(e,t){let{bookmark:a}=await f(e,{plane:"account",args:["d1","time-travel","get-bookmark",t]},Ne);return a}async function vn(e,t,a){await f(e,{plane:"account",args:["d1","time-travel","restore",t,"--bookmark",a,"--force"]},ve)}function Sn(e,t,a,{platform:n=process.platform,shell:r=process.env.SHELL}={}){let i=`npx cf@${ye} d1 time-travel restore ${e} --bookmark ${t} --force`;return a?n==="win32"&&!r?`$env:CLOUDFLARE_ACCOUNT_ID="${a}"; ${i}`:`CLOUDFLARE_ACCOUNT_ID=${a} ${i}`:i}function qe(e,t){let a=Fe.resolve(e);return["--dir",a,...t?["--pattern",Fe.join(a,"*","migration.sql")]:[]]}async function In({cf:e,databaseId:t,dir:a,nested:n=!1}){return(await f(e,{plane:"account",args:["d1","migrations","list",t,...qe(a,n)]},Te)).map(i=>i.Name)}async function On({cf:e,databaseId:t,dir:a,nested:n=!1}){let r=await f(e,{plane:"account",timeoutMs:It,args:["d1","migrations","apply",t,...qe(a,n)]},De),i=r.filter(s=>s.status!=="\u2705");if(i.length>0)throw new Error(`cf reported ${i.map(s=>`${s.name} ${s.status}`).join(", ")} (applying ${r.map(s=>s.name).join(", ")}).`);return r.map(s=>s.name)}import{generateKeyPairSync as Lt,randomBytes as Ct}from"node:crypto";var Ve=["self_hosted","hosted"];function kn({gatewayUrl:e,accountId:t,deploymentMode:a}){let{privateKey:n,publicKey:r}=Lt("rsa",{modulusLength:2048,publicKeyEncoding:{type:"spki",format:"pem"},privateKeyEncoding:{type:"pkcs8",format:"pem"}});return{secrets:{GATEWAY_URL:e,BETTER_AUTH_SECRET:Ct(32).toString("base64"),JWT_PRIVATE_KEY:n,JWT_PUBLIC_KEY:r,GATEWAY_DEPLOYMENT_MODE:a,CLOUDFLARE_ACCOUNT_ID:t},jwtPublicKey:r}}var kt=`CREATE TABLE IF NOT EXISTS _everyapp_install (
2
+ id TEXT PRIMARY KEY CHECK (id = 'install'),
3
+ account_id TEXT NOT NULL,
4
+ zone_id TEXT NOT NULL,
5
+ zone_name TEXT NOT NULL,
6
+ gateway_host TEXT NOT NULL,
7
+ app_base_domain TEXT NOT NULL,
8
+ oauth_kv_id TEXT NOT NULL,
9
+ release_version TEXT NOT NULL,
10
+ release_sha256 TEXT NOT NULL,
11
+ release_schema INTEGER NOT NULL,
12
+ release_committed_at INTEGER NOT NULL,
13
+ source_tree_sha256 TEXT,
14
+ live_version_id TEXT,
15
+ live_domains TEXT NOT NULL DEFAULT '[]',
16
+ live_app_workers TEXT NOT NULL DEFAULT '[]',
17
+ updated_at INTEGER NOT NULL,
18
+ updated_by TEXT,
19
+ jwt_public_key TEXT,
20
+ deployment_mode TEXT
21
+ )`;function Be(e){try{let t=JSON.parse(String(e??"[]"));return Array.isArray(t)?t.map(String):[]}catch{return[]}}var Pt=e=>Ve.includes(e)?e:null;function Ye(){return new l("GATEWAY_NOT_INSTALLED",`The Gateway's install didn't finish
22
+ Setup stopped before it recorded the install.`,{rerun:`${c} setup`,rerunNote:"asks for the hostname again"})}async function Ke(e){let[t=[]]=await e.run([{sql:"SELECT name FROM sqlite_master WHERE type = 'table' AND name = '_everyapp_install'"}]);if(t.length===0)return null;let[a=[]]=await e.run([{sql:"SELECT * FROM _everyapp_install WHERE id = 'install'"}]),n=a[0];return n?{accountId:String(n.account_id),zoneId:String(n.zone_id),zoneName:String(n.zone_name),gatewayHost:String(n.gateway_host),appBaseDomain:String(n.app_base_domain),oauthKvId:String(n.oauth_kv_id),releaseVersion:String(n.release_version),releaseSha256:String(n.release_sha256),releaseOrder:{schema:Number(n.release_schema),committedAt:Number(n.release_committed_at)},sourceTreeSha256:N(n.source_tree_sha256),liveVersionId:N(n.live_version_id),liveDomains:Be(n.live_domains),liveAppWorkers:Be(n.live_app_workers),updatedAt:Number(n.updated_at),updatedBy:N(n.updated_by),jwtPublicKey:N(n.jwt_public_key),deploymentMode:Pt(n.deployment_mode)}:null}async function zn(e,t){let a=[t.accountId,t.zoneId,t.zoneName,t.gatewayHost,t.appBaseDomain,t.oauthKvId,t.releaseVersion,t.releaseSha256,t.releaseOrder.schema,t.releaseOrder.committedAt,t.sourceTreeSha256,t.liveVersionId,JSON.stringify(t.liveDomains),JSON.stringify(t.liveAppWorkers),t.updatedAt,t.updatedBy,t.jwtPublicKey,t.deploymentMode];await e.run([{sql:kt},{sql:`INSERT INTO _everyapp_install (id, account_id, zone_id, zone_name, gateway_host,
23
+ app_base_domain, oauth_kv_id, release_version, release_sha256, release_schema,
24
+ release_committed_at, source_tree_sha256, live_version_id, live_domains,
25
+ live_app_workers, updated_at, updated_by, jwt_public_key, deployment_mode)
26
+ VALUES ('install', ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18)
27
+ ON CONFLICT(id) DO UPDATE SET account_id = excluded.account_id,
28
+ zone_id = excluded.zone_id, zone_name = excluded.zone_name,
29
+ gateway_host = excluded.gateway_host, app_base_domain = excluded.app_base_domain,
30
+ oauth_kv_id = excluded.oauth_kv_id, release_version = excluded.release_version,
31
+ release_sha256 = excluded.release_sha256, release_schema = excluded.release_schema,
32
+ release_committed_at = excluded.release_committed_at,
33
+ source_tree_sha256 = excluded.source_tree_sha256,
34
+ live_version_id = excluded.live_version_id, live_domains = excluded.live_domains,
35
+ live_app_workers = excluded.live_app_workers, updated_at = excluded.updated_at,
36
+ updated_by = excluded.updated_by,
37
+ jwt_public_key = COALESCE(excluded.jwt_public_key, _everyapp_install.jwt_public_key),
38
+ deployment_mode = COALESCE(excluded.deployment_mode, _everyapp_install.deployment_mode)`,params:a}])}var xt=100,$t=50;async function je(e,t){let a=await e();if(a)return{id:a,created:!1};try{return{id:await t(),created:!0}}catch(n){let r=S(n,"already_exists")?await e():null;if(r)return{id:r,created:!1};throw n}}async function B(e,t){return(await f(e,{plane:"account",args:["d1","list","--name",t,"--per-page","100"]},Re)).find(n=>n.name===t)?.uuid??null}async function Ut(e,t){return(await f(e,{plane:"account",args:["d1","create","--name",t]},be)).uuid}function Xe(e,t){return je(()=>B(e,t),()=>Ut(e,t))}async function Mt(e,t){return(await he(e,["kv","namespaces","list"],Ie,{perPage:xt,maxPages:$t})).find(n=>n.title===t)?.id??null}async function zt(e,t){return(await f(e,{plane:"account",args:["kv","namespaces","create","--title",t]},Se)).id}function Je(e,t){return je(()=>Mt(e,t),()=>zt(e,t))}async function qn(e,t){await e.run({plane:"account",mode:"json",args:["d1","delete",t,"--force"]})}async function Vn(e,t){await e.run({plane:"account",mode:"json",args:["kv","namespaces","delete",t,"--force"]})}import{randomBytes as qt}from"node:crypto";import{randomBytes as Y}from"node:crypto";var Ze="0123456789ABCDEFGHJKMNPQRSTVWXYZ",Gt=10,Wt=16;function Ft(e=Date.now()){let t="",a=Math.max(0,Math.floor(e));for(let r=0;r<Gt;r+=1)t=Ze[a%32]+t,a=Math.floor(a/32);let n=[...Y(Wt)].map(r=>Ze[r%32]).join("");return`${t}${n}`}var K=e=>`evt_${Ft(e)}`,j=()=>`sub_${Y(12).toString("hex")}`,X=()=>`dlv_${Y(12).toString("hex")}`;var Ht=/^\d{1,3}(\.\d{1,3}){3}$/,J=e=>e.trim().toLowerCase().replace(/\.$/,""),Qe=(e,t)=>t!==""&&(e===t||e.endsWith(`.${t}`)),y=(e,t=!1)=>({ok:!1,reason:e,private:t});function et(e,t){let a=e.trim();if(a.length>F)return y(`A webhook URL is at most ${F.toLocaleString("en-US")} characters.`);let n;try{n=new URL(a)}catch{return y("It isn't a URL: give the whole address, like https://hooks.example.com/everyapp.")}if(n.protocol==="http:"){if(!t.allowPrivate)return y("A webhook URL starts with https://: the event and its signature would cross the internet in the clear.",!0)}else if(n.protocol!=="https:")return y(`A webhook URL starts with https://, not ${n.protocol}//.`);if(n.username||n.password)return y("A webhook URL carries no user name or password: the subscription's secret signs each delivery instead.");if(n.hash||a.includes("#"))return y("A webhook URL has no fragment (#\u2026): it is never sent to the receiver.");let r=J(n.hostname),i=J(t.gatewayHost),s=J(t.appBaseDomain);return Qe(r,i)||Qe(r,s)?y(`${r} is the Gateway's own host, or under its apps' domain ${s}: a delivery there would loop back into the Gateway.`):r.startsWith("[")||Ht.test(r)?t.allowPrivate?{ok:!0,url:n.toString()}:y("A webhook URL names its host, not an IP address.",!0):ge(r)&&!t.allowPrivate?y(`${r} is a local or internal name, which the Gateway's Worker can't reach.`,!0):{ok:!0,url:n.toString()}}function Xn(e){try{let t=new URL(e),a=t.pathname==="/"?"":t.pathname;return`${t.protocol==="http:"?"http://":""}${t.host}${a}`}catch{return"(unreadable URL)"}}function Jn(e){try{return new URL(e).hostname}catch{return"Webhook"}}function Q(e){return{kind:"operator",id:e.actor,...e.email?{email:e.email}:{}}}var tt=new WeakMap;function ee(e){let t=tt.get(e);return t||(t=e.run([{sql:"PRAGMA table_info(events)"}]).then(([a=[]])=>a.length>0),tt.set(e,t)),t}async function R(e){if(!await ee(e))throw new l("GATEWAY_OUTDATED",`The Gateway predates events
39
+ Its database has no event tables until the Gateway is updated to a release that has them.`,{rerun:`${c} update`,rerunNote:"then run this again"})}async function te(e,t){if(!await ee(e))return[];let a=U(t.type);if(!a)throw new Error(`${t.type} isn't in the event catalogue`);let n=Ee(t.data,me);if(!n.ok)throw new Error(`${t.type}'s data: ${n.message}`);let r=t.now??Date.now(),i=K(r),[s=[]]=await e.run([{sql:"SELECT id, events FROM event_subscriptions WHERE organization_id = ? AND enabled = 1",params:[t.organizationId]}]),o=s.filter(u=>_e(nt(u.events),t.type)).map(u=>String(u.id));return[{sql:`INSERT INTO events (id, organization_id, type, version, time, actor, data, app_row_id, dedupe_key, created_at)
40
+ SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ? WHERE 1${t.onlyIf?` AND (${t.onlyIf.sql})`:""}
41
+ ON CONFLICT DO NOTHING`,params:[i,t.organizationId,t.type,a.version,r,JSON.stringify(t.actor),JSON.stringify(t.data),t.appRowId??null,t.dedupeKey??null,r,...t.onlyIf?.params??[]]},...o.map(u=>Vt(i,u,t.organizationId,r))]}function Vt(e,t,a,n){return{sql:`INSERT INTO event_deliveries (id, event_id, subscription_id, organization_id, status, attempts, next_attempt_at, created_at)
42
+ SELECT ?1, ?2, ?3, ?4, 'pending', 0, ?5, ?5
43
+ WHERE EXISTS (SELECT 1 FROM events WHERE id = ?2)
44
+ AND EXISTS (SELECT 1 FROM event_subscriptions WHERE id = ?3 AND organization_id = ?4 AND enabled = 1)`,params:[X(),e,t,a,n]}}var Bt="cap_alerts",Yt="Cap alerts",Kt=["cap.warning","cap.reached"];async function ia(e,t){return await ee(e)?{sql:`INSERT INTO event_subscriptions (id, organization_id, name, sink, url, secret, recipients, events, enabled,
45
+ builtin, description, created_at, updated_at, created_by, consecutive_failures)
46
+ SELECT ?1, ?2, ?3, 'email', NULL, NULL, 'admins', ?4, 1, ?5, ?6, ?7, ?7, ?8, 0
47
+ WHERE NOT EXISTS (SELECT 1 FROM event_subscriptions WHERE organization_id = ?2 AND builtin = ?5)
48
+ RETURNING id`,params:[j(),t.organizationId,Yt,JSON.stringify(Kt),Bt,"Owners and admins get an email at 80% and at the cap.",t.now,`operator:${t.deployer.actor}`]}:null}function nt(e){try{let t=JSON.parse(String(e));if(Array.isArray(t)&&t.every(a=>typeof a=="string"))return t}catch{}return[]}var ne="id, name, sink, url, recipients, events, enabled, builtin, description, created_at, created_by, last_delivery_at, last_delivery_status, consecutive_failures",b=e=>e==null?null:Number(e),h=e=>e==null?null:String(e);function ae(e){return{id:String(e.id),name:String(e.name),sink:e.sink==="email"?"email":"webhook",url:h(e.url),recipients:e.recipients==="owners"||e.recipients==="admins"?e.recipients:null,events:nt(e.events),enabled:Number(e.enabled)===1,builtin:h(e.builtin),description:h(e.description),createdAt:Number(e.created_at),createdBy:h(e.created_by),lastDeliveryAt:b(e.last_delivery_at),lastDeliveryStatus:h(e.last_delivery_status),consecutiveFailures:Number(e.consecutive_failures??0)}}async function sa(e,t){await R(e);let[a=[]]=await e.run([{sql:`SELECT ${ne} FROM event_subscriptions WHERE organization_id = ? ORDER BY created_at, id`,params:[t]}]);return a.map(ae)}function jt(e,t){return new l("EVENT_SUBSCRIPTION_NOT_FOUND",`No subscription ${e} in ${t}
49
+ Subscriptions belong to one organization; --org names another.`,{rerun:`${c} events list`,rerunNote:"lists them"})}async function re(e,t,a){await R(e);let[n=[]]=await e.run([{sql:`SELECT ${ne} FROM event_subscriptions WHERE id = ? AND organization_id = ?`,params:[a.trim(),t.id]}]);if(!n[0])throw jt(a.trim(),t.name);return ae(n[0])}function oa(e){let t=[...new Set((e??[]).flatMap(n=>n.split(",")).map(n=>n.trim()).filter(Boolean))];if(t.length===0)return["*"];let a=t.flatMap(n=>{let r=fe(n);return r?[{pattern:n,problem:r}]:[]});if(a.length>0)throw new l("EVENT_TYPE_UNKNOWN",[a.length===1?`${a[0].pattern} isn't an event type`:`${a.length} of --events aren't event types`,...a.map(n=>n.problem)].join(`
50
+ `),{fix:"name types (member.joined), prefixes (member.*), an app's own events (app.crm.*) or * for everything",rerun:`${c} events types`,rerunNote:"lists the types",data:{patterns:a.map(n=>n.pattern)}});return t.includes("*")?["*"]:t}function la(e,t){let a=et(e,t);if(a.ok)return a.url;throw new l("EVENT_TARGET_REFUSED",`The Gateway won't deliver to that URL
51
+ ${a.reason}`,{...a.private?{fix:`use a public https:// receiver; for one on a private network, set EVENTS_ALLOW_PRIVATE_TARGETS on the Gateway (${c} secret set EVENTS_ALLOW_PRIVATE_TARGETS, value true; self-host only)`}:{fix:"give the receiver's full https:// URL (Slack's, Zapier's, n8n's, your own)"}})}var Xt=/^[\x21-\x7e]+$/;function ua(e){let t=e.length<z||e.length>G?`A signing secret is ${z} to ${G} characters (this one is ${e.length}).`:Xt.test(e)?null:"A signing secret is printable ASCII with no spaces, so every receiver's HMAC reads the same bytes.";if(!t)return e;throw new l("EVENT_SECRET_INVALID",`That signing secret won't do
52
+ ${t}`,{fix:"leave --secret out and the CLI makes one, or give one of 16 to 128 printable characters"})}var da=()=>`whsec_${qt(32).toString("base64url")}`;function ca(e){let t=e?.replace(/\s+/g," ").trim()??"";return t===""?null:t.length>H?t.slice(0,H):t}async function pa(e,t){await R(e);let a=t.now??Date.now(),n=j(),{target:r}=t,[i=[]]=await e.run([{sql:`INSERT INTO event_subscriptions (id, organization_id, name, sink, url, secret, recipients, events, enabled,
53
+ builtin, description, created_at, updated_at, created_by, consecutive_failures)
54
+ SELECT ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, 1, NULL, NULL, ?9, ?9, ?10, 0
55
+ WHERE (SELECT COUNT(*) FROM event_subscriptions WHERE organization_id = ?2) < ?11
56
+ RETURNING ${ne}`,params:[n,t.organization.id,t.name,r.sink,r.sink==="webhook"?r.url:null,r.sink==="webhook"?r.secret:null,r.sink==="email"?r.recipients:null,JSON.stringify(t.events),a,`operator:${t.deployer.actor}`,M]}]);if(!i[0])throw new l("EVENT_SUBSCRIPTIONS_LIMIT",`${t.organization.name} has ${M} subscriptions, the most an organization may have
57
+ Nothing was added.`,{fix:`remove one you no longer need (${c} events remove <id>), or widen one's --events instead of adding another`,rerun:`${c} events list`,rerunNote:"lists them"});return ae(i[0])}async function ma(e,t,a,n=Date.now()){let r=await re(e,t,a);return r.builtin?(await e.run([{sql:"UPDATE event_subscriptions SET enabled = 0, updated_at = ? WHERE id = ? AND organization_id = ?",params:[n,r.id,t.id]}]),{subscription:{...r,enabled:!1},outcome:"disabled"}):(await e.run([{sql:"DELETE FROM event_subscriptions WHERE id = ? AND organization_id = ?",params:[r.id,t.id]}]),{subscription:r,outcome:"removed"})}async function ga(e,t,a,n,r=Date.now()){let i=await re(e,t,a);return i.enabled===n?{subscription:i,changed:!1}:(await e.run([{sql:"UPDATE event_subscriptions SET enabled = ?, updated_at = ? WHERE id = ? AND organization_id = ?",params:[n?1:0,r,i.id,t.id]}]),{subscription:{...i,enabled:n},changed:!0})}function Jt(e,t){return new l("EVENT_SUBSCRIPTION_DISABLED",`${e.name} (${e.id}) is disabled
58
+ The Gateway drops what is queued for a disabled subscription, so ${t} would go nowhere.`,{rerun:`${c} events enable ${e.id}`,rerunNote:"then run this again"})}var at=`d.id, d.event_id, e.type, d.subscription_id, s.name AS subscription_name, s.sink, d.status, d.attempts,
59
+ d.next_attempt_at, d.claimed_until, d.last_attempt_at, d.last_status_code, d.last_error, d.delivered_at,
60
+ d.redelivered_at, d.created_at`,rt=`FROM event_deliveries d
61
+ LEFT JOIN events e ON e.id = d.event_id
62
+ LEFT JOIN event_subscriptions s ON s.id = d.subscription_id AND s.organization_id = d.organization_id`;function it(e){let t=String(e.status);return{id:String(e.id),eventId:String(e.event_id),type:h(e.type),subscriptionId:String(e.subscription_id),subscriptionName:h(e.subscription_name),sink:e.sink==="email"?"email":e.sink==="webhook"?"webhook":null,status:t==="delivered"||t==="dead"?t:"pending",attempts:Number(e.attempts??0),nextAttemptAt:b(e.next_attempt_at),claimedUntil:b(e.claimed_until),lastAttemptAt:b(e.last_attempt_at),lastStatusCode:b(e.last_status_code),lastError:h(e.last_error),deliveredAt:b(e.delivered_at),redeliveredAt:b(e.redelivered_at),createdAt:Number(e.created_at)}}function Zt(e,t=Date.now()){if(e.status!=="pending")return e.status;let a=e.claimedUntil!==null&&e.claimedUntil>t;return e.attempts>0&&e.lastError!==null&&!a?"failed":"pending"}var Qt=200;async function _a(e,t){await R(e);let a=(t.now??Date.now())-W*24*60*60*1e3,n=["d.organization_id = ?","d.created_at >= ?",...t.subscriptionId?["d.subscription_id = ?"]:[],...t.dead?["d.status = 'dead'"]:[]],[r=[]]=await e.run([{sql:`SELECT ${at} ${rt} WHERE ${n.join(" AND ")} ORDER BY d.created_at DESC, d.id DESC LIMIT ?`,params:[t.organizationId,a,...t.subscriptionId?[t.subscriptionId]:[],Math.min(Math.max(1,Math.floor(t.limit)),Qt)]}]);return r.map(it)}async function Z(e,t,a){let[n=[]]=await e.run([{sql:`SELECT ${at} ${rt} WHERE d.id = ? AND d.organization_id = ?`,params:[a,t]}]);return n[0]?it(n[0]):null}async function fa(e,t,a,n=Date.now()){await R(e);let r=await Z(e,t.id,a.trim());if(!r)throw new l("EVENT_DELIVERY_NOT_FOUND",`No delivery ${a.trim()} in ${t.name}
63
+ Deliveries are kept ${W} days, under the organization of their subscription.`,{rerun:`${c} events deliveries`,rerunNote:"lists the last ones"});let i=await re(e,t,r.subscriptionId).catch(u=>{throw u instanceof l&&u.code==="EVENT_SUBSCRIPTION_NOT_FOUND"?new l("EVENT_SUBSCRIPTION_NOT_FOUND",`${r.id} was for ${r.subscriptionId}, which is removed
64
+ There is nowhere to send it again.`,{rerun:`${c} events list`,rerunNote:"lists the subscriptions there are"}):u});if(!i.enabled)throw Jt(i,"sending it again");let[s=[]]=await e.run([{sql:`UPDATE event_deliveries SET status = 'pending', attempts = 0, next_attempt_at = ?1, redelivered_at = ?1, claimed_until = NULL
65
+ WHERE id = ?2 AND organization_id = ?3 AND status IN ('pending', 'dead') AND (claimed_until IS NULL OR claimed_until <= ?1)
66
+ RETURNING id`,params:[n,r.id,t.id]}]),o=await Z(e,t.id,r.id)??r,d=s.length>0?"queued":o.status==="delivered"?"delivered":"attempting";return{delivery:o,previous:r,outcome:d}}async function Ea(e,t){await R(e);let a=t.now??Date.now(),n=K(a),r=X(),i={subscription:{id:t.subscription.id,name:t.subscription.name},message:"A test event from everyapp events test. A signed delivery like this one means the subscription works."};return await e.run([{sql:`INSERT INTO events (id, organization_id, type, version, time, actor, data, app_row_id, dedupe_key, created_at)
67
+ VALUES (?1, ?2, 'ping', ?3, ?4, ?5, ?6, NULL, NULL, ?4)`,params:[n,t.organizationId,U("ping").version,a,JSON.stringify(t.actor),JSON.stringify(i)]},{sql:`INSERT INTO event_deliveries (id, event_id, subscription_id, organization_id, status, attempts, next_attempt_at, created_at)
68
+ VALUES (?1, ?2, ?3, ?4, 'pending', 0, ?5, ?5)`,params:[r,n,t.subscription.id,t.organizationId,a]}]),{eventId:n,deliveryId:r}}var en=9e4;async function ya(e,t,a,n={}){let r=n.sleep??(o=>new Promise(d=>setTimeout(d,o))),i=n.now??Date.now,s=i()+(n.timeoutMs??en);for(;;){let o=await Z(e,t,a);if(o&&Zt(o,i())!=="pending")return o;if(i()>=s)return null;await r(Math.min(n.intervalMs??3e3,Math.max(0,s-i())))}}import{randomUUID as tn}from"node:crypto";function ut(e,t,a=process.env){return a.CLOUDFLARE_API_TOKEN||!e?{actor:`api-token:${t}`,email:null}:{actor:e,email:e}}function nn(e){return e instanceof C?new l(e.code,e.message,{retryable:e.status>=500}):e}async function oe(e){try{return await e()}catch(t){throw nn(t)}}var dt="id, organization_id, app_slug, name, description, hostname, worker_name, tier, scope, manifest, status, version_id, deployed_at, deployed_by_actor, is_default, email_senders, email_inbound",an=`${dt}, secret_names`,st=new WeakMap;function I(e){let t=st.get(e);return t||(t=e.run([{sql:"PRAGMA table_info(apps)"}]).then(([a=[]])=>a.some(n=>n.name==="secret_names")),st.set(e,t)),t}async function k(e){return await I(e)?an:dt}var m=e=>e==null?null:String(e);function P(e){return{id:String(e.id),organizationId:String(e.organization_id),appSlug:String(e.app_slug),name:String(e.name),description:String(e.description),hostname:m(e.hostname),workerName:m(e.worker_name),tier:String(e.tier),scope:String(e.scope),manifest:m(e.manifest),status:String(e.status),versionId:m(e.version_id),deployedAt:e.deployed_at==null?null:Number(e.deployed_at),deployedByActor:m(e.deployed_by_actor),isDefault:!!Number(e.is_default),emailSenders:m(e.email_senders),emailInbound:m(e.email_inbound),secretNames:m(e.secret_names)}}function ot(e){return e?{organizationId:String(e.organization_id),appSlug:String(e.app_slug),hostname:m(e.hostname),workerName:m(e.worker_name)}:null}function lt(e){return e?{id:String(e.id),name:String(e.name),slug:String(e.slug)}:null}var ct={sql:`SELECT id, name, slug FROM organizations
69
+ WHERE EXISTS (SELECT 1 FROM members WHERE members.organization_id = organizations.id AND members.role = 'owner')
70
+ ORDER BY created_at, id LIMIT 1`},pt={sql:"SELECT id, name, slug FROM organizations ORDER BY created_at, id LIMIT 1"};async function mt(e){let[t=[],a=[]]=await e.run([ct,pt]);return gt(t,a)}function gt(e,t){let a=lt(e[0]);if(a)return{organization:a,hasOwner:!0};let n=lt(t[0]);return n?{organization:n,hasOwner:!1}:null}function rn(e){return e.trim().toLowerCase().replace(/[^a-z0-9\s-]/g,"").replace(/\s+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"").slice(0,48)}async function sn(e,t,a){let n=await mt(e);if(n)return n;let r=t.trim()||"My Organization",[,i=[],s=[]]=await e.run([{sql:`INSERT INTO organizations (id, name, slug, created_at)
71
+ SELECT ?1, ?2, ?3, ?4 WHERE NOT EXISTS (SELECT 1 FROM organizations)`,params:[tn(),r,rn(r)||"default",a]},ct,pt]),o=gt(i,s);if(!o)throw new Error("The gateway's database has no organization.");return o}function on(e,t){let a=$e(t);return{sql:`WITH candidates(rank, candidate) AS (VALUES ${a.map((r,i)=>`(${i}, ?${i+2})`).join(", ")})
72
+ INSERT OR IGNORE INTO organization_keys (organization_id, org_key)
73
+ SELECT ?1, candidate FROM candidates
74
+ WHERE NOT EXISTS (SELECT 1 FROM organization_keys WHERE organization_id = ?1)
75
+ AND candidate NOT IN (SELECT org_key FROM organization_keys)
76
+ ORDER BY rank LIMIT 1`,params:[e,...a]}}function va(e,t){return oe(()=>ln(e,t))}async function ln(e,t){let a=t.now??Date.now(),{organization:n,hasOwner:r}=await sn(e,t.organizationName,a),[,i=[],s=[],o=[],d=[]]=await e.run([on(n.id,n.slug),{sql:"SELECT org_key FROM organization_keys WHERE organization_id = ?",params:[n.id]},{sql:`SELECT ${await k(e)} FROM apps WHERE organization_id = ? AND app_slug = ?`,params:[n.id,t.appSlug]},..._t(n.id,t.deployer.email)]),u=m(i[0]?.org_key);if(!u)throw new C({status:409,code:"ORG_KEY_UNAVAILABLE",message:`Every key for organization "${n.slug}" is taken by another organization on this gateway.`});let g=s[0]?P(s[0]):null,D=Ue({appSlug:t.appSlug,orgKey:u,isInstallOrganization:!0,appBaseDomain:t.appBaseDomain,existingApp:g}),[O=[],p=[]]=await e.run([{sql:"SELECT organization_id, app_slug, hostname, worker_name FROM apps WHERE hostname = ?",params:[D.hostname]},{sql:"SELECT organization_id, app_slug, hostname, worker_name FROM apps WHERE worker_name = ?",params:[D.workerName]}]),_=m(d[0]?.id),T=ft(o),w=ze({organizationId:n.id,isInstallOrganization:!0,scope:t.scope,appSlug:t.appSlug,name:t.name,description:t.description,manifest:t.manifest,appBaseDomain:t.appBaseDomain,orgKey:u,existingApp:g,hostnameOwner:ot(O[0]),workerNameOwner:ot(p[0]),members:T,deployerUserId:_});if(w.app.scope==="shared"&&Et(t.deployer,_,T,n,t.expectedWorkerName===void 0?"deploy":"register"),t.expectedWorkerName!==void 0&&w.app.workerName!==t.expectedWorkerName)throw new l("WORKER_NAME_MISMATCH",`${t.appSlug}'s Worker must be named ${w.app.workerName}, not ${t.expectedWorkerName}
77
+ The Gateway binds each app's Worker by that name only.`,{fix:`deploy the Worker as ${w.app.workerName}`,rerun:`${A("--worker")} --worker ${w.app.workerName}`});return await e.run(dn(w,a,{secretNames:await I(e)})),{plan:w,organization:n,hasOwner:r,deployerGranted:_!==null&&w.grants.some(St=>St.userId===_)}}function _t(e,t){return[{sql:"SELECT user_id, role FROM members WHERE organization_id = ?",params:[e]},{sql:"SELECT id FROM users WHERE lower(email) = lower(?) AND email_verified = 1",params:[t]}]}function ft(e){return e.map(t=>({id:String(t.user_id),role:m(t.role)}))}var un=e=>(e??"").split(",").some(t=>["owner","admin"].includes(t.trim()));function Et(e,t,a,n,r){if(e.email===null)return;let i=a.find(s=>s.id===t);if(!(i&&un(i.role)))throw new l("SHARED_APP_FORBIDDEN",`Only ${n.name} owners and admins can ${r} shared apps
78
+ ${e.email} isn't an owner or admin of ${n.name}, the platform organization.`,{fix:`ask an owner of ${n.name} to make you an admin, or to do it for you`})}function dn(e,t,a){let{app:n}=e;if(e.kind==="existing")return[{sql:"UPDATE apps SET name = ?, description = ?, updated_at = ? WHERE id = ?",params:[n.name,n.description,t,n.id]}];let r=e.grants.map(i=>({sql:`INSERT INTO user_app_access (id, user_id, app_row_id, organization_id, granted_by)
79
+ VALUES (?, ?, ?, ?, NULL) ON CONFLICT DO NOTHING`,params:[i.id,i.userId,i.appRowId,i.organizationId]}));return e.kind==="new"?[{sql:`INSERT INTO apps (id, organization_id, app_slug, name, description, hostname,
80
+ worker_name, tier, manifest, status, version_id, deployed_at, deployed_by_actor,
81
+ is_default, created_at, updated_at, scope)
82
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?15, ?16)`,params:[n.id,n.organizationId,n.appSlug,n.name,n.description,n.hostname,n.workerName,n.tier,n.manifest,n.status,n.versionId,n.deployedAt,n.deployedByActor,n.isDefault?1:0,t,n.scope]},...r]:[{sql:`UPDATE apps SET name = ?, description = ?, hostname = ?, worker_name = ?,
83
+ manifest = ?, status = ?, is_default = ?, updated_at = ?
84
+ WHERE id = ? AND status = '${E}'`,params:[n.name,n.description,n.hostname,n.workerName,n.manifest,n.status,n.isDefault?1:0,t,n.id]},...yt(n,t,a),...r]}function yt(e,t,{secretNames:a=!0}={}){let n=[e.id,e.organizationId];return[{sql:`UPDATE apps SET email_senders = NULL, email_inbound = NULL${a?", secret_names = NULL":""} WHERE id = ? AND organization_id = ?`,params:n},{sql:"DELETE FROM user_app_access WHERE app_row_id = ? AND organization_id = ?",params:n},{sql:"DELETE FROM group_app_access WHERE app_row_id = ? AND organization_id = ?",params:n},{sql:`UPDATE user_access_tokens SET revoked_at = ?1, updated_at = ?1
85
+ WHERE app_row_id = ?2 AND organization_id = ?3 AND revoked_at IS NULL`,params:[t,...n]},{sql:"DELETE FROM app_tools WHERE app_row_id = ? AND organization_id = ?",params:n},{sql:"DELETE FROM app_tool_catalogs WHERE app_row_id = ? AND organization_id = ?",params:n},{sql:"DELETE FROM mcp_connection_apps WHERE app_row_id = ?",params:[e.id]},{sql:"DELETE FROM org_app_settings WHERE app_row_id = ?",params:[e.id]}]}async function cn(e,t){let[a=[]]=await e.run([{sql:`SELECT ${await k(e)} FROM apps WHERE id = ?`,params:[t]}]);return a[0]?P(a[0]):null}var pn=3,ie=e=>({id:e.appSlug,rowId:e.id,name:e.name});async function mn(e,t,a,n){let r=t.status==="pending";return!r&&t.versionId===a.versionId?[]:te(e,{organizationId:t.organizationId,type:r?"app.installed":"app.updated",actor:Q({actor:a.actor,email:a.email??null}),data:r?{app:ie(t),version:a.versionId,...t.hostname?{hostname:t.hostname}:{},scope:t.scope==="shared"?"shared":"org",source:a.source??"cli"}:{app:ie(t),version:a.versionId,...t.versionId?{previousVersion:t.versionId}:{}},appRowId:t.id,onlyIf:{sql:"EXISTS (SELECT 1 FROM apps WHERE id = ? AND version_id = ?)",params:[t.id,a.versionId]},now:n})}function Sa(e,t,a){return oe(async()=>{let n=await I(e);for(let r=1;;r+=1){let i=await cn(e,t);if(!i)throw new C({status:404,code:"APP_NOT_FOUND",message:"The app's registry row is gone; deploy it again."});let s=Ge(i,a),o=await mn(e,i,a,s.deployedAt),[d=[]]=await e.run([{sql:`UPDATE apps SET manifest = ?, version_id = ?, deployed_at = ?, deployed_by_actor = ?,
86
+ status = ?, updated_at = ?${n?", secret_names = COALESCE(?, secret_names)":""}
87
+ WHERE id = ? AND status = ? RETURNING status`,params:[s.manifest,s.versionId,s.deployedAt,s.deployedByActor,s.status,s.deployedAt,...n?[a.secretNames?V(a.secretNames):null]:[],t,i.status]},...o]);if(d.length>0)return s.status;if(r>=pn)throw new l("APP_CHANGING",`The app's registry row keeps changing while this deploy records its upload
88
+ The upload is kept.`,{retryable:!0})}})}function x(e){return{id:e.id,appSlug:e.appSlug,organizationId:e.organizationId,status:e.status,workerName:e.workerName??"",hostname:e.hostname??"",resources:Me(e),email:{senders:v(e.emailSenders),inbound:v(e.emailInbound)},declaresInbound:_n(e.manifest),publicRoutes:Oe(e.manifest),mcp:Le(e.manifest),manifest:gn(e.manifest),secretNames:xe(e.secretNames),tier:e.tier}}function gn(e){if(!e)return null;try{let t=JSON.parse(e);return t&&typeof t=="object"&&!Array.isArray(t)?t:null}catch{return null}}function _n(e){if(!e)return!1;try{let a=JSON.parse(e)?.email?.inbound;return a===!0||Array.isArray(a)}catch{return!1}}async function le(e,t){let a=await mt(e);if(!a)return null;let[n=[]]=await e.run([{sql:`SELECT ${await k(e)} FROM apps WHERE organization_id = ? AND app_slug = ?`,params:[a.organization.id,t]}]);return n[0]?{app:P(n[0]),organization:a.organization}:null}async function wt(e,t,a,n){if(t.email===null)return;let[r=[],i=[]]=await e.run(_t(a.id,t.email));Et(t,m(i[0]?.id),ft(r),a,n)}function se(e){return new l("APP_NOT_FOUND",`${e} isn't deployed to this Gateway yet`,{rerun:`${c} deploy`,rerunNote:"in the app's directory"})}async function Ia(e,t){let a=await fn(e,t);if(!a)throw se(t);return a}async function fn(e,t){let a=(await le(e,t))?.app;return a&&ht(a)?x(a):null}function ht(e){return e.status!==E&&!!e.workerName}async function Oa(e,t){let[a=[]]=await e.run([{sql:"SELECT email_senders, email_inbound FROM apps WHERE id = ?",params:[t]}]),n=a[0];if(!n)throw new l("APP_NOT_FOUND","The app is no longer registered on this Gateway",{rerun:`${c} deploy`,rerunNote:"in the app's directory"});return{senders:v(n.email_senders),inbound:v(n.email_inbound)}}async function La(e,t,a,n,r=Date.now()){return oe(async()=>{let i=await le(e,t);if(!i||!ht(i.app))throw se(t);let{app:s,organization:o}=i;s.scope==="shared"&&await wt(e,n,o,"change the email of");let d=$(a.senders),u=$(a.inbound),[g=[]]=await e.run([{sql:`UPDATE apps SET email_senders = ?, email_inbound = ?, updated_at = ?
89
+ WHERE id = ? AND status != '${E}' RETURNING id`,params:[d,u,r,s.id]}]);if(g.length===0)throw se(t);return x({...s,emailSenders:d,emailInbound:u})})}async function Ca(e,t,a,n=Date.now()){await I(e)&&await e.run([{sql:`UPDATE apps SET secret_names = ?, updated_at = ?
90
+ WHERE id = ? AND status != '${E}'`,params:[V(a),n,t]}])}async function ka(e,t){let[a=[]]=await e.run([{sql:`SELECT app_slug FROM apps WHERE status != '${E}' AND (worker_name = ? OR substr(?, 1, length(worker_name) + 2) = worker_name || '--')`,params:[t,t]}]);return m(a[0]?.app_slug)}async function Pa(e){let[t=[]]=await e.run([{sql:`SELECT ${await k(e)} FROM apps WHERE status != '${E}' ORDER BY app_slug, organization_id`}]);return t.map(P).map(a=>({...x(a),deployedBy:a.deployedByActor,deployedAt:a.deployedAt}))}async function xa(e){let[t=[]]=await e.run([{sql:"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'apps'"}]);if(t.length===0)return[];let[a=[]]=await e.run([{sql:"SELECT app_slug, hostname, worker_name, status FROM apps ORDER BY app_slug"}]);return a.map(n=>({appSlug:String(n.app_slug),hostname:m(n.hostname),workerName:m(n.worker_name),status:String(n.status)}))}async function $a(e,t,a,n=Date.now(),{purge:r=!1}={}){let i=await le(e,t);if(i&&i.app.tier===pe&&i.app.status!==E)throw new l("APP_NOT_FOUND",`${t} is an MCP app, not an app deployed to this Gateway`,{rerun:`${c} mcp remove ${t}`,rerunNote:"removes an MCP app"});if(!i||!i.app.workerName)throw new l("APP_NOT_FOUND",`No app named ${t} on this Gateway`,{rerun:`${c} status`,rerunNote:"lists its apps"});let{app:s,organization:o}=i;s.scope==="shared"&&await wt(e,a,o,"delete");let d=We(s);return d&&await e.run([{sql:"UPDATE apps SET status = ?, is_default = ?, updated_at = ? WHERE id = ?",params:[d.status,d.isDefault?1:0,n,s.id]},...yt(s,n,{secretNames:await I(e)}),...await te(e,{organizationId:s.organizationId,type:"app.removed",actor:Q(a),data:{app:ie(s),purged:r},appRowId:s.id,now:n})]),{...x(s),status:E,alreadyDeleted:d===null}}var ue="every-app-gateway",Dt="every-app-gateway-OAUTH_KV";async function za(e){let t=await Xe(e,ue),a=await Je(e,Dt);return{d1Id:t.id,oauthKvId:a.id,created:[...t.created?[`D1 ${ue}`]:[],...a.created?[`KV ${Dt}`]:[]]}}function bt(e){return B(e,ue)}async function Rt({whoami:e,createCf:t,accountId:a,host:n,hostFlag:r,interactive:i,pick:s=wn}){let o=a||process.env.CLOUDFLARE_ACCOUNT_ID||void 0,d=(e.accounts??[]).map(p=>({id:p.id,name:p.name??null})),u=o&&!d.some(p=>p.id===o)?[...d,{id:o,name:null}]:d,g=(await Promise.all(u.map(p=>En(p,t)))).filter(p=>p!==null),D={probed:u,found:g,...o?{requestedAccountId:o}:{}};if(o)return{...D,gateway:g.find(p=>p.account.id===o)??null};if(g.length<=1)return{...D,gateway:g[0]??null};let O=n?g.filter(p=>p.install?.gatewayHost.toLowerCase()===n.toLowerCase()):[];if(O.length===1)return{...D,gateway:O[0]};if(i)return{...D,gateway:await s(g,e)};throw new L("choose_account",`Choose which Gateway to use
91
+ ${e.email??"This login"} sees a Gateway in ${g.length} Cloudflare accounts. Run one of:`,void 0,{rerun:null,data:{choices:g.map(p=>{let _=p.install?.gatewayHost,T=r&&_;return{accountId:p.account.id,accountName:p.account.name,gatewayUrl:_?`https://${_}`:null,label:T?p.account.name??p.account.id:[p.account.name,_].filter(Boolean).join(" \xB7 "),rerun:T?`${A(r)} ${r} ${_}`:ce(["--account-id",p.account.id])}})}})}async function En(e,t){let a=t(e.id);try{let n=await bt(a);if(!n)return null;let r=He(a,n);return{account:e,cf:a,databaseId:n,db:r,install:await Ke(r)}}catch(n){if(S(n,"auth")||S(n,"not_found"))return null;throw n}}function de(e,t){if(e.gateway)return e.gateway;let a=t.email?[`Logged in to Cloudflare as ${t.email}.`]:[],n={accounts:e.probed};if(e.requestedAccountId&&e.found.length>0)throw new l("GATEWAY_NOT_FOUND",[`Cloudflare account ${e.requestedAccountId} has no Gateway`,`This login's Gateway${e.found.length===1?" is":"s are"} in ${e.found.map(yn).join("; ")}.`].join(`
92
+ `),{fix:"pass that account's id to --account-id (or CLOUDFLARE_ACCOUNT_ID), or drop it",data:n});if(e.probed.length===0)throw new l("GATEWAY_NOT_FOUND",["This Cloudflare login lists no accounts",...a].join(`
93
+ `),{fix:"pass the Gateway's account with --account-id, or set CLOUDFLARE_ACCOUNT_ID",data:n});let r=e.probed.map(i=>i.name??i.id);throw new l("GATEWAY_NOT_FOUND",[r.length===1?`No Gateway in ${r[0]}, the only account this login sees`:`No Gateway in the ${r.length} accounts this login sees`,...r.length===1?[]:[`${r.join(", ")}.`],...a,`Or log in to the Gateway's account: ${c} login`].join(`
94
+ `),{rerun:`${c} setup --domain <hostname>`,rerunNote:"to install one",data:n})}function Tt(e,t,a=process.argv.slice(2)){if(!t)return;let n=new URL(t).host.toLowerCase(),r=e.install.gatewayHost.toLowerCase();if(n===r)return;let i=a.some(o=>o==="--gateway"||o.startsWith("--gateway=")),s=e.account.name??e.account.id;throw new l("GATEWAY_URL_MISMATCH",`The Gateway here is ${r}, not ${n}
95
+ Found in ${s}. For ${n}, pass its account with --account-id.`,i?{rerun:A("--gateway",a),rerunNote:`to use ${r}`}:{fix:`unset EVERYAPP_GATEWAY_URL to use ${r}`})}function yn(e){return`${e.account.name??e.account.id}${e.install?` at https://${e.install.gatewayHost}`:""}`}function wn(e,t){return ke("Which Gateway?",e.map(a=>{let n=a.account.name??a.account.id;return a.install?{label:a.install.gatewayHost,hint:n,value:a}:{label:n,value:a}}),{context:[`${t.email??"This login"} sees a Gateway in ${e.length} Cloudflare accounts`]})}var Nt=e=>we({accountId:e});function At(e,t){let a;try{a=new URL(e)}catch{throw new l("INVALID_GATEWAY_URL",t==="--gateway"?`--gateway must be a full URL, not "${e}"
96
+ For example https://apps.example.com.`:`EVERYAPP_GATEWAY_URL must be a full URL, not "${e}"`,t==="--gateway"?{}:{fix:`set it to https://${e.replace(/^\w+:\/\//,"")}, or unset it`})}return a.pathname=a.pathname.replace(/\/+$/,""),a.search="",a.hash="",a.toString().replace(/\/+$/,"")}function ar(e){if(e)return At(e,"--gateway");let t=process.env.EVERYAPP_GATEWAY_URL;return t?At(t,"EVERYAPP_GATEWAY_URL"):void 0}async function vt({createCf:e=Nt,accountId:t,host:a,interactive:n,onDeviceLogin:r}){let i=await Pe({cf:e(),interactive:n,onDeviceLogin:r}),s=await Rt({whoami:i,createCf:e,accountId:t,host:a,interactive:n});return{whoami:i,discovery:s}}function hn(e){let{install:t}=e;if(!t)throw Ye();if(t.liveVersionId===null)throw new l("GATEWAY_NOT_INSTALLED",`The Gateway at https://${t.gatewayHost} isn't finished installing
97
+ Setup stopped before its first upload.`,{rerun:`${c} setup`});return{...e,install:t}}async function rr({json:e,out:t,accountId:a,createCf:n}){let{whoami:r,discovery:i}=await vt({createCf:n,accountId:a,interactive:Ce(e??!1),onDeviceLogin:e?q(t,"gateway.login"):void 0});if(i.found.length===0&&i.probed.length>0&&!i.requestedAccountId){let s=i.probed.map(o=>o.name??o.id);throw new L("install_gateway",[`No Gateway in ${s.length===1?`${s[0]}'s Cloudflare account`:`the ${s.length} Cloudflare accounts this login sees`}${r.email?` (logged in as ${r.email})`:""}`,`Gateway in another account? Log in to it: ${c} login`].join(`
98
+ `),void 0,{rerun:`${c} setup`,rerunNote:"installs one",data:{accounts:i.probed}})}return de(i,r)}async function ir({gateway:e,accountId:t,interactive:a,createCf:n=Nt,onNoGateway:r,login:i}){let s=await vt({createCf:n,accountId:t,host:e?new URL(e).host.toLowerCase():void 0,interactive:a,onDeviceLogin:i?.json?q(i.out,i.step):void 0}),{whoami:o}=s,{discovery:d}=s;r&&d.gateway===null&&d.found.length===0&&d.probed.length>0&&(d=await r({whoami:o,discovery:d}));let u=hn(de(d,o));return Tt(u,e),{cf:u.cf,accountId:u.account.id,accountName:u.account.name,databaseId:u.databaseId,db:u.db,install:u.install,gatewayUrl:`https://${u.install.gatewayHost}`,deployer:ut(o.email,u.account.id)}}export{He as a,An as b,Ot as c,Nn as d,vn as e,Sn as f,In as g,On as h,kn as i,Ye as j,Ke as k,zn as l,B as m,Ut as n,Mt as o,zt as p,qn as q,Vn as r,za as s,bt as t,Rt as u,de as v,Xn as w,Jn as x,Q as y,ee as z,R as A,te as B,ia as C,sa as D,re as E,oa as F,la as G,ua as H,da as I,ca as J,pa as K,ma as L,ga as M,Jt as N,Zt as O,Qt as P,_a as Q,fa as R,Ea as S,en as T,ya as U,ut as V,oe as W,I as X,k as Y,m as Z,P as _,mt as $,sn as aa,va as ba,_t as ca,ft as da,yt as ea,cn as fa,Sa as ga,Ia as ha,fn as ia,Oa as ja,La as ka,Ca as la,ka as ma,Pa as na,xa as oa,$a as pa,ar as qa,rr as ra,ir as sa};
@@ -0,0 +1,10 @@
1
+ import{e as A,h as d}from"./chunk-CCWBPAKH.js";import{b as L}from"./chunk-JYKRUS5C.js";import{Bb as u,Cb as s,Fb as h,Jb as C,bc as p,c,d as g,jc as E}from"./chunk-LYNBZ7RV.js";import f from"chalk";var O=null;async function _(o){let t=await p(o,{plane:"account",args:["auth","whoami"]},L);return O=t.authenticated&&!process.env.CLOUDFLARE_API_TOKEN?t.email??null:null,t}function x(){return O}var m=5*60*1e3;function F(o,t){return i=>o.emit({type:"action_required",action:"cloudflare_login",step:t,message:"Log in to Cloudflare: open this link and enter the code",data:{url:i.url,code:i.code,expiresAt:new Date(Date.now()+m).toISOString(),waiting:!0,waitingFor:"Cloudflare login"}})}async function S(o){let t=await _(o.cf);return t.authenticated?t:w(o)}async function w({cf:o,interactive:t,onDeviceLogin:i}){if(process.env.CLOUDFLARE_API_TOKEN)throw new u("CLOUDFLARE_TOKEN_REJECTED",`Cloudflare didn't accept CLOUDFLARE_API_TOKEN
2
+ It may be mistyped, expired or revoked.
3
+ A token needs Account \u203A Workers Scripts \u203A Edit, Account \u203A D1 \u203A Edit, Account \u203A Workers KV Storage \u203A Edit, Zone \u203A Zone \u203A Read and Zone \u203A DNS \u203A Read: https://dash.cloudflare.com/profile/api-tokens`,{fix:`set a valid token, or unset CLOUDFLARE_API_TOKEN and run ${c} login`});if(t)d(`${f.cyan("\u2192")} Log in to Cloudflare to continue
4
+ ${f.dim(" Starting Cloudflare's login. Open its link and enter the code.")}`),await o.run({plane:"account",mode:"interactive",args:["auth","login"]});else if(i)await D(o,i);else throw new s("cloudflare_login",`Log in to Cloudflare with ${c} login
5
+ Unattended? Set CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID instead.`);let n=await _(o);if(!n.authenticated)throw new u("CLOUDFLARE_LOGIN_FAILED","Cloudflare login didn't complete",{rerun:`${c} login`});return t&&d(`Logged in to Cloudflare${n.email?` as ${n.email}`:""} ${f.green("\u2713")}`),n}async function D(o,t){let i="",n=!1;try{await o.run({plane:"account",mode:"text",timeoutMs:m,args:["auth","login","--no-browser"],onOutput:l=>{i+=l;let a=/please visit:\s*(https?:\/\/\S+)/i.exec(i)?.[1],e=/enter the code:\s*(\S+)/i.exec(i)?.[1];n||!a||!e||(n=!0,t({url:a,code:e}))}})}catch(l){throw new u("CLOUDFLARE_LOGIN_FAILED",l instanceof C?`Cloudflare login timed out after ${E(m)}
6
+ Or set CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID.`:`Cloudflare login didn't complete
7
+ ${h(l)}`,{retryable:!0,rerun:`${c} login`})}}async function P({whoami:o,flag:t,interactive:i}){let n=(o.accounts??[]).map(e=>({id:e.id,name:e.name??null})),l=e=>n.find(r=>r.id===e)??{id:e,name:null},a=t||process.env.CLOUDFLARE_ACCOUNT_ID||void 0;if(a){if(n.length>0&&!n.some(e=>e.id===a)){let e=Math.max(...n.map(r=>(r.name??r.id).length));throw new u("ACCOUNT_NOT_ACCESSIBLE",[`${o.email??"This login"} can't use Cloudflare account ${a}`,"Accounts this login can use:",...n.map(r=>` ${(r.name??r.id).padEnd(e)} ${r.id}`)].join(`
8
+ `),{rerun:`${c} login`,fix:"pass one of these with --account-id, or log in as someone else"})}return l(a)}if(n.length===1)return n[0];if(n.length===0)throw new u("ACCOUNT_REQUIRED",`This Cloudflare login can't list any accounts
9
+ The account id is in your dashboard URL: dash.cloudflare.com/<account-id>/\u2026`,{fix:"pass --account-id, or set CLOUDFLARE_ACCOUNT_ID"});if(!i)throw new s("choose_account",`Choose the Cloudflare account to install in
10
+ ${o.email??"This login"} can use ${n.length} accounts. Run one of:`,void 0,{rerun:null,data:{choices:n.map(e=>({accountId:e.id,accountName:e.name,label:e.name,rerun:g(["--account-id",e.id])}))}});return A("Which account should the Gateway go in?",n.map(e=>({label:e.name??e.id,value:e})),{context:[`${o.email??"This login"} can use ${n.length} Cloudflare accounts`]})}export{_ as a,x as b,F as c,S as d,w as e,P as f};