@shipfox/api-workspaces 7.1.0 → 9.0.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.
Files changed (46) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +68 -0
  3. package/README.md +1 -5
  4. package/dist/core/entities/workspace.d.ts +1 -0
  5. package/dist/core/entities/workspace.d.ts.map +1 -1
  6. package/dist/core/entities/workspace.js.map +1 -1
  7. package/dist/core/workspaces.d.ts +3 -0
  8. package/dist/core/workspaces.d.ts.map +1 -1
  9. package/dist/core/workspaces.js +6 -1
  10. package/dist/core/workspaces.js.map +1 -1
  11. package/dist/db/db.d.ts +34 -0
  12. package/dist/db/db.d.ts.map +1 -1
  13. package/dist/db/schema/common.d.ts.map +1 -1
  14. package/dist/db/schema/common.js +1 -1
  15. package/dist/db/schema/common.js.map +1 -1
  16. package/dist/db/schema/workspaces.d.ts +17 -0
  17. package/dist/db/schema/workspaces.d.ts.map +1 -1
  18. package/dist/db/schema/workspaces.js +3 -1
  19. package/dist/db/schema/workspaces.js.map +1 -1
  20. package/dist/index.js +2 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/presentation/inter-module.d.ts.map +1 -1
  23. package/dist/presentation/inter-module.js +15 -1
  24. package/dist/presentation/inter-module.js.map +1 -1
  25. package/dist/tsconfig.test.tsbuildinfo +1 -1
  26. package/drizzle/0000_initial.sql +50 -1
  27. package/drizzle/meta/0000_snapshot.json +377 -3
  28. package/drizzle/meta/_journal.json +0 -28
  29. package/package.json +26 -19
  30. package/src/core/entities/workspace.ts +1 -0
  31. package/src/core/workspaces.ts +9 -1
  32. package/src/db/schema/common.ts +1 -3
  33. package/src/db/schema/workspaces.ts +3 -1
  34. package/src/index.ts +1 -1
  35. package/src/presentation/inter-module.test.ts +71 -0
  36. package/src/presentation/inter-module.ts +15 -1
  37. package/test/factories/workspace.ts +1 -0
  38. package/test/globalSetup.ts +1 -1
  39. package/tsconfig.build.tsbuildinfo +1 -1
  40. package/drizzle/0001_memberships_invitations.sql +0 -30
  41. package/drizzle/0002_membership_user_snapshots.sql +0 -40
  42. package/drizzle/0003_outgoing_enchantress.sql +0 -16
  43. package/drizzle/0004_tired_talon.sql +0 -1
  44. package/drizzle/meta/0001_snapshot.json +0 -705
  45. package/drizzle/meta/0003_snapshot.json +0 -442
  46. package/drizzle/meta/0004_snapshot.json +0 -448
@@ -1,9 +1,58 @@
1
1
  CREATE TYPE "public"."workspaces_workspace_status" AS ENUM('active', 'suspended', 'deleted');--> statement-breakpoint
