@bantr-sports/sdk 12.9.0 → 12.11.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 (75) hide show
  1. package/api-type/src/modules/broadcast/broadcast.factory.d.ts +4 -0
  2. package/api-type/src/modules/broadcast/broadcast.schema.d.ts +302 -0
  3. package/api-type/src/modules/broadcast/broadcast.service.d.ts +219 -0
  4. package/api-type/src/modules/broadcast/broadcast_content_hash.d.ts +17 -0
  5. package/api-type/src/modules/chat/chat.repository.d.ts +65 -1
  6. package/api-type/src/modules/chat/chat.schema.d.ts +7 -1
  7. package/api-type/src/modules/chat/chat.service.d.ts +41 -0
  8. package/api-type/src/modules/discount_code/discount_code.schema.d.ts +133 -2
  9. package/api-type/src/modules/geolocation/geolocation.schema.d.ts +22 -1
  10. package/api-type/src/modules/geolocation/geolocation.service.d.ts +2 -0
  11. package/api-type/src/modules/member_notification_settings/member_notification_settings.middleware.d.ts +8 -4
  12. package/api-type/src/modules/member_notification_settings/member_notification_settings.service.d.ts +1 -0
  13. package/api-type/src/modules/rules/rules.factory.d.ts +4 -0
  14. package/api-type/src/modules/rules/rules.schema.d.ts +67 -0
  15. package/api-type/src/modules/rules/rules.service.d.ts +38 -0
  16. package/api-type/src/modules/scout_feed/scout_feed.service.d.ts +6 -0
  17. package/api-type/src/modules/scout_feed/scout_feed_location.d.ts +27 -0
  18. package/api-type/src/modules/scout_invite/scout_invite.factory.d.ts +4 -0
  19. package/api-type/src/modules/scout_invite/scout_invite.schema.d.ts +51 -0
  20. package/api-type/src/modules/scout_invite/scout_invite.service.d.ts +65 -0
  21. package/api-type/src/modules/scout_profile/scout_soccer_profile.model.d.ts +2 -0
  22. package/api-type/src/modules/suspension/suspension.constants.d.ts +1 -0
  23. package/api-type/src/modules/suspension/suspension.dates.d.ts +1 -0
  24. package/api-type/src/modules/suspension/suspension.hooks.d.ts +5 -13
  25. package/api-type/src/modules/suspension/suspension.queries.d.ts +3 -0
  26. package/api-type/src/modules/suspension/suspension.schema.d.ts +4 -2
  27. package/api-type/src/modules/suspension/suspension.scope.d.ts +1 -0
  28. package/api-type/src/modules/suspension/suspension.service.d.ts +21 -6
  29. package/api-type/src/modules/transaction/transaction.service.d.ts +1 -0
  30. package/api-type/src/trpcRouter/auth.router.d.ts +4 -1
  31. package/api-type/src/trpcRouter/broadcast.router.d.ts +190 -0
  32. package/api-type/src/trpcRouter/calendar.router.d.ts +4 -1
  33. package/api-type/src/trpcRouter/chat.router.d.ts +38 -3
  34. package/api-type/src/trpcRouter/csae-report.router.d.ts +4 -1
  35. package/api-type/src/trpcRouter/discount_code.router.d.ts +4 -1
  36. package/api-type/src/trpcRouter/event.router.d.ts +4 -1
  37. package/api-type/src/trpcRouter/free_agent_payments.router.d.ts +4 -1
  38. package/api-type/src/trpcRouter/geolocation.router.d.ts +19 -1
  39. package/api-type/src/trpcRouter/league.router.d.ts +4 -1
  40. package/api-type/src/trpcRouter/league_payments.router.d.ts +4 -1
  41. package/api-type/src/trpcRouter/marketplace.router.d.ts +4 -1
  42. package/api-type/src/trpcRouter/member_notification_settings.d.ts +4 -1
  43. package/api-type/src/trpcRouter/messaging.router.d.ts +15 -12
  44. package/api-type/src/trpcRouter/oauth.router.d.ts +4 -1
  45. package/api-type/src/trpcRouter/organization.router.d.ts +4 -1
  46. package/api-type/src/trpcRouter/organization_debt.router.d.ts +4 -1
  47. package/api-type/src/trpcRouter/pickup_payments.router.d.ts +4 -1
  48. package/api-type/src/trpcRouter/player_id_validation.router.d.ts +4 -1
  49. package/api-type/src/trpcRouter/product.router.d.ts +4 -1
  50. package/api-type/src/trpcRouter/refund_request.router.d.ts +4 -1
  51. package/api-type/src/trpcRouter/router.d.ts +1036 -88
  52. package/api-type/src/trpcRouter/rules.router.d.ts +53 -0
  53. package/api-type/src/trpcRouter/scout_feed.router.d.ts +4 -1
  54. package/api-type/src/trpcRouter/scout_invite.router.d.ts +103 -0
  55. package/api-type/src/trpcRouter/scout_profile.router.d.ts +4 -1
  56. package/api-type/src/trpcRouter/super_admin_organizers.router.d.ts +4 -1
  57. package/api-type/src/trpcRouter/super_admin_stripe_settings.router.d.ts +4 -1
  58. package/api-type/src/trpcRouter/super_admin_transfers.router.d.ts +4 -1
  59. package/api-type/src/trpcRouter/suspension.router.d.ts +6 -3
  60. package/api-type/src/trpcRouter/team.d.ts +4 -1
  61. package/api-type/src/trpcRouter/transaction.router.d.ts +5 -1
  62. package/api-type/src/types/common.d.ts +1 -0
  63. package/api-type/src/types/game_indicator.d.ts +2 -0
  64. package/api-type/src/types/geolocation.d.ts +24 -0
  65. package/api-type/src/types/index.d.ts +2 -2
  66. package/api-type/src/types/league.d.ts +3 -1
  67. package/api-type/src/types/member_notification_settings.d.ts +2 -1
  68. package/api-type/src/types/team.d.ts +2 -0
  69. package/dist/index.d.ts +1542 -120
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/provider.d.ts +1010 -62
  72. package/dist/provider.d.ts.map +1 -1
  73. package/dist/query.d.ts +505 -31
  74. package/dist/query.d.ts.map +1 -1
  75. package/package.json +1 -1
