Skip to content

Native Promise accepted by types but not serializable at runtime #146

@VastBlast

Description

@VastBlast

When passing native promises in a stub call, a TypeError: Cannot serialize value: [object Promise] runtime error is thrown. No ts error is given.

It is unclear whether native promises are intended to be supported or not, since a comment in types.d.ts mentions all promises, even though the current library throws an error on native promises:

capnweb/src/types.d.ts

Lines 124 to 125 in 686da44

// You can put promises anywhere in the params and they'll be resolved before delivery.
// (This also covers RpcPromise, because it's defined as being a Promise.)

So depending on what is intended, this issue is either:

  1. a runtime bug, where it is not actually resolving promises before delivery
  2. or a ts typing bug

Are all promises supposed to be resolved by the library internally? Or does this library only handle RpcPromise?

Edit: It was confirmed here that it is a missing feature that will be worked on.

Here is a reproduction of the issue:

import { RpcPromise, RpcTarget, newMessagePortRpcSession } from "capnweb";

class MyApi extends RpcTarget {
  sayHello(): string {
    return 'hello'
  }

  formatMessage(message: string): string {
    return `server received: ${message}`;
  }

  formatObject(obj: Record<string, string>): string {
    let result = 'server received object with keys:\n';
    for (const key in obj) {
      result += `- ${key}: ${obj[key]}\n`;
    }
    return result;
  }
}

async function main() {
  const channel = new MessageChannel();
  newMessagePortRpcSession(channel.port1, new MyApi());
  const api = newMessagePortRpcSession<MyApi>(channel.port2);

  const pipelinedHello: RpcPromise<string> = api.sayHello();

  const out1 = api.formatMessage(pipelinedHello);

  const out2 = api.formatMessage(api.sayHello());

  const out3 = api.formatObject({
    greeting: pipelinedHello,
    direct: api.sayHello(),
    formatted: out2,
    static: 'static value',
  });

  console.log(await out1); // success
  console.log(await out2); // success
  console.log(await out3); // success

  const nativePromise = Promise.resolve(pipelinedHello);

  // no ts error given below, but these are actually runtime errors because native Promise values aren't serializable by capnweb
  // and aren't automatically resolved like RpcPromise values are.
  api.formatMessage(nativePromise); // throws TypeError: Cannot serialize value: [object Promise]

  api.formatMessage(Promise.resolve("not actually transportable")); // throws TypeError: Cannot serialize value: [object Promise]

  api.formatObject({
    validKey: pipelinedHello,
    invalidKey: Promise.resolve("not transportable")
  }) // throws TypeError: Cannot serialize value: [object Promise]
}

main();

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions