@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,2 @@
1
+ $ shipfox-swc
2
+ Successfully compiled: 47 files with swc (171.61ms)
@@ -0,0 +1 @@
1
+ $ shipfox-tsc-emit
@@ -0,0 +1 @@
1
+ $ shipfox-tsc-check
package/CHANGELOG.md ADDED
@@ -0,0 +1,97 @@
1
+ # @shipfox/api-workspaces
2
+
3
+ ## 2.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c31a7e0: Adds public auth session and cookie composition APIs with password-less user and idempotent membership provisioning.
8
+ - 1b0d344: Publishes the complete API runtime closure with packed-consumer-safe internal imports and records its exact package set in application releases.
9
+
10
+ ### Patch Changes
11
+
12
+ - Updated dependencies [0cd6dd4]
13
+ - Updated dependencies [1b0d344]
14
+ - Updated dependencies [521e006]
15
+ - @shipfox/node-module@0.2.0
16
+ - @shipfox/api-auth-context@2.0.0
17
+ - @shipfox/api-workspaces-dto@2.0.0
18
+ - @shipfox/node-tokens@0.2.0
19
+ - @shipfox/config@1.2.1
20
+ - @shipfox/node-drizzle@0.2.1
21
+ - @shipfox/node-email@0.2.1
22
+ - @shipfox/node-fastify@0.2.1
23
+ - @shipfox/node-mailer@0.1.2
24
+ - @shipfox/node-opentelemetry@0.5.0
25
+ - @shipfox/node-outbox@0.2.1
26
+ - @shipfox/node-postgres@0.4.1
27
+
28
+ ## 0.1.2
29
+
30
+ ### Patch Changes
31
+
32
+ - Updated dependencies [705dd43]
33
+ - @shipfox/node-outbox@0.2.0
34
+ - @shipfox/node-module@0.1.2
35
+
36
+ ## 0.1.1
37
+
38
+ ### Patch Changes
39
+
40
+ - Updated dependencies [ec75cd5]
41
+ - Updated dependencies [6a1fb54]
42
+ - @shipfox/node-drizzle@0.2.0
43
+ - @shipfox/node-postgres@0.4.0
44
+ - @shipfox/node-module@0.1.1
45
+ - @shipfox/node-outbox@0.1.1
46
+
47
+ ## 0.1.0
48
+
49
+ ### Minor Changes
50
+
51
+ - a81b68c: Adds provisioner token and auth context primitives for workspace-scoped control-plane credentials.
52
+
53
+ ### Patch Changes
54
+
55
+ - d02c5fd: Queues auth and workspace transactional emails through module-owned outbox events so account verification, password reset, and invitation sends retry outside request transactions.
56
+ - 72ce351: Removes the legacy workspace API-key auth surface, its DTOs, project-access branch, database table, and token prefix support.
57
+ - 82d22e4: Make the workspace-membership gate stateless. `requireWorkspaceAccess` now lives in `@shipfox/api-auth-context` and authorizes a request purely from the verified session-token claims, replacing the `requireMembership` gate in `@shipfox/api-workspaces` that read the workspace row from the database on every workspace-scoped request. Membership and role already travel in the token, so the check needs no database access.
58
+
59
+ This removes the per-request database read and severs the runtime dependency on `@shipfox/api-workspaces` from feature modules that only needed the membership gate (integration providers, secrets, projects, agent, runners). Workspace existence and `active`-status enforcement, which no code path currently exercises, moves off the hot path; enforce it at token issuance when workspace suspension is introduced.
60
+
61
+ - 27770eb: Tightens signup, workspace, and project display-name validation with shared trimming, control and format-character rejection, length limits, and contextual client form errors.
62
+ - Updated dependencies [cdd8931]
63
+ - Updated dependencies [34ba284]
64
+ - Updated dependencies [5707d6d]
65
+ - Updated dependencies [b9c3f32]
66
+ - Updated dependencies [d02c5fd]
67
+ - Updated dependencies [a81b68c]
68
+ - Updated dependencies [c0a883c]
69
+ - Updated dependencies [72ce351]
70
+ - Updated dependencies [e47f8da]
71
+ - Updated dependencies [7b175f5]
72
+ - Updated dependencies [ae7a63c]
73
+ - Updated dependencies [5729548]
74
+ - Updated dependencies [f92122b]
75
+ - Updated dependencies [857fd73]
76
+ - Updated dependencies [75520ff]
77
+ - Updated dependencies [4798517]
78
+ - Updated dependencies [d6d4862]
79
+ - Updated dependencies [c0a883c]
80
+ - Updated dependencies [6077301]
81
+ - Updated dependencies [3bea87f]
82
+ - Updated dependencies [82d22e4]
83
+ - Updated dependencies [27770eb]
84
+ - Updated dependencies [6181819]
85
+ - Updated dependencies [9c149d1]
86
+ - @shipfox/node-email@0.2.0
87
+ - @shipfox/node-fastify@0.2.0
88
+ - @shipfox/node-drizzle@0.1.0
89
+ - @shipfox/api-workspaces-dto@0.1.0
90
+ - @shipfox/node-tokens@0.1.0
91
+ - @shipfox/api-auth-context@0.1.0
92
+ - @shipfox/node-opentelemetry@0.4.2
93
+ - @shipfox/node-postgres@0.3.2
94
+ - @shipfox/node-module@0.1.0
95
+ - @shipfox/node-outbox@0.1.0
96
+ - @shipfox/node-mailer@0.1.1
97
+ - @shipfox/config@1.2.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shipfox
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # Shipfox API Workspaces
2
+
3
+ Shipfox API Workspaces manages who can use a workspace and send or accept invites.
4
+
5
+ ## What it does
6
+
7
+ - **`workspacesModule`**: Adds table changes, API routes, outbox events, and metrics.
8
+ - **`ensureMembership`**: Adds a user to a workspace or returns the row that is there.
9
+ - **Invitation helpers**: Make, view, accept, list, and revoke invites.
10
+ - **Workspace helpers**: Read workspaces and check a signed-in user's access.
11
+
12
+ ## Installation / Setup
13
+
14
+ ```sh
15
+ pnpm add @shipfox/api-workspaces
16
+ ```
17
+
18
+ Set `CLIENT_BASE_URL` to the public client URL. Invite emails use this URL for
19
+ their accept links. Set up the shared mailer when invite email must be sent.
20
+
21
+ ## Usage
22
+
23
+ Call `ensureMembership` after an identity callback has the user profile:
24
+
25
+ ```ts
26
+ import {ensureMembership} from '@shipfox/api-workspaces';
27
+
28
+ const membership = await ensureMembership({
29
+ userId: user.id,
30
+ userEmail: user.email,
31
+ userName: user.name,
32
+ workspaceId,
33
+ });
34
+ ```
35
+
36
+ ## Environment
37
+
38
+ | Variable | Default | Purpose |
39
+ | --- | --- | --- |
40
+ | `CLIENT_BASE_URL` | `http://localhost:5173` | Base URL used in workspace invitation links. |
41
+
42
+ The package also uses the shared mailer configuration when it sends invitation email.
43
+
44
+ ## Routes / API / Data Model
45
+
46
+ Routes mount under `/workspaces`. They make and list workspaces, manage members,
47
+ and make, list, view, accept, or revoke invites.
48
+
49
+ The module creates these tables:
50
+
51
+ - `workspaces`
52
+ - `workspaces_memberships`
53
+ - `workspaces_invitations`
54
+ - `workspaces_outbox`
55
+
56
+ ## Behavior Notes
57
+
58
+ `ensureMembership` uses a unique database rule to keep one row for `user_id`
59
+ and `workspace_id`. Calls at the same time get the same row. It saves the email
60
+ and name only for a new row. Later calls do not change saved values. The metric
61
+ counts only new rows.
62
+
63
+ Invite acceptance keeps its current transaction. It does not change a row that
64
+ is already there.
65
+
66
+ `ensureMembership` fails when its workspace does not exist. Workspace checks
67
+ throw `WorkspaceNotFoundError` or `MembershipRequiredError`. Invite helpers
68
+ throw their exported token and email mismatch errors when an invite cannot be
69
+ used.
70
+
71
+ ## Development
72
+
73
+ ```sh
74
+ turbo check --filter=@shipfox/api-workspaces
75
+ turbo type --filter=@shipfox/api-workspaces
76
+ turbo test --filter=@shipfox/api-workspaces
77
+ ```
78
+
79
+ Tests use Vitest and PostgreSQL. Start local services before the suite:
80
+
81
+ ```sh
82
+ docker compose up -d
83
+ ```
84
+
85
+ ## License
86
+
87
+ MIT
@@ -0,0 +1,12 @@
1
+ import { type Mailer } from '@shipfox/node-mailer';
2
+ export declare const config: Readonly<{
3
+ CLIENT_BASE_URL: string;
4
+ MAILER_TRANSPORT: "console" | "smtp";
5
+ MAILER_FROM: string;
6
+ SMTP_HOST: string | undefined;
7
+ SMTP_PORT: number;
8
+ SMTP_USER: string | undefined;
9
+ SMTP_PASSWORD: string | undefined;
10
+ } & import("@shipfox/config").CleanedEnvAccessors>;
11
+ export declare const mailer: Mailer;
12
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,EAAwC,KAAK,MAAM,EAAC,MAAM,sBAAsB,CAAC;AAExF,eAAO,MAAM,MAAM;;;;;;;;kDA8BjB,CAAC;AAiBH,eAAO,MAAM,MAAM,QAAiB,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,58 @@
1
+ import { createConfig, num, str } from '@shipfox/config';
2
+ import { createConsoleMailer, createSmtpMailer } from '@shipfox/node-mailer';
3
+ export const config = createConfig({
4
+ CLIENT_BASE_URL: str({
5
+ desc: 'Base URL of the client app. Used to build links in workspace invitation emails.',
6
+ default: 'http://localhost:5173'
7
+ }),
8
+ MAILER_TRANSPORT: str({
9
+ desc: 'How emails are delivered. Use console to print them to the log, or smtp to send them through an SMTP server.',
10
+ choices: [
11
+ 'console',
12
+ 'smtp'
13
+ ],
14
+ default: 'console'
15
+ }),
16
+ MAILER_FROM: str({
17
+ desc: 'Sender address shown on outgoing emails.',
18
+ default: 'noreply@shipfox.local'
19
+ }),
20
+ SMTP_HOST: str({
21
+ desc: 'Hostname of the SMTP server. Required when MAILER_TRANSPORT is smtp.',
22
+ default: undefined
23
+ }),
24
+ SMTP_PORT: num({
25
+ desc: 'Port of the SMTP server.',
26
+ default: 587
27
+ }),
28
+ SMTP_USER: str({
29
+ desc: 'Username for SMTP authentication. Leave it unset if the server needs no login.',
30
+ default: undefined
31
+ }),
32
+ SMTP_PASSWORD: str({
33
+ desc: 'Password for SMTP authentication. Leave it unset if the server needs no login.',
34
+ default: undefined
35
+ })
36
+ });
37
+ function createMailer() {
38
+ if (config.MAILER_TRANSPORT === 'smtp') {
39
+ if (!config.SMTP_HOST) throw new Error('SMTP_HOST is required when MAILER_TRANSPORT=smtp');
40
+ return createSmtpMailer({
41
+ host: config.SMTP_HOST,
42
+ port: config.SMTP_PORT,
43
+ ...config.SMTP_USER ? {
44
+ user: config.SMTP_USER
45
+ } : {},
46
+ ...config.SMTP_PASSWORD ? {
47
+ password: config.SMTP_PASSWORD
48
+ } : {},
49
+ from: config.MAILER_FROM
50
+ });
51
+ }
52
+ return createConsoleMailer({
53
+ from: config.MAILER_FROM
54
+ });
55
+ }
56
+ export const mailer = createMailer();
57
+
58
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts"],"sourcesContent":["import {createConfig, num, str} from '@shipfox/config';\nimport {createConsoleMailer, createSmtpMailer, type Mailer} from '@shipfox/node-mailer';\n\nexport const config = createConfig({\n CLIENT_BASE_URL: str({\n desc: 'Base URL of the client app. Used to build links in workspace invitation emails.',\n default: 'http://localhost:5173',\n }),\n MAILER_TRANSPORT: str({\n desc: 'How emails are delivered. Use console to print them to the log, or smtp to send them through an SMTP server.',\n choices: ['console', 'smtp'],\n default: 'console',\n }),\n MAILER_FROM: str({\n desc: 'Sender address shown on outgoing emails.',\n default: 'noreply@shipfox.local',\n }),\n SMTP_HOST: str({\n desc: 'Hostname of the SMTP server. Required when MAILER_TRANSPORT is smtp.',\n default: undefined,\n }),\n SMTP_PORT: num({\n desc: 'Port of the SMTP server.',\n default: 587,\n }),\n SMTP_USER: str({\n desc: 'Username for SMTP authentication. Leave it unset if the server needs no login.',\n default: undefined,\n }),\n SMTP_PASSWORD: str({\n desc: 'Password for SMTP authentication. Leave it unset if the server needs no login.',\n default: undefined,\n }),\n});\n\nfunction createMailer(): Mailer {\n if (config.MAILER_TRANSPORT === 'smtp') {\n if (!config.SMTP_HOST) throw new Error('SMTP_HOST is required when MAILER_TRANSPORT=smtp');\n return createSmtpMailer({\n host: config.SMTP_HOST,\n port: config.SMTP_PORT,\n ...(config.SMTP_USER ? {user: config.SMTP_USER} : {}),\n ...(config.SMTP_PASSWORD ? {password: config.SMTP_PASSWORD} : {}),\n from: config.MAILER_FROM,\n });\n }\n\n return createConsoleMailer({from: config.MAILER_FROM});\n}\n\nexport const mailer = createMailer();\n"],"names":["createConfig","num","str","createConsoleMailer","createSmtpMailer","config","CLIENT_BASE_URL","desc","default","MAILER_TRANSPORT","choices","MAILER_FROM","SMTP_HOST","undefined","SMTP_PORT","SMTP_USER","SMTP_PASSWORD","createMailer","Error","host","port","user","password","from","mailer"],"mappings":"AAAA,SAAQA,YAAY,EAAEC,GAAG,EAAEC,GAAG,QAAO,kBAAkB;AACvD,SAAQC,mBAAmB,EAAEC,gBAAgB,QAAoB,uBAAuB;AAExF,OAAO,MAAMC,SAASL,aAAa;IACjCM,iBAAiBJ,IAAI;QACnBK,MAAM;QACNC,SAAS;IACX;IACAC,kBAAkBP,IAAI;QACpBK,MAAM;QACNG,SAAS;YAAC;YAAW;SAAO;QAC5BF,SAAS;IACX;IACAG,aAAaT,IAAI;QACfK,MAAM;QACNC,SAAS;IACX;IACAI,WAAWV,IAAI;QACbK,MAAM;QACNC,SAASK;IACX;IACAC,WAAWb,IAAI;QACbM,MAAM;QACNC,SAAS;IACX;IACAO,WAAWb,IAAI;QACbK,MAAM;QACNC,SAASK;IACX;IACAG,eAAed,IAAI;QACjBK,MAAM;QACNC,SAASK;IACX;AACF,GAAG;AAEH,SAASI;IACP,IAAIZ,OAAOI,gBAAgB,KAAK,QAAQ;QACtC,IAAI,CAACJ,OAAOO,SAAS,EAAE,MAAM,IAAIM,MAAM;QACvC,OAAOd,iBAAiB;YACtBe,MAAMd,OAAOO,SAAS;YACtBQ,MAAMf,OAAOS,SAAS;YACtB,GAAIT,OAAOU,SAAS,GAAG;gBAACM,MAAMhB,OAAOU,SAAS;YAAA,IAAI,CAAC,CAAC;YACpD,GAAIV,OAAOW,aAAa,GAAG;gBAACM,UAAUjB,OAAOW,aAAa;YAAA,IAAI,CAAC,CAAC;YAChEO,MAAMlB,OAAOM,WAAW;QAC1B;IACF;IAEA,OAAOR,oBAAoB;QAACoB,MAAMlB,OAAOM,WAAW;IAAA;AACtD;AAEA,OAAO,MAAMa,SAASP,eAAe"}
@@ -0,0 +1,4 @@
1
+ export type { Invitation } from './invitation.js';
2
+ export type { Membership } from './membership.js';
3
+ export type { Workspace, WorkspaceStatus } from './workspace.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/entities/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAC,SAAS,EAAE,eAAe,EAAC,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/entities/index.ts"],"sourcesContent":["export type {Invitation} from './invitation.js';\nexport type {Membership} from './membership.js';\nexport type {Workspace, WorkspaceStatus} from './workspace.js';\n"],"names":[],"mappings":"AAEA,WAA+D"}
@@ -0,0 +1,14 @@
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
+ }
14
+ //# sourceMappingURL=invitation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invitation.d.ts","sourceRoot":"","sources":["../../../src/core/entities/invitation.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=invitation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/entities/invitation.ts"],"sourcesContent":["export interface Invitation {\n id: string;\n workspaceId: string;\n email: string;\n hashedToken: string;\n expiresAt: Date;\n acceptedAt: Date | null;\n acceptedByUserId: string | null;\n invitedByUserId: string;\n invitedByDisplay: string | null;\n createdAt: Date;\n updatedAt: Date;\n}\n"],"names":[],"mappings":"AAAA,WAYC"}
@@ -0,0 +1,10 @@
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
+ }
10
+ //# sourceMappingURL=membership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"membership.d.ts","sourceRoot":"","sources":["../../../src/core/entities/membership.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=membership.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/entities/membership.ts"],"sourcesContent":["export interface Membership {\n id: string;\n userId: string;\n userEmail: string;\n userName: string | null;\n workspaceId: string;\n createdAt: Date;\n updatedAt: Date;\n}\n"],"names":[],"mappings":"AAAA,WAQC"}
@@ -0,0 +1,10 @@
1
+ export type WorkspaceStatus = 'active' | 'suspended' | 'deleted';
2
+ export interface Workspace {
3
+ id: string;
4
+ name: string;
5
+ status: WorkspaceStatus;
6
+ settings: Record<string, unknown>;
7
+ createdAt: Date;
8
+ updatedAt: Date;
9
+ }
10
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../../src/core/entities/workspace.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB"}
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/entities/workspace.ts"],"sourcesContent":["export type WorkspaceStatus = 'active' | 'suspended' | 'deleted';\n\nexport interface Workspace {\n id: string;\n name: string;\n status: WorkspaceStatus;\n settings: Record<string, unknown>;\n createdAt: Date;\n updatedAt: Date;\n}\n"],"names":[],"mappings":"AAEA,WAOC"}
@@ -0,0 +1,52 @@
1
+ export declare class WorkspaceNotFoundError extends Error {
2
+ constructor(workspaceId: string);
3
+ }
4
+ export declare class WorkspaceInactiveError extends Error {
5
+ constructor(workspaceId: string);
6
+ }
7
+ export declare class InvitationNotFoundError extends Error {
8
+ constructor(id: string);
9
+ }
10
+ export declare class InvitationWorkspaceMismatchError extends Error {
11
+ constructor();
12
+ }
13
+ export declare class MembershipNotFoundError extends Error {
14
+ constructor(userId: string, workspaceId: string);
15
+ }
16
+ export declare class UserNotFoundError extends Error {
17
+ constructor(idOrEmail: string);
18
+ }
19
+ export declare class EmailTakenError extends Error {
20
+ constructor(email: string);
21
+ }
22
+ export declare class InvalidCredentialsError extends Error {
23
+ constructor();
24
+ }
25
+ export declare class EmailNotVerifiedError extends Error {
26
+ constructor();
27
+ }
28
+ export declare class TokenInvalidError extends Error {
29
+ constructor(reason?: string);
30
+ }
31
+ export declare class TokenExpiredError extends Error {
32
+ constructor();
33
+ }
34
+ export declare class TokenAlreadyUsedError extends Error {
35
+ constructor();
36
+ }
37
+ export declare class MembershipRequiredError extends Error {
38
+ constructor(workspaceId: string);
39
+ }
40
+ export declare class LastMemberError extends Error {
41
+ constructor(workspaceId: string);
42
+ }
43
+ export declare class SelfRemovalNotAllowedError extends Error {
44
+ constructor();
45
+ }
46
+ export declare class InvitationEmailMismatchError extends Error {
47
+ constructor();
48
+ }
49
+ export declare class OpenInvitationExistsError extends Error {
50
+ constructor(email: string);
51
+ }
52
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,EAAE,EAAE,MAAM;CAIvB;AAED,qBAAa,gCAAiC,SAAQ,KAAK;;CAK1D;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAIhD;AAED,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,SAAS,EAAE,MAAM;CAI9B;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,KAAK,EAAE,MAAM;CAI1B;AAED,qBAAa,uBAAwB,SAAQ,KAAK;;CAKjD;AAED,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C;AAED,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,MAAM,CAAC,EAAE,MAAM;CAI5B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;;CAK3C;AAED,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,WAAW,EAAE,MAAM;CAIhC;AAED,qBAAa,0BAA2B,SAAQ,KAAK;;CAKpD;AAED,qBAAa,4BAA6B,SAAQ,KAAK;;CAKtD;AAED,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,KAAK,EAAE,MAAM;CAI1B"}
@@ -0,0 +1,104 @@
1
+ export class WorkspaceNotFoundError extends Error {
2
+ constructor(workspaceId){
3
+ super(`Workspace not found: ${workspaceId}`);
4
+ this.name = 'WorkspaceNotFoundError';
5
+ }
6
+ }
7
+ export class WorkspaceInactiveError extends Error {
8
+ constructor(workspaceId){
9
+ super(`Workspace is not active: ${workspaceId}`);
10
+ this.name = 'WorkspaceInactiveError';
11
+ }
12
+ }
13
+ export class InvitationNotFoundError extends Error {
14
+ constructor(id){
15
+ super(`Invitation not found: ${id}`);
16
+ this.name = 'InvitationNotFoundError';
17
+ }
18
+ }
19
+ export class InvitationWorkspaceMismatchError extends Error {
20
+ constructor(){
21
+ super('Invitation does not belong to this workspace');
22
+ this.name = 'InvitationWorkspaceMismatchError';
23
+ }
24
+ }
25
+ export class MembershipNotFoundError extends Error {
26
+ constructor(userId, workspaceId){
27
+ super(`Membership not found for user ${userId} in workspace ${workspaceId}`);
28
+ this.name = 'MembershipNotFoundError';
29
+ }
30
+ }
31
+ export class UserNotFoundError extends Error {
32
+ constructor(idOrEmail){
33
+ super(`User not found: ${idOrEmail}`);
34
+ this.name = 'UserNotFoundError';
35
+ }
36
+ }
37
+ export class EmailTakenError extends Error {
38
+ constructor(email){
39
+ super(`Email already registered: ${email}`);
40
+ this.name = 'EmailTakenError';
41
+ }
42
+ }
43
+ export class InvalidCredentialsError extends Error {
44
+ constructor(){
45
+ super('Invalid credentials');
46
+ this.name = 'InvalidCredentialsError';
47
+ }
48
+ }
49
+ export class EmailNotVerifiedError extends Error {
50
+ constructor(){
51
+ super('Email not verified');
52
+ this.name = 'EmailNotVerifiedError';
53
+ }
54
+ }
55
+ export class TokenInvalidError extends Error {
56
+ constructor(reason){
57
+ super(reason ? `Invalid token: ${reason}` : 'Invalid token');
58
+ this.name = 'TokenInvalidError';
59
+ }
60
+ }
61
+ export class TokenExpiredError extends Error {
62
+ constructor(){
63
+ super('Token has expired');
64
+ this.name = 'TokenExpiredError';
65
+ }
66
+ }
67
+ export class TokenAlreadyUsedError extends Error {
68
+ constructor(){
69
+ super('Token has already been used');
70
+ this.name = 'TokenAlreadyUsedError';
71
+ }
72
+ }
73
+ export class MembershipRequiredError extends Error {
74
+ constructor(workspaceId){
75
+ super(`Membership required for workspace: ${workspaceId}`);
76
+ this.name = 'MembershipRequiredError';
77
+ }
78
+ }
79
+ export class LastMemberError extends Error {
80
+ constructor(workspaceId){
81
+ super(`Cannot remove the last member of workspace: ${workspaceId}`);
82
+ this.name = 'LastMemberError';
83
+ }
84
+ }
85
+ export class SelfRemovalNotAllowedError extends Error {
86
+ constructor(){
87
+ super('Cannot remove yourself from a workspace');
88
+ this.name = 'SelfRemovalNotAllowedError';
89
+ }
90
+ }
91
+ export class InvitationEmailMismatchError extends Error {
92
+ constructor(){
93
+ super('Invitation email does not match authenticated user');
94
+ this.name = 'InvitationEmailMismatchError';
95
+ }
96
+ }
97
+ export class OpenInvitationExistsError extends Error {
98
+ constructor(email){
99
+ super(`An open invitation already exists for: ${email}`);
100
+ this.name = 'OpenInvitationExistsError';
101
+ }
102
+ }
103
+
104
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/errors.ts"],"sourcesContent":["export class WorkspaceNotFoundError extends Error {\n constructor(workspaceId: string) {\n super(`Workspace not found: ${workspaceId}`);\n this.name = 'WorkspaceNotFoundError';\n }\n}\n\nexport class WorkspaceInactiveError extends Error {\n constructor(workspaceId: string) {\n super(`Workspace is not active: ${workspaceId}`);\n this.name = 'WorkspaceInactiveError';\n }\n}\n\nexport class InvitationNotFoundError extends Error {\n constructor(id: string) {\n super(`Invitation not found: ${id}`);\n this.name = 'InvitationNotFoundError';\n }\n}\n\nexport class InvitationWorkspaceMismatchError extends Error {\n constructor() {\n super('Invitation does not belong to this workspace');\n this.name = 'InvitationWorkspaceMismatchError';\n }\n}\n\nexport class MembershipNotFoundError extends Error {\n constructor(userId: string, workspaceId: string) {\n super(`Membership not found for user ${userId} in workspace ${workspaceId}`);\n this.name = 'MembershipNotFoundError';\n }\n}\n\nexport class UserNotFoundError extends Error {\n constructor(idOrEmail: string) {\n super(`User not found: ${idOrEmail}`);\n this.name = 'UserNotFoundError';\n }\n}\n\nexport class EmailTakenError extends Error {\n constructor(email: string) {\n super(`Email already registered: ${email}`);\n this.name = 'EmailTakenError';\n }\n}\n\nexport class InvalidCredentialsError extends Error {\n constructor() {\n super('Invalid credentials');\n this.name = 'InvalidCredentialsError';\n }\n}\n\nexport class EmailNotVerifiedError extends Error {\n constructor() {\n super('Email not verified');\n this.name = 'EmailNotVerifiedError';\n }\n}\n\nexport class TokenInvalidError extends Error {\n constructor(reason?: string) {\n super(reason ? `Invalid token: ${reason}` : 'Invalid token');\n this.name = 'TokenInvalidError';\n }\n}\n\nexport class TokenExpiredError extends Error {\n constructor() {\n super('Token has expired');\n this.name = 'TokenExpiredError';\n }\n}\n\nexport class TokenAlreadyUsedError extends Error {\n constructor() {\n super('Token has already been used');\n this.name = 'TokenAlreadyUsedError';\n }\n}\n\nexport class MembershipRequiredError extends Error {\n constructor(workspaceId: string) {\n super(`Membership required for workspace: ${workspaceId}`);\n this.name = 'MembershipRequiredError';\n }\n}\n\nexport class LastMemberError extends Error {\n constructor(workspaceId: string) {\n super(`Cannot remove the last member of workspace: ${workspaceId}`);\n this.name = 'LastMemberError';\n }\n}\n\nexport class SelfRemovalNotAllowedError extends Error {\n constructor() {\n super('Cannot remove yourself from a workspace');\n this.name = 'SelfRemovalNotAllowedError';\n }\n}\n\nexport class InvitationEmailMismatchError extends Error {\n constructor() {\n super('Invitation email does not match authenticated user');\n this.name = 'InvitationEmailMismatchError';\n }\n}\n\nexport class OpenInvitationExistsError extends Error {\n constructor(email: string) {\n super(`An open invitation already exists for: ${email}`);\n this.name = 'OpenInvitationExistsError';\n }\n}\n"],"names":["WorkspaceNotFoundError","Error","workspaceId","name","WorkspaceInactiveError","InvitationNotFoundError","id","InvitationWorkspaceMismatchError","MembershipNotFoundError","userId","UserNotFoundError","idOrEmail","EmailTakenError","email","InvalidCredentialsError","EmailNotVerifiedError","TokenInvalidError","reason","TokenExpiredError","TokenAlreadyUsedError","MembershipRequiredError","LastMemberError","SelfRemovalNotAllowedError","InvitationEmailMismatchError","OpenInvitationExistsError"],"mappings":"AAAA,OAAO,MAAMA,+BAA+BC;IAC1C,YAAYC,WAAmB,CAAE;QAC/B,KAAK,CAAC,CAAC,qBAAqB,EAAEA,aAAa;QAC3C,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMC,+BAA+BH;IAC1C,YAAYC,WAAmB,CAAE;QAC/B,KAAK,CAAC,CAAC,yBAAyB,EAAEA,aAAa;QAC/C,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAME,gCAAgCJ;IAC3C,YAAYK,EAAU,CAAE;QACtB,KAAK,CAAC,CAAC,sBAAsB,EAAEA,IAAI;QACnC,IAAI,CAACH,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMI,yCAAyCN;IACpD,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMK,gCAAgCP;IAC3C,YAAYQ,MAAc,EAAEP,WAAmB,CAAE;QAC/C,KAAK,CAAC,CAAC,8BAA8B,EAAEO,OAAO,cAAc,EAAEP,aAAa;QAC3E,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMO,0BAA0BT;IACrC,YAAYU,SAAiB,CAAE;QAC7B,KAAK,CAAC,CAAC,gBAAgB,EAAEA,WAAW;QACpC,IAAI,CAACR,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMS,wBAAwBX;IACnC,YAAYY,KAAa,CAAE;QACzB,KAAK,CAAC,CAAC,0BAA0B,EAAEA,OAAO;QAC1C,IAAI,CAACV,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMW,gCAAgCb;IAC3C,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMY,8BAA8Bd;IACzC,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMa,0BAA0Bf;IACrC,YAAYgB,MAAe,CAAE;QAC3B,KAAK,CAACA,SAAS,CAAC,eAAe,EAAEA,QAAQ,GAAG;QAC5C,IAAI,CAACd,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMe,0BAA0BjB;IACrC,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMgB,8BAA8BlB;IACzC,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMiB,gCAAgCnB;IAC3C,YAAYC,WAAmB,CAAE;QAC/B,KAAK,CAAC,CAAC,mCAAmC,EAAEA,aAAa;QACzD,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMkB,wBAAwBpB;IACnC,YAAYC,WAAmB,CAAE;QAC/B,KAAK,CAAC,CAAC,4CAA4C,EAAEA,aAAa;QAClE,IAAI,CAACC,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMmB,mCAAmCrB;IAC9C,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMoB,qCAAqCtB;IAChD,aAAc;QACZ,KAAK,CAAC;QACN,IAAI,CAACE,IAAI,GAAG;IACd;AACF;AAEA,OAAO,MAAMqB,kCAAkCvB;IAC7C,YAAYY,KAAa,CAAE;QACzB,KAAK,CAAC,CAAC,uCAAuC,EAAEA,OAAO;QACvD,IAAI,CAACV,IAAI,GAAG;IACd;AACF"}
@@ -0,0 +1,8 @@
1
+ export type { Invitation } from './entities/invitation.js';
2
+ export type { Membership } from './entities/membership.js';
3
+ export type { Workspace, WorkspaceStatus } from './entities/workspace.js';
4
+ export { InvitationEmailMismatchError, InvitationNotFoundError, InvitationWorkspaceMismatchError, LastMemberError, MembershipNotFoundError, MembershipRequiredError, OpenInvitationExistsError, SelfRemovalNotAllowedError, TokenAlreadyUsedError, TokenExpiredError, WorkspaceNotFoundError, } from './errors.js';
5
+ export { acceptWorkspaceInvitation, createWorkspaceInvitation, listWorkspaceInvitations, type PreviewInvitationResult, previewInvitation, revokeWorkspaceInvitation, } from './invitations.js';
6
+ export { type EnsureMembershipParams, ensureMembership } from './memberships.js';
7
+ export { createWorkspaceForUser, getWorkspace, listUserWorkspaceMemberships, listWorkspaceMembers, type RequireWorkspaceMembershipParams, type RequireWorkspaceMembershipResult, removeWorkspaceMember, requireWorkspaceMembership, } from './workspaces.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AACzD,YAAY,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AACzD,YAAY,EAAC,SAAS,EAAE,eAAe,EAAC,MAAM,yBAAyB,CAAC;AACxE,OAAO,EACL,4BAA4B,EAC5B,uBAAuB,EACvB,gCAAgC,EAChC,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,yBAAyB,EACzB,0BAA0B,EAC1B,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,yBAAyB,EACzB,yBAAyB,EACzB,wBAAwB,EACxB,KAAK,uBAAuB,EAC5B,iBAAiB,EACjB,yBAAyB,GAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAC,KAAK,sBAAsB,EAAE,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,4BAA4B,EAC5B,oBAAoB,EACpB,KAAK,gCAAgC,EACrC,KAAK,gCAAgC,EACrC,qBAAqB,EACrB,0BAA0B,GAC3B,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { InvitationEmailMismatchError, InvitationNotFoundError, InvitationWorkspaceMismatchError, LastMemberError, MembershipNotFoundError, MembershipRequiredError, OpenInvitationExistsError, SelfRemovalNotAllowedError, TokenAlreadyUsedError, TokenExpiredError, WorkspaceNotFoundError } from './errors.js';
2
+ export { acceptWorkspaceInvitation, createWorkspaceInvitation, listWorkspaceInvitations, previewInvitation, revokeWorkspaceInvitation } from './invitations.js';
3
+ export { ensureMembership } from './memberships.js';
4
+ export { createWorkspaceForUser, getWorkspace, listUserWorkspaceMemberships, listWorkspaceMembers, removeWorkspaceMember, requireWorkspaceMembership } from './workspaces.js';
5
+
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/index.ts"],"sourcesContent":["export type {Invitation} from './entities/invitation.js';\nexport type {Membership} from './entities/membership.js';\nexport type {Workspace, WorkspaceStatus} from './entities/workspace.js';\nexport {\n InvitationEmailMismatchError,\n InvitationNotFoundError,\n InvitationWorkspaceMismatchError,\n LastMemberError,\n MembershipNotFoundError,\n MembershipRequiredError,\n OpenInvitationExistsError,\n SelfRemovalNotAllowedError,\n TokenAlreadyUsedError,\n TokenExpiredError,\n WorkspaceNotFoundError,\n} from './errors.js';\nexport {\n acceptWorkspaceInvitation,\n createWorkspaceInvitation,\n listWorkspaceInvitations,\n type PreviewInvitationResult,\n previewInvitation,\n revokeWorkspaceInvitation,\n} from './invitations.js';\nexport {type EnsureMembershipParams, ensureMembership} from './memberships.js';\nexport {\n createWorkspaceForUser,\n getWorkspace,\n listUserWorkspaceMemberships,\n listWorkspaceMembers,\n type RequireWorkspaceMembershipParams,\n type RequireWorkspaceMembershipResult,\n removeWorkspaceMember,\n requireWorkspaceMembership,\n} from './workspaces.js';\n"],"names":["InvitationEmailMismatchError","InvitationNotFoundError","InvitationWorkspaceMismatchError","LastMemberError","MembershipNotFoundError","MembershipRequiredError","OpenInvitationExistsError","SelfRemovalNotAllowedError","TokenAlreadyUsedError","TokenExpiredError","WorkspaceNotFoundError","acceptWorkspaceInvitation","createWorkspaceInvitation","listWorkspaceInvitations","previewInvitation","revokeWorkspaceInvitation","ensureMembership","createWorkspaceForUser","getWorkspace","listUserWorkspaceMemberships","listWorkspaceMembers","removeWorkspaceMember","requireWorkspaceMembership"],"mappings":"AAGA,SACEA,4BAA4B,EAC5BC,uBAAuB,EACvBC,gCAAgC,EAChCC,eAAe,EACfC,uBAAuB,EACvBC,uBAAuB,EACvBC,yBAAyB,EACzBC,0BAA0B,EAC1BC,qBAAqB,EACrBC,iBAAiB,EACjBC,sBAAsB,QACjB,cAAc;AACrB,SACEC,yBAAyB,EACzBC,yBAAyB,EACzBC,wBAAwB,EAExBC,iBAAiB,EACjBC,yBAAyB,QACpB,mBAAmB;AAC1B,SAAqCC,gBAAgB,QAAO,mBAAmB;AAC/E,SACEC,sBAAsB,EACtBC,YAAY,EACZC,4BAA4B,EAC5BC,oBAAoB,EAGpBC,qBAAqB,EACrBC,0BAA0B,QACrB,kBAAkB"}