@peers-app/peers-sdk 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/context/data-context.d.ts +31 -0
- package/dist/context/data-context.js +56 -0
- package/dist/context/index.d.ts +3 -0
- package/dist/context/index.js +19 -0
- package/dist/context/user-context-singleton.d.ts +11 -0
- package/dist/context/user-context-singleton.js +121 -0
- package/dist/context/user-context.d.ts +55 -0
- package/dist/context/user-context.js +205 -0
- package/dist/data/assistants.d.ts +68 -0
- package/dist/data/assistants.js +64 -0
- package/dist/data/change-tracking.d.ts +219 -0
- package/dist/data/change-tracking.js +119 -0
- package/dist/data/channels.d.ts +29 -0
- package/dist/data/channels.js +25 -0
- package/dist/data/data-locks.d.ts +37 -0
- package/dist/data/data-locks.js +180 -0
- package/dist/data/data-locks.test.d.ts +1 -0
- package/dist/data/data-locks.test.js +456 -0
- package/dist/data/device-sync-info.d.ts +19 -0
- package/dist/data/device-sync-info.js +24 -0
- package/dist/data/devices.d.ts +51 -0
- package/dist/data/devices.js +36 -0
- package/dist/data/embeddings.d.ts +47 -0
- package/dist/data/embeddings.js +36 -0
- package/dist/data/files/file-read-stream.d.ts +27 -0
- package/dist/data/files/file-read-stream.js +195 -0
- package/dist/data/files/file-write-stream.d.ts +20 -0
- package/dist/data/files/file-write-stream.js +113 -0
- package/dist/data/files/file.types.d.ts +47 -0
- package/dist/data/files/file.types.js +55 -0
- package/dist/data/files/files.d.ts +28 -0
- package/dist/data/files/files.js +127 -0
- package/dist/data/files/files.test.d.ts +1 -0
- package/dist/data/files/files.test.js +728 -0
- package/dist/data/files/index.d.ts +4 -0
- package/dist/data/files/index.js +23 -0
- package/dist/data/group-member-roles.d.ts +9 -0
- package/dist/data/group-member-roles.js +25 -0
- package/dist/data/group-members.d.ts +39 -0
- package/dist/data/group-members.js +68 -0
- package/dist/data/group-members.test.d.ts +1 -0
- package/dist/data/group-members.test.js +287 -0
- package/dist/data/group-permissions.d.ts +8 -0
- package/dist/data/group-permissions.js +73 -0
- package/dist/data/group-share.d.ts +50 -0
- package/dist/data/group-share.js +196 -0
- package/dist/data/groups.d.ts +50 -0
- package/dist/data/groups.js +73 -0
- package/dist/data/groups.test.d.ts +1 -0
- package/dist/data/groups.test.js +153 -0
- package/dist/data/index.d.ts +31 -0
- package/dist/data/index.js +47 -0
- package/dist/data/knowledge/knowledge-frames.d.ts +34 -0
- package/dist/data/knowledge/knowledge-frames.js +34 -0
- package/dist/data/knowledge/knowledge-links.d.ts +30 -0
- package/dist/data/knowledge/knowledge-links.js +25 -0
- package/dist/data/knowledge/knowledge-values.d.ts +35 -0
- package/dist/data/knowledge/knowledge-values.js +35 -0
- package/dist/data/knowledge/peer-types.d.ts +112 -0
- package/dist/data/knowledge/peer-types.js +27 -0
- package/dist/data/knowledge/predicates.d.ts +34 -0
- package/dist/data/knowledge/predicates.js +27 -0
- package/dist/data/messages.d.ts +57 -0
- package/dist/data/messages.js +97 -0
- package/dist/data/orm/client-proxy.data-source.d.ts +27 -0
- package/dist/data/orm/client-proxy.data-source.js +65 -0
- package/dist/data/orm/cursor.d.ts +25 -0
- package/dist/data/orm/cursor.js +47 -0
- package/dist/data/orm/cursor.test.d.ts +1 -0
- package/dist/data/orm/cursor.test.js +315 -0
- package/dist/data/orm/data-query.d.ts +96 -0
- package/dist/data/orm/data-query.js +208 -0
- package/dist/data/orm/data-query.mongo.d.ts +17 -0
- package/dist/data/orm/data-query.mongo.js +267 -0
- package/dist/data/orm/data-query.mongo.test.d.ts +1 -0
- package/dist/data/orm/data-query.mongo.test.js +398 -0
- package/dist/data/orm/data-query.sqlite.d.ts +14 -0
- package/dist/data/orm/data-query.sqlite.js +297 -0
- package/dist/data/orm/data-query.sqlite.test.d.ts +1 -0
- package/dist/data/orm/data-query.sqlite.test.js +377 -0
- package/dist/data/orm/data-query.test.d.ts +1 -0
- package/dist/data/orm/data-query.test.js +553 -0
- package/dist/data/orm/decorators.d.ts +6 -0
- package/dist/data/orm/decorators.js +21 -0
- package/dist/data/orm/dependency-injection.test.d.ts +1 -0
- package/dist/data/orm/dependency-injection.test.js +171 -0
- package/dist/data/orm/doc.d.ts +26 -0
- package/dist/data/orm/doc.js +124 -0
- package/dist/data/orm/event-registry.d.ts +24 -0
- package/dist/data/orm/event-registry.js +40 -0
- package/dist/data/orm/event-registry.test.d.ts +1 -0
- package/dist/data/orm/event-registry.test.js +44 -0
- package/dist/data/orm/factory.d.ts +8 -0
- package/dist/data/orm/factory.js +147 -0
- package/dist/data/orm/index.d.ts +16 -0
- package/dist/data/orm/index.js +32 -0
- package/dist/data/orm/multi-cursors.d.ts +11 -0
- package/dist/data/orm/multi-cursors.js +146 -0
- package/dist/data/orm/multi-cursors.test.d.ts +1 -0
- package/dist/data/orm/multi-cursors.test.js +455 -0
- package/dist/data/orm/sql-db.d.ts +6 -0
- package/dist/data/orm/sql-db.js +2 -0
- package/dist/data/orm/sql.data-source.d.ts +38 -0
- package/dist/data/orm/sql.data-source.js +379 -0
- package/dist/data/orm/sql.data-source.test.d.ts +1 -0
- package/dist/data/orm/sql.data-source.test.js +406 -0
- package/dist/data/orm/subscribable.data-source.d.ts +25 -0
- package/dist/data/orm/subscribable.data-source.js +72 -0
- package/dist/data/orm/table-container-events.test.d.ts +1 -0
- package/dist/data/orm/table-container-events.test.js +93 -0
- package/dist/data/orm/table-container.d.ts +39 -0
- package/dist/data/orm/table-container.js +96 -0
- package/dist/data/orm/table-definitions.system.d.ts +9 -0
- package/dist/data/orm/table-definitions.system.js +29 -0
- package/dist/data/orm/table-definitions.type.d.ts +19 -0
- package/dist/data/orm/table-definitions.type.js +2 -0
- package/dist/data/orm/table-dependencies.d.ts +32 -0
- package/dist/data/orm/table-dependencies.js +2 -0
- package/dist/data/orm/table.d.ts +42 -0
- package/dist/data/orm/table.event-source.test.d.ts +1 -0
- package/dist/data/orm/table.event-source.test.js +341 -0
- package/dist/data/orm/table.js +244 -0
- package/dist/data/orm/types.d.ts +20 -0
- package/dist/data/orm/types.js +115 -0
- package/dist/data/orm/types.test.d.ts +1 -0
- package/dist/data/orm/types.test.js +71 -0
- package/dist/data/package-permissions.d.ts +7 -0
- package/dist/data/package-permissions.js +18 -0
- package/dist/data/packages.d.ts +92 -0
- package/dist/data/packages.js +90 -0
- package/dist/data/peer-events/peer-event-handlers.d.ts +21 -0
- package/dist/data/peer-events/peer-event-handlers.js +28 -0
- package/dist/data/peer-events/peer-event-types.d.ts +119 -0
- package/dist/data/peer-events/peer-event-types.js +29 -0
- package/dist/data/peer-events/peer-events.d.ts +41 -0
- package/dist/data/peer-events/peer-events.js +102 -0
- package/dist/data/persistent-vars.d.ts +87 -0
- package/dist/data/persistent-vars.js +230 -0
- package/dist/data/tool-tests.d.ts +37 -0
- package/dist/data/tool-tests.js +27 -0
- package/dist/data/tools.d.ts +358 -0
- package/dist/data/tools.js +48 -0
- package/dist/data/user-permissions.d.ts +15 -0
- package/dist/data/user-permissions.js +39 -0
- package/dist/data/user-permissions.test.d.ts +1 -0
- package/dist/data/user-permissions.test.js +252 -0
- package/dist/data/users.d.ts +38 -0
- package/dist/data/users.js +73 -0
- package/dist/data/workflow-logs.d.ts +106 -0
- package/dist/data/workflow-logs.js +67 -0
- package/dist/data/workflow-runs.d.ts +103 -0
- package/dist/data/workflow-runs.js +313 -0
- package/dist/data/workflows.d.ts +16 -0
- package/dist/data/workflows.js +21 -0
- package/dist/device/connection.d.ts +41 -0
- package/dist/device/connection.js +249 -0
- package/dist/device/connection.test.d.ts +1 -0
- package/dist/device/connection.test.js +292 -0
- package/dist/device/device-election.d.ts +36 -0
- package/dist/device/device-election.js +137 -0
- package/dist/device/device.d.ts +22 -0
- package/dist/device/device.js +110 -0
- package/dist/device/device.test.d.ts +1 -0
- package/dist/device/device.test.js +203 -0
- package/dist/device/get-trust-level.d.ts +3 -0
- package/dist/device/get-trust-level.js +87 -0
- package/dist/device/socket.type.d.ts +20 -0
- package/dist/device/socket.type.js +15 -0
- package/dist/device/streamed-socket.d.ts +27 -0
- package/dist/device/streamed-socket.js +154 -0
- package/dist/device/streamed-socket.test.d.ts +1 -0
- package/dist/device/streamed-socket.test.js +44 -0
- package/dist/events.d.ts +35 -0
- package/dist/events.js +128 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +50 -0
- package/dist/keys.d.ts +51 -0
- package/dist/keys.js +234 -0
- package/dist/keys.test.d.ts +1 -0
- package/dist/keys.test.js +215 -0
- package/dist/mentions.d.ts +9 -0
- package/dist/mentions.js +46 -0
- package/dist/observable.d.ts +19 -0
- package/dist/observable.js +112 -0
- package/dist/observable.test.d.ts +1 -0
- package/dist/observable.test.js +183 -0
- package/dist/package-loader/get-require.d.ts +10 -0
- package/dist/package-loader/get-require.js +31 -0
- package/dist/package-loader/index.d.ts +1 -0
- package/dist/package-loader/index.js +17 -0
- package/dist/package-loader/package-loader.d.ts +16 -0
- package/dist/package-loader/package-loader.js +102 -0
- package/dist/peers-ui/peers-ui.d.ts +15 -0
- package/dist/peers-ui/peers-ui.js +23 -0
- package/dist/peers-ui/peers-ui.types.d.ts +35 -0
- package/dist/peers-ui/peers-ui.types.js +3 -0
- package/dist/rpc-types.d.ts +45 -0
- package/dist/rpc-types.js +47 -0
- package/dist/serial-json.d.ts +5 -0
- package/dist/serial-json.js +186 -0
- package/dist/serial-json.test.d.ts +1 -0
- package/dist/serial-json.test.js +86 -0
- package/dist/system-ids.d.ts +6 -0
- package/dist/system-ids.js +10 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/tools-factory.d.ts +5 -0
- package/dist/tools/tools-factory.js +34 -0
- package/dist/types/app-nav.d.ts +18 -0
- package/dist/types/app-nav.js +10 -0
- package/dist/types/assistant-runner-args.d.ts +9 -0
- package/dist/types/assistant-runner-args.js +2 -0
- package/dist/types/field-type.d.ts +37 -0
- package/dist/types/field-type.js +26 -0
- package/dist/types/peer-device.d.ts +40 -0
- package/dist/types/peer-device.js +14 -0
- package/dist/types/peers-package.d.ts +23 -0
- package/dist/types/peers-package.js +2 -0
- package/dist/types/workflow-logger.d.ts +2 -0
- package/dist/types/workflow-logger.js +2 -0
- package/dist/types/workflow-run-context.d.ts +12 -0
- package/dist/types/workflow-run-context.js +2 -0
- package/dist/types/workflow.d.ts +72 -0
- package/dist/types/workflow.js +24 -0
- package/dist/types/zod-types.d.ts +7 -0
- package/dist/types/zod-types.js +12 -0
- package/dist/users.query.d.ts +13 -0
- package/dist/users.query.js +134 -0
- package/dist/utils.d.ts +39 -0
- package/dist/utils.js +240 -0
- package/dist/utils.test.d.ts +1 -0
- package/dist/utils.test.js +140 -0
- package/package.json +50 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
3
|
+
var useValue = arguments.length > 2;
|
|
4
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
5
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
6
|
+
}
|
|
7
|
+
return useValue ? value : void 0;
|
|
8
|
+
};
|
|
9
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
10
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
11
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
12
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
13
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
14
|
+
var _, done = false;
|
|
15
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
16
|
+
var context = {};
|
|
17
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
18
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
19
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
20
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
21
|
+
if (kind === "accessor") {
|
|
22
|
+
if (result === void 0) continue;
|
|
23
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
24
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
25
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
26
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
27
|
+
}
|
|
28
|
+
else if (_ = accept(result)) {
|
|
29
|
+
if (kind === "field") initializers.unshift(_);
|
|
30
|
+
else descriptor[key] = _;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
34
|
+
done = true;
|
|
35
|
+
};
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.workflowRunSchema = void 0;
|
|
38
|
+
exports.WorkflowRuns = WorkflowRuns;
|
|
39
|
+
exports.runWorkflow = runWorkflow;
|
|
40
|
+
const moment = require("moment-timezone");
|
|
41
|
+
const channels_1 = require("./channels");
|
|
42
|
+
const groups_1 = require("./groups");
|
|
43
|
+
const messages_1 = require("./messages");
|
|
44
|
+
const table_1 = require("./orm/table");
|
|
45
|
+
const types_1 = require("./orm/types");
|
|
46
|
+
const users_1 = require("./users");
|
|
47
|
+
const workflow_logs_1 = require("./workflow-logs");
|
|
48
|
+
const workflows_1 = require("./workflows");
|
|
49
|
+
const utils_1 = require("../utils");
|
|
50
|
+
const mentions_1 = require("../mentions");
|
|
51
|
+
const user_context_singleton_1 = require("../context/user-context-singleton");
|
|
52
|
+
const table_definitions_system_1 = require("./orm/table-definitions.system");
|
|
53
|
+
const zod_1 = require("zod");
|
|
54
|
+
const workflow_1 = require("../types/workflow");
|
|
55
|
+
const zod_types_1 = require("../types/zod-types");
|
|
56
|
+
const data_locks_1 = require("./data-locks");
|
|
57
|
+
const assistants_1 = require("./assistants");
|
|
58
|
+
const system_ids_1 = require("../system-ids");
|
|
59
|
+
const orm_1 = require("./orm");
|
|
60
|
+
exports.workflowRunSchema = zod_1.z.object({
|
|
61
|
+
workflowRunId: zod_types_1.zodPeerId,
|
|
62
|
+
workflowId: zod_types_1.zodPeerId.optional().describe('The workflow that is being run. '),
|
|
63
|
+
parentMessageId: zod_types_1.zodPeerId.describe('The message that this workflow will run in the context of'),
|
|
64
|
+
createdAt: zod_1.z.date().default(() => new Date()).describe('The date the workflow run was created'),
|
|
65
|
+
scheduleDT: zod_1.z.date().optional().describe('The date and time that the workflow run is scheduled to run'),
|
|
66
|
+
instructions: workflow_1.workflowInstructionSchema.array().default([]).describe('The remaining instructions that still need to be done. The LLM can use this as a scratch pad, adding and removing instructions as needed.'),
|
|
67
|
+
currentInstructionIndex: zod_1.z.number().default(0).describe('The index of the current instruction that is being run'),
|
|
68
|
+
instructionResults: zod_1.z.any().array().default([]).describe('The results of the instructions that have been run.'),
|
|
69
|
+
inErrorState: zod_1.z.boolean().optional().describe('Whether or not the workflow run is in an error state'),
|
|
70
|
+
startedAt: zod_1.z.date().optional().describe('The date the workflow run first started to be processed'),
|
|
71
|
+
completedAt: zod_1.z.date().optional().describe('The date the workflow run was completed'),
|
|
72
|
+
vars: zod_types_1.zodAnyObject.default(() => ({})).describe(`The current value of the workflow run. This is a scratch pad that the LLM can use to store values that are needed for the workflow run.`),
|
|
73
|
+
parentWorkflowRunId: zod_types_1.zodPeerId.optional().describe('The parent workflow run id if this is a sub workflow run'),
|
|
74
|
+
defaultAssistantId: zod_types_1.zodPeerId.describe('The default assistant to use for this workflow run'),
|
|
75
|
+
});
|
|
76
|
+
const metaData = {
|
|
77
|
+
name: 'WorkflowRuns',
|
|
78
|
+
description: 'workflows instances that have been run manually, from messages, or from events',
|
|
79
|
+
primaryKeyName: 'workflowRunId',
|
|
80
|
+
fields: (0, types_1.schemaToFields)(exports.workflowRunSchema),
|
|
81
|
+
indexes: [
|
|
82
|
+
{ fields: ['workflowId'], },
|
|
83
|
+
{ fields: ['parentMessageId'], },
|
|
84
|
+
{ fields: ['parentWorkflowRunId'], },
|
|
85
|
+
{ fields: ['completedAt'], },
|
|
86
|
+
{ fields: ['inErrorState'], },
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
let WorkflowRunTable = (() => {
|
|
90
|
+
let _classSuper = table_1.Table;
|
|
91
|
+
let _instanceExtraInitializers = [];
|
|
92
|
+
let _haltRun_decorators;
|
|
93
|
+
return class WorkflowRunTable extends _classSuper {
|
|
94
|
+
static {
|
|
95
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
96
|
+
_haltRun_decorators = [(0, orm_1.ProxyClientCalls)()];
|
|
97
|
+
__esDecorate(this, null, _haltRun_decorators, { kind: "method", name: "haltRun", static: false, private: false, access: { has: obj => "haltRun" in obj, get: obj => obj.haltRun }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
98
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
99
|
+
}
|
|
100
|
+
/** @deprecated Direct calls to save forbidden; use insert or saveWithLock */
|
|
101
|
+
save(..._args) {
|
|
102
|
+
throw new Error('Direct inserts forbidden; use insert() or saveWithLock()');
|
|
103
|
+
}
|
|
104
|
+
/** @deprecated Direct calls to update forbidden; use saveWithLock() */
|
|
105
|
+
update(..._args) {
|
|
106
|
+
throw new Error('Direct updates forbidden; use saveWithLock()');
|
|
107
|
+
}
|
|
108
|
+
async saveWithLock(workflowRun, lock) {
|
|
109
|
+
if (!workflowRun.workflowRunId) {
|
|
110
|
+
workflowRun.workflowRunId = (0, utils_1.newid)();
|
|
111
|
+
return super.insert(workflowRun);
|
|
112
|
+
}
|
|
113
|
+
let lockedForThisSave = false;
|
|
114
|
+
if (!lock) {
|
|
115
|
+
lock = await (0, data_locks_1.DataLocks)().acquireLock(workflowRun.workflowRunId);
|
|
116
|
+
lockedForThisSave = true;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
const currentLock = await (0, data_locks_1.DataLocks)().getCurrentLock(workflowRun.workflowRunId);
|
|
120
|
+
if (currentLock?.dataLockId !== lock.dataLockId) {
|
|
121
|
+
throw new Error(`Provided lock is not the current lock for workflowRunId ${workflowRun.workflowRunId} - aborting save`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (!lock) {
|
|
125
|
+
throw new Error(`Could not acquire lock for workflow run ${workflowRun.workflowRunId}`);
|
|
126
|
+
}
|
|
127
|
+
if (lock.recordId !== workflowRun.workflowRunId) {
|
|
128
|
+
throw new Error(`Provided lock recordId ${lock?.recordId} does not match workflowRunId ${workflowRun.workflowRunId}`);
|
|
129
|
+
}
|
|
130
|
+
let dbData = await this.get(workflowRun.workflowRunId);
|
|
131
|
+
if (dbData && !lock) {
|
|
132
|
+
const currentLock = await (0, data_locks_1.DataLocks)().getCurrentLock(workflowRun.workflowRunId);
|
|
133
|
+
if (currentLock) {
|
|
134
|
+
throw new Error(`Workflow run ${workflowRun.workflowRunId} is locked by ${currentLock.dataLockId} - the lock will timeout at ${new Date(currentLock.lockedUntil)}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (dbData?.inErrorState) {
|
|
138
|
+
throw new Error(`Workflow run ${workflowRun.workflowRunId} is in an error state - use clearErrorState to continue the run`);
|
|
139
|
+
}
|
|
140
|
+
if (dbData) {
|
|
141
|
+
dbData = await super.update(workflowRun);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
dbData = await super.insert(workflowRun);
|
|
145
|
+
}
|
|
146
|
+
if (lockedForThisSave) {
|
|
147
|
+
await (0, data_locks_1.DataLocks)().releaseLock(lock);
|
|
148
|
+
}
|
|
149
|
+
return dbData;
|
|
150
|
+
}
|
|
151
|
+
async acquireLock(workflowRunId, timeoutMs, lockTimeMs) {
|
|
152
|
+
const workflowDbData = await this.get(workflowRunId);
|
|
153
|
+
if (!workflowDbData)
|
|
154
|
+
return undefined;
|
|
155
|
+
if (workflowDbData.inErrorState) {
|
|
156
|
+
console.warn(`Workflow run ${workflowRunId} is in an error state - not acquiring lock`);
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
return await (0, data_locks_1.DataLocks)().acquireLock(workflowRunId, timeoutMs, lockTimeMs);
|
|
160
|
+
}
|
|
161
|
+
async saveAndRelease(workflowRun, lock) {
|
|
162
|
+
const workflowDbData = await this.get(workflowRun.workflowRunId);
|
|
163
|
+
if (!workflowDbData)
|
|
164
|
+
return;
|
|
165
|
+
const currentLock = await (0, data_locks_1.DataLocks)().getCurrentLock(workflowRun.workflowRunId);
|
|
166
|
+
if (!currentLock || currentLock.dataLockId !== lock.dataLockId) {
|
|
167
|
+
console.warn(`Workflow run ${workflowRun.workflowRunId} is not locked by ${lock.dataLockId} - aborting save`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (workflowDbData.inErrorState) {
|
|
171
|
+
console.warn(`Workflow run ${workflowRun.workflowRunId} is in an error state - aborting save`);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
await super.update(workflowRun);
|
|
175
|
+
await (0, data_locks_1.DataLocks)().releaseLock(lock);
|
|
176
|
+
}
|
|
177
|
+
async haltRun(workflowRunId) {
|
|
178
|
+
const run = await super.get(workflowRunId);
|
|
179
|
+
if (!run) {
|
|
180
|
+
throw new Error(`Workflow run ${workflowRunId} not found`);
|
|
181
|
+
}
|
|
182
|
+
if (run.inErrorState) {
|
|
183
|
+
console.warn(`Workflow run ${workflowRunId} is already in an error state - not halting`);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!run.completedAt) {
|
|
187
|
+
run.inErrorState = true;
|
|
188
|
+
await super.update(run);
|
|
189
|
+
// Release any existing lock
|
|
190
|
+
while (true) {
|
|
191
|
+
const currentLock = await (0, data_locks_1.DataLocks)().getCurrentLock(workflowRunId);
|
|
192
|
+
if (currentLock) {
|
|
193
|
+
await (0, data_locks_1.DataLocks)().releaseLock(currentLock);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
break; // No lock to release
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// also halt any child runs
|
|
200
|
+
this.list({ parentWorkflowRunId: workflowRunId }).then(async (childRuns) => {
|
|
201
|
+
childRuns.forEach(async (child) => {
|
|
202
|
+
this.haltRun(child.workflowRunId).catch((err) => console.error(`Error halting child run ${child.workflowRunId}`, err));
|
|
203
|
+
});
|
|
204
|
+
}).catch((err) => console.error(`Error halting child runs for ${workflowRunId}`, err));
|
|
205
|
+
// send message and log
|
|
206
|
+
const runHaltMessage = `Workflow run canceled at ${new Date().toISOString()}`;
|
|
207
|
+
await (0, messages_1.sendMessage)({
|
|
208
|
+
channelOrThreadIdOrWorkflowRunId: run.parentMessageId,
|
|
209
|
+
assistantId: run.defaultAssistantId,
|
|
210
|
+
messageContent: runHaltMessage,
|
|
211
|
+
});
|
|
212
|
+
const logger = (0, workflow_logs_1.getLogger)(run.workflowRunId, (0, utils_1.newid)());
|
|
213
|
+
logger(runHaltMessage);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Removes the error state from a workflow run and locks it so
|
|
218
|
+
* additional editing can be done before it is re-run.
|
|
219
|
+
*/
|
|
220
|
+
async clearErrorState(workflowRunId) {
|
|
221
|
+
const run = await super.get(workflowRunId);
|
|
222
|
+
if (!run) {
|
|
223
|
+
throw new Error(`Workflow run ${workflowRunId} not found`);
|
|
224
|
+
}
|
|
225
|
+
if (!run.inErrorState) {
|
|
226
|
+
console.warn(`Workflow run ${workflowRunId} is not in an error state - not clearing`);
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
const lock = await (0, data_locks_1.DataLocks)().acquireLock(workflowRunId);
|
|
230
|
+
if (!lock) {
|
|
231
|
+
console.warn(`Could not acquire lock for workflow run ${workflowRunId}`);
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
run.inErrorState = false;
|
|
235
|
+
await super.update(run);
|
|
236
|
+
return lock;
|
|
237
|
+
}
|
|
238
|
+
constructor() {
|
|
239
|
+
super(...arguments);
|
|
240
|
+
__runInitializers(this, _instanceExtraInitializers);
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
})();
|
|
244
|
+
(0, table_definitions_system_1.registerSystemTableDefinition)(metaData, exports.workflowRunSchema, WorkflowRunTable);
|
|
245
|
+
function WorkflowRuns(dataContext) {
|
|
246
|
+
return (0, user_context_singleton_1.getTableContainer)(dataContext).getTable(metaData, exports.workflowRunSchema);
|
|
247
|
+
}
|
|
248
|
+
async function runWorkflow(args) {
|
|
249
|
+
const { workflowId, parentWorkflowRunId, vars } = args;
|
|
250
|
+
// TODO determine what dataContext this is for
|
|
251
|
+
const workflow = await (0, workflows_1.Workflows)().get(workflowId);
|
|
252
|
+
if (!workflow) {
|
|
253
|
+
throw new Error(`Workflow ${workflowId} not found`);
|
|
254
|
+
}
|
|
255
|
+
const me = await (0, users_1.getMe)();
|
|
256
|
+
const assistantId = workflow.defaultAssistantId
|
|
257
|
+
|| (await (0, assistants_1.getPrimaryAssistant)()).assistantId
|
|
258
|
+
|| system_ids_1.defaultAssistantId;
|
|
259
|
+
let parentMessageId = '';
|
|
260
|
+
let channelId = '';
|
|
261
|
+
if (args.parentMessageIdOrChannelIdOrGroupId) {
|
|
262
|
+
let message = await (0, messages_1.Messages)().get(args.parentMessageIdOrChannelIdOrGroupId);
|
|
263
|
+
if (message) {
|
|
264
|
+
parentMessageId = message.messageId;
|
|
265
|
+
channelId = message.channelId;
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
channelId = args.parentMessageIdOrChannelIdOrGroupId;
|
|
269
|
+
const channel = await (0, channels_1.Channels)().get(args.parentMessageIdOrChannelIdOrGroupId);
|
|
270
|
+
if (!channel) {
|
|
271
|
+
const group = await (0, groups_1.Groups)().get(args.parentMessageIdOrChannelIdOrGroupId);
|
|
272
|
+
if (!group) {
|
|
273
|
+
throw new Error(`Message, channel, or group ${args.parentMessageIdOrChannelIdOrGroupId} not found`);
|
|
274
|
+
}
|
|
275
|
+
channelId = group.groupId;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const workflowRunId = (0, utils_1.newid)();
|
|
280
|
+
const workflowMention = (0, mentions_1.formatMention)({ kind: 'workflow', id: workflowId, name: workflow.name });
|
|
281
|
+
let messageContent = `Running workflow ${workflowMention}`;
|
|
282
|
+
if (!parentMessageId) {
|
|
283
|
+
if (!channelId) {
|
|
284
|
+
channelId = me.userId;
|
|
285
|
+
}
|
|
286
|
+
if (args.scheduleDT) {
|
|
287
|
+
messageContent = `Scheduled workflow ${workflowMention} for ${moment(args.scheduleDT).calendar()} (\`${args.scheduleDT.toISOString()}\`)`;
|
|
288
|
+
}
|
|
289
|
+
const message = await (0, messages_1.sendMessage)({
|
|
290
|
+
channelOrThreadIdOrWorkflowRunId: channelId,
|
|
291
|
+
assistantId,
|
|
292
|
+
messageContent,
|
|
293
|
+
});
|
|
294
|
+
parentMessageId = message.messageId;
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
(0, workflow_logs_1.getLogger)(workflowRunId, (0, utils_1.newid)())(messageContent);
|
|
298
|
+
}
|
|
299
|
+
const run = await WorkflowRuns().insert({
|
|
300
|
+
workflowRunId,
|
|
301
|
+
createdAt: new Date(),
|
|
302
|
+
scheduleDT: args.scheduleDT,
|
|
303
|
+
workflowId,
|
|
304
|
+
parentMessageId,
|
|
305
|
+
instructions: workflow.instructions,
|
|
306
|
+
currentInstructionIndex: 0,
|
|
307
|
+
instructionResults: [],
|
|
308
|
+
defaultAssistantId: assistantId,
|
|
309
|
+
parentWorkflowRunId,
|
|
310
|
+
vars,
|
|
311
|
+
});
|
|
312
|
+
return run;
|
|
313
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DataContext } from "../context/data-context";
|
|
2
|
+
export declare function Workflows(dataContext?: DataContext): import("./orm").Table<{
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
createdAt: Date;
|
|
6
|
+
workflowId: string;
|
|
7
|
+
defaultAssistantId: string;
|
|
8
|
+
instructions: {
|
|
9
|
+
markdown?: string | undefined;
|
|
10
|
+
onError?: string | undefined;
|
|
11
|
+
directCallToolId?: string | undefined;
|
|
12
|
+
subWorkflowId?: string | undefined;
|
|
13
|
+
}[];
|
|
14
|
+
createdBy: string;
|
|
15
|
+
updatedAt: Date;
|
|
16
|
+
}>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Workflows = Workflows;
|
|
4
|
+
const workflow_1 = require("../types/workflow");
|
|
5
|
+
const types_1 = require("./orm/types");
|
|
6
|
+
const user_context_singleton_1 = require("../context/user-context-singleton");
|
|
7
|
+
const table_definitions_system_1 = require("./orm/table-definitions.system");
|
|
8
|
+
const metaData = {
|
|
9
|
+
name: 'Workflows',
|
|
10
|
+
description: 'workflows',
|
|
11
|
+
primaryKeyName: 'workflowId',
|
|
12
|
+
fields: (0, types_1.schemaToFields)(workflow_1.workflowSchema),
|
|
13
|
+
iconClassName: 'bi bi-database-fill-gear',
|
|
14
|
+
indexes: [
|
|
15
|
+
{ fields: ['name'], },
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
(0, table_definitions_system_1.registerSystemTableDefinition)(metaData, workflow_1.workflowSchema);
|
|
19
|
+
function Workflows(dataContext) {
|
|
20
|
+
return (0, user_context_singleton_1.getTableContainer)(dataContext).getTable(metaData, workflow_1.workflowSchema);
|
|
21
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { IDataBox } from "../keys";
|
|
2
|
+
import { Device } from "./device";
|
|
3
|
+
import { IDeviceHandshake, IDeviceInfo } from "../data";
|
|
4
|
+
import { ISocket, TrustLevel } from "./socket.type";
|
|
5
|
+
export type GetTrustLevel = (deviceInfo: IDeviceInfo, registerNew?: boolean) => Promise<TrustLevel>;
|
|
6
|
+
export declare class Connection {
|
|
7
|
+
readonly localDevice: Device;
|
|
8
|
+
readonly localDeviceServerAddresses?: string[] | undefined;
|
|
9
|
+
protected readonly getTrustLevel: GetTrustLevel;
|
|
10
|
+
private _verified;
|
|
11
|
+
private _remoteDeviceInfo;
|
|
12
|
+
secureLocal: boolean;
|
|
13
|
+
secureRemote: boolean;
|
|
14
|
+
forceInsecure: boolean;
|
|
15
|
+
trustLevel: TrustLevel;
|
|
16
|
+
onHandshakeComplete: ((deviceInfo: IDeviceInfo) => void) | undefined;
|
|
17
|
+
timeoutMs: number;
|
|
18
|
+
maxChunkSize: number;
|
|
19
|
+
handshakeTimestampToleranceMs: number;
|
|
20
|
+
readonly socket: ISocket;
|
|
21
|
+
constructor(socket: ISocket, localDevice: Device, localDeviceServerAddresses?: string[] | undefined, getTrustLevel?: GetTrustLevel);
|
|
22
|
+
get verified(): boolean;
|
|
23
|
+
get secure(): boolean;
|
|
24
|
+
get remoteDeviceInfo(): {
|
|
25
|
+
userId: string;
|
|
26
|
+
deviceId: string;
|
|
27
|
+
publicKey: string;
|
|
28
|
+
publicBoxKey: string;
|
|
29
|
+
};
|
|
30
|
+
get connectionId(): string;
|
|
31
|
+
exposeRPC<T extends Function>(name: string, fn: T): void;
|
|
32
|
+
exposeRPC<T extends Function>(fn: T): void;
|
|
33
|
+
emit<T = any>(eventName: string, ...args: any): Promise<T>;
|
|
34
|
+
on(eventName: string, handler: Function): void;
|
|
35
|
+
removeAllListeners(eventName: string): void;
|
|
36
|
+
reset(): void;
|
|
37
|
+
initiateHandshake(serverAddress: string, remoteDeviceInfo?: IDeviceInfo): IDataBox;
|
|
38
|
+
completeHandshake(boxedHandshake: IDataBox): Promise<IDeviceHandshake>;
|
|
39
|
+
doHandshake(remoteAddress: string): Promise<IDeviceHandshake>;
|
|
40
|
+
}
|
|
41
|
+
export declare function normalizeAddress(address: string): string;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Connection = void 0;
|
|
4
|
+
exports.normalizeAddress = normalizeAddress;
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const keys_1 = require("../keys");
|
|
7
|
+
const socket_type_1 = require("./socket.type");
|
|
8
|
+
const streamed_socket_1 = require("./streamed-socket");
|
|
9
|
+
const HANDSHAKE_TIMESTAMP_TOLERANCE_MS = 300_000; // 5 minutes
|
|
10
|
+
class Connection {
|
|
11
|
+
localDevice;
|
|
12
|
+
localDeviceServerAddresses;
|
|
13
|
+
getTrustLevel;
|
|
14
|
+
_verified = false;
|
|
15
|
+
_remoteDeviceInfo = {
|
|
16
|
+
deviceId: '',
|
|
17
|
+
userId: '',
|
|
18
|
+
publicKey: '',
|
|
19
|
+
publicBoxKey: '',
|
|
20
|
+
};
|
|
21
|
+
secureLocal = false;
|
|
22
|
+
secureRemote = false;
|
|
23
|
+
// TODO this concept of insecure needs to be adjusted
|
|
24
|
+
// what it actually means is that the underlying connection _is_ secure
|
|
25
|
+
// OR that both the client and server want to skip encryption (which we maybe shouldn't allow)
|
|
26
|
+
// webRTC connections _are_ secure so we'll be setting `forceInsecure` to true (which is a misnomer)
|
|
27
|
+
forceInsecure = false;
|
|
28
|
+
trustLevel = socket_type_1.TrustLevel.Unknown;
|
|
29
|
+
onHandshakeComplete;
|
|
30
|
+
timeoutMs = 60_000; // 60 seconds
|
|
31
|
+
maxChunkSize = socket_type_1.DEFAULT_MAX_CHUNK_SIZE;
|
|
32
|
+
handshakeTimestampToleranceMs = HANDSHAKE_TIMESTAMP_TOLERANCE_MS;
|
|
33
|
+
socket;
|
|
34
|
+
constructor(socket, localDevice, localDeviceServerAddresses, getTrustLevel = () => Promise.resolve(socket_type_1.TrustLevel.Unknown)) {
|
|
35
|
+
this.localDevice = localDevice;
|
|
36
|
+
this.localDeviceServerAddresses = localDeviceServerAddresses;
|
|
37
|
+
this.getTrustLevel = getTrustLevel;
|
|
38
|
+
this.localDeviceServerAddresses = localDeviceServerAddresses?.map(normalizeAddress);
|
|
39
|
+
// this.socket = socket;
|
|
40
|
+
this.socket = new streamed_socket_1.StreamedSocket(socket, this.maxChunkSize);
|
|
41
|
+
if (!socket.id) {
|
|
42
|
+
socket.id = (0, utils_1.newid)();
|
|
43
|
+
}
|
|
44
|
+
// Only the server side of a connection should expose these methods
|
|
45
|
+
if (localDeviceServerAddresses) {
|
|
46
|
+
this.exposeRPC('reset', this.reset.bind(this));
|
|
47
|
+
this.exposeRPC('getTrustLevel', async (deviceInfo) => {
|
|
48
|
+
const trustLevel = await this.getTrustLevel(deviceInfo, false);
|
|
49
|
+
console.log(`Sending client trust level ${trustLevel}`);
|
|
50
|
+
return trustLevel;
|
|
51
|
+
});
|
|
52
|
+
this.exposeRPC('requestDeviceInfo', this.localDevice.getDeviceInfo.bind(this.localDevice));
|
|
53
|
+
this.exposeRPC('completeHandshake', async (handshakeBox) => {
|
|
54
|
+
const handshakeResponse = await this.completeHandshake(handshakeBox);
|
|
55
|
+
return handshakeResponse;
|
|
56
|
+
});
|
|
57
|
+
this.exposeRPC('requestSecure', () => {
|
|
58
|
+
this.secureRemote = true;
|
|
59
|
+
return this.secure;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
get verified() {
|
|
64
|
+
return this._verified;
|
|
65
|
+
}
|
|
66
|
+
get secure() {
|
|
67
|
+
if (this.forceInsecure) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return this.secureLocal && this.secureRemote;
|
|
71
|
+
}
|
|
72
|
+
get remoteDeviceInfo() {
|
|
73
|
+
return { ...this._remoteDeviceInfo };
|
|
74
|
+
}
|
|
75
|
+
get connectionId() {
|
|
76
|
+
return this.socket.id || '';
|
|
77
|
+
}
|
|
78
|
+
exposeRPC(fn, name) {
|
|
79
|
+
if (typeof name === 'function') {
|
|
80
|
+
const _fn = name;
|
|
81
|
+
// @ts-ignore
|
|
82
|
+
name = fn;
|
|
83
|
+
fn = _fn;
|
|
84
|
+
}
|
|
85
|
+
name = name || fn.name;
|
|
86
|
+
this.on(name, async (...args) => {
|
|
87
|
+
return fn(...args);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
emit(eventName, ...args) {
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
try {
|
|
93
|
+
if (this._verified && !this.secure) {
|
|
94
|
+
args = this.localDevice.signAndBoxDataForDevice(args, this._remoteDeviceInfo);
|
|
95
|
+
}
|
|
96
|
+
const timeoutMs = this.timeoutMs;
|
|
97
|
+
const timeoutPid = setTimeout(() => {
|
|
98
|
+
reject(`${eventName} timed out after ${timeoutMs}ms`);
|
|
99
|
+
}, timeoutMs);
|
|
100
|
+
this.socket.emit(eventName, args, (err, result) => {
|
|
101
|
+
try {
|
|
102
|
+
clearTimeout(timeoutPid);
|
|
103
|
+
if (err) {
|
|
104
|
+
err = this.localDevice.unwrapResponse(err);
|
|
105
|
+
return reject(err);
|
|
106
|
+
}
|
|
107
|
+
if (eventName === 'requestSecure') {
|
|
108
|
+
this.secureRemote = this.localDevice.unwrapResponse(result);
|
|
109
|
+
result = this.secureRemote;
|
|
110
|
+
}
|
|
111
|
+
else if (this._verified && !this.secure) {
|
|
112
|
+
// this purposely results in an error if the client is not securing the data when it should be
|
|
113
|
+
result = this.localDevice.openBoxedAndSignedData(result);
|
|
114
|
+
}
|
|
115
|
+
resolve(result);
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
console.error(`Error connection.emit callback for ${eventName}(${JSON.stringify(args)})`, e);
|
|
119
|
+
return reject(e);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
catch (e) {
|
|
124
|
+
console.error(`Error connection.emit for ${eventName}(${JSON.stringify(args)})`, e);
|
|
125
|
+
return reject(e);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
on(eventName, handler) {
|
|
130
|
+
const handshakeEvents = ['requestDeviceInfo', 'completeHandshake', 'reset', 'getTrustLevel'];
|
|
131
|
+
this.socket.on(eventName, async (args, callback) => {
|
|
132
|
+
if (!this.verified && !handshakeEvents.includes(eventName)) {
|
|
133
|
+
console.error(`Ignoring event from unverified connection: ${eventName}`);
|
|
134
|
+
return callback(`Connection not verified. Handshake must be completed successfully before calling ${eventName}`);
|
|
135
|
+
}
|
|
136
|
+
let result;
|
|
137
|
+
try {
|
|
138
|
+
if (this._verified && !this.secure) {
|
|
139
|
+
args = this.localDevice.openBoxedAndSignedData(args);
|
|
140
|
+
}
|
|
141
|
+
result = await handler(...args);
|
|
142
|
+
if (this._verified && !this.secure) {
|
|
143
|
+
result = this.localDevice.signAndBoxDataForDevice(result, this._remoteDeviceInfo);
|
|
144
|
+
}
|
|
145
|
+
callback(null, result);
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
console.error(`Error handling ${eventName}(${JSON.stringify(args)})`, e);
|
|
149
|
+
let rpcError = { error: e.message, errorType: 'RPC_ERROR' };
|
|
150
|
+
if (this._verified && !this.secure) {
|
|
151
|
+
rpcError = this.localDevice.signAndBoxDataForDevice(rpcError, this._remoteDeviceInfo);
|
|
152
|
+
}
|
|
153
|
+
callback(rpcError);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
removeAllListeners(eventName) {
|
|
158
|
+
this.socket.removeAllListeners(eventName);
|
|
159
|
+
}
|
|
160
|
+
reset() {
|
|
161
|
+
this._remoteDeviceInfo = {
|
|
162
|
+
deviceId: '',
|
|
163
|
+
userId: '',
|
|
164
|
+
publicKey: '',
|
|
165
|
+
publicBoxKey: '',
|
|
166
|
+
};
|
|
167
|
+
this._verified = false;
|
|
168
|
+
this.secureLocal = false;
|
|
169
|
+
this.secureRemote = false;
|
|
170
|
+
this.forceInsecure = false;
|
|
171
|
+
this.trustLevel = socket_type_1.TrustLevel.Unknown;
|
|
172
|
+
}
|
|
173
|
+
initiateHandshake(serverAddress, remoteDeviceInfo) {
|
|
174
|
+
if (remoteDeviceInfo) {
|
|
175
|
+
this._remoteDeviceInfo = remoteDeviceInfo;
|
|
176
|
+
}
|
|
177
|
+
const handshake = this.localDevice.getHandshake(this.connectionId, serverAddress);
|
|
178
|
+
return this.localDevice.boxDataForDevice(handshake, this._remoteDeviceInfo);
|
|
179
|
+
}
|
|
180
|
+
async completeHandshake(boxedHandshake) {
|
|
181
|
+
const signedHandshake = this.localDevice.openBoxWithSecretKey(boxedHandshake);
|
|
182
|
+
const _handshake = signedHandshake.contents;
|
|
183
|
+
const timeDiff = Math.abs(Date.now() - _handshake.timestamp);
|
|
184
|
+
if (timeDiff > this.handshakeTimestampToleranceMs) {
|
|
185
|
+
throw new Error(`Remote device's system clock is too far out of sync`);
|
|
186
|
+
}
|
|
187
|
+
const clientServerAddress = normalizeAddress(signedHandshake.contents.serverAddress);
|
|
188
|
+
const thisServerAddress = this.localDeviceServerAddresses?.find(a => a === clientServerAddress) ||
|
|
189
|
+
this.localDeviceServerAddresses?.[0] ||
|
|
190
|
+
'unknown';
|
|
191
|
+
// only set local secure if the server address matches the client's address and the address is using https
|
|
192
|
+
this.secureLocal = clientServerAddress === thisServerAddress && thisServerAddress.startsWith('https');
|
|
193
|
+
const handshakeResponse = this.localDevice.handshakeResponse(signedHandshake, this.connectionId, thisServerAddress);
|
|
194
|
+
this._remoteDeviceInfo = {
|
|
195
|
+
userId: _handshake.userId,
|
|
196
|
+
deviceId: _handshake.deviceId,
|
|
197
|
+
publicKey: _handshake.publicKey,
|
|
198
|
+
publicBoxKey: _handshake.publicBoxKey,
|
|
199
|
+
};
|
|
200
|
+
this.trustLevel = await this.getTrustLevel(signedHandshake.contents, true);
|
|
201
|
+
if (this.trustLevel < socket_type_1.TrustLevel.Unknown) {
|
|
202
|
+
throw new Error('Untrusted connection');
|
|
203
|
+
}
|
|
204
|
+
console.log(new Date().toISOString(), `Connection ${this.connectionId} verified on server side with trust level ${this.trustLevel}`);
|
|
205
|
+
this._verified = true;
|
|
206
|
+
if (this.onHandshakeComplete) {
|
|
207
|
+
setTimeout(() => {
|
|
208
|
+
this.onHandshakeComplete?.(this._remoteDeviceInfo);
|
|
209
|
+
}, 10);
|
|
210
|
+
}
|
|
211
|
+
return handshakeResponse;
|
|
212
|
+
}
|
|
213
|
+
async doHandshake(remoteAddress) {
|
|
214
|
+
remoteAddress = normalizeAddress(remoteAddress);
|
|
215
|
+
this.reset();
|
|
216
|
+
await this.emit('reset');
|
|
217
|
+
const remoteDeviceInfoSigned = await this.emit('requestDeviceInfo');
|
|
218
|
+
const remoteDeviceInfo = (0, keys_1.openSignedObject)(remoteDeviceInfoSigned);
|
|
219
|
+
const handshake = await this.initiateHandshake(remoteAddress, remoteDeviceInfo);
|
|
220
|
+
const handshakeResponseBox = await this.emit('completeHandshake', handshake);
|
|
221
|
+
const handshakeResponse = await this.localDevice.openBoxedAndSignedData(handshakeResponseBox);
|
|
222
|
+
if (handshakeResponse.connectionId !== this.connectionId) {
|
|
223
|
+
throw new Error(`Invalid connectionId ${handshakeResponse.connectionId}, expected ${this.connectionId}`);
|
|
224
|
+
}
|
|
225
|
+
if (remoteDeviceInfo.publicKey != handshakeResponse.publicKey || remoteDeviceInfo.publicBoxKey != handshakeResponse.publicBoxKey) {
|
|
226
|
+
throw new Error('Inconsistent public keys');
|
|
227
|
+
}
|
|
228
|
+
if (remoteDeviceInfo.userId != handshakeResponse.userId || remoteDeviceInfo.deviceId != handshakeResponse.deviceId) {
|
|
229
|
+
throw new Error('Inconsistent device info');
|
|
230
|
+
}
|
|
231
|
+
this._verified = true;
|
|
232
|
+
this.secureLocal = handshakeResponse.serverAddress === remoteAddress && remoteAddress.startsWith('https');
|
|
233
|
+
if (this.secureLocal) {
|
|
234
|
+
await this.emit('requestSecure');
|
|
235
|
+
}
|
|
236
|
+
this.trustLevel = await this.getTrustLevel(remoteDeviceInfo, true);
|
|
237
|
+
if (this.trustLevel < socket_type_1.TrustLevel.Unknown) {
|
|
238
|
+
this.reset();
|
|
239
|
+
this.emit('reset');
|
|
240
|
+
throw new Error('Untrusted connection');
|
|
241
|
+
}
|
|
242
|
+
console.log(new Date().toISOString(), `Connection ${this.connectionId} (${remoteAddress}) verified on client side with trust level ${this.trustLevel}`);
|
|
243
|
+
return handshakeResponse;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
exports.Connection = Connection;
|
|
247
|
+
function normalizeAddress(address) {
|
|
248
|
+
return address.toLowerCase().replace(/\/$/, '');
|
|
249
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|