@shipfox/api-workspaces 2.0.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.
Files changed (284) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/.turbo/turbo-type$colon$emit.log +1 -0
  3. package/.turbo/turbo-type.log +1 -0
  4. package/CHANGELOG.md +97 -0
  5. package/LICENSE +21 -0
  6. package/README.md +87 -0
  7. package/dist/config.d.ts +12 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +58 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/core/entities/index.d.ts +4 -0
  12. package/dist/core/entities/index.d.ts.map +1 -0
  13. package/dist/core/entities/index.js +3 -0
  14. package/dist/core/entities/index.js.map +1 -0
  15. package/dist/core/entities/invitation.d.ts +14 -0
  16. package/dist/core/entities/invitation.d.ts.map +1 -0
  17. package/dist/core/entities/invitation.js +3 -0
  18. package/dist/core/entities/invitation.js.map +1 -0
  19. package/dist/core/entities/membership.d.ts +10 -0
  20. package/dist/core/entities/membership.d.ts.map +1 -0
  21. package/dist/core/entities/membership.js +3 -0
  22. package/dist/core/entities/membership.js.map +1 -0
  23. package/dist/core/entities/workspace.d.ts +10 -0
  24. package/dist/core/entities/workspace.d.ts.map +1 -0
  25. package/dist/core/entities/workspace.js +3 -0
  26. package/dist/core/entities/workspace.js.map +1 -0
  27. package/dist/core/errors.d.ts +52 -0
  28. package/dist/core/errors.d.ts.map +1 -0
  29. package/dist/core/errors.js +104 -0
  30. package/dist/core/errors.js.map +1 -0
  31. package/dist/core/index.d.ts +8 -0
  32. package/dist/core/index.d.ts.map +1 -0
  33. package/dist/core/index.js +6 -0
  34. package/dist/core/index.js.map +1 -0
  35. package/dist/core/invitations.d.ts +51 -0
  36. package/dist/core/invitations.d.ts.map +1 -0
  37. package/dist/core/invitations.js +136 -0
  38. package/dist/core/invitations.js.map +1 -0
  39. package/dist/core/memberships.d.ts +9 -0
  40. package/dist/core/memberships.d.ts.map +1 -0
  41. package/dist/core/memberships.js +13 -0
  42. package/dist/core/memberships.js.map +1 -0
  43. package/dist/core/workspaces.d.ts +40 -0
  44. package/dist/core/workspaces.d.ts.map +1 -0
  45. package/dist/core/workspaces.js +85 -0
  46. package/dist/core/workspaces.js.map +1 -0
  47. package/dist/db/db.d.ts +1253 -0
  48. package/dist/db/db.d.ts.map +1 -0
  49. package/dist/db/db.js +24 -0
  50. package/dist/db/db.js.map +1 -0
  51. package/dist/db/index.d.ts +10 -0
  52. package/dist/db/index.d.ts.map +1 -0
  53. package/dist/db/index.js +10 -0
  54. package/dist/db/index.js.map +1 -0
  55. package/dist/db/invitations.d.ts +47 -0
  56. package/dist/db/invitations.d.ts.map +1 -0
  57. package/dist/db/invitations.js +107 -0
  58. package/dist/db/invitations.js.map +1 -0
  59. package/dist/db/memberships.d.ts +44 -0
  60. package/dist/db/memberships.d.ts.map +1 -0
  61. package/dist/db/memberships.js +75 -0
  62. package/dist/db/memberships.js.map +1 -0
  63. package/dist/db/schema/common.d.ts +2 -0
  64. package/dist/db/schema/common.d.ts.map +1 -0
  65. package/dist/db/schema/common.js +4 -0
  66. package/dist/db/schema/common.js.map +1 -0
  67. package/dist/db/schema/invitations.d.ts +199 -0
  68. package/dist/db/schema/invitations.d.ts.map +1 -0
  69. package/dist/db/schema/invitations.js +47 -0
  70. package/dist/db/schema/invitations.js.map +1 -0
  71. package/dist/db/schema/memberships.d.ts +131 -0
  72. package/dist/db/schema/memberships.d.ts.map +1 -0
  73. package/dist/db/schema/memberships.js +35 -0
  74. package/dist/db/schema/memberships.js.map +1 -0
  75. package/dist/db/schema/outbox.d.ts +195 -0
  76. package/dist/db/schema/outbox.d.ts.map +1 -0
  77. package/dist/db/schema/outbox.js +5 -0
  78. package/dist/db/schema/outbox.js.map +1 -0
  79. package/dist/db/schema/workspaces.d.ts +115 -0
  80. package/dist/db/schema/workspaces.d.ts.map +1 -0
  81. package/dist/db/schema/workspaces.js +32 -0
  82. package/dist/db/schema/workspaces.js.map +1 -0
  83. package/dist/db/workspaces.d.ts +20 -0
  84. package/dist/db/workspaces.d.ts.map +1 -0
  85. package/dist/db/workspaces.js +53 -0
  86. package/dist/db/workspaces.js.map +1 -0
  87. package/dist/index.d.ts +13 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +40 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/metrics/index.d.ts +2 -0
  92. package/dist/metrics/index.d.ts.map +1 -0
  93. package/dist/metrics/index.js +3 -0
  94. package/dist/metrics/index.js.map +1 -0
  95. package/dist/metrics/instance.d.ts +8 -0
  96. package/dist/metrics/instance.d.ts.map +1 -0
  97. package/dist/metrics/instance.js +41 -0
  98. package/dist/metrics/instance.js.map +1 -0
  99. package/dist/metrics/service.d.ts +2 -0
  100. package/dist/metrics/service.d.ts.map +1 -0
  101. package/dist/metrics/service.js +26 -0
  102. package/dist/metrics/service.js.map +1 -0
  103. package/dist/presentation/dto/index.d.ts +4 -0
  104. package/dist/presentation/dto/index.d.ts.map +1 -0
  105. package/dist/presentation/dto/index.js +5 -0
  106. package/dist/presentation/dto/index.js.map +1 -0
  107. package/dist/presentation/dto/invitation.d.ts +4 -0
  108. package/dist/presentation/dto/invitation.d.ts.map +1 -0
  109. package/dist/presentation/dto/invitation.js +15 -0
  110. package/dist/presentation/dto/invitation.js.map +1 -0
  111. package/dist/presentation/dto/membership.d.ts +5 -0
  112. package/dist/presentation/dto/membership.d.ts.map +1 -0
  113. package/dist/presentation/dto/membership.js +23 -0
  114. package/dist/presentation/dto/membership.js.map +1 -0
  115. package/dist/presentation/dto/workspace.d.ts +4 -0
  116. package/dist/presentation/dto/workspace.d.ts.map +1 -0
  117. package/dist/presentation/dto/workspace.js +12 -0
  118. package/dist/presentation/dto/workspace.js.map +1 -0
  119. package/dist/presentation/e2eRoutes/create-invitation.d.ts +2 -0
  120. package/dist/presentation/e2eRoutes/create-invitation.d.ts.map +1 -0
  121. package/dist/presentation/e2eRoutes/create-invitation.js +39 -0
  122. package/dist/presentation/e2eRoutes/create-invitation.js.map +1 -0
  123. package/dist/presentation/e2eRoutes/create-workspace.d.ts +2 -0
  124. package/dist/presentation/e2eRoutes/create-workspace.d.ts.map +1 -0
  125. package/dist/presentation/e2eRoutes/create-workspace.js +27 -0
  126. package/dist/presentation/e2eRoutes/create-workspace.js.map +1 -0
  127. package/dist/presentation/e2eRoutes/index.d.ts +3 -0
  128. package/dist/presentation/e2eRoutes/index.d.ts.map +1 -0
  129. package/dist/presentation/e2eRoutes/index.js +11 -0
  130. package/dist/presentation/e2eRoutes/index.js.map +1 -0
  131. package/dist/presentation/index.d.ts +2 -0
  132. package/dist/presentation/index.d.ts.map +1 -0
  133. package/dist/presentation/index.js +3 -0
  134. package/dist/presentation/index.js.map +1 -0
  135. package/dist/presentation/routes/index.d.ts +3 -0
  136. package/dist/presentation/routes/index.d.ts.map +1 -0
  137. package/dist/presentation/routes/index.js +23 -0
  138. package/dist/presentation/routes/index.js.map +1 -0
  139. package/dist/presentation/routes/invitations/accept.d.ts +2 -0
  140. package/dist/presentation/routes/invitations/accept.d.ts.map +1 -0
  141. package/dist/presentation/routes/invitations/accept.js +67 -0
  142. package/dist/presentation/routes/invitations/accept.js.map +1 -0
  143. package/dist/presentation/routes/invitations/create.d.ts +2 -0
  144. package/dist/presentation/routes/invitations/create.d.ts.map +1 -0
  145. package/dist/presentation/routes/invitations/create.js +66 -0
  146. package/dist/presentation/routes/invitations/create.js.map +1 -0
  147. package/dist/presentation/routes/invitations/index.d.ts +4 -0
  148. package/dist/presentation/routes/invitations/index.d.ts.map +1 -0
  149. package/dist/presentation/routes/invitations/index.js +19 -0
  150. package/dist/presentation/routes/invitations/index.js.map +1 -0
  151. package/dist/presentation/routes/invitations/list.d.ts +2 -0
  152. package/dist/presentation/routes/invitations/list.d.ts.map +1 -0
  153. package/dist/presentation/routes/invitations/list.js +58 -0
  154. package/dist/presentation/routes/invitations/list.js.map +1 -0
  155. package/dist/presentation/routes/invitations/preview.d.ts +2 -0
  156. package/dist/presentation/routes/invitations/preview.d.ts.map +1 -0
  157. package/dist/presentation/routes/invitations/preview.js +47 -0
  158. package/dist/presentation/routes/invitations/preview.js.map +1 -0
  159. package/dist/presentation/routes/invitations/revoke.d.ts +2 -0
  160. package/dist/presentation/routes/invitations/revoke.d.ts.map +1 -0
  161. package/dist/presentation/routes/invitations/revoke.js +66 -0
  162. package/dist/presentation/routes/invitations/revoke.js.map +1 -0
  163. package/dist/presentation/routes/members/index.d.ts +3 -0
  164. package/dist/presentation/routes/members/index.d.ts.map +1 -0
  165. package/dist/presentation/routes/members/index.js +8 -0
  166. package/dist/presentation/routes/members/index.js.map +1 -0
  167. package/dist/presentation/routes/members/list.d.ts +2 -0
  168. package/dist/presentation/routes/members/list.d.ts.map +1 -0
  169. package/dist/presentation/routes/members/list.js +58 -0
  170. package/dist/presentation/routes/members/list.js.map +1 -0
  171. package/dist/presentation/routes/members/remove.d.ts +2 -0
  172. package/dist/presentation/routes/members/remove.d.ts.map +1 -0
  173. package/dist/presentation/routes/members/remove.js +71 -0
  174. package/dist/presentation/routes/members/remove.js.map +1 -0
  175. package/dist/presentation/routes/workspaces/create.d.ts +2 -0
  176. package/dist/presentation/routes/workspaces/create.d.ts.map +1 -0
  177. package/dist/presentation/routes/workspaces/create.js +36 -0
  178. package/dist/presentation/routes/workspaces/create.js.map +1 -0
  179. package/dist/presentation/routes/workspaces/index.d.ts +3 -0
  180. package/dist/presentation/routes/workspaces/index.d.ts.map +1 -0
  181. package/dist/presentation/routes/workspaces/index.js +4 -0
  182. package/dist/presentation/routes/workspaces/index.js.map +1 -0
  183. package/dist/presentation/routes/workspaces/list.d.ts +2 -0
  184. package/dist/presentation/routes/workspaces/list.d.ts.map +1 -0
  185. package/dist/presentation/routes/workspaces/list.js +32 -0
  186. package/dist/presentation/routes/workspaces/list.js.map +1 -0
  187. package/dist/presentation/subscribers/index.d.ts +2 -0
  188. package/dist/presentation/subscribers/index.d.ts.map +1 -0
  189. package/dist/presentation/subscribers/index.js +3 -0
  190. package/dist/presentation/subscribers/index.js.map +1 -0
  191. package/dist/presentation/subscribers/on-invitation-send-requested.d.ts +3 -0
  192. package/dist/presentation/subscribers/on-invitation-send-requested.d.ts.map +1 -0
  193. package/dist/presentation/subscribers/on-invitation-send-requested.js +16 -0
  194. package/dist/presentation/subscribers/on-invitation-send-requested.js.map +1 -0
  195. package/dist/tsconfig.test.tsbuildinfo +1 -0
  196. package/drizzle/0000_initial.sql +9 -0
  197. package/drizzle/0001_memberships_invitations.sql +30 -0
  198. package/drizzle/0002_membership_user_snapshots.sql +40 -0
  199. package/drizzle/0003_outgoing_enchantress.sql +16 -0
  200. package/drizzle/meta/0000_snapshot.json +80 -0
  201. package/drizzle/meta/0001_snapshot.json +705 -0
  202. package/drizzle/meta/0003_snapshot.json +442 -0
  203. package/drizzle/meta/_journal.json +34 -0
  204. package/drizzle.config.ts +7 -0
  205. package/package.json +71 -0
  206. package/src/config.ts +51 -0
  207. package/src/core/entities/index.ts +3 -0
  208. package/src/core/entities/invitation.ts +13 -0
  209. package/src/core/entities/membership.ts +9 -0
  210. package/src/core/entities/workspace.ts +10 -0
  211. package/src/core/errors.ts +118 -0
  212. package/src/core/index.ts +35 -0
  213. package/src/core/invitations.test.ts +251 -0
  214. package/src/core/invitations.ts +191 -0
  215. package/src/core/memberships.test.ts +77 -0
  216. package/src/core/memberships.ts +17 -0
  217. package/src/core/workspaces.test.ts +72 -0
  218. package/src/core/workspaces.ts +126 -0
  219. package/src/db/db.ts +24 -0
  220. package/src/db/index.ts +43 -0
  221. package/src/db/invitations.test.ts +204 -0
  222. package/src/db/invitations.ts +235 -0
  223. package/src/db/memberships.test.ts +107 -0
  224. package/src/db/memberships.ts +139 -0
  225. package/src/db/schema/common.ts +5 -0
  226. package/src/db/schema/invitations.ts +47 -0
  227. package/src/db/schema/memberships.ts +39 -0
  228. package/src/db/schema/outbox.ts +4 -0
  229. package/src/db/schema/workspaces.ts +33 -0
  230. package/src/db/workspaces.test.ts +114 -0
  231. package/src/db/workspaces.ts +81 -0
  232. package/src/index.test.ts +25 -0
  233. package/src/index.ts +43 -0
  234. package/src/metrics/index.ts +1 -0
  235. package/src/metrics/instance.test.ts +74 -0
  236. package/src/metrics/instance.ts +57 -0
  237. package/src/metrics/service.ts +26 -0
  238. package/src/presentation/dto/index.ts +3 -0
  239. package/src/presentation/dto/invitation.ts +16 -0
  240. package/src/presentation/dto/membership.ts +27 -0
  241. package/src/presentation/dto/workspace.ts +13 -0
  242. package/src/presentation/e2eRoutes/create-invitation.ts +44 -0
  243. package/src/presentation/e2eRoutes/create-workspace.ts +30 -0
  244. package/src/presentation/e2eRoutes/index.ts +8 -0
  245. package/src/presentation/index.ts +1 -0
  246. package/src/presentation/routes/index.ts +23 -0
  247. package/src/presentation/routes/invitations/accept.test.ts +154 -0
  248. package/src/presentation/routes/invitations/accept.ts +70 -0
  249. package/src/presentation/routes/invitations/create.test.ts +99 -0
  250. package/src/presentation/routes/invitations/create.ts +60 -0
  251. package/src/presentation/routes/invitations/index.ts +17 -0
  252. package/src/presentation/routes/invitations/list.test.ts +94 -0
  253. package/src/presentation/routes/invitations/list.ts +53 -0
  254. package/src/presentation/routes/invitations/preview.test.ts +140 -0
  255. package/src/presentation/routes/invitations/preview.ts +46 -0
  256. package/src/presentation/routes/invitations/revoke.test.ts +99 -0
  257. package/src/presentation/routes/invitations/revoke.ts +64 -0
  258. package/src/presentation/routes/members/index.ts +5 -0
  259. package/src/presentation/routes/members/list.test.ts +95 -0
  260. package/src/presentation/routes/members/list.ts +53 -0
  261. package/src/presentation/routes/members/remove.test.ts +110 -0
  262. package/src/presentation/routes/members/remove.ts +66 -0
  263. package/src/presentation/routes/workspaces/create.test.ts +87 -0
  264. package/src/presentation/routes/workspaces/create.ts +36 -0
  265. package/src/presentation/routes/workspaces/index.ts +2 -0
  266. package/src/presentation/routes/workspaces/list.test.ts +56 -0
  267. package/src/presentation/routes/workspaces/list.ts +29 -0
  268. package/src/presentation/subscribers/index.ts +1 -0
  269. package/src/presentation/subscribers/invitation-send-requested.test.ts +64 -0
  270. package/src/presentation/subscribers/on-invitation-send-requested.ts +15 -0
  271. package/test/env.ts +8 -0
  272. package/test/factories/index.ts +3 -0
  273. package/test/factories/membership.ts +24 -0
  274. package/test/factories/user.ts +15 -0
  275. package/test/factories/workspace.ts +18 -0
  276. package/test/globalSetup.ts +15 -0
  277. package/test/index.ts +3 -0
  278. package/test/routes.ts +255 -0
  279. package/test/setup.ts +17 -0
  280. package/tsconfig.build.json +9 -0
  281. package/tsconfig.build.tsbuildinfo +1 -0
  282. package/tsconfig.json +3 -0
  283. package/tsconfig.test.json +8 -0
  284. package/vitest.config.ts +11 -0
