componentized/directory

componentized:valkey-client

component

A WASM component client for Valkey (and Redis).

Imports

Exports

WIT

package root:component;

world root {
  import wasi:sockets/network@0.2.3;
  import wasi:sockets/instance-network@0.2.3;
  import wasi:io/poll@0.2.3;
  import wasi:io/error@0.2.3;
  import wasi:io/streams@0.2.3;
  import wasi:sockets/tcp@0.2.3;
  import wasi:sockets/tcp-create-socket@0.2.3;
  import wasi:sockets/ip-name-lookup@0.2.3;
  import wasi:config/store@0.2.0-rc.1;

  export componentized:valkey/resp;
  export componentized:valkey/store;
  export wasi:keyvalue/store@0.2.0-draft2;
  export wasi:keyvalue/atomics@0.2.0-draft2;
  export wasi:keyvalue/batch@0.2.0-draft2;
}
package componentized:valkey {
  interface resp {
    type error = string;

    type nested-value = list<u8>;

    variant value {
      %string(string),
      error(string),
      integer(s64),
      bulk-string(string),
      array(list<nested-value>),
      null,
      boolean(bool),
      double(f64),
      big-number(string),
      bulk-error(string),
      verbatim-string(tuple<string, string>),
      %map(list<tuple<nested-value, nested-value>>),
      set(list<nested-value>),
      push(list<nested-value>),
    }

    decode: func(data: list<u8>) -> result<value, error>;

    encode: func(value: value) -> result<list<u8>, error>;
  }
  interface store {
    use resp.{error as resp-error, value};

    variant error {
      client(string),
      resp(resp-error),
      valkey(string),
    }

    record hello-opts {
      proto-ver: option<string>,
      auth: option<tuple<string, string>>,
      client-name: option<string>,
    }

    record hrandfield-opts {
      count: option<s64>,
      with-values: option<bool>,
    }

    record hscan-opts {
      match: option<string>,
      count: option<s64>,
      no-values: option<bool>,
    }

    resource connection {
      send: func(command: list<value>) -> result<value, error>;
      acl-deluser: func(username: string) -> result<_, error>;
      acl-genpass: func() -> result<string, error>;
      acl-setuser: func(username: string, rules: list<string>) -> result<_, error>;
      auth: func(username: string, password: string) -> result<_, error>;
      del: func(key: string) -> result<_, error>;
      exists: func(key: string) -> result<bool, error>;
      get: func(key: string) -> result<option<string>, error>;
      hdel: func(key: string, field: string) -> result<_, error>;
      hello: func(opts: option<hello-opts>) -> result<list<tuple<string, value>>, error>;
      hexists: func(key: string, field: string) -> result<bool, error>;
      hget: func(key: string, field: string) -> result<option<string>, error>;
      hgetall: func(key: string) -> result<list<tuple<string, string>>, error>;
      hincrby: func(key: string, field: string, increment: s64) -> result<s64, error>;
      hincrbyfloat: func(key: string, field: string, increment: f64) -> result<string, error>;
      hkeys: func(key: string) -> result<list<string>, error>;
      hlen: func(key: string) -> result<u64, error>;
      hmget: func(key: string, fields: list<string>) -> result<list<option<string>>, error>;
      hmset: func(key: string, fields: list<tuple<string, string>>) -> result<_, error>;
      hrandfield: func(key: string, opts: option<hrandfield-opts>) -> result<option<list<tuple<string, option<string>>>>, error>;
      hscan: func(key: string, cursor: option<string>, opts: option<hscan-opts>) -> result<tuple<option<string>, list<tuple<string, option<string>>>>, error>;
      hset: func(key: string, field: string, value: string) -> result<_, error>;
      hsetnx: func(key: string, field: string, value: string) -> result<bool, error>;
      hstrlen: func(key: string, field: string) -> result<u64, error>;
      hvals: func(key: string) -> result<list<string>, error>;
      incr: func(key: string) -> result<s64, error>;
      incrby: func(key: string, increment: s64) -> result<s64, error>;
      keys: func(pattern: string) -> result<list<string>, error>;
      ping: func() -> result<_, error>;
      publish: func(channel: string, message: string) -> result<s64, error>;
      quit: func() -> result<_, error>;
      set: func(key: string, value: string) -> result<_, error>;
    }

    connect: func(host: string, port: u16, opts: option<hello-opts>) -> result<connection, error>;
  }
}


