@peers-app/peers-sdk 0.16.4 → 0.16.6
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/user-context.js +6 -0
- package/dist/contracts/__tests__/builder.test.d.ts +1 -0
- package/dist/contracts/__tests__/builder.test.js +411 -0
- package/dist/contracts/__tests__/extract.test.d.ts +1 -0
- package/dist/contracts/__tests__/extract.test.js +145 -0
- package/dist/contracts/__tests__/integration.test.d.ts +1 -0
- package/dist/contracts/__tests__/integration.test.js +348 -0
- package/dist/contracts/__tests__/registry.test.d.ts +1 -0
- package/dist/contracts/__tests__/registry.test.js +324 -0
- package/dist/contracts/__tests__/validate.test.d.ts +1 -0
- package/dist/contracts/__tests__/validate.test.js +699 -0
- package/dist/contracts/builder.d.ts +97 -0
- package/dist/contracts/builder.js +211 -0
- package/dist/contracts/contract-providers.table.d.ts +40 -0
- package/dist/contracts/contract-providers.table.js +41 -0
- package/dist/contracts/contracts.table.d.ts +44 -0
- package/dist/contracts/contracts.table.js +44 -0
- package/dist/contracts/extract.d.ts +46 -0
- package/dist/contracts/extract.js +51 -0
- package/dist/contracts/index.d.ts +9 -0
- package/dist/contracts/index.js +31 -0
- package/dist/contracts/persistent-registry.d.ts +32 -0
- package/dist/contracts/persistent-registry.js +138 -0
- package/dist/contracts/registry.d.ts +58 -0
- package/dist/contracts/registry.js +155 -0
- package/dist/contracts/types.d.ts +108 -0
- package/dist/contracts/types.js +10 -0
- package/dist/contracts/validate.d.ts +24 -0
- package/dist/contracts/validate.js +274 -0
- package/dist/data/assistants.d.ts +5 -0
- package/dist/data/assistants.js +1 -0
- package/dist/data/package-versions.d.ts +2 -2
- package/dist/data/persistent-vars.d.ts +3 -0
- package/dist/data/persistent-vars.js +17 -2
- package/dist/data/tools.d.ts +4 -0
- package/dist/data/tools.js +1 -0
- package/dist/data/workflows.d.ts +1 -0
- package/dist/events.d.ts +13 -0
- package/dist/events.js +218 -34
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/package-loader/contract-package-loader.d.ts +23 -0
- package/dist/package-loader/contract-package-loader.js +65 -0
- package/dist/package-loader/index.d.ts +1 -0
- package/dist/package-loader/index.js +1 -0
- package/dist/package-loader/package-loader.d.ts +11 -0
- package/dist/package-loader/package-loader.js +59 -8
- package/dist/rpc-types.d.ts +4 -0
- package/dist/rpc-types.js +5 -4
- package/dist/types/workflow.d.ts +3 -0
- package/dist/types/workflow.js +1 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.js +39 -0
- package/package.json +1 -1
package/dist/events.js
CHANGED
|
@@ -1,37 +1,195 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Emitter = exports.Event = void 0;
|
|
4
|
+
exports.notifyClientConnected = notifyClientConnected;
|
|
5
|
+
exports.subscribePrefix = subscribePrefix;
|
|
4
6
|
exports.subscribe = subscribe;
|
|
5
7
|
exports.subscribeDebounce = subscribeDebounce;
|
|
6
8
|
exports.emit = emit;
|
|
7
9
|
exports.unionEvents = unionEvents;
|
|
8
10
|
const rpc_types_1 = require("./rpc-types");
|
|
9
11
|
const unitTests = process.env.NODE_ENV === "test";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
// ─── Subscription Storage ────────────────────────────────────────────────────
|
|
13
|
+
/** Subscriptions indexed by exact event name for O(1) dispatch. */
|
|
14
|
+
const nameIndex = new Map();
|
|
15
|
+
/** Subscriptions that use custom filter functions (checked on every emit). */
|
|
16
|
+
const wildcardSubscriptions = new Set();
|
|
17
|
+
function addSubscription(subscription) {
|
|
18
|
+
if (subscription.eventName) {
|
|
19
|
+
let bucket = nameIndex.get(subscription.eventName);
|
|
20
|
+
if (!bucket) {
|
|
21
|
+
bucket = new Set();
|
|
22
|
+
nameIndex.set(subscription.eventName, bucket);
|
|
23
|
+
}
|
|
24
|
+
bucket.add(subscription);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
wildcardSubscriptions.add(subscription);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function removeSubscription(subscription) {
|
|
31
|
+
if (subscription.eventName) {
|
|
32
|
+
const bucket = nameIndex.get(subscription.eventName);
|
|
33
|
+
if (bucket) {
|
|
34
|
+
const removed = bucket.delete(subscription);
|
|
35
|
+
if (bucket.size === 0) {
|
|
36
|
+
nameIndex.delete(subscription.eventName);
|
|
37
|
+
}
|
|
38
|
+
return removed;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return wildcardSubscriptions.delete(subscription);
|
|
43
|
+
}
|
|
44
|
+
// ─── Client → Server Subscription Registration ──────────────────────────────
|
|
45
|
+
// In multi-process mode (Electron), the client tells the server which event
|
|
46
|
+
// names/prefixes it cares about so the server can skip forwarding unneeded events.
|
|
47
|
+
/** Reference counts for event names registered with the server. */
|
|
48
|
+
const clientNameRefCounts = new Map();
|
|
49
|
+
/** Reference counts for event prefixes registered with the server. */
|
|
50
|
+
const clientPrefixRefCounts = new Map();
|
|
51
|
+
/** Whether the client-server connection is established (for deferred registration). */
|
|
52
|
+
let clientConnected = false;
|
|
53
|
+
/** Names pending registration (accumulated before connection is ready). */
|
|
54
|
+
const pendingNameSubscriptions = new Set();
|
|
55
|
+
/** Prefixes pending registration (accumulated before connection is ready). */
|
|
56
|
+
const pendingPrefixSubscriptions = new Set();
|
|
57
|
+
/**
|
|
58
|
+
* Notify the events system that the client connection is ready.
|
|
59
|
+
* Flushes any subscriptions that were registered before the connection.
|
|
60
|
+
*/
|
|
61
|
+
function notifyClientConnected() {
|
|
62
|
+
clientConnected = true;
|
|
63
|
+
if (pendingNameSubscriptions.size > 0) {
|
|
64
|
+
const names = [...pendingNameSubscriptions];
|
|
65
|
+
pendingNameSubscriptions.clear();
|
|
66
|
+
rpc_types_1.rpcServerCalls.subscribeEvents(names).catch((err) => {
|
|
67
|
+
console.error("Failed to register pending event subscriptions with server", err);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (pendingPrefixSubscriptions.size > 0) {
|
|
71
|
+
const prefixes = [...pendingPrefixSubscriptions];
|
|
72
|
+
pendingPrefixSubscriptions.clear();
|
|
73
|
+
rpc_types_1.rpcServerCalls.subscribePrefixes(prefixes).catch((err) => {
|
|
74
|
+
console.error("Failed to register pending prefix subscriptions with server", err);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function clientRegisterName(name) {
|
|
79
|
+
if (unitTests || (0, rpc_types_1.isSingleProcessClient)())
|
|
80
|
+
return;
|
|
81
|
+
const count = clientNameRefCounts.get(name) || 0;
|
|
82
|
+
clientNameRefCounts.set(name, count + 1);
|
|
83
|
+
if (count === 0) {
|
|
84
|
+
if (clientConnected) {
|
|
85
|
+
rpc_types_1.rpcServerCalls.subscribeEvents([name]).catch((err) => {
|
|
86
|
+
console.error(`Failed to register event subscription with server: ${name}`, err);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
pendingNameSubscriptions.add(name);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function clientUnregisterName(name) {
|
|
95
|
+
if (unitTests || (0, rpc_types_1.isSingleProcessClient)())
|
|
96
|
+
return;
|
|
97
|
+
const count = clientNameRefCounts.get(name) || 0;
|
|
98
|
+
if (count <= 1) {
|
|
99
|
+
clientNameRefCounts.delete(name);
|
|
100
|
+
pendingNameSubscriptions.delete(name);
|
|
101
|
+
if (clientConnected) {
|
|
102
|
+
rpc_types_1.rpcServerCalls.unsubscribeEvents([name]).catch((err) => {
|
|
103
|
+
console.error(`Failed to unregister event subscription with server: ${name}`, err);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
clientNameRefCounts.set(name, count - 1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Register a prefix-based event subscription with the server.
|
|
113
|
+
* Events whose name starts with this prefix will be forwarded to the client.
|
|
114
|
+
* Returns an unsubscribe function that decrements the refcount.
|
|
115
|
+
*/
|
|
116
|
+
function subscribePrefix(prefix) {
|
|
117
|
+
if (!rpc_types_1.isClient || unitTests || (0, rpc_types_1.isSingleProcessClient)()) {
|
|
118
|
+
return () => { };
|
|
119
|
+
}
|
|
120
|
+
const count = clientPrefixRefCounts.get(prefix) || 0;
|
|
121
|
+
clientPrefixRefCounts.set(prefix, count + 1);
|
|
122
|
+
if (count === 0) {
|
|
123
|
+
if (clientConnected) {
|
|
124
|
+
rpc_types_1.rpcServerCalls.subscribePrefixes([prefix]).catch((err) => {
|
|
125
|
+
console.error(`Failed to register prefix subscription with server: ${prefix}`, err);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
pendingPrefixSubscriptions.add(prefix);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return () => {
|
|
133
|
+
const current = clientPrefixRefCounts.get(prefix) || 0;
|
|
134
|
+
if (current <= 1) {
|
|
135
|
+
clientPrefixRefCounts.delete(prefix);
|
|
136
|
+
pendingPrefixSubscriptions.delete(prefix);
|
|
137
|
+
if (clientConnected) {
|
|
138
|
+
rpc_types_1.rpcServerCalls.unsubscribePrefixes([prefix]).catch((err) => {
|
|
139
|
+
console.error(`Failed to unregister prefix subscription with server: ${prefix}`, err);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
clientPrefixRefCounts.set(prefix, current - 1);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// ─── Server-Side Event Forwarding Gate ───────────────────────────────────────
|
|
149
|
+
// The server uses this to decide whether to forward an event to the client.
|
|
150
|
+
/** Event names the client has subscribed to. Server-side only. */
|
|
151
|
+
const serverClientNames = new Set();
|
|
152
|
+
/** Event prefixes the client has subscribed to. Server-side only. */
|
|
153
|
+
const serverClientPrefixes = new Set();
|
|
154
|
+
/**
|
|
155
|
+
* Check whether the client wants this event.
|
|
156
|
+
* Used by the server to gate `rpcClientCalls.emitEvent`.
|
|
157
|
+
*/
|
|
158
|
+
function clientWantsEvent(event) {
|
|
159
|
+
if (serverClientNames.has(event.name))
|
|
160
|
+
return true;
|
|
161
|
+
for (const prefix of serverClientPrefixes) {
|
|
162
|
+
if (event.name.startsWith(prefix))
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
12
168
|
function subscribe(nameOrFilter, handler) {
|
|
169
|
+
let eventName;
|
|
170
|
+
let filter;
|
|
13
171
|
if (typeof nameOrFilter === "string") {
|
|
14
|
-
|
|
15
|
-
|
|
172
|
+
eventName = nameOrFilter;
|
|
173
|
+
filter = (evt) => evt.name === eventName;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
filter = nameOrFilter;
|
|
177
|
+
}
|
|
178
|
+
const subscription = { filter, handler, eventName };
|
|
179
|
+
addSubscription(subscription);
|
|
180
|
+
if (rpc_types_1.isClient && eventName) {
|
|
181
|
+
clientRegisterName(eventName);
|
|
16
182
|
}
|
|
17
|
-
const filter = nameOrFilter;
|
|
18
|
-
const subscription = {
|
|
19
|
-
filter,
|
|
20
|
-
handler,
|
|
21
|
-
};
|
|
22
|
-
subscriptions.push(subscription);
|
|
23
183
|
return {
|
|
24
184
|
unsubscribe: () => {
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
return true;
|
|
185
|
+
const removed = removeSubscription(subscription);
|
|
186
|
+
if (removed && rpc_types_1.isClient && eventName) {
|
|
187
|
+
clientUnregisterName(eventName);
|
|
29
188
|
}
|
|
30
|
-
return
|
|
189
|
+
return removed;
|
|
31
190
|
},
|
|
32
191
|
};
|
|
33
192
|
}
|
|
34
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
35
193
|
function subscribeDebounce(nameOrFilter, handler, debounceMs) {
|
|
36
194
|
let pid = 0;
|
|
37
195
|
const handlerDebounced = (evt) => {
|
|
@@ -46,37 +204,64 @@ function subscribeDebounce(nameOrFilter, handler, debounceMs) {
|
|
|
46
204
|
return subscribe(nameOrFilter, handlerDebounced);
|
|
47
205
|
}
|
|
48
206
|
async function emit(event, dontPropagate) {
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
207
|
+
const matched = [];
|
|
208
|
+
const bucket = nameIndex.get(event.name);
|
|
209
|
+
if (bucket) {
|
|
210
|
+
for (const sub of bucket) {
|
|
211
|
+
matched.push(sub);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
for (const sub of wildcardSubscriptions) {
|
|
215
|
+
if (sub.filter(event)) {
|
|
216
|
+
matched.push(sub);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const handlerPromises = matched.map(async (subscription) => {
|
|
52
220
|
try {
|
|
53
221
|
return await subscription.handler(event);
|
|
54
222
|
}
|
|
55
223
|
catch (err) {
|
|
56
|
-
console.error(`An unhandled error occurred in a handler while processing event: ${JSON.stringify({ event
|
|
224
|
+
console.error(`An unhandled error occurred in a handler while processing event: ${JSON.stringify({ event })}`, err);
|
|
57
225
|
return false;
|
|
58
226
|
}
|
|
59
227
|
});
|
|
60
|
-
// if (!(dontPropagate || unitTests)) {
|
|
61
|
-
// matchedHandlerPromises.push(
|
|
62
|
-
// isClient
|
|
63
|
-
// ? rpcServerCalls.emitEvent(event).catch((err) => { console.error(`Error while propagating event to server`, err); return false; })
|
|
64
|
-
// : rpcClientCalls.emitEvent(event).catch((err) => { console.error(`Error while propagating event to client`, err); return false; })
|
|
65
|
-
// );
|
|
66
|
-
// }
|
|
67
228
|
if (!(dontPropagate || unitTests || (0, rpc_types_1.isSingleProcessClient)())) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
229
|
+
if (clientWantsEvent(event)) {
|
|
230
|
+
handlerPromises.push(rpc_types_1.rpcClientCalls.emitEvent(event).catch((err) => {
|
|
231
|
+
console.error(`Error while propagating event to client`, err);
|
|
232
|
+
return false;
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
72
235
|
}
|
|
73
|
-
const results = await Promise.all(
|
|
74
|
-
// if any handlers returned false (or errored), return false, otherwise return true
|
|
236
|
+
const results = await Promise.all(handlerPromises);
|
|
75
237
|
return !results.some((r) => r === false);
|
|
76
238
|
}
|
|
77
239
|
if (rpc_types_1.isClient) {
|
|
78
240
|
rpc_types_1.rpcClientCalls.emitEvent = (event) => emit(event, true);
|
|
79
241
|
}
|
|
242
|
+
// Server-side: register RPC handlers for client subscription management
|
|
243
|
+
if (!rpc_types_1.isClient) {
|
|
244
|
+
rpc_types_1.rpcServerCalls.subscribeEvents = async (names) => {
|
|
245
|
+
for (const name of names) {
|
|
246
|
+
serverClientNames.add(name);
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
rpc_types_1.rpcServerCalls.unsubscribeEvents = async (names) => {
|
|
250
|
+
for (const name of names) {
|
|
251
|
+
serverClientNames.delete(name);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
rpc_types_1.rpcServerCalls.subscribePrefixes = async (prefixes) => {
|
|
255
|
+
for (const prefix of prefixes) {
|
|
256
|
+
serverClientPrefixes.add(prefix);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
rpc_types_1.rpcServerCalls.unsubscribePrefixes = async (prefixes) => {
|
|
260
|
+
for (const prefix of prefixes) {
|
|
261
|
+
serverClientPrefixes.delete(prefix);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
80
265
|
class Event {
|
|
81
266
|
_eventName;
|
|
82
267
|
constructor(_eventName) {
|
|
@@ -119,7 +304,6 @@ class Emitter {
|
|
|
119
304
|
}
|
|
120
305
|
}
|
|
121
306
|
exports.Emitter = Emitter;
|
|
122
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
123
307
|
function unionEvents(...events) {
|
|
124
308
|
const eventName = events.map((s) => s.eventName()).join("|");
|
|
125
309
|
return {
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
exports.tools = exports.workflowLogSchema = exports.WorkflowLogs = exports.getLogger = exports.orm = exports.data = void 0;
|
|
18
18
|
__exportStar(require("./context"), exports);
|
|
19
|
+
__exportStar(require("./contracts"), exports);
|
|
19
20
|
__exportStar(require("./data"), exports);
|
|
20
21
|
exports.data = require("./data");
|
|
21
22
|
__exportStar(require("./data/orm"), exports);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DataContext } from "../context/data-context";
|
|
2
|
+
import type { ContractRegistry } from "../contracts/registry";
|
|
3
|
+
import type { IPackageDefinitionResult } from "../contracts/types";
|
|
4
|
+
/**
|
|
5
|
+
* Installs a contract-based package into a DataContext.
|
|
6
|
+
*
|
|
7
|
+
* Handles packages that export an `IPackageDefinitionResult` from `definePackage()`.
|
|
8
|
+
* Registers contracts in the provided ContractRegistry, saves tools/assistants/workflows
|
|
9
|
+
* with the `packageId` from the definition set, and registers table definitions.
|
|
10
|
+
*/
|
|
11
|
+
export declare function installContractPackage(dataContext: DataContext, packageDefinition: IPackageDefinitionResult, opts?: {
|
|
12
|
+
registry?: ContractRegistry;
|
|
13
|
+
}): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Attempts to extract an `IPackageDefinitionResult` from a bundle's module exports.
|
|
16
|
+
* Returns undefined if the bundle doesn't export a contract-based package definition.
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractPackageDefinition(bundleExports: Record<string, unknown>): IPackageDefinitionResult | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Determines whether a bundle exports a contract-based package definition,
|
|
21
|
+
* indicating it should be installed via the new contract-aware path.
|
|
22
|
+
*/
|
|
23
|
+
export declare function hasPackageDefinition(bundleExports: Record<string, unknown>): boolean;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.installContractPackage = installContractPackage;
|
|
4
|
+
exports.extractPackageDefinition = extractPackageDefinition;
|
|
5
|
+
exports.hasPackageDefinition = hasPackageDefinition;
|
|
6
|
+
const tools_1 = require("../data/tools");
|
|
7
|
+
const tools_2 = require("../tools");
|
|
8
|
+
/**
|
|
9
|
+
* Installs a contract-based package into a DataContext.
|
|
10
|
+
*
|
|
11
|
+
* Handles packages that export an `IPackageDefinitionResult` from `definePackage()`.
|
|
12
|
+
* Registers contracts in the provided ContractRegistry, saves tools/assistants/workflows
|
|
13
|
+
* with the `packageId` from the definition set, and registers table definitions.
|
|
14
|
+
*/
|
|
15
|
+
async function installContractPackage(dataContext, packageDefinition, opts) {
|
|
16
|
+
const { packageId } = packageDefinition;
|
|
17
|
+
const registry = opts?.registry;
|
|
18
|
+
// Register contracts in the in-memory registry
|
|
19
|
+
if (registry) {
|
|
20
|
+
for (const contract of packageDefinition.contracts) {
|
|
21
|
+
const key = `${contract.contractId}@${contract.version}`;
|
|
22
|
+
const alsoImpl = packageDefinition.alsoImplements.get(key) ?? [];
|
|
23
|
+
const result = registry.register(packageId, contract, alsoImpl);
|
|
24
|
+
if (!result.valid) {
|
|
25
|
+
console.error(`[ContractPackageLoader] Contract registration failed for ${contract.name}:`, result.errors);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Install tool instances with packageId
|
|
30
|
+
for (const toolInstance of packageDefinition.toolInstances) {
|
|
31
|
+
(0, tools_2.registerTool)(toolInstance);
|
|
32
|
+
const toolWithPackageId = { ...toolInstance.tool, packageId };
|
|
33
|
+
await (0, tools_1.Tools)(dataContext).save(toolWithPackageId);
|
|
34
|
+
}
|
|
35
|
+
// Install table definitions
|
|
36
|
+
for (const tableDefinition of packageDefinition.tableDefinitions) {
|
|
37
|
+
dataContext.tableContainer.registerTableDefinition(tableDefinition, {
|
|
38
|
+
overwrite: true,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// Install assistants with packageId
|
|
42
|
+
const { Assistants } = await Promise.resolve().then(() => require("../data/assistants"));
|
|
43
|
+
for (const assistant of packageDefinition.assistants) {
|
|
44
|
+
const assistantWithPackageId = { ...assistant, packageId };
|
|
45
|
+
await Assistants(dataContext).save(assistantWithPackageId);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Attempts to extract an `IPackageDefinitionResult` from a bundle's module exports.
|
|
50
|
+
* Returns undefined if the bundle doesn't export a contract-based package definition.
|
|
51
|
+
*/
|
|
52
|
+
function extractPackageDefinition(bundleExports) {
|
|
53
|
+
const def = bundleExports?.packageDefinition;
|
|
54
|
+
if (def && Array.isArray(def.contracts) && def.contracts.length > 0) {
|
|
55
|
+
return def;
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Determines whether a bundle exports a contract-based package definition,
|
|
61
|
+
* indicating it should be installed via the new contract-aware path.
|
|
62
|
+
*/
|
|
63
|
+
function hasPackageDefinition(bundleExports) {
|
|
64
|
+
return extractPackageDefinition(bundleExports) !== undefined;
|
|
65
|
+
}
|
|
@@ -14,4 +14,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./contract-package-loader"), exports);
|
|
17
18
|
__exportStar(require("./package-loader"), exports);
|
|
@@ -6,8 +6,12 @@ export declare class PackageLoader {
|
|
|
6
6
|
static PeersSDK: any;
|
|
7
7
|
static Zod: any;
|
|
8
8
|
private packageInstances;
|
|
9
|
+
/** Packages that were installed via the contract-based path (tools/assistants/tables already saved with packageId). */
|
|
10
|
+
private contractInstalledPackages;
|
|
9
11
|
require: (<T>(module: string) => T) | undefined;
|
|
10
12
|
constructor(dataContext: DataContext);
|
|
13
|
+
/** Returns true if a package was installed via the contract-based definePackage() path. */
|
|
14
|
+
isContractInstalled(packageId: string): boolean;
|
|
11
15
|
loadAllPackages(opts?: {
|
|
12
16
|
force?: boolean;
|
|
13
17
|
}): Promise<void>;
|
|
@@ -16,6 +20,13 @@ export declare class PackageLoader {
|
|
|
16
20
|
localPath?: string;
|
|
17
21
|
}): Promise<IPeersPackage | undefined>;
|
|
18
22
|
private _readLocalBundle;
|
|
23
|
+
/**
|
|
24
|
+
* Post-correction: if the package definition carries version/versionTag,
|
|
25
|
+
* update the active IPackageVersion record to match. This fixes cases where
|
|
26
|
+
* the PV record was created with stale or placeholder values (e.g. "0.0.1")
|
|
27
|
+
* before the bundle was evaluated.
|
|
28
|
+
*/
|
|
29
|
+
private correctPackageVersion;
|
|
19
30
|
private _evaluateBundle;
|
|
20
31
|
}
|
|
21
32
|
export declare function setDefaultRequire(require: <T>(module: string) => T): void;
|
|
@@ -7,15 +7,22 @@ const package_versions_1 = require("../data/package-versions");
|
|
|
7
7
|
const packages_1 = require("../data/packages");
|
|
8
8
|
const tools_1 = require("../data/tools");
|
|
9
9
|
const tools_2 = require("../tools");
|
|
10
|
+
const contract_package_loader_1 = require("./contract-package-loader");
|
|
10
11
|
class PackageLoader {
|
|
11
12
|
dataContext;
|
|
12
13
|
static PeersSDK;
|
|
13
14
|
static Zod;
|
|
14
15
|
packageInstances = {};
|
|
16
|
+
/** Packages that were installed via the contract-based path (tools/assistants/tables already saved with packageId). */
|
|
17
|
+
contractInstalledPackages = new Set();
|
|
15
18
|
require = undefined;
|
|
16
19
|
constructor(dataContext) {
|
|
17
20
|
this.dataContext = dataContext;
|
|
18
21
|
}
|
|
22
|
+
/** Returns true if a package was installed via the contract-based definePackage() path. */
|
|
23
|
+
isContractInstalled(packageId) {
|
|
24
|
+
return this.contractInstalledPackages.has(packageId);
|
|
25
|
+
}
|
|
19
26
|
async loadAllPackages(opts) {
|
|
20
27
|
const packages = await (0, packages_1.Packages)(this.dataContext).list();
|
|
21
28
|
await Promise.all(packages.filter((pkg) => !pkg.disabled).map((pkg) => this.loadPackage(pkg, opts)));
|
|
@@ -91,6 +98,36 @@ class PackageLoader {
|
|
|
91
98
|
return;
|
|
92
99
|
}
|
|
93
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Post-correction: if the package definition carries version/versionTag,
|
|
103
|
+
* update the active IPackageVersion record to match. This fixes cases where
|
|
104
|
+
* the PV record was created with stale or placeholder values (e.g. "0.0.1")
|
|
105
|
+
* before the bundle was evaluated.
|
|
106
|
+
*/
|
|
107
|
+
correctPackageVersion(pkg, def) {
|
|
108
|
+
if (!pkg.activePackageVersionId)
|
|
109
|
+
return;
|
|
110
|
+
if (!def.version && !def.versionTag)
|
|
111
|
+
return;
|
|
112
|
+
const pvTable = (0, package_versions_1.PackageVersions)(this.dataContext);
|
|
113
|
+
pvTable.get(pkg.activePackageVersionId).then((pv) => {
|
|
114
|
+
if (!pv)
|
|
115
|
+
return;
|
|
116
|
+
let needsUpdate = false;
|
|
117
|
+
const updated = { ...pv };
|
|
118
|
+
if (def.version && pv.version !== def.version) {
|
|
119
|
+
updated.version = def.version;
|
|
120
|
+
needsUpdate = true;
|
|
121
|
+
}
|
|
122
|
+
if (def.versionTag && pv.versionTag !== def.versionTag) {
|
|
123
|
+
updated.versionTag = def.versionTag;
|
|
124
|
+
needsUpdate = true;
|
|
125
|
+
}
|
|
126
|
+
if (needsUpdate) {
|
|
127
|
+
pvTable.save(updated);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
94
131
|
_evaluateBundle(pkg, bundleCode) {
|
|
95
132
|
// Node.js built-in modules that do not exist in React Native (and would cause
|
|
96
133
|
// a fatal native error if passed through to RN's require). We block them here
|
|
@@ -156,18 +193,32 @@ class PackageLoader {
|
|
|
156
193
|
const bundleFunction = new Function("module", "exports", "require", bundleCode);
|
|
157
194
|
bundleFunction(module, moduleExports, customRequire);
|
|
158
195
|
const bundleExports = module.exports;
|
|
196
|
+
// Check for contract-based package definition (new path)
|
|
197
|
+
const packageDefinition = (0, contract_package_loader_1.extractPackageDefinition)(bundleExports);
|
|
198
|
+
if (packageDefinition) {
|
|
199
|
+
if (packageDefinition.packageId !== pkg.packageId) {
|
|
200
|
+
console.warn(`[PackageLoader] packageId mismatch: definition has "${packageDefinition.packageId}" but DB record has "${pkg.packageId}"`);
|
|
201
|
+
}
|
|
202
|
+
(0, contract_package_loader_1.installContractPackage)(this.dataContext, packageDefinition);
|
|
203
|
+
this.contractInstalledPackages.add(packageDefinition.packageId);
|
|
204
|
+
this.correctPackageVersion(pkg, packageDefinition);
|
|
205
|
+
}
|
|
206
|
+
// Legacy path: extract IPeersPackage for backward compat
|
|
159
207
|
const packageInstance = bundleExports?.exports || bundleExports?.package || bundleExports?.default || bundleExports;
|
|
160
208
|
this.packageInstances[pkg.packageId] = packageInstance;
|
|
161
209
|
if (packageInstance && typeof packageInstance === "object") {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
210
|
+
// Skip legacy tool/table registration if the contract path already handled it
|
|
211
|
+
if (!packageDefinition) {
|
|
212
|
+
packageInstance.toolInstances?.forEach((toolInstance) => {
|
|
213
|
+
(0, tools_2.registerTool)(toolInstance);
|
|
214
|
+
(0, tools_1.Tools)(this.dataContext).save(toolInstance.tool);
|
|
215
|
+
});
|
|
216
|
+
packageInstance.tableDefinitions?.forEach((tableDefinition) => {
|
|
217
|
+
this.dataContext.tableContainer.registerTableDefinition(tableDefinition, {
|
|
218
|
+
overwrite: true,
|
|
219
|
+
});
|
|
169
220
|
});
|
|
170
|
-
}
|
|
221
|
+
}
|
|
171
222
|
return packageInstance;
|
|
172
223
|
}
|
|
173
224
|
return;
|
package/dist/rpc-types.d.ts
CHANGED
|
@@ -116,6 +116,10 @@ export declare const rpcServerCalls: {
|
|
|
116
116
|
voiceDisable: () => Promise<void>;
|
|
117
117
|
voiceEnable: () => Promise<void>;
|
|
118
118
|
flushDatabases: () => Promise<void>;
|
|
119
|
+
subscribeEvents: (names: string[]) => Promise<void>;
|
|
120
|
+
unsubscribeEvents: (names: string[]) => Promise<void>;
|
|
121
|
+
subscribePrefixes: (prefixes: string[]) => Promise<void>;
|
|
122
|
+
unsubscribePrefixes: (prefixes: string[]) => Promise<void>;
|
|
119
123
|
};
|
|
120
124
|
export declare const rpcClientCalls: {
|
|
121
125
|
ping: (msg: string) => Promise<string>;
|
package/dist/rpc-types.js
CHANGED
|
@@ -67,10 +67,11 @@ exports.rpcServerCalls = {
|
|
|
67
67
|
// Flush all in-memory database snapshots to durable storage (IndexedDB in PWA).
|
|
68
68
|
// No-op on Electron where better-sqlite3 writes are synchronous to disk.
|
|
69
69
|
flushDatabases: (async () => { }),
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
// Event subscription management (for selective proxying)
|
|
71
|
+
subscribeEvents: rpcStub("subscribeEvents"),
|
|
72
|
+
unsubscribeEvents: rpcStub("unsubscribeEvents"),
|
|
73
|
+
subscribePrefixes: rpcStub("subscribePrefixes"),
|
|
74
|
+
unsubscribePrefixes: rpcStub("unsubscribePrefixes"),
|
|
74
75
|
};
|
|
75
76
|
exports.rpcClientCalls = {
|
|
76
77
|
ping: async (msg) => `pong: ${msg}`,
|
package/dist/types/workflow.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export declare const workflowSchema: z.ZodObject<{
|
|
|
40
40
|
createdBy: z.ZodEffects<z.ZodString, string, string>;
|
|
41
41
|
createdAt: z.ZodDefault<z.ZodDate>;
|
|
42
42
|
updatedAt: z.ZodDefault<z.ZodDate>;
|
|
43
|
+
packageId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
43
44
|
}, "strip", z.ZodTypeAny, {
|
|
44
45
|
name: string;
|
|
45
46
|
description: string;
|
|
@@ -54,12 +55,14 @@ export declare const workflowSchema: z.ZodObject<{
|
|
|
54
55
|
subWorkflowId?: string | undefined;
|
|
55
56
|
}[];
|
|
56
57
|
updatedAt: Date;
|
|
58
|
+
packageId?: string | undefined;
|
|
57
59
|
}, {
|
|
58
60
|
name: string;
|
|
59
61
|
description: string;
|
|
60
62
|
createdBy: string;
|
|
61
63
|
workflowId: string;
|
|
62
64
|
defaultAssistantId: string;
|
|
65
|
+
packageId?: string | undefined;
|
|
63
66
|
createdAt?: Date | undefined;
|
|
64
67
|
instructions?: {
|
|
65
68
|
markdown?: string | undefined;
|
package/dist/types/workflow.js
CHANGED
package/dist/utils.d.ts
CHANGED
|
@@ -31,6 +31,21 @@ export declare function simpleHash(str: string): number;
|
|
|
31
31
|
export type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
32
32
|
/** `simpleHash` of JSON-stable stringification of an object. */
|
|
33
33
|
export declare function simpleObjectHash(obj: any): number;
|
|
34
|
+
/**
|
|
35
|
+
* Generates a deterministic 25-character peer ID for a persistent variable.
|
|
36
|
+
* The ID has the fixed prefix `000pvar0` (8 chars) followed by 17 base-36 characters
|
|
37
|
+
* derived from a SHA-512 hash of the input name. Two calls with the same name always
|
|
38
|
+
* return the same ID.
|
|
39
|
+
*
|
|
40
|
+
* @param name The persistent variable name as stored in the database
|
|
41
|
+
* (already includes group suffixes for groupDevice/groupUser scopes)
|
|
42
|
+
*/
|
|
43
|
+
export declare function deterministicPvarId(name: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Returns whether a peer ID was generated by {@link deterministicPvarId}
|
|
46
|
+
* (starts with the `000pvar0` prefix).
|
|
47
|
+
*/
|
|
48
|
+
export declare function isDeterministicPvarId(id: string): boolean;
|
|
34
49
|
/** Resolves after `ms` milliseconds (0 yields a microtask-yield on most runtimes). */
|
|
35
50
|
export declare function sleep(ms?: number): Promise<void>;
|
|
36
51
|
/** Turns `fooBar` into `Foo Bar` for labels (also replaces `_` with space). */
|