@voyantjs/hono 0.63.0 → 0.64.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.
package/dist/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAS3B,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA2BlF;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAmB,CAAC,SAAS,GAAG,OAAO;IACtD;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3C;AAED,wBAAgB,SAAS,CAAC,SAAS,SAAS,cAAc,EACxD,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,GACjC,IAAI,CAAC;IAAE,QAAQ,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,eAAe,CAAA;CAAE,CAAC,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAuP5F"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAS3B,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AA2BlF;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAmB,CAAC,SAAS,GAAG,OAAO;IACtD;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3C;AAED,wBAAgB,SAAS,CAAC,SAAS,SAAS,cAAc,EACxD,MAAM,EAAE,eAAe,CAAC,SAAS,CAAC,GACjC,IAAI,CAAC;IAAE,QAAQ,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,eAAe,CAAA;CAAE,CAAC,GAAG,mBAAmB,CAAC,SAAS,CAAC,CA6P5F"}
package/dist/app.js CHANGED
@@ -191,8 +191,14 @@ export function createApp(config) {
191
191
  }
192
192
  // Auth middleware for all other routes
193
193
  app.use("*", requireAuth(config.db, { publicPaths: config.publicPaths, auth: config.auth }));
194
- // DB middleware — sets c.var.db for all downstream handlers
195
- app.use("*", db(config.db));
194
+ // DB middleware — sets c.var.db for all downstream handlers.
195
+ // Pass the list of modules that need interactive transactions so the
196
+ // middleware can throw a clear startup-style error on first request if
197
+ // the wired adapter is neon-http (which doesn't support db.transaction).
198
+ const txRequiringModules = allModules
199
+ .filter((m) => m.module.requiresTransactionalDb)
200
+ .map((m) => m.module.name);
201
+ app.use("*", db(config.db, { requiresTransactionalDb: txRequiringModules }));
196
202
  // Actor guards for the two API surfaces
197
203
  app.use("/v1/admin/*", requireActor("staff"));
198
204
  app.use("/v1/public/*", requireActor("customer", "partner", "supplier"));
@@ -1,5 +1,18 @@
1
1
  import type { MiddlewareHandler } from "hono";
2
2
  import { type DbFactory, type VoyantBindings, type VoyantDb } from "../types.js";
3
+ export interface DbMiddlewareOptions {
4
+ /**
5
+ * Names of modules that require a transaction-capable db adapter
6
+ * (those that set `Module.requiresTransactionalDb`). If non-empty
7
+ * and the first resolved db reports
8
+ * `dbSupportsTransactions(db) === false`, the middleware throws a
9
+ * clear error naming the offending modules. A capability of
10
+ * `undefined` (untagged drivers like raw `drizzle-orm/node-postgres`)
11
+ * is treated as "assume capable" — only an explicit `false`
12
+ * (neon-http) trips the assertion.
13
+ */
14
+ requiresTransactionalDb?: readonly string[];
15
+ }
3
16
  /**
4
17
  * Resolves the per-request db client and stores it on Hono context.
5
18
  *
@@ -14,7 +27,7 @@ import { type DbFactory, type VoyantBindings, type VoyantDb } from "../types.js"
14
27
  * postgres-js client cached at the module level) are wired up as
15
28
  * before with no cleanup hook.
16
29
  */
