@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/brain/signatures.md +1 -0
- package/dist/index.cjs +42 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +42 -28
- package/dist/index.js.map +1 -1
- package/package.json +93 -94
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 =
|
|
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
|
-
|
|
1278
|
-
|
|
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
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
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
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
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
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
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
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
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
|
-
|
|
1304
|
-
// ── Update current workspace — ID
|
|
1305
|
-
// (or personal
|
|
1306
|
-
|
|
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
|
-
|
|
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(
|