@@ -0,0 +1,442 @@
1
+ {
2
+ "id": "86af97dc-249d-4cc9-98bc-52681d4ca30f",
3
+ "prevId": "71580355-da9f-475d-ab24-8d5e8cb5bb47",
4
+ "version": "7",
5
+ "dialect": "postgresql",
6
+ "tables": {
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
+ "accepted_at": {
43
+ "name": "accepted_at",
44
+ "type": "timestamp with time zone",
45
+ "primaryKey": false,
46
+ "notNull": false
47
+ },
48
+ "accepted_by_user_id": {
49
+ "name": "accepted_by_user_id",
50
+ "type": "uuid",
51
+ "primaryKey": false,
52
+ "notNull": false
53
+ },
54
+ "invited_by_user_id": {
55
+ "name": "invited_by_user_id",
56
+ "type": "uuid",
57
+ "primaryKey": false,
58
+ "notNull": true
59
+ },
60
+ "invited_by_display": {
61
+ "name": "invited_by_display",
62
+ "type": "text",
63
+ "primaryKey": false,
64
+ "notNull": false
65
+ },
66
+ "created_at": {
67
+ "name": "created_at",
68
+ "type": "timestamp with time zone",
69
+ "primaryKey": false,
70
+ "notNull": true,
71
+ "default": "now()"
72
+ },
73
+ "updated_at": {
74
+ "name": "updated_at",
75
+ "type": "timestamp with time zone",
76
+ "primaryKey": false,
77
+ "notNull": true,
78
+ "default": "now()"
79
+ }
80
+ },
81
+ "indexes": {
82
+ "workspaces_invitations_hashed_token_unique": {
83
+ "name": "workspaces_invitations_hashed_token_unique",
84
+ "columns": [
85
+ {
86
+ "expression": "hashed_token",
87
+ "isExpression": false,
88
+ "asc": true,
89
+ "nulls": "last"
90
+ }
91
+ ],
92
+ "isUnique": true,
93
+ "concurrently": false,
94
+ "method": "btree",
95
+ "with": {}
96
+ },
97
+ "workspaces_invitations_workspace_email_idx": {
98
+ "name": "workspaces_invitations_workspace_email_idx",
99
+ "columns": [
100
+ {
101
+ "expression": "workspace_id",
102
+ "isExpression": false,
103
+ "asc": true,
104
+ "nulls": "last"
105
+ },
106
+ {
107
+ "expression": "email",
108
+ "isExpression": false,
109
+ "asc": true,
110
+ "nulls": "last"
111
+ }
112
+ ],
113
+ "isUnique": false,
114
+ "concurrently": false,
115
+ "method": "btree",
116
+ "with": {}
117
+ }
118
+ },
119
+ "foreignKeys": {
120
+ "workspaces_invitations_workspace_id_workspaces_id_fk": {
121
+ "name": "workspaces_invitations_workspace_id_workspaces_id_fk",
122
+ "tableFrom": "workspaces_invitations",
123
+ "tableTo": "workspaces",
124
+ "columnsFrom": ["workspace_id"],
125
+ "columnsTo": ["id"],
126
+ "onDelete": "cascade",
127
+ "onUpdate": "no action"
128
+ }
129
+ },
130
+ "compositePrimaryKeys": {},
131
+ "uniqueConstraints": {},
132
+ "policies": {},
133
+ "checkConstraints": {},
134
+ "isRLSEnabled": false
135
+ },
136
+ "public.workspaces_memberships": {
137
+ "name": "workspaces_memberships",
138
+ "schema": "",
139
+ "columns": {
140
+ "id": {
141
+ "name": "id",
142
+ "type": "uuid",
143
+ "primaryKey": true,
144
+ "notNull": true,
145
+ "default": "uuidv7()"
146
+ },
147
+ "user_id": {
148
+ "name": "user_id",
149
+ "type": "uuid",
150
+ "primaryKey": false,
151
+ "notNull": true
152
+ },
153
+ "user_email": {
154
+ "name": "user_email",
155
+ "type": "text",
156
+ "primaryKey": false,
157
+ "notNull": true
158
+ },
159
+ "user_name": {
160
+ "name": "user_name",
161
+ "type": "text",
162
+ "primaryKey": false,
163
+ "notNull": false
164
+ },
165
+ "workspace_id": {
166
+ "name": "workspace_id",
167
+ "type": "uuid",
168
+ "primaryKey": false,
169
+ "notNull": true
170
+ },
171
+ "created_at": {
172
+ "name": "created_at",
173
+ "type": "timestamp with time zone",
174
+ "primaryKey": false,
175
+ "notNull": true,
176
+ "default": "now()"
177
+ },
178
+ "updated_at": {
179
+ "name": "updated_at",
180
+ "type": "timestamp with time zone",
181
+ "primaryKey": false,
182
+ "notNull": true,
183
+ "default": "now()"
184
+ }
185
+ },
186
+ "indexes": {
187
+ "workspaces_memberships_user_workspace_unique": {
188
+ "name": "workspaces_memberships_user_workspace_unique",
189
+ "columns": [
190
+ {
191
+ "expression": "user_id",
192
+ "isExpression": false,
193
+ "asc": true,
194
+ "nulls": "last"
195
+ },
196
+ {
197
+ "expression": "workspace_id",
198
+ "isExpression": false,
199
+ "asc": true,
200
+ "nulls": "last"
201
+ }
202
+ ],
203
+ "isUnique": true,
204
+ "concurrently": false,
205
+ "method": "btree",
206
+ "with": {}
207
+ },
208
+ "workspaces_memberships_workspace_id_idx": {
209
+ "name": "workspaces_memberships_workspace_id_idx",
210
+ "columns": [
211
+ {
212
+ "expression": "workspace_id",
213
+ "isExpression": false,
214
+ "asc": true,
215
+ "nulls": "last"
216
+ }
217
+ ],
218
+ "isUnique": false,
219
+ "concurrently": false,
220
+ "method": "btree",
221
+ "with": {}
222
+ }
223
+ },
224
+ "foreignKeys": {
225
+ "workspaces_memberships_workspace_id_workspaces_id_fk": {
226
+ "name": "workspaces_memberships_workspace_id_workspaces_id_fk",
227
+ "tableFrom": "workspaces_memberships",
228
+ "tableTo": "workspaces",
229
+ "columnsFrom": ["workspace_id"],
230
+ "columnsTo": ["id"],
231
+ "onDelete": "cascade",
232
+ "onUpdate": "no action"
233
+ }
234
+ },
235
+ "compositePrimaryKeys": {},
236
+ "uniqueConstraints": {},
237
+ "policies": {},
238
+ "checkConstraints": {},
239
+ "isRLSEnabled": false
240
+ },
241
+ "public.workspaces_outbox": {
242
+ "name": "workspaces_outbox",
243
+ "schema": "",
244
+ "columns": {
245
+ "id": {
246
+ "name": "id",
247
+ "type": "uuid",
248
+ "primaryKey": true,
249
+ "notNull": true,
250
+ "default": "uuidv7()"
251
+ },
252
+ "event_type": {
253
+ "name": "event_type",
254
+ "type": "text",
255
+ "primaryKey": false,
256
+ "notNull": true
257
+ },
258
+ "ordering_key": {
259
+ "name": "ordering_key",
260
+ "type": "text",
261
+ "primaryKey": false,
262
+ "notNull": false
263
+ },
264
+ "payload": {
265
+ "name": "payload",
266
+ "type": "jsonb",
267
+ "primaryKey": false,
268
+ "notNull": true
269
+ },
270
+ "created_at": {
271
+ "name": "created_at",
272
+ "type": "timestamp with time zone",
273
+ "primaryKey": false,
274
+ "notNull": true,
275
+ "default": "now()"
276
+ },
277
+ "dispatched_at": {
278
+ "name": "dispatched_at",
279
+ "type": "timestamp with time zone",
280
+ "primaryKey": false,
281
+ "notNull": false
282
+ },
283
+ "dispatch_attempts": {
284
+ "name": "dispatch_attempts",
285
+ "type": "integer",
286
+ "primaryKey": false,
287
+ "notNull": true,
288
+ "default": 0
289
+ },
290
+ "next_dispatch_at": {
291
+ "name": "next_dispatch_at",
292
+ "type": "timestamp with time zone",
293
+ "primaryKey": false,
294
+ "notNull": true,
295
+ "default": "now()"
296
+ },
297
+ "last_dispatch_error": {
298
+ "name": "last_dispatch_error",
299
+ "type": "jsonb",
300
+ "primaryKey": false,
301
+ "notNull": false
302
+ },
303
+ "last_dispatch_failed_at": {
304
+ "name": "last_dispatch_failed_at",
305
+ "type": "timestamp with time zone",
306
+ "primaryKey": false,
307
+ "notNull": false
308
+ },
309
+ "dead_lettered_at": {
310
+ "name": "dead_lettered_at",
311
+ "type": "timestamp with time zone",
312
+ "primaryKey": false,
313
+ "notNull": false
314
+ }
315
+ },
316
+ "indexes": {
317
+ "workspaces_outbox_pending_idx": {
318
+ "name": "workspaces_outbox_pending_idx",
319
+ "columns": [
320
+ {
321
+ "expression": "next_dispatch_at",
322
+ "isExpression": false,
323
+ "asc": true,
324
+ "nulls": "last"
325
+ },
326
+ {
327
+ "expression": "created_at",
328
+ "isExpression": false,
329
+ "asc": true,
330
+ "nulls": "last"
331
+ }
332
+ ],
333
+ "isUnique": false,
334
+ "where": "\"dispatched_at\" IS NULL AND \"dead_lettered_at\" IS NULL",
335
+ "concurrently": false,
336
+ "method": "btree",
337
+ "with": {}
338
+ },
339
+ "workspaces_outbox_dispatched_retention_idx": {
340
+ "name": "workspaces_outbox_dispatched_retention_idx",
341
+ "columns": [
342
+ {
343
+ "expression": "dispatched_at",
344
+ "isExpression": false,
345
+ "asc": true,
346
+ "nulls": "last"
347
+ },
348
+ {
349
+ "expression": "id",
350
+ "isExpression": false,
351
+ "asc": true,
352
+ "nulls": "last"
353
+ }
354
+ ],
355
+ "isUnique": false,
356
+ "where": "\"dispatched_at\" IS NOT NULL",
357
+ "concurrently": false,
358
+ "method": "btree",
359
+ "with": {}
360
+ }
361
+ },
362
+ "foreignKeys": {},
363
+ "compositePrimaryKeys": {},
364
+ "uniqueConstraints": {},
365
+ "policies": {},
366
+ "checkConstraints": {},
367
+ "isRLSEnabled": false
368
+ },
369
+ "public.workspaces": {
370
+ "name": "workspaces",
371
+ "schema": "",
372
+ "columns": {
373
+ "id": {
374
+ "name": "id",
375
+ "type": "uuid",
376
+ "primaryKey": true,
377
+ "notNull": true,
378
+ "default": "uuidv7()"
379
+ },
380
+ "name": {
381
+ "name": "name",
382
+ "type": "text",
383
+ "primaryKey": false,
384
+ "notNull": true
385
+ },
386
+ "status": {
387
+ "name": "status",
388
+ "type": "workspaces_workspace_status",
389
+ "typeSchema": "public",
390
+ "primaryKey": false,
391
+ "notNull": true,
392
+ "default": "'active'"
393
+ },
394
+ "settings": {
395
+ "name": "settings",
396
+ "type": "jsonb",
397
+ "primaryKey": false,
398
+ "notNull": true,
399
+ "default": "'{}'::jsonb"
400
+ },
401
+ "created_at": {
402
+ "name": "created_at",
403
+ "type": "timestamp with time zone",
404
+ "primaryKey": false,
405
+ "notNull": true,
406
+ "default": "now()"
407
+ },
408
+ "updated_at": {
409
+ "name": "updated_at",
410
+ "type": "timestamp with time zone",
411
+ "primaryKey": false,
412
+ "notNull": true,
413
+ "default": "now()"
414
+ }
415
+ },
416
+ "indexes": {},
417
+ "foreignKeys": {},
418
+ "compositePrimaryKeys": {},
419
+ "uniqueConstraints": {},
420
+ "policies": {},
421
+ "checkConstraints": {},
422
+ "isRLSEnabled": false
423
+ }
424
+ },
425
+ "enums": {
426
+ "public.workspaces_workspace_status": {
427
+ "name": "workspaces_workspace_status",
428
+ "schema": "public",
429
+ "values": ["active", "suspended", "deleted"]
430
+ }
431
+ },
432
+ "schemas": {},
433
+ "sequences": {},
434
+ "roles": {},
435
+ "policies": {},
436
+ "views": {},
437
+ "_meta": {
438
+ "columns": {},
439
+ "schemas": {},
440
+ "tables": {}
441
+ }
442
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "version": "7",
3
+ "dialect": "postgresql",
4
+ "entries": [
5
+ {
6
+ "idx": 0,
7
+ "version": "7",
8
+ "when": 1777229181112,
9
+ "tag": "0000_initial",
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
+ }
@@ -0,0 +1,7 @@
1
+ import {defineConfig} from 'drizzle-kit';
2
+
3
+ export default defineConfig({
4
+ schema: './src/db/schema/*.ts',
5
+ out: './drizzle',
6
+ dialect: 'postgresql',
7
+ });
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@shipfox/api-workspaces",
3
+ "license": "MIT",
4
+ "version": "2.0.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
8
+ "directory": "libs/api/workspaces"
9
+ },
10
+ "private": false,
11
+ "type": "module",
12
+ "main": "dist/index.js",
13
+ "types": "dist/index.d.ts",
14
+ "imports": {
15
+ "#test/*": "./test/*",
16
+ "#*": {
17
+ "workspace-source": "./src/*",
18
+ "development": "./src/*",
19
+ "default": "./dist/*"
20
+ }
21
+ },
22
+ "exports": {
23
+ ".": {
24
+ "development": {
25
+ "types": "./src/index.ts",
26
+ "default": "./src/index.ts"
27
+ },
28
+ "default": {
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ }
32
+ }
33
+ },
34
+ "dependencies": {
35
+ "drizzle-orm": "^0.45.2",
36
+ "zod": "^4.4.3",
37
+ "@shipfox/api-workspaces-dto": "2.0.0",
38
+ "@shipfox/api-auth-context": "2.0.0",
39
+ "@shipfox/node-email": "0.2.1",
40
+ "@shipfox/node-drizzle": "0.2.1",
41
+ "@shipfox/config": "1.2.1",
42
+ "@shipfox/node-fastify": "0.2.1",
43
+ "@shipfox/node-mailer": "0.1.2",
44
+ "@shipfox/node-module": "0.2.0",
45
+ "@shipfox/node-outbox": "0.2.1",
46
+ "@shipfox/node-opentelemetry": "0.5.0",
47
+ "@shipfox/node-postgres": "0.4.1",
48
+ "@shipfox/node-tokens": "0.2.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/pg": "^8.15.5",
52
+ "drizzle-kit": "^0.31.10",
53
+ "fastify": "^5.3.3",
54
+ "fastify-type-provider-zod": "^6.0.0",
55
+ "fishery": "^2.2.2",
56
+ "@shipfox/swc": "1.2.5",
57
+ "@shipfox/typescript": "1.1.6",
58
+ "@shipfox/ts-config": "1.3.8",
59
+ "@shipfox/biome": "1.8.1",
60
+ "@shipfox/vitest": "1.2.2"
61
+ },
62
+ "scripts": {
63
+ "build": "shipfox-swc",
64
+ "check": "shipfox-biome-check",
65
+ "check:fix": "shipfox-biome-check --write",
66
+ "test": "shipfox-vitest-run",
67
+ "test:watch": "shipfox-vitest-watch",
68
+ "type": "shipfox-tsc-check",
69
+ "type:emit": "shipfox-tsc-emit"
70
+ }
71
+ }
package/src/config.ts ADDED
@@ -0,0 +1,51 @@
1
+ import {createConfig, num, str} from '@shipfox/config';
2
+ import {createConsoleMailer, createSmtpMailer, type Mailer} from '@shipfox/node-mailer';
3
+
4
+ export const config = createConfig({
5
+ CLIENT_BASE_URL: str({
6
+ desc: 'Base URL of the client app. Used to build links in workspace invitation emails.',
7
+ default: 'http://localhost:5173',
8
+ }),
9
+ MAILER_TRANSPORT: str({
10
+ desc: 'How emails are delivered. Use console to print them to the log, or smtp to send them through an SMTP server.',
11
+ choices: ['console', 'smtp'],
12
+ default: 'console',
13
+ }),
14
+ MAILER_FROM: str({
15
+ desc: 'Sender address shown on outgoing emails.',
16
+ default: 'noreply@shipfox.local',
17
+ }),
18
+ SMTP_HOST: str({
19
+ desc: 'Hostname of the SMTP server. Required when MAILER_TRANSPORT is smtp.',
20
+ default: undefined,
21
+ }),
22
+ SMTP_PORT: num({
23
+ desc: 'Port of the SMTP server.',
24
+ default: 587,
25
+ }),
26
+ SMTP_USER: str({
27
+ desc: 'Username for SMTP authentication. Leave it unset if the server needs no login.',
28
+ default: undefined,
29
+ }),
30
+ SMTP_PASSWORD: str({
31
+ desc: 'Password for SMTP authentication. Leave it unset if the server needs no login.',
32
+ default: undefined,
33
+ }),
34
+ });
35
+
36
+ function createMailer(): Mailer {
37
+ if (config.MAILER_TRANSPORT === 'smtp') {
38
+ if (!config.SMTP_HOST) throw new Error('SMTP_HOST is required when MAILER_TRANSPORT=smtp');
39
+ return createSmtpMailer({
40
+ host: config.SMTP_HOST,
41
+ port: config.SMTP_PORT,
42
+ ...(config.SMTP_USER ? {user: config.SMTP_USER} : {}),
43
+ ...(config.SMTP_PASSWORD ? {password: config.SMTP_PASSWORD} : {}),
44
+ from: config.MAILER_FROM,
45
+ });
46
+ }
47
+
48
+ return createConsoleMailer({from: config.MAILER_FROM});
49
+ }
50
+
51
+ export const mailer = createMailer();
@@ -0,0 +1,3 @@
1
+ export type {Invitation} from './invitation.js';
2
+ export type {Membership} from './membership.js';
3
+ export type {Workspace, WorkspaceStatus} from './workspace.js';
@@ -0,0 +1,13 @@
1
+ export interface Invitation {
2
+ id: string;
3
+ workspaceId: string;
4
+ email: string;
5
+ hashedToken: string;
6
+ expiresAt: Date;
7
+ acceptedAt: Date | null;
8
+ acceptedByUserId: string | null;
9
+ invitedByUserId: string;
10
+ invitedByDisplay: string | null;
11
+ createdAt: Date;
12
+ updatedAt: Date;
13
+ }
@@ -0,0 +1,9 @@
1
+ export interface Membership {
2
+ id: string;
3
+ userId: string;
4
+ userEmail: string;
5
+ userName: string | null;
6
+ workspaceId: string;
7
+ createdAt: Date;
8
+ updatedAt: Date;
9
+ }
@@ -0,0 +1,10 @@
1
+ export type WorkspaceStatus = 'active' | 'suspended' | 'deleted';
2
+
3
+ export interface Workspace {
4
+ id: string;
5
+ name: string;
6
+ status: WorkspaceStatus;
7
+ settings: Record<string, unknown>;
8
+ createdAt: Date;
9
+ updatedAt: Date;
10
+ }