@muyichengshayu/promptx 0.2.13 → 0.2.15

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 (52) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/apps/server/src/agentSessionDiscovery.js +180 -7
  3. package/apps/web/dist/assets/{CodexSessionManagerDialog-Dic9kMHK.js → CodexSessionManagerDialog-y7O-JTxP.js} +1 -1
  4. package/apps/web/dist/assets/{TaskDiffReviewDialog-CKiZdXqi.js → TaskDiffReviewDialog-CTr_zoAn.js} +1 -1
  5. package/apps/web/dist/assets/{WorkbenchSettingsDialog-CP0z90bm.js → WorkbenchSettingsDialog-Bf2DCuN_.js} +1 -1
  6. package/apps/web/dist/assets/{WorkbenchView-D1oxqNr4.css → WorkbenchView-CK1snPBz.css} +1 -1
  7. package/apps/web/dist/assets/WorkbenchView-Gq3mmtsK.js +60 -0
  8. package/apps/web/dist/assets/index-Co1Ssha9.js +2 -0
  9. package/apps/web/dist/index.html +1 -1
  10. package/package.json +21 -14
  11. package/apps/runner/src/engines/claudeCodeRunner.test.js +0 -467
  12. package/apps/runner/src/engines/kimiCodeRunner.test.js +0 -127
  13. package/apps/runner/src/engines/openCodeRunner.test.js +0 -236
  14. package/apps/runner/src/engines/runnerContract.test.js +0 -449
  15. package/apps/runner/src/engines/shellRunner.test.js +0 -46
  16. package/apps/runner/src/runManager.test.js +0 -913
  17. package/apps/runner/src/serverClient.test.js +0 -93
  18. package/apps/server/src/agentSessionDiscovery.test.js +0 -186
  19. package/apps/server/src/appPaths.test.js +0 -52
  20. package/apps/server/src/assetRoutes.test.js +0 -168
  21. package/apps/server/src/codex.test.js +0 -518
  22. package/apps/server/src/codexRoutes.test.js +0 -376
  23. package/apps/server/src/codexRuns.test.js +0 -160
  24. package/apps/server/src/codexSessions.test.js +0 -369
  25. package/apps/server/src/db.test.js +0 -182
  26. package/apps/server/src/gitDiff.test.js +0 -542
  27. package/apps/server/src/gitDiffClient.test.js +0 -140
  28. package/apps/server/src/internalRoutes.test.js +0 -134
  29. package/apps/server/src/maintenance.test.js +0 -154
  30. package/apps/server/src/processControl.test.js +0 -147
  31. package/apps/server/src/relayClient.test.js +0 -478
  32. package/apps/server/src/relayConfig.test.js +0 -73
  33. package/apps/server/src/relayProtocol.test.js +0 -49
  34. package/apps/server/src/relayServer.test.js +0 -798
  35. package/apps/server/src/relayTenants.test.js +0 -137
  36. package/apps/server/src/relayUsageStore.test.js +0 -65
  37. package/apps/server/src/repository.test.js +0 -150
  38. package/apps/server/src/runDispatchService.test.js +0 -563
  39. package/apps/server/src/runEventIngest.test.js +0 -225
  40. package/apps/server/src/runRecovery.test.js +0 -73
  41. package/apps/server/src/runnerClient.test.js +0 -80
  42. package/apps/server/src/runnerDispatch.test.js +0 -136
  43. package/apps/server/src/systemConfig.test.js +0 -112
  44. package/apps/server/src/systemRoutes.test.js +0 -319
  45. package/apps/server/src/taskRoutes.test.js +0 -775
  46. package/apps/server/src/upload.test.js +0 -30
  47. package/apps/server/src/webAppRoutes.test.js +0 -67
  48. package/apps/server/src/workspaceFiles.test.js +0 -279
  49. package/apps/web/dist/assets/WorkbenchView-noayQwj4.js +0 -60
  50. package/apps/web/dist/assets/index-HLkdzIYF.js +0 -2
  51. package/packages/shared/src/dailyLogStream.test.js +0 -29
  52. package/packages/shared/src/shellCommands.test.js +0 -45
