@arcote.tech/arc-workspace 0.4.10 → 0.5.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arcote.tech/arc-workspace",
3
3
  "type": "module",
4
- "version": "0.4.10",
4
+ "version": "0.5.0",
5
5
  "private": false,
6
6
  "description": "Reusable workspace module for Arc framework — multi-workspace with dual token architecture",
7
7
  "main": "./src/index.ts",
@@ -10,8 +10,8 @@
10
10
  "type-check": "tsc --noEmit"
11
11
  },
12
12
  "peerDependencies": {
13
- "@arcote.tech/arc": "^0.4.10",
14
- "@arcote.tech/arc-auth": "^0.4.10",
13
+ "@arcote.tech/arc": "^0.5.0",
14
+ "@arcote.tech/arc-auth": "^0.5.0",
15
15
  "typescript": "^5.0.0"
16
16
  },
17
17
  "devDependencies": {
@@ -1,9 +1,4 @@
1
- import {
2
- aggregate,
3
- date,
4
- string,
5
- type ArcId,
6
- } from "@arcote.tech/arc";
1
+ import { aggregate, date, string, type ArcId } from "@arcote.tech/arc";
7
2
  import type { Token } from "@arcote.tech/arc-auth";
8
3
  import type { WorkspaceToken } from "../tokens/workspace-token";
9
4
 
@@ -17,7 +12,8 @@ export type WorkspaceInvitationAggregateData = {
17
12
  };
18
13
 
19
14
  function generateInviteToken(): string {
20
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
15
+ const chars =
16
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
21
17
  let result = "";
22
18
  for (let i = 0; i < 32; i++) {
23
19
  result += chars.charAt(Math.floor(Math.random() * chars.length));
@@ -39,7 +35,7 @@ export const createWorkspaceInvitationAggregate = <
39
35
  } = data;
40
36
 
41
37
  return aggregate(
42
- `${data.name}WorkspaceInvitations`,
38
+ `${data.name as Data["name"]}WorkspaceInvitations`,
43
39
  workspaceInvitationId,
44
40
  {
45
41
  workspaceId,
@@ -113,107 +109,115 @@ export const createWorkspaceInvitationAggregate = <
113
109
 
114
110
  .mutateMethod(
115
111
  "createInvitation",
116
- {
117
- params: {
118
- workspaceId,
119
- role: string(),
120
- workspaceName: string(),
121
- workspaceType: string(),
122
- email: string().optional(),
123
- },
124
- },
125
- ONLY_SERVER &&
126
- (async (ctx, params) => {
127
- const invId = workspaceInvitationId.generate();
128
- const token = generateInviteToken();
129
- const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 days
130
-
131
- await ctx.invitationCreated.emit({
132
- workspaceInvitationId: invId,
133
- workspaceId: params.workspaceId,
134
- invitedBy: ctx.$auth.params.accountId,
135
- role: params.role,
136
- token,
137
- email: params.email,
138
- workspaceName: params.workspaceName,
139
- workspaceType: params.workspaceType,
140
- expiresAt,
141
- });
142
-
143
- return { workspaceInvitationId: invId, token };
144
- }),
112
+ (fn) =>
113
+ fn
114
+ .withParams({
115
+ workspaceId,
116
+ role: string(),
117
+ workspaceName: string(),
118
+ workspaceType: string(),
119
+ email: string().optional(),
120
+ })
121
+ .handle(
122
+ ONLY_SERVER &&
123
+ (async (ctx, params) => {
124
+ const invId = workspaceInvitationId.generate();
125
+ const token = generateInviteToken();
126
+ const expiresAt = new Date(
127
+ Date.now() + 7 * 24 * 60 * 60 * 1000,
128
+ ); // 7 days
129
+
130
+ await ctx.invitationCreated.emit({
131
+ workspaceInvitationId: invId,
132
+ workspaceId: params.workspaceId,
133
+ invitedBy: ctx.$auth.params.accountId,
134
+ role: params.role,
135
+ token,
136
+ email: params.email,
137
+ workspaceName: params.workspaceName,
138
+ workspaceType: params.workspaceType,
139
+ expiresAt,
140
+ });
141
+
142
+ return { workspaceInvitationId: invId, token };
143
+ }),
144
+ ),
145
145
  )
146
146
 
147
147
  .mutateMethod(
148
148
  "acceptInvitation",
149
- { params: { token: string() } },
150
- ONLY_SERVER &&
151
- (async (ctx, params) => {
152
- const invitation = await ctx.$query.findOne({
153
- token: params.token,
154
- });
155
-
156
- if (!invitation) {
157
- return { error: "INVITATION_NOT_FOUND" as const };
158
- }
159
- if (invitation.status !== "pending") {
160
- return { error: "INVITATION_NOT_VALID" as const };
161
- }
162
- if (new Date(invitation.expiresAt) < new Date()) {
163
- return { error: "INVITATION_EXPIRED" as const };
164
- }
165
-
166
- // Emit accepted event — WorkspaceMember handles adding the member
167
- await ctx.invitationAccepted.emit({
168
- workspaceInvitationId: invitation._id,
169
- workspaceId: invitation.workspaceId,
170
- acceptedBy: ctx.$auth.params.accountId,
171
- role: invitation.role,
172
- workspaceName: invitation.workspaceName,
173
- workspaceType: invitation.workspaceType,
174
- });
175
-
176
- // Generate workspace token for the new member
177
- const wsToken = workspaceToken.generateJWT({
178
- accountId: ctx.$auth.params.accountId,
179
- workspaceId: invitation.workspaceId,
180
- role: invitation.role,
181
- workspaceType: invitation.workspaceType,
182
- });
183
-
184
- return {
185
- success: true,
186
- token: wsToken,
187
- workspaceId: invitation.workspaceId,
188
- };
189
- }),
149
+ (fn) =>
150
+ fn.withParams({ token: string() }).handle(
151
+ ONLY_SERVER &&
152
+ (async (ctx, params) => {
153
+ const invitation = await ctx.$query.findOne({
154
+ token: params.token,
155
+ });
156
+
157
+ if (!invitation) {
158
+ return { error: "INVITATION_NOT_FOUND" as const };
159
+ }
160
+ if (invitation.status !== "pending") {
161
+ return { error: "INVITATION_NOT_VALID" as const };
162
+ }
163
+ if (new Date(invitation.expiresAt) < new Date()) {
164
+ return { error: "INVITATION_EXPIRED" as const };
165
+ }
166
+
167
+ // Emit accepted event — WorkspaceMember handles adding the member
168
+ await ctx.invitationAccepted.emit({
169
+ workspaceInvitationId: invitation._id,
170
+ workspaceId: invitation.workspaceId,
171
+ acceptedBy: ctx.$auth.params.accountId,
172
+ role: invitation.role,
173
+ workspaceName: invitation.workspaceName,
174
+ workspaceType: invitation.workspaceType,
175
+ });
176
+
177
+ // Generate workspace token for the new member
178
+ const wsToken = workspaceToken.generateJWT({
179
+ accountId: ctx.$auth.params.accountId,
180
+ workspaceId: invitation.workspaceId,
181
+ role: invitation.role,
182
+ workspaceType: invitation.workspaceType,
183
+ });
184
+
185
+ return {
186
+ success: true,
187
+ token: wsToken,
188
+ workspaceId: invitation.workspaceId,
189
+ };
190
+ }),
191
+ ),
190
192
  )
191
193
 
192
194
  .mutateMethod(
193
195
  "revokeInvitation",
194
- { params: { workspaceInvitationId } },
195
- ONLY_SERVER &&
196
- (async (ctx, params) => {
197
- const invitation = await ctx.$query.findOne({
198
- _id: params.workspaceInvitationId,
199
- });
200
- if (!invitation || invitation.status !== "pending") {
201
- return { error: "INVITATION_NOT_VALID" as const };
202
- }
203
-
204
- await ctx.invitationRevoked.emit({
205
- workspaceInvitationId: params.workspaceInvitationId,
206
- });
207
-
208
- return { success: true };
209
- }),
196
+ (fn) =>
197
+ fn.withParams({ workspaceInvitationId }).handle(
198
+ ONLY_SERVER &&
199
+ (async (ctx, params) => {
200
+ const invitation = await ctx.$query.findOne({
201
+ _id: params.workspaceInvitationId,
202
+ });
203
+ if (!invitation || invitation.status !== "pending") {
204
+ return { error: "INVITATION_NOT_VALID" as const };
205
+ }
206
+
207
+ await ctx.invitationRevoked.emit({
208
+ workspaceInvitationId: params.workspaceInvitationId,
209
+ });
210
+
211
+ return { success: true };
212
+ }),
213
+ ),
210
214
  )
211
215
 
212
- .protectBy(userToken, (p: any) => ({ invitedBy: p.accountId }))
213
- .clientQuery("getByWorkspace", async (ctx) => ctx.$query.find({}))
214
- ;
216
+ .protectBy(userToken, (p) => ({ invitedBy: p.accountId }))
217
+ .clientQuery("getByWorkspace", (fn) => fn.handle(async (ctx) => ctx.$query.find({})));
215
218
  };
216
219
 
217
220
  export type WorkspaceInvitationAggregate<
218
- Data extends WorkspaceInvitationAggregateData = WorkspaceInvitationAggregateData,
221
+ Data extends WorkspaceInvitationAggregateData =
222
+ WorkspaceInvitationAggregateData,
219
223
  > = ReturnType<typeof createWorkspaceInvitationAggregate<Data>>;
@@ -1,12 +1,8 @@
1
- import {
2
- aggregate,
3
- date,
4
- string,
5
- type ArcAggregateElement,
6
- type ArcId,
7
- } from "@arcote.tech/arc";
1
+ import { aggregate, date, string, type ArcId } from "@arcote.tech/arc";
8
2
  import type { Token } from "@arcote.tech/arc-auth";
9
3
  import type { WorkspaceToken } from "../tokens/workspace-token";
4
+ import type { createWorkspaceAggregate } from "./workspace";
5
+ import type { createWorkspaceInvitationAggregate } from "./workspace-invitation";
10
6
 
11
7
  export type WorkspaceMemberAggregateData = {
12
8
  name: string;
@@ -15,8 +11,10 @@ export type WorkspaceMemberAggregateData = {
15
11
  accountId: ArcId<any>;
16
12
  workspaceToken: WorkspaceToken;
17
13
  userToken: Token;
18
- WorkspaceAggregate: ArcAggregateElement<any, any, any, any, any, any>;
19
- WorkspaceInvitationAggregate?: ArcAggregateElement<any, any, any, any, any, any>;
14
+ WorkspaceAggregate: ReturnType<typeof createWorkspaceAggregate>;
15
+ WorkspaceInvitationAggregate: ReturnType<
16
+ typeof createWorkspaceInvitationAggregate
17
+ >;
20
18
  };
21
19
 
22
20
  export const createWorkspaceMemberAggregate = <
@@ -34,226 +32,238 @@ export const createWorkspaceMemberAggregate = <
34
32
  WorkspaceInvitationAggregate,
35
33
  } = data;
36
34
 
37
- const workspaceCreatedEvent = WorkspaceAggregate.getEvent("workspaceCreated");
35
+ const name = data.name as Data["name"];
38
36
 
39
- let Constructor = aggregate(
40
- `${data.name}WorkspaceMembers`,
41
- workspaceMemberId,
42
- {
37
+ return (
38
+ aggregate(`${name}WorkspaceMembers`, workspaceMemberId, {
43
39
  workspaceId,
44
40
  accountId,
45
41
  role: string(),
46
42
  workspaceName: string(),
47
43
  workspaceType: string(),
48
44
  joinedAt: date(),
49
- },
50
- )
51
- .publicEvent(
52
- "workspaceMemberAdded",
53
- {
54
- workspaceMemberId,
55
- workspaceId,
56
- accountId,
57
- role: string(),
58
- workspaceName: string(),
59
- workspaceType: string(),
60
- },
61
- async (ctx, event) => {
62
- const {
63
- workspaceMemberId: id,
64
- workspaceId: wsId,
65
- accountId: accId,
66
- role,
67
- workspaceName,
68
- workspaceType,
69
- } = event.payload;
70
- await ctx.set(id, {
71
- workspaceId: wsId,
72
- accountId: accId,
73
- role,
74
- workspaceName,
75
- workspaceType,
76
- joinedAt: event.createdAt,
77
- });
78
- },
79
- )
80
-
81
- .publicEvent(
82
- "workspaceMemberRemoved",
83
- { workspaceMemberId },
84
- async (ctx, event) => {
85
- await ctx.remove(event.payload.workspaceMemberId);
86
- },
87
- )
88
-
89
- .publicEvent(
90
- "workspaceMemberRoleChanged",
91
- {
92
- workspaceMemberId,
93
- role: string(),
94
- },
95
- async (ctx, event) => {
96
- await ctx.modify(event.payload.workspaceMemberId, {
97
- role: event.payload.role,
98
- });
99
- },
100
- )
101
-
102
- // Auto-create owner membership when workspace is created
103
- .handleEvent(workspaceCreatedEvent, async (ctx, event) => {
104
- await ctx.set(event.payload.ownerMemberId, {
105
- workspaceId: event.payload.workspaceId,
106
- accountId: event.payload.ownerId,
107
- role: "owner",
108
- workspaceName: event.payload.name,
109
- workspaceType: event.payload.type,
110
- joinedAt: event.createdAt,
111
- });
112
45
  })
113
-
114
- // Remove all members when workspace is archived
115
- .handleEvent(WorkspaceAggregate.getEvent("workspaceArchived"), async (ctx, event) => {
116
- const members = await ctx.find({
117
- where: { workspaceId: event.payload.workspaceId },
118
- });
119
- for (const member of members) {
120
- await ctx.remove(member._id);
121
- }
122
- })
123
-
124
- // Sync workspace name to all members when workspace is renamed
125
- .handleEvent(WorkspaceAggregate.getEvent("workspaceRenamed"), async (ctx, event) => {
126
- const members = await ctx.find({
127
- where: { workspaceId: event.payload.workspaceId },
128
- });
129
- for (const member of members) {
130
- await ctx.modify(member._id, {
131
- workspaceName: event.payload.name,
132
- });
133
- }
134
- })
135
-
136
- ;
137
-
138
- // Auto-add member when invitation is accepted
139
- if (WorkspaceInvitationAggregate) {
140
- const invitationAcceptedEvent = WorkspaceInvitationAggregate.getEvent("invitationAccepted");
141
- Constructor = Constructor.handleEvent(invitationAcceptedEvent, async (ctx, event) => {
142
- const p = event.payload;
143
- const memberId = workspaceMemberId.generate();
144
- await ctx.set(memberId, {
145
- workspaceId: p.workspaceId,
146
- accountId: p.acceptedBy,
147
- role: p.role,
148
- workspaceName: p.workspaceName,
149
- workspaceType: p.workspaceType,
150
- joinedAt: event.createdAt,
151
- });
152
- });
153
- }
154
-
155
- Constructor = Constructor.mutateMethod(
156
- "addMember",
157
- {
158
- params: {
46
+ .publicEvent(
47
+ "memberAdded",
48
+ {
49
+ workspaceMemberId,
159
50
  workspaceId,
160
51
  accountId,
161
52
  role: string(),
162
53
  workspaceName: string(),
163
54
  workspaceType: string(),
164
55
  },
165
- },
166
- ONLY_SERVER &&
167
- (async (ctx, params) => {
168
- const existing = await ctx.$query.findOne({
169
- workspaceId: params.workspaceId,
170
- accountId: params.accountId,
171
- });
172
- if (existing) {
173
- return { error: "ALREADY_A_MEMBER" as const };
174
- }
175
-
176
- const id = workspaceMemberId.generate();
177
-
178
- await ctx.workspaceMemberAdded.emit({
56
+ async (ctx, event) => {
57
+ const {
179
58
  workspaceMemberId: id,
180
- workspaceId: params.workspaceId,
181
- accountId: params.accountId,
182
- role: params.role,
183
- workspaceName: params.workspaceName,
184
- workspaceType: params.workspaceType,
59
+ workspaceId: wsId,
60
+ accountId: accId,
61
+ role,
62
+ workspaceName,
63
+ workspaceType,
64
+ } = event.payload;
65
+ await ctx.set(id, {
66
+ workspaceId: wsId,
67
+ accountId: accId,
68
+ role,
69
+ workspaceName,
70
+ workspaceType,
71
+ joinedAt: event.createdAt,
185
72
  });
73
+ },
74
+ )
186
75
 
187
- return { workspaceMemberId: id };
188
- }),
189
- )
190
-
191
- .mutateMethod(
192
- "removeMember",
193
- { params: { workspaceMemberId } },
194
- ONLY_SERVER &&
195
- (async (ctx, params) => {
196
- await ctx.workspaceMemberRemoved.emit({
197
- workspaceMemberId: params.workspaceMemberId,
198
- });
199
- }),
200
- )
76
+ .publicEvent(
77
+ "memberRemoved",
78
+ { workspaceMemberId },
79
+ async (ctx, event) => {
80
+ await ctx.remove(event.payload.workspaceMemberId);
81
+ },
82
+ )
201
83
 
202
- .mutateMethod(
203
- "changeRole",
204
- {
205
- params: {
84
+ .publicEvent(
85
+ "roleChanged",
86
+ {
206
87
  workspaceMemberId,
207
88
  role: string(),
208
89
  },
209
- },
210
- ONLY_SERVER &&
211
- (async (ctx, params) => {
212
- await ctx.workspaceMemberRoleChanged.emit({
213
- workspaceMemberId: params.workspaceMemberId,
214
- role: params.role,
90
+ async (ctx, event) => {
91
+ await ctx.modify(event.payload.workspaceMemberId, {
92
+ role: event.payload.role,
215
93
  });
216
- }),
217
- )
94
+ },
95
+ )
218
96
 
219
- .mutateMethod(
220
- "switchWorkspace",
221
- { params: { workspaceMemberId } },
222
- ONLY_SERVER &&
223
- (async (ctx, params) => {
224
- const member = await ctx.$query.findOne({
225
- _id: params.workspaceMemberId,
97
+ // Auto-create owner membership when workspace is created
98
+ .handleEvent(
99
+ WorkspaceAggregate.getEvent("workspaceCreated"),
100
+ async (ctx, event) => {
101
+ await ctx.set(event.payload.ownerMemberId, {
102
+ workspaceId: event.payload.workspaceId,
103
+ accountId: event.payload.ownerId,
104
+ role: "owner",
105
+ workspaceName: event.payload.name,
106
+ workspaceType: event.payload.type,
107
+ joinedAt: event.createdAt,
226
108
  });
109
+ },
110
+ )
227
111
 
228
- if (!member) {
229
- return { error: "NOT_A_MEMBER" as const };
112
+ // Remove all members when workspace is archived
113
+ .handleEvent(
114
+ WorkspaceAggregate.getEvent("workspaceArchived"),
115
+ async (ctx, event) => {
116
+ const members = await ctx.find({
117
+ where: { workspaceId: event.payload.workspaceId },
118
+ });
119
+ for (const member of members) {
120
+ await ctx.remove(member._id);
230
121
  }
122
+ },
123
+ )
231
124
 
232
- if (
233
- ctx.$auth.params.accountId &&
234
- ctx.$auth.params.accountId !== member.accountId
235
- ) {
236
- return { error: "NOT_A_MEMBER" as const };
125
+ // Sync workspace name to all members when workspace is renamed
126
+ .handleEvent(
127
+ WorkspaceAggregate.getEvent("workspaceRenamed"),
128
+ async (ctx, event) => {
129
+ const members = await ctx.find({
130
+ where: { workspaceId: event.payload.workspaceId },
131
+ });
132
+ for (const member of members) {
133
+ await ctx.modify(member._id, {
134
+ workspaceName: event.payload.name,
135
+ });
237
136
  }
137
+ },
138
+ )
238
139
 
239
- const token = workspaceToken.generateJWT({
240
- accountId: member.accountId,
241
- workspaceId: member.workspaceId,
242
- role: member.role,
243
- workspaceType: member.workspaceType,
140
+ // Auto-add member when invitation is accepted
141
+ .handleEvent(
142
+ WorkspaceInvitationAggregate.getEvent("invitationAccepted"),
143
+ async (ctx, event) => {
144
+ const p = event.payload;
145
+ const memberId = workspaceMemberId.generate();
146
+ await ctx.set(memberId, {
147
+ workspaceId: p.workspaceId,
148
+ accountId: p.acceptedBy,
149
+ role: p.role,
150
+ workspaceName: p.workspaceName,
151
+ workspaceType: p.workspaceType,
152
+ joinedAt: event.createdAt,
244
153
  });
154
+ },
155
+ )
156
+
157
+ .mutateMethod(
158
+ "addMember",
159
+ (fn) =>
160
+ fn
161
+ .withParams({
162
+ workspaceId,
163
+ accountId,
164
+ role: string(),
165
+ workspaceName: string(),
166
+ workspaceType: string(),
167
+ })
168
+ .handle(
169
+ ONLY_SERVER &&
170
+ (async (ctx, params) => {
171
+ const existing = await ctx.$query.findOne({
172
+ workspaceId: params.workspaceId,
173
+ accountId: params.accountId,
174
+ });
175
+ if (existing) {
176
+ return { error: "ALREADY_A_MEMBER" as const };
177
+ }
178
+
179
+ const id = workspaceMemberId.generate();
180
+
181
+ await ctx.memberAdded.emit({
182
+ workspaceMemberId: id,
183
+ workspaceId: params.workspaceId,
184
+ accountId: params.accountId,
185
+ role: params.role,
186
+ workspaceName: params.workspaceName,
187
+ workspaceType: params.workspaceType,
188
+ });
189
+
190
+ return { workspaceMemberId: id };
191
+ }),
192
+ ),
193
+ )
194
+
195
+ .mutateMethod(
196
+ "removeMember",
197
+ (fn) =>
198
+ fn.withParams({ workspaceMemberId }).handle(
199
+ ONLY_SERVER &&
200
+ (async (ctx, params) => {
201
+ await ctx.memberRemoved.emit({
202
+ workspaceMemberId: params.workspaceMemberId,
203
+ });
204
+ }),
205
+ ),
206
+ )
207
+
208
+ .mutateMethod(
209
+ "changeRole",
210
+ (fn) =>
211
+ fn
212
+ .withParams({
213
+ workspaceMemberId,
214
+ role: string(),
215
+ })
216
+ .handle(
217
+ ONLY_SERVER &&
218
+ (async (ctx, params) => {
219
+ await ctx.roleChanged.emit({
220
+ workspaceMemberId: params.workspaceMemberId,
221
+ role: params.role,
222
+ });
223
+ }),
224
+ ),
225
+ )
226
+
227
+ .mutateMethod(
228
+ "switchWorkspace",
229
+ (fn) =>
230
+ fn.withParams({ workspaceMemberId }).handle(
231
+ ONLY_SERVER &&
232
+ (async (ctx, params) => {
233
+ const member = await ctx.$query.findOne({
234
+ _id: params.workspaceMemberId,
235
+ });
236
+
237
+ if (!member) {
238
+ return { error: "NOT_A_MEMBER" as const };
239
+ }
240
+
241
+ if (
242
+ ctx.$auth.params.accountId &&
243
+ ctx.$auth.params.accountId !== member.accountId
244
+ ) {
245
+ return { error: "NOT_A_MEMBER" as const };
246
+ }
245
247
 
246
- return { token };
247
- }),
248
- )
248
+ const token = workspaceToken.generateJWT({
249
+ accountId: member.accountId,
250
+ workspaceId: member.workspaceId,
251
+ role: member.role,
252
+ workspaceType: member.workspaceType,
253
+ });
249
254
 
250
- .protectBy(userToken, (params: any) => ({ accountId: params.accountId }))
251
- .protectBy(workspaceToken, (params: any) => ({ workspaceId: params.workspaceId }))
252
- .clientQuery("getAll", async (ctx) => ctx.$query.find({}))
253
- .clientQuery("getByWorkspace", async (ctx) => ctx.$query.find({}))
254
- ;
255
+ return { token };
256
+ }),
257
+ ),
258
+ )
255
259
 
256
- return Constructor;
260
+ .protectBy(userToken, (params) => ({ accountId: params.accountId }))
261
+ .protectBy(workspaceToken, (params) => ({
262
+ workspaceId: params.workspaceId,
263
+ }))
264
+ .clientQuery("getAll", (fn) => fn.handle(async (ctx) => ctx.$query.find({})))
265
+ .clientQuery("getByWorkspace", (fn) => fn.handle(async (ctx) => ctx.$query.find({})))
266
+ );
257
267
  };
258
268
 
259
269
  export type WorkspaceMemberAggregate<
@@ -16,7 +16,7 @@ export const createWorkspaceAggregate = <
16
16
  ) => {
17
17
  const { workspaceId, workspaceMemberId, accountId, workspaceToken } = data;
18
18
 
19
- return aggregate(`${data.name}Workspaces`, workspaceId, {
19
+ return aggregate(`${data.name as Data["name"]}Workspaces`, workspaceId, {
20
20
  name: string().minLength(1).maxLength(100),
21
21
  type: string(),
22
22
  ownerId: accountId,
@@ -59,95 +59,96 @@ export const createWorkspaceAggregate = <
59
59
 
60
60
  .mutateMethod(
61
61
  "create",
62
- {
63
- params: {
64
- name: string().minLength(1).maxLength(100),
65
- type: string(),
66
- },
67
- },
68
- ONLY_SERVER &&
69
- (async (ctx, params) => {
70
- const id = workspaceId.generate();
71
- const ownerMemberId = workspaceMemberId.generate();
72
- const ownerId = ctx.$auth.params.accountId;
73
-
74
- await ctx.workspaceCreated.emit({
75
- workspaceId: id,
76
- ownerMemberId,
77
- name: params.name,
78
- type: params.type,
79
- ownerId,
80
- });
81
-
82
- const token = workspaceToken.generateJWT({
83
- accountId: ownerId,
84
- workspaceId: id,
85
- role: "owner",
86
- workspaceType: params.type,
87
- });
88
-
89
- return { workspaceId: id, token, accountId: ownerId };
90
- }),
62
+ (fn) =>
63
+ fn
64
+ .withParams({
65
+ name: string().minLength(1).maxLength(100),
66
+ type: string(),
67
+ })
68
+ .handle(
69
+ ONLY_SERVER &&
70
+ (async (ctx, params) => {
71
+ const id = workspaceId.generate();
72
+ const ownerMemberId = workspaceMemberId.generate();
73
+ const ownerId = ctx.$auth.params.accountId;
74
+
75
+ await ctx.workspaceCreated.emit({
76
+ workspaceId: id,
77
+ ownerMemberId,
78
+ name: params.name,
79
+ type: params.type,
80
+ ownerId,
81
+ });
82
+
83
+ const token = workspaceToken.generateJWT({
84
+ accountId: ownerId,
85
+ workspaceId: id,
86
+ role: "owner",
87
+ workspaceType: params.type,
88
+ });
89
+
90
+ return { workspaceId: id, token, accountId: ownerId };
91
+ }),
92
+ ),
91
93
  )
92
94
 
93
95
  .mutateMethod(
94
96
  "rename",
95
- {
96
- params: {
97
- workspaceId,
98
- name: string().minLength(1).maxLength(100),
99
- },
100
- },
101
- ONLY_SERVER &&
102
- (async (ctx, params) => {
103
- const existing = await ctx.$query.findOne({
104
- _id: params.workspaceId,
105
- });
106
- if (!existing) {
107
- return { error: "WORKSPACE_NOT_FOUND" as const };
108
- }
109
-
110
- await ctx.workspaceRenamed.emit({
111
- workspaceId: params.workspaceId,
112
- name: params.name,
113
- });
114
-
115
- return { success: true };
116
- }),
97
+ (fn) =>
98
+ fn
99
+ .withParams({
100
+ workspaceId,
101
+ name: string().minLength(1).maxLength(100),
102
+ })
103
+ .handle(
104
+ ONLY_SERVER &&
105
+ (async (ctx, params) => {
106
+ const existing = await ctx.$query.findOne({
107
+ _id: params.workspaceId,
108
+ });
109
+ if (!existing) {
110
+ return { error: "WORKSPACE_NOT_FOUND" as const };
111
+ }
112
+
113
+ await ctx.workspaceRenamed.emit({
114
+ workspaceId: params.workspaceId,
115
+ name: params.name,
116
+ });
117
+
118
+ return { success: true };
119
+ }),
120
+ ),
117
121
  )
118
122
 
119
- .publicEvent(
120
- "workspaceArchived",
121
- { workspaceId },
122
- async (ctx, event) => {
123
- await ctx.modify(event.payload.workspaceId, {
124
- isArchived: true,
125
- });
126
- },
127
- )
123
+ .publicEvent("workspaceArchived", { workspaceId }, async (ctx, event) => {
124
+ await ctx.modify(event.payload.workspaceId, {
125
+ isArchived: true,
126
+ });
127
+ })
128
128
 
129
129
  .mutateMethod(
130
130
  "archive",
131
- { params: { workspaceId } },
132
- ONLY_SERVER &&
133
- (async (ctx, params) => {
134
- const existing = await ctx.$query.findOne({
135
- _id: params.workspaceId,
136
- });
137
- if (!existing) {
138
- return { error: "WORKSPACE_NOT_FOUND" as const };
139
- }
140
-
141
- await ctx.workspaceArchived.emit({
142
- workspaceId: params.workspaceId,
143
- });
144
-
145
- return { success: true };
146
- }),
131
+ (fn) =>
132
+ fn.withParams({ workspaceId }).handle(
133
+ ONLY_SERVER &&
134
+ (async (ctx, params) => {
135
+ const existing = await ctx.$query.findOne({
136
+ _id: params.workspaceId,
137
+ });
138
+ if (!existing) {
139
+ return { error: "WORKSPACE_NOT_FOUND" as const };
140
+ }
141
+
142
+ await ctx.workspaceArchived.emit({
143
+ workspaceId: params.workspaceId,
144
+ });
145
+
146
+ return { success: true };
147
+ }),
148
+ ),
147
149
  )
148
150
 
149
- .clientQuery("getAll", async (ctx) => ctx.$query.find({}))
150
- ;
151
+ .clientQuery("getAll", (fn) => fn.handle(async (ctx) => ctx.$query.find({})));
151
152
  };
152
153
 
153
154
  export type WorkspaceAggregate<
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  context,
3
- type ArcAggregateElement,
4
3
  type ArcContextElement,
5
4
  } from "@arcote.tech/arc";
6
5
  import type { AccountId, Token } from "@arcote.tech/arc-auth";
@@ -17,9 +16,9 @@ export class WorkspaceBuilder<
17
16
  WsMemberId,
18
17
  WsInvId,
19
18
  WsToken,
20
- Workspace extends ArcAggregateElement,
21
- WorkspaceMember extends ArcAggregateElement,
22
- WorkspaceInvitation extends ArcAggregateElement,
19
+ Workspace,
20
+ WorkspaceMember,
21
+ WorkspaceInvitation,
23
22
  Types extends readonly string[],
24
23
  Elements extends ArcContextElement<any>[],
25
24
  > {