Skip to content

@mettascript/das-client and @mettascript/das-gateway

The Distributed AtomSpace feature is split in two. @mettascript/das-client is the Node client for a live DAS Query Agent and local transport-backed spaces. @mettascript/das-gateway is the browser-facing query codec over an injected HTTP transport.

bash
npm install @mettascript/das-client @mettascript/das-gateway

Use the client when Node can host the inbound DAS bus node. Use the gateway when a browser needs to reach a server-side DAS bridge.

Client spaces and transports

ts
interface DasTransport {
  query(pattern: Atom): Bindings[];
  add(atom: Atom): void;
  remove(atom: Atom): boolean;
  atoms(): readonly Atom[];
}

class MockTransport implements DasTransport {
  constructor(store?: Atom[]);
}

class DasSpace implements Space {
  constructor(transport: DasTransport);
  add(atom: Atom): void;
  remove(atom: Atom): boolean;
  query(pattern: Atom): Bindings[];
  atoms(): readonly Atom[];
}

DasSpace implements the core Space interface by delegating to a DasTransport. MockTransport keeps tests and offline examples on the same path without a remote DAS.

ts
import { 
DasSpace
,
MockTransport
} from "@mettascript/das-client";
import {
expr
,
format
,
instantiate
,
sym
,
variable
, type
Atom
} from "@mettascript/core";
const
A
= (...
items
:
Atom
[]) =>
expr
(
items
);
const
transport
= new
MockTransport
([
A
(
sym
("parent"),
sym
("Tom"),
sym
("Ada"))]);
const
space
= new
DasSpace
(
transport
);
const
child
=
variable
("child");
const
bindings
=
space
.
query
(
A
(
sym
("parent"),
sym
("Tom"),
child
));
console
.
log
(
bindings
.
map
((
b
) =>
format
(
instantiate
(
b
,
child
)))); // ["Ada"]

Query tokens and live queries

ts
type Pattern =
  | { kind: "node"; type: string; name: string }
  | { kind: "var"; name: string }
  | { kind: "atom"; handle: string }
  | { kind: "expr"; children: Pattern[] };

function node(name: string, type?: string): Pattern;
function variable(name: string): Pattern;
function expr(...children: Pattern[]): Pattern;
function encodeQuery(p: Pattern, linkType?: string): string[];

node, variable, and expr build the DAS pattern tree. encodeQuery turns it into the prefix token stream used by DAS pattern matching. A link with any nested variable becomes a LINK_TEMPLATE; a ground link becomes a LINK.

ts
interface QueryOptions {
  readonly proxyHost?: string;
  readonly agentAddress: string;
  readonly pattern: Pattern;
  readonly context?: string;
  readonly timeoutMs?: number;
  readonly populateMettaMapping?: boolean;
}

interface QueryResult {
  readonly answers: QueryAnswer[];
  readonly finished: boolean;
  readonly aborted: boolean;
}

function queryPatternMatching(opts: QueryOptions): Promise<QueryResult>;

queryPatternMatching hosts an inbound proxy node, sends a pattern_matching_query to the Query Agent, waits for streamed answer bundles, and decodes them.

The client exports the lower-level bus and answer helpers for hosts that need the protocol boundary:

ts
class BusNode {
  constructor(address: string, onMessage?: MessageHandler);
  start(): Promise<void>;
  send(peer: string, message: MessageData): Promise<void>;
  ping(peer: string): Promise<Ack>;
  stop(): Promise<void>;
}

const BusCommand: {
  readonly ping: "ping";
  readonly ack: "ack";
  readonly nodeJoinedNetwork: "node_joined_network";
  readonly busCommandProxy: "bus_command_proxy";
  readonly queryAnswerTokensFlow: "query_answer_tokens_flow";
};

function parseQueryAnswer(token: string): QueryAnswer;
function collectAnswers(messages: readonly { command: string; args: string[] }[]): QueryResult;
function unwrapProxyMessage(args: readonly string[]): { command: string; args: string[] };
const PROXY_COMMAND: string;
const ANSWER_BUNDLE: string;
const FINISHED: string;
const ABORT: string;

Hashing

ts
function computeHash(input: string): string;
function namedTypeHash(name: string): string;
function terminalHash(type: string, name: string): string;
function compositeHash(elements: readonly string[]): string;
function expressionHash(typeHash: string, elements: readonly string[]): string;

These helpers reproduce DAS atom-handle hashing. Query handles must match the handles stored in AtomDB, or a live query will miss.

Async spaces

ts
interface AsyncSpace {
  queryAsync(pattern: Atom): Promise<Bindings[]>;
}

class DasLiveSpace implements AsyncSpace {
  constructor(agentAddress: string, proxyHost?: string, timeoutMs?: number);
  queryAsync(pattern: Atom): Promise<Bindings[]>;
}

function atomToPattern(atom: Atom): Pattern;
function matchAsync(space: AsyncSpace, pattern: Atom, template?: Atom): Promise<Atom[]>;

DasLiveSpace queries a live DAS Query Agent and resolves returned handles through the answer's MeTTa mapping. matchAsync is the async analogue of (match space pattern template).

ts
import { 
DasLiveSpace
,
matchAsync
} from "@mettascript/das-client";
import {
expr
,
sym
,
variable
, type
Atom
} from "@mettascript/core";
const
A
= (...
items
:
Atom
[]) =>
expr
(
items
);
const
live
= new
DasLiveSpace
("127.0.0.1:40002");
const
results
= await
matchAsync
(
live
,
A
(
sym
("parent"),
sym
("Tom"),
variable
("child")));
console
.
log
(
results
.
map
(
String
));

Gateway

ts
interface QueryRequest {
  readonly space: string;
  readonly pattern: string;
}

interface QueryResponse {
  readonly bindings: ReadonlyArray<ReadonlyArray<readonly [string, string]>>;
}

interface GatewayTransport {
  query(req: QueryRequest): Promise<QueryResponse>;
}

const encodePattern: (a: Atom) => string;
const decodeBindings: (resp: QueryResponse) => Bindings[];
function queryDas(transport: GatewayTransport, space: string, pattern: Atom): Promise<Bindings[]>;

queryDas encodes the query pattern as MeTTa source, sends it through the transport, and decodes each returned binding value as exactly one MeTTa atom. Blank, malformed, bang-prefixed, and multi-atom binding values throw at decode time.

ts
import { 
queryDas
, type GatewayTransport } from "@mettascript/das-gateway";
import {
parse
,
standardTokenizer
} from "@mettascript/core";
const
transport
: GatewayTransport = {
query
: async (
request
) => {
console
.
log
(
request
.
pattern
);
return {
bindings
: [[["x", "Ada"]]] };
}, }; const
pattern
=
parse
("(parent Tom $x)",
standardTokenizer
())!;
const
bindings
= await
queryDas
(
transport
, "&self",
pattern
);
console
.
log
(
bindings
.
length
); // 1

See Distributed AtomSpace for the live DAS setup flow and the browser gateway shape.

Released under the MIT License.