bunderstack 0.21.0 → 0.22.0

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 (137) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +24 -8
  3. package/dist/api/builder.d.ts +2 -2
  4. package/dist/api/builder.js +1 -1
  5. package/dist/api/builder.js.map +1 -1
  6. package/dist/api/context.d.ts +1 -1
  7. package/dist/api/context.d.ts.map +1 -1
  8. package/dist/api/context.js.map +1 -1
  9. package/dist/auth.d.ts +8 -0
  10. package/dist/auth.d.ts.map +1 -1
  11. package/dist/auth.js +14 -0
  12. package/dist/auth.js.map +1 -1
  13. package/dist/backend-internals.d.ts +32 -0
  14. package/dist/backend-internals.d.ts.map +1 -0
  15. package/dist/backend-internals.js +2 -0
  16. package/dist/backend-internals.js.map +1 -0
  17. package/dist/backend.d.ts +26 -0
  18. package/dist/backend.d.ts.map +1 -0
  19. package/dist/backend.js +53 -0
  20. package/dist/backend.js.map +1 -0
  21. package/dist/blueprint-generator.d.ts.map +1 -1
  22. package/dist/blueprint-generator.js +41 -51
  23. package/dist/blueprint-generator.js.map +1 -1
  24. package/dist/config.d.ts +0 -6
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js.map +1 -1
  27. package/dist/database/adapter.d.ts +10 -3
  28. package/dist/database/adapter.d.ts.map +1 -1
  29. package/dist/database/adapter.js.map +1 -1
  30. package/dist/database/bun-sql.d.ts.map +1 -1
  31. package/dist/database/bun-sql.js +1 -3
  32. package/dist/database/bun-sql.js.map +1 -1
  33. package/dist/database/bun-sqlite.d.ts +8 -0
  34. package/dist/database/bun-sqlite.d.ts.map +1 -0
  35. package/dist/database/bun-sqlite.js +56 -0
  36. package/dist/database/bun-sqlite.js.map +1 -0
  37. package/dist/database/libsql.d.ts.map +1 -1
  38. package/dist/database/libsql.js +25 -3
  39. package/dist/database/libsql.js.map +1 -1
  40. package/dist/database/pglite.d.ts.map +1 -1
  41. package/dist/database/pglite.js +25 -4
  42. package/dist/database/pglite.js.map +1 -1
  43. package/dist/database/postgres-js.d.ts.map +1 -1
  44. package/dist/database/postgres-js.js +1 -3
  45. package/dist/database/postgres-js.js.map +1 -1
  46. package/dist/db.d.ts +1 -2
  47. package/dist/db.d.ts.map +1 -1
  48. package/dist/db.js +5 -3
  49. package/dist/db.js.map +1 -1
  50. package/dist/email.d.ts +3 -1
  51. package/dist/email.d.ts.map +1 -1
  52. package/dist/email.js +9 -2
  53. package/dist/email.js.map +1 -1
  54. package/dist/env.d.ts +1 -1
  55. package/dist/env.d.ts.map +1 -1
  56. package/dist/env.js +1 -4
  57. package/dist/env.js.map +1 -1
  58. package/dist/index.d.ts +3 -108
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +1 -484
  61. package/dist/index.js.map +1 -1
  62. package/dist/jobs/define.d.ts +1 -1
  63. package/dist/jobs/define.d.ts.map +1 -1
  64. package/dist/jobs/define.js.map +1 -1
  65. package/dist/jobs/index.js +1 -1
  66. package/dist/jobs/index.js.map +1 -1
  67. package/dist/jobs/queue.d.ts +1 -1
  68. package/dist/jobs/queue.d.ts.map +1 -1
  69. package/dist/jobs/queue.js +1 -2
  70. package/dist/jobs/queue.js.map +1 -1
  71. package/dist/jobs/worker.d.ts +9 -0
  72. package/dist/jobs/worker.d.ts.map +1 -1
  73. package/dist/jobs/worker.js +32 -3
  74. package/dist/jobs/worker.js.map +1 -1
  75. package/dist/provision-internals.d.ts +1 -1
  76. package/dist/provision-internals.js +1 -1
  77. package/dist/provision-internals.js.map +1 -1
  78. package/dist/provision.d.ts +2 -0
  79. package/dist/provision.d.ts.map +1 -1
  80. package/dist/provision.js +24 -3
  81. package/dist/provision.js.map +1 -1
  82. package/dist/query/infer.d.ts +1 -1
  83. package/dist/query/infer.d.ts.map +1 -1
  84. package/dist/query/infer.js.map +1 -1
  85. package/dist/runtime.d.ts +149 -0
  86. package/dist/runtime.d.ts.map +1 -0
  87. package/dist/runtime.js +522 -0
  88. package/dist/runtime.js.map +1 -0
  89. package/dist/schema-export-pg.js +1 -1
  90. package/dist/schema-export-pg.js.map +1 -1
  91. package/dist/start/index.d.ts +3 -3
  92. package/dist/start/index.d.ts.map +1 -1
  93. package/dist/start/index.js +3 -3
  94. package/dist/start/index.js.map +1 -1
  95. package/dist/storage/background.d.ts +3 -0
  96. package/dist/storage/background.d.ts.map +1 -0
  97. package/dist/storage/background.js +3 -0
  98. package/dist/storage/background.js.map +1 -0
  99. package/dist/testing/auth.d.ts +57 -0
  100. package/dist/testing/auth.d.ts.map +1 -0
  101. package/dist/testing/auth.js +51 -0
  102. package/dist/testing/auth.js.map +1 -0
  103. package/dist/testing/client.d.ts +6 -0
  104. package/dist/testing/client.d.ts.map +1 -0
  105. package/dist/testing/client.js +9 -0
  106. package/dist/testing/client.js.map +1 -0
  107. package/dist/testing/database.d.ts +6 -0
  108. package/dist/testing/database.d.ts.map +1 -0
  109. package/dist/testing/database.js +8 -0
  110. package/dist/testing/database.js.map +1 -0
  111. package/dist/testing/email.d.ts +15 -0
  112. package/dist/testing/email.d.ts.map +1 -0
  113. package/dist/testing/email.js +32 -0
  114. package/dist/testing/email.js.map +1 -0
  115. package/dist/testing/fixture.d.ts +33 -0
  116. package/dist/testing/fixture.d.ts.map +1 -0
  117. package/dist/testing/fixture.js +125 -0
  118. package/dist/testing/fixture.js.map +1 -0
  119. package/dist/testing/jobs.d.ts +32 -0
  120. package/dist/testing/jobs.d.ts.map +1 -0
  121. package/dist/testing/jobs.js +67 -0
  122. package/dist/testing/jobs.js.map +1 -0
  123. package/dist/testing/storage.d.ts +7 -0
  124. package/dist/testing/storage.d.ts.map +1 -0
  125. package/dist/testing/storage.js +29 -0
  126. package/dist/testing/storage.js.map +1 -0
  127. package/dist/testing.d.ts +9 -26
  128. package/dist/testing.d.ts.map +1 -1
  129. package/dist/testing.js +3 -9
  130. package/dist/testing.js.map +1 -1
  131. package/llms.txt +43 -13
  132. package/package.json +23 -15
  133. package/skills/creating-bunderstack-apps/references/application-structure.md +16 -12
  134. package/skills/creating-bunderstack-apps/references/runtime-integrations.md +4 -1
  135. package/skills/migrating-to-bunderstack/SKILL.md +7 -6
  136. package/skills/migrating-to-bunderstack/references/audit-checklist.md +4 -4
  137. package/skills/migrating-to-bunderstack/references/runtime-replacements.md +55 -49
