Skip to content

Commit 610d594

Browse files
committed
fix: save correct outputs
1 parent 941711a commit 610d594

File tree

5 files changed

+142
-27
lines changed

5 files changed

+142
-27
lines changed

pnpm-lock.yaml

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/core/constants.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export const FLYTRAP_CIRCULAR = 'FLYTRAP_CIRCULAR'
99
export const FLYTRAP_HEADERS = 'FLYTRAP_HEADERS'
1010
export const FLYTRAP_RESPONSE = 'FLYTRAP_RESPONSE'
1111
export const FLYTRAP_REQUEST = 'FLYTRAP_REQUEST'
12+
export const FLYTRAP_CLASS = 'FLYTRAP_CLASS'
1213

1314
export const FLYTRAP_REPLACE_VALUES = [
1415
FLYTRAP_UNSERIALIZABLE_VALUE,
@@ -17,5 +18,6 @@ export const FLYTRAP_REPLACE_VALUES = [
1718
FLYTRAP_CIRCULAR,
1819
FLYTRAP_HEADERS,
1920
FLYTRAP_REQUEST,
20-
FLYTRAP_RESPONSE
21+
FLYTRAP_RESPONSE,
22+
FLYTRAP_CLASS
2123
]

src/core/storage.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ import { FLYTRAP_UNSERIALIZABLE_VALUE, NO_SOURCE } from './constants'
1515
import { encrypt } from './encryption'
1616
import { log } from './logging'
1717
import { serializeError } from 'serialize-error'
18-
import { copy } from 'copy-anything'
1918
import {
2019
addLinksToCaptures,
2120
decryptCapture,
2221
extractArgs,
2322
extractOutputs,
2423
parse,
24+
processCaptures,
2525
removeCircularDependencies,
2626
stringify,
2727
superJsonRegisterCustom
@@ -191,8 +191,14 @@ export const liveFlytrapStorage: FlytrapStorage = {
191191
return
192192
}
193193

194-
calls = removeIllegalValues(removeCircularDependencies(calls))
195-
functions = removeIllegalValues(removeCircularDependencies(functions))
194+
calls = removeIllegalValues(calls)
195+
functions = removeIllegalValues(functions)
196+
197+
calls = processCaptures(calls)
198+
functions = processCaptures(functions)
199+
200+
calls = removeCircularDependencies(calls)
201+
functions = removeCircularDependencies(functions)
196202

197203
const args = [...extractArgs(calls), ...extractArgs(functions)]
198204
const outputs = [...extractOutputs(calls), ...extractOutputs(functions)]
@@ -210,7 +216,7 @@ export const liveFlytrapStorage: FlytrapStorage = {
210216
source: NO_SOURCE,
211217
// args, outputs,
212218
args: await encrypt(publicApiKey, stringify(args)),
213-
outputs: await encrypt(publicApiKey, stringify(args)),
219+
outputs: await encrypt(publicApiKey, stringify(outputs)),
214220
calls: linkedCalls,
215221
functions: linkedFunctions,
216222
...(error && {
@@ -274,7 +280,7 @@ function isSerializable(input: any) {
274280
}
275281

276282
export function removeIllegalValues(captures: (CapturedCall | CapturedFunction)[]) {
277-
const capturesClone = copy(captures)
283+
const capturesClone = captures
278284

279285
for (let i = 0; i < capturesClone.length; i++) {
280286
for (let j = 0; j < capturesClone[i].invocations.length; j++) {

src/core/stringify.ts

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import SuperJSON from 'superjson'
22
import {
33
FLYTRAP_CIRCULAR,
4+
FLYTRAP_CLASS,
45
FLYTRAP_DOM_EVENT,
56
FLYTRAP_FUNCTION,
67
FLYTRAP_HEADERS,
@@ -17,7 +18,7 @@ import {
1718
} from './types'
1819
import { deepEqual } from 'fast-equals'
1920
import { decrypt } from './encryption'
20-
import { copy } from 'copy-anything'
21+
// import { copy } from 'copy-anything'
2122

2223
export function superJsonRegisterCustom(superJsonInstance: typeof SuperJSON) {
2324
// Fetch API classes
@@ -46,17 +47,17 @@ export function superJsonRegisterCustom(superJsonInstance: typeof SuperJSON) {
4647
'Request'
4748
)
4849

49-
// handle functions
50+
// Functions
5051
superJsonInstance.registerCustom<any, string>(
5152
{
5253
isApplicable: (v): v is Function => typeof v === 'function',
5354
serialize: () => FLYTRAP_FUNCTION,
5455
deserialize: () => FLYTRAP_FUNCTION
5556
},
56-
'functions'
57+
'Functions'
5758
)
5859

59-
// handle DOM events
60+
// DOM Events
6061
superJsonInstance.registerCustom<any, string>(
6162
{
6263
isApplicable: (v): v is Event => {
@@ -65,7 +66,29 @@ export function superJsonRegisterCustom(superJsonInstance: typeof SuperJSON) {
6566
serialize: () => FLYTRAP_DOM_EVENT,
6667
deserialize: () => FLYTRAP_DOM_EVENT
6768
},
68-
'dom events'
69+
'DOM Events'
70+
)
71+
72+
// Classes
73+
superJsonInstance.registerCustom<any, string>(
74+
{
75+
isApplicable: (v): v is Request => {
76+
return isClassInstance(v)
77+
},
78+
serialize: () => FLYTRAP_CLASS,
79+
deserialize: () => FLYTRAP_CLASS
80+
},
81+
'Classes'
82+
)
83+
}
84+
85+
export function isClassInstance<T>(obj: T): boolean {
86+
return (
87+
obj !== null &&
88+
typeof obj === 'object' &&
89+
!(obj instanceof Array) &&
90+
obj.constructor &&
91+
obj.constructor !== Object
6992
)
7093
}
7194

@@ -113,7 +136,6 @@ export function removeCircularDependencies<T>(obj: T, seenObjects = new Set()):
113136
// It's a circular reference
114137
// @ts-expect-error
115138
return FLYTRAP_CIRCULAR
116-
// return null; // Or replace with some placeholder if needed
117139
}
118140

119141
// Keep track of this object so we don't process it again
@@ -137,16 +159,6 @@ export function removeCircularDependencies<T>(obj: T, seenObjects = new Set()):
137159
return newObj as T
138160
}
139161

140-
/*export function removeCircularDependencies<T>(obj: T): T {
141-
superJsonRegisterCustom(SuperJSON)
142-
const serialized = SuperJSON.serialize(obj)
143-
if (serialized.meta?.referentialEqualities) {
144-
delete serialized.meta.referentialEqualities
145-
}
146-
147-
return SuperJSON.deserialize(serialized)
148-
}*/
149-
150162
function _extract(captures: (CapturedCall | CapturedFunction)[], key: 'args' | 'output' = 'args') {
151163
const values = captures.reduce(
152164
(acc, curr) => [...acc, ...curr.invocations.map((i) => i[key])],
@@ -171,7 +183,7 @@ export function extractArgs(captures: (CapturedCall | CapturedFunction)[]): any[
171183
return _extract(captures, 'args')
172184
}
173185

174-
export function extractOutputs(captures: (CapturedCall | CapturedFunction)[]): any[][] {
186+
export function extractOutputs(captures: (CapturedCall | CapturedFunction)[]): any[] {
175187
return _extract(captures, 'output')
176188
}
177189

@@ -188,7 +200,8 @@ export function addLinks(
188200
invocations: CaptureInvocation[],
189201
{ args, outputs }: { args: any[][]; outputs: any[] }
190202
) {
191-
const invocationsCopy = copy(invocations)
203+
// const invocationsCopy = copy(invocations)
204+
const invocationsCopy = invocations
192205

193206
for (let i = 0; i < invocationsCopy.length; i++) {
194207
// Args
@@ -210,7 +223,8 @@ export function addLinksToCaptures(
210223
captures: (CapturedCall | CapturedFunction)[],
211224
{ args, outputs }: { args: any[][]; outputs: any[] }
212225
) {
213-
const capturesCopy = copy(captures)
226+
// const capturesCopy = copy(captures)
227+
const capturesCopy = captures
214228
for (let i = 0; i < capturesCopy.length; i++) {
215229
// captures[i].invocations
216230
const linkedInvocations = addLinks(capturesCopy[i].invocations, { args, outputs })
@@ -275,7 +289,8 @@ export function reviveLinks(
275289
invocations: CaptureInvocationWithLinks[],
276290
{ args, outputs }: { args: any[][]; outputs: any[] }
277291
): CaptureInvocation[] {
278-
const invocationsCopy = copy(invocations)
292+
// const invocationsCopy = copy(invocations)
293+
const invocationsCopy = invocations
279294

280295
for (let i = 0; i < invocationsCopy.length; i++) {
281296
// Revive args
@@ -289,3 +304,11 @@ export function reviveLinks(
289304

290305
return invocationsCopy as unknown as CaptureInvocation[]
291306
}
307+
308+
export function processCaptures(captures: (CapturedCall | CapturedFunction)[]) {
309+
superJsonRegisterCustom(SuperJSON)
310+
for (let i = 0; i < captures.length; i++) {
311+
captures[i] = SuperJSON.deserialize(SuperJSON.serialize(captures[i]))
312+
}
313+
return captures
314+
}

test/stringify.test.ts

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,23 @@ import {
33
addLinks,
44
extractArgs,
55
extractOutputs,
6+
isClassInstance,
67
parse,
8+
processCaptures,
79
reviveLinks,
810
stringify
911
} from '../src/core/stringify'
1012
import SuperJSON from 'superjson'
1113
import {
14+
FLYTRAP_CLASS,
1215
FLYTRAP_DOM_EVENT,
1316
FLYTRAP_FUNCTION,
1417
FLYTRAP_HEADERS,
1518
FLYTRAP_REQUEST,
1619
FLYTRAP_RESPONSE
1720
} from '../src/core/constants'
1821
import { GlobalRegistrator } from '@happy-dom/global-registrator'
19-
import { CapturedCall } from '../src/exports'
22+
import { CapturedCall, type CapturedFunction } from '../src/exports'
2023
GlobalRegistrator.register()
2124

2225
it('removes cyclical dependencies', () => {
@@ -163,6 +166,67 @@ describe('Deduplication', () => {
163166
})
164167
})
165168

169+
it('isClassInstance', () => {
170+
class Foo {}
171+
class Bar {}
172+
abstract class Baz {}
173+
const FooBar = class {}
174+
class FooBarBaz extends Baz {}
175+
176+
const fixtures: any[] = [
177+
[new Foo(), true],
178+
[new Bar(), true],
179+
[new FooBar(), true],
180+
[new FooBarBaz(), true],
181+
[{ foo: Foo }, false],
182+
[{ foo: 'bar', bar: new Bar() }, false],
183+
[[{ foo: Foo }, new Bar()], false]
184+
]
185+
186+
for (let i = 0; i < fixtures.length; i++) {
187+
expect(isClassInstance(fixtures[i][0]), `Fixture at index ${i}`).toEqual(fixtures[i][1])
188+
}
189+
})
190+
191+
it('processCaptures', () => {
192+
// const mockClass
193+
class HelloWorld {}
194+
const outputArgs = {
195+
user: { name: 'John Doe' },
196+
hello: new HelloWorld(),
197+
res: new Response('Hello World')
198+
}
199+
const mockCaptures: (CapturedCall | CapturedFunction)[] = [
200+
{
201+
id: 'mock-call',
202+
invocations: [
203+
{
204+
args: [],
205+
output: outputArgs,
206+
timestamp: 0
207+
}
208+
]
209+
}
210+
]
211+
212+
expect(processCaptures(mockCaptures)).toEqual([
213+
{
214+
id: 'mock-call',
215+
invocations: [
216+
{
217+
args: [],
218+
output: {
219+
user: { name: 'John Doe' },
220+
hello: FLYTRAP_CLASS,
221+
res: FLYTRAP_RESPONSE
222+
},
223+
timestamp: 0
224+
}
225+
]
226+
}
227+
])
228+
})
229+
166230
/*describe.skip('Encrypting captures', async () => {
167231
it('TODO', async () => {
168232
expect(await encryptCaptures(mockCapturedCalls, '')).toEqual([])

0 commit comments

Comments
 (0)