@plexspaces/sdk 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +225 -0
- package/dist/actor.d.ts +81 -0
- package/dist/actor.js +484 -0
- package/dist/actor.test.d.ts +1 -0
- package/dist/actor.test.js +171 -0
- package/dist/actor_id.d.ts +46 -0
- package/dist/actor_id.js +85 -0
- package/dist/decorators.d.ts +40 -0
- package/dist/decorators.js +97 -0
- package/dist/host.d.ts +312 -0
- package/dist/host.js +828 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +14 -0
- package/dist/leader_worker.d.ts +36 -0
- package/dist/leader_worker.js +119 -0
- package/dist/process_groups.d.ts +4 -0
- package/dist/process_groups.js +14 -0
- package/dist/proto.d.ts +33 -0
- package/dist/proto.js +10 -0
- package/dist/router.d.ts +37 -0
- package/dist/router.js +78 -0
- package/dist/wire/http-fetch-proto-wire.d.ts +7 -0
- package/dist/wire/http-fetch-proto-wire.js +101 -0
- package/dist/wire/proto-wire-common.d.ts +18 -0
- package/dist/wire/proto-wire-common.js +91 -0
- package/dist/wire/registry-proto-wire.d.ts +41 -0
- package/dist/wire/registry-proto-wire.js +280 -0
- package/dist/wire/shard-group-proto-wire.d.ts +7 -0
- package/dist/wire/shard-group-proto-wire.js +723 -0
- package/dist/wire/tuplespace-proto-wire.d.ts +8 -0
- package/dist/wire/tuplespace-proto-wire.js +183 -0
- package/dist/wit-payload.d.ts +23 -0
- package/dist/wit-payload.js +42 -0
- package/dist/workflow.d.ts +14 -0
- package/dist/workflow.js +47 -0
- package/package.json +36 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsed form of a canonical PlexSpaces actor ID.
|
|
3
|
+
*
|
|
4
|
+
* Canonical string format: {name}//{actor_type}::{namespace}@{node_id}
|
|
5
|
+
*/
|
|
6
|
+
export declare class ActorID {
|
|
7
|
+
/** Unique instance identifier (role name or ULID). */
|
|
8
|
+
readonly name: string;
|
|
9
|
+
/** Behavior type registered in the application (e.g. 'budget_manager'). */
|
|
10
|
+
readonly actorType: string;
|
|
11
|
+
/** Application namespace (e.g. 'go-resource-aware-inference'). */
|
|
12
|
+
readonly namespace: string;
|
|
13
|
+
/** Node hosting the actor (e.g. 'test-node-8091'). Empty string if absent. */
|
|
14
|
+
readonly nodeId: string;
|
|
15
|
+
constructor(name: string, actorType: string, namespace: string, nodeId: string);
|
|
16
|
+
/**
|
|
17
|
+
* Parse a canonical actor ID string into an ActorID.
|
|
18
|
+
*
|
|
19
|
+
* Expected format: {name}//{actor_type}::{namespace}@{node_id}
|
|
20
|
+
* Throws if the string does not contain the expected separators.
|
|
21
|
+
*/
|
|
22
|
+
static parse(id: string): ActorID;
|
|
23
|
+
/** Return the canonical actor ID string: {name}//{actor_type}::{namespace}@{node_id}. */
|
|
24
|
+
toString(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Return a copy with an explicit actor type and name.
|
|
27
|
+
*
|
|
28
|
+
* Use this to build a canonical ID for a peer actor with the given type and name,
|
|
29
|
+
* keeping the same namespace and node.
|
|
30
|
+
*
|
|
31
|
+
* For supervisor-spawned actors with stable role names (name == type == role):
|
|
32
|
+
* ```ts
|
|
33
|
+
* const peer = self.withTypeAndName("budget_manager", "budget_manager");
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* For actors where name and type differ (e.g. ULID-named workers of a shared type):
|
|
37
|
+
* ```ts
|
|
38
|
+
* const peer = self.withTypeAndName("inference_worker", ulid);
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
withTypeAndName(actorType: string, name: string): ActorID;
|
|
42
|
+
/** Return a copy with a different name. */
|
|
43
|
+
withName(name: string): ActorID;
|
|
44
|
+
/** Return a copy with a different name and actor_type. */
|
|
45
|
+
withType(name: string, actorType: string): ActorID;
|
|
46
|
+
}
|
package/dist/actor_id.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2025 PlexSpaces Contributors
|
|
3
|
+
//
|
|
4
|
+
// ActorID — parsed representation of a canonical PlexSpaces actor ID.
|
|
5
|
+
//
|
|
6
|
+
// Canonical format: {name}//{actor_type}::{namespace}@{node_id}
|
|
7
|
+
//
|
|
8
|
+
// The name is typically a stable role name for supervisor-spawned actors,
|
|
9
|
+
// or a ULID for dynamically spawned actors.
|
|
10
|
+
//
|
|
11
|
+
// Usage — peer/sibling discovery from within a WASM actor:
|
|
12
|
+
//
|
|
13
|
+
// const selfID = ActorID.parse(host.selfId());
|
|
14
|
+
// const budgetID = selfID.sibling("budget_manager");
|
|
15
|
+
// const reply = await host.ask(budgetID.toString(), payload, 5000);
|
|
16
|
+
/**
|
|
17
|
+
* Parsed form of a canonical PlexSpaces actor ID.
|
|
18
|
+
*
|
|
19
|
+
* Canonical string format: {name}//{actor_type}::{namespace}@{node_id}
|
|
20
|
+
*/
|
|
21
|
+
export class ActorID {
|
|
22
|
+
constructor(name, actorType, namespace, nodeId) {
|
|
23
|
+
this.name = name;
|
|
24
|
+
this.actorType = actorType;
|
|
25
|
+
this.namespace = namespace;
|
|
26
|
+
this.nodeId = nodeId;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse a canonical actor ID string into an ActorID.
|
|
30
|
+
*
|
|
31
|
+
* Expected format: {name}//{actor_type}::{namespace}@{node_id}
|
|
32
|
+
* Throws if the string does not contain the expected separators.
|
|
33
|
+
*/
|
|
34
|
+
static parse(id) {
|
|
35
|
+
const slashIdx = id.indexOf("//");
|
|
36
|
+
if (slashIdx < 0) {
|
|
37
|
+
throw new Error(`parseActorID: missing '//' in ${JSON.stringify(id)}`);
|
|
38
|
+
}
|
|
39
|
+
const name = id.slice(0, slashIdx);
|
|
40
|
+
const rest = id.slice(slashIdx + 2); // "{actor_type}::{namespace}@{node_id}"
|
|
41
|
+
// Split on "@" to separate type::namespace from node_id
|
|
42
|
+
const atIdx = rest.indexOf("@");
|
|
43
|
+
const nodeId = atIdx >= 0 ? rest.slice(atIdx + 1) : "";
|
|
44
|
+
const typeNs = atIdx >= 0 ? rest.slice(0, atIdx) : rest;
|
|
45
|
+
// Split on "::" to separate actor_type from namespace
|
|
46
|
+
const colonIdx = typeNs.indexOf("::");
|
|
47
|
+
const actorType = colonIdx >= 0 ? typeNs.slice(0, colonIdx) : typeNs;
|
|
48
|
+
const namespace = colonIdx >= 0 ? typeNs.slice(colonIdx + 2) : "";
|
|
49
|
+
return new ActorID(name, actorType, namespace, nodeId);
|
|
50
|
+
}
|
|
51
|
+
/** Return the canonical actor ID string: {name}//{actor_type}::{namespace}@{node_id}. */
|
|
52
|
+
toString() {
|
|
53
|
+
if (this.nodeId) {
|
|
54
|
+
return `${this.name}//${this.actorType}::${this.namespace}@${this.nodeId}`;
|
|
55
|
+
}
|
|
56
|
+
return `${this.name}//${this.actorType}::${this.namespace}`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Return a copy with an explicit actor type and name.
|
|
60
|
+
*
|
|
61
|
+
* Use this to build a canonical ID for a peer actor with the given type and name,
|
|
62
|
+
* keeping the same namespace and node.
|
|
63
|
+
*
|
|
64
|
+
* For supervisor-spawned actors with stable role names (name == type == role):
|
|
65
|
+
* ```ts
|
|
66
|
+
* const peer = self.withTypeAndName("budget_manager", "budget_manager");
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* For actors where name and type differ (e.g. ULID-named workers of a shared type):
|
|
70
|
+
* ```ts
|
|
71
|
+
* const peer = self.withTypeAndName("inference_worker", ulid);
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
withTypeAndName(actorType, name) {
|
|
75
|
+
return new ActorID(name, actorType, this.namespace, this.nodeId);
|
|
76
|
+
}
|
|
77
|
+
/** Return a copy with a different name. */
|
|
78
|
+
withName(name) {
|
|
79
|
+
return new ActorID(name, this.actorType, this.namespace, this.nodeId);
|
|
80
|
+
}
|
|
81
|
+
/** Return a copy with a different name and actor_type. */
|
|
82
|
+
withType(name, actorType) {
|
|
83
|
+
return new ActorID(name, actorType, this.namespace, this.nodeId);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type BehaviorType = 'GenServer' | 'GenEvent' | 'GenStateMachine' | 'Workflow';
|
|
2
|
+
export type InvocationType = 'call' | 'cast';
|
|
3
|
+
export interface HandlerMetadata {
|
|
4
|
+
methodName: string;
|
|
5
|
+
msgTypes: string[];
|
|
6
|
+
invocation: InvocationType;
|
|
7
|
+
}
|
|
8
|
+
export interface ActorDefinitionMetadata {
|
|
9
|
+
behaviorType: BehaviorType;
|
|
10
|
+
facets: string[];
|
|
11
|
+
handlers: Record<string, HandlerMetadata>;
|
|
12
|
+
runHandler?: string;
|
|
13
|
+
signalHandlers: Record<string, string>;
|
|
14
|
+
queryHandlers: Record<string, string>;
|
|
15
|
+
fsmStates?: string[];
|
|
16
|
+
fsmInitial?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function actor(options?: {
|
|
19
|
+
facets?: string[];
|
|
20
|
+
}): <T extends Function>(target: T) => T;
|
|
21
|
+
export declare function gen_server_actor(options?: {
|
|
22
|
+
facets?: string[];
|
|
23
|
+
}): <T extends Function>(target: T) => T;
|
|
24
|
+
export declare function event_actor(options?: {
|
|
25
|
+
facets?: string[];
|
|
26
|
+
}): <T extends Function>(target: T) => T;
|
|
27
|
+
export declare function fsm_actor(options?: {
|
|
28
|
+
facets?: string[];
|
|
29
|
+
states?: string[];
|
|
30
|
+
initial?: string;
|
|
31
|
+
}): <T extends Function>(target: T) => T;
|
|
32
|
+
export declare function workflow_actor(options?: {
|
|
33
|
+
facets?: string[];
|
|
34
|
+
}): <T extends Function>(target: T) => T;
|
|
35
|
+
export declare function handler(...msgTypes: string[]): (target: object, propertyKey: string, _descriptor: PropertyDescriptor) => void;
|
|
36
|
+
export declare const init_handler: typeof handler;
|
|
37
|
+
export declare function run_handler(target: object, propertyKey: string, _descriptor: PropertyDescriptor): void;
|
|
38
|
+
export declare function signal_handler(...names: string[]): (target: object, propertyKey: string, _descriptor: PropertyDescriptor) => void;
|
|
39
|
+
export declare function query_handler(...names: string[]): (target: object, propertyKey: string, _descriptor: PropertyDescriptor) => void;
|
|
40
|
+
export declare function getActorDefinition(target: object): ActorDefinitionMetadata | undefined;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// Copyright (C) 2025 PlexSpaces Contributors
|
|
3
|
+
const ACTOR_METADATA = Symbol.for('plexspaces.actor.metadata');
|
|
4
|
+
function ensureMetadata(target) {
|
|
5
|
+
const ctor = typeof target === 'function' ? target : target.constructor;
|
|
6
|
+
const existing = Reflect.get(ctor, ACTOR_METADATA);
|
|
7
|
+
if (existing)
|
|
8
|
+
return existing;
|
|
9
|
+
const created = {
|
|
10
|
+
behaviorType: 'GenServer',
|
|
11
|
+
facets: [],
|
|
12
|
+
handlers: {},
|
|
13
|
+
signalHandlers: {},
|
|
14
|
+
queryHandlers: {},
|
|
15
|
+
};
|
|
16
|
+
Reflect.set(ctor, ACTOR_METADATA, created);
|
|
17
|
+
return created;
|
|
18
|
+
}
|
|
19
|
+
function actorDecorator(behaviorType, facets = []) {
|
|
20
|
+
return function (target) {
|
|
21
|
+
const metadata = ensureMetadata(target);
|
|
22
|
+
metadata.behaviorType = behaviorType;
|
|
23
|
+
metadata.facets = [...facets];
|
|
24
|
+
return target;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function actor(options = {}) {
|
|
28
|
+
return actorDecorator('GenServer', options.facets ?? []);
|
|
29
|
+
}
|
|
30
|
+
export function gen_server_actor(options = {}) {
|
|
31
|
+
return actorDecorator('GenServer', options.facets ?? []);
|
|
32
|
+
}
|
|
33
|
+
export function event_actor(options = {}) {
|
|
34
|
+
return actorDecorator('GenEvent', options.facets ?? []);
|
|
35
|
+
}
|
|
36
|
+
export function fsm_actor(options = {}) {
|
|
37
|
+
return function (target) {
|
|
38
|
+
const result = actorDecorator('GenStateMachine', options.facets ?? [])(target);
|
|
39
|
+
if (options.states !== undefined || options.initial !== undefined) {
|
|
40
|
+
const metadata = ensureMetadata(result);
|
|
41
|
+
if (options.states !== undefined)
|
|
42
|
+
metadata.fsmStates = [...options.states];
|
|
43
|
+
if (options.initial !== undefined)
|
|
44
|
+
metadata.fsmInitial = options.initial;
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function workflow_actor(options = {}) {
|
|
50
|
+
return actorDecorator('Workflow', options.facets ?? []);
|
|
51
|
+
}
|
|
52
|
+
export function handler(...msgTypes) {
|
|
53
|
+
let invocation = 'call';
|
|
54
|
+
const effectiveTypes = msgTypes.filter((value) => {
|
|
55
|
+
if (value === 'call' || value === 'cast') {
|
|
56
|
+
invocation = value;
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
});
|
|
61
|
+
return function (target, propertyKey, _descriptor) {
|
|
62
|
+
const metadata = ensureMetadata(target);
|
|
63
|
+
const entry = {
|
|
64
|
+
methodName: propertyKey,
|
|
65
|
+
msgTypes: effectiveTypes,
|
|
66
|
+
invocation,
|
|
67
|
+
};
|
|
68
|
+
for (const msgType of effectiveTypes) {
|
|
69
|
+
metadata.handlers[msgType] = entry;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export const init_handler = handler;
|
|
74
|
+
export function run_handler(target, propertyKey, _descriptor) {
|
|
75
|
+
const metadata = ensureMetadata(target);
|
|
76
|
+
metadata.runHandler = propertyKey;
|
|
77
|
+
}
|
|
78
|
+
export function signal_handler(...names) {
|
|
79
|
+
return function (target, propertyKey, _descriptor) {
|
|
80
|
+
const metadata = ensureMetadata(target);
|
|
81
|
+
for (const name of names) {
|
|
82
|
+
metadata.signalHandlers[name] = propertyKey;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export function query_handler(...names) {
|
|
87
|
+
return function (target, propertyKey, _descriptor) {
|
|
88
|
+
const metadata = ensureMetadata(target);
|
|
89
|
+
for (const name of names) {
|
|
90
|
+
metadata.queryHandlers[name] = propertyKey;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export function getActorDefinition(target) {
|
|
95
|
+
const ctor = typeof target === 'function' ? target : target.constructor;
|
|
96
|
+
return Reflect.get(ctor, ACTOR_METADATA);
|
|
97
|
+
}
|
package/dist/host.d.ts
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { ObjectType as RegistryObjectType } from './wire/registry-proto-wire.js';
|
|
2
|
+
/**
|
|
3
|
+
* Tuple space helper: list-in, list-out API.
|
|
4
|
+
* Use null in patterns for wildcards. Consistent with Python host.ts and Go host.TS().
|
|
5
|
+
*/
|
|
6
|
+
export declare class TupleSpace {
|
|
7
|
+
private host;
|
|
8
|
+
constructor(host: Host);
|
|
9
|
+
/**
|
|
10
|
+
* Write a tuple. Values are encoded as plexspaces.tuplespace.v1 WriteRequest protobuf wire
|
|
11
|
+
* (same as Go `TupleSpace.Write` / Rust simple_component_host).
|
|
12
|
+
*/
|
|
13
|
+
write(tuple: unknown[]): string;
|
|
14
|
+
/** Take one matching tuple (destructive). */
|
|
15
|
+
take(pattern: unknown[]): unknown[] | null;
|
|
16
|
+
/** Read one matching tuple (non-destructive). */
|
|
17
|
+
read(pattern: unknown[]): unknown[] | null;
|
|
18
|
+
/** Read all matching tuples (non-destructive). */
|
|
19
|
+
readAll(pattern: unknown[]): unknown[][];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Process groups sub-API.
|
|
23
|
+
* broadcast(group, msgType, payload): msgType is used by the host for routing; payload can be data-only.
|
|
24
|
+
*/
|
|
25
|
+
export declare class ProcessGroups {
|
|
26
|
+
/** Join a named process group */
|
|
27
|
+
join(group: string): void;
|
|
28
|
+
/** Leave a named process group */
|
|
29
|
+
leave(group: string): void;
|
|
30
|
+
/** Get members of a process group */
|
|
31
|
+
members(group: string): string[];
|
|
32
|
+
/** Broadcast to all group members. msgType is used for routing so payload can be data-only. */
|
|
33
|
+
broadcast(group: string, msgType: string, payload?: unknown): void;
|
|
34
|
+
/** Return the first member of a process group, or null if empty. */
|
|
35
|
+
first(group: string): string | null;
|
|
36
|
+
/** Return the first member of a process group, throwing if empty. */
|
|
37
|
+
firstOrThrow(group: string): string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* PlexSpaces host function interface.
|
|
41
|
+
*
|
|
42
|
+
* Provides typed access to all WIT host capabilities.
|
|
43
|
+
*
|
|
44
|
+
* Usage:
|
|
45
|
+
* import { host } from '@plexspaces/sdk';
|
|
46
|
+
*
|
|
47
|
+
* host.send('other-actor', 'ping', { data: 'hello' });
|
|
48
|
+
* const response = host.ask('other-actor', 'get_balance', {}, 5000);
|
|
49
|
+
* const myId = host.selfId();
|
|
50
|
+
*/
|
|
51
|
+
/** Object registration data from the registry. */
|
|
52
|
+
export interface ObjectRegistration {
|
|
53
|
+
objectId: string;
|
|
54
|
+
objectType: string;
|
|
55
|
+
grpcAddress?: string;
|
|
56
|
+
objectCategory?: string;
|
|
57
|
+
tenantId?: string;
|
|
58
|
+
namespace?: string;
|
|
59
|
+
capabilities?: string[];
|
|
60
|
+
labels?: string[];
|
|
61
|
+
healthStatus?: string;
|
|
62
|
+
createdAt?: number;
|
|
63
|
+
updatedAt?: number;
|
|
64
|
+
lastHeartbeat?: number;
|
|
65
|
+
alias?: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Object Registry host functions for registration and discovery.
|
|
69
|
+
*
|
|
70
|
+
* All calls encode request/response as proto wire bytes matching
|
|
71
|
+
* plexspaces.object_registry.v1 messages.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* // Register this actor
|
|
76
|
+
* host.registry.register({ objectId: myId, objectType: 'actor', objectCategory: 'GenServer' });
|
|
77
|
+
*
|
|
78
|
+
* // Look up by alias (Orleans grain directory pattern)
|
|
79
|
+
* const reg = host.registry.lookupByAlias('Counter:my-counter:default:tenant1');
|
|
80
|
+
*
|
|
81
|
+
* // Discover all actors of a given category
|
|
82
|
+
* const actors = host.registry.discover({ objectType: RegistryObjectType.ACTOR, objectCategory: 'GenServer' });
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare class Registry {
|
|
86
|
+
/**
|
|
87
|
+
* Register an object in the registry.
|
|
88
|
+
*/
|
|
89
|
+
register(reg: ObjectRegistration): void;
|
|
90
|
+
/**
|
|
91
|
+
* Unregister an object from the registry.
|
|
92
|
+
*/
|
|
93
|
+
unregister(objectId: string, objectType: number, tenantId?: string, namespace?: string): void;
|
|
94
|
+
/**
|
|
95
|
+
* Look up an object by ID. Returns null if not found, throws on storage errors.
|
|
96
|
+
*/
|
|
97
|
+
lookup(objectId: string, objectType?: number, tenantId?: string, namespace?: string): ObjectRegistration | null;
|
|
98
|
+
/**
|
|
99
|
+
* Look up an object by alias (Orleans grain directory pattern).
|
|
100
|
+
* Alias format: "{actor_type}:{name}:{namespace}:{tenant_id}"
|
|
101
|
+
* Returns null if not found, throws on storage errors.
|
|
102
|
+
*/
|
|
103
|
+
lookupByAlias(alias: string): ObjectRegistration | null;
|
|
104
|
+
/**
|
|
105
|
+
* Discover objects with optional filtering.
|
|
106
|
+
*/
|
|
107
|
+
discover(options?: {
|
|
108
|
+
objectType?: number;
|
|
109
|
+
objectCategory?: string;
|
|
110
|
+
tenantId?: string;
|
|
111
|
+
namespace?: string;
|
|
112
|
+
capabilities?: string[];
|
|
113
|
+
labels?: string[];
|
|
114
|
+
pageSize?: number;
|
|
115
|
+
}): ObjectRegistration[];
|
|
116
|
+
/**
|
|
117
|
+
* Update the heartbeat for a registered object.
|
|
118
|
+
*/
|
|
119
|
+
heartbeat(objectId: string, objectType?: number, tenantId?: string, namespace?: string): void;
|
|
120
|
+
}
|
|
121
|
+
export { RegistryObjectType };
|
|
122
|
+
export declare class Host {
|
|
123
|
+
readonly processGroups: ProcessGroups;
|
|
124
|
+
/** Tuple space: list-in, list-out. Use null in patterns for wildcards. */
|
|
125
|
+
readonly ts: TupleSpace;
|
|
126
|
+
/** Object registry: register, discover, and look up actors and services. */
|
|
127
|
+
readonly registry: Registry;
|
|
128
|
+
/** Send message to another actor (fire-and-forget) */
|
|
129
|
+
send(to: string, msgType: string, payload?: unknown): string;
|
|
130
|
+
/** Send request and wait for response (request-reply) */
|
|
131
|
+
ask(to: string, msgType: string, payload?: unknown, timeoutMs?: number): unknown;
|
|
132
|
+
/** Get own actor ID */
|
|
133
|
+
selfId(): string;
|
|
134
|
+
/**
|
|
135
|
+
* Spawn a new actor through the framework-owned actor spawn path exposed by the host.
|
|
136
|
+
* @param moduleRef - Actor type/module reference (must be deployed)
|
|
137
|
+
* @param actorId - Unique ID for the new actor (empty = auto-generated ULID)
|
|
138
|
+
* @param initConfig - Optional config passed to the new actor's init()
|
|
139
|
+
* @returns Spawned actor ID string (may be auto-generated if actorId was empty)
|
|
140
|
+
*/
|
|
141
|
+
spawn(moduleRef: string, actorId?: string, initConfig?: unknown): string;
|
|
142
|
+
/** Stop an actor gracefully */
|
|
143
|
+
stop(actorId: string): void;
|
|
144
|
+
/** Bidirectional link */
|
|
145
|
+
link(actorId: string): void;
|
|
146
|
+
/** Remove bidirectional link */
|
|
147
|
+
unlink(actorId: string): void;
|
|
148
|
+
/** Monitor an actor (returns monitor reference) */
|
|
149
|
+
monitor(actorId: string): string;
|
|
150
|
+
/** Cancel a monitor */
|
|
151
|
+
demonitor(monitorRef: string): void;
|
|
152
|
+
/**
|
|
153
|
+
* Send message to self after delay (returns timer ID for tracking).
|
|
154
|
+
* Timer cancellation is managed by the framework's TimerFacet/ReminderFacet.
|
|
155
|
+
* Stop the actor to cancel pending timers.
|
|
156
|
+
*
|
|
157
|
+
* WIT `payload` is opaque bytes; pass UTF-8 JSON bytes so the host matches Go/Rust guest JSON.
|
|
158
|
+
*/
|
|
159
|
+
sendAfter(delayMs: number, msgType: string, payload?: unknown): string;
|
|
160
|
+
/** Log a message */
|
|
161
|
+
log(level: string, message: string): void;
|
|
162
|
+
debug(message: string): void;
|
|
163
|
+
info(message: string): void;
|
|
164
|
+
warn(message: string): void;
|
|
165
|
+
error(message: string): void;
|
|
166
|
+
/** Get current timestamp in milliseconds */
|
|
167
|
+
nowMs(): number;
|
|
168
|
+
kvGet(key: string): string;
|
|
169
|
+
kvPut(key: string, value: string): string;
|
|
170
|
+
kvDelete(key: string): string;
|
|
171
|
+
kvList(prefix: string): string;
|
|
172
|
+
/** Retrieve a JSON value by key. Returns parsed object or null if not found. */
|
|
173
|
+
kvGetJson<T = unknown>(key: string): T | null;
|
|
174
|
+
/** Serialize value to JSON and store under key. Throws on write failure. */
|
|
175
|
+
kvPutJson(key: string, value: unknown): void;
|
|
176
|
+
/** Increment a single named application metric counter by 1. Errors are swallowed. */
|
|
177
|
+
incrCounter(applicationId: string, name: string): void;
|
|
178
|
+
/** Increment one or more named application metric counters. Errors are swallowed. */
|
|
179
|
+
incrCounters(applicationId: string, counters: Record<string, number>): void;
|
|
180
|
+
/** @internal TupleSpace — plexspaces.tuplespace.v1 wire bytes. */
|
|
181
|
+
tsWritePayload(data: Uint8Array): string;
|
|
182
|
+
/** @internal */
|
|
183
|
+
tsReadPayload(data: Uint8Array): Uint8Array;
|
|
184
|
+
/** @internal */
|
|
185
|
+
tsTakePayload(data: Uint8Array): Uint8Array;
|
|
186
|
+
/** @internal */
|
|
187
|
+
tsReadAllPayload(data: Uint8Array): Uint8Array;
|
|
188
|
+
lockAcquire(tenantId: string, namespace: string, holderId: string, lockName: string, leaseDurationSecs?: number, timeoutMs?: number): string;
|
|
189
|
+
lockRelease(lockId: string, tenantId: string, namespace: string, holderId: string, lockVersion: string): string;
|
|
190
|
+
lockRenew(lockId: string, tenantId: string, namespace: string, holderId: string, lockVersion: string, leaseDurationSecs?: number): string;
|
|
191
|
+
blobUpload(blobId: string, data: string, contentType?: string): string;
|
|
192
|
+
blobDownload(blobId: string): string;
|
|
193
|
+
blobDelete(blobId: string): string;
|
|
194
|
+
blobList(prefix: string): string;
|
|
195
|
+
/**
|
|
196
|
+
* Checkout an actor from a named pool. Returns handle { actor_id, pool_name, checkout_id } or null on failure.
|
|
197
|
+
*/
|
|
198
|
+
poolCheckout(poolName: string, timeoutMs?: number): {
|
|
199
|
+
actor_id: string;
|
|
200
|
+
pool_name: string;
|
|
201
|
+
checkout_id: string;
|
|
202
|
+
} | null;
|
|
203
|
+
/**
|
|
204
|
+
* Checkin an actor to the pool. Pass actor_id and checkout_id from the handle returned by poolCheckout.
|
|
205
|
+
*/
|
|
206
|
+
poolCheckin(poolName: string, actorId: string, checkoutId: string, healthy: boolean): void;
|
|
207
|
+
/**
|
|
208
|
+
* Get pool metrics (total_actors, available_actors, busy_actors, current_load, etc.). Returns null if not available.
|
|
209
|
+
*/
|
|
210
|
+
poolGetMetrics(poolName: string): Record<string, unknown> | null;
|
|
211
|
+
createShardGroup(request: Record<string, unknown>): Record<string, unknown>;
|
|
212
|
+
bulkUpdateShardGroup(request: Record<string, unknown>): Record<string, unknown>;
|
|
213
|
+
mapShardGroup(request: Record<string, unknown>): Record<string, unknown>;
|
|
214
|
+
scatterGather(request: Record<string, unknown>): Record<string, unknown>;
|
|
215
|
+
broadcastShardGroup(request: Record<string, unknown>): Record<string, unknown>;
|
|
216
|
+
reduceShardGroup(request: Record<string, unknown>): Record<string, unknown>;
|
|
217
|
+
allReduceShardGroup(request: Record<string, unknown>): Record<string, unknown>;
|
|
218
|
+
barrierShardGroup(request: Record<string, unknown>): Record<string, unknown>;
|
|
219
|
+
spawnActors(request: Record<string, unknown>): Record<string, unknown>;
|
|
220
|
+
applicationMetricsAdd(applicationId: string, metrics: Record<string, unknown>): Record<string, unknown>;
|
|
221
|
+
applicationGetMetrics(applicationId: string, nodeId: string): Record<string, unknown>;
|
|
222
|
+
applicationGetStatus(applicationId: string, nodeId: string): Record<string, unknown>;
|
|
223
|
+
/**
|
|
224
|
+
* Execute an outbound HTTP request via a named service link.
|
|
225
|
+
*
|
|
226
|
+
* The link must be pre-configured in RuntimeConfig.service_links.
|
|
227
|
+
* The host handles retries, circuit breaking, and auth injection.
|
|
228
|
+
*
|
|
229
|
+
* @param linkName Service link name (e.g. "payments-api")
|
|
230
|
+
* @param method HTTP method ("GET", "POST", "PUT", "DELETE", "PATCH")
|
|
231
|
+
* @param pathAndQuery Path and optional query string (e.g. "/v1/users?limit=10")
|
|
232
|
+
* @param headers Optional extra headers object
|
|
233
|
+
* @param body Optional request body string (JSON or base64-encoded bytes)
|
|
234
|
+
* @returns Response object with status, headers, body
|
|
235
|
+
*/
|
|
236
|
+
httpFetch(linkName: string, method: string, pathAndQuery: string, headers?: Record<string, string>, body?: string): {
|
|
237
|
+
status: number;
|
|
238
|
+
headers: Record<string, string>;
|
|
239
|
+
body: string;
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Two-cursor monotonic append-only log backed by KV.
|
|
244
|
+
*
|
|
245
|
+
* Embed in actor state (serialize with `JSON.stringify`). Each consumer
|
|
246
|
+
* tracks its own read cursor so they advance independently.
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```typescript
|
|
250
|
+
* const log = new EventLog();
|
|
251
|
+
* const seq = log.append(host, 'audit:', { action: 'login' });
|
|
252
|
+
* const [events, newCursor] = log.poll(host, 'audit:', 'consumer-1', 20);
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
export declare class EventLog {
|
|
256
|
+
watermark: number;
|
|
257
|
+
constructor(watermark?: number);
|
|
258
|
+
/** Append an entry to the log. Returns the assigned sequence number. */
|
|
259
|
+
append(h: Host, prefix: string, entry: unknown): number;
|
|
260
|
+
/**
|
|
261
|
+
* Return up to `limit` events for `consumerId` that arrived after its last cursor.
|
|
262
|
+
* Returns `[events, newCursor]`. The new cursor is persisted in KV.
|
|
263
|
+
*/
|
|
264
|
+
poll(h: Host, prefix: string, consumerId: string, limit?: number): [unknown[], number];
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Ergonomic outbound HTTP client backed by a named service link.
|
|
268
|
+
*
|
|
269
|
+
* The link must be pre-configured in RuntimeConfig.service_links.
|
|
270
|
+
* The host handles retries, circuit breaking, and auth injection.
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```typescript
|
|
274
|
+
* const http = new ServiceHttpClient("payments-api");
|
|
275
|
+
* const balance = http.get("/v1/balance?account=123");
|
|
276
|
+
* const result = http.post("/v1/transfer", { amount: 100 });
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
export declare class ServiceHttpClient {
|
|
280
|
+
private readonly linkName;
|
|
281
|
+
constructor(linkName: string);
|
|
282
|
+
/** GET request. Returns response object with status, headers, body. */
|
|
283
|
+
get(pathAndQuery: string, headers?: Record<string, string>): {
|
|
284
|
+
status: number;
|
|
285
|
+
headers: Record<string, string>;
|
|
286
|
+
body: string;
|
|
287
|
+
};
|
|
288
|
+
/** POST JSON request. body is serialized to JSON. */
|
|
289
|
+
post(pathAndQuery: string, body?: unknown, headers?: Record<string, string>): {
|
|
290
|
+
status: number;
|
|
291
|
+
headers: Record<string, string>;
|
|
292
|
+
body: string;
|
|
293
|
+
};
|
|
294
|
+
/** PUT JSON request. */
|
|
295
|
+
put(pathAndQuery: string, body?: unknown, headers?: Record<string, string>): {
|
|
296
|
+
status: number;
|
|
297
|
+
headers: Record<string, string>;
|
|
298
|
+
body: string;
|
|
299
|
+
};
|
|
300
|
+
/** DELETE request. */
|
|
301
|
+
delete(pathAndQuery: string, headers?: Record<string, string>): {
|
|
302
|
+
status: number;
|
|
303
|
+
headers: Record<string, string>;
|
|
304
|
+
body: string;
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
/** Global host instance */
|
|
308
|
+
export declare const host: Host;
|
|
309
|
+
/** Return the first member of a process group, or null if empty. */
|
|
310
|
+
export declare function pgFirst(group: string): string | null;
|
|
311
|
+
/** Return the first member of a process group, throwing if empty. */
|
|
312
|
+
export declare function pgFirstOrThrow(group: string): string;
|