package/dist/email.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/email.ts — email sending: console / resend / custom adapters.
2
- // SMTP is provided by the static `bunderstack/email/smtp` factory subpath.
2
+ // SMTP is provided by the static `bunderstack/email-smtp` factory subpath.
3
3
  import { and, eq } from 'drizzle-orm';
4
4
  import { emailsTableFor } from './internal-tables.js';
5
5
  /** Root string provider tag ('resend' | 'console') or undefined. */
@@ -56,6 +56,13 @@ function createResendAdapter(apiKey, fetchFn) {
56
56
  };
57
57
  }
58
58
  function resolveAdapter(config, opts) {
59
+ if (opts.adapterOverride) {
60
+ return {
61
+ adapter: opts.adapterOverride,
62
+ provider: 'capture',
63
+ capture: true,
64
+ };
65
+ }
59
66
  const managedProvider = opts.env.BUNDERSTACK_EMAIL_PROVIDER;
60
67
  const provider = managedProvider === 'resend' ? 'resend' : config.provider;
61
68
  if (typeof provider === 'function') {
@@ -88,7 +95,7 @@ function resolveAdapter(config, opts) {
88
95
  };
89
96
  default:
90
97
  if (provider === 'smtp') {
91
- throw new Error("email provider 'smtp' was removed. Import `smtp` from 'bunderstack/email/smtp' instead.");
98
+ throw new Error("email provider 'smtp' was removed. Import `smtp` from 'bunderstack/email-smtp' instead.");
92
99
  }
93
100
  return {
94
101
  adapter: createConsoleAdapter(),
package/dist/email.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"email.js","sourceRoot":"","sources":["../src/email.ts"],"names":[],"mappings":"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","sourcesContent":["// src/email.ts — email sending: console / resend / custom adapters.\n// SMTP is provided by the static `bunderstack/email/smtp` factory subpath.\n\nimport { and, eq } from 'drizzle-orm'\n\nimport type { AnyDb } from './dialect'\n\nimport { emailsTableFor } from './internal-tables'\n\nexport type EmailMessage = {\n to: string | string[]\n subject: string\n html?: string\n text?: string\n from?: string\n replyTo?: string\n cc?: string | string[]\n bcc?: string | string[]\n}\n\nexport type SentEmail = { id?: string; providerId?: string }\n\ntype AdapterSentEmail = { id?: string }\n\n/** Adapters receive the message with `from` already resolved. */\nexport type EmailAdapter = {\n send(msg: EmailMessage & { from: string }): Promise<AdapterSentEmail>\n}\n\nexport type EmailConfigInput = {\n from: string\n provider?: 'resend' | 'console' | EmailAdapter | EmailAdapter['send']\n}\n\nexport type EmailFacade = {\n send(msg: EmailMessage): Promise<SentEmail>\n}\n\nexport type CreateEmailOptions = {\n env: {\n RESEND_API_KEY?: string\n SMTP_URL?: string\n NODE_ENV?: string\n BUNDERSTACK_EMAIL_PROVIDER?: string\n BUNDERSTACK_EMAIL_FROM?: string\n BUNDERHOST_ENVIRONMENT_ID?: string\n }\n /** Internal application db. Present when created through createBunderstack. */\n db?: AnyDb\n /** Test seam for the resend adapter. */\n fetchFn?: typeof fetch\n}\n\n/** Root string provider tag ('resend' | 'console') or undefined. */\nexport function emailProviderTag(\n config: EmailConfigInput | undefined,\n): string | undefined {\n return typeof config?.provider === 'string' ? config.provider : undefined\n}\n\nconst toArray = (v: string | string[] | undefined) =>\n v === undefined ? undefined : Array.isArray(v) ? v : [v]\n\nfunction createConsoleAdapter(): EmailAdapter {\n return {\n async send(msg) {\n const line = '─'.repeat(60)\n console.log(\n [\n line,\n '📧 email (console provider — not sent)',\n `from: ${msg.from}`,\n `to: ${toArray(msg.to)!.join(', ')}`,\n `subject: ${msg.subject}`,\n line,\n msg.text ?? msg.html ?? '',\n line,\n ].join('\\n'),\n )\n return { id: '' }\n },\n }\n}\n\nconst captureAdapter: EmailAdapter = { send: async () => ({}) }\n\nfunction createResendAdapter(\n apiKey: string,\n fetchFn: typeof fetch,\n): EmailAdapter {\n return {\n async send(msg) {\n const res = await fetchFn('https://api.resend.com/emails', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n from: msg.from,\n to: toArray(msg.to),\n subject: msg.subject,\n html: msg.html,\n text: msg.text,\n reply_to: msg.replyTo,\n cc: toArray(msg.cc),\n bcc: toArray(msg.bcc),\n tags: (msg as EmailMessage & { tags?: unknown }).tags,\n }),\n })\n if (!res.ok) {\n throw new Error(`resend API error (${res.status}): ${await res.text()}`)\n }\n const data = (await res.json()) as { id?: string }\n return { id: data.id ?? '' }\n },\n }\n}\n\nfunction resolveAdapter(\n config: EmailConfigInput,\n opts: CreateEmailOptions,\n): { adapter: EmailAdapter; provider: string; capture: boolean } {\n const managedProvider = opts.env.BUNDERSTACK_EMAIL_PROVIDER\n const provider = managedProvider === 'resend' ? 'resend' : config.provider\n if (typeof provider === 'function') {\n return { adapter: { send: provider }, provider: 'custom', capture: false }\n }\n if (typeof provider === 'object') {\n return { adapter: provider, provider: 'custom', capture: false }\n }\n const fetchFn = opts.fetchFn ?? globalThis.fetch.bind(globalThis)\n switch (provider) {\n case 'resend':\n return {\n adapter: createResendAdapter(opts.env.RESEND_API_KEY ?? '', fetchFn),\n provider: 'resend',\n capture: false,\n }\n\n case 'console':\n return {\n adapter: createConsoleAdapter(),\n provider: 'capture',\n capture: true,\n }\n case undefined:\n return {\n adapter:\n opts.env.NODE_ENV === 'production'\n ? captureAdapter\n : createConsoleAdapter(),\n provider: 'capture',\n capture: true,\n }\n default:\n if (provider === 'smtp') {\n throw new Error(\n \"email provider 'smtp' was removed. Import `smtp` from 'bunderstack/email/smtp' instead.\",\n )\n }\n return {\n adapter: createConsoleAdapter(),\n provider: 'capture',\n capture: true,\n }\n }\n}\n\nasync function insertJournal(\n db: AnyDb | undefined,\n value: Record<string, unknown>,\n) {\n if (!db) return\n const table = emailsTableFor(db)\n await db.insert(table).values(value)\n}\n\nasync function updateJournal(\n db: AnyDb | undefined,\n id: string,\n value: Record<string, unknown>,\n expectedStatus?: string,\n) {\n if (!db) return\n const table = emailsTableFor(db)\n await db\n .update(table)\n .set(value)\n .where(\n expectedStatus\n ? and(eq(table.id, id), eq(table.status, expectedStatus))\n : eq(table.id, id),\n )\n}\n\nexport function createEmail(\n config: EmailConfigInput | undefined,\n opts: CreateEmailOptions,\n): EmailFacade {\n if (!config) {\n return {\n async send() {\n throw new Error(\n 'email is not configured — add an email key to your bunderstack config',\n )\n },\n }\n }\n const resolved = resolveAdapter(config, opts)\n return {\n async send(msg) {\n if (!msg.html && !msg.text) {\n throw new Error('email message needs html or text content')\n }\n const id = `email_${crypto.randomUUID()}`\n const now = Date.now()\n const from = opts.env.BUNDERSTACK_EMAIL_FROM ?? msg.from ?? config.from\n await insertJournal(opts.db, {\n id,\n provider: resolved.provider,\n status: resolved.capture ? 'captured' : 'sending',\n from,\n toJson: JSON.stringify(toArray(msg.to) ?? []),\n ccJson: JSON.stringify(toArray(msg.cc) ?? []),\n bccJson: JSON.stringify(toArray(msg.bcc) ?? []),\n replyTo: msg.replyTo,\n subject: msg.subject,\n html: msg.html,\n text: msg.text,\n createdAt: now,\n updatedAt: now,\n })\n if (resolved.capture) {\n await resolved.adapter.send({ ...msg, from })\n return { id }\n }\n try {\n const tags = [\n { name: 'bunderstack_email_id', value: id },\n ...(opts.env.BUNDERHOST_ENVIRONMENT_ID\n ? [\n {\n name: 'bunderhost_environment_id',\n value: opts.env.BUNDERHOST_ENVIRONMENT_ID,\n },\n ]\n : []),\n ]\n const sent = await resolved.adapter.send({\n ...msg,\n from,\n tags,\n } as EmailMessage & {\n from: string\n })\n await updateJournal(\n opts.db,\n id,\n {\n providerId: sent.id || undefined,\n status: 'sent',\n updatedAt: Date.now(),\n },\n 'sending',\n )\n return { id, providerId: sent.id || undefined }\n } catch (error) {\n await updateJournal(\n opts.db,\n id,\n {\n status: 'failed',\n error: error instanceof Error ? error.message : String(error),\n updatedAt: Date.now(),\n },\n 'sending',\n )\n throw error\n }\n },\n }\n}\n"]}
1
+ {"version":3,"file":"email.js","sourceRoot":"","sources":["../src/email.ts"],"names":[],"mappings":"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","sourcesContent":["// src/email.ts — email sending: console / resend / custom adapters.\n// SMTP is provided by the static `bunderstack/email-smtp` factory subpath.\n\nimport { and, eq } from 'drizzle-orm'\n\nimport type { AnyDb } from './dialect'\n\nimport { emailsTableFor } from './internal-tables'\n\nexport type EmailMessage = {\n to: string | string[]\n subject: string\n html?: string\n text?: string\n from?: string\n replyTo?: string\n cc?: string | string[]\n bcc?: string | string[]\n}\n\nexport type SentEmail = { id?: string; providerId?: string }\n\ntype AdapterSentEmail = { id?: string }\n\n/** Adapters receive the message with `from` already resolved. */\nexport type EmailAdapter = {\n send(msg: EmailMessage & { from: string }): Promise<AdapterSentEmail>\n}\n\nexport type EmailConfigInput = {\n from: string\n provider?: 'resend' | 'console' | EmailAdapter | EmailAdapter['send']\n}\n\nexport type EmailFacade = {\n send(msg: EmailMessage): Promise<SentEmail>\n}\n\nexport type CreateEmailOptions = {\n env: {\n RESEND_API_KEY?: string\n SMTP_URL?: string\n NODE_ENV?: string\n BUNDERSTACK_EMAIL_PROVIDER?: string\n BUNDERSTACK_EMAIL_FROM?: string\n BUNDERHOST_ENVIRONMENT_ID?: string\n }\n /** Internal application db. Present when created through bunderstack. */\n db?: AnyDb\n /** Test seam for the resend adapter. */\n fetchFn?: typeof fetch\n /** Internal runtime substitution used by isolated test fixtures. */\n adapterOverride?: EmailAdapter\n}\n\n/** Root string provider tag ('resend' | 'console') or undefined. */\nexport function emailProviderTag(\n config: EmailConfigInput | undefined,\n): string | undefined {\n return typeof config?.provider === 'string' ? config.provider : undefined\n}\n\nconst toArray = (v: string | string[] | undefined) =>\n v === undefined ? undefined : Array.isArray(v) ? v : [v]\n\nfunction createConsoleAdapter(): EmailAdapter {\n return {\n async send(msg) {\n const line = '─'.repeat(60)\n console.log(\n [\n line,\n '📧 email (console provider — not sent)',\n `from: ${msg.from}`,\n `to: ${toArray(msg.to)!.join(', ')}`,\n `subject: ${msg.subject}`,\n line,\n msg.text ?? msg.html ?? '',\n line,\n ].join('\\n'),\n )\n return { id: '' }\n },\n }\n}\n\nconst captureAdapter: EmailAdapter = { send: async () => ({}) }\n\nfunction createResendAdapter(\n apiKey: string,\n fetchFn: typeof fetch,\n): EmailAdapter {\n return {\n async send(msg) {\n const res = await fetchFn('https://api.resend.com/emails', {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n from: msg.from,\n to: toArray(msg.to),\n subject: msg.subject,\n html: msg.html,\n text: msg.text,\n reply_to: msg.replyTo,\n cc: toArray(msg.cc),\n bcc: toArray(msg.bcc),\n tags: (msg as EmailMessage & { tags?: unknown }).tags,\n }),\n })\n if (!res.ok) {\n throw new Error(`resend API error (${res.status}): ${await res.text()}`)\n }\n const data = (await res.json()) as { id?: string }\n return { id: data.id ?? '' }\n },\n }\n}\n\nfunction resolveAdapter(\n config: EmailConfigInput,\n opts: CreateEmailOptions,\n): { adapter: EmailAdapter; provider: string; capture: boolean } {\n if (opts.adapterOverride) {\n return {\n adapter: opts.adapterOverride,\n provider: 'capture',\n capture: true,\n }\n }\n const managedProvider = opts.env.BUNDERSTACK_EMAIL_PROVIDER\n const provider = managedProvider === 'resend' ? 'resend' : config.provider\n if (typeof provider === 'function') {\n return { adapter: { send: provider }, provider: 'custom', capture: false }\n }\n if (typeof provider === 'object') {\n return { adapter: provider, provider: 'custom', capture: false }\n }\n const fetchFn = opts.fetchFn ?? globalThis.fetch.bind(globalThis)\n switch (provider) {\n case 'resend':\n return {\n adapter: createResendAdapter(opts.env.RESEND_API_KEY ?? '', fetchFn),\n provider: 'resend',\n capture: false,\n }\n\n case 'console':\n return {\n adapter: createConsoleAdapter(),\n provider: 'capture',\n capture: true,\n }\n case undefined:\n return {\n adapter:\n opts.env.NODE_ENV === 'production'\n ? captureAdapter\n : createConsoleAdapter(),\n provider: 'capture',\n capture: true,\n }\n default:\n if (provider === 'smtp') {\n throw new Error(\n \"email provider 'smtp' was removed. Import `smtp` from 'bunderstack/email-smtp' instead.\",\n )\n }\n return {\n adapter: createConsoleAdapter(),\n provider: 'capture',\n capture: true,\n }\n }\n}\n\nasync function insertJournal(\n db: AnyDb | undefined,\n value: Record<string, unknown>,\n) {\n if (!db) return\n const table = emailsTableFor(db)\n await db.insert(table).values(value)\n}\n\nasync function updateJournal(\n db: AnyDb | undefined,\n id: string,\n value: Record<string, unknown>,\n expectedStatus?: string,\n) {\n if (!db) return\n const table = emailsTableFor(db)\n await db\n .update(table)\n .set(value)\n .where(\n expectedStatus\n ? and(eq(table.id, id), eq(table.status, expectedStatus))\n : eq(table.id, id),\n )\n}\n\nexport function createEmail(\n config: EmailConfigInput | undefined,\n opts: CreateEmailOptions,\n): EmailFacade {\n if (!config) {\n return {\n async send() {\n throw new Error(\n 'email is not configured — add an email key to your bunderstack config',\n )\n },\n }\n }\n const resolved = resolveAdapter(config, opts)\n return {\n async send(msg) {\n if (!msg.html && !msg.text) {\n throw new Error('email message needs html or text content')\n }\n const id = `email_${crypto.randomUUID()}`\n const now = Date.now()\n const from = opts.env.BUNDERSTACK_EMAIL_FROM ?? msg.from ?? config.from\n await insertJournal(opts.db, {\n id,\n provider: resolved.provider,\n status: resolved.capture ? 'captured' : 'sending',\n from,\n toJson: JSON.stringify(toArray(msg.to) ?? []),\n ccJson: JSON.stringify(toArray(msg.cc) ?? []),\n bccJson: JSON.stringify(toArray(msg.bcc) ?? []),\n replyTo: msg.replyTo,\n subject: msg.subject,\n html: msg.html,\n text: msg.text,\n createdAt: now,\n updatedAt: now,\n })\n if (resolved.capture) {\n await resolved.adapter.send({ ...msg, from })\n return { id }\n }\n try {\n const tags = [\n { name: 'bunderstack_email_id', value: id },\n ...(opts.env.BUNDERHOST_ENVIRONMENT_ID\n ? [\n {\n name: 'bunderhost_environment_id',\n value: opts.env.BUNDERHOST_ENVIRONMENT_ID,\n },\n ]\n : []),\n ]\n const sent = await resolved.adapter.send({\n ...msg,\n from,\n tags,\n } as EmailMessage & {\n from: string\n })\n await updateJournal(\n opts.db,\n id,\n {\n providerId: sent.id || undefined,\n status: 'sent',\n updatedAt: Date.now(),\n },\n 'sending',\n )\n return { id, providerId: sent.id || undefined }\n } catch (error) {\n await updateJournal(\n opts.db,\n id,\n {\n status: 'failed',\n error: error instanceof Error ? error.message : String(error),\n updatedAt: Date.now(),\n },\n 'sending',\n )\n throw error\n }\n },\n }\n}\n"]}
package/dist/env.d.ts CHANGED
@@ -36,7 +36,7 @@ export type ValidateEnvOptions = {
36
36
  emailProvider?: string;
37
37
  /** Value source; defaults to process.env. Tests pass this explicitly. */
38
38
  source?: Record<string, string | undefined>;
39
- /** Dialect-aware DATABASE_URL fallback; createBunderstack passes it. */
39
+ /** Dialect-aware DATABASE_URL fallback; bunderstack passes it. */
40
40
  defaultDatabaseUrl?: string;
41
41
  };
42
42
  export declare function validateEnv<TEnv extends EnvConfigInput | undefined>(envConfig: TEnv, options?: ValidateEnvOptions): ValidatedEnv<TEnv>;
package/dist/env.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAO7D,eAAO,MAAM,aAAa,EAAG,SAAkB,CAAA;AAE/C,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;IACzC,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAA;AAItD,0DAA0D;AAC1D,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0BAA0B,CAAC,EAAE,MAAM,CAAA;IACnC,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC,gBAAgB,EAAE,eAAe,CAAA;CAClC,CAAA;AAED,KAAK,SAAS,CAAC,CAAC,IACd,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GACtC;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GACtD,OAAO,CAAA;AAGb,MAAM,MAAM,YAAY,CAAC,IAAI,SAAS,cAAc,GAAG,SAAS,IAAI;IAClE,IAAI;CACL,SAAS,CAAC,cAAc,CAAC,GACtB,OAAO,GACL,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,GACtC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,GACxC,OAAO,CAAA;AAEX,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;gBAEb,MAAM,EAAE,MAAM,EAAE;CAK7B;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IAC3C,wEAAwE;IACxE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B,CAAA;AAqCD,wBAAgB,WAAW,CAAC,IAAI,SAAS,cAAc,GAAG,SAAS,EACjE,SAAS,EAAE,IAAI,EACf,OAAO,GAAE,kBAAuB,GAC/B,YAAY,CAAC,IAAI,CAAC,CA+CpB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,SAAS,cAAc,EACzD,SAAS,EAAE,IAAI,GACd,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAsB3B"}
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAO7D,eAAO,MAAM,aAAa,EAAG,SAAkB,CAAA;AAE/C,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;IACzC,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACrC,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAA;AAItD,0DAA0D;AAC1D,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0BAA0B,CAAC,EAAE,MAAM,CAAA;IACnC,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC,gBAAgB,EAAE,eAAe,CAAA;CAClC,CAAA;AAED,KAAK,SAAS,CAAC,CAAC,IACd,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GACtC;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GACtD,OAAO,CAAA;AAGb,MAAM,MAAM,YAAY,CAAC,IAAI,SAAS,cAAc,GAAG,SAAS,IAAI;IAClE,IAAI;CACL,SAAS,CAAC,cAAc,CAAC,GACtB,OAAO,GACL,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,GACtC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,GACxC,OAAO,CAAA;AAEX,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAA;gBAEb,MAAM,EAAE,MAAM,EAAE;CAK7B;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IAC3C,kEAAkE;IAClE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B,CAAA;AAqCD,wBAAgB,WAAW,CAAC,IAAI,SAAS,cAAc,GAAG,SAAS,EACjE,SAAS,EAAE,IAAI,EACf,OAAO,GAAE,kBAAuB,GAC/B,YAAY,CAAC,IAAI,CAAC,CA4CpB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,SAAS,cAAc,EACzD,SAAS,EAAE,IAAI,GACd,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAsB3B"}
package/dist/env.js CHANGED
@@ -67,10 +67,7 @@ export function validateEnv(envConfig, options = {}) {
67
67
  const userVars = {};
68
68
  validateSection(envConfig?.server, 'server', source, issues, userVars);
69
69
  validateSection(envConfig?.client, 'client', source, issues, userVars);
70
- // Introspection (Bunderhost builder) imports the app declaration to read
71
- // its manifest; missing user env must not kill the boot there.
72
- const lenient = source.BUNDERSTACK_INTROSPECT === '1';
73
- if (issues.length > 0 && !lenient)
70
+ if (issues.length > 0)
74
71
  throw new BunderstackEnvError(issues);
75
72
  return { ...base, ...userVars };
76
73
  }
package/dist/env.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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","sourcesContent":["// src/env.ts — env validation. Browser-safe: type-only Standard Schema import.\nimport type { StandardSchemaV1 } from '@standard-schema/spec'\n\nimport {\n StandardSchemaValidationError,\n validateStandardSchema,\n} from './standard-schema'\n\nexport const CLIENT_PREFIX = 'PUBLIC_' as const\n\nexport type EnvConfigInput = {\n server?: Record<string, StandardSchemaV1>\n client?: Record<string, StandardSchemaV1>\n /** Explicit value source for client vars (e.g. Vite's import.meta.env). */\n runtimeEnv?: Record<string, unknown>\n}\n\nexport type BunderstackRole = 'all' | 'web' | 'worker'\n\nconst ROLES: readonly BunderstackRole[] = ['all', 'web', 'worker']\n\n/** Vars bunderstack itself consumes, always validated. */\nexport type BaseEnv = {\n NODE_ENV?: string\n DATABASE_URL: string\n DATABASE_AUTH_TOKEN?: string\n AUTH_SECRET: string\n REDIS_URL?: string\n RESEND_API_KEY?: string\n SMTP_URL?: string\n BUNDERSTACK_EMAIL_PROVIDER?: string\n BUNDERSTACK_EMAIL_FROM?: string\n BUNDERHOST_ENVIRONMENT_ID?: string\n BUNDERSTACK_ROLE: BunderstackRole\n}\n\ntype InferVars<T> =\n T extends Record<string, StandardSchemaV1>\n ? { [K in keyof T]: StandardSchemaV1.InferOutput<T[K]> }\n : unknown\n\n// Non-distributive so `ValidatedEnv<undefined>` is BaseEnv, not `never`.\nexport type ValidatedEnv<TEnv extends EnvConfigInput | undefined> = [\n TEnv,\n] extends [EnvConfigInput]\n ? BaseEnv &\n InferVars<NonNullable<TEnv>['server']> &\n InferVars<NonNullable<TEnv>['client']>\n : BaseEnv\n\nexport class BunderstackEnvError extends Error {\n readonly issues: string[]\n\n constructor(issues: string[]) {\n super(`Invalid environment:\\n - ${issues.join('\\n - ')}`)\n this.name = 'BunderstackEnvError'\n this.issues = issues\n }\n}\n\nexport type ValidateEnvOptions = {\n /** String tag of the configured email provider ('resend' | 'smtp'), if any. */\n emailProvider?: string\n /** Value source; defaults to process.env. Tests pass this explicitly. */\n source?: Record<string, string | undefined>\n /** Dialect-aware DATABASE_URL fallback; createBunderstack passes it. */\n defaultDatabaseUrl?: string\n}\n\nconst DEV_AUTH_SECRET = 'dev-secret-change-in-prod'\n\nfunction validateSection(\n section: Record<string, StandardSchemaV1> | undefined,\n kind: 'server' | 'client',\n source: Record<string, unknown>,\n issues: string[],\n out: Record<string, unknown>,\n) {\n for (const [key, schema] of Object.entries(section ?? {})) {\n const isPublic = key.startsWith(CLIENT_PREFIX)\n if (kind === 'server' && isPublic) {\n issues.push(\n `${key}: server vars must not start with ${CLIENT_PREFIX} (move it to env.client)`,\n )\n continue\n }\n if (kind === 'client' && !isPublic) {\n issues.push(\n `${key}: client vars must start with ${CLIENT_PREFIX} (rename it or move it to env.server)`,\n )\n continue\n }\n try {\n out[key] = validateStandardSchema(schema, source[key], 'env')\n } catch (error) {\n if (!(error instanceof StandardSchemaValidationError)) throw error\n for (const issue of error.issues) {\n const path = issue.path.map(String).join('.')\n issues.push(`${key}${path ? `.${path}` : ''}: ${issue.message}`)\n }\n }\n }\n}\n\nexport function validateEnv<TEnv extends EnvConfigInput | undefined>(\n envConfig: TEnv,\n options: ValidateEnvOptions = {},\n): ValidatedEnv<TEnv> {\n const source =\n options.source ?? (process.env as Record<string, string | undefined>)\n const issues: string[] = []\n const isProduction = source.NODE_ENV === 'production'\n\n const base: BaseEnv = {\n NODE_ENV: source.NODE_ENV,\n DATABASE_URL:\n source.DATABASE_URL ?? options.defaultDatabaseUrl ?? 'file:./data.db',\n DATABASE_AUTH_TOKEN: source.DATABASE_AUTH_TOKEN,\n AUTH_SECRET: source.AUTH_SECRET ?? DEV_AUTH_SECRET,\n REDIS_URL: source.REDIS_URL,\n RESEND_API_KEY: source.RESEND_API_KEY,\n SMTP_URL: source.SMTP_URL,\n BUNDERSTACK_EMAIL_PROVIDER: source.BUNDERSTACK_EMAIL_PROVIDER,\n BUNDERSTACK_EMAIL_FROM: source.BUNDERSTACK_EMAIL_FROM,\n BUNDERHOST_ENVIRONMENT_ID: source.BUNDERHOST_ENVIRONMENT_ID,\n BUNDERSTACK_ROLE: (source.BUNDERSTACK_ROLE ?? 'all') as BunderstackRole,\n }\n if (isProduction && !source.AUTH_SECRET) {\n issues.push('AUTH_SECRET: required in production')\n }\n if (\n source.BUNDERSTACK_ROLE !== undefined &&\n !ROLES.includes(source.BUNDERSTACK_ROLE as BunderstackRole)\n ) {\n issues.push(\n `BUNDERSTACK_ROLE: must be one of ${ROLES.join(', ')} (got \"${String(source.BUNDERSTACK_ROLE)}\")`,\n )\n }\n if (options.emailProvider === 'resend' && !source.RESEND_API_KEY) {\n issues.push(\"RESEND_API_KEY: required when email provider is 'resend'\")\n }\n if (options.emailProvider === 'smtp' && !source.SMTP_URL) {\n issues.push(\"SMTP_URL: required when email provider is 'smtp'\")\n }\n\n const userVars: Record<string, unknown> = {}\n validateSection(envConfig?.server, 'server', source, issues, userVars)\n validateSection(envConfig?.client, 'client', source, issues, userVars)\n\n // Introspection (Bunderhost builder) imports the app declaration to read\n // its manifest; missing user env must not kill the boot there.\n const lenient = source.BUNDERSTACK_INTROSPECT === '1'\n if (issues.length > 0 && !lenient) throw new BunderstackEnvError(issues)\n return { ...base, ...userVars } as ValidatedEnv<TEnv>\n}\n\n/**\n * Browser-side companion (t3-env style): validates ONLY the client section.\n * Server keys exist on the returned object as traps that throw on access, so\n * a leaked import fails loudly instead of silently reading undefined.\n */\nexport function createClientEnv<TEnv extends EnvConfigInput>(\n envConfig: TEnv,\n): InferVars<TEnv['client']> {\n const source =\n envConfig.runtimeEnv ??\n (typeof process !== 'undefined'\n ? (process.env as Record<string, unknown>)\n : {})\n const issues: string[] = []\n const values: Record<string, unknown> = {}\n validateSection(envConfig.client, 'client', source, issues, values)\n if (issues.length > 0) throw new BunderstackEnvError(issues)\n\n const serverKeys = new Set(Object.keys(envConfig.server ?? {}))\n return new Proxy(values, {\n get(target, prop) {\n if (typeof prop === 'string' && serverKeys.has(prop)) {\n throw new Error(\n `${prop} is server-only and not available in client env`,\n )\n }\n return Reflect.get(target, prop)\n },\n }) as InferVars<TEnv['client']>\n}\n"]}
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"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","sourcesContent":["// src/env.ts — env validation. Browser-safe: type-only Standard Schema import.\nimport type { StandardSchemaV1 } from '@standard-schema/spec'\n\nimport {\n StandardSchemaValidationError,\n validateStandardSchema,\n} from './standard-schema'\n\nexport const CLIENT_PREFIX = 'PUBLIC_' as const\n\nexport type EnvConfigInput = {\n server?: Record<string, StandardSchemaV1>\n client?: Record<string, StandardSchemaV1>\n /** Explicit value source for client vars (e.g. Vite's import.meta.env). */\n runtimeEnv?: Record<string, unknown>\n}\n\nexport type BunderstackRole = 'all' | 'web' | 'worker'\n\nconst ROLES: readonly BunderstackRole[] = ['all', 'web', 'worker']\n\n/** Vars bunderstack itself consumes, always validated. */\nexport type BaseEnv = {\n NODE_ENV?: string\n DATABASE_URL: string\n DATABASE_AUTH_TOKEN?: string\n AUTH_SECRET: string\n REDIS_URL?: string\n RESEND_API_KEY?: string\n SMTP_URL?: string\n BUNDERSTACK_EMAIL_PROVIDER?: string\n BUNDERSTACK_EMAIL_FROM?: string\n BUNDERHOST_ENVIRONMENT_ID?: string\n BUNDERSTACK_ROLE: BunderstackRole\n}\n\ntype InferVars<T> =\n T extends Record<string, StandardSchemaV1>\n ? { [K in keyof T]: StandardSchemaV1.InferOutput<T[K]> }\n : unknown\n\n// Non-distributive so `ValidatedEnv<undefined>` is BaseEnv, not `never`.\nexport type ValidatedEnv<TEnv extends EnvConfigInput | undefined> = [\n TEnv,\n] extends [EnvConfigInput]\n ? BaseEnv &\n InferVars<NonNullable<TEnv>['server']> &\n InferVars<NonNullable<TEnv>['client']>\n : BaseEnv\n\nexport class BunderstackEnvError extends Error {\n readonly issues: string[]\n\n constructor(issues: string[]) {\n super(`Invalid environment:\\n - ${issues.join('\\n - ')}`)\n this.name = 'BunderstackEnvError'\n this.issues = issues\n }\n}\n\nexport type ValidateEnvOptions = {\n /** String tag of the configured email provider ('resend' | 'smtp'), if any. */\n emailProvider?: string\n /** Value source; defaults to process.env. Tests pass this explicitly. */\n source?: Record<string, string | undefined>\n /** Dialect-aware DATABASE_URL fallback; bunderstack passes it. */\n defaultDatabaseUrl?: string\n}\n\nconst DEV_AUTH_SECRET = 'dev-secret-change-in-prod'\n\nfunction validateSection(\n section: Record<string, StandardSchemaV1> | undefined,\n kind: 'server' | 'client',\n source: Record<string, unknown>,\n issues: string[],\n out: Record<string, unknown>,\n) {\n for (const [key, schema] of Object.entries(section ?? {})) {\n const isPublic = key.startsWith(CLIENT_PREFIX)\n if (kind === 'server' && isPublic) {\n issues.push(\n `${key}: server vars must not start with ${CLIENT_PREFIX} (move it to env.client)`,\n )\n continue\n }\n if (kind === 'client' && !isPublic) {\n issues.push(\n `${key}: client vars must start with ${CLIENT_PREFIX} (rename it or move it to env.server)`,\n )\n continue\n }\n try {\n out[key] = validateStandardSchema(schema, source[key], 'env')\n } catch (error) {\n if (!(error instanceof StandardSchemaValidationError)) throw error\n for (const issue of error.issues) {\n const path = issue.path.map(String).join('.')\n issues.push(`${key}${path ? `.${path}` : ''}: ${issue.message}`)\n }\n }\n }\n}\n\nexport function validateEnv<TEnv extends EnvConfigInput | undefined>(\n envConfig: TEnv,\n options: ValidateEnvOptions = {},\n): ValidatedEnv<TEnv> {\n const source =\n options.source ?? (process.env as Record<string, string | undefined>)\n const issues: string[] = []\n const isProduction = source.NODE_ENV === 'production'\n\n const base: BaseEnv = {\n NODE_ENV: source.NODE_ENV,\n DATABASE_URL:\n source.DATABASE_URL ?? options.defaultDatabaseUrl ?? 'file:./data.db',\n DATABASE_AUTH_TOKEN: source.DATABASE_AUTH_TOKEN,\n AUTH_SECRET: source.AUTH_SECRET ?? DEV_AUTH_SECRET,\n REDIS_URL: source.REDIS_URL,\n RESEND_API_KEY: source.RESEND_API_KEY,\n SMTP_URL: source.SMTP_URL,\n BUNDERSTACK_EMAIL_PROVIDER: source.BUNDERSTACK_EMAIL_PROVIDER,\n BUNDERSTACK_EMAIL_FROM: source.BUNDERSTACK_EMAIL_FROM,\n BUNDERHOST_ENVIRONMENT_ID: source.BUNDERHOST_ENVIRONMENT_ID,\n BUNDERSTACK_ROLE: (source.BUNDERSTACK_ROLE ?? 'all') as BunderstackRole,\n }\n if (isProduction && !source.AUTH_SECRET) {\n issues.push('AUTH_SECRET: required in production')\n }\n if (\n source.BUNDERSTACK_ROLE !== undefined &&\n !ROLES.includes(source.BUNDERSTACK_ROLE as BunderstackRole)\n ) {\n issues.push(\n `BUNDERSTACK_ROLE: must be one of ${ROLES.join(', ')} (got \"${String(source.BUNDERSTACK_ROLE)}\")`,\n )\n }\n if (options.emailProvider === 'resend' && !source.RESEND_API_KEY) {\n issues.push(\"RESEND_API_KEY: required when email provider is 'resend'\")\n }\n if (options.emailProvider === 'smtp' && !source.SMTP_URL) {\n issues.push(\"SMTP_URL: required when email provider is 'smtp'\")\n }\n\n const userVars: Record<string, unknown> = {}\n validateSection(envConfig?.server, 'server', source, issues, userVars)\n validateSection(envConfig?.client, 'client', source, issues, userVars)\n\n if (issues.length > 0) throw new BunderstackEnvError(issues)\n return { ...base, ...userVars } as ValidatedEnv<TEnv>\n}\n\n/**\n * Browser-side companion (t3-env style): validates ONLY the client section.\n * Server keys exist on the returned object as traps that throw on access, so\n * a leaked import fails loudly instead of silently reading undefined.\n */\nexport function createClientEnv<TEnv extends EnvConfigInput>(\n envConfig: TEnv,\n): InferVars<TEnv['client']> {\n const source =\n envConfig.runtimeEnv ??\n (typeof process !== 'undefined'\n ? (process.env as Record<string, unknown>)\n : {})\n const issues: string[] = []\n const values: Record<string, unknown> = {}\n validateSection(envConfig.client, 'client', source, issues, values)\n if (issues.length > 0) throw new BunderstackEnvError(issues)\n\n const serverKeys = new Set(Object.keys(envConfig.server ?? {}))\n return new Proxy(values, {\n get(target, prop) {\n if (typeof prop === 'string' && serverKeys.has(prop)) {\n throw new Error(\n `${prop} is server-only and not available in client env`,\n )\n }\n return Reflect.get(target, prop)\n },\n }) as InferVars<TEnv['client']>\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,109 +1,5 @@
1
- import type { AnyRouter as AnyORPCRouter } from '@orpc/server';
2
- import type { TableAccessInput } from './access.js';
3
- import type { RealtimeApiRouter } from './api/realtime-router.js';
4
- import type { CrudApiRouterFor, MergeApiRouterTypes, UnifiedApiRouter } from './api/types.js';
5
- import type { DbFor } from './db.js';
6
- import type { BunderstackJobsBuilder, JobsDefs, JobsFacade, StartWorkerOptions, WorkerHandle } from './jobs/index.js';
7
- import type { StorageConfigInput } from './storage/buckets.js';
8
- import type { StorageAdapter } from './storage/index.js';
9
- import { createAuth } from './auth.js';
10
- import { type BunderstackConfig } from './config.js';
11
- import { type EmailFacade } from './email.js';
12
- import { type EnvConfigInput, type ValidatedEnv } from './env.js';
13
- import { type LifecycleStatus } from './lifecycle.js';
14
- import { type BunderstackManifest } from './manifest.js';
15
- import { type RealtimeFacade } from './realtime/facade.js';
16
- export type AuthInstance = ReturnType<typeof createAuth>;
17
- /**
18
- * Public storage facade exposed as `app.storage`. Object-level operations live
19
- * on the per-bucket adapters; this surface offers the app-wide deletes that
20
- * must also clean the file-meta row.
21
- */
22
- export interface StorageFacade {
23
- /** Delete a file row and purge all underlying storage derivatives. */
24
- delete(fileId: string): Promise<void>;
25
- /** Low-level access to the underlying storage adapter for a bucket. */
26
- bucket(name: string): StorageAdapter | undefined;
27
- /**
28
- * Reap stale `pending` uploads older than `olderThanMs` (default 30m). Runs
29
- * only when explicitly invoked by the host or local scheduler. Returns
30
- * the count reaped.
31
- */
32
- sweep(olderThanMs?: number): Promise<number>;
33
- /**
34
- * Get a public or presigned download URL for a file key.
35
- * Returns a presigned S3 URL when S3 is configured, or local proxy route `/api/files/...` in development.
36
- */
37
- getUrl(key: string, opts?: {
38
- bucket?: string;
39
- expiresIn?: number;
40
- }): Promise<string>;
41
- /**
42
- * Upload bytes as a ready file and register it in file_meta so it is
43
- * accessible via `GET /api/files/<key>`. Use this for server-generated
44
- * files (e.g. generated PDFs) that are not uploaded by end-users.
45
- */
46
- upload(key: string, body: ArrayBuffer | Uint8Array, contentType: string, opts?: {
47
- ownerId?: string;
48
- filename?: string;
49
- }): Promise<void>;
50
- }
51
- export type AppStartWorkerOptions = Omit<StartWorkerOptions, 'tick'>;
52
- export type AppRunWorkerOptions = AppStartWorkerOptions & {
53
- /**
54
- * Permit process-local realtime in a standalone worker.
55
- *
56
- * Use only when job handlers never call ctx.realtime.publish(). Publications
57
- * made through the memory broker cannot reach SSE clients in another process.
58
- */
59
- allowProcessLocalRealtime?: boolean;
60
- };
61
- /** Bucket names declared in a storage config; `string` when unknowable. */
62
- export type BucketNamesOf<TStorage> = TStorage extends {
63
- buckets: infer B extends Record<string, unknown>;
64
- } ? keyof B & string : string;
65
- export type BunderstackApp<TSchema extends Record<string, unknown>, TAccess extends Record<string, TableAccessInput> | undefined = undefined, TBuckets extends string = string, TEnv extends EnvConfigInput | undefined = undefined, TJobsDefs extends JobsDefs | undefined = undefined, TCustomApiRouter extends AnyORPCRouter | undefined = undefined, TRealtime = undefined> = {
66
- handler: (req: Request) => Promise<Response>;
67
- db: DbFor<TSchema>;
68
- auth: AuthInstance;
69
- storage: StorageFacade;
70
- /** Validated env: bunderstack's base vars plus the config's `env` extension. */
71
- env: ValidatedEnv<TEnv>;
72
- /** Email facade; always present — send() throws when email isn't configured. */
73
- email: EmailFacade;
74
- /** Job queue facade; always present — enqueue throws when jobs aren't configured. */
75
- jobs: JobsFacade<TJobsDefs extends JobsDefs ? TJobsDefs : Record<never, never>>;
76
- /** Typed custom row publication; enabled=false/no-op when realtime is off. */
77
- realtime: RealtimeFacade<TSchema>;
78
- startWorker(options?: AppStartWorkerOptions): Promise<WorkerHandle>;
79
- /** Run a queue worker until aborted, then close the application. */
80
- runWorker(options?: AppRunWorkerOptions): Promise<void>;
81
- close(): Promise<void>;
82
- /** True when this process is running the background tick loop. */
83
- readonly backgroundRunning: boolean;
84
- readonly status: LifecycleStatus;
85
- readonly signal: AbortSignal;
86
- /** Deploy-time introspection: what this app needs provisioned. */
87
- manifest: BunderstackManifest;
88
- /**
89
- * Type-only carrier for client inference (`createClient<typeof app>()`).
90
- * Never assigned at runtime.
91
- */
92
- readonly $inferClient?: {
93
- schema: TSchema;
94
- access: TAccess;
95
- buckets: TBuckets;
96
- api: MergeApiRouterTypes<UnifiedApiRouter<CrudApiRouterFor<TSchema, TAccess, [
97
- TRealtime
98
- ] extends [false | undefined] ? false : true>, TCustomApiRouter>, [
99
- TRealtime
100
- ] extends [false | undefined] ? {} : RealtimeApiRouter>;
101
- };
102
- };
103
- export declare function createBunderstack<TSchema extends Record<string, unknown>, const TAccess extends Record<string, TableAccessInput> | undefined = undefined, const TStorage extends StorageConfigInput | undefined = undefined, const TEnv extends EnvConfigInput | undefined = undefined, const TJobsDefs extends JobsDefs | undefined = undefined, TCustomApiRouter extends AnyORPCRouter | undefined = undefined, const TRealtime extends BunderstackConfig<TSchema, TAccess, TStorage, TEnv, TCustomApiRouter>['realtime'] = undefined>(options: BunderstackConfig<TSchema, TAccess, TStorage, TEnv, TCustomApiRouter> & {
104
- realtime?: TRealtime;
105
- jobs?: TJobsDefs | ((j: BunderstackJobsBuilder<TSchema, ValidatedEnv<TEnv>>) => TJobsDefs);
106
- }): Promise<BunderstackApp<TSchema, TAccess, BucketNamesOf<TStorage>, TEnv, TJobsDefs, TCustomApiRouter, TRealtime>>;
1
+ export * from './backend.js';
2
+ export type { AppRunWorkerOptions, AppStartWorkerOptions, AuthInstance, BucketNamesOf, BunderstackApp, StorageFacade, } from './runtime.js';
107
3
  export { listSpec } from './api/list-spec.js';
108
4
  export type { ListSpecOptions } from './api/list-spec.js';
109
5
  export type { BunderstackDb, BunderstackTx } from './db.js';
@@ -124,11 +20,10 @@ export { defineAccess, validateAndResolveAccess, checkAccess, AUTH_TABLE_NAMES,
124
20
  export type { TableAccessInput, OperationRule, AccessContext, AccessUser, } from './access.js';
125
21
  export { typeid, generate as generateTypeId, parse as parseTypeId, asTypeId, } from './typeid.js';
126
22
  export type { TypeId } from './typeid.js';
127
- export type { DatabaseAdapter, DatabaseConnectOptions, DatabaseConnection, DatabaseConnectionResult, } from './database/adapter.js';
23
+ export type { DatabaseAdapter, DatabaseConnection, DatabaseConnectionResult, } from './database/adapter.js';
128
24
  export type { StorageAdapter } from './storage/index.js';
129
25
  export type { StorageConfigInput, BucketConfigInput, ResolvedBucket, } from './storage/buckets.js';
130
26
  export type { TransformSpec } from './storage/thumbnails.js';
131
- export { mockAuthSession } from './testing.js';
132
27
  export type { RealtimeAction } from './realtime/publisher.js';
133
28
  export { createRealtimeFacade } from './realtime/facade.js';
134
29
  export type { RealtimeFacade, RealtimeTransport, SchemaTable, } from './realtime/facade.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}