@fonderie/workspaces 1.2.2 → 2.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/dist/index.js CHANGED
@@ -1031,7 +1031,6 @@ function roleController(store) {
1031
1031
  // src/controllers/invitation.controller.ts
1032
1032
  import { setApiResponse as setApiResponse5, HTTP as HTTP5 } from "@fonderie/core";
1033
1033
  import { NOTIFICATION_EVENT } from "@fonderie/events";
1034
- import { getPlanLimit } from "@fonderie/billing";
1035
1034
 
1036
1035
  // src/services/invitations.ts
1037
1036
  import { randomBytes } from "crypto";
@@ -1153,6 +1152,12 @@ var InvitationModel = class {
1153
1152
  };
1154
1153
 
1155
1154
  // src/controllers/invitation.controller.ts
1155
+ function seatLimitFromMeta(ctx) {
1156
+ const billing = ctx.meta["billing"];
1157
+ const status = billing?.statuses?.["seats"];
1158
+ if (!status || status.type === "feature" || typeof status.limit !== "number") return null;
1159
+ return status.limit;
1160
+ }
1156
1161
  function invitationController(store, ttl, bus) {
1157
1162
  const invitations = new InvitationModel(store);
1158
1163
  return {
@@ -1182,7 +1187,7 @@ function invitationController(store, ttl, bus) {
1182
1187
  return setApiResponse5(HTTP5.UNPROCESSABLE, "INVALID_PARAMETER", "email is required for every invite");
1183
1188
  }
1184
1189
  }
1185
- const seatLimit = getPlanLimit(ctx, "seats");
1190
+ const seatLimit = seatLimitFromMeta(ctx);
1186
1191
  if (seatLimit !== null) {
1187
1192
  const [countRow] = await store.query(
1188
1193
  `SELECT COUNT(*) AS count FROM fonderie_role_user_workspaces
@@ -1272,38 +1277,45 @@ function buildWorkspaceRoutes(store, config, bus) {
1272
1277
  const member = memberController(store);
1273
1278
  const role = roleController(store);
1274
1279
  const invitation = invitationController(store, ttl, bus);
1280
+ const R = (id, method, path, ...handlers) => {
1281
+ const o = config.routes?.[id];
1282
+ if (!o) return [method, path, ...handlers];
1283
+ if (typeof o === "string") return [method, o, ...handlers];
1284
+ return [o.method ?? method, o.path ?? path, ...handlers];
1285
+ };
1275
1286
  return [
1276
1287
  // ── Workspace creation + listing (no workspace context required)
1277
- ["POST", "/workspaces", requireAuth, validate(createWorkspaceSchema), workspace.create],
1278
- ["GET", "/workspaces", requireAuth, workspace.list],
1288
+ R("createWorkspace", "POST", "/workspaces", requireAuth, validate(createWorkspaceSchema), workspace.create),
1289
+ R("listWorkspaces", "GET", "/workspaces", requireAuth, workspace.list),
1279
1290
  // ── Members (workspace resolved from X-Workspace-ID header)
1280
- ["GET", "/workspaces/members", requireAuth, wsCtx, member.list],
1281
- ["DELETE", "/workspaces/members/:userId", requireAuth, wsCtx, member.remove],
1282
- ["GET", "/workspaces/members/:userId/roles", requireAuth, wsCtx, member.getUserRoles],
1283
- ["POST", "/workspaces/members/:userId/roles", requireAuth, wsCtx, validate(addMemberRoleSchema), member.addRole],
1284
- ["DELETE", "/workspaces/members/:userId/roles/:roleId", requireAuth, wsCtx, member.removeRole],
1291
+ R("listMembers", "GET", "/workspaces/members", requireAuth, wsCtx, member.list),
1292
+ R("removeMember", "DELETE", "/workspaces/members/:userId", requireAuth, wsCtx, member.remove),
1293
+ R("getMemberRoles", "GET", "/workspaces/members/:userId/roles", requireAuth, wsCtx, member.getUserRoles),
1294
+ R("addMemberRole", "POST", "/workspaces/members/:userId/roles", requireAuth, wsCtx, validate(addMemberRoleSchema), member.addRole),
1295
+ R("removeMemberRole", "DELETE", "/workspaces/members/:userId/roles/:roleId", requireAuth, wsCtx, member.removeRole),
1285
1296
  // ── Invitations
1286
- ["GET", "/workspaces/invitations", requireAuth, wsCtx, invitation.list],
1287
- ["POST", "/workspaces/invitations", requireAuth, wsCtx, validate(createInvitationsSchema), invitation.invite],
1288
- ["DELETE", "/workspaces/invitations/:inviteId", requireAuth, wsCtx, invitation.cancel],
1289
- ["POST", "/workspaces/invitations/accept", requireAuth, validate(acceptInvitationSchema), invitation.accept],
1297
+ R("listInvitations", "GET", "/workspaces/invitations", requireAuth, wsCtx, invitation.list),
1298
+ R("invite", "POST", "/workspaces/invitations", requireAuth, wsCtx, validate(createInvitationsSchema), invitation.invite),
1299
+ R("cancelInvitation", "DELETE", "/workspaces/invitations/:inviteId", requireAuth, wsCtx, invitation.cancel),
1300
+ R("acceptInvitation", "POST", "/workspaces/invitations/accept", requireAuth, validate(acceptInvitationSchema), invitation.accept),
1290
1301
  // ── Roles
1291
- ["POST", "/workspaces/roles", requireAuth, wsCtx, validate(createRoleSchema), role.create],
1292
- ["GET", "/workspaces/roles", requireAuth, wsCtx, role.list],
1293
- ["GET", "/workspaces/roles/:roleId", requireAuth, wsCtx, role.get],
1294
- ["PUT", "/workspaces/roles/:roleId", requireAuth, wsCtx, validate(updateRoleSchema), role.update],
1295
- ["DELETE", "/workspaces/roles/:roleId", requireAuth, wsCtx, role.remove],
1296
- ["POST", "/workspaces/roles/:roleId/permissions", requireAuth, wsCtx, validate(setRolePermissionsSchema), role.setPermissions],
1302
+ R("createRole", "POST", "/workspaces/roles", requireAuth, wsCtx, validate(createRoleSchema), role.create),
1303
+ R("listRoles", "GET", "/workspaces/roles", requireAuth, wsCtx, role.list),
1304
+ R("getRole", "GET", "/workspaces/roles/:roleId", requireAuth, wsCtx, role.get),
1305
+ R("updateRole", "PUT", "/workspaces/roles/:roleId", requireAuth, wsCtx, validate(updateRoleSchema), role.update),
1306
+ R("removeRole", "DELETE", "/workspaces/roles/:roleId", requireAuth, wsCtx, role.remove),
1307
+ R("setRolePermissions", "POST", "/workspaces/roles/:roleId/permissions", requireAuth, wsCtx, validate(setRolePermissionsSchema), role.setPermissions),
1297
1308
  // ── Workspace lifecycle
1298
- ["POST", "/workspaces/archive", requireAuth, wsCtx, workspace.archive],
1299
- ["POST", "/workspaces/restore", requireAuth, wsCtx, workspace.restore],
1300
- ["GET", "/workspaces/settings", requireAuth, wsCtx, workspace.getSettings],
1301
- ["PUT", "/workspaces/settings", requireAuth, wsCtx, validate(updateSettingsSchema), workspace.updateSettings],
1309
+ R("archive", "POST", "/workspaces/archive", requireAuth, wsCtx, workspace.archive),
1310
+ R("restore", "POST", "/workspaces/restore", requireAuth, wsCtx, workspace.restore),
1311
+ R("getSettings", "GET", "/workspaces/settings", requireAuth, wsCtx, workspace.getSettings),
1312
+ R("updateSettings", "PUT", "/workspaces/settings", requireAuth, wsCtx, validate(updateSettingsSchema), workspace.updateSettings),
1302
1313
  // ── Path-based lookup by ID (admin / cross-workspace use)
1303
- ["GET", "/workspaces/:id", requireAuth, wsCtx, workspace.get],
1304
- // ── Update current workspace — ID resolved from X-Workspace-ID header
1305
- // (or personal workspace fallback when header is absent)
1306
- ["PUT", "/workspaces", requireAuth, wsCtx, validate(updateWorkspaceSchema), workspace.update]
1314
+ R("getWorkspace", "GET", "/workspaces/:id", requireAuth, wsCtx, workspace.get),
1315
+ // ── Update current workspace — ID from :id path param (wsCtx) or the
1316
+ // X-Workspace-ID header (or personal-workspace fallback when absent). Set
1317
+ // routes.updateWorkspace = '/workspaces/:id' to match a path-id frontend.
1318
+ R("updateWorkspace", "PUT", "/workspaces", requireAuth, wsCtx, validate(updateWorkspaceSchema), workspace.update)
1307
1319
  ];
1308
1320
  }
1309
1321
 
@@ -1319,7 +1331,9 @@ var WorkspacesModule = class {
1319
1331
  config;
1320
1332
  bus;
1321
1333
  name = "@fonderie/workspaces";
1322
- deps = ["@fonderie/auth", "@fonderie/billing"];
1334
+ // billing is OPTIONAL — seat limits activate if it's registered (read via
1335
+ // ctx.meta['billing']), otherwise invitations are unlimited. Not a hard dep.
1336
+ deps = ["@fonderie/auth"];
1323
1337
  install(app) {
1324
1338
  if (this.bus && this.config.personalWorkspace !== false) {
1325
1339
  this.bus.on(