@peers-app/peers-sdk 0.19.14 → 0.20.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.
Files changed (86) hide show
  1. package/dist/contracts/__tests__/builder.test.js +24 -0
  2. package/dist/contracts/__tests__/contract-events.test.d.ts +1 -0
  3. package/dist/contracts/__tests__/contract-events.test.js +199 -0
  4. package/dist/contracts/__tests__/contract-observables.test.d.ts +1 -0
  5. package/dist/contracts/__tests__/contract-observables.test.js +290 -0
  6. package/dist/contracts/__tests__/contract-provider-router.test.d.ts +1 -0
  7. package/dist/contracts/__tests__/contract-provider-router.test.js +193 -0
  8. package/dist/contracts/__tests__/contract-proxy.test.d.ts +1 -0
  9. package/dist/contracts/__tests__/contract-proxy.test.js +424 -0
  10. package/dist/contracts/__tests__/contract-resolvers.test.d.ts +1 -0
  11. package/dist/contracts/__tests__/contract-resolvers.test.js +148 -0
  12. package/dist/contracts/__tests__/contract-subscription-lifecycle.test.d.ts +1 -0
  13. package/dist/contracts/__tests__/contract-subscription-lifecycle.test.js +353 -0
  14. package/dist/contracts/__tests__/contract-table-events.test.d.ts +1 -0
  15. package/dist/contracts/__tests__/contract-table-events.test.js +209 -0
  16. package/dist/contracts/__tests__/contract-transport.test.d.ts +1 -0
  17. package/dist/contracts/__tests__/contract-transport.test.js +163 -0
  18. package/dist/contracts/__tests__/persistent-registry.test.d.ts +1 -0
  19. package/dist/contracts/__tests__/persistent-registry.test.js +109 -0
  20. package/dist/contracts/__tests__/playground.test.d.ts +1 -0
  21. package/dist/contracts/__tests__/playground.test.js +213 -0
  22. package/dist/contracts/__tests__/validate.test.js +122 -0
  23. package/dist/contracts/builder.d.ts +9 -1
  24. package/dist/contracts/builder.js +13 -0
  25. package/dist/contracts/contract-provider-router.d.ts +72 -0
  26. package/dist/contracts/contract-provider-router.js +164 -0
  27. package/dist/contracts/contract-proxy.d.ts +333 -0
  28. package/dist/contracts/contract-proxy.js +663 -0
  29. package/dist/contracts/contract-resolvers.d.ts +66 -0
  30. package/dist/contracts/contract-resolvers.js +138 -0
  31. package/dist/contracts/contract-transport.d.ts +94 -0
  32. package/dist/contracts/contract-transport.js +159 -0
  33. package/dist/contracts/contracts.table.d.ts +1 -1
  34. package/dist/contracts/contracts.table.js +2 -2
  35. package/dist/contracts/index.d.ts +7 -1
  36. package/dist/contracts/index.js +34 -1
  37. package/dist/contracts/persistent-registry.js +3 -1
  38. package/dist/contracts/system/device-operations-contract.d.ts +72 -0
  39. package/dist/contracts/system/device-operations-contract.js +110 -0
  40. package/dist/contracts/system/logs-contract.d.ts +24 -0
  41. package/dist/contracts/system/logs-contract.js +60 -0
  42. package/dist/contracts/types.d.ts +27 -4
  43. package/dist/contracts/validate.d.ts +2 -2
  44. package/dist/contracts/validate.js +44 -2
  45. package/dist/data/assistants.d.ts +4 -4
  46. package/dist/data/channels.d.ts +1 -1
  47. package/dist/data/devices.d.ts +1 -1
  48. package/dist/data/embeddings.d.ts +1 -1
  49. package/dist/data/group-secret.d.ts +21 -0
  50. package/dist/data/group-secret.js +53 -0
  51. package/dist/data/index.d.ts +1 -0
  52. package/dist/data/index.js +1 -0
  53. package/dist/data/messages.d.ts +1 -1
  54. package/dist/data/orm/decorators.d.ts +6 -0
  55. package/dist/data/orm/decorators.js +21 -0
  56. package/dist/data/package-versions.d.ts +2 -2
  57. package/dist/data/peer-types.d.ts +1 -1
  58. package/dist/data/persistent-vars.d.ts +17 -0
  59. package/dist/data/persistent-vars.js +115 -35
  60. package/dist/data/persistent-vars.migration.test.d.ts +1 -0
  61. package/dist/data/persistent-vars.migration.test.js +133 -0
  62. package/dist/data/table-definitions-table.d.ts +1 -1
  63. package/dist/data/tool-tests.d.ts +1 -1
  64. package/dist/data/tools.d.ts +1 -1
  65. package/dist/data/user-trust-levels.d.ts +3 -1
  66. package/dist/data/user-trust-levels.js +2 -1
  67. package/dist/data/user-trust-levels.test.d.ts +1 -0
  68. package/dist/data/user-trust-levels.test.js +37 -0
  69. package/dist/data/voice-messages.d.ts +1 -1
  70. package/dist/data/workflow-logs.d.ts +1 -1
  71. package/dist/data/workflow-runs.d.ts +2 -2
  72. package/dist/data/workflows.d.ts +3 -3
  73. package/dist/device/binary-peer-connection-v2.d.ts +2 -0
  74. package/dist/device/binary-peer-connection-v2.js +12 -2
  75. package/dist/device/binary-peer-connection-v2.test.js +23 -0
  76. package/dist/device/get-trust-level-fn.d.ts +6 -0
  77. package/dist/device/get-trust-level-fn.js +12 -7
  78. package/dist/device/get-trust-level-fn.test.js +16 -2
  79. package/dist/logging/console-logs.table.d.ts +3 -0
  80. package/dist/logging/console-logs.table.js +2 -1
  81. package/dist/rpc-types.d.ts +37 -0
  82. package/dist/rpc-types.js +13 -0
  83. package/dist/system-ids.d.ts +25 -0
  84. package/dist/system-ids.js +26 -1
  85. package/dist/types/workflow.d.ts +4 -4
  86. package/package.json +1 -1
