@whitewall/blip-sdk 0.0.179 → 0.0.181

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 (57) hide show
  1. package/dist/cjs/index.js +1 -0
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/namespaces/desk.js +64 -1
  4. package/dist/cjs/namespaces/desk.js.map +1 -1
  5. package/dist/cjs/sender/enveloperesolver.js +2 -2
  6. package/dist/cjs/sender/enveloperesolver.js.map +1 -1
  7. package/dist/cjs/sender/sender.js +6 -0
  8. package/dist/cjs/sender/sender.js.map +1 -1
  9. package/dist/cjs/sender/sessionnegotiator.js +15 -7
  10. package/dist/cjs/sender/sessionnegotiator.js.map +1 -1
  11. package/dist/cjs/sender/tcp/tcpsender.js +47 -31
  12. package/dist/cjs/sender/tcp/tcpsender.js.map +1 -1
  13. package/dist/cjs/sender/websocket/websocketsender.js +40 -12
  14. package/dist/cjs/sender/websocket/websocketsender.js.map +1 -1
  15. package/dist/cjs/utils/builder.js +121 -0
  16. package/dist/cjs/utils/builder.js.map +1 -0
  17. package/dist/esm/index.js +1 -0
  18. package/dist/esm/index.js.map +1 -1
  19. package/dist/esm/namespaces/desk.js +64 -1
  20. package/dist/esm/namespaces/desk.js.map +1 -1
  21. package/dist/esm/sender/enveloperesolver.js +2 -2
  22. package/dist/esm/sender/enveloperesolver.js.map +1 -1
  23. package/dist/esm/sender/sender.js +6 -0
  24. package/dist/esm/sender/sender.js.map +1 -1
  25. package/dist/esm/sender/sessionnegotiator.js +15 -7
  26. package/dist/esm/sender/sessionnegotiator.js.map +1 -1
  27. package/dist/esm/sender/tcp/tcpsender.js +47 -31
  28. package/dist/esm/sender/tcp/tcpsender.js.map +1 -1
  29. package/dist/esm/sender/websocket/websocketsender.js +40 -12
  30. package/dist/esm/sender/websocket/websocketsender.js.map +1 -1
  31. package/dist/esm/utils/builder.js +115 -0
  32. package/dist/esm/utils/builder.js.map +1 -0
  33. package/dist/types/index.d.ts +1 -0
  34. package/dist/types/index.d.ts.map +1 -1
  35. package/dist/types/namespaces/desk.d.ts +73 -1
  36. package/dist/types/namespaces/desk.d.ts.map +1 -1
  37. package/dist/types/sender/enveloperesolver.d.ts +1 -1
  38. package/dist/types/sender/enveloperesolver.d.ts.map +1 -1
  39. package/dist/types/sender/sender.d.ts +1 -0
  40. package/dist/types/sender/sender.d.ts.map +1 -1
  41. package/dist/types/sender/sessionnegotiator.d.ts +2 -0
  42. package/dist/types/sender/sessionnegotiator.d.ts.map +1 -1
  43. package/dist/types/sender/tcp/tcpsender.d.ts.map +1 -1
  44. package/dist/types/types/desk.d.ts +18 -0
  45. package/dist/types/types/desk.d.ts.map +1 -1
  46. package/dist/types/utils/builder.d.ts +54 -0
  47. package/dist/types/utils/builder.d.ts.map +1 -0
  48. package/package.json +1 -1
  49. package/src/index.ts +1 -0
  50. package/src/namespaces/desk.ts +145 -1
  51. package/src/sender/enveloperesolver.ts +2 -2
  52. package/src/sender/sender.ts +7 -0
  53. package/src/sender/sessionnegotiator.ts +16 -7
  54. package/src/sender/tcp/tcpsender.ts +51 -33
  55. package/src/sender/websocket/websocketsender.ts +40 -14
  56. package/src/types/desk.ts +19 -0
  57. package/src/utils/builder.ts +165 -0
