@fonderie/workspaces 5.0.0 → 5.2.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
@@ -34,7 +34,7 @@ typed `EVENT_KEYS` are exported for your handlers and event consumers.
34
34
  You've shipped this plumbing before — auth, teams, billing, messaging —
35
35
  and the next project will ask for it again. Fonderie packages it once:
36
36
  plain TypeScript modules for
37
- [`@fonderie/core`](https://github.com/fonderie-js/sdk/tree/main/packages/core),
37
+ [`@fonderie/core`](https://github.com/fonderiejs/sdk/tree/main/packages/core),
38
38
  PostgreSQL-backed, self-hosted, MIT. No external control plane, no
39
39
  per-seat anything. Register the modules you need; skip the ones you don't.
40
40
 
@@ -43,7 +43,7 @@ and role containers — the bricks scope their data by the workspace context
43
43
  this one provides.
44
44
 
45
45
  Browse the whole set at
46
- [fonderie-js/sdk](https://github.com/fonderie-js/sdk) · follow
46
+ [fonderiejs/sdk](https://github.com/fonderiejs/sdk) · follow
47
47
  [@fonderiejs](https://x.com/fonderiejs)
48
48
 
49
49
  ## License
package/brain/outcomes.md CHANGED
@@ -102,6 +102,7 @@ INSERT INTO fonderie_roles (name, workspace_id, is_system, description) VALUES (
102
102
  | DELETE | `/workspaces/roles/:roleId` | `requireAuth → wsCtx → role.remove` |
103
103
  | GET | `/workspaces/roles/:roleId` | `requireAuth → wsCtx → role.get` |
104
104
  | PUT | `/workspaces/roles/:roleId` | `requireAuth → wsCtx → validate(updateRoleSchema) → role.update` |
105
+ | GET | `/workspaces/roles/:roleId/permissions` | `requireAuth → wsCtx → role.getPermissions` |
105
106
  | POST | `/workspaces/roles/:roleId/permissions` | `requireAuth → wsCtx → validate(setRolePermissionsSchema) → role.setPermissions` |
106
107
  | GET | `/workspaces/settings` | `requireAuth → wsCtx → workspace.getSettings` |
107
108
  | PUT | `/workspaces/settings` | `requireAuth → wsCtx → validate(updateSettingsSchema) → workspace.updateSettings` |
@@ -106,6 +106,7 @@ interface IWorkspaceDTO {
106
106
  isPersonal: boolean;
107
107
  isArchived: boolean;
108
108
  archivedAt: string;
109
+ archivedBy: string;
109
110
  createdAt: string;
110
111
  updatedAt: string;
111
112
  }
@@ -126,6 +127,10 @@ interface IMemberDTO {
126
127
  roleName: string;
127
128
  confirmed: boolean;
128
129
  createdAt: string;
130
+ email: string;
131
+ firstName: string;
132
+ lastName: string;
133
+ profileImageUrl: string;
129
134
  }
130
135
 
131
136
  interface IInvitationDTO {
@@ -204,4 +209,10 @@ interface IImportMembership {
204
209
  confirmed?: boolean;
205
210
  createdAt?: Date;
206
211
  }
212
+
213
+ function deleteUserData(store: IStoreAdapter, userId: string): Promise<number>
214
+
215
+ function exportUserData(store: IStoreAdapter, userId: string): Promise<unknown>
216
+
217
+ function workspaceExportContributor(store: IStoreAdapter): { name: string; collect: (userId: string) => Promise<unknown>; }
207
218
  ```
package/dist/index.cjs CHANGED
@@ -23,6 +23,8 @@ __export(index_exports, {
23
23
  EVENT_KEYS: () => EVENT_KEYS,
24
24
  MESSAGE_KEYS: () => MESSAGE_KEYS,
25
25
  WorkspacesModule: () => WorkspacesModule,
26
+ deleteUserData: () => deleteUserData,
27
+ exportUserData: () => exportUserData,
26
28
  importMembership: () => importMembership,
27
29
  importRole: () => importRole,
28
30
  importWorkspace: () => importWorkspace,
@@ -33,7 +35,8 @@ __export(index_exports, {
33
35
  toRoleDTO: () => toRoleDTO,
34
36
  toSettingsDTO: () => toSettingsDTO,
35
37
  toWorkspaceDTO: () => toWorkspaceDTO,
36
- withWorkspace: () => withWorkspace
38
+ withWorkspace: () => withWorkspace,
39
+ workspaceExportContributor: () => workspaceExportContributor
37
40
  });
38
41
  module.exports = __toCommonJS(index_exports);
39
42
 
@@ -75,10 +78,10 @@ var addressSchema = import_zod.z.object({
75
78
  line1: import_zod.z.string().max(200).optional(),
76
79
  line2: import_zod.z.string().max(200).optional(),
77
80
  city: import_zod.z.string().max(100).optional(),
78
- region: import_zod.z.string().max(100).optional(),
79
- postalCode: import_zod.z.string().max(20).optional(),
81
+ state: import_zod.z.string().max(100).optional(),
82
+ zip: import_zod.z.string().max(20).optional(),
80
83
  country: import_zod.z.string().max(60).optional()
81
- }).passthrough();
84
+ });
82
85
  var updateWorkspaceSchema = import_zod.z.object({
83
86
  name: import_zod.z.string().trim().min(1).max(200).optional(),
84
87
  description: import_zod.z.string().max(2e3).nullable().optional(),
@@ -619,6 +622,19 @@ async function setRolePermissions(roleId, workspaceId, permissions, store) {
619
622
  }
620
623
  });
621
624
  }
625
+ async function getRolePermissions(roleId, workspaceId, store) {
626
+ return store.query(
627
+ `SELECT permission_key AS "permissionKey",
628
+ can_create AS "canCreate",
629
+ can_read AS "canRead",
630
+ can_update AS "canUpdate",
631
+ can_delete AS "canDelete"
632
+ FROM fonderie_role_permissions
633
+ WHERE role_id = $1 AND workspace_id = $2
634
+ ORDER BY permission_key`,
635
+ [roleId, workspaceId]
636
+ );
637
+ }
622
638
 
623
639
  // src/models/role.model.ts
624
640
  var RoleModel = class {
@@ -647,6 +663,9 @@ var RoleModel = class {
647
663
  setPermissions(roleId, workspaceId, permissions) {
648
664
  return setRolePermissions(roleId, workspaceId, permissions, this.store);
649
665
  }
666
+ getPermissions(roleId, workspaceId) {
667
+ return getRolePermissions(roleId, workspaceId, this.store);
668
+ }
650
669
  };
651
670
 
652
671
  // src/dtos/workspace.ts
@@ -674,9 +693,10 @@ function toWorkspaceDTO(ws) {
674
693
  ownerId: (0, import_parser.stringOrEmpty)(ws.ownerId),
675
694
  isPersonal: (0, import_parser.booleanOrFalse)(ws.isPersonal),
676
695
  isArchived: ws.archivedAt !== null,
677
- archivedAt: (0, import_parser.stringOrEmpty)(ws.archivedAt),
678
- createdAt: (0, import_parser.stringOrEmpty)(ws.createdAt),
679
- updatedAt: (0, import_parser.stringOrEmpty)(ws.updatedAt)
696
+ archivedAt: (0, import_parser.dateOrEmpty)(ws.archivedAt),
697
+ archivedBy: (0, import_parser.stringOrEmpty)(ws.archivedBy),
698
+ createdAt: (0, import_parser.dateOrEmpty)(ws.createdAt),
699
+ updatedAt: (0, import_parser.dateOrEmpty)(ws.updatedAt)
680
700
  };
681
701
  }
682
702
  function toRoleDTO(role) {
@@ -696,7 +716,11 @@ function toMemberDTO(m) {
696
716
  roleId: (0, import_parser.stringOrEmpty)(m.roleId),
697
717
  roleName: (0, import_parser.stringOrEmpty)(m.roleName),
698
718
  confirmed: (0, import_parser.booleanOrFalse)(m.confirmed),
699
- createdAt: (0, import_parser.stringOrEmpty)(m.createdAt)
719
+ createdAt: (0, import_parser.dateOrEmpty)(m.createdAt),
720
+ email: (0, import_parser.stringOrEmpty)(m.email),
721
+ firstName: (0, import_parser.stringOrEmpty)(m.firstName),
722
+ lastName: (0, import_parser.stringOrEmpty)(m.lastName),
723
+ profileImageUrl: (0, import_parser.stringOrEmpty)(m.profileImageUrl)
700
724
  };
701
725
  }
702
726
  function toInvitationDTO(inv) {
@@ -707,8 +731,8 @@ function toInvitationDTO(inv) {
707
731
  roleId: (0, import_parser.stringOrEmpty)(inv.roleId),
708
732
  token: (0, import_parser.stringOrEmpty)(inv.token),
709
733
  status: (0, import_parser.stringOrEmpty)(inv.status),
710
- expiresAt: (0, import_parser.stringOrEmpty)(inv.expiresAt),
711
- createdAt: (0, import_parser.stringOrEmpty)(inv.createdAt)
734
+ expiresAt: (0, import_parser.dateOrEmpty)(inv.expiresAt),
735
+ createdAt: (0, import_parser.dateOrEmpty)(inv.createdAt)
712
736
  };
713
737
  }
714
738
  function toSettingsDTO(s) {
@@ -1027,6 +1051,24 @@ function roleController(store) {
1027
1051
  await roles.delete(roleId, ctx.workspace.id);
1028
1052
  return (0, import_core4.setApiResponse)(import_core4.HTTP.OK, "ROLE_DELETED", "Role deleted successfully.");
1029
1053
  },
1054
+ async getPermissions(ctx) {
1055
+ if (!ctx.workspace) {
1056
+ return (0, import_core4.setApiResponse)(import_core4.HTTP.NOT_FOUND, "NOT_FOUND", "Workspace not found");
1057
+ }
1058
+ const params = ctx.meta["params"];
1059
+ const roleId = params?.["roleId"];
1060
+ if (!roleId) {
1061
+ return (0, import_core4.setApiResponse)(import_core4.HTTP.UNPROCESSABLE, "INVALID_PARAMETER", "roleId is required");
1062
+ }
1063
+ const role = await roles.findById(roleId);
1064
+ if (!role) {
1065
+ return (0, import_core4.setApiResponse)(import_core4.HTTP.NOT_FOUND, "NOT_FOUND", "Role not found");
1066
+ }
1067
+ const permissions = await roles.getPermissions(roleId, ctx.workspace.id);
1068
+ return (0, import_core4.setApiResponse)(import_core4.HTTP.OK, "PERMISSIONS_FETCHED", "Role permissions retrieved successfully.", {
1069
+ permissions
1070
+ });
1071
+ },
1030
1072
  async setPermissions(ctx) {
1031
1073
  if (!ctx.workspace) {
1032
1074
  return (0, import_core4.setApiResponse)(import_core4.HTTP.NOT_FOUND, "NOT_FOUND", "Workspace not found");
@@ -1337,6 +1379,7 @@ function buildWorkspaceRoutes(store, config, bus) {
1337
1379
  R("getRole", "GET", "/workspaces/roles/:roleId", import_middlewares.requireAuth, wsCtx, role.get),
1338
1380
  R("updateRole", "PUT", "/workspaces/roles/:roleId", import_middlewares.requireAuth, wsCtx, (0, import_middlewares.validate)(updateRoleSchema), role.update),
1339
1381
  R("removeRole", "DELETE", "/workspaces/roles/:roleId", import_middlewares.requireAuth, wsCtx, role.remove),
1382
+ R("getRolePermissions", "GET", "/workspaces/roles/:roleId/permissions", import_middlewares.requireAuth, wsCtx, role.getPermissions),
1340
1383
  R("setRolePermissions", "POST", "/workspaces/roles/:roleId/permissions", import_middlewares.requireAuth, wsCtx, (0, import_middlewares.validate)(setRolePermissionsSchema), role.setPermissions),
1341
1384
  // ── Workspace lifecycle
1342
1385
  R("archive", "POST", "/workspaces/archive", import_middlewares.requireAuth, wsCtx, workspace.archive),
@@ -1493,11 +1536,36 @@ async function importMembership(store, m) {
1493
1536
  vals
1494
1537
  );
1495
1538
  }
1539
+
1540
+ // src/retention.ts
1541
+ async function deleteUserData(store, userId) {
1542
+ const rows = await store.query(
1543
+ `DELETE FROM fonderie_role_user_workspaces WHERE user_id = $1 RETURNING user_id`,
1544
+ [userId]
1545
+ );
1546
+ return rows.length;
1547
+ }
1548
+ async function exportUserData(store, userId) {
1549
+ const rows = await store.query(
1550
+ `SELECT ruw.workspace_id, ruw.role_id, r.name AS role_name
1551
+ FROM fonderie_role_user_workspaces ruw
1552
+ JOIN fonderie_roles r ON r.id = ruw.role_id
1553
+ WHERE ruw.user_id = $1 AND ruw.removed = false
1554
+ ORDER BY ruw.workspace_id`,
1555
+ [userId]
1556
+ );
1557
+ return { memberships: rows };
1558
+ }
1559
+ function workspaceExportContributor(store) {
1560
+ return { name: "workspaces", collect: (userId) => exportUserData(store, userId) };
1561
+ }
1496
1562
  // Annotate the CommonJS export names for ESM import in node:
1497
1563
  0 && (module.exports = {
1498
1564
  EVENT_KEYS,
1499
1565
  MESSAGE_KEYS,
1500
1566
  WorkspacesModule,
1567
+ deleteUserData,
1568
+ exportUserData,
1501
1569
  importMembership,
1502
1570
  importRole,
1503
1571
  importWorkspace,
@@ -1508,6 +1576,7 @@ async function importMembership(store, m) {
1508
1576
  toRoleDTO,
1509
1577
  toSettingsDTO,
1510
1578
  toWorkspaceDTO,
1511
- withWorkspace
1579
+ withWorkspace,
1580
+ workspaceExportContributor
1512
1581
  });
1513
1582
  //# sourceMappingURL=index.cjs.map