@peers-app/peers-sdk 0.7.2 → 0.7.5
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/data-context.d.ts +1 -1
- package/dist/context/data-context.js +2 -3
- package/dist/context/user-context-singleton.js +13 -31
- package/dist/context/user-context.d.ts +2 -5
- package/dist/context/user-context.js +20 -15
- package/dist/data/assistants.d.ts +1 -1
- package/dist/data/change-tracking.d.ts +16 -16
- package/dist/data/channels.d.ts +1 -1
- package/dist/data/data-locks.d.ts +2 -2
- package/dist/data/data-locks.test.js +3 -0
- package/dist/data/devices.d.ts +4 -4
- package/dist/data/embeddings.d.ts +1 -1
- package/dist/data/group-members.d.ts +7 -4
- package/dist/data/group-members.js +98 -32
- package/dist/data/groups.d.ts +7 -3
- package/dist/data/groups.js +91 -30
- package/dist/data/index.d.ts +1 -0
- package/dist/data/index.js +1 -0
- package/dist/data/knowledge/knowledge-frames.d.ts +1 -1
- package/dist/data/knowledge/knowledge-links.d.ts +1 -1
- package/dist/data/knowledge/knowledge-values.d.ts +1 -1
- package/dist/data/knowledge/peer-types.d.ts +1 -1
- package/dist/data/knowledge/predicates.d.ts +1 -1
- package/dist/data/messages.d.ts +4 -4
- package/dist/data/orm/client-proxy.data-source.js +8 -18
- package/dist/data/orm/decorators.d.ts +1 -1
- package/dist/data/orm/decorators.js +7 -6
- package/dist/data/packages.d.ts +2 -1
- package/dist/data/packages.js +90 -40
- package/dist/data/peer-events/peer-event-handlers.d.ts +1 -1
- package/dist/data/peer-events/peer-event-types.d.ts +1 -1
- package/dist/data/persistent-vars.js +124 -119
- package/dist/data/tool-tests.d.ts +1 -1
- package/dist/data/tools.d.ts +1 -1
- package/dist/data/user-permissions.test.js +7 -10
- package/dist/data/user-trust-levels.d.ts +42 -0
- package/dist/data/user-trust-levels.js +60 -0
- package/dist/data/users.d.ts +7 -7
- package/dist/data/users.js +86 -27
- package/dist/data/workflow-logs.d.ts +1 -1
- package/dist/data/workflow-runs.js +1 -1
- package/dist/data/workflows.d.ts +1 -1
- package/dist/device/connection.js +2 -2
- package/dist/device/get-trust-level.js +10 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/logging/console-logger.d.ts +10 -0
- package/dist/logging/console-logger.js +206 -0
- package/dist/logging/console-logs.table.d.ts +48 -0
- package/dist/logging/console-logs.table.js +140 -0
- package/dist/logging/index.d.ts +2 -0
- package/dist/logging/index.js +18 -0
- package/dist/rpc-types.d.ts +0 -11
- package/dist/rpc-types.js +0 -8
- package/dist/types/peer-device.d.ts +10 -0
- package/dist/users.query.d.ts +3 -1
- package/dist/users.query.js +39 -11
- package/package.json +1 -1
package/dist/data/users.d.ts
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { DataContext } from "../context/data-context";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import type { ISaveOptions } from "./orm/data-query";
|
|
4
|
+
import { Table } from "./orm/table";
|
|
5
5
|
export declare const userSchema: z.ZodObject<{
|
|
6
6
|
userId: z.ZodString;
|
|
7
7
|
name: z.ZodString;
|
|
8
8
|
publicKey: z.ZodString;
|
|
9
9
|
publicBoxKey: z.ZodString;
|
|
10
|
-
trustLevel: z.ZodOptional<z.ZodNativeEnum<typeof TrustLevel>>;
|
|
11
10
|
signature: z.ZodOptional<z.ZodString>;
|
|
12
11
|
}, "strip", z.ZodTypeAny, {
|
|
13
12
|
name: string;
|
|
14
13
|
publicKey: string;
|
|
15
|
-
publicBoxKey: string;
|
|
16
14
|
userId: string;
|
|
15
|
+
publicBoxKey: string;
|
|
17
16
|
signature?: string | undefined;
|
|
18
|
-
trustLevel?: TrustLevel | undefined;
|
|
19
17
|
}, {
|
|
20
18
|
name: string;
|
|
21
19
|
publicKey: string;
|
|
22
|
-
publicBoxKey: string;
|
|
23
20
|
userId: string;
|
|
21
|
+
publicBoxKey: string;
|
|
24
22
|
signature?: string | undefined;
|
|
25
|
-
trustLevel?: TrustLevel | undefined;
|
|
26
23
|
}>;
|
|
27
24
|
export type IUser = z.infer<typeof userSchema>;
|
|
28
25
|
export declare class UsersTable extends Table<IUser> {
|
|
29
26
|
static isPassthrough: boolean;
|
|
30
27
|
save(user: IUser, opts?: ISaveOptions): Promise<IUser>;
|
|
28
|
+
signAndSave(user: IUser, opts?: ISaveOptions): Promise<IUser>;
|
|
29
|
+
private static addSignatureToUser;
|
|
30
|
+
static enableUserSigning(fn: (user: IUser) => IUser): void;
|
|
31
31
|
/** @deprecated Forbidden on UsersTable; use save() */
|
|
32
32
|
insert(..._args: Parameters<Table<IUser>['insert']>): never;
|
|
33
33
|
/** @deprecated Forbidden on UsersTable; use save() */
|
package/dist/data/users.js
CHANGED
|
@@ -1,22 +1,55 @@
|
|
|
1
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
|
+
};
|
|
2
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
37
|
exports.myUserId = exports.UsersTable = exports.userSchema = void 0;
|
|
4
38
|
exports.Users = Users;
|
|
5
39
|
exports.getMe = getMe;
|
|
6
40
|
const zod_1 = require("zod");
|
|
7
41
|
const user_context_singleton_1 = require("../context/user-context-singleton");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
42
|
+
const decorators_1 = require("./orm/decorators");
|
|
43
|
+
const table_1 = require("./orm/table");
|
|
10
44
|
const table_definitions_system_1 = require("./orm/table-definitions.system");
|
|
11
45
|
const types_1 = require("./orm/types");
|
|
12
|
-
const user_permissions_1 = require("./user-permissions");
|
|
13
46
|
const persistent_vars_1 = require("./persistent-vars");
|
|
47
|
+
const user_permissions_1 = require("./user-permissions");
|
|
14
48
|
exports.userSchema = zod_1.z.object({
|
|
15
49
|
userId: zod_1.z.string(),
|
|
16
50
|
name: zod_1.z.string(),
|
|
17
51
|
publicKey: zod_1.z.string().describe('The public key the user uses to sign messages'),
|
|
18
52
|
publicBoxKey: zod_1.z.string().describe('The public key to use to encrypt data that only this user can decrypt'),
|
|
19
|
-
trustLevel: zod_1.z.nativeEnum(socket_type_1.TrustLevel).optional().describe('The trust level of the user'),
|
|
20
53
|
signature: zod_1.z.string().optional().describe('The signed hash of this user object excluding the signature itself'),
|
|
21
54
|
});
|
|
22
55
|
const metaData = {
|
|
@@ -30,32 +63,58 @@ const metaData = {
|
|
|
30
63
|
{ fields: ['publicBoxKey'] },
|
|
31
64
|
]
|
|
32
65
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
66
|
+
let UsersTable = (() => {
|
|
67
|
+
let _classSuper = table_1.Table;
|
|
68
|
+
let _instanceExtraInitializers = [];
|
|
69
|
+
let _signAndSave_decorators;
|
|
70
|
+
return class UsersTable extends _classSuper {
|
|
71
|
+
static {
|
|
72
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
73
|
+
_signAndSave_decorators = [(0, decorators_1.ProxyClientTableMethodCalls)()];
|
|
74
|
+
__esDecorate(this, null, _signAndSave_decorators, { kind: "method", name: "signAndSave", static: false, private: false, access: { has: obj => "signAndSave" in obj, get: obj => obj.signAndSave }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
75
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
38
76
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
77
|
+
static isPassthrough = false;
|
|
78
|
+
async save(user, opts) {
|
|
79
|
+
if (UsersTable.isPassthrough) {
|
|
80
|
+
return super.save(user, opts);
|
|
81
|
+
}
|
|
82
|
+
const userContext = await (0, user_context_singleton_1.getUserContext)();
|
|
83
|
+
const userContextUserTable = Users(userContext.userDataContext);
|
|
84
|
+
if (this === userContextUserTable) {
|
|
85
|
+
// user is allowed to make any changes they want to their own user table
|
|
86
|
+
return super.save(user, opts);
|
|
87
|
+
}
|
|
88
|
+
// Get the old user record if it exists
|
|
89
|
+
const oldUser = await this.get(user.userId);
|
|
90
|
+
await (0, user_permissions_1.verifyUserSignature)(user, oldUser);
|
|
43
91
|
return super.save(user, opts);
|
|
44
92
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
93
|
+
async signAndSave(user, opts) {
|
|
94
|
+
if (!UsersTable.addSignatureToUser) {
|
|
95
|
+
throw new Error('User signing must be enabled to sign and save users. Call UsersTable.enableUserSigning(fn) to enable it.');
|
|
96
|
+
}
|
|
97
|
+
user = UsersTable.addSignatureToUser(user);
|
|
98
|
+
return this.save(user, opts);
|
|
99
|
+
}
|
|
100
|
+
static addSignatureToUser = undefined;
|
|
101
|
+
static enableUserSigning(fn) {
|
|
102
|
+
UsersTable.addSignatureToUser = fn;
|
|
103
|
+
}
|
|
104
|
+
/** @deprecated Forbidden on UsersTable; use save() */
|
|
105
|
+
insert(..._args) {
|
|
106
|
+
throw new Error('UsersTable forbids insert; use save()');
|
|
107
|
+
}
|
|
108
|
+
/** @deprecated Forbidden on UsersTable; use save() */
|
|
109
|
+
update(..._args) {
|
|
110
|
+
throw new Error('UsersTable forbids update; use save()');
|
|
111
|
+
}
|
|
112
|
+
constructor() {
|
|
113
|
+
super(...arguments);
|
|
114
|
+
__runInitializers(this, _instanceExtraInitializers);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
})();
|
|
59
118
|
exports.UsersTable = UsersTable;
|
|
60
119
|
(0, table_definitions_system_1.registerSystemTableDefinition)(metaData, exports.userSchema, UsersTable);
|
|
61
120
|
function Users(dataContext) {
|
|
@@ -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("
|
|
69
|
+
export declare function WorkflowLogs(dataContext?: DataContext): import("./orm").Table<{
|
|
70
70
|
workflowLogId: string;
|
|
71
71
|
workflowRunId: string;
|
|
72
72
|
contextId: string;
|
|
@@ -93,7 +93,7 @@ let WorkflowRunTable = (() => {
|
|
|
93
93
|
return class WorkflowRunTable extends _classSuper {
|
|
94
94
|
static {
|
|
95
95
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
96
|
-
_haltRun_decorators = [(0, orm_1.
|
|
96
|
+
_haltRun_decorators = [(0, orm_1.ProxyClientTableMethodCalls)()];
|
|
97
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
98
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
99
99
|
}
|
package/dist/data/workflows.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DataContext } from "../context/data-context";
|
|
2
|
-
export declare function Workflows(dataContext?: DataContext): import("
|
|
2
|
+
export declare function Workflows(dataContext?: DataContext): import("./orm").Table<{
|
|
3
3
|
name: string;
|
|
4
4
|
description: string;
|
|
5
5
|
createdAt: Date;
|
|
@@ -201,7 +201,7 @@ class Connection {
|
|
|
201
201
|
if (this.trustLevel < socket_type_1.TrustLevel.Unknown) {
|
|
202
202
|
throw new Error('Untrusted connection');
|
|
203
203
|
}
|
|
204
|
-
console.log(
|
|
204
|
+
console.log(`Connection ${this.connectionId} verified on server side with trust level ${this.trustLevel}`);
|
|
205
205
|
this._verified = true;
|
|
206
206
|
if (this.onHandshakeComplete) {
|
|
207
207
|
setTimeout(() => {
|
|
@@ -239,7 +239,7 @@ class Connection {
|
|
|
239
239
|
this.emit('reset');
|
|
240
240
|
throw new Error('Untrusted connection');
|
|
241
241
|
}
|
|
242
|
-
console.log(
|
|
242
|
+
console.log(`Connection ${this.connectionId} (${remoteAddress}) verified on client side with trust level ${this.trustLevel}`);
|
|
243
243
|
return handshakeResponse;
|
|
244
244
|
}
|
|
245
245
|
}
|
|
@@ -15,16 +15,17 @@ function getTrustLevelFn(me, serverUrl) {
|
|
|
15
15
|
return socket_type_1.TrustLevel.Trusted;
|
|
16
16
|
}
|
|
17
17
|
// await Devices().delete(deviceInfo.deviceId);
|
|
18
|
-
let [user, device] = await Promise.all([
|
|
18
|
+
let [user, device, userTrustLevel] = await Promise.all([
|
|
19
19
|
(0, data_1.Users)(userDataContext).get(deviceInfo.userId),
|
|
20
20
|
(0, data_1.Devices)(userDataContext).get(deviceInfo.deviceId),
|
|
21
|
+
(0, data_1.UserTrustLevels)(userDataContext).get(deviceInfo.userId),
|
|
21
22
|
]);
|
|
22
23
|
if (user && device && !(deviceInfo.userId === device.userId && deviceInfo.userId === user.userId && deviceInfo.publicKey === user.publicKey && deviceInfo.publicBoxKey === user.publicBoxKey)) {
|
|
23
24
|
console.error(new Date().toISOString(), 'deviceInfo does not align with local info about user and device', { deviceInfo, user, device });
|
|
24
25
|
// TODO check if user has changed their public keys
|
|
25
26
|
return socket_type_1.TrustLevel.Untrusted;
|
|
26
27
|
}
|
|
27
|
-
if (
|
|
28
|
+
if (userTrustLevel?.trustLevel && userTrustLevel.trustLevel >= socket_type_1.TrustLevel.Trusted && device?.trustLevel && device.trustLevel >= socket_type_1.TrustLevel.Trusted) {
|
|
28
29
|
device.lastSeen = new Date();
|
|
29
30
|
await (0, data_1.Devices)(userDataContext).update(device);
|
|
30
31
|
return socket_type_1.TrustLevel.Trusted;
|
|
@@ -63,7 +64,7 @@ function getTrustLevelFn(me, serverUrl) {
|
|
|
63
64
|
// console.error(new Date().toISOString(), 'Error getting trust level from server', serverUrl, err);
|
|
64
65
|
// return TrustLevel.Unknown;
|
|
65
66
|
// });
|
|
66
|
-
// console.log(
|
|
67
|
+
// console.log('Remote trust level', { _remoteTrustLevel, serverUrl, remoteUrlBeingChecked: serverUrl });
|
|
67
68
|
// if (_remoteTrustLevel < TrustLevel.Unknown) {
|
|
68
69
|
// console.error(new Date().toISOString(), 'Unverified user failed trust check', { user, remoteTrustLevel });
|
|
69
70
|
// device.trustLevel = _remoteTrustLevel;
|
|
@@ -76,9 +77,12 @@ function getTrustLevelFn(me, serverUrl) {
|
|
|
76
77
|
// }
|
|
77
78
|
// }
|
|
78
79
|
// }
|
|
79
|
-
if (remoteTrustLevel > socket_type_1.TrustLevel.Unknown && !
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
if (remoteTrustLevel > socket_type_1.TrustLevel.Unknown && !userTrustLevel) {
|
|
81
|
+
await (0, data_1.UserTrustLevels)(userDataContext).save({
|
|
82
|
+
userId: deviceInfo.userId,
|
|
83
|
+
trustLevel: socket_type_1.TrustLevel.Known,
|
|
84
|
+
assignedAt: new Date(),
|
|
85
|
+
});
|
|
82
86
|
}
|
|
83
87
|
else if (newUser) {
|
|
84
88
|
await (0, data_1.Users)(userDataContext).save(user);
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup console proxy to capture all console output and write to ConsoleLogs table.
|
|
3
|
+
* Also subscribes to dataChanged events to output logs from other process instances.
|
|
4
|
+
* @param processName - The name of the process (e.g., 'main', 'renderer')
|
|
5
|
+
*/
|
|
6
|
+
export declare function setupConsoleProxy(processName: string): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Restore original console methods
|
|
9
|
+
*/
|
|
10
|
+
export declare function restoreConsole(): void;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setupConsoleProxy = setupConsoleProxy;
|
|
4
|
+
exports.restoreConsole = restoreConsole;
|
|
5
|
+
const utils_1 = require("../utils");
|
|
6
|
+
const console_logs_table_1 = require("./console-logs.table");
|
|
7
|
+
// Store original console methods
|
|
8
|
+
const originalConsole = {
|
|
9
|
+
debug: console.debug,
|
|
10
|
+
info: console.info,
|
|
11
|
+
log: console.log,
|
|
12
|
+
warn: console.warn,
|
|
13
|
+
error: console.error,
|
|
14
|
+
};
|
|
15
|
+
let isProxySetup = false;
|
|
16
|
+
let currentProcessName = 'unknown';
|
|
17
|
+
let currentProcessInstanceId = '';
|
|
18
|
+
/**
|
|
19
|
+
* Setup console proxy to capture all console output and write to ConsoleLogs table.
|
|
20
|
+
* Also subscribes to dataChanged events to output logs from other process instances.
|
|
21
|
+
* @param processName - The name of the process (e.g., 'main', 'renderer')
|
|
22
|
+
*/
|
|
23
|
+
async function setupConsoleProxy(processName) {
|
|
24
|
+
if (isProxySetup) {
|
|
25
|
+
console.warn('Console proxy already setup, skipping...');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
isProxySetup = true;
|
|
29
|
+
currentProcessName = processName;
|
|
30
|
+
currentProcessInstanceId = (0, utils_1.newid)(); // Unique ID for this process instance
|
|
31
|
+
const levels = ['debug', 'info', 'log', 'warn', 'error'];
|
|
32
|
+
// Monkey-patch console methods to capture local logs
|
|
33
|
+
levels.forEach((level) => {
|
|
34
|
+
const original = originalConsole[level];
|
|
35
|
+
console[level] = function (...args) {
|
|
36
|
+
// Always call original console method first (preserve terminal output)
|
|
37
|
+
original.apply(console, args);
|
|
38
|
+
// Asynchronously write to database (don't block console output)
|
|
39
|
+
writeLogToDatabase(level, args).catch((err) => {
|
|
40
|
+
// Use original console to avoid infinite recursion
|
|
41
|
+
originalConsole.error('Failed to write log to database:', err);
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
// Subscribe to dataChanged events to output logs from OTHER process instances
|
|
46
|
+
try {
|
|
47
|
+
const consoleLogsTable = await (0, console_logs_table_1.ConsoleLogs)();
|
|
48
|
+
consoleLogsTable.dataChanged.subscribe((evt) => {
|
|
49
|
+
const log = evt.dataObject;
|
|
50
|
+
// Skip if this is our own log
|
|
51
|
+
if (log.processInstanceId === currentProcessInstanceId) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Output log from another process with prefix
|
|
55
|
+
const colorCode = log.process === 'renderer' ? '\x1b[36m' : '\x1b[35m'; // cyan for renderer, magenta for main
|
|
56
|
+
const resetCode = '\x1b[0m';
|
|
57
|
+
const prefix = `${colorCode}[${log.process}]${resetCode}`;
|
|
58
|
+
const logLevel = log.level;
|
|
59
|
+
const logArgs = [prefix, log.message];
|
|
60
|
+
if (log.context) {
|
|
61
|
+
logArgs.push(log.context);
|
|
62
|
+
}
|
|
63
|
+
if (originalConsole[logLevel]) {
|
|
64
|
+
originalConsole[logLevel](...logArgs);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
originalConsole.log(...logArgs);
|
|
68
|
+
}
|
|
69
|
+
// Also output stack trace for errors
|
|
70
|
+
if (log.stackTrace) {
|
|
71
|
+
originalConsole.error(log.stackTrace);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
originalConsole.error('Failed to subscribe to console logs dataChanged:', err);
|
|
77
|
+
}
|
|
78
|
+
console.log(`Console proxy initialized for process: ${processName} (instance: ${currentProcessInstanceId})`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Restore original console methods
|
|
82
|
+
*/
|
|
83
|
+
function restoreConsole() {
|
|
84
|
+
if (!isProxySetup) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
console.debug = originalConsole.debug;
|
|
88
|
+
console.info = originalConsole.info;
|
|
89
|
+
console.log = originalConsole.log;
|
|
90
|
+
console.warn = originalConsole.warn;
|
|
91
|
+
console.error = originalConsole.error;
|
|
92
|
+
isProxySetup = false;
|
|
93
|
+
originalConsole.log('Console proxy removed, original console restored');
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Write a log entry to the ConsoleLogs table
|
|
97
|
+
*/
|
|
98
|
+
async function writeLogToDatabase(level, args) {
|
|
99
|
+
try {
|
|
100
|
+
// Format message from arguments
|
|
101
|
+
const message = formatLogMessage(args);
|
|
102
|
+
// Extract context objects from arguments
|
|
103
|
+
const context = extractContext(args);
|
|
104
|
+
// Get stack trace for errors
|
|
105
|
+
const stackTrace = level === 'error' ? getStackTrace() : undefined;
|
|
106
|
+
// Extract source from stack trace
|
|
107
|
+
const source = extractSource(stackTrace);
|
|
108
|
+
const logRecord = {
|
|
109
|
+
logId: (0, utils_1.newid)(),
|
|
110
|
+
timestamp: (0, utils_1.getTimestamp)(),
|
|
111
|
+
level,
|
|
112
|
+
process: currentProcessName,
|
|
113
|
+
processInstanceId: currentProcessInstanceId,
|
|
114
|
+
source,
|
|
115
|
+
message,
|
|
116
|
+
context,
|
|
117
|
+
stackTrace,
|
|
118
|
+
};
|
|
119
|
+
const consoleLogsTable = await (0, console_logs_table_1.ConsoleLogs)();
|
|
120
|
+
await consoleLogsTable.insert(logRecord);
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
// Silently fail if table not available (e.g., during initialization)
|
|
124
|
+
// Don't use console here to avoid infinite recursion
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Format log arguments into a single message string
|
|
129
|
+
*/
|
|
130
|
+
function formatLogMessage(args) {
|
|
131
|
+
return args.map((arg) => {
|
|
132
|
+
if (typeof arg === 'string') {
|
|
133
|
+
return arg;
|
|
134
|
+
}
|
|
135
|
+
if (arg instanceof Error) {
|
|
136
|
+
return `${arg.name}: ${arg.message}`;
|
|
137
|
+
}
|
|
138
|
+
if (typeof arg === 'object') {
|
|
139
|
+
try {
|
|
140
|
+
return JSON.stringify(arg);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return String(arg);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return String(arg);
|
|
147
|
+
}).join(' ');
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Extract structured context objects from log arguments
|
|
151
|
+
*/
|
|
152
|
+
function extractContext(args) {
|
|
153
|
+
const objects = args.filter((arg) => arg && typeof arg === 'object' && !(arg instanceof Error) && !(arg instanceof Date));
|
|
154
|
+
if (objects.length === 0) {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
if (objects.length === 1) {
|
|
158
|
+
return objects[0];
|
|
159
|
+
}
|
|
160
|
+
// Merge multiple objects
|
|
161
|
+
return Object.assign({}, ...objects);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get current stack trace
|
|
165
|
+
*/
|
|
166
|
+
function getStackTrace() {
|
|
167
|
+
try {
|
|
168
|
+
const stack = new Error().stack;
|
|
169
|
+
if (!stack)
|
|
170
|
+
return undefined;
|
|
171
|
+
// Remove first few lines (Error message and this function's frames)
|
|
172
|
+
const lines = stack.split('\n');
|
|
173
|
+
return lines.slice(4).join('\n');
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Extract source file/module from stack trace
|
|
181
|
+
*/
|
|
182
|
+
function extractSource(stackTrace) {
|
|
183
|
+
if (!stackTrace)
|
|
184
|
+
return undefined;
|
|
185
|
+
try {
|
|
186
|
+
const lines = stackTrace.split('\n');
|
|
187
|
+
if (lines.length === 0)
|
|
188
|
+
return undefined;
|
|
189
|
+
// Get first line of stack (caller's location)
|
|
190
|
+
const firstLine = lines[0];
|
|
191
|
+
// Extract file path from patterns like:
|
|
192
|
+
// "at function (file:///path/to/file.ts:123:45)"
|
|
193
|
+
// "at file:///path/to/file.ts:123:45"
|
|
194
|
+
const match = firstLine.match(/\((.*?):\d+:\d+\)|at (.*?):\d+:\d+/);
|
|
195
|
+
if (match) {
|
|
196
|
+
const path = match[1] || match[2];
|
|
197
|
+
// Extract just the filename
|
|
198
|
+
const filename = path.split('/').pop()?.split('?')[0];
|
|
199
|
+
return filename;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// Ignore parsing errors
|
|
204
|
+
}
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ITableMetaData } from "../data/orm/types";
|
|
3
|
+
import { ITableDependencies, Table } from "../data/orm";
|
|
4
|
+
export declare const consoleLogSchema: z.ZodObject<{
|
|
5
|
+
logId: z.ZodEffects<z.ZodString, string, string>;
|
|
6
|
+
timestamp: z.ZodDefault<z.ZodNumber>;
|
|
7
|
+
level: z.ZodEnum<["debug", "info", "log", "warn", "error"]>;
|
|
8
|
+
process: z.ZodString;
|
|
9
|
+
processInstanceId: z.ZodString;
|
|
10
|
+
source: z.ZodOptional<z.ZodString>;
|
|
11
|
+
message: z.ZodString;
|
|
12
|
+
context: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodAny, z.objectOutputType<{}, z.ZodAny, "strip">, z.objectInputType<{}, z.ZodAny, "strip">>>;
|
|
13
|
+
stackTrace: z.ZodOptional<z.ZodString>;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
message: string;
|
|
16
|
+
timestamp: number;
|
|
17
|
+
logId: string;
|
|
18
|
+
level: "error" | "debug" | "info" | "log" | "warn";
|
|
19
|
+
process: string;
|
|
20
|
+
processInstanceId: string;
|
|
21
|
+
source?: string | undefined;
|
|
22
|
+
context?: z.objectOutputType<{}, z.ZodAny, "strip"> | undefined;
|
|
23
|
+
stackTrace?: string | undefined;
|
|
24
|
+
}, {
|
|
25
|
+
message: string;
|
|
26
|
+
logId: string;
|
|
27
|
+
level: "error" | "debug" | "info" | "log" | "warn";
|
|
28
|
+
process: string;
|
|
29
|
+
processInstanceId: string;
|
|
30
|
+
source?: string | undefined;
|
|
31
|
+
timestamp?: number | undefined;
|
|
32
|
+
context?: z.objectInputType<{}, z.ZodAny, "strip"> | undefined;
|
|
33
|
+
stackTrace?: string | undefined;
|
|
34
|
+
}>;
|
|
35
|
+
export type IConsoleLog = z.infer<typeof consoleLogSchema>;
|
|
36
|
+
export declare class ConsoleLogsTable extends Table<IConsoleLog> {
|
|
37
|
+
readonly LOG_TTL: number;
|
|
38
|
+
readonly LOG_CLEANUP_INTERVAL: number;
|
|
39
|
+
constructor(metaData: ITableMetaData, deps: ITableDependencies);
|
|
40
|
+
private logCleanupInitialized;
|
|
41
|
+
initializeLogCleanup(): Promise<void>;
|
|
42
|
+
deleteOldLogs(cutoffTimestamp?: number): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* We always use the user's personal data context so all logs are written to the same place. This requires
|
|
46
|
+
* that the table be accessed in an asynchronous way
|
|
47
|
+
*/
|
|
48
|
+
export declare function ConsoleLogs(): Promise<ConsoleLogsTable>;
|