17
- export declare function db<TBindings extends VoyantBindings>(factory: DbFactory<TBindings>): MiddlewareHandler<{
30
+ export declare function db<TBindings extends VoyantBindings>(factory: DbFactory<TBindings>, options?: DbMiddlewareOptions): MiddlewareHandler<{
18
31
  Bindings: TBindings;
19
32
  Variables: {
20
33
  db: VoyantDb;
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/middleware/db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,cAAc,EACnB,KAAK,QAAQ,EACd,MAAM,aAAa,CAAA;AAYpB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,EAAE,CAAC,SAAS,SAAS,cAAc,EACjD,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,GAC5B,iBAAiB,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE;QAAE,EAAE,EAAE,QAAQ,CAAA;KAAE,CAAA;CAC5B,CAAC,CAwBD"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/middleware/db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,cAAc,EACnB,KAAK,QAAQ,EACd,MAAM,aAAa,CAAA;AAEpB,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;OASG;IACH,uBAAuB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC5C;AAwBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,EAAE,CAAC,SAAS,SAAS,cAAc,EACjD,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,EAC7B,OAAO,GAAE,mBAAwB,GAChC,iBAAiB,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE;QAAE,EAAE,EAAE,QAAQ,CAAA;KAAE,CAAA;CAC5B,CAAC,CA4CD"}
@@ -1,4 +1,14 @@
1
+ import { dbSupportsTransactions } from "@voyantjs/db/transaction-capability";
1
2
  import { resolveDbFactoryResult, } from "../types.js";
3
+ function buildIncapableDbError(modules) {
4
+ const list = [...modules].sort().join(", ");
5
+ return new Error(`[voyant] db adapter does not support interactive transactions, but the ` +
6
+ `following modules require it: ${list}. ` +
7
+ `Use createServerlessDbClient (neon-serverless / WebSocket) for ` +
8
+ `Cloudflare Workers, or createDbClient(url, { adapter: "node" }) for ` +
9
+ `Node deployments. The "edge" adapter (neon-http) is read-mostly ` +
10
+ `and cannot run db.transaction(async (tx) => …).`);
11
+ }
2
12
  /**
3
13
  * Resolves the per-request db client and stores it on Hono context.
4
14
  *
@@ -13,10 +23,31 @@ import { resolveDbFactoryResult, } from "../types.js";
13
23
  * postgres-js client cached at the module level) are wired up as
14
24
  * before with no cleanup hook.
15
25
  */
16
- export function db(factory) {
26
+ export function db(factory, options = {}) {
27
+ const requiresTx = options.requiresTransactionalDb ?? [];
28
+ // Stays `false` until a request resolves a db whose capability tag is
29
+ // anything other than an explicit `false`. As long as the adapter is
30
+ // wired wrong, every request keeps surfacing the actionable error —
31
+ // we don't want the first failing request to silence subsequent
32
+ // checks and let later writes crash with the deep transaction error.
33
+ let txCapabilityVerified = false;
17
34
  return async (c, next) => {
18
35
  const result = factory(c.env);
19
36
  const { db, dispose } = resolveDbFactoryResult(result);
37
+ if (!txCapabilityVerified && requiresTx.length > 0) {
38
+ if (dbSupportsTransactions(db) === false) {
39
+ if (dispose) {
40
+ try {
41
+ await dispose();
42
+ }
43
+ catch {
44
+ // swallow dispose errors — the original throw is the actionable one
45
+ }
46
+ }
47
+ throw buildIncapableDbError(requiresTx);
48
+ }
49
+ txCapabilityVerified = true;
50
+ }
20
51
  if (dispose) {
21
52
  c.set("db", db);
22
53
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/hono",
3
- "version": "0.63.0",
3
+ "version": "0.64.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -94,18 +94,18 @@
94
94
  "drizzle-orm": "^0.45.2",
95
95
  "hono": "^4.12.10",
96
96
  "zod": "^4.3.6",
97
- "@voyantjs/core": "0.63.0",
98
- "@voyantjs/db": "0.63.0",
99
- "@voyantjs/types": "0.63.0",
100
- "@voyantjs/utils": "0.63.0",
101
- "@voyantjs/workflows": "0.63.0"
97
+ "@voyantjs/core": "0.64.0",
98
+ "@voyantjs/db": "0.64.0",
99
+ "@voyantjs/types": "0.64.0",
100
+ "@voyantjs/utils": "0.64.0",
101
+ "@voyantjs/workflows": "0.64.0"
102
102
  },
103
103
  "devDependencies": {
104
104
  "@cloudflare/workers-types": "^4.20260426.1",
105
105
  "typescript": "^6.0.2",
106
106
  "vitest": "^4.1.2",
107
107
  "@voyantjs/voyant-typescript-config": "0.1.0",
108
- "@voyantjs/workflows-orchestrator": "0.63.0"
108
+ "@voyantjs/workflows-orchestrator": "0.64.0"
109
109
  },
110
110
  "files": [
111
111
  "dist"