package wasi:io@0.2.3 {
  interface poll {
    resource pollable {
      block: func();
    }
  }
  interface error {
    resource error {
      to-debug-string: func() -> string;
    }
  }
  interface streams {
    use error.{error};

    resource input-stream {
      blocking-read: func(len: u64) -> result<list<u8>, stream-error>;
    }

    variant stream-error {
      last-operation-failed(error),
      closed,
    }

    resource output-stream {
      blocking-write-and-flush: func(contents: list<u8>) -> result<_, stream-error>;
    }
  }
}


package wasi:sockets@0.2.3 {
  interface network {
    resource network;

    type ipv4-address = tuple<u8, u8, u8, u8>;

    record ipv4-socket-address {
      port: u16,
      address: ipv4-address,
    }

    type ipv6-address = tuple<u16, u16, u16, u16, u16, u16, u16, u16>;

    record ipv6-socket-address {
      port: u16,
      flow-info: u32,
      address: ipv6-address,
      scope-id: u32,
    }

    variant ip-socket-address {
      ipv4(ipv4-socket-address),
      ipv6(ipv6-socket-address),
    }

    enum error-code {
      unknown,
      access-denied,
      not-supported,
      invalid-argument,
      out-of-memory,
      timeout,
      concurrency-conflict,
      not-in-progress,
      would-block,
      invalid-state,
      new-socket-limit,
      address-not-bindable,
      address-in-use,
      remote-unreachable,
      connection-refused,
      connection-reset,
      connection-aborted,
      datagram-too-large,
      name-unresolvable,
      temporary-resolver-failure,
      permanent-resolver-failure,
    }

    enum ip-address-family {
      ipv4,
      ipv6,
    }

    variant ip-address {
      ipv4(ipv4-address),
      ipv6(ipv6-address),
    }
  }
  interface instance-network {
    use network.{network};

    instance-network: func() -> network;
  }
  interface tcp {
    use network.{network, ip-socket-address, error-code};
    use wasi:io/streams@0.2.3.{input-stream, output-stream};
    use wasi:io/poll@0.2.3.{pollable};

    resource tcp-socket {
      start-connect: func(network: borrow<network>, remote-address: ip-socket-address) -> result<_, error-code>;
      finish-connect: func() -> result<tuple<input-stream, output-stream>, error-code>;
      subscribe: func() -> pollable;
    }
  }
  interface tcp-create-socket {
    use network.{ip-address-family};
    use tcp.{tcp-socket};
    use network.{error-code};

    create-tcp-socket: func(address-family: ip-address-family) -> result<tcp-socket, error-code>;
  }
  interface ip-name-lookup {
    use network.{ip-address, error-code};
    use wasi:io/poll@0.2.3.{pollable};
    use network.{network};

    resource resolve-address-stream {
      resolve-next-address: func() -> result<option<ip-address>, error-code>;
      subscribe: func() -> pollable;
    }

    resolve-addresses: func(network: borrow<network>, name: string) -> result<resolve-address-stream, error-code>;
  }
}


package wasi:config@0.2.0-rc.1 {
  interface store {
    variant error {
      upstream(string),
      io(string),
    }

    get: func(key: string) -> result<option<string>, error>;
  }
}


package wasi:keyvalue@0.2.0-draft2 {
  interface store {
    variant error {
      no-such-store,
      access-denied,
      other(string),
    }

    record key-response {
      keys: list<string>,
      cursor: option<string>,
    }

    resource bucket {
      get: func(key: string) -> result<option<list<u8>>, error>;
      set: func(key: string, value: list<u8>) -> result<_, error>;
      delete: func(key: string) -> result<_, error>;
      exists: func(key: string) -> result<bool, error>;
      list-keys: func(cursor: option<string>) -> result<key-response, error>;
    }

    open: func(identifier: string) -> result<bucket, error>;
  }
  interface atomics {
    use store.{bucket, error};

    resource cas {
      new: static func(bucket: borrow<bucket>, key: string) -> result<cas, error>;
      current: func() -> result<option<list<u8>>, error>;
    }

    variant cas-error {
      store-error(error),
      cas-failed(cas),
    }

    increment: func(bucket: borrow<bucket>, key: string, delta: s64) -> result<s64, error>;

    swap: func(cas: cas, value: list<u8>) -> result<_, cas-error>;
  }
  interface batch {
    use store.{bucket, error};

    get-many: func(bucket: borrow<bucket>, keys: list<string>) -> result<list<option<tuple<string, list<u8>>>>, error>;

    set-many: func(bucket: borrow<bucket>, key-values: list<tuple<string, list<u8>>>) -> result<_, error>;

    delete-many: func(bucket: borrow<bucket>, keys: list<string>) -> result<_, error>;
  }
}