actor.ts 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  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. }
  21. }
  22. interface System {
  23. type: "system"
  24. properties: {
  25. workspaceID: string
  26. }
  27. }
  28. export type Info = Account | Public | User | System
  29. const ctx = Context.create<Info>()
  30. export const use = ctx.use
  31. const log = Log.create().tag("namespace", "actor")
  32. export function provide<R, T extends Info["type"]>(
  33. type: T,
  34. properties: Extract<Info, { type: T }>["properties"],
  35. cb: () => R,
  36. ) {
  37. return ctx.provide(
  38. {
  39. type,
  40. properties,
  41. } as any,
  42. () => {
  43. return Log.provide({ ...properties }, () => {
  44. log.info("provided")
  45. return cb()
  46. })
  47. },
  48. )
  49. }
  50. export function assert<T extends Info["type"]>(type: T) {
  51. const actor = use()
  52. if (actor.type !== type) {
  53. throw new Error(`Expected actor type ${type}, got ${actor.type}`)
  54. }
  55. return actor as Extract<Info, { type: T }>
  56. }
  57. export function workspace() {
  58. const actor = use()
  59. if ("workspaceID" in actor.properties) {
  60. return actor.properties.workspaceID
  61. }
  62. throw new Error(`actor of type "${actor.type}" is not associated with a workspace`)
  63. }
  64. }