cloud.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import { WebhookEndpoint } from "pulumi-stripe"
  2. import { domain } from "./stage"
  3. import log from "../packages/web/dist/_worker.js/chunks/log_GHQSQ8rj.mjs"
  4. ////////////////
  5. // DATABASE
  6. ////////////////
  7. const cluster = planetscale.getDatabaseOutput({
  8. name: "opencode",
  9. organization: "anomalyco",
  10. })
  11. const branch =
  12. $app.stage === "production"
  13. ? planetscale.getBranchOutput({
  14. name: "production",
  15. organization: cluster.organization,
  16. database: cluster.name,
  17. })
  18. : new planetscale.Branch("DatabaseBranch", {
  19. database: cluster.name,
  20. organization: cluster.organization,
  21. name: $app.stage,
  22. parentBranch: "production",
  23. })
  24. const password = new planetscale.Password("DatabasePassword", {
  25. name: $app.stage,
  26. database: cluster.name,
  27. organization: cluster.organization,
  28. branch: branch.name,
  29. })
  30. export const database = new sst.Linkable("Database", {
  31. properties: {
  32. host: password.accessHostUrl,
  33. database: cluster.name,
  34. username: password.username,
  35. password: password.plaintext,
  36. port: 3306,
  37. },
  38. })
  39. new sst.x.DevCommand("Studio", {
  40. link: [database],
  41. dev: {
  42. command: "bun db studio",
  43. directory: "cloud/core",
  44. autostart: true,
  45. },
  46. })
  47. ////////////////
  48. // AUTH
  49. ////////////////
  50. const GITHUB_CLIENT_ID_CONSOLE = new sst.Secret("GITHUB_CLIENT_ID_CONSOLE")
  51. const GITHUB_CLIENT_SECRET_CONSOLE = new sst.Secret("GITHUB_CLIENT_SECRET_CONSOLE")
  52. const GOOGLE_CLIENT_ID = new sst.Secret("GOOGLE_CLIENT_ID")
  53. const authStorage = new sst.cloudflare.Kv("AuthStorage")
  54. export const auth = new sst.cloudflare.Worker("AuthApi", {
  55. domain: `auth.${domain}`,
  56. handler: "cloud/function/src/auth.ts",
  57. url: true,
  58. link: [database, authStorage, GITHUB_CLIENT_ID_CONSOLE, GITHUB_CLIENT_SECRET_CONSOLE, GOOGLE_CLIENT_ID],
  59. })
  60. ////////////////
  61. // GATEWAY
  62. ////////////////
  63. export const stripeWebhook = new WebhookEndpoint("StripeWebhookEndpoint", {
  64. url: $interpolate`https://${domain}/stripe/webhook`,
  65. enabledEvents: [
  66. "checkout.session.async_payment_failed",
  67. "checkout.session.async_payment_succeeded",
  68. "checkout.session.completed",
  69. "checkout.session.expired",
  70. "customer.created",
  71. "customer.deleted",
  72. "customer.updated",
  73. "customer.discount.created",
  74. "customer.discount.deleted",
  75. "customer.discount.updated",
  76. "customer.source.created",
  77. "customer.source.deleted",
  78. "customer.source.expiring",
  79. "customer.source.updated",
  80. "customer.subscription.created",
  81. "customer.subscription.deleted",
  82. "customer.subscription.paused",
  83. "customer.subscription.pending_update_applied",
  84. "customer.subscription.pending_update_expired",
  85. "customer.subscription.resumed",
  86. "customer.subscription.trial_will_end",
  87. "customer.subscription.updated",
  88. "customer.tax_id.created",
  89. "customer.tax_id.deleted",
  90. "customer.tax_id.updated",
  91. ],
  92. })
  93. const ANTHROPIC_API_KEY = new sst.Secret("ANTHROPIC_API_KEY")
  94. const XAI_API_KEY = new sst.Secret("XAI_API_KEY")
  95. const BASETEN_API_KEY = new sst.Secret("BASETEN_API_KEY")
  96. const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY")
  97. const HONEYCOMB_API_KEY = new sst.Secret("HONEYCOMB_API_KEY")
  98. const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
  99. properties: { value: auth.url.apply((url) => url!) },
  100. })
  101. const STRIPE_WEBHOOK_SECRET = new sst.Linkable("STRIPE_WEBHOOK_SECRET", {
  102. properties: { value: stripeWebhook.secret },
  103. })
  104. ////////////////
  105. // CONSOLE
  106. ////////////////
  107. let logProcessor
  108. if ($app.stage === "production" || $app.stage === "frank") {
  109. logProcessor = new sst.cloudflare.Worker("LogProcessor", {
  110. handler: "cloud/function/src/log-processor.ts",
  111. link: [HONEYCOMB_API_KEY],
  112. })
  113. }
  114. new sst.cloudflare.x.SolidStart("Console", {
  115. domain,
  116. path: "cloud/app",
  117. link: [
  118. database,
  119. AUTH_API_URL,
  120. STRIPE_WEBHOOK_SECRET,
  121. STRIPE_SECRET_KEY,
  122. ANTHROPIC_API_KEY,
  123. XAI_API_KEY,
  124. BASETEN_API_KEY,
  125. ],
  126. environment: {
  127. //VITE_DOCS_URL: web.url.apply((url) => url!),
  128. //VITE_API_URL: gateway.url.apply((url) => url!),
  129. VITE_AUTH_URL: auth.url.apply((url) => url!),
  130. },
  131. transform: {
  132. server: {
  133. transform: {
  134. worker: {
  135. placement: { mode: "smart" },
  136. tailConsumers: logProcessor ? [{ service: logProcessor.nodes.worker.scriptName }] : [],
  137. },
  138. },
  139. },
  140. },
  141. })