@@ -1 +1 @@
1
- {"version":3,"file":"tcpsender.d.ts","sourceRoot":"","sources":["../../../../src/sender/tcp/tcpsender.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACR,OAAO,EACP,cAAc,EAGd,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACzB,MAAM,sBAAsB,CAAA;AAI7B,OAAO,EAAoB,KAAK,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAMvG;;;;;GAKG;AACH,qBAAa,SAAU,SAAQ,oBAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;IACpD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;gBAE1C,OAAO,EAAE,qBAAqB,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC;IAoC7D,gBAAgB,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3D,WAAW,CAAC,IAAI,SAAS,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IASnF,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BzD,mBAAmB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpE,KAAK;IAMlB,OAAc,KAAK;;;MAAoC;YAEzC,eAAe;CAahC"}
1
+ {"version":3,"file":"tcpsender.d.ts","sourceRoot":"","sources":["../../../../src/sender/tcp/tcpsender.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACR,OAAO,EACP,cAAc,EAGd,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACzB,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAoB,KAAK,2BAA2B,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAMvG;;;;;GAKG;AACH,qBAAa,SAAU,SAAQ,oBAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;IACpD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;gBAE1C,OAAO,EAAE,qBAAqB,CAAC,2BAA2B,CAAC,CAAC,CAAC,CAAC;IAmC7D,gBAAgB,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3D,WAAW,CAAC,IAAI,SAAS,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IASnF,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BzD,mBAAmB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpE,KAAK;IAMlB,OAAc,KAAK;;;MAAoC;YAEzC,eAAe;CAahC"}
@@ -79,6 +79,24 @@ export type DeskRule = {
79
79
  storageDate?: string;
80
80
  queueId?: string;
81
81
  };
82
+ /**
83
+ * Filters accepted by every `/analytics/reports/*` endpoint. The backend
84
+ * applies all filters with AND semantics; arrays inside a single filter are
85
+ * OR'd together.
86
+ */
87
+ export type ReportFilters = {
88
+ beginDate: string | Date;
89
+ endDate: string | Date;
90
+ teams?: Array<string>;
91
+ tags?: Array<string>;
92
+ agentIdentities?: Array<Identity>;
93
+ customerIdentities?: Array<Identity>;
94
+ domains?: Array<string>;
95
+ /** Include SLA applied/achieved counts on agent rows. */
96
+ calculateSla?: boolean;
97
+ /** Force a fresh aggregation on `/tags`, bypassing the server cache. */
98
+ refreshCache?: boolean;
99
+ };
82
100
  export type DeskPriorityRule = {
83
101
  id?: string;
84
102
  ownerIdentity?: Identity;
@@ -1 +1 @@
1
- {"version":3,"file":"desk.d.ts","sourceRoot":"","sources":["../../../src/types/desk.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"desk.d.ts","sourceRoot":"","sources":["../../../src/types/desk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import type { Action, ContentActionItem, State } from '../types/flow.ts';
2
+ export type MinifiedAction = {
3
+ type: string;
4
+ settings: Record<string, unknown>;
5
+ conditions?: Array<{
6
+ source: string;
7
+ variable?: string;
8
+ comparison: string;
9
+ operator?: string;
10
+ values: Array<string>;
11
+ }>;
12
+ };
13
+ export type MinifiedInput = {
14
+ bypass: boolean;
15
+ variable?: string;
16
+ validation?: {
17
+ rule: string;
18
+ regex?: string;
19
+ type?: string;
20
+ error: string;
21
+ };
22
+ expiration?: string;
23
+ conditions?: MinifiedAction['conditions'];
24
+ };
25
+ export type MinifiedOutput = {
26
+ stateId: string;
27
+ stateName?: string;
28
+ typeOfStateId?: string;
29
+ conditions?: MinifiedAction['conditions'];
30
+ };
31
+ export type MinifiedState = {
32
+ id: string;
33
+ name: string;
34
+ root?: boolean;
35
+ enteringActions?: Array<MinifiedAction>;
36
+ contentActions?: Array<{
37
+ action?: MinifiedAction;
38
+ input?: MinifiedInput;
39
+ }>;
40
+ leavingActions?: Array<MinifiedAction>;
41
+ outputs?: Array<MinifiedOutput>;
42
+ defaultOutput: {
43
+ stateId: string;
44
+ stateName?: string;
45
+ typeOfStateId?: string;
46
+ };
47
+ afterStateChangedActions?: Array<MinifiedAction>;
48
+ localActions?: Array<MinifiedAction>;
49
+ };
50
+ export declare function minifyAction(action: Action): MinifiedAction;
51
+ export declare function isChatStateSendMessage(item: ContentActionItem): boolean;
52
+ export declare function resolveStateName(stateId: string, flow: Record<string, State>): string | undefined;
53
+ export declare function minifyState(stateId: string, state: State, flow: Record<string, State>): MinifiedState;
54
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/utils/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAExE,MAAM,MAAM,cAAc,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,UAAU,CAAC,EAAE,KAAK,CAAC;QACf,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,UAAU,EAAE,MAAM,CAAA;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;KACxB,CAAC,CAAA;CACL,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IACxB,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,cAAc,CAAC,YAAY,CAAC,CAAA;CAC5C,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,cAAc,CAAC,YAAY,CAAC,CAAA;CAC5C,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,eAAe,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IACvC,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,CAAC,EAAE,cAAc,CAAC;QAAC,KAAK,CAAC,EAAE,aAAa,CAAA;KAAE,CAAC,CAAA;IAC1E,cAAc,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IACtC,OAAO,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IAC/B,aAAa,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9E,wBAAwB,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IAChD,YAAY,CAAC,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;CACvC,CAAA;AA4BD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAQ3D;AAoBD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAEvE;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,GAAG,SAAS,CAGjG;AAkBD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,aAAa,CA2CrG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whitewall/blip-sdk",
3
- "version": "0.0.179",
3
+ "version": "0.0.181",
4
4
  "description": "Blip API wrapper",
5
5
  "exports": {
6
6
  "types": "./dist/types/index.d.ts",
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ export * from './namespaces/namespace.ts'
3
3
  export * from './schemas/index.ts'
4
4
  export * from './sender/index.ts'
5
5
  export * from './types/index.ts'
6
+ export * from './utils/builder.ts'
6
7
  export * from './utils/desk.ts'
7
8
  export * from './utils/odata.ts'
8
9
  export * from './utils/thread.ts'
@@ -8,6 +8,7 @@ import {
8
8
  type DetailedAttendanceHour,
9
9
  type Identity,
10
10
  Node,
11
+ type ReportFilters,
11
12
  type ThreadItem,
12
13
  type Ticket,
13
14
  type TicketStatus,
@@ -522,8 +523,10 @@ export class DeskNamespace extends Namespace {
522
523
  }}`,
523
524
  },
524
525
  {
525
- collection: true,
526
+ // The server caps $take at 500; use it to minimize round trips when paginating
527
+ take: Math.min(opts?.max ?? 500, 500),
526
528
  ...opts,
529
+ collection: true,
527
530
  },
528
531
  )
529
532
  }
@@ -823,6 +826,147 @@ export class DeskNamespace extends Namespace {
823
826
  )
824
827
  }
825
828
 
829
+ /**
830
+ * Shared filters for the `/analytics/reports/*` endpoints. All reports
831
+ * are SQL-backed pre-aggregations over closed/historical tickets, so
832
+ * they are the cheapest way to answer "group X by Y" questions over a
833
+ * date range without paginating ticket lists.
834
+ */
835
+ private buildReportQuery(filters: ReportFilters): Record<string, unknown> {
836
+ return {
837
+ beginDate: filters.beginDate,
838
+ endDate: filters.endDate,
839
+ teams: filters.teams?.join(','),
840
+ tags: filters.tags?.join(','),
841
+ agentIdentities: filters.agentIdentities?.join(','),
842
+ customerIdentities: filters.customerIdentities?.join(','),
843
+ domains: filters.domains?.join(','),
844
+ calculateSla: filters.calculateSla,
845
+ refreshCache: filters.refreshCache,
846
+ }
847
+ }
848
+
849
+ /**
850
+ * Returns one row per tag found in tickets closed within the date range,
851
+ * with the number of tickets and average timings. Cached by the backend.
852
+ */
853
+ public async getTagsReport(
854
+ filters: ReportFilters,
855
+ opts?: ConsumeOptions,
856
+ ): Promise<
857
+ Array<{
858
+ name: string
859
+ closedTickets: number
860
+ ticketsCount: number
861
+ /** Format: `hh:mm:ss[.fffffff]` from .NET TimeSpan. */
862
+ averageFirstResponseTime?: string
863
+ averageWaitTime?: string
864
+ averageAttendanceTime?: string
865
+ averageResponseTime?: string
866
+ }>
867
+ > {
868
+ return await this.sendCommand(
869
+ {
870
+ method: 'get',
871
+ uri: uri`/analytics/reports/tags?${this.buildReportQuery(filters)}`,
872
+ },
873
+ { collection: true, ...opts },
874
+ )
875
+ }
876
+
877
+ /**
878
+ * Returns one row per team for tickets in the date range, with closed
879
+ * counts and average timings.
880
+ */
881
+ public async getTeamsReport(
882
+ filters: ReportFilters,
883
+ opts?: ConsumeOptions,
884
+ ): Promise<
885
+ Array<{
886
+ name: string
887
+ closedTickets: number
888
+ ticketsCount: number
889
+ waitingTickets: number
890
+ openedTickets: number
891
+ averageFirstResponseTime?: string
892
+ averageWaitTime?: string
893
+ averageAttendanceTime?: string
894
+ averageResponseTime?: string
895
+ }>
896
+ > {
897
+ return await this.sendCommand(
898
+ {
899
+ method: 'get',
900
+ uri: uri`/analytics/reports/teams?${this.buildReportQuery(filters)}`,
901
+ },
902
+ { collection: true, ...opts },
903
+ )
904
+ }
905
+
906
+ /**
907
+ * Returns one row per agent (identified by `identity`) for tickets in the
908
+ * date range, with closed counts, average timings and optional SLA counts
909
+ * when `calculateSla` is true.
910
+ */
911
+ public async getAttendantsReport(
912
+ filters: ReportFilters,
913
+ opts?: ConsumeOptions,
914
+ ): Promise<
915
+ Array<{
916
+ identity: Identity
917
+ agentName?: string
918
+ status?: 'Offline' | 'Pause' | 'Online' | 'Invisible'
919
+ isEnabled?: boolean
920
+ closedTickets: number
921
+ ticketsCount: number
922
+ openedTickets?: number
923
+ slaAppliedTicketCount?: number
924
+ slaAchievedTicketCount?: number
925
+ averageFirstResponseTime?: string
926
+ averageWaitTime?: string
927
+ averageAttendanceTime?: string
928
+ averageResponseTime?: string
929
+ }>
930
+ > {
931
+ return await this.sendCommand(
932
+ {
933
+ method: 'get',
934
+ uri: uri`/analytics/reports/attendants?${this.buildReportQuery(filters)}`,
935
+ },
936
+ { collection: true, ...opts },
937
+ )
938
+ }
939
+
940
+ /**
941
+ * Returns one row per day in the date range with ticket status counts
942
+ * (open, closed, waiting, transferred, missed, …). Suitable for daily
943
+ * time-series charts.
944
+ */
945
+ public async getTicketsReport(
946
+ filters: ReportFilters,
947
+ opts?: ConsumeOptions,
948
+ ): Promise<
949
+ Array<{
950
+ date: string
951
+ open: number
952
+ waiting: number
953
+ closed: number
954
+ closedAttendant: number
955
+ closedClient: number
956
+ transferred: number
957
+ missed: number
958
+ inAttendance: number
959
+ }>
960
+ > {
961
+ return await this.sendCommand(
962
+ {
963
+ method: 'get',
964
+ uri: uri`/analytics/reports/tickets?${this.buildReportQuery(filters)}`,
965
+ },
966
+ { collection: true, ...opts },
967
+ )
968
+ }
969
+
826
970
  public async getTags(team?: string, opts?: ConsumeOptions): Promise<Array<string>> {
827
971
  if (team && team !== 'DIRECT_TRANSFER') {
828
972
  const result = await this.sendCommand<'get', Array<{ tag: string }>>(
@@ -164,9 +164,9 @@ export class EnvelopeResolver {
164
164
  }
165
165
  }
166
166
 
167
- public rejectPendingEnvelopes(reason: string) {
167
+ public rejectPendingEnvelopes(error: Error) {
168
168
  for (const id in this.waitingEnvelopeResponseResolvers) {
169
- this.resolveEnvelopeResponse(id, new RetryableError(reason))
169
+ this.resolveEnvelopeResponse(id, error)
170
170
  }
171
171
  }
172
172
 
@@ -12,6 +12,7 @@ import {
12
12
  } from '../types/index.ts'
13
13
  import type { Closable } from './closable.ts'
14
14
  import { EnvelopeResolver, type EventMap, type Listener } from './enveloperesolver.ts'
15
+ import { RetryableError } from './retryableerror.ts'
15
16
  import type { Authentication } from './security.ts'
16
17
  import type { SessionNegotiator } from './sessionnegotiator.ts'
17
18
 
@@ -149,4 +150,10 @@ export abstract class OpenConnectionSender extends ConnectionSender implements S
149
150
  this.envelopeResolver.close()
150
151
  return Promise.resolve()
151
152
  }
153
+
154
+ protected rejectPending(reason: string) {
155
+ const error = new RetryableError(reason)
156
+ this.sessionNegotiator?.fail(error)
157
+ this.envelopeResolver.rejectPendingEnvelopes(error)
158
+ }
152
159
  }
@@ -17,6 +17,7 @@ export class SessionNegotiator {
17
17
 
18
18
  private presencePromise: Promise<void> | null = null
19
19
  private currentSessionResolver: Pick<PromiseWithResolvers<Session>, 'reject' | 'resolve'> | null = null
20
+ private failure: Error | null = null
20
21
 
21
22
  constructor(
22
23
  private readonly sender: OpenConnectionSender,
@@ -28,11 +29,8 @@ export class SessionNegotiator {
28
29
  authentication: Authentication
29
30
  upgradeToTls?: () => Promise<void>
30
31
  }): Promise<void> {
31
- const timeout = setTimeout(async () => {
32
- if (this.negotiating) {
33
- await this.sender.close()
34
- throw new Error('Negotiation timeout')
35
- }
32
+ const timeout = setTimeout(() => {
33
+ this.fail(new Error('Negotiation timeout'))
36
34
  }, 60000) // 60 seconds
37
35
 
38
36
  try {
@@ -116,6 +114,14 @@ export class SessionNegotiator {
116
114
  }
117
115
  }
118
116
 
117
+ public fail(error: Error) {
118
+ this.failure = error
119
+ if (this.currentSessionResolver) {
120
+ this.currentSessionResolver.reject(error)
121
+ this.currentSessionResolver = null
122
+ }
123
+ }
124
+
119
125
  public async ensurePresence(currentCommandUri = ''): Promise<void> {
120
126
  if (!this.session) {
121
127
  throw new Error('Session not established')
@@ -159,11 +165,11 @@ export class SessionNegotiator {
159
165
 
160
166
  public finish() {
161
167
  if (!this.session) {
162
- throw new Error('Session not established')
168
+ return
163
169
  }
164
170
 
165
171
  this.sendSession({
166
- id: this.session?.id,
172
+ id: this.session.id,
167
173
  state: 'finishing',
168
174
  })
169
175
  }
@@ -173,6 +179,9 @@ export class SessionNegotiator {
173
179
  }
174
180
 
175
181
  private async waitForSessionResponse(): Promise<Session> {
182
+ if (this.failure) {
183
+ throw this.failure
184
+ }
176
185
  const { promise, resolve, reject } = Promise.withResolvers<Session>()
177
186
  this.currentSessionResolver = { resolve, reject }
178
187
  const session = await promise
@@ -10,7 +10,6 @@ import type {
10
10
  Notification,
11
11
  UnknownCommandResponse,
12
12
  } from '../../types/index.ts'
13
- import { logger } from '../../utils/logger.ts'
14
13
  import { BlipError } from '../bliperror.ts'
15
14
  import { RetryableError } from '../retryableerror.ts'
16
15
  import { ConnectionSender, type ConnectionSenderConstructor, OpenConnectionSender } from '../sender.ts'
@@ -41,21 +40,20 @@ export class TCPSender extends OpenConnectionSender {
41
40
  this.connectionHandle = new TCPHandle<Envelope>(
42
41
  host,
43
42
  443,
44
- () => {
43
+ (socketRef) => {
45
44
  this.sessionNegotiator = new SessionNegotiator(this, (session) => {
46
- this.connectionHandle
47
- .get()
48
- .then((s) => s.write(JSON.stringify(session)))
49
- .catch((err) => logger.warn('TCPSender', 'Failed to write session frame', err))
45
+ socketRef.current.write(JSON.stringify(session))
50
46
  })
51
- const upgradeToTls = tlsOptions ? () => this.connectionHandle.upgradeToTls(tlsOptions) : undefined
47
+ const upgradeToTls = tlsOptions
48
+ ? () => this.connectionHandle.upgradeToTls(tlsOptions, socketRef)
49
+ : undefined
52
50
  return this.sessionNegotiator.negotiate({
53
51
  node: options.node,
54
52
  authentication: auth,
55
53
  upgradeToTls,
56
54
  })
57
55
  },
58
- () => this.envelopeResolver.rejectPendingEnvelopes('Connection was closed'),
56
+ () => this.rejectPending('Connection was closed'),
59
57
  (envelope: Envelope) => {
60
58
  if (this.sessionNegotiator?.negotiating) {
61
59
  return this.sessionNegotiator.handleEnvelope(envelope)
@@ -143,7 +141,7 @@ class TCPHandle<T> {
143
141
  constructor(
144
142
  host: string,
145
143
  port: number,
146
- onConnected: () => Promise<void>,
144
+ onConnected: (socketRef: { current: Socket }) => Promise<void>,
147
145
  onClose: () => void,
148
146
  onMessage: (message: T) => void,
149
147
  ) {
@@ -167,17 +165,19 @@ class TCPHandle<T> {
167
165
  }
168
166
  }
169
167
 
170
- public async upgradeToTls(options: ConnectionOptions): Promise<void> {
171
- if (!this.currentSocketPromise) {
172
- throw new Error('Cannot upgrade: no active socket.')
173
- }
174
- const plain = await this.currentSocketPromise
168
+ public async upgradeToTls(options: ConnectionOptions, socketRef: { current: Socket }): Promise<void> {
169
+ const plain = socketRef.current
175
170
  plain.removeAllListeners('data')
176
171
  this.buffer = Buffer.alloc(0)
177
172
 
178
173
  const { connect: tlsConnect } = await import('node:tls')
179
174
  const secured = tlsConnect({ ...options, socket: plain })
180
175
 
176
+ // Permanent no-op handler attached up front, so errors that arrive in
177
+ // the microtask gap after secureConnect resolves don't become
178
+ // uncaughtException. The underlying TCP socket's 'close' drives reconnect.
179
+ secured.on('error', () => undefined)
180
+
181
181
  await new Promise<void>((resolve, reject) => {
182
182
  const onError = (err: Error) => {
183
183
  secured.off('secureConnect', onConnect)
@@ -192,7 +192,7 @@ class TCPHandle<T> {
192
192
  })
193
193
 
194
194
  this.attachDataListener(secured)
195
- this.currentSocketPromise = Promise.resolve(secured)
195
+ socketRef.current = secured
196
196
  }
197
197
 
198
198
  private attachDataListener(socket: NodeJS.ReadableStream) {
@@ -209,7 +209,7 @@ class TCPHandle<T> {
209
209
  private async connect(
210
210
  host: string,
211
211
  port: number,
212
- onConnected: () => Promise<void>,
212
+ onConnected: (socketRef: { current: Socket }) => Promise<void>,
213
213
  onClose: () => void,
214
214
  ): Promise<Socket> {
215
215
  const { connect } = await import('node:net')
@@ -217,42 +217,60 @@ class TCPHandle<T> {
217
217
  const socket = connect({ host, port }).setKeepAlive(true)
218
218
  this.buffer = Buffer.alloc(0)
219
219
 
220
- await new Promise<void>((resolve) => {
220
+ // Mutable holder so upgradeToTls can swap the socket mid-handshake;
221
+ // the negotiator's sendSession reads .current at write time, so frames
222
+ // always go to the active socket even after the TLS upgrade.
223
+ const socketRef = { current: socket }
224
+
225
+ await new Promise<void>((resolve, reject) => {
226
+ let connected = false
227
+
221
228
  socket.once('connect', () => {
229
+ connected = true
222
230
  resolve()
223
231
  })
224
232
 
225
233
  socket.once('error', (err) => {
226
- if (!this.closing) {
227
- throw err
234
+ if (!connected) {
235
+ reject(err)
228
236
  }
237
+ // Post-connect errors are followed by 'close', which drives reconnect;
238
+ // this listener exists only to prevent uncaughtException.
229
239
  })
230
240
 
231
241
  socket.once('close', () => {
232
- socket.removeAllListeners('data')
242
+ // socketRef.current is the TLS-upgraded socket if upgrade ran; the
243
+ // plain one otherwise. Both cases hold the only live data listener.
244
+ socketRef.current.removeAllListeners('data')
245
+
233
246
  if (!this.closing) {
234
- onClose()
247
+ if (connected) onClose()
235
248
 
236
249
  this.connectionAttempts++
237
- if (this.connectionAttempts < 3) {
238
- this.currentSocketPromise = this.connect(host, port, onConnected, onClose)
239
- } else {
240
- throw new Error('Failed to connect/reconnect to TCP socket')
241
- }
250
+ // Swallow the rejection of the now-orphaned previous promise; any
251
+ // in-flight get() awaiter still sees it via their captured reference.
252
+ const previous = this.currentSocketPromise
253
+ this.currentSocketPromise =
254
+ this.connectionAttempts < 3 ? this.connect(host, port, onConnected, onClose) : null
255
+ previous?.catch(() => undefined)
242
256
  }
257
+
258
+ if (!connected) reject(new Error('Socket closed before connect'))
243
259
  })
244
260
 
245
261
  this.attachDataListener(socket)
246
262
  })
247
263
 
248
- // sendSession callbacks read currentSocketPromise via .get(); resolve it
249
- // before onConnected runs so negotiate() can write the 'new' session frame
250
- // (otherwise we deadlock waiting on the outer connect() promise).
251
- this.currentSocketPromise = Promise.resolve(socket)
252
-
253
- await onConnected()
264
+ try {
265
+ await onConnected(socketRef)
266
+ } catch (err) {
267
+ // Handshake failures (timeout, bad response) leave the socket open
268
+ // otherwise; destroy it so the 'close' handler drives reconnect.
269
+ socketRef.current.destroy()
270
+ throw err
271
+ }
254
272
  this.connectionAttempts = 0
255
273
 
256
- return socket
274
+ return socketRef.current
257
275
  }
258
276
  }
@@ -39,7 +39,7 @@ export class WebSocketSender extends OpenConnectionSender {
39
39
  authentication: options.authentication,
40
40
  })
41
41
  },
42
- () => this.envelopeResolver.rejectPendingEnvelopes('Connection was closed'),
42
+ () => this.rejectPending('Connection was closed'),
43
43
  (envelope: Envelope) => {
44
44
  if (this.sessionNegotiator?.negotiating) {
45
45
  return this.sessionNegotiator.handleEnvelope(envelope)
@@ -139,7 +139,10 @@ class WebSocketHandle<T> {
139
139
  }
140
140
 
141
141
  public get() {
142
- return this.currentWebSocketPromise!
142
+ if (!this.currentWebSocketPromise) {
143
+ throw new Error('WebSocket connection is not available.')
144
+ }
145
+ return this.currentWebSocketPromise
143
146
  }
144
147
 
145
148
  public async close() {
@@ -159,31 +162,54 @@ class WebSocketHandle<T> {
159
162
  const connection = new WebSocket(url, 'lime')
160
163
 
161
164
  await new Promise<void>((resolve, reject) => {
165
+ let connected = false
166
+
162
167
  connection.onopen = () => {
168
+ connected = true
163
169
  resolve()
164
170
  }
171
+ connection.onerror = (err) => {
172
+ if (!connected) {
173
+ reject('message' in err ? new Error(`WebSocket error: ${err.message}`, { cause: err }) : err)
174
+ }
175
+ // Post-open errors are followed by 'close', which drives reconnect.
176
+ }
165
177
  connection.onclose = () => {
166
178
  if (!this.closing) {
167
- this.connectionAttempts++
168
-
169
- if (this.connectionAttempts < 3) {
170
- this.currentWebSocketPromise = this.connect(url, onConnected, onClose, onMessage)
171
- } else {
172
- reject(new Error('Failed to connect to WebSocket'))
173
- }
179
+ if (connected) onClose()
174
180
 
175
- onClose()
181
+ this.connectionAttempts++
182
+ // Swallow the rejection of the now-orphaned previous promise; any
183
+ // in-flight get() awaiter still sees it via their captured reference.
184
+ const previous = this.currentWebSocketPromise
185
+ this.currentWebSocketPromise =
186
+ this.connectionAttempts < 3 ? this.connect(url, onConnected, onClose, onMessage) : null
187
+ previous?.catch(() => undefined)
176
188
  }
189
+
190
+ if (!connected) reject(new Error('WebSocket closed before open'))
177
191
  }
178
192
  connection.onmessage = (event) => {
179
193
  onMessage(JSON.parse(event.data))
180
194
  }
181
- connection.onerror = (err) => {
182
- reject('message' in err ? new Error(`WebSocket error: ${err.message}`, { cause: err }) : err)
183
- }
184
195
  })
185
196
 
186
- await onConnected(connection)
197
+ try {
198
+ await onConnected(connection)
199
+ } catch (err) {
200
+ // Handshake failures leave the socket open otherwise; tear it down so
201
+ // the 'onclose' handler drives reconnect. Prefer ws.terminate() (hard
202
+ // kill, Node only) to avoid waiting on the graceful close handshake
203
+ // with a peer that just failed to negotiate; fall back to close() in
204
+ // browsers where terminate() doesn't exist.
205
+ const terminable = connection as WebSocket & { terminate?: () => void }
206
+ if (terminable.terminate) {
207
+ terminable.terminate()
208
+ } else {
209
+ connection.close()
210
+ }
211
+ throw err
212
+ }
187
213
  this.connectionAttempts = 0
188
214
 
189
215
  return connection
package/src/types/desk.ts CHANGED
@@ -101,6 +101,25 @@ export type DeskRule = {
101
101
  queueId?: string
102
102
  }
103
103
 
104
+ /**
105
+ * Filters accepted by every `/analytics/reports/*` endpoint. The backend
106
+ * applies all filters with AND semantics; arrays inside a single filter are
107
+ * OR'd together.
108
+ */
109
+ export type ReportFilters = {
110
+ beginDate: string | Date
111
+ endDate: string | Date
112
+ teams?: Array<string>
113
+ tags?: Array<string>
114
+ agentIdentities?: Array<Identity>
115
+ customerIdentities?: Array<Identity>
116
+ domains?: Array<string>
117
+ /** Include SLA applied/achieved counts on agent rows. */
118
+ calculateSla?: boolean
119
+ /** Force a fresh aggregation on `/tags`, bypassing the server cache. */
120
+ refreshCache?: boolean
121
+ }
122
+
104
123
  export type DeskPriorityRule = {
105
124
  id?: string
106
125
  ownerIdentity?: Identity