@stratum-hq/hono 1.0.0 → 1.1.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/README.md CHANGED
@@ -41,7 +41,7 @@ app.get("/users", (c) => {
41
41
  | `header` | Read a request header (default: `x-tenant-id`) |
42
42
  | `resolve` | Optional callback `(tenantId) => TenantContext` to populate ancestry, config, and permissions |
43
43
 
44
- If no tenant ID is found, the middleware responds with `400 { error: "Missing tenant ID" }`. Without a `resolve` callback the context is a placeholder (empty config/permissions) — provide `resolve` for real tenant data.
44
+ If no tenant ID is found, the middleware responds with `400 { error: "Missing tenant ID" }`. If `resolve` rejects with a tenant error from `@stratum-hq/core`, for example from `StratumClient.resolveTenant`, the middleware responds with 404 `TENANT_NOT_FOUND`, 403 `TENANT_SUSPENDED`, 410 `TENANT_ARCHIVED`, or 403 `FORBIDDEN`. A control plane timeout gets 504 `CONTROL_PLANE_TIMEOUT`. An `UnauthorizedError` for the SDK's own API key gets 500 `CONTROL_PLANE_AUTH_FAILED` and a `console.error` line. Other errors go to the Hono error handler. Without a `resolve` callback the context is a placeholder (empty config/permissions) — provide `resolve` for real tenant data.
45
45
 
46
46
  ## Features
47
47
 
@@ -11,6 +11,12 @@ export interface StratumMiddlewareOptions {
11
11
  * Optional callback to resolve a full tenant context from the tenant ID.
12
12
  * When provided, the middleware will call this to obtain ancestry, config,
13
13
  * and permissions instead of using placeholder values.
14
+ *
15
+ * If the callback rejects with a tenant error from `@stratum-hq/core`, for
16
+ * example from `StratumClient.resolveTenant`, the middleware answers 404,
17
+ * 403 or 410. A control plane timeout answers 504. A rejected SDK API key
18
+ * answers 500 and writes the cause to `console.error`. Other errors go to
19
+ * the Hono error handler.
14
20
  */
15
21
  resolve?: (tenantId: string) => Promise<ResolvedTenantContext> | ResolvedTenantContext;
16
22
  }
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAE7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAG9D,MAAM,WAAW,wBAAwB;IACvC,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,GAAG,qBAAqB,CAAC;CACxF;AAkBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,wBAA6B,GACrC,iBAAiB,CAqCnB"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAG7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAG9D,MAAM,WAAW,wBAAwB;IACvC,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,GAAG,qBAAqB,CAAC;CACxF;AAkBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,wBAA6B,GACrC,iBAAiB,CA4CnB"}
@@ -1,4 +1,4 @@
1
- import { runWithTenantContext } from "@stratum-hq/sdk";
1
+ import { controlPlaneErrorResponse, runWithTenantContext, tenantErrorResponse } from "@stratum-hq/sdk";
2
2
  import { IsolationStrategy } from "@stratum-hq/core";
3
3
  function extractFromHeader(c, header) {
4
4
  return c.req.header(header) ?? undefined;
@@ -36,21 +36,30 @@ export function stratumMiddleware(options = {}) {
36
36
  return c.json({ error: "Missing tenant ID" }, 400);
37
37
  }
38
38
  c.set("tenantId", tenantId);
39
- const ctx = options.resolve
40
- ? await options.resolve(tenantId)
41
- : /**
42
- * @warning Placeholder context — ancestry_path, resolved_config, and
43
- * resolved_permissions are stub values. Provide a `resolve` callback
44
- * to populate real tenant data.
45
- */
46
- {
47
- tenant_id: tenantId,
48
- ancestry_path: tenantId,
49
- depth: 0,
50
- resolved_config: {},
51
- resolved_permissions: {},
52
- isolation_strategy: IsolationStrategy.SHARED_RLS,
53
- };
39
+ let ctx;
40
+ try {
41
+ ctx = options.resolve
42
+ ? await options.resolve(tenantId)
43
+ : /**
44
+ * @warning Placeholder context — ancestry_path, resolved_config, and
45
+ * resolved_permissions are stub values. Provide a `resolve` callback
46
+ * to populate real tenant data.
47
+ */
48
+ {
49
+ tenant_id: tenantId,
50
+ ancestry_path: tenantId,
51
+ depth: 0,
52
+ resolved_config: {},
53
+ resolved_permissions: {},
54
+ isolation_strategy: IsolationStrategy.SHARED_RLS,
55
+ };
56
+ }
57
+ catch (err) {
58
+ const response = tenantErrorResponse(err, tenantId) ?? controlPlaneErrorResponse(err);
59
+ if (!response)
60
+ throw err;
61
+ return c.json(response.body, response.status);
62
+ }
54
63
  return runWithTenantContext(ctx, () => next());
55
64
  };
56
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAiBrD,SAAS,iBAAiB,CAAC,CAAU,EAAE,MAAc;IACnD,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;AAC3C,CAAC;AAED,SAAS,mBAAmB,CAAC,CAAU,EAAE,KAAa;IACpD,8EAA8E;IAC9E,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,YAAY,CAAwC,CAAC;IAC3E,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,SAAS,oBAAoB,CAAC,CAAU,EAAE,KAAa;IACrD,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAoC,EAAE;IAEtC,OAAO,KAAK,EAAE,CAAU,EAAE,IAAU,EAAE,EAAE;QACtC,IAAI,QAA4B,CAAC;QAEjC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,QAAQ,GAAG,mBAAmB,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtD,CAAC;aAAM,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YAC7B,QAAQ,GAAG,oBAAoB,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QACxD,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC;YAC/C,QAAQ,GAAG,iBAAiB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC1C,CAAC;QAED,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,GAAG,CAAC,CAAC;QACrD,CAAC;QAED,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAE5B,MAAM,GAAG,GAA0B,OAAO,CAAC,OAAO;YAChD,CAAC,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;YACjC,CAAC,CAAC;;;;iBAIG;gBACH;oBACE,SAAS,EAAE,QAAQ;oBACnB,aAAa,EAAE,QAAQ;oBACvB,KAAK,EAAE,CAAC;oBACR,eAAe,EAAE,EAAE;oBACnB,oBAAoB,EAAE,EAAE;oBACxB,kBAAkB,EAAE,iBAAiB,CAAC,UAAU;iBACjD,CAAC;QAEN,OAAO,oBAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEvG,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAuBrD,SAAS,iBAAiB,CAAC,CAAU,EAAE,MAAc;IACnD,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;AAC3C,CAAC;AAED,SAAS,mBAAmB,CAAC,CAAU,EAAE,KAAa;IACpD,8EAA8E;IAC9E,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,YAAY,CAAwC,CAAC;IAC3E,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED,SAAS,oBAAoB,CAAC,CAAU,EAAE,KAAa;IACrD,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAoC,EAAE;IAEtC,OAAO,KAAK,EAAE,CAAU,EAAE,IAAU,EAAE,EAAE;QACtC,IAAI,QAA4B,CAAC;QAEjC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,QAAQ,GAAG,mBAAmB,CAAC,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtD,CAAC;aAAM,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YAC7B,QAAQ,GAAG,oBAAoB,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QACxD,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,CAAC;YAC/C,QAAQ,GAAG,iBAAiB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC1C,CAAC;QAED,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,GAAG,CAAC,CAAC;QACrD,CAAC;QAED,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAE5B,IAAI,GAA0B,CAAC;QAC/B,IAAI,CAAC;YACH,GAAG,GAAG,OAAO,CAAC,OAAO;gBACnB,CAAC,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACjC,CAAC,CAAC;;;;qBAIG;oBACH;wBACE,SAAS,EAAE,QAAQ;wBACnB,aAAa,EAAE,QAAQ;wBACvB,KAAK,EAAE,CAAC;wBACR,eAAe,EAAE,EAAE;wBACnB,oBAAoB,EAAE,EAAE;wBACxB,kBAAkB,EAAE,iBAAiB,CAAC,UAAU;qBACjD,CAAC;QACR,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,mBAAmB,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,yBAAyB,CAAC,GAAG,CAAC,CAAC;YACtF,IAAI,CAAC,QAAQ;gBAAE,MAAM,GAAG,CAAC;YACzB,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAA8B,CAAC,CAAC;QACxE,CAAC;QAED,OAAO,oBAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stratum-hq/hono",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Stratum Hono integration — tenant extraction middleware with ALS context",
5
5
  "keywords": [
6
6
  "multi-tenancy",
@@ -38,16 +38,16 @@
38
38
  "registry": "https://registry.npmjs.org/"
39
39
  },
40
40
  "peerDependencies": {
41
- "@stratum-hq/core": ">=1.0.0",
42
- "@stratum-hq/sdk": ">=1.0.0",
41
+ "@stratum-hq/core": "^1.0.0",
42
+ "@stratum-hq/sdk": "^1.2.0",
43
43
  "hono": ">=4.0.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@stratum-hq/core": "*",
47
47
  "@stratum-hq/sdk": "*",
48
- "hono": "^4.0.0",
48
+ "hono": "^4.13.9",
49
49
  "typescript": "^5.4.0",
50
- "vitest": "^1.6.0"
50
+ "vitest": "^4.1.11"
51
51
  },
52
52
  "license": "MIT",
53
53
  "author": "Christian Crank",