2
- CREATE TABLE "workspaces" (
2
+ CREATE TABLE "workspaces_invitations" (
3
+ "id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
4
+ "workspace_id" uuid NOT NULL,
5
+ "email" text NOT NULL,
6
+ "hashed_token" text NOT NULL,
7
+ "expires_at" timestamp with time zone NOT NULL,
8
+ "revoked_at" timestamp with time zone,
9
+ "accepted_at" timestamp with time zone,
10
+ "accepted_by_user_id" uuid,
11
+ "invited_by_user_id" uuid NOT NULL,
12
+ "invited_by_display" text,
13
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
14
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
15
+ );
16
+ --> statement-breakpoint
17
+ CREATE TABLE "workspaces_memberships" (
18
+ "id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
19
+ "user_id" uuid NOT NULL,
20
+ "user_email" text NOT NULL,
21
+ "user_name" text,
22
+ "workspace_id" uuid NOT NULL,
23
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
24
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
25
+ );
26
+ --> statement-breakpoint
27
+ CREATE TABLE "workspaces_outbox" (
28
+ "id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
29
+ "event_type" text NOT NULL,
30
+ "ordering_key" text,
31
+ "payload" jsonb NOT NULL,
32
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
33
+ "dispatched_at" timestamp with time zone,
34
+ "dispatch_attempts" integer DEFAULT 0 NOT NULL,
35
+ "next_dispatch_at" timestamp with time zone DEFAULT now() NOT NULL,
36
+ "last_dispatch_error" jsonb,
37
+ "last_dispatch_failed_at" timestamp with time zone,
38
+ "dead_lettered_at" timestamp with time zone
39
+ );
40
+ --> statement-breakpoint
41
+ CREATE TABLE "workspaces_workspaces" (
3
42
  "id" uuid PRIMARY KEY DEFAULT uuidv7() NOT NULL,
4
43
  "name" text NOT NULL,
5
44
  "status" "workspaces_workspace_status" DEFAULT 'active' NOT NULL,
6
45
  "settings" jsonb DEFAULT '{}'::jsonb NOT NULL,
46
+ "created_by" uuid,
7
47
  "created_at" timestamp with time zone DEFAULT now() NOT NULL,
8
48
  "updated_at" timestamp with time zone DEFAULT now() NOT NULL
9
49
  );
50
+ --> statement-breakpoint
51
+ ALTER TABLE "workspaces_invitations" ADD CONSTRAINT "workspaces_invitations_workspace_id_workspaces_workspaces_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces_workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
52
+ ALTER TABLE "workspaces_memberships" ADD CONSTRAINT "workspaces_memberships_workspace_id_workspaces_workspaces_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces_workspaces"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
53
+ CREATE UNIQUE INDEX "workspaces_invitations_hashed_token_unique" ON "workspaces_invitations" USING btree ("hashed_token");--> statement-breakpoint
54
+ CREATE INDEX "workspaces_invitations_workspace_email_idx" ON "workspaces_invitations" USING btree ("workspace_id","email");--> statement-breakpoint
55
+ CREATE UNIQUE INDEX "workspaces_memberships_user_workspace_unique" ON "workspaces_memberships" USING btree ("user_id","workspace_id");--> statement-breakpoint
56
+ CREATE INDEX "workspaces_memberships_workspace_id_idx" ON "workspaces_memberships" USING btree ("workspace_id");--> statement-breakpoint
57
+ CREATE INDEX "workspaces_outbox_pending_idx" ON "workspaces_outbox" USING btree ("next_dispatch_at","created_at") WHERE "dispatched_at" IS NULL AND "dead_lettered_at" IS NULL;--> statement-breakpoint
58
+ CREATE INDEX "workspaces_outbox_dispatched_retention_idx" ON "workspaces_outbox" USING btree ("dispatched_at","id") WHERE "dispatched_at" IS NOT NULL;
@@ -1,11 +1,379 @@
1
1
  {
2
- "id": "0d727c74-5924-496b-94b6-df0c8943fcc4",
2
+ "id": "074ad011-b8db-44f8-b880-47460ca229d2",
3
3
  "prevId": "00000000-0000-0000-0000-000000000000",
4
4
  "version": "7",
5
5
  "dialect": "postgresql",
6
6
  "tables": {
7
- "public.workspaces": {
8
- "name": "workspaces",
7
+ "public.workspaces_invitations": {
8
+ "name": "workspaces_invitations",
9
+ "schema": "",
10
+ "columns": {
11
+ "id": {
12
+ "name": "id",
13
+ "type": "uuid",
14
+ "primaryKey": true,
15
+ "notNull": true,
16
+ "default": "uuidv7()"
17
+ },
18
+ "workspace_id": {
19
+ "name": "workspace_id",
20
+ "type": "uuid",
21
+ "primaryKey": false,
22
+ "notNull": true
23
+ },
24
+ "email": {
25
+ "name": "email",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true
29
+ },
30
+ "hashed_token": {
31
+ "name": "hashed_token",
32
+ "type": "text",
33
+ "primaryKey": false,
34
+ "notNull": true
35
+ },
36
+ "expires_at": {
37
+ "name": "expires_at",
38
+ "type": "timestamp with time zone",
39
+ "primaryKey": false,
40
+ "notNull": true
41
+ },
42
+ "revoked_at": {
43
+ "name": "revoked_at",
44
+ "type": "timestamp with time zone",
45
+ "primaryKey": false,
46
+ "notNull": false
47
+ },
48
+ "accepted_at": {
49
+ "name": "accepted_at",
50
+ "type": "timestamp with time zone",
51
+ "primaryKey": false,
52
+ "notNull": false
53
+ },
54
+ "accepted_by_user_id": {
55
+ "name": "accepted_by_user_id",
56
+ "type": "uuid",
57
+ "primaryKey": false,
58
+ "notNull": false
59
+ },
60
+ "invited_by_user_id": {
61
+ "name": "invited_by_user_id",
62
+ "type": "uuid",
63
+ "primaryKey": false,
64
+ "notNull": true
65
+ },
66
+ "invited_by_display": {
67
+ "name": "invited_by_display",
68
+ "type": "text",
69
+ "primaryKey": false,
70
+ "notNull": false
71
+ },
72
+ "created_at": {
73
+ "name": "created_at",
74
+ "type": "timestamp with time zone",
75
+ "primaryKey": false,
76
+ "notNull": true,
77
+ "default": "now()"
78
+ },
79
+ "updated_at": {
80
+ "name": "updated_at",
81
+ "type": "timestamp with time zone",
82
+ "primaryKey": false,
83
+ "notNull": true,
84
+ "default": "now()"
85
+ }
86
+ },
87
+ "indexes": {
88
+ "workspaces_invitations_hashed_token_unique": {
89
+ "name": "workspaces_invitations_hashed_token_unique",
90
+ "columns": [
91
+ {
92
+ "expression": "hashed_token",
93
+ "isExpression": false,
94
+ "asc": true,
95
+ "nulls": "last"
96
+ }
97
+ ],
98
+ "isUnique": true,
99
+ "concurrently": false,
100
+ "method": "btree",
101
+ "with": {}
102
+ },
103
+ "workspaces_invitations_workspace_email_idx": {
104
+ "name": "workspaces_invitations_workspace_email_idx",
105
+ "columns": [
106
+ {
107
+ "expression": "workspace_id",
108
+ "isExpression": false,
109
+ "asc": true,
110
+ "nulls": "last"
111
+ },
112
+ {
113
+ "expression": "email",
114
+ "isExpression": false,
115
+ "asc": true,
116
+ "nulls": "last"
117
+ }
118
+ ],
119
+ "isUnique": false,
120
+ "concurrently": false,
121
+ "method": "btree",
122
+ "with": {}
123
+ }
124
+ },
125
+ "foreignKeys": {
126
+ "workspaces_invitations_workspace_id_workspaces_workspaces_id_fk": {
127
+ "name": "workspaces_invitations_workspace_id_workspaces_workspaces_id_fk",
128
+ "tableFrom": "workspaces_invitations",
129
+ "tableTo": "workspaces_workspaces",
130
+ "columnsFrom": ["workspace_id"],
131
+ "columnsTo": ["id"],
132
+ "onDelete": "cascade",
133
+ "onUpdate": "no action"
134
+ }
135
+ },
136
+ "compositePrimaryKeys": {},
137
+ "uniqueConstraints": {},
138
+ "policies": {},
139
+ "checkConstraints": {},
140
+ "isRLSEnabled": false
141
+ },
142
+ "public.workspaces_memberships": {
143
+ "name": "workspaces_memberships",
144
+ "schema": "",
145
+ "columns": {
146
+ "id": {
147
+ "name": "id",
148
+ "type": "uuid",
149
+ "primaryKey": true,
150
+ "notNull": true,
151
+ "default": "uuidv7()"
152
+ },
153
+ "user_id": {
154
+ "name": "user_id",
155
+ "type": "uuid",
156
+ "primaryKey": false,
157
+ "notNull": true
158
+ },
159
+ "user_email": {
160
+ "name": "user_email",
161
+ "type": "text",
162
+ "primaryKey": false,
163
+ "notNull": true
164
+ },
165
+ "user_name": {
166
+ "name": "user_name",
167
+ "type": "text",
168
+ "primaryKey": false,
169
+ "notNull": false
170
+ },
171
+ "workspace_id": {
172
+ "name": "workspace_id",
173
+ "type": "uuid",
174
+ "primaryKey": false,
175
+ "notNull": true
176
+ },
177
+ "created_at": {
178
+ "name": "created_at",
179
+ "type": "timestamp with time zone",
180
+ "primaryKey": false,
181
+ "notNull": true,
182
+ "default": "now()"
183
+ },
184
+ "updated_at": {
185
+ "name": "updated_at",
186
+ "type": "timestamp with time zone",
187
+ "primaryKey": false,
188
+ "notNull": true,
189
+ "default": "now()"
190
+ }
191
+ },
192
+ "indexes": {
193
+ "workspaces_memberships_user_workspace_unique": {
194
+ "name": "workspaces_memberships_user_workspace_unique",
195
+ "columns": [
196
+ {
197
+ "expression": "user_id",
198
+ "isExpression": false,
199
+ "asc": true,
200
+ "nulls": "last"
201
+ },
202
+ {
203
+ "expression": "workspace_id",
204
+ "isExpression": false,
205
+ "asc": true,
206
+ "nulls": "last"
207
+ }
208
+ ],
209
+ "isUnique": true,
210
+ "concurrently": false,
211
+ "method": "btree",
212
+ "with": {}
213
+ },
214
+ "workspaces_memberships_workspace_id_idx": {
215
+ "name": "workspaces_memberships_workspace_id_idx",
216
+ "columns": [
217
+ {
218
+ "expression": "workspace_id",
219
+ "isExpression": false,
220
+ "asc": true,
221
+ "nulls": "last"
222
+ }
223
+ ],
224
+ "isUnique": false,
225
+ "concurrently": false,
226
+ "method": "btree",
227
+ "with": {}
228
+ }
229
+ },
230
+ "foreignKeys": {
231
+ "workspaces_memberships_workspace_id_workspaces_workspaces_id_fk": {
232
+ "name": "workspaces_memberships_workspace_id_workspaces_workspaces_id_fk",
233
+ "tableFrom": "workspaces_memberships",
234
+ "tableTo": "workspaces_workspaces",
235
+ "columnsFrom": ["workspace_id"],
236
+ "columnsTo": ["id"],
237
+ "onDelete": "cascade",
238
+ "onUpdate": "no action"
239
+ }
240
+ },
241
+ "compositePrimaryKeys": {},
242
+ "uniqueConstraints": {},
243
+ "policies": {},
244
+ "checkConstraints": {},
245
+ "isRLSEnabled": false
246
+ },
247
+ "public.workspaces_outbox": {
248
+ "name": "workspaces_outbox",
249
+ "schema": "",
250
+ "columns": {
251
+ "id": {
252
+ "name": "id",
253
+ "type": "uuid",
254
+ "primaryKey": true,
255
+ "notNull": true,
256
+ "default": "uuidv7()"
257
+ },
258
+ "event_type": {
259
+ "name": "event_type",
260
+ "type": "text",
261
+ "primaryKey": false,
262
+ "notNull": true
263
+ },
264
+ "ordering_key": {
265
+ "name": "ordering_key",
266
+ "type": "text",
267
+ "primaryKey": false,
268
+ "notNull": false
269
+ },
270
+ "payload": {
271
+ "name": "payload",
272
+ "type": "jsonb",
273
+ "primaryKey": false,
274
+ "notNull": true
275
+ },
276
+ "created_at": {
277
+ "name": "created_at",
278
+ "type": "timestamp with time zone",
279
+ "primaryKey": false,
280
+ "notNull": true,
281
+ "default": "now()"
282
+ },
283
+ "dispatched_at": {
284
+ "name": "dispatched_at",
285
+ "type": "timestamp with time zone",
286
+ "primaryKey": false,
287
+ "notNull": false
288
+ },
289
+ "dispatch_attempts": {
290
+ "name": "dispatch_attempts",
291
+ "type": "integer",
292
+ "primaryKey": false,
293
+ "notNull": true,
294
+ "default": 0
295
+ },
296
+ "next_dispatch_at": {
297
+ "name": "next_dispatch_at",
298
+ "type": "timestamp with time zone",
299
+ "primaryKey": false,
300
+ "notNull": true,
301
+ "default": "now()"
302
+ },
303
+ "last_dispatch_error": {
304
+ "name": "last_dispatch_error",
305
+ "type": "jsonb",
306
+ "primaryKey": false,
307
+ "notNull": false
308
+ },
309
+ "last_dispatch_failed_at": {
310
+ "name": "last_dispatch_failed_at",
311
+ "type": "timestamp with time zone",
312
+ "primaryKey": false,
313
+ "notNull": false
314
+ },
315
+ "dead_lettered_at": {
316
+ "name": "dead_lettered_at",
317
+ "type": "timestamp with time zone",
318
+ "primaryKey": false,
319
+ "notNull": false
320
+ }
321
+ },
322
+ "indexes": {
323
+ "workspaces_outbox_pending_idx": {
324
+ "name": "workspaces_outbox_pending_idx",
325
+ "columns": [
326
+ {
327
+ "expression": "next_dispatch_at",
328
+ "isExpression": false,
329
+ "asc": true,
330
+ "nulls": "last"
331
+ },
332
+ {
333
+ "expression": "created_at",
334
+ "isExpression": false,
335
+ "asc": true,
336
+ "nulls": "last"
337
+ }
338
+ ],
339
+ "isUnique": false,
340
+ "where": "\"dispatched_at\" IS NULL AND \"dead_lettered_at\" IS NULL",
341
+ "concurrently": false,
342
+ "method": "btree",
343
+ "with": {}
344
+ },
345
+ "workspaces_outbox_dispatched_retention_idx": {
346
+ "name": "workspaces_outbox_dispatched_retention_idx",
347
+ "columns": [
348
+ {
349
+ "expression": "dispatched_at",
350
+ "isExpression": false,
351
+ "asc": true,
352
+ "nulls": "last"
353
+ },
354
+ {
355
+ "expression": "id",
356
+ "isExpression": false,
357
+ "asc": true,
358
+ "nulls": "last"
359
+ }
360
+ ],
361
+ "isUnique": false,
362
+ "where": "\"dispatched_at\" IS NOT NULL",
363
+ "concurrently": false,
364
+ "method": "btree",
365
+ "with": {}
366
+ }
367
+ },
368
+ "foreignKeys": {},
369
+ "compositePrimaryKeys": {},
370
+ "uniqueConstraints": {},
371
+ "policies": {},
372
+ "checkConstraints": {},
373
+ "isRLSEnabled": false
374
+ },
375
+ "public.workspaces_workspaces": {
376
+ "name": "workspaces_workspaces",
9
377
  "schema": "",
10
378
  "columns": {
11
379
  "id": {
@@ -36,6 +404,12 @@
36
404
  "notNull": true,
37
405
  "default": "'{}'::jsonb"
38
406
  },
407
+ "created_by": {
408
+ "name": "created_by",
409
+ "type": "uuid",
410
+ "primaryKey": false,
411
+ "notNull": false
412
+ },
39
413
  "created_at": {
40
414
  "name": "created_at",
41
415
  "type": "timestamp with time zone",
@@ -8,34 +8,6 @@
8
8
  "when": 1777229181112,
9
9
  "tag": "0000_initial",
10
10
  "breakpoints": true
11
- },
12
- {
13
- "idx": 1,
14
- "version": "7",
15
- "when": 1777289648915,
16
- "tag": "0001_memberships_invitations",
17
- "breakpoints": true
18
- },
19
- {
20
- "idx": 2,
21
- "version": "7",
22
- "when": 1777297640000,
23
- "tag": "0002_membership_user_snapshots",
24
- "breakpoints": true
25
- },
26
- {
27
- "idx": 3,
28
- "version": "7",
29
- "when": 1782352229611,
30
- "tag": "0003_outgoing_enchantress",
31
- "breakpoints": true
32
- },
33
- {
34
- "idx": 4,
35
- "version": "7",
36
- "when": 1784571790437,
37
- "tag": "0004_tired_talon",
38
- "breakpoints": true
39
11
  }
40
12
  ]
41
13
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shipfox/api-workspaces",
3
3
  "license": "MIT",
4
- "version": "7.1.0",
4
+ "version": "9.0.2",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
@@ -11,10 +11,6 @@
11
11
  "type": "module",
12
12
  "main": "dist/index.js",
13
13
  "types": "dist/index.d.ts",
14
- "imports": {
15
- "#test/*": "./test/*",
16
- "#*": "./dist/*"
17
- },
18
14
  "exports": {
19
15
  ".": {
20
16
  "types": "./dist/index.d.ts",
@@ -28,20 +24,31 @@
28
24
  "dependencies": {
29
25
  "drizzle-orm": "^0.45.2",
30
26
  "zod": "^4.4.3",
31
- "@shipfox/api-common-dto": "6.0.0",
32
- "@shipfox/api-auth-context": "7.1.0",
33
- "@shipfox/api-workspaces-dto": "6.0.0",
34
- "@shipfox/config": "1.2.2",
35
- "@shipfox/inter-module": "0.2.0",
36
- "@shipfox/node-drizzle": "0.3.2",
37
- "@shipfox/node-fastify": "0.3.0",
38
- "@shipfox/node-email": "0.3.1",
39
- "@shipfox/node-mailer": "0.2.1",
40
- "@shipfox/node-module": "0.5.0",
41
- "@shipfox/node-opentelemetry": "0.6.0",
42
- "@shipfox/node-outbox": "0.2.4",
43
- "@shipfox/node-postgres": "0.4.2",
44
- "@shipfox/node-tokens": "0.3.0"
27
+ "@shipfox/api-workspaces-dto": "9.0.2",
28
+ "@shipfox/api-common-dto": "9.0.2",
29
+ "@shipfox/config": "1.2.4",
30
+ "@shipfox/inter-module": "0.2.2",
31
+ "@shipfox/api-auth-context": "9.0.2",
32
+ "@shipfox/node-drizzle": "0.3.4",
33
+ "@shipfox/node-fastify": "0.3.2",
34
+ "@shipfox/node-mailer": "0.2.3",
35
+ "@shipfox/node-email": "0.3.3",
36
+ "@shipfox/node-module": "1.0.1",
37
+ "@shipfox/node-opentelemetry": "0.6.2",
38
+ "@shipfox/node-postgres": "0.4.4",
39
+ "@shipfox/node-outbox": "0.2.6",
40
+ "@shipfox/node-tokens": "0.3.2"
41
+ },
42
+ "imports": {
43
+ "#*": "./dist/*"
44
+ },
45
+ "shipfox": {
46
+ "architecture": {
47
+ "schema": 1,
48
+ "realm": "source-available",
49
+ "kind": "implementation",
50
+ "context": "workspaces"
51
+ }
45
52
  },
46
53
  "scripts": {
47
54
  "build": "shipfox-swc",
@@ -5,6 +5,7 @@ export interface Workspace {
5
5
  name: string;
6
6
  status: WorkspaceStatus;
7
7
  settings: Record<string, unknown>;
8
+ createdBy: string | null;
8
9
  createdAt: Date;
9
10
  updatedAt: Date;
10
11
  }
@@ -66,7 +66,10 @@ export async function createWorkspaceForUser(params: {
66
66
  userName?: string | null | undefined;
67
67
  }): Promise<Workspace> {
68
68
  return await db().transaction(async (tx) => {
69
- const [workspaceRow] = await tx.insert(workspaces).values({name: params.name}).returning();
69
+ const [workspaceRow] = await tx
70
+ .insert(workspaces)
71
+ .values({name: params.name, createdBy: params.userId})
72
+ .returning();
70
73
  if (!workspaceRow) throw new Error('Insert returned no rows');
71
74
  await tx.insert(memberships).values({
72
75
  userId: params.userId,
@@ -98,6 +101,11 @@ export async function getWorkspace(params: {workspaceId: string}): Promise<Works
98
101
  return workspace;
99
102
  }
100
103
 
104
+ export async function getWorkspaceCreator(params: {workspaceId: string}): Promise<string | null> {
105
+ const workspace = await getWorkspace(params);
106
+ return workspace.createdBy;
107
+ }
108
+
101
109
  export async function listUserWorkspaceMemberships(params: {
102
110
  userId: string;
103
111
  }): Promise<MembershipWithWorkspace[]> {
@@ -1,5 +1,3 @@
1
1
  import {pgTableCreator} from 'drizzle-orm/pg-core';
2
2
 
3
- export const pgTable = pgTableCreator((name) =>
4
- name === 'workspaces' ? name : `workspaces_${name}`,
5
- );
3
+ export const pgTable = pgTableCreator((name) => `workspaces_${name}`);
@@ -1,5 +1,5 @@
1
1
  import {uuidv7PrimaryKey} from '@shipfox/node-drizzle';
2
- import {jsonb, pgEnum, text, timestamp} from 'drizzle-orm/pg-core';
2
+ import {jsonb, pgEnum, text, timestamp, uuid} from 'drizzle-orm/pg-core';
3
3
  import type {Workspace, WorkspaceStatus} from '#core/entities/workspace.js';
4
4
  import {pgTable} from './common.js';
5
5
 
@@ -14,6 +14,7 @@ export const workspaces = pgTable('workspaces', {
14
14
  name: text('name').notNull(),
15
15
  status: workspaceStatusEnum('status').notNull().default('active'),
16
16
  settings: jsonb('settings').notNull().default({}),
17
+ createdBy: uuid('created_by'),
17
18
  createdAt: timestamp('created_at', {withTimezone: true}).notNull().defaultNow(),
18
19
  updatedAt: timestamp('updated_at', {withTimezone: true}).notNull().defaultNow(),
19
20
  });
@@ -27,6 +28,7 @@ export function toWorkspace(row: WorkspaceDb): Workspace {
27
28
  name: row.name,
28
29
  status: row.status as WorkspaceStatus,
29
30
  settings: row.settings as Record<string, unknown>,
31
+ createdBy: row.createdBy,
30
32
  createdAt: row.createdAt,
31
33
  updatedAt: row.updatedAt,
32
34
  };
package/src/index.ts CHANGED
@@ -38,7 +38,7 @@ const subscriber = subscriberFactory<WorkspacesEventMap>();
38
38
 
39
39
  export const workspacesModule: ShipfoxModule = {
40
40
  name: 'workspaces',
41
- database: {db, migrationsPath},
41
+ database: {db, migrationsPath, databaseNamespace: 'workspaces'},
42
42
  routes: workspacesRoutes,
43
43
  e2eRoutes: [workspacesE2eRoutes],
44
44
  publishers: [