@@ -0,0 +1,4 @@
1
+ import { BroadcastService } from './broadcast.service';
2
+ export declare class BroadcastFactory {
3
+ static createInstance(): BroadcastService;
4
+ }
@@ -0,0 +1,302 @@
1
+ import { z } from 'zod';
2
+ export declare const GetBroadcastsInputSchema: z.ZodObject<{
3
+ organizationId: z.ZodNumber;
4
+ orgWorkspaceId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
5
+ search: z.ZodOptional<z.ZodString>;
6
+ isArchived: z.ZodOptional<z.ZodEnum<["active", "archived"]>>;
7
+ limit: z.ZodDefault<z.ZodNumber>;
8
+ offset: z.ZodDefault<z.ZodNumber>;
9
+ }, "strip", z.ZodTypeAny, {
10
+ limit: number;
11
+ offset: number;
12
+ organizationId: number;
13
+ search?: string | undefined;
14
+ orgWorkspaceId?: number | null | undefined;
15
+ isArchived?: "active" | "archived" | undefined;
16
+ }, {
17
+ organizationId: number;
18
+ limit?: number | undefined;
19
+ offset?: number | undefined;
20
+ search?: string | undefined;
21
+ orgWorkspaceId?: number | null | undefined;
22
+ isArchived?: "active" | "archived" | undefined;
23
+ }>;
24
+ export type GetBroadcastsInput = z.infer<typeof GetBroadcastsInputSchema>;
25
+ export declare const GetBroadcastByIdInputSchema: z.ZodObject<{
26
+ id: z.ZodNumber;
27
+ }, "strip", z.ZodTypeAny, {
28
+ id: number;
29
+ }, {
30
+ id: number;
31
+ }>;
32
+ export type GetBroadcastByIdInput = z.infer<typeof GetBroadcastByIdInputSchema>;
33
+ export declare const GetBroadcastDeliveryStatusesInputSchema: z.ZodObject<{
34
+ broadcastId: z.ZodNumber;
35
+ }, "strip", z.ZodTypeAny, {
36
+ broadcastId: number;
37
+ }, {
38
+ broadcastId: number;
39
+ }>;
40
+ export type GetBroadcastDeliveryStatusesInput = z.infer<typeof GetBroadcastDeliveryStatusesInputSchema>;
41
+ export declare const GetAudienceInputSchema: z.ZodObject<{
42
+ seasonId: z.ZodOptional<z.ZodNumber>;
43
+ leagueId: z.ZodOptional<z.ZodNumber>;
44
+ teamId: z.ZodOptional<z.ZodNumber>;
45
+ pickupGroupId: z.ZodOptional<z.ZodNumber>;
46
+ pickupEventId: z.ZodOptional<z.ZodNumber>;
47
+ playerRole: z.ZodOptional<z.ZodNullable<z.ZodString>>;
48
+ }, "strip", z.ZodTypeAny, {
49
+ teamId?: number | undefined;
50
+ pickupGroupId?: number | undefined;
51
+ leagueId?: number | undefined;
52
+ seasonId?: number | undefined;
53
+ pickupEventId?: number | undefined;
54
+ playerRole?: string | null | undefined;
55
+ }, {
56
+ teamId?: number | undefined;
57
+ pickupGroupId?: number | undefined;
58
+ leagueId?: number | undefined;
59
+ seasonId?: number | undefined;
60
+ pickupEventId?: number | undefined;
61
+ playerRole?: string | null | undefined;
62
+ }>;
63
+ export type GetAudienceInput = z.infer<typeof GetAudienceInputSchema>;
64
+ export declare const SaveBroadcastInputSchema: z.ZodObject<{
65
+ id: z.ZodOptional<z.ZodNumber>;
66
+ organizationId: z.ZodNumber;
67
+ orgWorkspaceId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
68
+ subject: z.ZodString;
69
+ message: z.ZodString;
70
+ delivery: z.ZodObject<{
71
+ email: z.ZodBoolean;
72
+ push: z.ZodBoolean;
73
+ }, "strip", z.ZodTypeAny, {
74
+ email: boolean;
75
+ push: boolean;
76
+ }, {
77
+ email: boolean;
78
+ push: boolean;
79
+ }>;
80
+ senderEmail: z.ZodString;
81
+ audienceGroups: z.ZodArray<z.ZodEffects<z.ZodObject<{
82
+ seasonId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
83
+ leagueId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
84
+ teamId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
85
+ pickupGroupId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
86
+ pickupEventId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
87
+ playerRole: z.ZodOptional<z.ZodNullable<z.ZodString>>;
88
+ memberIds: z.ZodArray<z.ZodNumber, "many">;
89
+ totalMembers: z.ZodOptional<z.ZodNumber>;
90
+ }, "strip", z.ZodTypeAny, {
91
+ memberIds: number[];
92
+ teamId?: number | null | undefined;
93
+ pickupGroupId?: number | null | undefined;
94
+ leagueId?: number | null | undefined;
95
+ seasonId?: number | null | undefined;
96
+ pickupEventId?: number | null | undefined;
97
+ playerRole?: string | null | undefined;
98
+ totalMembers?: number | undefined;
99
+ }, {
100
+ memberIds: number[];
101
+ teamId?: number | null | undefined;
102
+ pickupGroupId?: number | null | undefined;
103
+ leagueId?: number | null | undefined;
104
+ seasonId?: number | null | undefined;
105
+ pickupEventId?: number | null | undefined;
106
+ playerRole?: string | null | undefined;
107
+ totalMembers?: number | undefined;
108
+ }>, {
109
+ memberIds: number[];
110
+ teamId?: number | null | undefined;
111
+ pickupGroupId?: number | null | undefined;
112
+ leagueId?: number | null | undefined;
113
+ seasonId?: number | null | undefined;
114
+ pickupEventId?: number | null | undefined;
115
+ playerRole?: string | null | undefined;
116
+ totalMembers?: number | undefined;
117
+ }, {
118
+ memberIds: number[];
119
+ teamId?: number | null | undefined;
120
+ pickupGroupId?: number | null | undefined;
121
+ leagueId?: number | null | undefined;
122
+ seasonId?: number | null | undefined;
123
+ pickupEventId?: number | null | undefined;
124
+ playerRole?: string | null | undefined;
125
+ totalMembers?: number | undefined;
126
+ }>, "many">;
127
+ }, "strip", z.ZodTypeAny, {
128
+ message: string;
129
+ organizationId: number;
130
+ subject: string;
131
+ senderEmail: string;
132
+ audienceGroups: {
133
+ memberIds: number[];
134
+ teamId?: number | null | undefined;
135
+ pickupGroupId?: number | null | undefined;
136
+ leagueId?: number | null | undefined;
137
+ seasonId?: number | null | undefined;
138
+ pickupEventId?: number | null | undefined;
139
+ playerRole?: string | null | undefined;
140
+ totalMembers?: number | undefined;
141
+ }[];
142
+ delivery: {
143
+ email: boolean;
144
+ push: boolean;
145
+ };
146
+ id?: number | undefined;
147
+ orgWorkspaceId?: number | null | undefined;
148
+ }, {
149
+ message: string;
150
+ organizationId: number;
151
+ subject: string;
152
+ senderEmail: string;
153
+ audienceGroups: {
154
+ memberIds: number[];
155
+ teamId?: number | null | undefined;
156
+ pickupGroupId?: number | null | undefined;
157
+ leagueId?: number | null | undefined;
158
+ seasonId?: number | null | undefined;
159
+ pickupEventId?: number | null | undefined;
160
+ playerRole?: string | null | undefined;
161
+ totalMembers?: number | undefined;
162
+ }[];
163
+ delivery: {
164
+ email: boolean;
165
+ push: boolean;
166
+ };
167
+ id?: number | undefined;
168
+ orgWorkspaceId?: number | null | undefined;
169
+ }>;
170
+ export type SaveBroadcastInput = z.infer<typeof SaveBroadcastInputSchema>;
171
+ export declare const SendBroadcastInputSchema: z.ZodObject<{
172
+ id: z.ZodOptional<z.ZodNumber>;
173
+ organizationId: z.ZodNumber;
174
+ orgWorkspaceId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
175
+ subject: z.ZodString;
176
+ message: z.ZodString;
177
+ delivery: z.ZodObject<{
178
+ email: z.ZodBoolean;
179
+ push: z.ZodBoolean;
180
+ }, "strip", z.ZodTypeAny, {
181
+ email: boolean;
182
+ push: boolean;
183
+ }, {
184
+ email: boolean;
185
+ push: boolean;
186
+ }>;
187
+ senderEmail: z.ZodString;
188
+ } & {
189
+ audienceGroups: z.ZodArray<z.ZodEffects<z.ZodObject<{
190
+ seasonId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
191
+ leagueId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
192
+ teamId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
193
+ pickupGroupId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
194
+ pickupEventId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
195
+ playerRole: z.ZodOptional<z.ZodNullable<z.ZodString>>;
196
+ memberIds: z.ZodArray<z.ZodNumber, "many">;
197
+ totalMembers: z.ZodOptional<z.ZodNumber>;
198
+ }, "strip", z.ZodTypeAny, {
199
+ memberIds: number[];
200
+ teamId?: number | null | undefined;
201
+ pickupGroupId?: number | null | undefined;
202
+ leagueId?: number | null | undefined;
203
+ seasonId?: number | null | undefined;
204
+ pickupEventId?: number | null | undefined;
205
+ playerRole?: string | null | undefined;
206
+ totalMembers?: number | undefined;
207
+ }, {
208
+ memberIds: number[];
209
+ teamId?: number | null | undefined;
210
+ pickupGroupId?: number | null | undefined;
211
+ leagueId?: number | null | undefined;
212
+ seasonId?: number | null | undefined;
213
+ pickupEventId?: number | null | undefined;
214
+ playerRole?: string | null | undefined;
215
+ totalMembers?: number | undefined;
216
+ }>, {
217
+ memberIds: number[];
218
+ teamId?: number | null | undefined;
219
+ pickupGroupId?: number | null | undefined;
220
+ leagueId?: number | null | undefined;
221
+ seasonId?: number | null | undefined;
222
+ pickupEventId?: number | null | undefined;
223
+ playerRole?: string | null | undefined;
224
+ totalMembers?: number | undefined;
225
+ }, {
226
+ memberIds: number[];
227
+ teamId?: number | null | undefined;
228
+ pickupGroupId?: number | null | undefined;
229
+ leagueId?: number | null | undefined;
230
+ seasonId?: number | null | undefined;
231
+ pickupEventId?: number | null | undefined;
232
+ playerRole?: string | null | undefined;
233
+ totalMembers?: number | undefined;
234
+ }>, "many">;
235
+ }, "strip", z.ZodTypeAny, {
236
+ message: string;
237
+ organizationId: number;
238
+ subject: string;
239
+ senderEmail: string;
240
+ audienceGroups: {
241
+ memberIds: number[];
242
+ teamId?: number | null | undefined;
243
+ pickupGroupId?: number | null | undefined;
244
+ leagueId?: number | null | undefined;
245
+ seasonId?: number | null | undefined;
246
+ pickupEventId?: number | null | undefined;
247
+ playerRole?: string | null | undefined;
248
+ totalMembers?: number | undefined;
249
+ }[];
250
+ delivery: {
251
+ email: boolean;
252
+ push: boolean;
253
+ };
254
+ id?: number | undefined;
255
+ orgWorkspaceId?: number | null | undefined;
256
+ }, {
257
+ message: string;
258
+ organizationId: number;
259
+ subject: string;
260
+ senderEmail: string;
261
+ audienceGroups: {
262
+ memberIds: number[];
263
+ teamId?: number | null | undefined;
264
+ pickupGroupId?: number | null | undefined;
265
+ leagueId?: number | null | undefined;
266
+ seasonId?: number | null | undefined;
267
+ pickupEventId?: number | null | undefined;
268
+ playerRole?: string | null | undefined;
269
+ totalMembers?: number | undefined;
270
+ }[];
271
+ delivery: {
272
+ email: boolean;
273
+ push: boolean;
274
+ };
275
+ id?: number | undefined;
276
+ orgWorkspaceId?: number | null | undefined;
277
+ }>;
278
+ export type SendBroadcastInput = z.infer<typeof SendBroadcastInputSchema>;
279
+ export declare const ArchiveBroadcastInputSchema: z.ZodObject<{
280
+ id: z.ZodNumber;
281
+ }, "strip", z.ZodTypeAny, {
282
+ id: number;
283
+ }, {
284
+ id: number;
285
+ }>;
286
+ export type ArchiveBroadcastInput = z.infer<typeof ArchiveBroadcastInputSchema>;
287
+ export declare const DeleteBroadcastInputSchema: z.ZodObject<{
288
+ id: z.ZodNumber;
289
+ }, "strip", z.ZodTypeAny, {
290
+ id: number;
291
+ }, {
292
+ id: number;
293
+ }>;
294
+ export type DeleteBroadcastInput = z.infer<typeof DeleteBroadcastInputSchema>;
295
+ export declare const DownloadBroadcastAudienceCsvInputSchema: z.ZodObject<{
296
+ id: z.ZodNumber;
297
+ }, "strip", z.ZodTypeAny, {
298
+ id: number;
299
+ }, {
300
+ id: number;
301
+ }>;
302
+ export type DownloadBroadcastAudienceCsvInput = z.infer<typeof DownloadBroadcastAudienceCsvInputSchema>;
@@ -0,0 +1,219 @@
1
+ import type { Queue } from 'bullmq';
2
+ import { Member } from '../../models/member';
3
+ import { Broadcast } from '../../models/broadcast';
4
+ import { BroadcastAudienceGroup } from '../../models/broadcast_audience_group';
5
+ import { BroadcastAudienceMember } from '../../models/broadcast_audience_member';
6
+ import { ArchiveBroadcastInput, DeleteBroadcastInput, DownloadBroadcastAudienceCsvInput, GetAudienceInput, GetBroadcastByIdInput, GetBroadcastDeliveryStatusesInput, GetBroadcastsInput, SaveBroadcastInput, SendBroadcastInput } from './broadcast.schema';
7
+ import { Organizer } from '../../models/organizer';
8
+ import type { BroadcastDeliveryStatus } from '../../models/broadcast_delivery';
9
+ /**
10
+ * `earlier_version` means a delivery exists, but of a message that has since been
11
+ * edited — so a resend correctly targets them again. `sending` distinguishes "no
12
+ * ledger row yet" on a broadcast still in flight from one that has finished.
13
+ */
14
+ export type BroadcastDeliverySummary = 'sent' | 'partial' | 'unknown' | 'failed' | 'earlier_version' | 'sending' | 'not_sent';
15
+ export type BroadcastMemberDeliveryStatus = {
16
+ memberId: number;
17
+ /** Outcome per channel for the content currently saved on the broadcast. */
18
+ email: BroadcastDeliveryStatus | null;
19
+ push: BroadcastDeliveryStatus | null;
20
+ notification: BroadcastDeliveryStatus | null;
21
+ summary: BroadcastDeliverySummary;
22
+ lastError: string | null;
23
+ deliveredAt: Date | null;
24
+ /** Highest attempt count across this member's channels — i.e. was this retried. */
25
+ attemptCount: number;
26
+ receivedEarlierVersion: boolean;
27
+ };
28
+ export declare class BroadcastService {
29
+ private readonly MemberModel;
30
+ private readonly BroadcastModel;
31
+ private readonly BroadcastAudienceGroupModel;
32
+ private readonly BroadcastAudienceMemberModel;
33
+ private readonly OrganizerModel;
34
+ constructor(MemberModel: typeof Member, BroadcastModel: typeof Broadcast, BroadcastAudienceGroupModel: typeof BroadcastAudienceGroup, BroadcastAudienceMemberModel: typeof BroadcastAudienceMember, OrganizerModel: typeof Organizer);
35
+ private assertOrganizationAccess;
36
+ private getBroadcastForOrganization;
37
+ private markBroadcastAsSending;
38
+ private normalizeFailureReason;
39
+ /**
40
+ * `note` is appended AFTER `normalizeFailureReason` truncates, so a long provider
41
+ * error cannot push it out of the message. The column is TEXT, so the combined
42
+ * length is not a concern. Used to warn that a resend may duplicate.
43
+ */
44
+ private markBroadcastAsFailed;
45
+ /**
46
+ * Public safety net for the queue worker's `failed` handler. If a job dies or
47
+ * stalls before `processQueuedBroadcast` runs its own catch block (crash, OOM,
48
+ * lost lock), the broadcast would otherwise be stranded in SENDING forever.
49
+ * This resets it to FAILED so it can be resent. Idempotent: the underlying
50
+ * patch only matches rows still in SENDING, so a reason set by
51
+ * `processQueuedBroadcast`'s own catch is preserved.
52
+ */
53
+ failQueuedBroadcast(organizationId: number, broadcastId: number, reason?: string | null): Promise<void>;
54
+ private assertOrganizationExists;
55
+ private insertInChunks;
56
+ /**
57
+ * Retries a ledger write a few times before giving up.
58
+ *
59
+ * A dropped ledger row is not a cosmetic problem: `getDeliveredMemberIdsByChannel`
60
+ * treats "no row" as "not delivered", so a lost row means a resend mails that
61
+ * person again. A transient connection blip is worth a second attempt.
62
+ */
63
+ private withLedgerWriteRetry;
64
+ /**
65
+ * Members who already received `contentHash` on each channel.
66
+ *
67
+ * Scoped to `status = 'sent'`, so `unknown` (timed-out, possibly delivered) and
68
+ * `failed` recipients are re-targeted by construction: for game-day comms a
69
+ * missed notice is worse than a duplicate, and the ambiguous count is reported
70
+ * back to the organizer instead of being silently resolved either way.
71
+ */
72
+ private getDeliveredMemberIdsByChannel;
73
+ /**
74
+ * Records what was handed to a delivery channel, one autocommit statement per
75
+ * chunk, immediately after that batch is acknowledged.
76
+ *
77
+ * DELIBERATELY NOT IN A TRANSACTION (the `notification` channel excepted, which
78
+ * passes its `trx`). This is the entire point of the ledger: if checkpoints were
79
+ * written inside a transaction spanning the send, a crash mid-delivery would roll
80
+ * them all back, and the resend would duplicate everything — which is the bug
81
+ * this exists to fix. Order is send-then-record, so a crash in that gap re-sends
82
+ * one batch (at-least-once). Recording intent first would be at-most-once, i.e.
83
+ * silent drops.
84
+ */
85
+ private recordDeliveries;
86
+ /**
87
+ * Recipients whose delivery outcome is genuinely unknown — a provider request
88
+ * timed out without being aborted, so it may or may not have been delivered.
89
+ * Surfaced in `failure_reason` so the organizer knows a resend can duplicate.
90
+ */
91
+ private countAmbiguousDeliveries;
92
+ private enqueueBroadcastSend;
93
+ /**
94
+ * Boot-time recovery for broadcasts stranded in SENDING. The worker's `failed`
95
+ * handler only fires for jobs that actually fail, so a row whose job never ran
96
+ * (Redis flushed, job ID collision, add rejected) or whose process died before
97
+ * that handler executed stays SENDING forever — it cannot be edited, resent, or
98
+ * completed. Rows younger than `staleAfterMs` are left alone so a legitimately
99
+ * slow send is never interrupted, and every patch is scoped to `status =
100
+ * 'SENDING'`, so concurrent API replicas running this cannot clobber a send that
101
+ * completed in the meantime.
102
+ */
103
+ reconcileStuckBroadcasts(queue: Pick<Queue, 'getJob'>, staleAfterMs?: number): Promise<{
104
+ checked: number;
105
+ reset: number;
106
+ }>;
107
+ private assertWorkspaceAccess;
108
+ private normalizeAudienceGroups;
109
+ private applyBroadcastFilters;
110
+ private validateAudienceGroups;
111
+ private escapeCsvValue;
112
+ private buildCsvRow;
113
+ private stripHtmlForPushNotification;
114
+ downloadBroadcastAudienceCsv(organizationId: number, { id }: DownloadBroadcastAudienceCsvInput): Promise<string | null>;
115
+ getBroadcastById(organizationId: number, { id }: GetBroadcastByIdInput): Promise<Broadcast | null>;
116
+ /**
117
+ * Per-recipient delivery state for the Recipients table, read straight off the
118
+ * ledger. Answers the question a `FAILED` broadcast otherwise leaves open: who
119
+ * actually received this, and who would a resend re-target?
120
+ *
121
+ * Rows are grouped per member rather than per channel because that is how the
122
+ * table displays them; the per-channel statuses stay on the payload so the UI can
123
+ * show the breakdown without a second request.
124
+ */
125
+ getBroadcastDeliveryStatuses(organizationId: number, { broadcastId }: GetBroadcastDeliveryStatusesInput): Promise<{
126
+ contentHash: string;
127
+ members: BroadcastMemberDeliveryStatus[];
128
+ } | null>;
129
+ /**
130
+ * Collapses a member's per-channel statuses into the single label the table shows.
131
+ *
132
+ * Derived from the rows that exist, deliberately not from the broadcast's channel
133
+ * toggles: a member with push enabled but no registered device, or who muted
134
+ * broadcasts, is never handed to FCM and has no `push` row. Treating that as an
135
+ * incomplete delivery would label ordinary opt-outs as a problem.
136
+ */
137
+ private summarizeMemberDelivery;
138
+ deleteBroadcast(organizationId: number, { id }: DeleteBroadcastInput): Promise<{
139
+ success: boolean;
140
+ id: number;
141
+ } | null>;
142
+ getAudience(organizationId: number, payload: GetAudienceInput): Promise<Member[]>;
143
+ saveBroadcast(creatorId: number, organizationId: number, input: SaveBroadcastInput): Promise<any>;
144
+ getBroadcasts(organizationId: number, payload: GetBroadcastsInput): Promise<{
145
+ items: {
146
+ audienceGroups: {
147
+ season: any;
148
+ league: any;
149
+ team: any;
150
+ pickupGroup: any;
151
+ pickupEvent: any;
152
+ id: number;
153
+ broadcastId: number;
154
+ seasonId: number;
155
+ leagueId: number | null;
156
+ teamId: number | null;
157
+ pickupGroupId: number | null;
158
+ pickupEventId: number | null;
159
+ playerRole: string | null;
160
+ totalMembers: number;
161
+ members?: Partial<Member>[];
162
+ audienceMembers?: BroadcastAudienceMember[];
163
+ createdAt: Date;
164
+ updatedAt: Date;
165
+ $modelClass: import("objection").ModelClass<BroadcastAudienceGroup>;
166
+ QueryBuilderType: import("objection").QueryBuilder<BroadcastAudienceGroup, BroadcastAudienceGroup[]>;
167
+ }[];
168
+ id: number;
169
+ organizationId: number;
170
+ orgWorkspaceId: number | null;
171
+ seasonId: number;
172
+ leagueId: number | null;
173
+ creatorId: number;
174
+ subject: string;
175
+ message: string;
176
+ emailNotification: boolean;
177
+ pushNotification: boolean;
178
+ senderEmail: string;
179
+ status: string;
180
+ failureReason: string | null;
181
+ isArchived: boolean;
182
+ sentAt: Date | null;
183
+ createdAt: Date;
184
+ updatedAt: Date;
185
+ deletedAt: Date | null;
186
+ $modelClass: import("objection").ModelClass<Broadcast>;
187
+ QueryBuilderType: import("objection").QueryBuilder<Broadcast, Broadcast[]>;
188
+ }[];
189
+ total: number;
190
+ limit: number;
191
+ offset: number;
192
+ }>;
193
+ toggleArchiveBroadcast(organizationId: number, { id }: ArchiveBroadcastInput): Promise<Broadcast | null>;
194
+ sendBroadcast(creatorId: number, organizationId: number, input: SendBroadcastInput): Promise<{
195
+ broadcast: Broadcast;
196
+ queued: boolean;
197
+ sentEmails: number;
198
+ sentPushNotifications: number;
199
+ createdNotifications: number;
200
+ } | null>;
201
+ processQueuedBroadcast(creatorId: number, organizationId: number, broadcastId: number): Promise<{
202
+ broadcast: Broadcast;
203
+ /** Addresses handed to Mailgun — see `recordedEmailDeliveries` for delivered. */
204
+ sentEmails: number;
205
+ /** Tokens handed to FCM — see `recordedPushDeliveries` for delivered. */
206
+ sentPushNotifications: number;
207
+ createdNotifications: number;
208
+ recordedEmailDeliveries: number;
209
+ ambiguousEmailDeliveries: number;
210
+ recordedPushDeliveries: number;
211
+ ambiguousPushDeliveries: number;
212
+ skippedAlreadyDelivered: number;
213
+ /**
214
+ * Reached, but missing from the ledger, so a resend cannot skip them.
215
+ * Non-zero means the ledger under-reports what was delivered.
216
+ */
217
+ unrecordedDeliveries: number;
218
+ } | null>;
219
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Fingerprints the content a recipient actually received, so the delivery ledger
3
+ * can tell "already got this message" apart from "already got an earlier draft".
4
+ *
5
+ * A FAILED broadcast is fully editable: the organizer can reword the subject or
6
+ * body before hitting Resend. Skipping every previously-delivered recipient would
7
+ * mean the reworded version silently never reaches them. Keying the ledger on
8
+ * this hash instead makes an edited resend re-target the whole audience, while an
9
+ * unchanged resend targets only the recipients who were never reached.
10
+ *
11
+ * The tuple is JSON-encoded before hashing so that a subject/message split cannot
12
+ * be shifted without changing the digest — ('ab', 'c') and ('a', 'bc') hash
13
+ * differently. Channel toggles, sender, and audience are deliberately excluded:
14
+ * enabling push after an email-only send then finds no `push` rows and correctly
15
+ * targets everyone.
16
+ */
17
+ export declare const buildBroadcastContentHash: (subject?: string | null, message?: string | null) => string;
@@ -4,7 +4,7 @@ type PrismaClientLike = typeof prisma;
4
4
  type DbClient = any;
5
5
  type CreateContextChatInput = {
6
6
  actorId: number;
7
- chatType: typeof CHAT_TYPES.TEAM | typeof CHAT_TYPES.MATCH | typeof CHAT_TYPES.PICKUP;
7
+ chatType: typeof CHAT_TYPES.TEAM | typeof CHAT_TYPES.MATCH | typeof CHAT_TYPES.PICKUP_GROUP | typeof CHAT_TYPES.PICKUP;
8
8
  contextId: number;
9
9
  ownerId?: number | null;
10
10
  name?: string | null;
@@ -23,6 +23,22 @@ type CreatePollInput = {
23
23
  allowMultiple: boolean;
24
24
  options: string[];
25
25
  };
26
+ type CreateScoutInviteMessageInput = {
27
+ chatId: number;
28
+ senderId: number;
29
+ content: string;
30
+ inviteId: number;
31
+ targetType: 'team' | 'pickup';
32
+ targetId: number;
33
+ targetName: string;
34
+ targetImage?: string | null;
35
+ inviteeMemberId: number;
36
+ notification: {
37
+ text: string;
38
+ textMeta: string;
39
+ metaData: Record<string, unknown>;
40
+ };
41
+ };
26
42
  type ReactionInput = {
27
43
  chatId: number;
28
44
  messageId: string;
@@ -50,8 +66,14 @@ export declare class ChatRepository {
50
66
  createMessage(input: CreateMessageInput): Promise<any>;
51
67
  getChatMessageWithDetails(chatId: number, messageId: string, db?: DbClient): Promise<any>;
52
68
  createPoll(input: CreatePollInput): Promise<any>;
69
+ createScoutInviteMessage(input: CreateScoutInviteMessageInput): Promise<any>;
53
70
  getPollInChat(chatId: number, pollId: number): Promise<any>;
54
71
  getPollChatMessage(chatId: number, pollId: number, db?: DbClient): Promise<any>;
72
+ getPendingScoutInviteForParticipants(targetType: 'team' | 'pickup', targetId: number, inviterMemberId: number, inviteeMemberId: number): Promise<any>;
73
+ getScoutInviteByInviteId(inviteId: number): Promise<any>;
74
+ getScoutInviteByMessageId(messageId: string): Promise<any>;
75
+ listScoutInvites(memberId: number, status?: string): Promise<any>;
76
+ updateScoutInviteStatus(inviteId: number, status: string): Promise<any>;
55
77
  votePoll(chatId: number, pollId: number, memberId: number, optionIds: number[]): Promise<any>;
56
78
  sendReaction(input: ReactionInput): Promise<any>;
57
79
  removeReaction(chatId: number, messageId: string, memberId: number): Promise<{
@@ -85,12 +107,54 @@ export declare class ChatRepository {
85
107
  getSharedTeamMemberIds(memberId: number, targetMemberIds: number[]): Promise<unknown[]>;
86
108
  getTeamContext(teamId: number): Promise<any>;
87
109
  getMatchContext(eventId: number): Promise<any>;
110
+ getNextTeamRsvpEvent(teamId: number, memberId: number): Promise<{
111
+ nextEvent: null;
112
+ hasRsvp: boolean;
113
+ rsvpStatus: string;
114
+ } | {
115
+ nextEvent: {
116
+ id: any;
117
+ title: any;
118
+ dateAndTime: any;
119
+ addressName: any;
120
+ location: any;
121
+ teamId: any;
122
+ timezone: any;
123
+ };
124
+ hasRsvp: boolean;
125
+ rsvpStatus: any;
126
+ }>;
127
+ getRsvpEvent(eventId: number, memberId: number): Promise<{
128
+ nextEvent: null;
129
+ hasRsvp: boolean;
130
+ rsvpStatus: string;
131
+ } | {
132
+ nextEvent: {
133
+ id: any;
134
+ title: any;
135
+ dateAndTime: any;
136
+ addressName: any;
137
+ location: any;
138
+ teamId: any;
139
+ timezone: any;
140
+ };
141
+ hasRsvp: boolean;
142
+ rsvpStatus: any;
143
+ }>;
88
144
  getPickupContext(pickupId: number): Promise<any>;
145
+ getPickupGroupContext(pickupGroupId: number): Promise<any>;
89
146
  getPickupMemberIds(pickupId: number): Promise<any>;
147
+ getPickupGroupMemberIds(pickupGroupId: number): Promise<any>;
90
148
  getActivePickupsForMember(memberId: number): Promise<any>;
149
+ getActivePickupGroupsForMember(memberId: number): Promise<any>;
150
+ private addContextMetadata;
91
151
  private chatMemberInclude;
92
152
  private messageInclude;
93
153
  private legacyChatType;
154
+ private emptyRsvpEventResponse;
155
+ private rsvpEventResponse;
156
+ private mapRsvpEvent;
157
+ private rsvpEventSelect;
94
158
  private sortMemberPair;
95
159
  private uniqueMemberIds;
96
160
  }
@@ -4,6 +4,7 @@ export declare const CHAT_TYPES: {
4
4
  readonly PRIVATE_GROUP: "private_group";
5
5
  readonly TEAM: "team";
6
6
  readonly MATCH: "match";
7
+ readonly PICKUP_GROUP: "pickup_group";
7
8
  readonly PICKUP: "pickup";
8
9
  };
9
10
  export declare const CHAT_MEMBER_ROLES: {
@@ -16,7 +17,12 @@ export declare const CHAT_MEMBER_STATUSES: {
16
17
  readonly REMOVED: "removed";
17
18
  readonly LEFT: "left";
18
19
  };
19
- export declare const chatTypeSchema: z.ZodEnum<["direct", "private_group", "team", "match", "pickup"]>;
20
+ export declare const CHAT_MESSAGE_TYPES: {
21
+ readonly TEXT: "text";
22
+ readonly POLL: "poll";
23
+ readonly INVITE: "invite";
24
+ };
25
+ export declare const chatTypeSchema: z.ZodEnum<["direct", "private_group", "team", "match", "pickup_group", "pickup"]>;
20
26
  export declare const chatMemberRoleSchema: z.ZodEnum<["owner", "admin", "member"]>;
21
27
  export declare const listChatsInputSchema: z.ZodObject<{
22
28
  limit: z.ZodDefault<z.ZodNumber>;