@@ -54,8 +54,8 @@ declare const schema: z.ZodObject<{
54
54
  version: string;
55
55
  signature: string;
56
56
  packageId: string;
57
- createdBy: string;
58
57
  createdAt: string;
58
+ createdBy: string;
59
59
  packageVersionId: string;
60
60
  packageVersionHash: string;
61
61
  packageBundleFileId: string;
@@ -82,8 +82,8 @@ declare const schema: z.ZodObject<{
82
82
  version: string;
83
83
  signature: string;
84
84
  packageId: string;
85
- createdBy: string;
86
85
  createdAt: string;
86
+ createdBy: string;
87
87
  packageVersionId: string;
88
88
  packageVersionHash: string;
89
89
  packageBundleFileId: string;
@@ -91,7 +91,7 @@ declare const valueTypeSchema: z.ZodObject<{
91
91
  iconClass?: string | undefined;
92
92
  }>;
93
93
  export type IPeerType = z.infer<typeof valueTypeSchema>;
94
- export declare function PeerTypes(dataContext?: DataContext): import("./orm").Table<{
94
+ export declare function PeerTypes(dataContext?: DataContext): import("..").Table<{
95
95
  name: string;
96
96
  schema: {
97
97
  type: import("./tools").IOSchemaType;
@@ -52,20 +52,37 @@ declare const schema: z.ZodObject<{
52
52
  modifiedAt?: number | undefined;
53
53
  packageId?: string | undefined;
54
54
  }>;
55
+ /** Table metadata for persisted observable variables. */
55
56
  export declare const persistentVarsMetaData: ITableMetaData;
57
+ /** Stored record for one persistent variable. */
56
58
  export type IPersistentVar = z.infer<typeof schema>;
59
+ /** Persistent-variable table with deterministic IDs and secret-value handling. */
57
60
  export declare class PersistentVarsTable extends Table<IPersistentVar> {
61
+ /** Insert a persistent variable through the canonical save path. */
58
62
  insert(persistentVar: IPersistentVar): Promise<IPersistentVar>;
63
+ /** Update a persistent variable through the canonical save path. */
59
64
  update(persistentVar: IPersistentVar): Promise<IPersistentVar>;
65
+ /** Save a variable, assigning its deterministic ID and encrypting new secret plaintext. */
60
66
  save(persistentVar: IPersistentVar, opts?: ISaveOptions): Promise<IPersistentVar>;
67
+ /**
68
+ * Replace a legacy random record ID without re-encrypting its already-stored value.
69
+ *
70
+ * Migration is storage-only: the value and modified timestamp are preserved. If the
71
+ * deterministic record already exists, it wins and the duplicate legacy row is removed.
72
+ */
73
+ migrateLegacyId(persistentVar: IPersistentVar): Promise<IPersistentVar>;
74
+ /** Return a stored variable's raw value by name. */
61
75
  getPersistentVarValue<T>(name: string): Promise<T | undefined>;
62
76
  }
77
+ /** Return the persistent-variable table for a data context. */
63
78
  export declare function PersistentVars(dataContext?: DataContext): PersistentVarsTable;
79
+ /** Reactive persistent value with an awaitable initial load and explicit deletion. */
64
80
  export type PersistentVar<T> = Observable<T> & {
65
81
  loadingPromise: Promise<PersistentVar<T>>;
66
82
  /** Delete the persistent variable from the database and reset to default value */
67
83
  delete: () => Promise<void>;
68
84
  };
85
+ /** Resolve a persistent-variable record by name, preferring device scope. */
69
86
  export declare function getPersistentVar(name: string, dataContext?: DataContext): Promise<IPersistentVar | undefined>;
70
87
  interface IPersistentVarOptionsBase {
71
88
  scope?: "device" | "user" | "group" | "groupDevice" | "groupUser";
@@ -5,6 +5,40 @@
5
5
  * Tests for this module are located in peers-device/src/persistent-vars.test.ts
6
6
  * (requires SQLite which is not available in peers-sdk)
7
7
  */
8
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
9
+ var useValue = arguments.length > 2;
10
+ for (var i = 0; i < initializers.length; i++) {
11
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
12
+ }
13
+ return useValue ? value : void 0;
14
+ };
15
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
16
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
17
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
18
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
19
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
20
+ var _, done = false;
21
+ for (var i = decorators.length - 1; i >= 0; i--) {
22
+ var context = {};
23
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
24
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
25
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
26
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
27
+ if (kind === "accessor") {
28
+ if (result === void 0) continue;
29
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
30
+ if (_ = accept(result.get)) descriptor.get = _;
31
+ if (_ = accept(result.set)) descriptor.set = _;
32
+ if (_ = accept(result.init)) initializers.unshift(_);
33
+ }
34
+ else if (_ = accept(result)) {
35
+ if (kind === "field") initializers.unshift(_);
36
+ else descriptor[key] = _;
37
+ }
38
+ }
39
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
40
+ done = true;
41
+ };
8
42
  Object.defineProperty(exports, "__esModule", { value: true });
9
43
  exports.PersistentVarsTable = exports.persistentVarsMetaData = void 0;
10
44
  exports.PersistentVars = PersistentVars;
@@ -21,6 +55,7 @@ const observable_1 = require("../observable");
21
55
  const rpc_types_1 = require("../rpc-types");
22
56
  const zod_types_1 = require("../types/zod-types");
23
57
  const utils_1 = require("../utils");
58
+ const decorators_1 = require("./orm/decorators");
24
59
  const table_1 = require("./orm/table");
25
60
  const table_definitions_system_1 = require("./orm/table-definitions.system");
26
61
  const types_1 = require("./orm/types");
@@ -44,6 +79,7 @@ const schema = zod_1.z.object({
44
79
  .optional()
45
80
  .describe("The package that owns this persistent variable, if any"),
46
81
  });
82
+ /** Table metadata for persisted observable variables. */
47
83
  exports.persistentVarsMetaData = {
48
84
  name: "PersistentVars",
49
85
  description: "table to persist variables across sessions and devices",
@@ -52,46 +88,93 @@ exports.persistentVarsMetaData = {
52
88
  iconClassName: "bi bi-braces",
53
89
  indexes: [{ fields: ["name"], unique: true }],
54
90
  };
55
- class PersistentVarsTable extends table_1.Table {
56
- async insert(persistentVar) {
57
- return this.save(persistentVar);
58
- }
59
- async update(persistentVar) {
60
- return this.save(persistentVar);
61
- }
62
- async save(persistentVar, opts) {
63
- if (!persistentVar.persistentVarId) {
64
- persistentVar.persistentVarId = (0, utils_1.deterministicPvarId)(persistentVar.name);
91
+ /** Persistent-variable table with deterministic IDs and secret-value handling. */
92
+ let PersistentVarsTable = (() => {
93
+ let _classSuper = table_1.Table;
94
+ let _instanceExtraInitializers = [];
95
+ let _migrateLegacyId_decorators;
96
+ return class PersistentVarsTable extends _classSuper {
97
+ static {
98
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
99
+ _migrateLegacyId_decorators = [(0, decorators_1.ProxyClientTableMethodCalls)()];
100
+ __esDecorate(this, null, _migrateLegacyId_decorators, { kind: "method", name: "migrateLegacyId", static: false, private: false, access: { has: obj => "migrateLegacyId" in obj, get: obj => obj.migrateLegacyId }, metadata: _metadata }, null, _instanceExtraInitializers);
101
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
102
+ }
103
+ /** Insert a persistent variable through the canonical save path. */
104
+ async insert(persistentVar) {
105
+ return this.save(persistentVar);
106
+ }
107
+ /** Update a persistent variable through the canonical save path. */
108
+ async update(persistentVar) {
109
+ return this.save(persistentVar);
110
+ }
111
+ /** Save a variable, assigning its deterministic ID and encrypting new secret plaintext. */
112
+ async save(persistentVar, opts) {
113
+ if (!persistentVar.persistentVarId) {
114
+ persistentVar.persistentVarId = (0, utils_1.deterministicPvarId)(persistentVar.name);
115
+ }
116
+ const dbVar = await this.get(persistentVar.persistentVarId);
117
+ if (persistentVar.isSecret &&
118
+ persistentVar.value.value !== undefined &&
119
+ (!rpc_types_1.isClient || (0, rpc_types_1.isSingleProcessClient)())) {
120
+ if (!dbVar ||
121
+ dbVar.value.value !== persistentVar.value.value ||
122
+ dbVar.isSecret !== persistentVar.isSecret) {
123
+ persistentVar.value.value = await rpc_types_1.rpcServerCalls.encryptData(persistentVar.value.value || "", this.groupId);
124
+ }
125
+ }
126
+ persistentVar.modifiedAt = Date.now();
127
+ opts ??= {};
128
+ opts = { saveAsSnapshot: true, ...opts };
129
+ return super.save(persistentVar, opts);
130
+ }
131
+ /**
132
+ * Replace a legacy random record ID without re-encrypting its already-stored value.
133
+ *
134
+ * Migration is storage-only: the value and modified timestamp are preserved. If the
135
+ * deterministic record already exists, it wins and the duplicate legacy row is removed.
136
+ */
137
+ async migrateLegacyId(persistentVar) {
138
+ if ((0, utils_1.isDeterministicPvarId)(persistentVar.persistentVarId)) {
139
+ return persistentVar;
140
+ }
141
+ const deterministicId = (0, utils_1.deterministicPvarId)(persistentVar.name);
142
+ const existing = await this.get(deterministicId);
143
+ await super.delete(persistentVar);
144
+ if (existing) {
145
+ return existing;
146
+ }
147
+ const migrated = { ...persistentVar, persistentVarId: deterministicId };
148
+ try {
149
+ return await super.save(migrated, { saveAsSnapshot: true });
150
+ }
151
+ catch (error) {
152
+ await super.save(persistentVar, { saveAsSnapshot: true }).catch(() => { });
153
+ throw error;
154
+ }
65
155
  }
66
- const dbVar = await this.get(persistentVar.persistentVarId);
67
- if (persistentVar.isSecret &&
68
- persistentVar.value.value !== undefined &&
69
- (!rpc_types_1.isClient || (0, rpc_types_1.isSingleProcessClient)())) {
70
- if (!dbVar ||
71
- dbVar.value.value !== persistentVar.value.value ||
72
- dbVar.isSecret !== persistentVar.isSecret) {
73
- persistentVar.value.value = await rpc_types_1.rpcServerCalls.encryptData(persistentVar.value.value || "", this.groupId);
156
+ /** Return a stored variable's raw value by name. */
157
+ async getPersistentVarValue(name) {
158
+ const pVars = await this.list({ name });
159
+ if (pVars.length > 1) {
160
+ console.warn(`Multiple persistent variables found with name "${name}". Using the last one.`);
74
161
  }
162
+ const pVar = pVars[pVars.length - 1];
163
+ return pVar?.value?.value;
75
164
  }
76
- persistentVar.modifiedAt = Date.now();
77
- opts ??= {};
78
- opts = { saveAsSnapshot: true, ...opts };
79
- return super.save(persistentVar, opts);
80
- }
81
- async getPersistentVarValue(name) {
82
- const pVars = await this.list({ name });
83
- if (pVars.length > 1) {
84
- console.warn(`Multiple persistent variables found with name "${name}". Using the last one.`);
165
+ constructor() {
166
+ super(...arguments);
167
+ __runInitializers(this, _instanceExtraInitializers);
85
168
  }
86
- const pVar = pVars[pVars.length - 1];
87
- return pVar?.value?.value;
88
- }
89
- }
169
+ };
170
+ })();
90
171
  exports.PersistentVarsTable = PersistentVarsTable;
91
172
  (0, table_definitions_system_1.registerSystemTableDefinition)(exports.persistentVarsMetaData, schema, PersistentVarsTable);
173
+ /** Return the persistent-variable table for a data context. */
92
174
  function PersistentVars(dataContext) {
93
175
  return (0, user_context_singleton_1.getTableContainer)(dataContext).getTable(exports.persistentVarsMetaData, schema, PersistentVarsTable);
94
176
  }
177
+ /** Resolve a persistent-variable record by name, preferring device scope. */
95
178
  async function getPersistentVar(name, dataContext) {
96
179
  const pVars = await PersistentVars(dataContext).list({ name });
97
180
  if (!pVars.length) {
@@ -210,10 +293,7 @@ function persistentVarFactory(name, opts) {
210
293
  }
211
294
  }
212
295
  if (dbRec && !(0, utils_1.isDeterministicPvarId)(dbRec.persistentVarId)) {
213
- const newId = (0, utils_1.deterministicPvarId)(name);
214
- await table.delete(dbRec);
215
- dbRec.persistentVarId = newId;
216
- dbRec = await table.save(dbRec);
296
+ dbRec = await table.migrateLegacyId(dbRec);
217
297
  }
218
298
  if (!dbRec) {
219
299
  dbRec = {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const originalClientFlag = process.env.PEERS_IS_CLIENT;
4
+ function createEventRegistry() {
5
+ return {
6
+ getEmitter: jest.fn().mockReturnValue({
7
+ event: { subscribe: jest.fn() },
8
+ emit: jest.fn(),
9
+ }),
10
+ };
11
+ }
12
+ function createLegacyRecord(name) {
13
+ return {
14
+ persistentVarId: "00mriijkhq94msfe9m2j6quwp",
15
+ name,
16
+ scope: "device",
17
+ isSecret: true,
18
+ value: { value: "encrypted:ciphertext" },
19
+ modifiedAt: 1234,
20
+ };
21
+ }
22
+ afterEach(() => {
23
+ if (originalClientFlag === undefined) {
24
+ delete process.env.PEERS_IS_CLIENT;
25
+ }
26
+ else {
27
+ process.env.PEERS_IS_CLIENT = originalClientFlag;
28
+ }
29
+ jest.resetModules();
30
+ jest.restoreAllMocks();
31
+ });
32
+ describe("PersistentVars legacy ID migration", () => {
33
+ it("uses one custom table RPC from a renderer client", async () => {
34
+ process.env.PEERS_IS_CLIENT = "true";
35
+ jest.resetModules();
36
+ await jest.isolateModulesAsync(async () => {
37
+ jest.doMock("../context/user-context-singleton", () => ({
38
+ getTableContainer: jest.fn(),
39
+ getUserContext: jest.fn(),
40
+ }));
41
+ const { PersistentVarsTable, persistentVarsMetaData } = await Promise.resolve().then(() => require("./persistent-vars"));
42
+ const { ClientProxyDataSource } = await Promise.resolve().then(() => require("./orm/client-proxy.data-source"));
43
+ const { rpcServerCalls } = await Promise.resolve().then(() => require("../rpc-types"));
44
+ const record = createLegacyRecord("rendererMigration");
45
+ const migrated = { ...record, persistentVarId: "00mriijkhq94msfe9m2j6quwq" };
46
+ const tableMethodCall = jest.fn().mockResolvedValue(migrated);
47
+ rpcServerCalls.tableMethodCall = tableMethodCall;
48
+ const dataContextId = "00mriijkhq94msfe9m2j6qabc";
49
+ const table = new PersistentVarsTable(persistentVarsMetaData, {
50
+ dataSource: new ClientProxyDataSource(persistentVarsMetaData, undefined, dataContextId),
51
+ eventRegistry: createEventRegistry(),
52
+ });
53
+ await expect(table.migrateLegacyId(record)).resolves.toEqual(migrated);
54
+ expect(tableMethodCall).toHaveBeenCalledTimes(1);
55
+ expect(tableMethodCall).toHaveBeenCalledWith(dataContextId, "PersistentVars", "migrateLegacyId", record);
56
+ });
57
+ });
58
+ it("removes a legacy duplicate when the canonical record already exists", async () => {
59
+ delete process.env.PEERS_IS_CLIENT;
60
+ jest.resetModules();
61
+ await jest.isolateModulesAsync(async () => {
62
+ jest.doMock("../context/user-context-singleton", () => ({
63
+ getTableContainer: jest.fn(),
64
+ getUserContext: jest.fn(),
65
+ }));
66
+ const { PersistentVarsTable, persistentVarsMetaData } = await Promise.resolve().then(() => require("./persistent-vars"));
67
+ const { deterministicPvarId } = await Promise.resolve().then(() => require("../utils"));
68
+ const legacy = createLegacyRecord("existingCanonical");
69
+ const canonical = {
70
+ ...legacy,
71
+ persistentVarId: deterministicPvarId(legacy.name),
72
+ value: { value: "encrypted:canonical" },
73
+ };
74
+ const deleteRecord = jest.fn().mockResolvedValue(undefined);
75
+ const save = jest.fn();
76
+ const table = new PersistentVarsTable(persistentVarsMetaData, {
77
+ dataSource: {
78
+ tableName: "PersistentVars",
79
+ primaryKeyName: "persistentVarId",
80
+ get: jest.fn().mockResolvedValue(canonical),
81
+ list: jest.fn(),
82
+ count: jest.fn(),
83
+ save,
84
+ insert: jest.fn(),
85
+ update: jest.fn(),
86
+ delete: deleteRecord,
87
+ },
88
+ eventRegistry: createEventRegistry(),
89
+ });
90
+ await expect(table.migrateLegacyId(legacy)).resolves.toEqual(canonical);
91
+ expect(deleteRecord).toHaveBeenCalledWith(legacy);
92
+ expect(save).not.toHaveBeenCalled();
93
+ });
94
+ });
95
+ it("restores the legacy record when writing the canonical ID fails", async () => {
96
+ delete process.env.PEERS_IS_CLIENT;
97
+ jest.resetModules();
98
+ await jest.isolateModulesAsync(async () => {
99
+ jest.doMock("../context/user-context-singleton", () => ({
100
+ getTableContainer: jest.fn(),
101
+ getUserContext: jest.fn(),
102
+ }));
103
+ const { PersistentVarsTable, persistentVarsMetaData } = await Promise.resolve().then(() => require("./persistent-vars"));
104
+ const legacy = createLegacyRecord("rollbackMigration");
105
+ const migrationError = new Error("canonical write failed");
106
+ const deleteRecord = jest.fn().mockResolvedValue(undefined);
107
+ const save = jest.fn().mockRejectedValueOnce(migrationError).mockResolvedValueOnce(legacy);
108
+ const table = new PersistentVarsTable(persistentVarsMetaData, {
109
+ dataSource: {
110
+ tableName: "PersistentVars",
111
+ primaryKeyName: "persistentVarId",
112
+ get: jest.fn().mockResolvedValue(undefined),
113
+ list: jest.fn(),
114
+ count: jest.fn(),
115
+ save,
116
+ insert: jest.fn(),
117
+ update: jest.fn(),
118
+ delete: deleteRecord,
119
+ },
120
+ eventRegistry: createEventRegistry(),
121
+ });
122
+ await expect(table.migrateLegacyId(legacy)).rejects.toBe(migrationError);
123
+ expect(deleteRecord).toHaveBeenCalledWith(legacy);
124
+ expect(save).toHaveBeenCalledTimes(2);
125
+ expect(save.mock.calls[0][0]).toMatchObject({
126
+ name: legacy.name,
127
+ value: legacy.value,
128
+ });
129
+ expect(save.mock.calls[0][0].persistentVarId).not.toBe(legacy.persistentVarId);
130
+ expect(save.mock.calls[1][0]).toEqual(legacy);
131
+ });
132
+ });
133
+ });
@@ -34,7 +34,7 @@ export type ITableDefinitionRecord = z.infer<typeof tableDefinitionRecordSchema>
34
34
  *
35
35
  * @param dataContext - Optional data context; when omitted the singleton context is used.
36
36
  */
37
- export declare function TableDefinitions(dataContext?: DataContext): import("./orm").Table<{
37
+ export declare function TableDefinitions(dataContext?: DataContext): import("..").Table<{
38
38
  name: string;
39
39
  metaData: {} & {
40
40
  [k: string]: any;
@@ -26,7 +26,7 @@ export declare const toolTestSchema: z.ZodObject<{
26
26
  mocks?: any;
27
27
  }>;
28
28
  export type IToolTest = z.infer<typeof toolTestSchema>;
29
- export declare function ToolTests(dataContext?: DataContext): import("./orm").Table<{
29
+ export declare function ToolTests(dataContext?: DataContext): import("..").Table<{
30
30
  code: string;
31
31
  description: string;
32
32
  toolId: string;
@@ -313,7 +313,7 @@ export interface IToolInstance {
313
313
  inputSchema?: z.ZodObject<any>;
314
314
  outputSchema?: z.ZodObject<any>;
315
315
  }
316
- export declare function Tools(dataContext?: DataContext): import("./orm").Table<{
316
+ export declare function Tools(dataContext?: DataContext): import("..").Table<{
317
317
  code: string;
318
318
  name: string;
319
319
  toolId: string;
@@ -24,8 +24,10 @@ export declare const userTrustLevelSchema: z.ZodObject<{
24
24
  assignedAt?: Date | undefined;
25
25
  notes?: string | undefined;
26
26
  }>;
27
+ /** A trust assignment for one user within a specific data context. */
27
28
  export type IUserTrustLevel = z.infer<typeof userTrustLevelSchema>;
28
- export declare function UserTrustLevels(dataContext?: DataContext): import("./orm").Table<{
29
+ /** Returns the context-scoped table containing explicit user trust assignments. */
30
+ export declare function UserTrustLevels(dataContext?: DataContext): import("..").Table<{
29
31
  userId: string;
30
32
  trustLevel: TrustLevel;
31
33
  assignedAt?: Date | undefined;
@@ -33,6 +33,7 @@ const metaData = {
33
33
  indexes: [{ fields: ["trustLevel"] }],
34
34
  };
35
35
  (0, table_definitions_system_1.registerSystemTableDefinition)(metaData, exports.userTrustLevelSchema);
36
+ /** Returns the context-scoped table containing explicit user trust assignments. */
36
37
  function UserTrustLevels(dataContext) {
37
38
  return (0, user_context_singleton_1.getTableContainer)(dataContext).getTable(metaData, exports.userTrustLevelSchema);
38
39
  }
@@ -41,7 +42,7 @@ function UserTrustLevels(dataContext) {
41
42
  * Returns TrustLevel.Unknown if no trust level has been assigned.
42
43
  */
43
44
  async function getUserTrustLevel(dataContext, userId) {
44
- const userContext = await (0, user_context_singleton_1.getUserContext)();
45
+ const userContext = dataContext.userContext;
45
46
  if (dataContext === userContext.userDataContext && userContext.userId === userId) {
46
47
  return socket_type_1.TrustLevel.Self;
47
48
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const socket_type_1 = require("../device/socket.type");
4
+ const utils_1 = require("../utils");
5
+ const user_trust_levels_1 = require("./user-trust-levels");
6
+ function makeDataContext(userId, trustRecord) {
7
+ const get = jest.fn().mockResolvedValue(trustRecord);
8
+ const userContext = { userId };
9
+ const dataContext = {
10
+ userContext,
11
+ tableContainer: {
12
+ getTable: jest.fn().mockReturnValue({ get }),
13
+ },
14
+ };
15
+ Object.assign(userContext, { userDataContext: dataContext });
16
+ return { dataContext, get };
17
+ }
18
+ describe("getUserTrustLevel", () => {
19
+ it("derives Self from the supplied personal context without a global user context", async () => {
20
+ const userId = (0, utils_1.newid)();
21
+ const { dataContext, get } = makeDataContext(userId);
22
+ await expect((0, user_trust_levels_1.getUserTrustLevel)(dataContext, userId)).resolves.toBe(socket_type_1.TrustLevel.Self);
23
+ expect(get).not.toHaveBeenCalled();
24
+ });
25
+ it("reads explicit trust from the supplied context", async () => {
26
+ const remoteUserId = (0, utils_1.newid)();
27
+ const { dataContext, get } = makeDataContext((0, utils_1.newid)(), {
28
+ trustLevel: socket_type_1.TrustLevel.Trusted,
29
+ });
30
+ await expect((0, user_trust_levels_1.getUserTrustLevel)(dataContext, remoteUserId)).resolves.toBe(socket_type_1.TrustLevel.Trusted);
31
+ expect(get).toHaveBeenCalledWith(remoteUserId);
32
+ });
33
+ it("returns Unknown when the supplied context has no trust assignment", async () => {
34
+ const { dataContext } = makeDataContext((0, utils_1.newid)());
35
+ await expect((0, user_trust_levels_1.getUserTrustLevel)(dataContext, (0, utils_1.newid)())).resolves.toBe(socket_type_1.TrustLevel.Unknown);
36
+ });
37
+ });
@@ -23,7 +23,7 @@ export declare const voiceMessageSchema: z.ZodObject<{
23
23
  threadId?: string | undefined;
24
24
  }>;
25
25
  export type IVoiceMessage = z.infer<typeof voiceMessageSchema>;
26
- export declare function VoiceMessages(dataContext?: DataContext): import("./orm").Table<{
26
+ export declare function VoiceMessages(dataContext?: DataContext): import("..").Table<{
27
27
  content: string;
28
28
  role: "user" | "assistant";
29
29
  createdAt: Date;
@@ -66,7 +66,7 @@ export declare const workflowLogSchema: z.ZodObject<{
66
66
  isError?: boolean | undefined;
67
67
  }>;
68
68
  export type IWorkflowLog = z.infer<typeof workflowLogSchema>;
69
- export declare function WorkflowLogs(dataContext?: DataContext): import("./orm").Table<{
69
+ export declare function WorkflowLogs(dataContext?: DataContext): import("..").Table<{
70
70
  workflowLogId: string;
71
71
  workflowRunId: string;
72
72
  contextId: string;
@@ -32,6 +32,7 @@ export declare const workflowRunSchema: z.ZodObject<{
32
32
  parentWorkflowRunId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
33
33
  defaultAssistantId: z.ZodEffects<z.ZodString, string, string>;
34
34
  }, "strip", z.ZodTypeAny, {
35
+ createdAt: Date;
35
36
  defaultAssistantId: string;
36
37
  instructions: {
37
38
  markdown?: string | undefined;
@@ -39,7 +40,6 @@ export declare const workflowRunSchema: z.ZodObject<{
39
40
  directCallToolId?: string | undefined;
40
41
  subWorkflowId?: string | undefined;
41
42
  }[];
42
- createdAt: Date;
43
43
  workflowRunId: string;
44
44
  parentMessageId: string;
45
45
  currentInstructionIndex: number;
@@ -57,6 +57,7 @@ export declare const workflowRunSchema: z.ZodObject<{
57
57
  defaultAssistantId: string;
58
58
  workflowRunId: string;
59
59
  parentMessageId: string;
60
+ createdAt?: Date | undefined;
60
61
  workflowId?: string | undefined;
61
62
  instructions?: {
62
63
  markdown?: string | undefined;
@@ -64,7 +65,6 @@ export declare const workflowRunSchema: z.ZodObject<{
64
65
  directCallToolId?: string | undefined;
65
66
  subWorkflowId?: string | undefined;
66
67
  }[] | undefined;
67
- createdAt?: Date | undefined;
68
68
  scheduleDT?: Date | undefined;
69
69
  currentInstructionIndex?: number | undefined;
70
70
  instructionResults?: any[] | undefined;
@@ -1,7 +1,9 @@
1
1
  import type { DataContext } from "../context/data-context";
2
- export declare function Workflows(dataContext?: DataContext): import("./orm").Table<{
2
+ export declare function Workflows(dataContext?: DataContext): import("..").Table<{
3
3
  name: string;
4
4
  description: string;
5
+ createdAt: Date;
6
+ updatedAt: Date;
5
7
  workflowId: string;
6
8
  defaultAssistantId: string;
7
9
  instructions: {
@@ -11,7 +13,5 @@ export declare function Workflows(dataContext?: DataContext): import("./orm").Ta
11
13
  subWorkflowId?: string | undefined;
12
14
  }[];
13
15
  createdBy: string;
14
- createdAt: Date;
15
- updatedAt: Date;
16
16
  packageId?: string | undefined;
17
17
  }>;
@@ -35,7 +35,9 @@ export interface IBinaryPeer {
35
35
  */
36
36
  getBufferedAmount?(): number;
37
37
  }
38
+ /** Backwards-compatible name for a WebRTC binary peer. */
38
39
  export type IWebRTCPeer = IBinaryPeer;
40
+ /** Options for wrapping a binary transport in a verified Peers connection. */
39
41
  export interface WrapBinaryPeerOptions {
40
42
  /** Protocol identifier used for server address (e.g., 'wrtc' or 'ws') */
41
43
  protocol: "wrtc" | "ws";
@@ -324,9 +324,19 @@ function createBinaryPeerSocket(connectionId, peer, protocol = "binary") {
324
324
  return;
325
325
  }
326
326
  if (message.type === "call") {
327
- const handler = handlers[message.eventName];
327
+ const eventName = message.eventName;
328
+ const handler = eventName ? handlers[eventName] : undefined;
328
329
  if (!handler) {
329
- console.warn(`No handler for event: ${message.eventName}`);
330
+ const error = eventName
331
+ ? `No handler registered for event: ${eventName}`
332
+ : "RPC call did not include an event name";
333
+ console.warn(error);
334
+ const responseMessage = {
335
+ type: "callback",
336
+ callbackId: message.callbackId,
337
+ error,
338
+ };
339
+ sendRPC(encodeMessage(responseMessage));
330
340
  return;
331
341
  }
332
342
  try {
@@ -117,6 +117,29 @@ describe("binary-peer-connection-v2", () => {
117
117
  iPeer.destroy();
118
118
  rPeer.destroy();
119
119
  });
120
+ it("should return an error when the remote event has no handler", async () => {
121
+ const { iPeer, rPeer } = await getMockPeerPair();
122
+ const socketA = (0, binary_peer_connection_v2_1.createBinaryPeerSocket)("a", iPeer, "ws");
123
+ (0, binary_peer_connection_v2_1.createBinaryPeerSocket)("b", rPeer, "ws");
124
+ const warning = jest.spyOn(console, "warn").mockImplementation(() => { });
125
+ try {
126
+ const response = await new Promise((resolve) => {
127
+ socketA.emit("missing-event", {}, (error, result) => {
128
+ resolve({ error, result });
129
+ });
130
+ });
131
+ expect(response).toEqual({
132
+ error: "No handler registered for event: missing-event",
133
+ result: undefined,
134
+ });
135
+ expect(warning).toHaveBeenCalledWith("No handler registered for event: missing-event");
136
+ }
137
+ finally {
138
+ warning.mockRestore();
139
+ iPeer.destroy();
140
+ rPeer.destroy();
141
+ }
142
+ });
120
143
  it("should handle Uint8Array args without txEncode", async () => {
121
144
  const { iPeer, rPeer } = await getMockPeerPair();
122
145
  const socketA = (0, binary_peer_connection_v2_1.createBinaryPeerSocket)("a", iPeer, "ws");
@@ -1,3 +1,9 @@
1
1
  import { type IDeviceInfo } from "../data";
2
2
  import { TrustLevel } from "./socket.type";
3
+ /**
4
+ * Build the connection-handshake trust evaluator for a local user identity.
5
+ *
6
+ * Known user keys are authoritative even for a newly observed device: a claimed identity
7
+ * whose signing or box key differs from the stored user record is rejected as untrusted.
8
+ */
3
9
  export declare function getTrustLevelFn(me: Pick<IDeviceInfo, "userId" | "publicKey" | "publicBoxKey">, serverUrl?: string): (deviceInfo: IDeviceInfo, _registerNew?: boolean) => Promise<TrustLevel>;