actor.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import { Context } from "./context"
  2. import { UserRole } from "./schema/user.sql"
  3. import { Log } from "./util/log"
  4. export namespace Actor {
  5. interface Account {
  6. type: "account"
  7. properties: {
  8. accountID: string
  9. email: string
  10. }
  11. }
  12. interface Public {
  13. type: "public"
  14. properties: {}
  15. }
  16. interface User {
  17. type: "user"
  18. properties: {
  19. userID: string
  20. workspaceID: string
  21. accountID: string
  22. role: (typeof UserRole)[number]
  23. }
  24. }
  25. interface System {
  26. type: "system"
  27. properties: {
  28. workspaceID: string
  29. }
  30. }
  31. export type Info = Account | Public | User | System
  32. const ctx = Context.create<Info>()
  33. export const use = ctx.use
  34. const log = Log.create().tag("namespace", "actor")
  35. export function provide<R, T extends Info["type"]>(
  36. type: T,
  37. properties: Extract<Info, { type: T }>["properties"],
  38. cb: () => R,
  39. ) {
  40. return ctx.provide(
  41. {
  42. type,
  43. properties,
  44. } as any,
  45. () => {
  46. return Log.provide({ ...properties }, () => {
  47. log.info("provided")
  48. return cb()
  49. })
  50. },
  51. )
  52. }
  53. export function assert<T extends Info["type"]>(type: T) {
  54. const actor = use()
  55. if (actor.type !== type) {
  56. throw new Error(`Expected actor type ${type}, got ${actor.type}`)
  57. }
  58. return actor as Extract<Info, { type: T }>
  59. }
  60. export function workspace() {
  61. const actor = use()
  62. if ("workspaceID" in actor.properties) {
  63. return actor.properties.workspaceID
  64. }
  65. throw new Error(`actor of type "${actor.type}" is not associated with a workspace`)
  66. }
  67. export function account() {
  68. const actor = use()
  69. if ("accountID" in actor.properties) {
  70. return actor.properties.accountID
  71. }
  72. throw new Error(`actor of type "${actor.type}" is not associated with an account`)
  73. }
  74. export function userID() {
  75. return Actor.assert("user").properties.userID
  76. }
  77. export function userRole() {
  78. return Actor.assert("user").properties.role
  79. }
  80. }