@phreshos/client 0.1.49 → 0.1.51
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/dist/context.js +2 -2
- package/dist/domain.js +41 -37
- package/dist/permission-requests.d.ts +2 -0
- package/dist/permission-requests.js +84 -0
- package/dist/permissions.d.ts +3 -2
- package/dist/permissions.js +17 -6
- package/dist/storage.d.ts +5 -1
- package/dist/storage.js +34 -1
- package/dist/system.js +4 -1
- package/package.json +3 -3
package/dist/context.js
CHANGED
|
@@ -2,7 +2,7 @@ import Deadline from "./deadline.js";
|
|
|
2
2
|
import { ClientEndpoint, ServerEndpoint, ServerTrafficHandle, TrafficHandle, endpointLifecycle, endpointEvents, process, program, visibleEndpoint, presentation, window as windowHandle, } from "./domain.js";
|
|
3
3
|
import Events from "./events.js";
|
|
4
4
|
import wire from "./wire.js";
|
|
5
|
-
import {
|
|
5
|
+
import { contextPermissions } from "./permissions.js";
|
|
6
6
|
class ContextServerHandle extends ServerEndpoint {
|
|
7
7
|
owner;
|
|
8
8
|
subscribe;
|
|
@@ -96,7 +96,7 @@ class ClientContext extends Events {
|
|
|
96
96
|
server = contextServer;
|
|
97
97
|
window = contextClient.window;
|
|
98
98
|
presentation = presentation(currentAddress);
|
|
99
|
-
permissions =
|
|
99
|
+
permissions = contextPermissions();
|
|
100
100
|
constructor() {
|
|
101
101
|
super((event, listener, impossible) => wire.on("end-end", event, value => listener(contextMessage(value)), null, impossible), (listener, impossible) => wire.onAll("end-end", (event, value) => {
|
|
102
102
|
if (typeof event === "string")
|
package/dist/domain.js
CHANGED
|
@@ -2,7 +2,7 @@ import { ClientEndpoint as CoreClientEndpoint, Endpoint as CoreEndpoint, Process
|
|
|
2
2
|
import Events, { stream } from "./events.js";
|
|
3
3
|
import Deadline from "./deadline.js";
|
|
4
4
|
import HandleRegistry from "./handle-registry.js";
|
|
5
|
-
import { area, sql, store } from "./storage.js";
|
|
5
|
+
import { area, programLogs, sql, store } from "./storage.js";
|
|
6
6
|
import startup from "./startup.js";
|
|
7
7
|
import { programPermissions } from "./permissions.js";
|
|
8
8
|
import wire from "./wire.js";
|
|
@@ -29,7 +29,7 @@ class ProgramHandle extends CoreProgram {
|
|
|
29
29
|
this.data = area(this.address, "data");
|
|
30
30
|
this.cache = area(this.address, "cache");
|
|
31
31
|
this.store = store(this.address);
|
|
32
|
-
this.logs =
|
|
32
|
+
this.logs = programLogs(this.address);
|
|
33
33
|
this.database = sql("database", this.address);
|
|
34
34
|
this.startup = startup(this.address);
|
|
35
35
|
this.permissions = programPermissions(this.address);
|
|
@@ -321,8 +321,6 @@ class WindowHandle extends Events {
|
|
|
321
321
|
}
|
|
322
322
|
async title() { return (await this.state()).title; }
|
|
323
323
|
async header() { return (await this.state()).header; }
|
|
324
|
-
async surface() { return (await this.state()).surface; }
|
|
325
|
-
async transaction() { return (await this.state()).transaction; }
|
|
326
324
|
async position() { return (await this.state()).position; }
|
|
327
325
|
async size() { return (await this.state()).size; }
|
|
328
326
|
async minimized() { return (await this.state()).minimized; }
|
|
@@ -336,24 +334,12 @@ class WindowHandle extends Events {
|
|
|
336
334
|
async maximize(maximized = true) { await wire.request(["maximize", await this.target(), maximized]); }
|
|
337
335
|
async setTitle(title) { await wire.request(["setTitle", await this.target(), title]); }
|
|
338
336
|
async setHeader(header) { await wire.request(["setHeader", await this.target(), header]); }
|
|
339
|
-
async setSurface(surface) { await wire.request(["setSurface", await this.target(), surface]); }
|
|
340
|
-
async setTransaction(transaction) { await wire.request(["setTransaction", await this.target(), transaction]); }
|
|
341
337
|
async raise() { await wire.request(["raise", await this.target()]); }
|
|
342
338
|
}
|
|
343
|
-
class WindowPresentationHandle
|
|
339
|
+
class WindowPresentationHandle {
|
|
344
340
|
target;
|
|
345
341
|
selected;
|
|
346
342
|
constructor(target, selected) {
|
|
347
|
-
super((event, listener, impossible) => {
|
|
348
|
-
if (!windowEvent(event)) {
|
|
349
|
-
impossible?.(new Error(`A Window presentation has no "${event}" event`));
|
|
350
|
-
return () => undefined;
|
|
351
|
-
}
|
|
352
|
-
return wire.on("presentation", event, listener, null, impossible);
|
|
353
|
-
}, (listener, impossible) => wire.onAll("presentation", (event, ...values) => {
|
|
354
|
-
if (typeof event === "string")
|
|
355
|
-
listener(event, values[0]);
|
|
356
|
-
}, null, impossible));
|
|
357
343
|
this.target = target;
|
|
358
344
|
this.selected = selected;
|
|
359
345
|
}
|
|
@@ -363,32 +349,50 @@ class WindowPresentationHandle extends Events {
|
|
|
363
349
|
transactionAndWait(transaction) {
|
|
364
350
|
return new WindowPresentationHandle(this.target, { transaction, wait: true });
|
|
365
351
|
}
|
|
366
|
-
async
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
async front() { return await this.read("front"); }
|
|
374
|
-
async layer() { return await this.read("layer"); }
|
|
352
|
+
async layer() {
|
|
353
|
+
const answer = await wire.request(["windowPresentationLayer", await this.target()]);
|
|
354
|
+
return answer[0];
|
|
355
|
+
}
|
|
356
|
+
beginMoveGesture(start) {
|
|
357
|
+
return new WindowMoveGestureHandle(this.target(), start);
|
|
358
|
+
}
|
|
375
359
|
async move(position) { await this.change("windowPresentationMove", position); }
|
|
376
360
|
async resize(size) { await this.change("windowPresentationResize", size); }
|
|
377
361
|
async setGeometry(geometry) { await this.change("windowPresentationGeometry", geometry); }
|
|
378
|
-
async minimize(minimized = true) { await this.change("windowPresentationMinimize", minimized); }
|
|
379
|
-
async maximize(maximized = true) { await this.change("windowPresentationMaximize", maximized); }
|
|
380
|
-
async setTitle(title) { await this.change("windowPresentationTitle", title); }
|
|
381
|
-
async setHeader(header) { await this.change("windowPresentationHeader", header); }
|
|
382
362
|
async setSurface(surface) { await this.change("windowPresentationSurface", surface); }
|
|
383
|
-
async
|
|
384
|
-
async unfollow() { await this.change("windowPresentationUnfollow"); }
|
|
363
|
+
async setInteractive(interactive) { await this.change("windowPresentationInteractive", interactive); }
|
|
385
364
|
async raise() { await this.change("windowPresentationRaise"); }
|
|
386
365
|
async change(operation, value) {
|
|
387
|
-
await wire.request([operation, await this.target(), value, this.selected
|
|
366
|
+
await wire.request([operation, await this.target(), value, this.selected ?? null]);
|
|
388
367
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
368
|
+
}
|
|
369
|
+
class WindowMoveGestureHandle {
|
|
370
|
+
gesture = crypto.randomUUID();
|
|
371
|
+
address;
|
|
372
|
+
ready;
|
|
373
|
+
finished;
|
|
374
|
+
ended = false;
|
|
375
|
+
constructor(target, start) {
|
|
376
|
+
this.address = target;
|
|
377
|
+
this.ready = target.then(async (address) => {
|
|
378
|
+
await wire.request(["windowPresentationMoveGestureBegin", address, this.gesture, start]);
|
|
379
|
+
});
|
|
380
|
+
this.finished = this.ready.then(async () => {
|
|
381
|
+
await wire.request(["windowPresentationMoveGestureWait", await this.address, this.gesture]);
|
|
382
|
+
});
|
|
383
|
+
// A gesture may be abandoned by document teardown before its owner can end
|
|
384
|
+
// it. The boundary still owns cleanup; this only prevents an unhandled rejection.
|
|
385
|
+
void this.finished.catch(() => undefined);
|
|
386
|
+
void this.finished.then(() => { this.ended = true; }, () => { this.ended = true; });
|
|
387
|
+
}
|
|
388
|
+
cancel() {
|
|
389
|
+
if (this.ended)
|
|
390
|
+
return;
|
|
391
|
+
this.ended = true;
|
|
392
|
+
void this.ready.then(async () => {
|
|
393
|
+
const address = await this.address;
|
|
394
|
+
wire.send("end-host", "windowPresentationMoveGestureCancel", address, this.gesture);
|
|
395
|
+
}, () => undefined);
|
|
392
396
|
}
|
|
393
397
|
}
|
|
394
398
|
function deferredScoped(route, target, convert) {
|
|
@@ -414,7 +418,7 @@ function deferredScoped(route, target, convert) {
|
|
|
414
418
|
];
|
|
415
419
|
}
|
|
416
420
|
function windowEvent(event) {
|
|
417
|
-
return event === "move" || event === "resize" || event === "minimize" || event === "maximize" || event === "changeTitle" || event === "changeHeader" || event === "
|
|
421
|
+
return event === "move" || event === "resize" || event === "minimize" || event === "maximize" || event === "changeTitle" || event === "changeHeader" || event === "front";
|
|
418
422
|
}
|
|
419
423
|
function deferred(target, register, impossible) {
|
|
420
424
|
let active = true;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { PermissionRequest as CorePermissionRequest, parsePermission, parsePermissionRequestSnapshot } from "@phreshos/core";
|
|
2
|
+
import { endpoint } from "./domain.js";
|
|
3
|
+
import Events from "./events.js";
|
|
4
|
+
import wire from "./wire.js";
|
|
5
|
+
const handles = new Map();
|
|
6
|
+
class PermissionRequestHandle extends CorePermissionRequest {
|
|
7
|
+
subscribe;
|
|
8
|
+
wait;
|
|
9
|
+
events;
|
|
10
|
+
identity;
|
|
11
|
+
from;
|
|
12
|
+
createdAt;
|
|
13
|
+
expiresAt;
|
|
14
|
+
name;
|
|
15
|
+
scope;
|
|
16
|
+
constructor(snapshot) {
|
|
17
|
+
super();
|
|
18
|
+
this.identity = snapshot.identity;
|
|
19
|
+
this.from = endpoint(snapshot.from);
|
|
20
|
+
this.createdAt = snapshot.createdAt;
|
|
21
|
+
this.expiresAt = snapshot.expiresAt;
|
|
22
|
+
this.name = snapshot.name;
|
|
23
|
+
this.scope = snapshot.scope;
|
|
24
|
+
const events = new Events((event, listener, impossible) => wire.on("permission-host", event, (...values) => {
|
|
25
|
+
listener(parsePermission(this.name, values[2]));
|
|
26
|
+
}, this.identity, impossible), (listener, impossible) => wire.onAll("permission-host", (event, ...values) => {
|
|
27
|
+
if (event === "resolve")
|
|
28
|
+
listener(event, parsePermission(this.name, values[2]));
|
|
29
|
+
}, this.identity, impossible));
|
|
30
|
+
this.subscribe = events.subscribe;
|
|
31
|
+
this.wait = events.wait;
|
|
32
|
+
this.events = events.events;
|
|
33
|
+
}
|
|
34
|
+
async pending() {
|
|
35
|
+
const answer = await wire.request(["permission-request-pending", this.identity]);
|
|
36
|
+
return answer[0] === true;
|
|
37
|
+
}
|
|
38
|
+
async allow() { await wire.request(["permission-request-allow", this.identity]); }
|
|
39
|
+
async deny() { await wire.request(["permission-request-deny", this.identity]); }
|
|
40
|
+
async cancel() { await wire.request(["permission-request-cancel", this.identity]); }
|
|
41
|
+
}
|
|
42
|
+
function requestHandle(value) {
|
|
43
|
+
const snapshot = parsePermissionRequestSnapshot(value);
|
|
44
|
+
const current = handles.get(snapshot.identity);
|
|
45
|
+
if (current)
|
|
46
|
+
return current;
|
|
47
|
+
const created = new PermissionRequestHandle(snapshot);
|
|
48
|
+
handles.set(snapshot.identity, created);
|
|
49
|
+
return created;
|
|
50
|
+
}
|
|
51
|
+
class PermissionRegistry extends Events {
|
|
52
|
+
constructor() {
|
|
53
|
+
super((event, listener, impossible) => wire.on("host-permission", permissionEvent(event), (...values) => {
|
|
54
|
+
listener(systemPermissionEvent(event, values));
|
|
55
|
+
}, null, impossible), (listener, impossible) => wire.onAll("host-permission", (event, ...values) => {
|
|
56
|
+
if (typeof event !== "string")
|
|
57
|
+
return;
|
|
58
|
+
const name = publicPermissionEvent(event);
|
|
59
|
+
if (name)
|
|
60
|
+
listener(name, systemPermissionEvent(name, values));
|
|
61
|
+
}, null, impossible));
|
|
62
|
+
}
|
|
63
|
+
async requests() {
|
|
64
|
+
const [values] = await wire.request(["host-permission-requests"]);
|
|
65
|
+
return values.map(requestHandle);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function permissionEvent(event) {
|
|
69
|
+
return event === "permissionRequest" ? "request" : "resolve";
|
|
70
|
+
}
|
|
71
|
+
function publicPermissionEvent(event) {
|
|
72
|
+
if (event === "request")
|
|
73
|
+
return "permissionRequest";
|
|
74
|
+
if (event === "resolve")
|
|
75
|
+
return "permissionResolve";
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
function systemPermissionEvent(event, values) {
|
|
79
|
+
const request = requestHandle(values[1]);
|
|
80
|
+
if (event === "permissionRequest")
|
|
81
|
+
return request;
|
|
82
|
+
return { request, permission: parsePermission(request.name, values[2]) };
|
|
83
|
+
}
|
|
84
|
+
export const systemPermissions = new PermissionRegistry();
|
package/dist/permissions.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { ProgramPermissions } from "@phreshos/core";
|
|
1
|
+
import type { ContextPermissions, ProgramPermissions } from "@phreshos/core";
|
|
2
2
|
import type { HandleAddress } from "./domain.js";
|
|
3
|
-
export declare const defaultPermissionTimeout = 120000;
|
|
4
3
|
/** Bind authoritative permission state to one exact Program handle. */
|
|
5
4
|
export declare function programPermissions(program?: HandleAddress): ProgramPermissions;
|
|
5
|
+
/** Bind permission reads and requests to the currently executing Client Endpoint. */
|
|
6
|
+
export declare function contextPermissions(): ContextPermissions;
|
package/dist/permissions.js
CHANGED
|
@@ -1,23 +1,34 @@
|
|
|
1
1
|
import { parsePermission, parsePermissions } from "@phreshos/core";
|
|
2
2
|
import wire from "./wire.js";
|
|
3
|
-
export const defaultPermissionTimeout = 120_000;
|
|
4
3
|
/** Bind authoritative permission state to one exact Program handle. */
|
|
5
4
|
export function programPermissions(program) {
|
|
6
5
|
const operate = (operation, name, permission) => (wire.request(["program-permissions", program, operation, name, permission]));
|
|
6
|
+
return {
|
|
7
|
+
async get(name) { return parsePermission(name, (await operate("get", name))[0]); },
|
|
8
|
+
async all() { return parsePermissions((await operate("all"))[0]); },
|
|
9
|
+
async allows(name, permission = true) { return (await operate("allows", name, permission))[0] === true; },
|
|
10
|
+
async allow(name, permission = true) { await operate("allow", name, permission); },
|
|
11
|
+
async deny(name) { await operate("deny", name); }
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** Bind permission reads and requests to the currently executing Client Endpoint. */
|
|
15
|
+
export function contextPermissions() {
|
|
16
|
+
const operate = (operation, name, permission) => (wire.request(["program-permissions", undefined, operation, name, permission]));
|
|
7
17
|
const timed = (timeout) => ({
|
|
8
18
|
async request(name, permission = true) {
|
|
9
19
|
const identity = crypto.randomUUID();
|
|
10
|
-
const
|
|
11
|
-
|
|
20
|
+
const request = ["context-permission-request", identity, name, permission];
|
|
21
|
+
if (timeout !== undefined)
|
|
22
|
+
request.push(timeout);
|
|
23
|
+
const result = await wire.request(request);
|
|
24
|
+
return parsePermission(name, result[0]);
|
|
12
25
|
}
|
|
13
26
|
});
|
|
14
27
|
return {
|
|
15
28
|
async get(name) { return parsePermission(name, (await operate("get", name))[0]); },
|
|
16
29
|
async all() { return parsePermissions((await operate("all"))[0]); },
|
|
17
30
|
async allows(name, permission = true) { return (await operate("allows", name, permission))[0] === true; },
|
|
18
|
-
|
|
19
|
-
async deny(name) { await operate("deny", name); },
|
|
20
|
-
request: timed(defaultPermissionTimeout).request,
|
|
31
|
+
request: timed().request,
|
|
21
32
|
timeout(milliseconds) {
|
|
22
33
|
if (!Number.isFinite(milliseconds) || milliseconds < 0)
|
|
23
34
|
throw new Error("A permission timeout must be a non-negative finite number");
|
package/dist/storage.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Storage, type ProgramSql, type ProgramStore } from "@phreshos/core";
|
|
1
|
+
import { Storage, type ProgramLogs, type ProgramSql, type ProgramStore, type SystemLogs } from "@phreshos/core";
|
|
2
2
|
import type { HandleAddress } from "./domain.js";
|
|
3
3
|
/** Client-side access to one exact Program storage area. */
|
|
4
4
|
export declare function area(program: HandleAddress, which: "data" | "cache"): Storage;
|
|
@@ -6,3 +6,7 @@ export declare function area(program: HandleAddress, which: "data" | "cache"): S
|
|
|
6
6
|
export declare function systemStorage(): Storage;
|
|
7
7
|
export declare function store(program: HandleAddress): ProgramStore;
|
|
8
8
|
export declare function sql(kind: "database" | "logs", program: HandleAddress): ProgramSql;
|
|
9
|
+
/** Read and observe one Program's captured Endpoint output. */
|
|
10
|
+
export declare function programLogs(program: HandleAddress): ProgramLogs;
|
|
11
|
+
/** Read and observe records produced by the PhreshOS System. */
|
|
12
|
+
export declare function systemLogs(): SystemLogs;
|
package/dist/storage.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Storage, StorageFile } from "@phreshos/core";
|
|
1
|
+
import { Storage, StorageFile, parseProgramLogRecord, parseSystemLogRecord } from "@phreshos/core";
|
|
2
2
|
import { content } from "./content.js";
|
|
3
3
|
import controlledStream from "./controlled-stream.js";
|
|
4
4
|
import wire from "./wire.js";
|
|
5
|
+
import Events from "./events.js";
|
|
5
6
|
/** Client-side access to one exact Program storage area. */
|
|
6
7
|
export function area(program, which) {
|
|
7
8
|
return new RemoteStorage(new ProgramStorageBoundary(program, which), []);
|
|
@@ -221,3 +222,35 @@ export function sql(kind, program) {
|
|
|
221
222
|
}
|
|
222
223
|
};
|
|
223
224
|
}
|
|
225
|
+
/** Read and observe one Program's captured Endpoint output. */
|
|
226
|
+
export function programLogs(program) {
|
|
227
|
+
const database = sql("logs", program);
|
|
228
|
+
const events = new Events((event, listener, impossible) => wire.on("program-log", event, (...values) => listener(parseProgramLogRecord(values[1])), program.reference, impossible), (listener, impossible) => wire.onAll("program-log", (event, ...values) => {
|
|
229
|
+
if (event === "log")
|
|
230
|
+
listener(event, parseProgramLogRecord(values[1]));
|
|
231
|
+
}, program.reference, impossible));
|
|
232
|
+
return {
|
|
233
|
+
query: database.query,
|
|
234
|
+
subscribe: events.subscribe,
|
|
235
|
+
wait: events.wait,
|
|
236
|
+
events: events.events
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/** Read and observe records produced by the PhreshOS System. */
|
|
240
|
+
export function systemLogs() {
|
|
241
|
+
const events = new Events((event, listener, impossible) => wire.on("host-log", event, (...values) => listener(parseSystemLogRecord(values[1])), null, impossible), (listener, impossible) => wire.onAll("host-log", (event, ...values) => {
|
|
242
|
+
if (event === "log")
|
|
243
|
+
listener(event, parseSystemLogRecord(values[1]));
|
|
244
|
+
}, null, impossible));
|
|
245
|
+
return {
|
|
246
|
+
async query(statement, ...rest) {
|
|
247
|
+
const text = typeof statement === "string" ? statement : statement.raw.join("?");
|
|
248
|
+
const values = typeof statement === "string" ? (Array.isArray(rest[0]) ? rest[0] : []) : rest;
|
|
249
|
+
const answer = await wire.request(["system-logs", text, values]);
|
|
250
|
+
return answer[0];
|
|
251
|
+
},
|
|
252
|
+
subscribe: events.subscribe,
|
|
253
|
+
wait: events.wait,
|
|
254
|
+
events: events.events
|
|
255
|
+
};
|
|
256
|
+
}
|
package/dist/system.js
CHANGED
|
@@ -5,15 +5,18 @@ import { prepareService } from "./service.js";
|
|
|
5
5
|
import { uploads } from "./uploads.js";
|
|
6
6
|
import Events from "./events.js";
|
|
7
7
|
import { exit, process, program } from "./domain.js";
|
|
8
|
-
import { systemStorage } from "./storage.js";
|
|
8
|
+
import { systemLogs, systemStorage } from "./storage.js";
|
|
9
9
|
import network from "./network.js";
|
|
10
10
|
import { connection, session } from "./authentication.js";
|
|
11
|
+
import { systemPermissions } from "./permission-requests.js";
|
|
11
12
|
class ClientSystem {
|
|
12
13
|
storage = systemStorage();
|
|
13
14
|
appearance = new ClientAppearance();
|
|
14
15
|
program = new SystemProgramHandle();
|
|
15
16
|
process = new SystemProcessHandle();
|
|
16
17
|
authentication = new SystemAuthenticationHandle();
|
|
18
|
+
permissions = systemPermissions;
|
|
19
|
+
logs = systemLogs();
|
|
17
20
|
service = new SystemServiceHandle();
|
|
18
21
|
uploads = uploads;
|
|
19
22
|
network = network;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phreshos/client",
|
|
3
|
-
|
|
3
|
+
"version": "0.1.51",
|
|
4
4
|
"description": "The SDK used by a Program's client endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -46,13 +46,13 @@
|
|
|
46
46
|
"test": "vitest run --project default"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
|
|
49
|
+
"@phreshos/core": "^0.1.60"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@the-link/messagepack": "^0.1.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@phreshos/core": "^0.1.
|
|
55
|
+
"@phreshos/core": "^0.1.60",
|
|
56
56
|
"typescript": "^6.0.3",
|
|
57
57
|
"vitest": "^4.1.10"
|
|
58
58
|
}
|