@graphcommerce/graphql 3.4.6 → 3.4.7

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Change Log
2
2
 
3
+ ## 3.4.7
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`860b4afc0`](https://github.com/graphcommerce-org/graphcommerce/commit/860b4afc0a2f79b1e660a5f9ce204532ce4fca47)]:
8
+ - @graphcommerce/graphql-codegen-near-operation-file@3.0.18
9
+
3
10
  ## 3.4.6
4
11
 
5
12
  ### Patch Changes
@@ -1,8 +1,11 @@
1
1
  /* eslint-disable no-console */
2
+ import { text } from 'stream/consumers'
2
3
  import { ApolloLink } from '@apollo/client'
3
4
 
4
- const slowOperationThreshold = 1000
5
- const slowResolverThreshold = 300
5
+ const running = new Map<
6
+ string,
7
+ { start: Date; end?: Date; internalStart?: Date; operationName: string }
8
+ >()
6
9
 
7
10
  interface TracingFormat {
8
11
  version: 1
@@ -21,46 +24,150 @@ interface TracingFormat {
21
24
  }
22
25
  }
23
26
 
27
+ const renderLine = (line: {
28
+ serverStart: number
29
+ requestStart: number
30
+ requestEnd: number
31
+ colDivider: number
32
+ additional: string[]
33
+ }) => {
34
+ const duration = line.requestEnd - line.requestStart
35
+ const serverDuration = duration - line.serverStart
36
+ const waitTime = duration - serverDuration
37
+
38
+ const reqStart = Math.floor(line.requestStart / line.colDivider)
39
+ const startSpacing = reqStart >= 1 ? ' '.repeat(reqStart) : ''
40
+
41
+ const waitDotsRound = Math.floor(waitTime / line.colDivider - 1)
42
+ const waitDots = waitDotsRound >= 1 ? `${'╌'.repeat(waitDotsRound)}` : ''
43
+
44
+ const dashrepeat = Math.floor(serverDuration / line.colDivider)
45
+
46
+ const dashes =
47
+ dashrepeat >= 1 ? `${waitDotsRound > 1 ? '┼' : ''}${'─'.repeat(dashrepeat - 1)}` : ''
48
+ const result = `${startSpacing}├${waitDots}${dashes}┤`
49
+
50
+ return ['', ...line.additional, result]
51
+ }
52
+
53
+ let timeout: NodeJS.Timeout | undefined
54
+ const markTimeout = () => {
55
+ if (timeout) {
56
+ clearTimeout(timeout)
57
+ }
58
+ timeout = setTimeout(() => {
59
+ const entries = Array.from(running.entries())
60
+ if (!entries.every(([k, v]) => v.end)) return
61
+
62
+ /**
63
+ * Print to the console a timeline that gives a visual reprentation of the starting time and
64
+ * duration of each operation like so;
65
+ *
66
+ * ╞═════════ QueryOne (250ms) ═════════╡ ╞══════════════════ Query Two (450ms)
67
+ * ══════════════════╡ ╞═════════ QueryThree ═════════╡
68
+ */
69
+
70
+ let start = Number.MAX_VALUE
71
+ let end = 0
72
+ entries.forEach(([key, value]) => {
73
+ if (value.start.getTime() < start) start = value.start.getTime()
74
+ if (value.end && value.end.getTime() > end) end = value.end.getTime()
75
+ })
76
+ end -= start
77
+
78
+ const colDivider = Math.max(Math.floor(end / 150), 20)
79
+
80
+ const lines = entries.map(([key, value]) => {
81
+ const requestStart = value.start.getTime() - start
82
+ const requestEnd = value.end ? value.end.getTime() - start : 0
83
+ const duration = requestEnd - requestStart
84
+
85
+ const serverStart = value.internalStart
86
+ ? value.internalStart.getTime() - value.start.getTime()
87
+ : 0
88
+
89
+ return renderLine({
90
+ serverStart,
91
+ requestStart,
92
+ requestEnd,
93
+ additional: [
94
+ value.operationName,
95
+ `${duration - (duration - serverStart)}ms`,
96
+ `${duration - serverStart}ms`,
97
+ ],
98
+ colDivider,
99
+ })
100
+ })
101
+
102
+ const items = [
103
+ ['', 'GraphQL requests', 'Bootup', 'Mesh', 'Waterfall'],
104
+ ['', '', '', '', ''],
105
+ ...lines,
106
+ renderLine({
107
+ serverStart: 0,
108
+ requestStart: 0,
109
+ requestEnd: end,
110
+ additional: [`Total time`, '', `${end}ms`],
111
+ colDivider,
112
+ }),
113
+ ]
114
+
115
+ // Rewrite the above so it can handle abritraty columns
116
+ const colWidths: number[] = Array(items[0].length).fill(0)
117
+ items.forEach((item) => {
118
+ item.forEach((t, index) => {
119
+ colWidths[index] = Math.max(colWidths[index], t.length)
120
+ })
121
+ })
122
+
123
+ // padd the items to the max length
124
+ items.forEach((item) => {
125
+ item.forEach((t, index) => {
126
+ item[index] = `${item[index].padEnd(colWidths[index], ' ')}${
127
+ index !== item.length - 1 ? ` │ ` : ''
128
+ }`
129
+ })
130
+ })
131
+
132
+ // render the items to a string
133
+ const output = [[''], ...items].map((item) => item.join(' ')).join('\n')
134
+ console.log(output)
135
+
136
+ running.clear()
137
+ }, 1000)
138
+ }
139
+
24
140
  /**
25
141
  * This doesn't work with the current implementation of the Apollo client. We're using SchemaLink
26
142
  * which doesn't support additional links.
27
143
  */
28
144
  export const measurePerformanceLink = new ApolloLink((operation, forward) => {
29
- if (typeof global.window !== 'undefined') {
30
- return forward(operation)
31
- }
32
- // Called before operation is sent to server
33
- operation.setContext({ measurePerformanceLinkStart: new Date().valueOf() })
34
- return forward(operation).map((data) => {
35
- // Called after server responds
36
- const time: number =
37
- new Date().valueOf() - (operation.getContext().measurePerformanceLinkStart as number)
38
- let vars =
145
+ if (typeof window === 'undefined') {
146
+ // Called before operation is sent to server
147
+ operation.setContext({ measurePerformanceLinkStart: new Date() })
148
+ const vars =
39
149
  Object.keys(operation.variables).length > 0 ? `(${JSON.stringify(operation.variables)})` : ''
40
- if (vars.length > 100) {
41
- vars = `${vars.substring(0, 100)}…`
42
- }
43
-
44
- if (data.extensions?.tracing && time > slowOperationThreshold) {
45
- const tracing = data.extensions?.tracing as TracingFormat
46
-
47
- const duration = Math.round(tracing.duration / (1000 * 1000))
48
-
49
- console.group(`GraphQL slow query/mutation '${operation.operationName}'${vars}`)
50
- console.info(`operations ${duration}ms, mesh: ${time - duration}ms`)
51
-
52
- tracing.execution.resolvers
53
- .filter((resolver) => resolver.duration > slowResolverThreshold * 1000 * 1000)
54
- .forEach((resolver) =>
55
- console.info(
56
- `${operation.operationName}.${resolver.path.join('.')}[${Math.round(
57
- resolver.duration / (1000 * 1000),
58
- )}ms]`,
59
- ),
60
- )
61
- console.groupEnd()
62
- }
63
-
64
- return data
65
- })
150
+ const operationString = `${operation.operationName}${vars}`
151
+
152
+ running.set(operationString, { start: new Date(), operationName: operation.operationName })
153
+ markTimeout()
154
+
155
+ // console.info(`GraphQL start ${operationString}`)
156
+ return forward(operation).map((data) => {
157
+ const tracing = data.extensions?.tracing as TracingFormat | undefined
158
+
159
+ // Called after server responds
160
+ running.set(operationString, {
161
+ internalStart: tracing ? new Date(tracing.startTime) : undefined,
162
+ start: operation.getContext().measurePerformanceLinkStart as Date,
163
+ end: new Date(),
164
+ operationName: operation.operationName,
165
+ })
166
+
167
+ markTimeout()
168
+
169
+ return data
170
+ })
171
+ }
172
+ return forward(operation)
66
173
  })
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/graphql",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "3.4.6",
5
+ "version": "3.4.7",
6
6
  "sideEffects": false,
7
7
  "main": "index.ts",
8
8
  "prettier": "@graphcommerce/prettier-config-pwa",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "@apollo/client": "^3.6.9",
23
- "@graphcommerce/graphql-codegen-near-operation-file": "3.0.17",
23
+ "@graphcommerce/graphql-codegen-near-operation-file": "3.0.18",
24
24
  "@graphcommerce/graphql-codegen-relay-optimizer-plugin": "3.0.10",
25
25
  "@graphql-codegen/add": "3.2.1",
26
26
  "@graphql-codegen/fragment-matcher": "3.3.1",