actor.ts 1.5 KB

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