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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions