@things-factory/worklist 10.1.202 → 10.1.205

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 (130) hide show
  1. package/dist-client/index.d.ts +1 -0
  2. package/dist-client/index.js +1 -0
  3. package/dist-client/index.js.map +1 -1
  4. package/dist-client/pages/activity/activity-list-page.d.ts +3 -0
  5. package/dist-client/pages/activity/activity-list-page.js +25 -13
  6. package/dist-client/pages/activity/activity-list-page.js.map +1 -1
  7. package/dist-client/pages/activity/activity-partial-view.js +1 -1
  8. package/dist-client/pages/activity/activity-partial-view.js.map +1 -1
  9. package/dist-client/pages/activity/assignee-roles-cell.d.ts +32 -0
  10. package/dist-client/pages/activity/assignee-roles-cell.js +26 -0
  11. package/dist-client/pages/activity/assignee-roles-cell.js.map +1 -0
  12. package/dist-client/pages/activity-catalog/activity-catalog-page.js +1 -1
  13. package/dist-client/pages/activity-catalog/activity-catalog-page.js.map +1 -1
  14. package/dist-client/pages/todo/done-list-calendar-page.d.ts +2 -0
  15. package/dist-client/pages/todo/done-list-calendar-page.js +63 -64
  16. package/dist-client/pages/todo/done-list-calendar-page.js.map +1 -1
  17. package/dist-client/pages/work-door/door-sentence.d.ts +1 -1
  18. package/dist-client/pages/work-door/door-sentence.js +2 -2
  19. package/dist-client/pages/work-door/door-sentence.js.map +1 -1
  20. package/dist-client/tsconfig.tsbuildinfo +1 -1
  21. package/dist-client/types/activity-instance-type.d.ts +2 -2
  22. package/dist-client/types/activity-instance-type.js.map +1 -1
  23. package/dist-client/types/activity-instance.d.ts +1 -1
  24. package/dist-client/types/activity-instance.js.map +1 -1
  25. package/dist-client/types/activity.d.ts +1 -1
  26. package/dist-client/types/activity.js.map +1 -1
  27. package/dist-client/work-calendar-sources.d.ts +53 -0
  28. package/dist-client/work-calendar-sources.js +47 -0
  29. package/dist-client/work-calendar-sources.js.map +1 -0
  30. package/dist-server/controllers/activity-approval/resolve-judgeable-seats.d.ts +2 -2
  31. package/dist-server/controllers/activity-approval/resolve-judgeable-seats.js +2 -2
  32. package/dist-server/controllers/activity-approval/resolve-judgeable-seats.js.map +1 -1
  33. package/dist-server/controllers/activity-instance/abort.js +1 -1
  34. package/dist-server/controllers/activity-instance/abort.js.map +1 -1
  35. package/dist-server/controllers/activity-instance/assign.d.ts +2 -1
  36. package/dist-server/controllers/activity-instance/assign.js +104 -2
  37. package/dist-server/controllers/activity-instance/assign.js.map +1 -1
  38. package/dist-server/controllers/activity-instance/assignee-input.d.ts +25 -0
  39. package/dist-server/controllers/activity-instance/assignee-input.js +28 -0
  40. package/dist-server/controllers/activity-instance/assignee-input.js.map +1 -0
  41. package/dist-server/controllers/activity-instance/draft.js +7 -2
  42. package/dist-server/controllers/activity-instance/draft.js.map +1 -1
  43. package/dist-server/controllers/activity-instance/end.js +1 -1
  44. package/dist-server/controllers/activity-instance/end.js.map +1 -1
  45. package/dist-server/controllers/activity-instance/entitlement.d.ts +1 -1
  46. package/dist-server/controllers/activity-instance/entitlement.js +7 -5
  47. package/dist-server/controllers/activity-instance/entitlement.js.map +1 -1
  48. package/dist-server/controllers/activity-instance/issue.js +28 -7
  49. package/dist-server/controllers/activity-instance/issue.js.map +1 -1
  50. package/dist-server/controllers/activity-instance/pick.js +56 -4
  51. package/dist-server/controllers/activity-instance/pick.js.map +1 -1
  52. package/dist-server/controllers/activity-read/assert-may-read.js +2 -1
  53. package/dist-server/controllers/activity-read/assert-may-read.js.map +1 -1
  54. package/dist-server/controllers/activity-read/participates.d.ts +2 -2
  55. package/dist-server/controllers/activity-read/participates.js +2 -2
  56. package/dist-server/controllers/activity-read/participates.js.map +1 -1
  57. package/dist-server/controllers/activity-thread/check-authority.js +38 -5
  58. package/dist-server/controllers/activity-thread/check-authority.js.map +1 -1
  59. package/dist-server/controllers/common.d.ts +13 -0
  60. package/dist-server/controllers/common.js +43 -15
  61. package/dist-server/controllers/common.js.map +1 -1
  62. package/dist-server/service/activity/activity-history.d.ts +1 -2
  63. package/dist-server/service/activity/activity-history.js +4 -8
  64. package/dist-server/service/activity/activity-history.js.map +1 -1
  65. package/dist-server/service/activity/activity-mutation.js +39 -8
  66. package/dist-server/service/activity/activity-mutation.js.map +1 -1
  67. package/dist-server/service/activity/activity-query.d.ts +1 -1
  68. package/dist-server/service/activity/activity-query.js +9 -9
  69. package/dist-server/service/activity/activity-query.js.map +1 -1
  70. package/dist-server/service/activity/activity-type.d.ts +2 -2
  71. package/dist-server/service/activity/activity-type.js +12 -6
  72. package/dist-server/service/activity/activity-type.js.map +1 -1
  73. package/dist-server/service/activity/activity.d.ts +2 -2
  74. package/dist-server/service/activity/activity.js +15 -7
  75. package/dist-server/service/activity/activity.js.map +1 -1
  76. package/dist-server/service/activity/event-subscriber.js.map +1 -1
  77. package/dist-server/service/activity-instance/activity-instance-history.d.ts +1 -2
  78. package/dist-server/service/activity-instance/activity-instance-history.js +4 -8
  79. package/dist-server/service/activity-instance/activity-instance-history.js.map +1 -1
  80. package/dist-server/service/activity-instance/activity-instance-mutation.d.ts +1 -1
  81. package/dist-server/service/activity-instance/activity-instance-mutation.js +10 -5
  82. package/dist-server/service/activity-instance/activity-instance-mutation.js.map +1 -1
  83. package/dist-server/service/activity-instance/activity-instance-query.d.ts +1 -2
  84. package/dist-server/service/activity-instance/activity-instance-query.js +16 -25
  85. package/dist-server/service/activity-instance/activity-instance-query.js.map +1 -1
  86. package/dist-server/service/activity-instance/activity-instance-type.d.ts +2 -2
  87. package/dist-server/service/activity-instance/activity-instance-type.js +12 -6
  88. package/dist-server/service/activity-instance/activity-instance-type.js.map +1 -1
  89. package/dist-server/service/activity-instance/activity-instance.d.ts +2 -2
  90. package/dist-server/service/activity-instance/activity-instance.js +15 -7
  91. package/dist-server/service/activity-instance/activity-instance.js.map +1 -1
  92. package/dist-server/service/activity-instance/assignee-pool.d.ts +59 -0
  93. package/dist-server/service/activity-instance/assignee-pool.js +99 -0
  94. package/dist-server/service/activity-instance/assignee-pool.js.map +1 -0
  95. package/dist-server/service/activity-instance/event-subscriber.d.ts +9 -1
  96. package/dist-server/service/activity-instance/event-subscriber.js +20 -4
  97. package/dist-server/service/activity-instance/event-subscriber.js.map +1 -1
  98. package/dist-server/service/activity-summary/activity-summary-query.js +3 -3
  99. package/dist-server/service/activity-summary/activity-summary-query.js.map +1 -1
  100. package/dist-server/service/activity-thread/my-open-threads.d.ts +1 -1
  101. package/dist-server/service/activity-thread/my-open-threads.js +19 -4
  102. package/dist-server/service/activity-thread/my-open-threads.js.map +1 -1
  103. package/dist-server/service/subscription/subscription-filters.d.ts +3 -2
  104. package/dist-server/service/subscription/subscription-filters.js +6 -3
  105. package/dist-server/service/subscription/subscription-filters.js.map +1 -1
  106. package/dist-server/service/work-door/work-door-service.js +9 -6
  107. package/dist-server/service/work-door/work-door-service.js.map +1 -1
  108. package/dist-server/service/work-door/work-door-type.d.ts +1 -1
  109. package/dist-server/service/work-door/work-door-type.js +4 -4
  110. package/dist-server/service/work-door/work-door-type.js.map +1 -1
  111. package/dist-server/service/work-door/work-door.d.ts +3 -3
  112. package/dist-server/service/work-door/work-door.js +2 -2
  113. package/dist-server/service/work-door/work-door.js.map +1 -1
  114. package/dist-server/tsconfig.tsbuildinfo +1 -1
  115. package/package.json +11 -11
  116. package/tests/assign-role-pool.test.ts +508 -0
  117. package/tests/assignee-pool-history.test.ts +81 -0
  118. package/tests/may-read-case.test.ts +3 -2
  119. package/tests/org-member-domain.test.ts +10 -4
  120. package/tests/pick-race.pg.test.ts +81 -3
  121. package/tests/pool-pick-waiting-thread.test.ts +254 -0
  122. package/tests/published-shape.test.ts +2 -2
  123. package/tests/role-pool-race.pg.test.ts +182 -0
  124. package/tests/work-door.test.ts +3 -3
  125. package/translations/en.json +6 -0
  126. package/translations/es.json +6 -0
  127. package/translations/ja.json +6 -0
  128. package/translations/ko.json +6 -0
  129. package/translations/ms.json +6 -0
  130. package/translations/zh.json +6 -0
@@ -1 +1 @@
1
- {"version":3,"file":"activity-instance.js","sourceRoot":"","sources":["../../../server/service/activity-instance/activity-instance.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, Int, ObjectType, registerEnumType } from 'type-graphql'\nimport {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n ManyToOne,\n OneToMany,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn,\n VersionColumn\n} from 'typeorm'\n\nimport { Role, User } from '@things-factory/auth-base'\nimport { Domain, ScalarObject } from '@things-factory/shell'\nimport { ApprovalLineItem } from '@things-factory/organization'\n\nimport { ActivityThread } from '../activity-thread/activity-thread.js'\nimport { Activity, ActivityType, ActivityUIType, AssigneeItem } from '../activity/activity.js'\n\nexport enum ActivityInstanceStatus {\n Draft = 'draft',\n Issued = 'issued',\n Unassigned = 'unassigned',\n Assigned = 'assigned',\n Started = 'started',\n Pending = 'pending',\n Ended = 'ended',\n Aborted = 'aborted'\n}\n\nregisterEnumType(ActivityInstanceStatus, {\n name: 'ActivityInstanceStatus',\n description: 'state enumeration of a activityInstance'\n})\n\n@Entity()\n@Index(\n 'ix_activity_instance_0',\n (activityInstance: ActivityInstance) => [activityInstance.domain, activityInstance.name],\n { unique: false }\n)\n@Index(\n 'ix_activity_instance_1',\n (activityInstance: ActivityInstance) => [activityInstance.domain, activityInstance.state, activityInstance.priority],\n { unique: false }\n)\n@ObjectType({ description: 'Entity for ActivityInstance' })\nexport class ActivityInstance {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @VersionColumn({ default: 1 })\n @Field({ nullable: true })\n version?: number = 1\n\n @ManyToOne(type => Domain)\n @Field(type => Domain)\n domain?: Domain\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.domain)\n domainId?: string\n\n @Column()\n @Field({ nullable: true })\n name?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n description?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n activityType?: ActivityType\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n adhocType?: string\n\n @Column({ nullable: true, default: '' })\n @Field({ nullable: true })\n key01?: string = ''\n\n @Column({ nullable: true, default: '' })\n @Field({ nullable: true })\n key02?: string = ''\n\n @Column({ nullable: true, default: '' })\n @Field({ nullable: true })\n key03?: string = ''\n\n @Column({ nullable: true, default: '' })\n @Field({ nullable: true })\n key04?: string = ''\n\n @Column({ nullable: true, default: '' })\n @Field({ nullable: true })\n key05?: string = ''\n\n @OneToMany(type => ActivityThread, activityThread => activityThread.activityInstance)\n @Field(type => [ActivityThread])\n activityThreads?: ActivityThread[]\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n uiType?: ActivityUIType\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n uiSource?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n viewType?: ActivityUIType\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n viewSource?: string\n\n @Column({ nullable: true, default: 1 })\n @Field({ nullable: true })\n priority?: number = 1\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n state?: ActivityInstanceStatus\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n reason?: string\n\n @Column({ nullable: true, default: 0 })\n @Field(type => Int, { nullable: true })\n threadsMin?: number = 0\n\n @Column({ nullable: true, default: 0 })\n @Field(type => Int, { nullable: true })\n threadsMax?: number = 0\n\n @Column('simple-json', { nullable: true })\n @Field(type => ScalarObject, { nullable: true })\n input?: { [key: string]: any }\n\n @Column('simple-json', { nullable: true })\n @Field(type => ScalarObject, { nullable: true })\n output?: { [key: string]: any }\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n refBy?: string\n\n @ManyToOne(type => Activity, { nullable: true })\n @Field(type => Activity, { nullable: true })\n activity?: Activity\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.activity)\n activityId?: string\n\n @ManyToOne(type => Role, { nullable: true })\n @Field(type => Role, { nullable: true })\n assigneeRole?: Role\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.assigneeRole)\n assigneeRoleId?: string\n\n @ManyToOne(type => Role, { nullable: true })\n @Field(type => Role, { nullable: true })\n supervisoryRole?: Role\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.supervisoryRole)\n supervisoryRoleId?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n dueAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n transaction?: string\n\n @Column('simple-json', { nullable: true })\n @Field(type => [AssigneeItem], { nullable: true })\n assignees?: AssigneeItem[]\n\n @Column('simple-json', { nullable: true })\n @Field(type => [ApprovalLineItem], { nullable: true })\n approvalLine?: ApprovalLineItem[]\n\n /**\n * 반려하면 끝인가 — 액티비티가 선언한 값을 낼 때 옮겨 담는다(`approvalLine` 과 같은 방식).\n *\n * 인스턴스에 두는 이유는 액티비티 없이 나는 건(adhoc)이 있어서다. 그때는 낸 쪽이 직접 준다.\n */\n @Column({ type: 'boolean', nullable: true, default: false })\n @Field({ nullable: true, description: 'true when a rejection closes this case for good' })\n rejectionIsFinal?: boolean\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n issuedAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n assignedAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n startedAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n terminatedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.updater)\n updaterId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field({ nullable: true })\n issuer?: User\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.issuer)\n issuerId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field({ nullable: true })\n starter?: User\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.starter)\n starterId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field({ nullable: true })\n terminator?: User\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.terminator)\n terminatorId?: string\n\n @Field(type => String, { nullable: true })\n thumbnail?: string\n\n isDelegatable(): boolean {\n switch (this.state) {\n case ActivityInstanceStatus.Issued:\n case ActivityInstanceStatus.Assigned:\n return true\n default:\n return false\n }\n }\n}\n"]}
1
+ {"version":3,"file":"activity-instance.js","sourceRoot":"","sources":["../../../server/service/activity-instance/activity-instance.ts"],"names":[],"mappings":"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","sourcesContent":["import { Field, ID, Int, ObjectType, registerEnumType } from 'type-graphql'\nimport {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n JoinTable,\n ManyToMany,\n ManyToOne,\n OneToMany,\n PrimaryGeneratedColumn,\n RelationId,\n UpdateDateColumn,\n VersionColumn\n} from 'typeorm'\n\nimport { Role, User } from '@things-factory/auth-base'\nimport { Domain, ScalarObject } from '@things-factory/shell'\nimport { ApprovalLineItem } from '@things-factory/organization'\n\nimport { ActivityThread } from '../activity-thread/activity-thread.js'\nimport { Activity, ActivityType, ActivityUIType, AssigneeItem } from '../activity/activity.js'\n\nexport enum ActivityInstanceStatus {\n Draft = 'draft',\n Issued = 'issued',\n Unassigned = 'unassigned',\n Assigned = 'assigned',\n Started = 'started',\n Pending = 'pending',\n Ended = 'ended',\n Aborted = 'aborted'\n}\n\nregisterEnumType(ActivityInstanceStatus, {\n name: 'ActivityInstanceStatus',\n description: 'state enumeration of a activityInstance'\n})\n\n@Entity()\n@Index(\n 'ix_activity_instance_0',\n (activityInstance: ActivityInstance) => [activityInstance.domain, activityInstance.name],\n { unique: false }\n)\n@Index(\n 'ix_activity_instance_1',\n (activityInstance: ActivityInstance) => [activityInstance.domain, activityInstance.state, activityInstance.priority],\n { unique: false }\n)\n@ObjectType({ description: 'Entity for ActivityInstance' })\nexport class ActivityInstance {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID)\n readonly id: string\n\n @VersionColumn({ default: 1 })\n @Field({ nullable: true })\n version?: number = 1\n\n @ManyToOne(type => Domain)\n @Field(type => Domain)\n domain?: Domain\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.domain)\n domainId?: string\n\n @Column()\n @Field({ nullable: true })\n name?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n description?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n activityType?: ActivityType\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n adhocType?: string\n\n @Column({ nullable: true, default: '' })\n @Field({ nullable: true })\n key01?: string = ''\n\n @Column({ nullable: true, default: '' })\n @Field({ nullable: true })\n key02?: string = ''\n\n @Column({ nullable: true, default: '' })\n @Field({ nullable: true })\n key03?: string = ''\n\n @Column({ nullable: true, default: '' })\n @Field({ nullable: true })\n key04?: string = ''\n\n @Column({ nullable: true, default: '' })\n @Field({ nullable: true })\n key05?: string = ''\n\n @OneToMany(type => ActivityThread, activityThread => activityThread.activityInstance)\n @Field(type => [ActivityThread])\n activityThreads?: ActivityThread[]\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n uiType?: ActivityUIType\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n uiSource?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n viewType?: ActivityUIType\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n viewSource?: string\n\n @Column({ nullable: true, default: 1 })\n @Field({ nullable: true })\n priority?: number = 1\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n state?: ActivityInstanceStatus\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n reason?: string\n\n @Column({ nullable: true, default: 0 })\n @Field(type => Int, { nullable: true })\n threadsMin?: number = 0\n\n @Column({ nullable: true, default: 0 })\n @Field(type => Int, { nullable: true })\n threadsMax?: number = 0\n\n @Column('simple-json', { nullable: true })\n @Field(type => ScalarObject, { nullable: true })\n input?: { [key: string]: any }\n\n @Column('simple-json', { nullable: true })\n @Field(type => ScalarObject, { nullable: true })\n output?: { [key: string]: any }\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n refBy?: string\n\n @ManyToOne(type => Activity, { nullable: true })\n @Field(type => Activity, { nullable: true })\n activity?: Activity\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.activity)\n activityId?: string\n\n /* The case's pool - anyone holding any one of these roles (ADR-0091 decision 9). Empty is no pool. */\n @ManyToMany(type => Role)\n @JoinTable({\n name: 'activity_instances_assignee_roles',\n joinColumn: { name: 'activity_instances_id', referencedColumnName: 'id' },\n inverseJoinColumn: { name: 'roles_id', referencedColumnName: 'id' }\n })\n @Field(type => [Role], {\n nullable: true,\n description: 'Roles whose holders may pick up this case - anyone holding any one of them.'\n })\n assigneeRoles?: Role[]\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.assigneeRoles)\n assigneeRoleIds?: string[]\n\n @ManyToOne(type => Role, { nullable: true })\n @Field(type => Role, { nullable: true })\n supervisoryRole?: Role\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.supervisoryRole)\n supervisoryRoleId?: string\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n dueAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n transaction?: string\n\n @Column('simple-json', { nullable: true })\n @Field(type => [AssigneeItem], { nullable: true })\n assignees?: AssigneeItem[]\n\n @Column('simple-json', { nullable: true })\n @Field(type => [ApprovalLineItem], { nullable: true })\n approvalLine?: ApprovalLineItem[]\n\n /**\n * 반려하면 끝인가 — 액티비티가 선언한 값을 낼 때 옮겨 담는다(`approvalLine` 과 같은 방식).\n *\n * 인스턴스에 두는 이유는 액티비티 없이 나는 건(adhoc)이 있어서다. 그때는 낸 쪽이 직접 준다.\n */\n @Column({ type: 'boolean', nullable: true, default: false })\n @Field({ nullable: true, description: 'true when a rejection closes this case for good' })\n rejectionIsFinal?: boolean\n\n @CreateDateColumn()\n @Field({ nullable: true })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true })\n updatedAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n issuedAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n assignedAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n startedAt?: Date\n\n @Column({ nullable: true })\n @Field({ nullable: true })\n terminatedAt?: Date\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n creator?: User\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.creator)\n creatorId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field(type => User, { nullable: true })\n updater?: User\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.updater)\n updaterId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field({ nullable: true })\n issuer?: User\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.issuer)\n issuerId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field({ nullable: true })\n starter?: User\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.starter)\n starterId?: string\n\n @ManyToOne(type => User, { nullable: true })\n @Field({ nullable: true })\n terminator?: User\n\n @RelationId((activityInstance: ActivityInstance) => activityInstance.terminator)\n terminatorId?: string\n\n @Field(type => String, { nullable: true })\n thumbnail?: string\n\n isDelegatable(): boolean {\n switch (this.state) {\n case ActivityInstanceStatus.Issued:\n case ActivityInstanceStatus.Assigned:\n return true\n default:\n return false\n }\n }\n}\n"]}
@@ -0,0 +1,59 @@
1
+ import { Role } from '@things-factory/auth-base';
2
+ /**
3
+ * The assignee pool - **one place**, `assigneeRoles` on the activity and on the case (ADR-0091 decision 9).
4
+ *
5
+ * Anyone holding **any one** of the roles may pick the case: one task can be done from several roles (user,
6
+ * 2026-10-20). Empty is no pool. Every reader asks this file - the to-do list, the pickable list, the summary,
7
+ * who may pick, who may read, who hears of it, how many people a pool reaches - so "in the pool" means the
8
+ * same thing everywhere. Written in each of them it drifts: one list shows a case another refuses.
9
+ *
10
+ * The doors stay shut by privilege; a role in the pool only says who may take the work.
11
+ */
12
+ /** The join table the case's pool is stored in - named here and on the entity's @JoinTable, nowhere else. */
13
+ export declare const CASE_POOL: {
14
+ readonly table: "activity_instances_assignee_roles";
15
+ readonly caseColumn: "activity_instances_id";
16
+ readonly roleColumn: "roles_id";
17
+ };
18
+ /** And the activity's. */
19
+ export declare const ACTIVITY_POOL: {
20
+ readonly table: "activities_assignee_roles";
21
+ readonly activityColumn: "activities_id";
22
+ readonly roleColumn: "roles_id";
23
+ };
24
+ /**
25
+ * "The case `alias` is in the pool of one of `:...param`" - a condition for a query builder's where.
26
+ *
27
+ * An EXISTS on the join table, not a join: the to-do list puts it inside an OR (my-open-threads.ts), where a
28
+ * join cannot go, and a join would repeat a case once per matching role. The caller binds `param` to a
29
+ * non-empty list of role ids; an empty IN is not valid SQL on every driver.
30
+ */
31
+ export declare function inPoolOf(alias: string, param?: string): string;
32
+ /**
33
+ * The pool's role ids off a case or an activity, whichever way it was read.
34
+ *
35
+ * The roles first: on an object about to be saved they are the new pool, and the RelationId beside them is
36
+ * still what was read before. On a row read back the two agree.
37
+ */
38
+ export declare function poolIdsOf(subject: {
39
+ assigneeRoleIds?: string[];
40
+ assigneeRoles?: {
41
+ id?: string;
42
+ }[];
43
+ } | null | undefined): string[];
44
+ /** Does someone holding these roles stand in this pool? An empty pool holds nobody - the caller says what that means. */
45
+ export declare function holdsAnyOf(heldRoleIds: readonly string[], poolIds: readonly string[]): boolean;
46
+ export declare const ROLE_NAMED_TWICE = "assignee-role-named-twice";
47
+ export declare const ROLE_NOT_HERE = "assignee-role-not-in-this-domain";
48
+ /**
49
+ * The roles a caller names for a pool, read in the case's domain - or a refusal by name.
50
+ *
51
+ * A role named twice is refused, not folded: the list was written by someone who meant something by it, and
52
+ * which of the two they meant is not ours to guess. A role of another tenant, or none at all, is refused too -
53
+ * nobody here holds it, so it would only look like a pool.
54
+ */
55
+ export declare function resolvePoolRoles(named: ({
56
+ id?: string;
57
+ } | string)[] | null | undefined, context: ResolverContext): Promise<Role[]>;
58
+ /** The people a pool reaches - each once, however many of its roles they hold. Users, not application accounts. */
59
+ export declare function poolMembers(roles: Pick<Role, 'users'>[]): Role['users'];
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ROLE_NOT_HERE = exports.ROLE_NAMED_TWICE = exports.ACTIVITY_POOL = exports.CASE_POOL = void 0;
4
+ exports.inPoolOf = inPoolOf;
5
+ exports.poolIdsOf = poolIdsOf;
6
+ exports.holdsAnyOf = holdsAnyOf;
7
+ exports.resolvePoolRoles = resolvePoolRoles;
8
+ exports.poolMembers = poolMembers;
9
+ const typeorm_1 = require("typeorm");
10
+ const auth_base_1 = require("@things-factory/auth-base");
11
+ /**
12
+ * The assignee pool - **one place**, `assigneeRoles` on the activity and on the case (ADR-0091 decision 9).
13
+ *
14
+ * Anyone holding **any one** of the roles may pick the case: one task can be done from several roles (user,
15
+ * 2026-10-20). Empty is no pool. Every reader asks this file - the to-do list, the pickable list, the summary,
16
+ * who may pick, who may read, who hears of it, how many people a pool reaches - so "in the pool" means the
17
+ * same thing everywhere. Written in each of them it drifts: one list shows a case another refuses.
18
+ *
19
+ * The doors stay shut by privilege; a role in the pool only says who may take the work.
20
+ */
21
+ /** The join table the case's pool is stored in - named here and on the entity's @JoinTable, nowhere else. */
22
+ exports.CASE_POOL = {
23
+ table: 'activity_instances_assignee_roles',
24
+ caseColumn: 'activity_instances_id',
25
+ roleColumn: 'roles_id'
26
+ };
27
+ /** And the activity's. */
28
+ exports.ACTIVITY_POOL = {
29
+ table: 'activities_assignee_roles',
30
+ activityColumn: 'activities_id',
31
+ roleColumn: 'roles_id'
32
+ };
33
+ /**
34
+ * "The case `alias` is in the pool of one of `:...param`" - a condition for a query builder's where.
35
+ *
36
+ * An EXISTS on the join table, not a join: the to-do list puts it inside an OR (my-open-threads.ts), where a
37
+ * join cannot go, and a join would repeat a case once per matching role. The caller binds `param` to a
38
+ * non-empty list of role ids; an empty IN is not valid SQL on every driver.
39
+ */
40
+ function inPoolOf(alias, param = 'roles') {
41
+ return (`EXISTS (SELECT 1 FROM ${exports.CASE_POOL.table} pool` +
42
+ ` WHERE pool.${exports.CASE_POOL.caseColumn} = ${alias}.id AND pool.${exports.CASE_POOL.roleColumn} IN (:...${param}))`);
43
+ }
44
+ /**
45
+ * The pool's role ids off a case or an activity, whichever way it was read.
46
+ *
47
+ * The roles first: on an object about to be saved they are the new pool, and the RelationId beside them is
48
+ * still what was read before. On a row read back the two agree.
49
+ */
50
+ function poolIdsOf(subject) {
51
+ if (subject?.assigneeRoles)
52
+ return subject.assigneeRoles.map(role => role?.id).filter(Boolean);
53
+ return subject?.assigneeRoleIds || [];
54
+ }
55
+ /** Does someone holding these roles stand in this pool? An empty pool holds nobody - the caller says what that means. */
56
+ function holdsAnyOf(heldRoleIds, poolIds) {
57
+ return poolIds.some(id => heldRoleIds.includes(id));
58
+ }
59
+ exports.ROLE_NAMED_TWICE = 'assignee-role-named-twice';
60
+ exports.ROLE_NOT_HERE = 'assignee-role-not-in-this-domain';
61
+ /**
62
+ * The roles a caller names for a pool, read in the case's domain - or a refusal by name.
63
+ *
64
+ * A role named twice is refused, not folded: the list was written by someone who meant something by it, and
65
+ * which of the two they meant is not ours to guess. A role of another tenant, or none at all, is refused too -
66
+ * nobody here holds it, so it would only look like a pool.
67
+ */
68
+ async function resolvePoolRoles(named, context) {
69
+ const { domain, tx } = context.state;
70
+ const ids = (named || []).map(one => (typeof one === 'string' ? one : one?.id)).filter(Boolean);
71
+ if (!ids.length)
72
+ return [];
73
+ const twice = ids.filter((id, index) => ids.indexOf(id) !== index);
74
+ if (twice.length) {
75
+ throw Object.assign(new Error(context.t('error.activity-instance assignee role named twice', { role: [...new Set(twice)].join(', ') })), {
76
+ code: exports.ROLE_NAMED_TWICE
77
+ });
78
+ }
79
+ const roles = await tx.getRepository(auth_base_1.Role).find({ where: { domain: { id: domain.id }, id: (0, typeorm_1.In)(ids) }, relations: ['users'] });
80
+ const missing = ids.filter(id => !roles.some(role => role.id === id));
81
+ if (missing.length) {
82
+ throw Object.assign(new Error(context.t('error.activity-instance role not in this domain', { role: missing.join(', ') })), {
83
+ code: exports.ROLE_NOT_HERE
84
+ });
85
+ }
86
+ return ids.map(id => roles.find(role => role.id === id));
87
+ }
88
+ /** The people a pool reaches - each once, however many of its roles they hold. Users, not application accounts. */
89
+ function poolMembers(roles) {
90
+ const seen = new Map();
91
+ for (const role of roles) {
92
+ for (const user of role.users || []) {
93
+ if (user.userType == 'user' && !seen.has(user.id))
94
+ seen.set(user.id, user);
95
+ }
96
+ }
97
+ return [...seen.values()];
98
+ }
99
+ //# sourceMappingURL=assignee-pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assignee-pool.js","sourceRoot":"","sources":["../../../server/service/activity-instance/assignee-pool.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\n\nimport { Role } from '@things-factory/auth-base'\n\n/**\n * The assignee pool - **one place**, `assigneeRoles` on the activity and on the case (ADR-0091 decision 9).\n *\n * Anyone holding **any one** of the roles may pick the case: one task can be done from several roles (user,\n * 2026-10-20). Empty is no pool. Every reader asks this file - the to-do list, the pickable list, the summary,\n * who may pick, who may read, who hears of it, how many people a pool reaches - so \"in the pool\" means the\n * same thing everywhere. Written in each of them it drifts: one list shows a case another refuses.\n *\n * The doors stay shut by privilege; a role in the pool only says who may take the work.\n */\n\n/** The join table the case's pool is stored in - named here and on the entity's @JoinTable, nowhere else. */\nexport const CASE_POOL = {\n table: 'activity_instances_assignee_roles',\n caseColumn: 'activity_instances_id',\n roleColumn: 'roles_id'\n} as const\n\n/** And the activity's. */\nexport const ACTIVITY_POOL = {\n table: 'activities_assignee_roles',\n activityColumn: 'activities_id',\n roleColumn: 'roles_id'\n} as const\n\n/**\n * \"The case `alias` is in the pool of one of `:...param`\" - a condition for a query builder's where.\n *\n * An EXISTS on the join table, not a join: the to-do list puts it inside an OR (my-open-threads.ts), where a\n * join cannot go, and a join would repeat a case once per matching role. The caller binds `param` to a\n * non-empty list of role ids; an empty IN is not valid SQL on every driver.\n */\nexport function inPoolOf(alias: string, param = 'roles'): string {\n return (\n `EXISTS (SELECT 1 FROM ${CASE_POOL.table} pool` +\n ` WHERE pool.${CASE_POOL.caseColumn} = ${alias}.id AND pool.${CASE_POOL.roleColumn} IN (:...${param}))`\n )\n}\n\n/**\n * The pool's role ids off a case or an activity, whichever way it was read.\n *\n * The roles first: on an object about to be saved they are the new pool, and the RelationId beside them is\n * still what was read before. On a row read back the two agree.\n */\nexport function poolIdsOf(subject: { assigneeRoleIds?: string[]; assigneeRoles?: { id?: string }[] } | null | undefined): string[] {\n if (subject?.assigneeRoles) return subject.assigneeRoles.map(role => role?.id).filter(Boolean) as string[]\n return subject?.assigneeRoleIds || []\n}\n\n/** Does someone holding these roles stand in this pool? An empty pool holds nobody - the caller says what that means. */\nexport function holdsAnyOf(heldRoleIds: readonly string[], poolIds: readonly string[]): boolean {\n return poolIds.some(id => heldRoleIds.includes(id))\n}\n\nexport const ROLE_NAMED_TWICE = 'assignee-role-named-twice'\nexport const ROLE_NOT_HERE = 'assignee-role-not-in-this-domain'\n\n/**\n * The roles a caller names for a pool, read in the case's domain - or a refusal by name.\n *\n * A role named twice is refused, not folded: the list was written by someone who meant something by it, and\n * which of the two they meant is not ours to guess. A role of another tenant, or none at all, is refused too -\n * nobody here holds it, so it would only look like a pool.\n */\nexport async function resolvePoolRoles(\n named: ({ id?: string } | string)[] | null | undefined,\n context: ResolverContext\n): Promise<Role[]> {\n const { domain, tx } = context.state\n const ids = (named || []).map(one => (typeof one === 'string' ? one : one?.id)).filter(Boolean) as string[]\n\n if (!ids.length) return []\n\n const twice = ids.filter((id, index) => ids.indexOf(id) !== index)\n if (twice.length) {\n throw Object.assign(new Error(context.t('error.activity-instance assignee role named twice', { role: [...new Set(twice)].join(', ') })), {\n code: ROLE_NAMED_TWICE\n })\n }\n\n const roles = await tx.getRepository(Role).find({ where: { domain: { id: domain.id }, id: In(ids) }, relations: ['users'] })\n const missing = ids.filter(id => !roles.some(role => role.id === id))\n\n if (missing.length) {\n throw Object.assign(new Error(context.t('error.activity-instance role not in this domain', { role: missing.join(', ') })), {\n code: ROLE_NOT_HERE\n })\n }\n\n return ids.map(id => roles.find(role => role.id === id))\n}\n\n/** The people a pool reaches - each once, however many of its roles they hold. Users, not application accounts. */\nexport function poolMembers(roles: Pick<Role, 'users'>[]): Role['users'] {\n const seen = new Map<string, Role['users'][number]>()\n\n for (const role of roles) {\n for (const user of role.users || []) {\n if (user.userType == 'user' && !seen.has(user.id)) seen.set(user.id, user)\n }\n }\n\n return [...seen.values()]\n}\n"]}
@@ -1,7 +1,15 @@
1
- import { EntitySubscriberInterface, InsertEvent, UpdateEvent } from 'typeorm';
1
+ import { EntityManager, EntitySubscriberInterface, InsertEvent, UpdateEvent } from 'typeorm';
2
2
  import { HistoryEntitySubscriber } from '@operato/typeorm-history';
