flightcontrolhq / superjson

Safely serialize JavaScript expressions to a superset of JSON, which includes Dates, BigInts, and more.
https://www.flightcontrol.dev?ref=superjson
MIT License
4.01k stars 87 forks source link

Support for functions #55

Closed davidkpiano closed 4 years ago

davidkpiano commented 4 years ago

Hey, I've been exploring JSON serialization libraries to use with XState that supports serializing an entire machine definition.

One of the missing parts is the ability to serialize pure, isolated functions, such as:

// ...
{
  actions: [
    (context, event) => {
      /* do something with the args */
    }
  ]
}

I can do this ad-hoc, but it would be useful to have this within a library.

A source of inspiration can be intrinsic functions in Amazon States Language, just to show that there is a need for this:

"X": {
  "Type": "Task",
  "Resource": "arn:aws:states:us-east-1:123456789012:task:X",
  "Next": "Y",
  "Parameters": {
    "greeting.$": "States.Format('Welcome to {} {}\\'s playlist.', $.firstName, $.lastName)"
  }
}

Would this be something that might be considered?

Skn0tt commented 4 years ago

Interesting idea, indeed!

I‘ve thought a lot about adding support for functions. They‘re the one big thing that‘s missing from SuperJSON to consider it fully JS-compatible, so it‘d be quite intriguing, wouldn‘t it? On the other hand, you can’t just send a serialized function definition over the wire, as it‘d open the doors to remote code execution.

In this article on „defunctionalisation“, an interesting point is made: Can‘t we replace any function in our code with a description of it? Given the following code ...

// /adder.ts
function adder(a: number) {
  return function add(b: number) {
    return a + b;
  }
}

... when passing adder(5) to SuperJSON, SuperJSON could serialize it to /adder.ts:adder:5, right?

There‘s still big problems with this approach:

In contrast to Amazon States Language, SuperJSON needs to work for communication from untrusted parties (client) to trusted parties (server). That‘s why we have to deal with remote code execution.

While I can absolutely see the need for this, I don‘t really see a way to make this work, sadly ... If you‘ve got a Geistesblitz though, I‘d love to hear it! :D

davidkpiano commented 4 years ago

@Skn0tt That's fair; for my use-case, it is understood that the serialized JS code would be dangerous to execute, so it is just there for reference, or in a "here's the code; read it and if you trust it, run it" sort of way.