@kelpie/server 0.5.1 → 0.5.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.
@@ -1 +1 @@
1
- {"version":3,"file":"workspaceAccessMiddleware.d.ts","sourceRoot":"","sources":["../../../src/modules/workspace/workspaceAccessMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAGtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAGxE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AA4BpE,MAAM,WAAW,qCAAsC,SAAQ,sBAAsB;IACnF,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAA;CAC3C;AAED,wBAAgB,+BAA+B,CAC7C,YAAY,EAAE,qCAAqC,GAClD,iBAAiB,CAmCnB"}
1
+ {"version":3,"file":"workspaceAccessMiddleware.d.ts","sourceRoot":"","sources":["../../../src/modules/workspace/workspaceAccessMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAGtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAGxE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAqCpE,MAAM,WAAW,qCAAsC,SAAQ,sBAAsB;IACnF,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAA;CAC3C;AAED,wBAAgB,+BAA+B,CAC7C,YAAY,EAAE,qCAAqC,GAClD,iBAAiB,CAmCnB"}
@@ -22,13 +22,21 @@ import { WORKSPACE_ACCESS } from './capabilities.js';
22
22
  * chance of understanding why. There is no `/v1` endpoint to switch a
23
23
  * session to a different workspace membership — a session is bound to one
24
24
  * at login — so there is nothing further to exempt for that case.
25
+ *
26
+ * Also exempts `DELETE /v1/workspaces/:id` itself, and only that exact
27
+ * path: a suspension must never trap an owner into a workspace they can no
28
+ * longer read or write but also cannot leave by deleting. Every other verb
29
+ * and every sub-resource under `/v1/workspaces/:id` (members, invites,
30
+ * modules) stays gated.
25
31
  */
26
- function isExempt(path) {
27
- return path.startsWith('/v1/auth/') || path.startsWith('/v1/account');
32
+ const WORKSPACE_DELETE_PATH = /^\/v1\/workspaces\/[^/]+$/u;
33
+ function isExempt(method, path) {
34
+ return path.startsWith('/v1/auth/') || path.startsWith('/v1/account') ||
35
+ (method === 'DELETE' && WORKSPACE_DELETE_PATH.test(path));
28
36
  }
29
37
  export function createWorkspaceAccessMiddleware(dependencies) {
30
38
  return async (context, next) => {
31
- if (isExempt(context.req.path)) {
39
+ if (isExempt(context.req.method, context.req.path)) {
32
40
  await next();
33
41
  return;
34
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"workspaceAccessMiddleware.js","sourceRoot":"","sources":["../../../src/modules/workspace/workspaceAccessMiddleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAE9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAEzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEpD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAA;AACvE,CAAC;AAMD,MAAM,UAAU,+BAA+B,CAC7C,YAAmD;IAEnD,OAAO,KAAK,EAAE,OAAgB,EAAE,IAAI,EAAE,EAAE;QACtC,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACnF,IAAI,KAAK,YAAY,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;gBAC/D,+DAA+D;gBAC/D,mEAAmE;gBACnE,OAAO,SAAS,CAAA;YAClB,CAAC;YAED,MAAM,KAAK,CAAA;QACb,CAAC,CAAC,CAAA;QAEF,MAAM,WAAW,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAA;QAExE,gEAAgE;QAChE,oEAAoE;QACpE,uDAAuD;QACvD,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,IAAI,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,KAAK,CAAC,WAAW,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAA;QAE7F,IAAI,WAAW,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACxD,MAAM,IAAI,QAAQ,CAAC,sBAAsB,EAAE,qCAAqC,CAAC,CAAA;QACnF,CAAC;QAED,MAAM,IAAI,EAAE,CAAA;IACd,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"workspaceAccessMiddleware.js","sourceRoot":"","sources":["../../../src/modules/workspace/workspaceAccessMiddleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAE9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAEzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,qBAAqB,GAAG,4BAA4B,CAAA;AAE1D,SAAS,QAAQ,CAAC,MAAc,EAAE,IAAY;IAC5C,OAAO,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QACnE,CAAC,MAAM,KAAK,QAAQ,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;AAC7D,CAAC;AAMD,MAAM,UAAU,+BAA+B,CAC7C,YAAmD;IAEnD,OAAO,KAAK,EAAE,OAAgB,EAAE,IAAI,EAAE,EAAE;QACtC,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,IAAI,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACnF,IAAI,KAAK,YAAY,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;gBAC/D,+DAA+D;gBAC/D,mEAAmE;gBACnE,OAAO,SAAS,CAAA;YAClB,CAAC;YAED,MAAM,KAAK,CAAA;QACb,CAAC,CAAC,CAAA;QAEF,MAAM,WAAW,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAA;QAExE,gEAAgE;QAChE,oEAAoE;QACpE,uDAAuD;QACvD,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,MAAM,IAAI,EAAE,CAAA;YACZ,OAAM;QACR,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,KAAK,CAAC,WAAW,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAA;QAE7F,IAAI,WAAW,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YACxD,MAAM,IAAI,QAAQ,CAAC,sBAAsB,EAAE,qCAAqC,CAAC,CAAA;QACnF,CAAC;QAED,MAAM,IAAI,EAAE,CAAA;IACd,CAAC,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kelpie/server",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "The Kelpie service as a library: module runtime, core CRM modules, REST API, MCP surface, and the shared migration pipeline.",
5
5
  "keywords": [
6
6
  "kelpie",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@hono/node-server": "^2.0.12",
55
- "@kelpie/schemas": "^0.5.1",
55
+ "@kelpie/schemas": "^0.5.2",
56
56
  "@node-rs/argon2": "^2.0.2",
57
57
  "drizzle-orm": "^0.45.2",
58
58
  "hono": "^4.12.32",
@@ -27,9 +27,18 @@ import { WORKSPACE_ACCESS } from './capabilities.ts'
27
27
  * chance of understanding why. There is no `/v1` endpoint to switch a
28
28
  * session to a different workspace membership — a session is bound to one
29
29
  * at login — so there is nothing further to exempt for that case.
30
+ *
31
+ * Also exempts `DELETE /v1/workspaces/:id` itself, and only that exact
32
+ * path: a suspension must never trap an owner into a workspace they can no
33
+ * longer read or write but also cannot leave by deleting. Every other verb
34
+ * and every sub-resource under `/v1/workspaces/:id` (members, invites,
35
+ * modules) stays gated.
30
36
  */
31
- function isExempt(path: string): boolean {
32
- return path.startsWith('/v1/auth/') || path.startsWith('/v1/account')
37
+ const WORKSPACE_DELETE_PATH = /^\/v1\/workspaces\/[^/]+$/u
38
+
39
+ function isExempt(method: string, path: string): boolean {
40
+ return path.startsWith('/v1/auth/') || path.startsWith('/v1/account') ||
41
+ (method === 'DELETE' && WORKSPACE_DELETE_PATH.test(path))
33
42
  }
34
43
 
35
44
  export interface WorkspaceAccessMiddlewareDependencies extends CredentialDependencies {
@@ -40,7 +49,7 @@ export function createWorkspaceAccessMiddleware(
40
49
  dependencies: WorkspaceAccessMiddlewareDependencies,
41
50
  ): MiddlewareHandler {
42
51
  return async (context: Context, next) => {
43
- if (isExempt(context.req.path)) {
52
+ if (isExempt(context.req.method, context.req.path)) {
44
53
  await next()
45
54
  return
46
55
  }