@@ -1,478 +0,0 @@
1
- import assert from 'node:assert/strict'
2
- import { EventEmitter } from 'node:events'
3
- import test from 'node:test'
4
- import { setTimeout as delay } from 'node:timers/promises'
5
- import { WebSocketServer } from 'ws'
6
-
7
- import { createRelayClient } from './relayClient.js'
8
-
9
- async function withRelayServer(run) {
10
- const server = new WebSocketServer({ port: 0 })
11
-
12
- await new Promise((resolve) => server.once('listening', resolve))
13
- const { port } = server.address()
14
-
15
- try {
16
- await run({
17
- relayWsUrl: `ws://127.0.0.1:${port}`,
18
- server,
19
- })
20
- } finally {
21
- server.clients.forEach((client) => {
22
- try {
23
- client.terminate()
24
- } catch {
25
- // ignore
26
- }
27
- })
28
- await new Promise((resolve) => server.close(resolve))
29
- }
30
- }
31
-
32
- function listenJsonMessages(socket, handler) {
33
- socket.on('message', (payload, isBinary) => {
34
- if (isBinary) {
35
- return
36
- }
37
-
38
- let message = null
39
- try {
40
- message = JSON.parse(payload.toString('utf8'))
41
- } catch {
42
- return
43
- }
44
-
45
- handler(message)
46
- })
47
- }
48
-
49
- async function waitFor(check, timeoutMs = 2_000) {
50
- const startedAt = Date.now()
51
- while (Date.now() - startedAt < timeoutMs) {
52
- const value = check()
53
- if (value) {
54
- return value
55
- }
56
- await delay(20)
57
- }
58
- throw new Error('waitFor timeout')
59
- }
60
-
61
- function createSilentLogger(logs = []) {
62
- return {
63
- info(...args) {
64
- logs.push(['info', args])
65
- },
66
- warn(...args) {
67
- logs.push(['warn', args])
68
- },
69
- error(...args) {
70
- logs.push(['error', args])
71
- },
72
- }
73
- }
74
-
75
- class FakeSocket extends EventEmitter {
76
- constructor() {
77
- super()
78
- this.readyState = 0
79
- this.sentPayloads = []
80
- }
81
-
82
- send(payload) {
83
- this.sentPayloads.push(JSON.parse(String(payload || '{}')))
84
- }
85
-
86
- close(code = 1000, reason = '') {
87
- this.readyState = 3
88
- this.emit('close', code, Buffer.from(String(reason || '')))
89
- }
90
-
91
- terminate() {
92
- this.close(1006, 'terminated')
93
- }
94
- }
95
-
96
- test('relay client becomes connected only after hello ack', async () => {
97
- await withRelayServer(async ({ relayWsUrl, server }) => {
98
- server.on('connection', (socket) => {
99
- listenJsonMessages(socket, (message) => {
100
- if (message?.type === 'hello') {
101
- socket.send(JSON.stringify({
102
- type: 'hello.ack',
103
- ok: true,
104
- deviceId: message.deviceId,
105
- }))
106
- }
107
- })
108
- })
109
-
110
- const logs = []
111
- const client = createRelayClient({
112
- relayUrl: relayWsUrl.replace(/^ws/, 'http'),
113
- deviceId: 'my-device',
114
- deviceToken: 'secret',
115
- logger: createSilentLogger(logs),
116
- })
117
-
118
- try {
119
- client.start()
120
- await waitFor(() => client.getStatus().connected === true)
121
-
122
- const status = client.getStatus()
123
- assert.equal(status.connected, true)
124
- assert.equal(status.lastError, '')
125
- assert.equal(Boolean(status.lastConnectedAt), true)
126
- assert.equal(Boolean(status.lastHeartbeatAt), true)
127
- assert.equal(status.lastCloseReason, '')
128
- assert.equal(status.pendingRequestCount, 0)
129
- assert.equal(status.socketReadyState, 1)
130
- assert.equal(status.recentEvents.some((event) => event.type === 'auth_ok'), true)
131
- assert.equal(logs.some(([level, args]) => level === 'info' && String(args.at(-1)).includes('连接已就绪')), true)
132
- } finally {
133
- client.stop()
134
- }
135
- })
136
- })
137
-
138
- test('relay client records heartbeat timestamp after server ping', async () => {
139
- await withRelayServer(async ({ relayWsUrl, server }) => {
140
- server.on('connection', (socket) => {
141
- listenJsonMessages(socket, (message) => {
142
- if (message?.type === 'hello') {
143
- socket.send(JSON.stringify({
144
- type: 'hello.ack',
145
- ok: true,
146
- deviceId: message.deviceId,
147
- }))
148
-
149
- setTimeout(() => {
150
- if (socket.readyState === 1) {
151
- socket.ping()
152
- }
153
- }, 40)
154
- }
155
- })
156
- })
157
-
158
- const client = createRelayClient({
159
- relayUrl: relayWsUrl.replace(/^ws/, 'http'),
160
- deviceId: 'my-device',
161
- deviceToken: 'secret',
162
- logger: createSilentLogger(),
163
- })
164
-
165
- try {
166
- client.start()
167
- await waitFor(() => client.getStatus().connected === true)
168
- const initialHeartbeatAt = client.getStatus().lastHeartbeatAt
169
- await waitFor(() => client.getStatus().lastHeartbeatAt && client.getStatus().lastHeartbeatAt !== initialHeartbeatAt)
170
-
171
- assert.equal(Boolean(client.getStatus().lastHeartbeatAt), true)
172
- } finally {
173
- client.stop()
174
- }
175
- })
176
- })
177
-
178
- test('relay client pauses reconnect after non-retryable reject reason', async () => {
179
- await withRelayServer(async ({ relayWsUrl, server }) => {
180
- let connectionCount = 0
181
- server.on('connection', (socket) => {
182
- connectionCount += 1
183
- listenJsonMessages(socket, (message) => {
184
- if (message?.type === 'hello') {
185
- socket.close(1008, 'invalid_device')
186
- }
187
- })
188
- })
189
-
190
- const client = createRelayClient({
191
- relayUrl: relayWsUrl.replace(/^ws/, 'http'),
192
- deviceId: 'my-device',
193
- deviceToken: 'secret',
194
- reconnectDelayStrategy: () => 20,
195
- logger: createSilentLogger(),
196
- })
197
-
198
- try {
199
- client.start()
200
- await waitFor(() => client.getStatus().lastCloseReason !== '')
201
- await delay(120)
202
-
203
- const status = client.getStatus()
204
- assert.equal(status.connected, false)
205
- assert.equal(status.lastCloseCode, 1008)
206
- assert.equal(status.lastCloseReason, '设备 ID 不匹配')
207
- assert.match(status.lastError, /设备 ID 不匹配/)
208
- assert.equal(status.reconnectPaused, true)
209
- assert.equal(status.reconnectPausedReason, '设备 ID 不匹配')
210
- assert.equal(connectionCount, 1)
211
- assert.equal(status.recentEvents.some((event) => event.type === 'reconnect_paused'), true)
212
- } finally {
213
- client.stop()
214
- }
215
- })
216
- })
217
-
218
- test('relay client resets reconnect count after reconnect succeeds', async () => {
219
- await withRelayServer(async ({ relayWsUrl, server }) => {
220
- let connectionCount = 0
221
- server.on('connection', (socket) => {
222
- connectionCount += 1
223
- const currentConnection = connectionCount
224
- listenJsonMessages(socket, (message) => {
225
- if (message?.type !== 'hello') {
226
- return
227
- }
228
-
229
- socket.send(JSON.stringify({
230
- type: 'hello.ack',
231
- ok: true,
232
- deviceId: message.deviceId,
233
- }))
234
-
235
- if (currentConnection === 1) {
236
- setTimeout(() => {
237
- if (socket.readyState === 1) {
238
- socket.close(1012, 'server_restart')
239
- }
240
- }, 30)
241
- }
242
- })
243
- })
244
-
245
- const client = createRelayClient({
246
- relayUrl: relayWsUrl.replace(/^ws/, 'http'),
247
- deviceId: 'my-device',
248
- deviceToken: 'secret',
249
- reconnectDelayStrategy: () => 20,
250
- logger: createSilentLogger(),
251
- })
252
-
253
- try {
254
- client.start()
255
- await waitFor(() => connectionCount >= 2)
256
- await waitFor(() => client.getStatus().connected === true && client.getStatus().reconnectCount === 0)
257
-
258
- const status = client.getStatus()
259
- assert.equal(status.connected, true)
260
- assert.equal(status.reconnectCount, 0)
261
- assert.equal(status.nextReconnectDelayMs, 0)
262
- assert.equal(status.reconnectPaused, false)
263
- assert.equal(status.recentEvents.some((event) => event.type === 'reconnect_scheduled'), true)
264
- } finally {
265
- client.stop()
266
- }
267
- })
268
- })
269
-
270
- test('relay client self-heals when heartbeat becomes stale', async () => {
271
- await withRelayServer(async ({ relayWsUrl, server }) => {
272
- let connectionCount = 0
273
- server.on('connection', (socket) => {
274
- connectionCount += 1
275
- const currentConnection = connectionCount
276
- listenJsonMessages(socket, (message) => {
277
- if (message?.type !== 'hello') {
278
- return
279
- }
280
-
281
- socket.send(JSON.stringify({
282
- type: 'hello.ack',
283
- ok: true,
284
- deviceId: message.deviceId,
285
- }))
286
-
287
- if (currentConnection >= 2) {
288
- setTimeout(() => {
289
- if (socket.readyState === 1) {
290
- socket.ping()
291
- }
292
- }, 20)
293
- }
294
- })
295
- })
296
-
297
- const client = createRelayClient({
298
- relayUrl: relayWsUrl.replace(/^ws/, 'http'),
299
- deviceId: 'my-device',
300
- deviceToken: 'secret',
301
- reconnectDelayStrategy: () => 20,
302
- healthCheckIntervalMs: 20,
303
- heartbeatTimeoutMs: 60,
304
- logger: createSilentLogger(),
305
- })
306
-
307
- try {
308
- client.start()
309
- await waitFor(() => connectionCount >= 2, 3_000)
310
- await waitFor(() => client.getStatus().connected === true)
311
-
312
- const status = client.getStatus()
313
- assert.equal(status.connected, true)
314
- assert.equal(connectionCount >= 2, true)
315
- assert.equal(status.recentEvents.some((event) => event.type === 'heartbeat_stale'), true)
316
- assert.equal(status.recentEvents.some((event) => event.type === 'reconnect_requested' && event.source === 'heartbeat_timeout'), true)
317
- } finally {
318
- client.stop()
319
- }
320
- })
321
- })
322
-
323
- test('relay client detects resume-like clock jump and reconnects', async () => {
324
- await withRelayServer(async ({ relayWsUrl, server }) => {
325
- let connectionCount = 0
326
- let fakeNow = Date.now()
327
-
328
- server.on('connection', (socket) => {
329
- connectionCount += 1
330
- const currentConnection = connectionCount
331
- listenJsonMessages(socket, (message) => {
332
- if (message?.type !== 'hello') {
333
- return
334
- }
335
-
336
- socket.send(JSON.stringify({
337
- type: 'hello.ack',
338
- ok: true,
339
- deviceId: message.deviceId,
340
- }))
341
-
342
- if (currentConnection >= 2) {
343
- setTimeout(() => {
344
- if (socket.readyState === 1) {
345
- socket.ping()
346
- }
347
- }, 20)
348
- }
349
- })
350
- })
351
-
352
- const client = createRelayClient({
353
- relayUrl: relayWsUrl.replace(/^ws/, 'http'),
354
- deviceId: 'my-device',
355
- deviceToken: 'secret',
356
- reconnectDelayStrategy: () => 20,
357
- healthCheckIntervalMs: 20,
358
- heartbeatTimeoutMs: 60,
359
- sleepResumeThresholdMs: 40,
360
- getNow: () => fakeNow,
361
- logger: createSilentLogger(),
362
- })
363
-
364
- try {
365
- client.start()
366
- await waitFor(() => client.getStatus().connected === true)
367
-
368
- fakeNow += 500
369
-
370
- await waitFor(() => connectionCount >= 2, 3_000)
371
- await waitFor(() => client.getStatus().connected === true)
372
-
373
- const status = client.getStatus()
374
- assert.equal(status.connected, true)
375
- assert.equal(status.recentEvents.some((event) => event.type === 'system_resume_detected'), true)
376
- assert.equal(status.recentEvents.some((event) => event.type === 'reconnect_requested' && event.source === 'heartbeat_timeout'), true)
377
- } finally {
378
- client.stop()
379
- }
380
- })
381
- })
382
-
383
- test('relay client supports manual reconnect', async () => {
384
- await withRelayServer(async ({ relayWsUrl, server }) => {
385
- let connectionCount = 0
386
- server.on('connection', (socket) => {
387
- connectionCount += 1
388
- listenJsonMessages(socket, (message) => {
389
- if (message?.type === 'hello') {
390
- socket.send(JSON.stringify({
391
- type: 'hello.ack',
392
- ok: true,
393
- deviceId: message.deviceId,
394
- }))
395
- }
396
- })
397
- })
398
-
399
- const client = createRelayClient({
400
- relayUrl: relayWsUrl.replace(/^ws/, 'http'),
401
- deviceId: 'my-device',
402
- deviceToken: 'secret',
403
- reconnectDelayStrategy: () => 20,
404
- logger: createSilentLogger(),
405
- })
406
-
407
- try {
408
- client.start()
409
- await waitFor(() => client.getStatus().connected === true)
410
-
411
- const reconnectResult = client.reconnect()
412
- assert.equal(reconnectResult, true)
413
-
414
- await waitFor(() => connectionCount >= 2, 3_000)
415
- await waitFor(() => client.getStatus().connected === true)
416
-
417
- const status = client.getStatus()
418
- assert.equal(status.connected, true)
419
- assert.equal(status.recentEvents.some((event) => event.type === 'reconnect_requested' && event.source === 'manual'), true)
420
- } finally {
421
- client.stop()
422
- }
423
- })
424
- })
425
-
426
- test('relay client ignores stale close events from previous socket instances', async () => {
427
- const sockets = []
428
- const client = createRelayClient({
429
- relayUrl: 'http://relay.example.com',
430
- deviceId: 'my-device',
431
- deviceToken: 'secret',
432
- healthCheckIntervalMs: 60_000,
433
- logger: createSilentLogger(),
434
- createWebSocket() {
435
- const socket = new FakeSocket()
436
- sockets.push(socket)
437
- return socket
438
- },
439
- })
440
-
441
- try {
442
- client.start()
443
- assert.equal(sockets.length, 1)
444
-
445
- const firstSocket = sockets[0]
446
- firstSocket.readyState = 1
447
- firstSocket.emit('open')
448
- firstSocket.emit('message', Buffer.from(JSON.stringify({
449
- type: 'hello.ack',
450
- ok: true,
451
- deviceId: 'my-device',
452
- })), false)
453
-
454
- assert.equal(client.getStatus().connected, true)
455
-
456
- firstSocket.readyState = 2
457
- client.start()
458
- assert.equal(sockets.length, 2)
459
-
460
- const secondSocket = sockets[1]
461
- secondSocket.readyState = 1
462
- secondSocket.emit('open')
463
- secondSocket.emit('message', Buffer.from(JSON.stringify({
464
- type: 'hello.ack',
465
- ok: true,
466
- deviceId: 'my-device',
467
- })), false)
468
-
469
- firstSocket.emit('close', 1000, Buffer.from('stale_socket_closed'))
470
-
471
- const status = client.getStatus()
472
- assert.equal(status.connected, true)
473
- assert.equal(status.socketReadyState, 1)
474
- assert.equal(status.recentEvents.some((event) => event.type === 'stale_close_ignored'), true)
475
- } finally {
476
- client.stop()
477
- }
478
- })
@@ -1,73 +0,0 @@
1
- import assert from 'node:assert/strict'
2
- import fs from 'node:fs'
3
- import os from 'node:os'
4
- import path from 'node:path'
5
- import test from 'node:test'
6
-
7
- test('relay config module reads and writes stored config under promptx data dir', async () => {
8
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-relay-config-'))
9
- const originalPromptxHome = process.env.PROMPTX_HOME
10
- process.env.PROMPTX_HOME = tempDir
11
-
12
- try {
13
- const relayConfigModule = await import(`./relayConfig.js?test=${Date.now()}`)
14
- const saved = relayConfigModule.writeStoredRelayConfig({
15
- relayUrl: ' https://relay.example.com ',
16
- deviceId: ' my-device ',
17
- deviceToken: ' abc ',
18
- allowRemoteShell: true,
19
- enabled: true,
20
- })
21
-
22
- assert.deepEqual(saved, {
23
- relayUrl: 'https://relay.example.com',
24
- deviceId: 'my-device',
25
- deviceToken: 'abc',
26
- allowRemoteShell: true,
27
- enabled: true,
28
- })
29
-
30
- const loaded = relayConfigModule.readStoredRelayConfig()
31
- assert.deepEqual(loaded, saved)
32
- assert.equal(fs.existsSync(relayConfigModule.getRelayConfigPath()), true)
33
- } finally {
34
- if (typeof originalPromptxHome === 'string') {
35
- process.env.PROMPTX_HOME = originalPromptxHome
36
- } else {
37
- delete process.env.PROMPTX_HOME
38
- }
39
- }
40
- })
41
-
42
- test('relay config module lets env override allowRemoteShell', async () => {
43
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-relay-config-env-'))
44
- const originalPromptxHome = process.env.PROMPTX_HOME
45
- const originalAllowRemoteShell = process.env.PROMPTX_RELAY_ALLOW_REMOTE_SHELL
46
- process.env.PROMPTX_HOME = tempDir
47
- process.env.PROMPTX_RELAY_ALLOW_REMOTE_SHELL = '1'
48
-
49
- try {
50
- const relayConfigModule = await import(`./relayConfig.js?test=${Date.now()}`)
51
- relayConfigModule.writeStoredRelayConfig({
52
- relayUrl: 'https://relay.example.com',
53
- deviceId: 'my-device',
54
- deviceToken: 'abc',
55
- allowRemoteShell: false,
56
- enabled: true,
57
- })
58
-
59
- const loaded = relayConfigModule.getRelayConfigForClient()
60
- assert.equal(loaded.allowRemoteShell, true)
61
- } finally {
62
- if (typeof originalPromptxHome === 'string') {
63
- process.env.PROMPTX_HOME = originalPromptxHome
64
- } else {
65
- delete process.env.PROMPTX_HOME
66
- }
67
- if (typeof originalAllowRemoteShell === 'string') {
68
- process.env.PROMPTX_RELAY_ALLOW_REMOTE_SHELL = originalAllowRemoteShell
69
- } else {
70
- delete process.env.PROMPTX_RELAY_ALLOW_REMOTE_SHELL
71
- }
72
- }
73
- })
@@ -1,49 +0,0 @@
1
- import assert from 'node:assert/strict'
2
- import test from 'node:test'
3
-
4
- import {
5
- buildRelayWebSocketUrl,
6
- chunkBuffer,
7
- constantTimeEqual,
8
- parseCookieHeader,
9
- sanitizeProxyHeaders,
10
- } from './relayProtocol.js'
11
-
12
- test('buildRelayWebSocketUrl converts base URL to relay websocket endpoint', () => {
13
- assert.equal(buildRelayWebSocketUrl('https://relay.example.com/base?q=1'), 'wss://relay.example.com/relay/connect')
14
- assert.equal(buildRelayWebSocketUrl('http://127.0.0.1:3030/'), 'ws://127.0.0.1:3030/relay/connect')
15
- })
16
-
17
- test('chunkBuffer splits buffers by max size', () => {
18
- const chunks = chunkBuffer(Buffer.from('abcdefghij'), 4)
19
- assert.deepEqual(chunks.map((item) => item.toString('utf8')), ['abcd', 'efgh', 'ij'])
20
- })
21
-
22
- test('sanitizeProxyHeaders strips hop-by-hop headers and keeps content headers', () => {
23
- assert.deepEqual(
24
- sanitizeProxyHeaders({
25
- Host: 'localhost:3000',
26
- Connection: 'keep-alive',
27
- 'Content-Type': 'application/json',
28
- Accept: 'application/json',
29
- Cookie: 'secret=1',
30
- }, ['cookie']),
31
- {
32
- 'content-type': 'application/json',
33
- accept: 'application/json',
34
- }
35
- )
36
- })
37
-
38
- test('parseCookieHeader parses browser cookies', () => {
39
- assert.deepEqual(parseCookieHeader('foo=bar; hello=world%20ok'), {
40
- foo: 'bar',
41
- hello: 'world ok',
42
- })
43
- })
44
-
45
- test('constantTimeEqual compares exact token text', () => {
46
- assert.equal(constantTimeEqual('abc', 'abc'), true)
47
- assert.equal(constantTimeEqual('abc', 'abcd'), false)
48
- assert.equal(constantTimeEqual('abc', 'abx'), false)
49
- })