@projectqai/proto 0.0.26 → 0.0.29
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/device.ts +85 -4
- package/package.json +2 -3
package/device.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createClient, type Client, ConnectError, Code } from "@connectrpc/connect";
|
|
2
|
-
import {
|
|
2
|
+
import { createTransport } from "@connectrpc/connect/protocol-connect";
|
|
3
|
+
import type { UniversalClientFn } from "@connectrpc/connect/protocol";
|
|
3
4
|
import { create, clone } from "@bufbuild/protobuf";
|
|
4
5
|
import {
|
|
5
6
|
WorldService,
|
|
@@ -37,9 +38,72 @@ export {
|
|
|
37
38
|
type Entity,
|
|
38
39
|
} from "./dist/world_pb.js";
|
|
39
40
|
|
|
41
|
+
// fetch-based universal HTTP client for the Connect protocol.
|
|
42
|
+
// Works in Node, Bun, browsers, and goja — no http2 dependency.
|
|
43
|
+
const universalFetch: UniversalClientFn = async (req) => {
|
|
44
|
+
const body = req.body ? await collectBytes(req.body) : undefined;
|
|
45
|
+
// Prevent the server from gzip-encoding responses — the Connect
|
|
46
|
+
// transport handles its own compression negotiation.
|
|
47
|
+
req.header.set("Accept-Encoding", "identity");
|
|
48
|
+
const resp = await fetch(req.url, {
|
|
49
|
+
method: req.method,
|
|
50
|
+
headers: req.header,
|
|
51
|
+
body,
|
|
52
|
+
signal: (req as any).signal,
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
status: resp.status,
|
|
56
|
+
header: resp.headers,
|
|
57
|
+
body: responseBodyStream(resp),
|
|
58
|
+
trailer: new Headers(),
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
async function collectBytes(iter: AsyncIterable<Uint8Array>): Promise<Uint8Array> {
|
|
63
|
+
const chunks: Uint8Array[] = [];
|
|
64
|
+
for await (const value of iter) {
|
|
65
|
+
chunks.push(value);
|
|
66
|
+
}
|
|
67
|
+
const len = chunks.reduce((n, c) => n + c.length, 0);
|
|
68
|
+
const out = new Uint8Array(len);
|
|
69
|
+
let off = 0;
|
|
70
|
+
for (const c of chunks) { out.set(c, off); off += c.length; }
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function responseBodyStream(resp: Response): AsyncIterable<Uint8Array> {
|
|
75
|
+
if (!resp.body) return { [Symbol.asyncIterator]() { return { next: () => Promise.resolve({ done: true as const, value: undefined }), throw: () => Promise.resolve({ done: true as const, value: undefined }) }; } };
|
|
76
|
+
const reader = resp.body.getReader();
|
|
77
|
+
return {
|
|
78
|
+
[Symbol.asyncIterator]() {
|
|
79
|
+
return {
|
|
80
|
+
async next() {
|
|
81
|
+
const { done, value } = await reader.read();
|
|
82
|
+
if (done) { reader.releaseLock(); return { done: true as const, value: undefined }; }
|
|
83
|
+
return { done: false as const, value };
|
|
84
|
+
},
|
|
85
|
+
async throw(e: unknown) {
|
|
86
|
+
reader.releaseLock();
|
|
87
|
+
return { done: true as const, value: undefined };
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
40
94
|
export function connect(serverURL?: string): WorldClient {
|
|
41
95
|
const base = serverURL ?? process.env.HYDRIS_SERVER ?? "http://localhost:50051";
|
|
42
|
-
const transport =
|
|
96
|
+
const transport = createTransport({
|
|
97
|
+
baseUrl: base,
|
|
98
|
+
httpClient: universalFetch,
|
|
99
|
+
useBinaryFormat: true,
|
|
100
|
+
interceptors: [],
|
|
101
|
+
acceptCompression: [],
|
|
102
|
+
sendCompression: null,
|
|
103
|
+
compressMinBytes: Number.MAX_SAFE_INTEGER,
|
|
104
|
+
readMaxBytes: Number.MAX_SAFE_INTEGER,
|
|
105
|
+
writeMaxBytes: Number.MAX_SAFE_INTEGER,
|
|
106
|
+
});
|
|
43
107
|
return createClient(WorldService, transport);
|
|
44
108
|
}
|
|
45
109
|
|
|
@@ -83,6 +147,7 @@ export interface AttachOptions<S extends SchemaProperties> {
|
|
|
83
147
|
device?: { category?: string };
|
|
84
148
|
icon?: string;
|
|
85
149
|
schema: S;
|
|
150
|
+
init?: (client: WorldClient, config: InferConfig<S>, signal: AbortSignal) => Promise<void>;
|
|
86
151
|
run: (client: WorldClient, config: InferConfig<S>, signal: AbortSignal) => Promise<void>;
|
|
87
152
|
health?: () => HealthResult | Promise<HealthResult>;
|
|
88
153
|
interval?: number;
|
|
@@ -138,10 +203,13 @@ export async function attach<S extends SchemaProperties>(opts: AttachOptions<S>)
|
|
|
138
203
|
|
|
139
204
|
let heartbeatId: ReturnType<typeof setInterval> | null = null;
|
|
140
205
|
|
|
206
|
+
let initialized = false;
|
|
207
|
+
|
|
141
208
|
const pushHeartbeat = (result?: Record<number, { label: string; value: number | bigint }>) => {
|
|
209
|
+
const state = initialized ? DeviceState.DeviceStateActive : DeviceState.DeviceStatePending;
|
|
142
210
|
const e = create(EntitySchema, {
|
|
143
211
|
id: entityID,
|
|
144
|
-
device: create(DeviceComponentSchema, { ...entity.device, state
|
|
212
|
+
device: create(DeviceComponentSchema, { ...entity.device, state }),
|
|
145
213
|
lifetime: create(LifetimeSchema, {
|
|
146
214
|
until: create(TimestampSchema, { seconds: BigInt(Math.floor((Date.now() + interval + 1_000) / 1000)) }),
|
|
147
215
|
}),
|
|
@@ -177,7 +245,7 @@ export async function attach<S extends SchemaProperties>(opts: AttachOptions<S>)
|
|
|
177
245
|
: create(ConfigurableComponentSchema);
|
|
178
246
|
cfg.state = state;
|
|
179
247
|
cfg.error = error;
|
|
180
|
-
if (entity.config && state === ConfigurableState.ConfigurableStateActive) {
|
|
248
|
+
if (entity.config && (state === ConfigurableState.ConfigurableStateStarting || state === ConfigurableState.ConfigurableStateActive)) {
|
|
181
249
|
cfg.appliedVersion = entity.config.version;
|
|
182
250
|
}
|
|
183
251
|
await push(client, create(EntitySchema, { id: entityID, configurable: cfg })).catch(() => { });
|
|
@@ -193,6 +261,7 @@ export async function attach<S extends SchemaProperties>(opts: AttachOptions<S>)
|
|
|
193
261
|
runningAbort.abort();
|
|
194
262
|
runningAbort = null;
|
|
195
263
|
currentEntity = null;
|
|
264
|
+
initialized = false;
|
|
196
265
|
console.log(`stopped entity=${entityID}`);
|
|
197
266
|
if (e) pushState(e, ConfigurableState.ConfigurableStateInactive);
|
|
198
267
|
}
|
|
@@ -206,6 +275,18 @@ export async function attach<S extends SchemaProperties>(opts: AttachOptions<S>)
|
|
|
206
275
|
(async () => {
|
|
207
276
|
while (!childSignal.aborted) {
|
|
208
277
|
await pushState(e, ConfigurableState.ConfigurableStateStarting);
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
if (opts.init) await opts.init(client, extractConfig(e, opts.schema), childSignal);
|
|
281
|
+
} catch (err) {
|
|
282
|
+
if (childSignal.aborted || isCanceled(err)) return;
|
|
283
|
+
console.error(`init failed entity=${entityID}`, err);
|
|
284
|
+
await pushState(e, ConfigurableState.ConfigurableStateFailed, String(err));
|
|
285
|
+
await sleep(5_000, childSignal);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
initialized = true;
|
|
209
290
|
await pushState(e, ConfigurableState.ConfigurableStateActive);
|
|
210
291
|
|
|
211
292
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@projectqai/proto",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.29",
|
|
4
4
|
"author": "projectq-release-bot",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -23,8 +23,7 @@
|
|
|
23
23
|
"@bufbuild/protobuf": "^2.10.1"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@connectrpc/connect": "^2.0.0"
|
|
27
|
-
"@connectrpc/connect-node": "^2.0.0"
|
|
26
|
+
"@connectrpc/connect": "^2.0.0"
|
|
28
27
|
},
|
|
29
28
|
"devDependencies": {
|
|
30
29
|
"@bufbuild/protoc-gen-es": "^2.10.1"
|