3
3
  import { ActivityInstance } from './activity-instance.js';
4
4
  import { ActivityInstanceHistory } from './activity-instance-history.js';
5
+ /**
6
+ * The pool's role ids on what is published - the subscription filter decides by them (subscription-filters.ts).
7
+ *
8
+ * A many-to-many is not a column: the saved object carries the roles only when the caller had them, and its
9
+ * RelationId is not filled in on a write. Asked here once per event when it is missing, never once per
10
+ * subscriber. An update with no entity (a query-builder UPDATE) publishes nothing to read, as before.
11
+ */
12
+ export declare function withPoolIds(activityInstance: ActivityInstance, manager: EntityManager): Promise<ActivityInstance>;
5
13
  export declare class ActivityInstanceSubscriber implements EntitySubscriberInterface<ActivityInstance> {
6
14
  listenTo(): typeof ActivityInstance;
7
15
  afterInsert(event: InsertEvent<ActivityInstance>): Promise<any | void>;
@@ -1,26 +1,42 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ActivityInstanceHistoryEntitySubscriber = exports.ActivityInstanceSubscriber = void 0;
4
+ exports.withPoolIds = withPoolIds;
4
5
  const tslib_1 = require("tslib");
5
6
  const typeorm_1 = require("typeorm");
6
7
  const typeorm_history_1 = require("@operato/typeorm-history");
7
8
  const shell_1 = require("@things-factory/shell");
8
9
  const activity_instance_js_1 = require("./activity-instance.js");
9
10
  const activity_instance_history_js_1 = require("./activity-instance-history.js");
11
+ const assignee_pool_js_1 = require("./assignee-pool.js");
12
+ /**
13
+ * The pool's role ids on what is published - the subscription filter decides by them (subscription-filters.ts).
14
+ *
15
+ * A many-to-many is not a column: the saved object carries the roles only when the caller had them, and its
16
+ * RelationId is not filled in on a write. Asked here once per event when it is missing, never once per
17
+ * subscriber. An update with no entity (a query-builder UPDATE) publishes nothing to read, as before.
18
+ */
19
+ async function withPoolIds(activityInstance, manager) {
20
+ if (!activityInstance?.id)
21
+ return activityInstance;
22
+ if (activityInstance.assigneeRoleIds || activityInstance.assigneeRoles) {
23
+ return Object.assign(activityInstance, { assigneeRoleIds: (0, assignee_pool_js_1.poolIdsOf)(activityInstance) });
24
+ }
25
+ const rows = await manager.query(`SELECT ${assignee_pool_js_1.CASE_POOL.roleColumn} AS roles_id FROM ${assignee_pool_js_1.CASE_POOL.table} WHERE ${assignee_pool_js_1.CASE_POOL.caseColumn} = ${manager.connection.driver.createParameter('id', 0)}`, [activityInstance.id]);
26
+ return Object.assign(activityInstance, { assigneeRoleIds: rows.map(row => row.roles_id) });
27
+ }
10
28
  let ActivityInstanceSubscriber = class ActivityInstanceSubscriber {
11
29
  listenTo() {
12
30
  return activity_instance_js_1.ActivityInstance;
13
31
  }
14
32
  async afterInsert(event) {
15
- const { entity: activityInstance, manager: tx } = event;
16
33
  shell_1.pubsub.publish('activity-instance', {
17
- activityInstance
34
+ activityInstance: await withPoolIds(event.entity, event.manager)
18
35
  });
19
36
  }
20
37
  async afterUpdate(event) {
21
- const { entity: activityInstance, manager: tx } = event;
22
38
  shell_1.pubsub.publish('activity-instance', {
23
- activityInstance
39
+ activityInstance: await withPoolIds(event.entity, event.manager)
24
40
  });
25
41
  }
26
42
  };
@@ -1 +1 @@
1
- {"version":3,"file":"event-subscriber.js","sourceRoot":"","sources":["../../../server/service/activity-instance/event-subscriber.ts"],"names":[],"mappings":";;;;AAAA,qCAA8F;AAE9F,8DAAkE;AAClE,iDAA8C;AAE9C,iEAAyD;AACzD,iFAAwE;AAGjE,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IACrC,QAAQ;QACN,OAAO,uCAAgB,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAoC;QACpD,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,KAAK,CAAA;QAEvD,cAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE;YAClC,gBAAgB;SACjB,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAoC;QACpD,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,KAAK,CAAA;QAEvD,cAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE;YAClC,gBAAgB;SACjB,CAAC,CAAA;IACJ,CAAC;CACF,CAAA;AApBY,gEAA0B;qCAA1B,0BAA0B;IADtC,IAAA,yBAAe,GAAE;GACL,0BAA0B,CAoBtC;AAGM,IAAM,uCAAuC,GAA7C,MAAM,uCAAwC,SAAQ,yCAG5D;IACC,IAAW,MAAM;QACf,OAAO,uCAAgB,CAAA;IACzB,CAAC;IAED,IAAW,aAAa;QACtB,OAAO,sDAAuB,CAAA;IAChC,CAAC;CACF,CAAA;AAXY,0FAAuC;kDAAvC,uCAAuC;IADnD,IAAA,yBAAe,GAAE;GACL,uCAAuC,CAWnD","sourcesContent":["import { EventSubscriber, EntitySubscriberInterface, InsertEvent, UpdateEvent } from 'typeorm'\n\nimport { HistoryEntitySubscriber } from '@operato/typeorm-history'\nimport { pubsub } from '@things-factory/shell'\n\nimport { ActivityInstance } from './activity-instance.js'\nimport { ActivityInstanceHistory } from './activity-instance-history.js'\n\n@EventSubscriber()\nexport class ActivityInstanceSubscriber implements EntitySubscriberInterface<ActivityInstance> {\n listenTo() {\n return ActivityInstance\n }\n\n async afterInsert(event: InsertEvent<ActivityInstance>): Promise<any | void> {\n const { entity: activityInstance, manager: tx } = event\n\n pubsub.publish('activity-instance', {\n activityInstance\n })\n }\n\n async afterUpdate(event: UpdateEvent<ActivityInstance>): Promise<any | void> {\n const { entity: activityInstance, manager: tx } = event\n\n pubsub.publish('activity-instance', {\n activityInstance\n })\n }\n}\n\n@EventSubscriber()\nexport class ActivityInstanceHistoryEntitySubscriber extends HistoryEntitySubscriber<\n ActivityInstance,\n ActivityInstanceHistory\n> {\n public get entity() {\n return ActivityInstance\n }\n\n public get historyEntity() {\n return ActivityInstanceHistory\n }\n}\n"]}
1
+ {"version":3,"file":"event-subscriber.js","sourceRoot":"","sources":["../../../server/service/activity-instance/event-subscriber.ts"],"names":[],"mappings":";;;AAgBA,kCAYC;;AA5BD,qCAA6G;AAE7G,8DAAkE;AAClE,iDAA8C;AAE9C,iEAAyD;AACzD,iFAAwE;AACxE,yDAAyD;AAEzD;;;;;;GAMG;AACI,KAAK,UAAU,WAAW,CAAC,gBAAkC,EAAE,OAAsB;IAC1F,IAAI,CAAC,gBAAgB,EAAE,EAAE;QAAE,OAAO,gBAAgB,CAAA;IAClD,IAAI,gBAAgB,CAAC,eAAe,IAAI,gBAAgB,CAAC,aAAa,EAAE,CAAC;QACvE,OAAO,MAAM,CAAC,MAAM,CAAC,gBAAgB,EAAE,EAAE,eAAe,EAAE,IAAA,4BAAS,EAAC,gBAAgB,CAAC,EAAE,CAAC,CAAA;IAC1F,CAAC;IAED,MAAM,IAAI,GAA2B,MAAM,OAAO,CAAC,KAAK,CACtD,UAAU,4BAAS,CAAC,UAAU,qBAAqB,4BAAS,CAAC,KAAK,UAAU,4BAAS,CAAC,UAAU,MAAM,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAC1J,CAAC,gBAAgB,CAAC,EAAE,CAAC,CACtB,CAAA;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,gBAAgB,EAAE,EAAE,eAAe,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;AAC5F,CAAC;AAGM,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IACrC,QAAQ;QACN,OAAO,uCAAgB,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAoC;QACpD,cAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE;YAClC,gBAAgB,EAAE,MAAM,WAAW,CAAC,KAAK,CAAC,MAA0B,EAAE,KAAK,CAAC,OAAO,CAAC;SACrF,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAoC;QACpD,cAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE;YAClC,gBAAgB,EAAE,MAAM,WAAW,CAAC,KAAK,CAAC,MAA0B,EAAE,KAAK,CAAC,OAAO,CAAC;SACrF,CAAC,CAAA;IACJ,CAAC;CACF,CAAA;AAhBY,gEAA0B;qCAA1B,0BAA0B;IADtC,IAAA,yBAAe,GAAE;GACL,0BAA0B,CAgBtC;AAGM,IAAM,uCAAuC,GAA7C,MAAM,uCAAwC,SAAQ,yCAG5D;IACC,IAAW,MAAM;QACf,OAAO,uCAAgB,CAAA;IACzB,CAAC;IAED,IAAW,aAAa;QACtB,OAAO,sDAAuB,CAAA;IAChC,CAAC;CAEF,CAAA;AAZY,0FAAuC;kDAAvC,uCAAuC;IADnD,IAAA,yBAAe,GAAE;GACL,uCAAuC,CAYnD","sourcesContent":["import { EntityManager, EventSubscriber, EntitySubscriberInterface, InsertEvent, UpdateEvent } from 'typeorm'\n\nimport { HistoryEntitySubscriber } from '@operato/typeorm-history'\nimport { pubsub } from '@things-factory/shell'\n\nimport { ActivityInstance } from './activity-instance.js'\nimport { ActivityInstanceHistory } from './activity-instance-history.js'\nimport { CASE_POOL, poolIdsOf } from './assignee-pool.js'\n\n/**\n * The pool's role ids on what is published - the subscription filter decides by them (subscription-filters.ts).\n *\n * A many-to-many is not a column: the saved object carries the roles only when the caller had them, and its\n * RelationId is not filled in on a write. Asked here once per event when it is missing, never once per\n * subscriber. An update with no entity (a query-builder UPDATE) publishes nothing to read, as before.\n */\nexport async function withPoolIds(activityInstance: ActivityInstance, manager: EntityManager): Promise<ActivityInstance> {\n if (!activityInstance?.id) return activityInstance\n if (activityInstance.assigneeRoleIds || activityInstance.assigneeRoles) {\n return Object.assign(activityInstance, { assigneeRoleIds: poolIdsOf(activityInstance) })\n }\n\n const rows: { roles_id: string }[] = await manager.query(\n `SELECT ${CASE_POOL.roleColumn} AS roles_id FROM ${CASE_POOL.table} WHERE ${CASE_POOL.caseColumn} = ${manager.connection.driver.createParameter('id', 0)}`,\n [activityInstance.id]\n )\n\n return Object.assign(activityInstance, { assigneeRoleIds: rows.map(row => row.roles_id) })\n}\n\n@EventSubscriber()\nexport class ActivityInstanceSubscriber implements EntitySubscriberInterface<ActivityInstance> {\n listenTo() {\n return ActivityInstance\n }\n\n async afterInsert(event: InsertEvent<ActivityInstance>): Promise<any | void> {\n pubsub.publish('activity-instance', {\n activityInstance: await withPoolIds(event.entity as ActivityInstance, event.manager)\n })\n }\n\n async afterUpdate(event: UpdateEvent<ActivityInstance>): Promise<any | void> {\n pubsub.publish('activity-instance', {\n activityInstance: await withPoolIds(event.entity as ActivityInstance, event.manager)\n })\n }\n}\n\n@EventSubscriber()\nexport class ActivityInstanceHistoryEntitySubscriber extends HistoryEntitySubscriber<\n ActivityInstance,\n ActivityInstanceHistory\n> {\n public get entity() {\n return ActivityInstance\n }\n\n public get historyEntity() {\n return ActivityInstanceHistory\n }\n\n}\n"]}
@@ -7,6 +7,7 @@ const auth_base_1 = require("@things-factory/auth-base");
7
7
  const shell_1 = require("@things-factory/shell");
8
8
  const activity_summary_js_1 = require("./activity-summary.js");
9
9
  const activity_instance_js_1 = require("../activity-instance/activity-instance.js");
10
+ const assignee_pool_js_1 = require("../activity-instance/assignee-pool.js");
10
11
  const open_work_js_1 = require("./open-work.js");
11
12
  let ActivitySummaryQuery = class ActivitySummaryQuery {
12
13
  async activitySummary(context) {
@@ -49,8 +50,7 @@ let ActivitySummaryQuery = class ActivitySummaryQuery {
49
50
  var { domain, user } = context.state;
50
51
  /*
51
52
  activity-instance 중에서 아직 created 상태이면서,
52
- activity-instance의 assigneeRole 이 지정되지 않았거나,
53
- assigneeRole이 지정되었으면 그 Role에 내가 해당된 경우이면서,
53
+ activity-instance 의 assigneeRoles 중 하나라도 내가 가진 경우이면서,
54
54
  나는 아직 해당 activity-instance의 thread를 할당받지 않은 경우에 해당하는
55
55
  activity-instance 리스트를 모두 가져오는 쿼리이다.
56
56
  */
@@ -72,7 +72,7 @@ let ActivitySummaryQuery = class ActivitySummaryQuery {
72
72
  .andWhere('ai.state IN (:...status)', {
73
73
  status: [activity_instance_js_1.ActivityInstanceStatus.Issued, activity_instance_js_1.ActivityInstanceStatus.Unassigned]
74
74
  })
75
- .andWhere('ai.assigneeRole IN (:...roles)', { roles })
75
+ .andWhere((0, assignee_pool_js_1.inPoolOf)('ai'), { roles })
76
76
  .andWhere('threads.id IS NULL') /* 이미 내가 할당된 경우는 제외한다. */
77
77
  .getCount();
78
78
  }
@@ -1 +1 @@
1
- {"version":3,"file":"activity-summary-query.js","sourceRoot":"","sources":["../../../server/service/activity-summary/activity-summary-query.ts"],"names":[],"mappings":";;;;AACA,+CAAwE;AAExE,yDAAgD;AAChD,iDAAoF;AAEpF,+DAAuD;AAIvD,oFAAoG;AACpG,iDAA4D;AAGrD,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAEzB,AAAN,KAAK,CAAC,eAAe,CAAQ,OAAwB;QACnD,OAAO,EAAE,CAAA;IACX,CAAC;IAGK,AAAN,KAAK,CAAC,aAAa,CAAS,eAAgC,EAAS,OAAwB;QAC3F,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEtC,gGAAgG;QAChG,OAAO,MAAM,IAAA,sBAAO,EAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;IACvC,CAAC;IAGK,AAAN,KAAK,CAAC,wBAAwB,CACpB,eAAgC,EACjC,OAAwB;QAE/B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEtC;;;;;;;;;;;;;;;;;;;;;;;WAuBG;QACH,OAAO,MAAM,IAAA,iCAAkB,EAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAA;IAClD,CAAC;IAGK,AAAN,KAAK,CAAC,aAAa,CAAS,eAAgC,EAAS,OAAwB;QAC3F,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEpC;;;;;;UAME;QAEF,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,gBAAI,CAAC,CAAC,OAAO,CAAC;YACvC,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;YACtB,SAAS,EAAE,CAAC,OAAO,CAAC;SACrB,CAAC,CAAA;QACF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAEzF,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAClB,OAAO,CAAC,CAAA;QACV,CAAC;QAED,OAAO,MAAM,IAAA,qCAA6B,EAAC;YACzC,UAAU,EAAE,IAAA,qBAAa,EAAC,uCAAgB,CAAC;YAC3C,MAAM,EAAE,EAAE;YACV,MAAM;YACN,KAAK,EAAE,IAAI;SACZ,CAAC;aACC,iBAAiB,CAAC,oBAAoB,EAAE,SAAS,EAAE,0BAA0B,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;aACjG,QAAQ,CAAC,0BAA0B,EAAE;YACpC,MAAM,EAAE,CAAC,6CAAsB,CAAC,MAAM,EAAE,6CAAsB,CAAC,UAAU,CAAC;SAC3E,CAAC;aACD,QAAQ,CAAC,gCAAgC,EAAE,EAAE,KAAK,EAAE,CAAC;aACrD,QAAQ,CAAC,oBAAoB,CAAC,CAAC,yBAAyB;aACxD,QAAQ,EAAE,CAAA;IACf,CAAC;IAGK,AAAN,KAAK,CAAC,cAAc,CAAS,eAAgC,EAAS,OAAwB;QAC5F,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;QAEpC,wDAAwD;QACxD,MAAM,MAAM,GAAG,CAAC,6CAAsB,CAAC,KAAK,CAAC,CAAA;QAE7C,OAAO,MAAM,IAAA,qCAA6B,EAAC;YACzC,UAAU,EAAE,IAAA,qBAAa,EAAC,uCAAgB,CAAC;YAC3C,MAAM,EAAE,EAAE;YACV,MAAM;YACN,KAAK,EAAE,IAAI;SACZ,CAAC;aACC,QAAQ,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,CAAC;aAChD,QAAQ,CAAC,oBAAoB,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;aACjD,QAAQ,EAAE,CAAA;IACf,CAAC;CACF,CAAA;AAtGY,oDAAoB;AAEzB;IADL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,qCAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,6BAA6B,EAAE,CAAC;IAC5E,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;2DAE3B;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IACT,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAAoC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAvB,qCAAe;;yDAK3D;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IAE3B,mBAAA,IAAA,mBAAI,GAAE,CAAA;IACN,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CADmB,qCAAe;;oEA8BzC;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IACT,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAAoC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAvB,qCAAe;;yDAkC3D;AAGK;IADL,IAAA,4BAAa,EAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IACR,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAAoC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CAAvB,qCAAe;;0DAe5D;+BArGU,oBAAoB;IADhC,IAAA,uBAAQ,EAAC,qCAAe,CAAC;GACb,oBAAoB,CAsGhC","sourcesContent":["import { Brackets } from 'typeorm'\nimport { Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { getQueryBuilderFromListParams, getRepository } from '@things-factory/shell'\n\nimport { ActivitySummary } from './activity-summary.js'\nimport { ActivityThread, ActivityThreadStatus } from '../activity-thread/activity-thread.js'\nimport { ActivityApproval } from '../activity-approval/activity-approval.js'\nimport { myPendingApprovalsWhere } from '../activity-approval/my-pending-approvals.js'\nimport { ActivityInstance, ActivityInstanceStatus } from '../activity-instance/activity-instance.js'\nimport { pendingApprovalsOf, toDosOf } from './open-work.js'\n\n@Resolver(ActivitySummary)\nexport class ActivitySummaryQuery {\n @Query(returns => ActivitySummary!, { nullable: true, description: 'To fetch a Activity Summary' })\n async activitySummary(@Ctx() context: ResolverContext): Promise<ActivitySummary> {\n return {}\n }\n\n @FieldResolver(type => Number)\n async numberOfToDos(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n const { domain, user } = context.state\n\n /* The rule lives in `open-work.ts`, shared with the person 360 - one answer to one question. */\n return await toDosOf(domain, user.id)\n }\n\n @FieldResolver(type => Number)\n async numberOfApprovalPendings(\n @Root() activitySummary: ActivitySummary,\n @Ctx() context: ResolverContext\n ): Promise<number> {\n const { domain, user } = context.state\n\n /*\n * The badge asks the same question the inbox does, through the same clause.\n *\n * ── What the badge was counting ───────────────────────────────────────\n * It had its own copy of \"not finished yet\", written as NOT IN four judgments, and that copy\n * had drifted three ways from the list it labels:\n *\n * closed a reference seat the case closed when it ended\n * aborted an approval closed because the thread was aborted\n * reference a seat that comments and never decides\n *\n * TERMINATED_JUDGMENTS holds six; this named four. So every ended thread and every case a\n * reference had been on kept adding to the number, and a role-held row had no judgment test at\n * all — once closed with nobody having pressed, `approver` stays empty and it would have been\n * counted forever, for everyone holding that role.\n *\n * The badge therefore read higher than the inbox it points at. Opening it showed fewer, or\n * nothing: a number that sends someone to an empty screen teaches them to stop believing it.\n *\n * ── Why the clause is borrowed rather than fixed here ─────────────────\n * Naming the six here would make the count right today and drift again at the seventh. The\n * inbox list and the calendar already share one clause for this; the badge is the third reader\n * and now asks through it too. `myPendingApprovalsWhere` carries why each part is there.\n */\n return await pendingApprovalsOf(domain, user.id)\n }\n\n @FieldResolver(type => Number)\n async numberOfPicks(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n var { domain, user } = context.state\n\n /* \n activity-instance 중에서 아직 created 상태이면서, \n activity-instance의 assigneeRole 이 지정되지 않았거나,\n assigneeRole이 지정되었으면 그 Role에 내가 해당된 경우이면서,\n 나는 아직 해당 activity-instance의 thread를 할당받지 않은 경우에 해당하는\n activity-instance 리스트를 모두 가져오는 쿼리이다.\n */\n\n user = await getRepository(User).findOne({\n where: { id: user.id },\n relations: ['roles']\n })\n const roles = user.roles.filter(role => role.domainId === domain.id).map(role => role.id)\n\n if (!roles.length) {\n return 0\n }\n\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityInstance),\n params: {},\n domain,\n alias: 'ai'\n })\n .leftJoinAndSelect('ai.activityThreads', 'threads', 'threads.assignee = :user', { user: user.id })\n .andWhere('ai.state IN (:...status)', {\n status: [ActivityInstanceStatus.Issued, ActivityInstanceStatus.Unassigned]\n })\n .andWhere('ai.assigneeRole IN (:...roles)', { roles })\n .andWhere('threads.id IS NULL') /* 이미 내가 할당된 경우는 제외한다. */\n .getCount()\n }\n\n @FieldResolver(type => Number)\n async numberOfDrafts(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n var { domain, user } = context.state\n\n /* 생성자가 자신이면서, 아직 Draft 상태인 activity-instance 리스트만 반환 */\n const status = [ActivityInstanceStatus.Draft]\n\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityInstance),\n params: {},\n domain,\n alias: 'ai'\n })\n .andWhere('ai.state IN (:...status)', { status })\n .andWhere('ai.creator = :user', { user: user.id })\n .getCount()\n }\n}\n"]}
1
+ {"version":3,"file":"activity-summary-query.js","sourceRoot":"","sources":["../../../server/service/activity-summary/activity-summary-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Brackets } from 'typeorm'\nimport { Ctx, FieldResolver, Query, Resolver, Root } from 'type-graphql'\n\nimport { User } from '@things-factory/auth-base'\nimport { getQueryBuilderFromListParams, getRepository } from '@things-factory/shell'\n\nimport { ActivitySummary } from './activity-summary.js'\nimport { ActivityThread, ActivityThreadStatus } from '../activity-thread/activity-thread.js'\nimport { ActivityApproval } from '../activity-approval/activity-approval.js'\nimport { myPendingApprovalsWhere } from '../activity-approval/my-pending-approvals.js'\nimport { ActivityInstance, ActivityInstanceStatus } from '../activity-instance/activity-instance.js'\nimport { inPoolOf } from '../activity-instance/assignee-pool.js'\nimport { pendingApprovalsOf, toDosOf } from './open-work.js'\n\n@Resolver(ActivitySummary)\nexport class ActivitySummaryQuery {\n @Query(returns => ActivitySummary!, { nullable: true, description: 'To fetch a Activity Summary' })\n async activitySummary(@Ctx() context: ResolverContext): Promise<ActivitySummary> {\n return {}\n }\n\n @FieldResolver(type => Number)\n async numberOfToDos(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n const { domain, user } = context.state\n\n /* The rule lives in `open-work.ts`, shared with the person 360 - one answer to one question. */\n return await toDosOf(domain, user.id)\n }\n\n @FieldResolver(type => Number)\n async numberOfApprovalPendings(\n @Root() activitySummary: ActivitySummary,\n @Ctx() context: ResolverContext\n ): Promise<number> {\n const { domain, user } = context.state\n\n /*\n * The badge asks the same question the inbox does, through the same clause.\n *\n * ── What the badge was counting ───────────────────────────────────────\n * It had its own copy of \"not finished yet\", written as NOT IN four judgments, and that copy\n * had drifted three ways from the list it labels:\n *\n * closed a reference seat the case closed when it ended\n * aborted an approval closed because the thread was aborted\n * reference a seat that comments and never decides\n *\n * TERMINATED_JUDGMENTS holds six; this named four. So every ended thread and every case a\n * reference had been on kept adding to the number, and a role-held row had no judgment test at\n * all — once closed with nobody having pressed, `approver` stays empty and it would have been\n * counted forever, for everyone holding that role.\n *\n * The badge therefore read higher than the inbox it points at. Opening it showed fewer, or\n * nothing: a number that sends someone to an empty screen teaches them to stop believing it.\n *\n * ── Why the clause is borrowed rather than fixed here ─────────────────\n * Naming the six here would make the count right today and drift again at the seventh. The\n * inbox list and the calendar already share one clause for this; the badge is the third reader\n * and now asks through it too. `myPendingApprovalsWhere` carries why each part is there.\n */\n return await pendingApprovalsOf(domain, user.id)\n }\n\n @FieldResolver(type => Number)\n async numberOfPicks(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n var { domain, user } = context.state\n\n /* \n activity-instance 중에서 아직 created 상태이면서, \n activity-instance 의 assigneeRoles 중 하나라도 내가 가진 경우이면서,\n 나는 아직 해당 activity-instance의 thread를 할당받지 않은 경우에 해당하는\n activity-instance 리스트를 모두 가져오는 쿼리이다.\n */\n\n user = await getRepository(User).findOne({\n where: { id: user.id },\n relations: ['roles']\n })\n const roles = user.roles.filter(role => role.domainId === domain.id).map(role => role.id)\n\n if (!roles.length) {\n return 0\n }\n\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityInstance),\n params: {},\n domain,\n alias: 'ai'\n })\n .leftJoinAndSelect('ai.activityThreads', 'threads', 'threads.assignee = :user', { user: user.id })\n .andWhere('ai.state IN (:...status)', {\n status: [ActivityInstanceStatus.Issued, ActivityInstanceStatus.Unassigned]\n })\n .andWhere(inPoolOf('ai'), { roles })\n .andWhere('threads.id IS NULL') /* 이미 내가 할당된 경우는 제외한다. */\n .getCount()\n }\n\n @FieldResolver(type => Number)\n async numberOfDrafts(@Root() activitySummary: ActivitySummary, @Ctx() context: ResolverContext): Promise<number> {\n var { domain, user } = context.state\n\n /* 생성자가 자신이면서, 아직 Draft 상태인 activity-instance 리스트만 반환 */\n const status = [ActivityInstanceStatus.Draft]\n\n return await getQueryBuilderFromListParams({\n repository: getRepository(ActivityInstance),\n params: {},\n domain,\n alias: 'ai'\n })\n .andWhere('ai.state IN (:...status)', { status })\n .andWhere('ai.creator = :user', { user: user.id })\n .getCount()\n }\n}\n"]}
@@ -12,7 +12,7 @@ export declare const FINISHED: ActivityThreadStatus[];
12
12
  * a different number than the list it opens. Nothing errors.
13
13
  *
14
14
  * Expects `at` (ActivityThread) and `ai` (ActivityInstance) to be joined already — the role branch
15
- * reads assigneeRole off the instance.
15
+ * reads the instance's pool (assignee-pool.ts).
16
16
  */
17
17
  export declare function myOpenThreadsWhere({ userId, roles }: {
18
18
  userId: string;
@@ -4,6 +4,7 @@ exports.FINISHED = exports.WAITING_ON_OTHERS = void 0;
4
4
  exports.myOpenThreadsWhere = myOpenThreadsWhere;
5
5
  exports.myThreadsOfOthersWhere = myThreadsOfOthersWhere;
6
6
  const typeorm_1 = require("typeorm");
7
+ const assignee_pool_js_1 = require("../activity-instance/assignee-pool.js");
7
8
  const activity_thread_js_1 = require("./activity-thread.js");
8
9
  /**
9
10
  * Thread states that are **not** my turn.
@@ -22,6 +23,12 @@ const NOT_MY_TURN = [
22
23
  activity_thread_js_1.ActivityThreadStatus.Ended,
23
24
  activity_thread_js_1.ActivityThreadStatus.Aborted
24
25
  ];
26
+ /** The thread table, for the raw EXISTS below - this module reads no entity metadata, as assignee-pool.ts. */
27
+ const THREADS = {
28
+ table: 'activity_threads',
29
+ caseColumn: 'activity_instance_id',
30
+ assigneeColumn: 'assignee_id'
31
+ };
25
32
  /** A thread I submitted, waiting on someone's judgment. */
26
33
  exports.WAITING_ON_OTHERS = [activity_thread_js_1.ActivityThreadStatus.Submitted, activity_thread_js_1.ActivityThreadStatus.Escalated];
27
34
  /** A thread that is over. */
@@ -34,19 +41,27 @@ exports.FINISHED = [activity_thread_js_1.ActivityThreadStatus.Ended, activity_th
34
41
  * a different number than the list it opens. Nothing errors.
35
42
  *
36
43
  * Expects `at` (ActivityThread) and `ai` (ActivityInstance) to be joined already — the role branch
37
- * reads assigneeRole off the instance.
44
+ * reads the instance's pool (assignee-pool.ts).
38
45
  */
39
46
  function myOpenThreadsWhere({ userId, roles }) {
40
47
  return new typeorm_1.Brackets(qb => {
41
48
  qb.where('at.state NOT IN (:...notMyTurn)', { notMyTurn: NOT_MY_TURN }).andWhere('at.assignee = :userId', {
42
49
  userId
43
50
  });
44
- /* 역할로 걸린 것은 아직 임자가 없다 — 그 역할을 가진 사람 모두의 할 일이다. */
51
+ /*
52
+ * 역할로 걸린 것은 아직 임자가 없다 — 그 역할들 중 하나라도 가진 사람 모두의 할 일이다.
53
+ *
54
+ * Except someone who holds a thread of the case already: in a case waiting for more than one person
55
+ * (threadsMin > 1) they would see it twice - their own thread and the waiting one beside it - and taking
56
+ * the waiting one is refused (one person, one thread of a case).
57
+ */
45
58
  if (roles.length > 0) {
46
59
  qb.orWhere(new typeorm_1.Brackets(subQb => {
47
60
  subQb
48
- .where('ai.assigneeRole IN (:...roles)', { roles })
49
- .andWhere('at.state = :unassigned', { unassigned: activity_thread_js_1.ActivityThreadStatus.Unassigned });
61
+ .where((0, assignee_pool_js_1.inPoolOf)('ai'), { roles })
62
+ .andWhere('at.state = :unassigned', { unassigned: activity_thread_js_1.ActivityThreadStatus.Unassigned })
63
+ .andWhere(`NOT EXISTS (SELECT 1 FROM ${THREADS.table} mine` +
64
+ ` WHERE mine.${THREADS.caseColumn} = ai.id AND mine.${THREADS.assigneeColumn} = :userId)`, { userId });
50
65
  }));
51
66
  }
52
67
  });
@@ -1 +1 @@
1
- {"version":3,"file":"my-open-threads.js","sourceRoot":"","sources":["../../../server/service/activity-thread/my-open-threads.ts"],"names":[],"mappings":";;;AAsCA,gDAiBC;AAYD,wDAMC;AAzED,qCAAkC;AAElC,6DAA2D;AAE3D;;;;;;;;;GASG;AACH,MAAM,WAAW,GAAG;IAClB,yCAAoB,CAAC,UAAU;IAC/B,yCAAoB,CAAC,SAAS;IAC9B,yCAAoB,CAAC,SAAS;IAC9B,yCAAoB,CAAC,KAAK;IAC1B,yCAAoB,CAAC,OAAO;CAC7B,CAAA;AAED,2DAA2D;AAC9C,QAAA,iBAAiB,GAAG,CAAC,yCAAoB,CAAC,SAAS,EAAE,yCAAoB,CAAC,SAAS,CAAC,CAAA;AAEjG,6BAA6B;AAChB,QAAA,QAAQ,GAAG,CAAC,yCAAoB,CAAC,KAAK,EAAE,yCAAoB,CAAC,OAAO,CAAC,CAAA;AAElF;;;;;;;;;GASG;AACH,SAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAuC;IACvF,OAAO,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE;QACvB,EAAE,CAAC,KAAK,CAAC,iCAAiC,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,uBAAuB,EAAE;YACxG,MAAM;SACP,CAAC,CAAA;QAEF,kDAAkD;QAClD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,EAAE,CAAC,OAAO,CACR,IAAI,kBAAQ,CAAC,KAAK,CAAC,EAAE;gBACnB,KAAK;qBACF,KAAK,CAAC,gCAAgC,EAAE,EAAE,KAAK,EAAE,CAAC;qBAClD,QAAQ,CAAC,wBAAwB,EAAE,EAAE,UAAU,EAAE,yCAAoB,CAAC,UAAU,EAAE,CAAC,CAAA;YACxF,CAAC,CAAC,CACH,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,sBAAsB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAsD;IAC3G,OAAO,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE;QACvB,EAAE,CAAC,KAAK,CAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,CAAC;aAC1C,QAAQ,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,CAAC;aAChD,QAAQ,CAAC,+CAA+C,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { Brackets } from 'typeorm'\n\nimport { ActivityThreadStatus } from './activity-thread.js'\n\n/**\n * Thread states that are **not** my turn.\n *\n * Submitted and escalated wait on an approver: the thread is still assigned to me, but nothing I do\n * moves it. Counting them made 할 일 say 1 to a person who had just put up an expenditure request\n * and had nothing left to do (2026-10-16). They are the 「제출한 것」 group of the same box.\n *\n * Unassigned belongs here for the person branch only — a thread nobody holds is not on my plate\n * until I claim it, and the role branch below is what surfaces it to the people who could.\n */\nconst NOT_MY_TURN = [\n ActivityThreadStatus.Unassigned,\n ActivityThreadStatus.Submitted,\n ActivityThreadStatus.Escalated,\n ActivityThreadStatus.Ended,\n ActivityThreadStatus.Aborted\n]\n\n/** A thread I submitted, waiting on someone's judgment. */\nexport const WAITING_ON_OTHERS = [ActivityThreadStatus.Submitted, ActivityThreadStatus.Escalated]\n\n/** A thread that is over. */\nexport const FINISHED = [ActivityThreadStatus.Ended, ActivityThreadStatus.Aborted]\n\n/**\n * The work that is on my plate — one definition, three readers.\n *\n * 할 일 목록 asks this, and so do the calendar and the badge (open-work). Written twice they drift:\n * a new state, or a new way of being assigned, lands in one and not the other, and the badge says\n * a different number than the list it opens. Nothing errors.\n *\n * Expects `at` (ActivityThread) and `ai` (ActivityInstance) to be joined already — the role branch\n * reads assigneeRole off the instance.\n */\nexport function myOpenThreadsWhere({ userId, roles }: { userId: string; roles: string[] }): Brackets {\n return new Brackets(qb => {\n qb.where('at.state NOT IN (:...notMyTurn)', { notMyTurn: NOT_MY_TURN }).andWhere('at.assignee = :userId', {\n userId\n })\n\n /* 역할로 걸린 것은 아직 임자가 없다 — 그 역할을 가진 사람 모두의 할 일이다. */\n if (roles.length > 0) {\n qb.orWhere(\n new Brackets(subQb => {\n subQb\n .where('ai.assigneeRole IN (:...roles)', { roles })\n .andWhere('at.state = :unassigned', { unassigned: ActivityThreadStatus.Unassigned })\n })\n )\n }\n })\n}\n\n/**\n * My threads in these states, of work **someone else** put up.\n *\n * What I put up myself is followed in 상신함 — the box of what I gave others to do. A post thread\n * is mine only as the vehicle of my request: once submitted it waits on the approvers, and when it\n * ends it is my request that ended. Listing it again under 할 일 put one fact in two boxes. While it\n * is my turn - rejected and back with me - it stays in 할 일, which is myOpenThreadsWhere above.\n *\n * Expects `at` and `ai` joined.\n */\nexport function myThreadsOfOthersWhere({ userId, states }: { userId: string; states: ActivityThreadStatus[] }): Brackets {\n return new Brackets(qb => {\n qb.where('at.assignee = :userId', { userId })\n .andWhere('at.state IN (:...states)', { states })\n .andWhere('(ai.creator IS NULL OR ai.creator != :userId)', { userId })\n })\n}\n"]}
1
+ {"version":3,"file":"my-open-threads.js","sourceRoot":"","sources":["../../../server/service/activity-thread/my-open-threads.ts"],"names":[],"mappings":";;;AA8CA,gDA4BC;AAYD,wDAMC;AA5FD,qCAAkC;AAElC,4EAAgE;AAChE,6DAA2D;AAE3D;;;;;;;;;GASG;AACH,MAAM,WAAW,GAAG;IAClB,yCAAoB,CAAC,UAAU;IAC/B,yCAAoB,CAAC,SAAS;IAC9B,yCAAoB,CAAC,SAAS;IAC9B,yCAAoB,CAAC,KAAK;IAC1B,yCAAoB,CAAC,OAAO;CAC7B,CAAA;AAED,8GAA8G;AAC9G,MAAM,OAAO,GAAG;IACd,KAAK,EAAE,kBAAkB;IACzB,UAAU,EAAE,sBAAsB;IAClC,cAAc,EAAE,aAAa;CACrB,CAAA;AAEV,2DAA2D;AAC9C,QAAA,iBAAiB,GAAG,CAAC,yCAAoB,CAAC,SAAS,EAAE,yCAAoB,CAAC,SAAS,CAAC,CAAA;AAEjG,6BAA6B;AAChB,QAAA,QAAQ,GAAG,CAAC,yCAAoB,CAAC,KAAK,EAAE,yCAAoB,CAAC,OAAO,CAAC,CAAA;AAElF;;;;;;;;;GASG;AACH,SAAgB,kBAAkB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAuC;IACvF,OAAO,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE;QACvB,EAAE,CAAC,KAAK,CAAC,iCAAiC,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,uBAAuB,EAAE;YACxG,MAAM;SACP,CAAC,CAAA;QAEF;;;;;;WAMG;QACH,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,EAAE,CAAC,OAAO,CACR,IAAI,kBAAQ,CAAC,KAAK,CAAC,EAAE;gBACnB,KAAK;qBACF,KAAK,CAAC,IAAA,2BAAQ,EAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC;qBAChC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,UAAU,EAAE,yCAAoB,CAAC,UAAU,EAAE,CAAC;qBACnF,QAAQ,CACP,6BAA6B,OAAO,CAAC,KAAK,OAAO;oBAC/C,eAAe,OAAO,CAAC,UAAU,qBAAqB,OAAO,CAAC,cAAc,aAAa,EAC3F,EAAE,MAAM,EAAE,CACX,CAAA;YACL,CAAC,CAAC,CACH,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,sBAAsB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAsD;IAC3G,OAAO,IAAI,kBAAQ,CAAC,EAAE,CAAC,EAAE;QACvB,EAAE,CAAC,KAAK,CAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,CAAC;aAC1C,QAAQ,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,CAAC;aAChD,QAAQ,CAAC,+CAA+C,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { Brackets } from 'typeorm'\n\nimport { inPoolOf } from '../activity-instance/assignee-pool.js'\nimport { ActivityThreadStatus } from './activity-thread.js'\n\n/**\n * Thread states that are **not** my turn.\n *\n * Submitted and escalated wait on an approver: the thread is still assigned to me, but nothing I do\n * moves it. Counting them made 할 일 say 1 to a person who had just put up an expenditure request\n * and had nothing left to do (2026-10-16). They are the 「제출한 것」 group of the same box.\n *\n * Unassigned belongs here for the person branch only — a thread nobody holds is not on my plate\n * until I claim it, and the role branch below is what surfaces it to the people who could.\n */\nconst NOT_MY_TURN = [\n ActivityThreadStatus.Unassigned,\n ActivityThreadStatus.Submitted,\n ActivityThreadStatus.Escalated,\n ActivityThreadStatus.Ended,\n ActivityThreadStatus.Aborted\n]\n\n/** The thread table, for the raw EXISTS below - this module reads no entity metadata, as assignee-pool.ts. */\nconst THREADS = {\n table: 'activity_threads',\n caseColumn: 'activity_instance_id',\n assigneeColumn: 'assignee_id'\n} as const\n\n/** A thread I submitted, waiting on someone's judgment. */\nexport const WAITING_ON_OTHERS = [ActivityThreadStatus.Submitted, ActivityThreadStatus.Escalated]\n\n/** A thread that is over. */\nexport const FINISHED = [ActivityThreadStatus.Ended, ActivityThreadStatus.Aborted]\n\n/**\n * The work that is on my plate — one definition, three readers.\n *\n * 할 일 목록 asks this, and so do the calendar and the badge (open-work). Written twice they drift:\n * a new state, or a new way of being assigned, lands in one and not the other, and the badge says\n * a different number than the list it opens. Nothing errors.\n *\n * Expects `at` (ActivityThread) and `ai` (ActivityInstance) to be joined already — the role branch\n * reads the instance's pool (assignee-pool.ts).\n */\nexport function myOpenThreadsWhere({ userId, roles }: { userId: string; roles: string[] }): Brackets {\n return new Brackets(qb => {\n qb.where('at.state NOT IN (:...notMyTurn)', { notMyTurn: NOT_MY_TURN }).andWhere('at.assignee = :userId', {\n userId\n })\n\n /*\n * 역할로 걸린 것은 아직 임자가 없다 — 그 역할들 중 하나라도 가진 사람 모두의 할 일이다.\n *\n * Except someone who holds a thread of the case already: in a case waiting for more than one person\n * (threadsMin > 1) they would see it twice - their own thread and the waiting one beside it - and taking\n * the waiting one is refused (one person, one thread of a case).\n */\n if (roles.length > 0) {\n qb.orWhere(\n new Brackets(subQb => {\n subQb\n .where(inPoolOf('ai'), { roles })\n .andWhere('at.state = :unassigned', { unassigned: ActivityThreadStatus.Unassigned })\n .andWhere(\n `NOT EXISTS (SELECT 1 FROM ${THREADS.table} mine` +\n ` WHERE mine.${THREADS.caseColumn} = ai.id AND mine.${THREADS.assigneeColumn} = :userId)`,\n { userId }\n )\n })\n )\n }\n })\n}\n\n/**\n * My threads in these states, of work **someone else** put up.\n *\n * What I put up myself is followed in 상신함 — the box of what I gave others to do. A post thread\n * is mine only as the vehicle of my request: once submitted it waits on the approvers, and when it\n * ends it is my request that ended. Listing it again under 할 일 put one fact in two boxes. While it\n * is my turn - rejected and back with me - it stays in 할 일, which is myOpenThreadsWhere above.\n *\n * Expects `at` and `ai` joined.\n */\nexport function myThreadsOfOthersWhere({ userId, states }: { userId: string; states: ActivityThreadStatus[] }): Brackets {\n return new Brackets(qb => {\n qb.where('at.assignee = :userId', { userId })\n .andWhere('at.state IN (:...states)', { states })\n .andWhere('(ai.creator IS NULL OR ai.creator != :userId)', { userId })\n })\n}\n"]}
@@ -33,13 +33,14 @@ export declare function hearsApproval(approval: {
33
33
  id: string;
34
34
  }[]>): Promise<boolean>;
35
35
  /**
36
- * An instance reaches whoever made it, and anyone holding the role it is waiting for. The roles are
36
+ * An instance reaches whoever made it, and anyone holding any one of the roles it is waiting for - once,
37
+ * however many of them they hold: this answers yes or no for one subscriber. The roles are
37
38
  * asked only after the domain matched — the lookup is not free and is never needed for another tenant.
38
39
  */
39
40
  export declare function hearsInstance(instance: {
40
41
  domainId?: string;
41
42
  creatorId?: string;
42
- assigneeRoleId?: string;
43
+ assigneeRoleIds?: string[];
43
44
  }, domain: DomainLike, userId: string, rolesOf: () => Promise<{
44
45
  id: string;
45
46
  }[]>): Promise<boolean>;
@@ -39,7 +39,8 @@ async function hearsApproval(approval, domain, userId, rolesOf) {
39
39
  return (await rolesOf()).some(role => role.id === approval.approverRoleId);
40
40
  }
41
41
  /**
42
- * An instance reaches whoever made it, and anyone holding the role it is waiting for. The roles are
42
+ * An instance reaches whoever made it, and anyone holding any one of the roles it is waiting for - once,
43
+ * however many of them they hold: this answers yes or no for one subscriber. The roles are
43
44
  * asked only after the domain matched — the lookup is not free and is never needed for another tenant.
44
45
  */
45
46
  async function hearsInstance(instance, domain, userId, rolesOf) {
@@ -47,8 +48,10 @@ async function hearsInstance(instance, domain, userId, rolesOf) {
47
48
  return false;
48
49
  if (instance.creatorId === userId)
49
50
  return true;
50
- if (!instance.assigneeRoleId)
51
+ const poolIds = instance.assigneeRoleIds || [];
52
+ if (!poolIds.length)
51
53
  return false;
52
- return (await rolesOf()).some(role => role.id === instance.assigneeRoleId);
54
+ const held = (await rolesOf()).map(role => role.id);
55
+ return poolIds.some(id => held.includes(id));
53
56
  }
54
57
  //# sourceMappingURL=subscription-filters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"subscription-filters.js","sourceRoot":"","sources":["../../../server/service/subscription/subscription-filters.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AASH,kCAEC;AAUD,sCAWC;AAMD,sCAWC;AA7CD,SAAS,QAAQ,CAAC,aAAiC,EAAE,MAAkB;IACrE,OAAO,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,aAAa,KAAK,MAAM,CAAC,EAAE,CAAA;AACvE,CAAC;AAED,qDAAqD;AACrD,SAAgB,WAAW,CAAC,MAAkD,EAAE,MAAkB,EAAE,MAAc;IAChH,OAAO,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,KAAK,MAAM,CAAA;AAC3E,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,aAAa,CACjC,QAA6E,EAC7E,MAAkB,EAClB,MAAc,EACd,OAAwC;IAExC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IACvD,IAAI,QAAQ,CAAC,UAAU,KAAK,MAAM;QAAE,OAAO,IAAI,CAAA;IAC/C,IAAI,CAAC,QAAQ,CAAC,cAAc;QAAE,OAAO,KAAK,CAAA;IAE1C,OAAO,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,QAAQ,CAAC,cAAc,CAAC,CAAA;AAC5E,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,aAAa,CACjC,QAA4E,EAC5E,MAAkB,EAClB,MAAc,EACd,OAAwC;IAExC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IACvD,IAAI,QAAQ,CAAC,SAAS,KAAK,MAAM;QAAE,OAAO,IAAI,CAAA;IAC9C,IAAI,CAAC,QAAQ,CAAC,cAAc;QAAE,OAAO,KAAK,CAAA;IAE1C,OAAO,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,QAAQ,CAAC,cAAc,CAAC,CAAA;AAC5E,CAAC","sourcesContent":["/**\n * Who hears which worklist event — the filters behind the three subscriptions, kept free of\n * entities and pubsub so they can be tested.\n *\n * Every filter compares the event's domain to the subscriber's first. A thread or an approval in\n * another tenant must never reach this socket, even when the ids beside it happen to match.\n * An event whose domain is not known is dropped: without it the filter cannot tell tenants apart.\n *\n * The ids are the entity's @RelationId fields. TypeORM fills them on the entity it hands the\n * subscriber, on insert as well as update - measured, and held by tests/published-shape.test.ts.\n */\n\ntype DomainLike = { id?: string } | null | undefined\n\nfunction inDomain(eventDomainId: string | undefined, domain: DomainLike): boolean {\n return !!eventDomainId && !!domain?.id && eventDomainId === domain.id\n}\n\n/** A thread reaches the person it is assigned to. */\nexport function hearsThread(thread: { domainId?: string; assigneeId?: string }, domain: DomainLike, userId: string) {\n return inDomain(thread?.domainId, domain) && thread.assigneeId === userId\n}\n\n/**\n * An approval reaches its approver, and anyone holding the role it is addressed to. A role-addressed\n * step has no approver - only the role - so without the second half nobody hears it. The roles are\n * asked only after the domain matched, as for an instance.\n *\n * Hearing is not being offered: the client refetches its summary, and the summary leaves out what the\n * listener issued (own-request.ts). So the issuer may hear their own step and still not see it.\n */\nexport async function hearsApproval(\n approval: { domainId?: string; approverId?: string; approverRoleId?: string },\n domain: DomainLike,\n userId: string,\n rolesOf: () => Promise<{ id: string }[]>\n): Promise<boolean> {\n if (!inDomain(approval?.domainId, domain)) return false\n if (approval.approverId === userId) return true\n if (!approval.approverRoleId) return false\n\n return (await rolesOf()).some(role => role.id === approval.approverRoleId)\n}\n\n/**\n * An instance reaches whoever made it, and anyone holding the role it is waiting for. The roles are\n * asked only after the domain matched — the lookup is not free and is never needed for another tenant.\n */\nexport async function hearsInstance(\n instance: { domainId?: string; creatorId?: string; assigneeRoleId?: string },\n domain: DomainLike,\n userId: string,\n rolesOf: () => Promise<{ id: string }[]>\n): Promise<boolean> {\n if (!inDomain(instance?.domainId, domain)) return false\n if (instance.creatorId === userId) return true\n if (!instance.assigneeRoleId) return false\n\n return (await rolesOf()).some(role => role.id === instance.assigneeRoleId)\n}\n"]}
1
+ {"version":3,"file":"subscription-filters.js","sourceRoot":"","sources":["../../../server/service/subscription/subscription-filters.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AASH,kCAEC;AAUD,sCAWC;AAOD,sCAaC;AAhDD,SAAS,QAAQ,CAAC,aAAiC,EAAE,MAAkB;IACrE,OAAO,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,aAAa,KAAK,MAAM,CAAC,EAAE,CAAA;AACvE,CAAC;AAED,qDAAqD;AACrD,SAAgB,WAAW,CAAC,MAAkD,EAAE,MAAkB,EAAE,MAAc;IAChH,OAAO,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,UAAU,KAAK,MAAM,CAAA;AAC3E,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,aAAa,CACjC,QAA6E,EAC7E,MAAkB,EAClB,MAAc,EACd,OAAwC;IAExC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IACvD,IAAI,QAAQ,CAAC,UAAU,KAAK,MAAM;QAAE,OAAO,IAAI,CAAA;IAC/C,IAAI,CAAC,QAAQ,CAAC,cAAc;QAAE,OAAO,KAAK,CAAA;IAE1C,OAAO,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,QAAQ,CAAC,cAAc,CAAC,CAAA;AAC5E,CAAC;AAED;;;;GAIG;AACI,KAAK,UAAU,aAAa,CACjC,QAA+E,EAC/E,MAAkB,EAClB,MAAc,EACd,OAAwC;IAExC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IACvD,IAAI,QAAQ,CAAC,SAAS,KAAK,MAAM;QAAE,OAAO,IAAI,CAAA;IAC9C,MAAM,OAAO,GAAG,QAAQ,CAAC,eAAe,IAAI,EAAE,CAAA;IAC9C,IAAI,CAAC,OAAO,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IAEjC,MAAM,IAAI,GAAG,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACnD,OAAO,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;AAC9C,CAAC","sourcesContent":["/**\n * Who hears which worklist event — the filters behind the three subscriptions, kept free of\n * entities and pubsub so they can be tested.\n *\n * Every filter compares the event's domain to the subscriber's first. A thread or an approval in\n * another tenant must never reach this socket, even when the ids beside it happen to match.\n * An event whose domain is not known is dropped: without it the filter cannot tell tenants apart.\n *\n * The ids are the entity's @RelationId fields. TypeORM fills them on the entity it hands the\n * subscriber, on insert as well as update - measured, and held by tests/published-shape.test.ts.\n */\n\ntype DomainLike = { id?: string } | null | undefined\n\nfunction inDomain(eventDomainId: string | undefined, domain: DomainLike): boolean {\n return !!eventDomainId && !!domain?.id && eventDomainId === domain.id\n}\n\n/** A thread reaches the person it is assigned to. */\nexport function hearsThread(thread: { domainId?: string; assigneeId?: string }, domain: DomainLike, userId: string) {\n return inDomain(thread?.domainId, domain) && thread.assigneeId === userId\n}\n\n/**\n * An approval reaches its approver, and anyone holding the role it is addressed to. A role-addressed\n * step has no approver - only the role - so without the second half nobody hears it. The roles are\n * asked only after the domain matched, as for an instance.\n *\n * Hearing is not being offered: the client refetches its summary, and the summary leaves out what the\n * listener issued (own-request.ts). So the issuer may hear their own step and still not see it.\n */\nexport async function hearsApproval(\n approval: { domainId?: string; approverId?: string; approverRoleId?: string },\n domain: DomainLike,\n userId: string,\n rolesOf: () => Promise<{ id: string }[]>\n): Promise<boolean> {\n if (!inDomain(approval?.domainId, domain)) return false\n if (approval.approverId === userId) return true\n if (!approval.approverRoleId) return false\n\n return (await rolesOf()).some(role => role.id === approval.approverRoleId)\n}\n\n/**\n * An instance reaches whoever made it, and anyone holding any one of the roles it is waiting for - once,\n * however many of them they hold: this answers yes or no for one subscriber. The roles are\n * asked only after the domain matched — the lookup is not free and is never needed for another tenant.\n */\nexport async function hearsInstance(\n instance: { domainId?: string; creatorId?: string; assigneeRoleIds?: string[] },\n domain: DomainLike,\n userId: string,\n rolesOf: () => Promise<{ id: string }[]>\n): Promise<boolean> {\n if (!inDomain(instance?.domainId, domain)) return false\n if (instance.creatorId === userId) return true\n const poolIds = instance.assigneeRoleIds || []\n if (!poolIds.length) return false\n\n const held = (await rolesOf()).map(role => role.id)\n return poolIds.some(id => held.includes(id))\n}\n"]}