@peers-app/peers-sdk 0.7.3 → 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/user-context-singleton.js +7 -1
- package/dist/context/user-context.d.ts +1 -2
- package/dist/context/user-context.js +11 -9
- package/dist/data/data-locks.test.js +3 -0
- package/dist/data/orm/decorators.js +4 -3
- package/dist/data/persistent-vars.js +124 -119
- package/dist/device/connection.js +2 -2
- package/dist/device/get-trust-level.js +1 -1
- 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.js +0 -1
- package/dist/types/peer-device.d.ts +10 -0
- package/package.json +1 -1
|
@@ -55,7 +55,7 @@ function getTableContainer(dataContext) {
|
|
|
55
55
|
}
|
|
56
56
|
function setDefaultClientUserContext(userId) {
|
|
57
57
|
const clientProxyDataSourceFactory = (metaData, schema, groupId) => {
|
|
58
|
-
return new client_proxy_data_source_1.ClientProxyDataSource(metaData, schema, groupId
|
|
58
|
+
return new client_proxy_data_source_1.ClientProxyDataSource(metaData, schema, groupId || userId);
|
|
59
59
|
};
|
|
60
60
|
const userContext = new user_context_1.UserContext(userId, clientProxyDataSourceFactory);
|
|
61
61
|
(async () => {
|
|
@@ -88,6 +88,12 @@ if (!rpc_types_1.isClient) {
|
|
|
88
88
|
}
|
|
89
89
|
// TODO: add check that client has permission to make this call
|
|
90
90
|
rpc_types_1.rpcServerCalls.tableMethodCall = async (dataContextId, tableName, methodName, ...args) => {
|
|
91
|
+
if (!tableName) {
|
|
92
|
+
throw new Error('tableName is required for tableMethodCall');
|
|
93
|
+
}
|
|
94
|
+
if (!dataContextId) {
|
|
95
|
+
console.warn('dataContextId not provided to tableMethodCall - defaulting to user context. This is discouraged. If userDataContext was intended then pass it in explicitly.');
|
|
96
|
+
}
|
|
91
97
|
const table = await getTable(dataContextId, tableName);
|
|
92
98
|
const method = table[methodName];
|
|
93
99
|
if (typeof method !== 'function') {
|
|
@@ -8,7 +8,6 @@ export declare class UserContext {
|
|
|
8
8
|
readonly dataSourceFactory: DataSourceFactory;
|
|
9
9
|
readonly deviceId: Observable<string>;
|
|
10
10
|
readonly currentlyActiveGroupId: Observable<string | undefined>;
|
|
11
|
-
readonly packagesRootDir: Observable<string>;
|
|
12
11
|
readonly reloadPackagesOnPageRefresh: Observable<boolean>;
|
|
13
12
|
readonly groupIds: Observable<string[]>;
|
|
14
13
|
readonly userDataContext: DataContext;
|
|
@@ -40,7 +39,7 @@ export declare class UserContext {
|
|
|
40
39
|
syncUserAndGroupObjects(userId: string, keys: IPublicPrivateKeys, me?: IUser): Promise<void>;
|
|
41
40
|
subscribeToDataChangedAcrossAllGroups<T extends {
|
|
42
41
|
[key: string]: any;
|
|
43
|
-
}>(table: Table<T>, handler: (evt: ICrossGroupSubscriptionHandlerArgs<T>) => any): import("../events").ISubscriptionResult;
|
|
42
|
+
}>(table: string | Table<T>, handler: (evt: ICrossGroupSubscriptionHandlerArgs<T>) => any): import("../events").ISubscriptionResult;
|
|
44
43
|
}
|
|
45
44
|
export interface ICrossGroupSubscriptionHandlerArgs<T> {
|
|
46
45
|
name: string;
|
|
@@ -13,7 +13,6 @@ class UserContext {
|
|
|
13
13
|
dataSourceFactory;
|
|
14
14
|
deviceId = (0, observable_1.observable)('');
|
|
15
15
|
currentlyActiveGroupId = (0, observable_1.observable)();
|
|
16
|
-
packagesRootDir = (0, observable_1.observable)('');
|
|
17
16
|
reloadPackagesOnPageRefresh = (0, observable_1.observable)(false);
|
|
18
17
|
groupIds = (0, observable_1.observable)([]);
|
|
19
18
|
userDataContext;
|
|
@@ -29,7 +28,12 @@ class UserContext {
|
|
|
29
28
|
this.loadingPromise = this.init();
|
|
30
29
|
}
|
|
31
30
|
async init() {
|
|
32
|
-
|
|
31
|
+
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') {
|
|
32
|
+
console.log(`not setting up user-context pvars during tests because they will interfere with other UserContext instances`);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
await this.loadUserContextObservablesFromDB();
|
|
36
|
+
}
|
|
33
37
|
await this.loadGroupContexts();
|
|
34
38
|
await this.loadAllPackages();
|
|
35
39
|
return this;
|
|
@@ -106,8 +110,9 @@ class UserContext {
|
|
|
106
110
|
* for the user context to be fully loaded before proceeding with standard data access
|
|
107
111
|
*/
|
|
108
112
|
async loadUserContextObservablesFromDB() {
|
|
109
|
-
const persistentVars = await this.userDataContext.tableContainer.getTableByName(
|
|
110
|
-
const
|
|
113
|
+
// const persistentVars: PersistentVarsTable = await this.userDataContext.tableContainer.getTableByName(persistentVarsMetaData.name) as PersistentVarsTable;
|
|
114
|
+
const persistentVars = (0, data_1.PersistentVars)(this.userDataContext);
|
|
115
|
+
const vars = await persistentVars.list({ name: { $in: ['thisDeviceId', 'currentlyActiveGroupId', 'reloadPackagesOnPageRefresh'] } });
|
|
111
116
|
const varDbValues = vars.reduce((acc, curr) => {
|
|
112
117
|
acc[curr.name] = curr.value?.value;
|
|
113
118
|
return acc;
|
|
@@ -119,15 +124,11 @@ class UserContext {
|
|
|
119
124
|
const currentlyActiveGroupIdPVar = (0, data_1.deviceVar)('currentlyActiveGroupId', { dbValue: varDbValues['currentlyActiveGroupId'], defaultValue: '', userContext: this });
|
|
120
125
|
this.currentlyActiveGroupId(currentlyActiveGroupIdPVar());
|
|
121
126
|
(0, observable_1.linkObservables)(currentlyActiveGroupIdPVar, this.currentlyActiveGroupId);
|
|
122
|
-
const packagesRootDirPVar = (0, data_1.deviceVar)('packagesRootDir', { defaultValue: '~/peers-packages', dbValue: varDbValues['packagesRootDir'], userContext: this });
|
|
123
|
-
this.packagesRootDir(packagesRootDirPVar());
|
|
124
|
-
(0, observable_1.linkObservables)(packagesRootDirPVar, this.packagesRootDir);
|
|
125
127
|
const reloadPackagesOnPageRefreshPVar = (0, data_1.deviceVar)('reloadPackagesOnPageRefresh', { defaultValue: false, dbValue: varDbValues['reloadPackagesOnPageRefresh'], userContext: this });
|
|
126
128
|
this.reloadPackagesOnPageRefresh(reloadPackagesOnPageRefreshPVar());
|
|
127
129
|
(0, observable_1.linkObservables)(reloadPackagesOnPageRefreshPVar, this.reloadPackagesOnPageRefresh);
|
|
128
130
|
await Promise.all([
|
|
129
131
|
deviceIdPVar.loadingPromise,
|
|
130
|
-
packagesRootDirPVar.loadingPromise,
|
|
131
132
|
reloadPackagesOnPageRefreshPVar.loadingPromise,
|
|
132
133
|
]);
|
|
133
134
|
}
|
|
@@ -185,7 +186,8 @@ class UserContext {
|
|
|
185
186
|
}
|
|
186
187
|
}
|
|
187
188
|
subscribeToDataChangedAcrossAllGroups(table, handler) {
|
|
188
|
-
const
|
|
189
|
+
const tableName = typeof table === 'string' ? table : table.tableName;
|
|
190
|
+
const tableEventPrefix = `${tableName}_DataChanged_`;
|
|
189
191
|
const subscription = (0, events_1.subscribe)(evt => evt.name.startsWith(tableEventPrefix), async (evt) => {
|
|
190
192
|
const dataContextId = evt.name.endsWith('_') ? this.userId : evt.name.split('_').pop();
|
|
191
193
|
const dataContext = this.getDataContext(dataContextId);
|
|
@@ -11,9 +11,10 @@ function ProxyClientTableMethodCalls() {
|
|
|
11
11
|
return function (target, context) {
|
|
12
12
|
if (context.kind === 'method' && rpc_types_1.isClient) {
|
|
13
13
|
const methodName = context.name;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
// WARNING: Using typescript's magical `this` param
|
|
15
|
+
return function (...args) {
|
|
16
|
+
const dataContextId = this.dataSource.dataContextId || this.groupId || '';
|
|
17
|
+
return rpc_types_1.rpcServerCalls.tableMethodCall(dataContextId, this.tableName, methodName, ...args);
|
|
17
18
|
};
|
|
18
19
|
}
|
|
19
20
|
return target;
|
|
@@ -136,145 +136,150 @@ function persistentVarFactory(name, opts) {
|
|
|
136
136
|
let isSecret = opts.isSecret;
|
|
137
137
|
let rec = undefined;
|
|
138
138
|
persistentVar.loadingPromise = new Promise(async (resolve) => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
function getVarNameInDb() {
|
|
152
|
-
if (scope === 'groupDevice' || scope === 'groupUser') {
|
|
153
|
-
const dc = opts?.dataContext || userContext.defaultDataContext();
|
|
154
|
-
// if it's a group var saved in the user's personal db, it's postfixed with the dataContextId to make it unique
|
|
155
|
-
return name + `_` + dc.dataContextId;
|
|
156
|
-
}
|
|
157
|
-
return name;
|
|
158
|
-
}
|
|
159
|
-
async function loadRecFromDb() {
|
|
160
|
-
const dc = getDataContext();
|
|
161
|
-
const table = PersistentVars(dc);
|
|
162
|
-
const name = getVarNameInDb();
|
|
163
|
-
let dbRec = await table.findOne({ name });
|
|
164
|
-
if (dbRec) {
|
|
165
|
-
if (dbRec.scope !== scope) {
|
|
166
|
-
console.warn(`${name}: deleting old persistent var record because scopes don't match. If this is unexpected there could be two different persistent variables using the same name`);
|
|
167
|
-
await table.delete(dbRec);
|
|
168
|
-
dbRec = undefined;
|
|
139
|
+
try {
|
|
140
|
+
const userContext = opts?.userContext || await (0, user_context_singleton_1.getUserContext)();
|
|
141
|
+
function getDataContext() {
|
|
142
|
+
if (opts?.dataContext) {
|
|
143
|
+
return opts.dataContext;
|
|
144
|
+
}
|
|
145
|
+
if (scope === 'group') {
|
|
146
|
+
return userContext.defaultDataContext();
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
return userContext.userDataContext;
|
|
169
150
|
}
|
|
170
151
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
// if the db says it's secret but the caller didn't specify, assume it's secret
|
|
181
|
-
if (dbRec.isSecret !== undefined && opts.isSecret === undefined) {
|
|
182
|
-
isSecret = dbRec.isSecret;
|
|
183
|
-
}
|
|
184
|
-
return dbRec;
|
|
185
|
-
}
|
|
186
|
-
async function reactToValueChanged(value) {
|
|
187
|
-
if (name === 'colorModePreference')
|
|
188
|
-
console.log(`colorModePreferences pvar value set: ${value}`);
|
|
189
|
-
if (!rec?.persistentVarId && value === defaultValue) {
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
if (!rec?.persistentVarId) {
|
|
193
|
-
rec = await loadRecFromDb();
|
|
194
|
-
}
|
|
195
|
-
const oldValue = rec.value.value;
|
|
196
|
-
if ((0, lodash_1.isEqual)(value, oldValue)) {
|
|
197
|
-
return;
|
|
152
|
+
function getVarNameInDb() {
|
|
153
|
+
if (scope === 'groupDevice' || scope === 'groupUser') {
|
|
154
|
+
const dc = opts?.dataContext || userContext.defaultDataContext();
|
|
155
|
+
// if it's a group var saved in the user's personal db, it's postfixed with the dataContextId to make it unique
|
|
156
|
+
return name + `_` + dc.dataContextId;
|
|
157
|
+
}
|
|
158
|
+
return name;
|
|
198
159
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (
|
|
205
|
-
if (
|
|
206
|
-
console.
|
|
160
|
+
async function loadRecFromDb() {
|
|
161
|
+
const dc = getDataContext();
|
|
162
|
+
const table = PersistentVars(dc);
|
|
163
|
+
const name = getVarNameInDb();
|
|
164
|
+
let dbRec = await table.findOne({ name });
|
|
165
|
+
if (dbRec) {
|
|
166
|
+
if (dbRec.scope !== scope) {
|
|
167
|
+
console.warn(`${name}: deleting old persistent var record because scopes don't match. If this is unexpected there could be two different persistent variables using the same name`);
|
|
168
|
+
await table.delete(dbRec);
|
|
169
|
+
dbRec = undefined;
|
|
207
170
|
}
|
|
208
|
-
await table.delete(rec);
|
|
209
171
|
}
|
|
210
|
-
|
|
172
|
+
if (!dbRec) {
|
|
173
|
+
dbRec = {
|
|
174
|
+
persistentVarId: '',
|
|
175
|
+
name,
|
|
176
|
+
scope,
|
|
177
|
+
isSecret,
|
|
178
|
+
value: { value: defaultValue },
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
// if the db says it's secret but the caller didn't specify, assume it's secret
|
|
182
|
+
if (dbRec.isSecret !== undefined && opts.isSecret === undefined) {
|
|
183
|
+
isSecret = dbRec.isSecret;
|
|
184
|
+
}
|
|
185
|
+
return dbRec;
|
|
211
186
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
187
|
+
async function reactToValueChanged(value) {
|
|
188
|
+
if (name === 'colorModePreference')
|
|
189
|
+
console.log(`colorModePreferences pvar value set: ${value}`);
|
|
190
|
+
if (!rec?.persistentVarId && value === defaultValue) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (!rec?.persistentVarId) {
|
|
194
|
+
rec = await loadRecFromDb();
|
|
195
|
+
}
|
|
196
|
+
const oldValue = rec.value.value;
|
|
197
|
+
if ((0, lodash_1.isEqual)(value, oldValue)) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
rec.value.value = value;
|
|
201
|
+
const dc = getDataContext();
|
|
202
|
+
const table = PersistentVars(dc);
|
|
203
|
+
// delete if value equals default value
|
|
204
|
+
if ((0, lodash_1.isEqual)(rec.value.value, defaultValue)) {
|
|
205
|
+
if (rec.persistentVarId) {
|
|
206
|
+
if (name === 'colorModePreference') {
|
|
207
|
+
console.log(`deleted persistent var ${name} from db:`, rec.value.value);
|
|
208
|
+
}
|
|
209
|
+
await table.delete(rec);
|
|
217
210
|
}
|
|
211
|
+
rec = undefined;
|
|
218
212
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
213
|
+
else {
|
|
214
|
+
try {
|
|
215
|
+
await table.save(rec);
|
|
216
|
+
if (name === 'colorModePreference') {
|
|
217
|
+
console.log(`Saved var ${name} to db:`, rec.value.value);
|
|
218
|
+
}
|
|
225
219
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
220
|
+
catch (err) {
|
|
221
|
+
const errMsg = err?.message || String(err) || '';
|
|
222
|
+
if (errMsg.includes('UNIQUE constraint failed')) {
|
|
223
|
+
console.warn(`Detected UNIQUE constraint failed error when saving persistent var, reloading and retrying: ${name}`);
|
|
224
|
+
rec = await loadRecFromDb();
|
|
225
|
+
persistentVar(rec.value.value);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
console.error('Error saving persistent var', { name, value, rec, err });
|
|
229
|
+
throw err;
|
|
230
|
+
}
|
|
229
231
|
}
|
|
230
232
|
}
|
|
231
233
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (!rec?.persistentVarId && dbRec.name === dbName) {
|
|
238
|
-
rec = dbRec;
|
|
239
|
-
}
|
|
240
|
-
if (dbRec.persistentVarId === rec?.persistentVarId) {
|
|
241
|
-
if (evt.data.op === 'delete') {
|
|
242
|
-
rec = undefined;
|
|
243
|
-
if (defaultValue !== undefined) {
|
|
244
|
-
persistentVar(defaultValue);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
234
|
+
// subscribe to db changes
|
|
235
|
+
userContext.subscribeToDataChangedAcrossAllGroups(exports.persistentVarsMetaData.name, async (evt) => {
|
|
236
|
+
const dbRec = evt.data.dataObject;
|
|
237
|
+
const dbName = getVarNameInDb();
|
|
238
|
+
if (!rec?.persistentVarId && dbRec.name === dbName) {
|
|
248
239
|
rec = dbRec;
|
|
249
|
-
|
|
250
|
-
|
|
240
|
+
}
|
|
241
|
+
if (dbRec.persistentVarId === rec?.persistentVarId) {
|
|
242
|
+
if (evt.data.op === 'delete') {
|
|
243
|
+
rec = undefined;
|
|
244
|
+
if (defaultValue !== undefined) {
|
|
245
|
+
persistentVar(defaultValue);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
rec = dbRec;
|
|
250
|
+
if (!(0, lodash_1.isEqual)(persistentVar(), rec.value.value)) {
|
|
251
|
+
persistentVar(rec.value.value);
|
|
252
|
+
}
|
|
251
253
|
}
|
|
252
254
|
}
|
|
255
|
+
});
|
|
256
|
+
// update group-dependent variables if group context changes and it hasn't been pinned to a specific data context
|
|
257
|
+
const groupDependentScopes = ['group', 'groupDevice', 'groupUser'];
|
|
258
|
+
if (!opts?.dataContext && groupDependentScopes.includes(scope)) {
|
|
259
|
+
userContext.defaultDataContext.subscribe(async () => {
|
|
260
|
+
rec = await loadRecFromDb();
|
|
261
|
+
persistentVar(rec.value.value);
|
|
262
|
+
});
|
|
253
263
|
}
|
|
254
|
-
|
|
255
|
-
// update group-dependent variables if group context changes and it hasn't been pinned to a specific data context
|
|
256
|
-
const groupDependentScopes = ['group', 'groupDevice', 'groupUser'];
|
|
257
|
-
if (!opts?.dataContext && groupDependentScopes.includes(scope)) {
|
|
258
|
-
userContext.defaultDataContext.subscribe(async () => {
|
|
264
|
+
if (!setWithDbValue) {
|
|
259
265
|
rec = await loadRecFromDb();
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (!(0, lodash_1.isEqual)(rec.value.value, persistentVar())) {
|
|
266
|
-
if (name === 'colorModePreference') {
|
|
267
|
-
console.log(`Loaded persistent var ${name} from db:`, rec.value.value);
|
|
266
|
+
if (!(0, lodash_1.isEqual)(rec.value.value, persistentVar())) {
|
|
267
|
+
if (name === 'colorModePreference') {
|
|
268
|
+
console.log(`Loaded persistent var ${name} from db:`, rec.value.value);
|
|
269
|
+
}
|
|
270
|
+
persistentVar(rec.value.value);
|
|
268
271
|
}
|
|
269
|
-
persistentVar(rec.value.value);
|
|
270
272
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
273
|
+
persistentVar.subscribe(newValue => {
|
|
274
|
+
persistentVar.loadingPromise = persistentVar.loadingPromise.then(async () => {
|
|
275
|
+
await reactToValueChanged(newValue);
|
|
276
|
+
return persistentVar;
|
|
277
|
+
});
|
|
276
278
|
});
|
|
277
|
-
}
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
console.error(`an unexpected occurred while loading a persistent var: ${name}`, err);
|
|
282
|
+
}
|
|
278
283
|
resolve(persistentVar);
|
|
279
284
|
});
|
|
280
285
|
return persistentVar;
|
|
@@ -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
|
}
|
|
@@ -64,7 +64,7 @@ function getTrustLevelFn(me, serverUrl) {
|
|
|
64
64
|
// console.error(new Date().toISOString(), 'Error getting trust level from server', serverUrl, err);
|
|
65
65
|
// return TrustLevel.Unknown;
|
|
66
66
|
// });
|
|
67
|
-
// console.log(
|
|
67
|
+
// console.log('Remote trust level', { _remoteTrustLevel, serverUrl, remoteUrlBeingChecked: serverUrl });
|
|
68
68
|
// if (_remoteTrustLevel < TrustLevel.Unknown) {
|
|
69
69
|
// console.error(new Date().toISOString(), 'Unverified user failed trust check', { user, remoteTrustLevel });
|
|
70
70
|
// device.trustLevel = _remoteTrustLevel;
|
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>;
|
|
@@ -0,0 +1,140 @@
|
|
|
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.ConsoleLogsTable = exports.consoleLogSchema = void 0;
|
|
38
|
+
exports.ConsoleLogs = ConsoleLogs;
|
|
39
|
+
const zod_1 = require("zod");
|
|
40
|
+
const zod_types_1 = require("../types/zod-types");
|
|
41
|
+
const types_1 = require("../data/orm/types");
|
|
42
|
+
const user_context_singleton_1 = require("../context/user-context-singleton");
|
|
43
|
+
const table_definitions_system_1 = require("../data/orm/table-definitions.system");
|
|
44
|
+
const utils_1 = require("../utils");
|
|
45
|
+
const orm_1 = require("../data/orm");
|
|
46
|
+
exports.consoleLogSchema = zod_1.z.object({
|
|
47
|
+
logId: zod_types_1.zodPeerId,
|
|
48
|
+
timestamp: zod_1.z.number().default(() => (0, utils_1.getTimestamp)()).describe('The timestamp the log was created created'),
|
|
49
|
+
level: zod_1.z.enum(['debug', 'info', 'log', 'warn', 'error']).describe('The log level'),
|
|
50
|
+
process: zod_1.z.string().describe('The process that generated the log (e.g., main, renderer, worker)'),
|
|
51
|
+
processInstanceId: zod_1.z.string().describe('Unique ID for this process instance to filter own logs'),
|
|
52
|
+
source: zod_1.z.string().optional().describe('The source file or module that generated the log'),
|
|
53
|
+
message: zod_1.z.string().describe('The log message'),
|
|
54
|
+
context: zod_types_1.zodAnyObject.optional().describe('Additional structured context data'),
|
|
55
|
+
stackTrace: zod_1.z.string().optional().describe('Stack trace for errors'),
|
|
56
|
+
});
|
|
57
|
+
const metaData = {
|
|
58
|
+
name: 'ConsoleLogs',
|
|
59
|
+
description: 'System-wide console log entries with cross-process visibility.',
|
|
60
|
+
primaryKeyName: 'logId',
|
|
61
|
+
fields: (0, types_1.schemaToFields)(exports.consoleLogSchema),
|
|
62
|
+
localOnly: true, // Don't sync logs between devices
|
|
63
|
+
indexes: [
|
|
64
|
+
{ fields: ['timestamp'] },
|
|
65
|
+
{ fields: ['level'] },
|
|
66
|
+
{ fields: ['process'] },
|
|
67
|
+
{ fields: ['processInstanceId'] },
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
let ConsoleLogsTable = (() => {
|
|
71
|
+
let _classSuper = orm_1.Table;
|
|
72
|
+
let _instanceExtraInitializers = [];
|
|
73
|
+
let _initializeLogCleanup_decorators;
|
|
74
|
+
let _deleteOldLogs_decorators;
|
|
75
|
+
return class ConsoleLogsTable extends _classSuper {
|
|
76
|
+
static {
|
|
77
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
78
|
+
_initializeLogCleanup_decorators = [(0, orm_1.ProxyClientTableMethodCalls)()];
|
|
79
|
+
_deleteOldLogs_decorators = [(0, orm_1.ProxyClientTableMethodCalls)()];
|
|
80
|
+
__esDecorate(this, null, _initializeLogCleanup_decorators, { kind: "method", name: "initializeLogCleanup", static: false, private: false, access: { has: obj => "initializeLogCleanup" in obj, get: obj => obj.initializeLogCleanup }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
81
|
+
__esDecorate(this, null, _deleteOldLogs_decorators, { kind: "method", name: "deleteOldLogs", static: false, private: false, access: { has: obj => "deleteOldLogs" in obj, get: obj => obj.deleteOldLogs }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
82
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
83
|
+
}
|
|
84
|
+
LOG_TTL = (__runInitializers(this, _instanceExtraInitializers), 7 * 24 * 60 * 60 * 1000); // 7 days
|
|
85
|
+
LOG_CLEANUP_INTERVAL = 24 * 60 * 60 * 1000; // 1 day
|
|
86
|
+
constructor(metaData, deps) {
|
|
87
|
+
super(metaData, deps);
|
|
88
|
+
if (typeof process !== 'undefined' && process.env.NODE_ENV !== 'test') {
|
|
89
|
+
this.initializeLogCleanup();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
logCleanupInitialized = false;
|
|
93
|
+
async initializeLogCleanup() {
|
|
94
|
+
if (this.logCleanupInitialized) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this.logCleanupInitialized = true;
|
|
98
|
+
// always cleanup old logs on startup - randomly spread out of the first 60 seconds to not slam the db
|
|
99
|
+
setTimeout(() => this.deleteOldLogs(), 60_000 * Math.random());
|
|
100
|
+
// regularly clean up logs
|
|
101
|
+
// TODO - consider doing this as a workflow
|
|
102
|
+
setInterval(() => this.deleteOldLogs(), this.LOG_CLEANUP_INTERVAL);
|
|
103
|
+
}
|
|
104
|
+
async deleteOldLogs(cutoffTimestamp = Date.now() - 7 * 24 * 60 * 60 * 1000) {
|
|
105
|
+
const count = await this.count({ timestamp: { $lt: cutoffTimestamp } });
|
|
106
|
+
if (count === 0) {
|
|
107
|
+
console.log(`No old logs to clean up older than ${new Date(cutoffTimestamp).toISOString()}`);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
let ds = this.dataSource;
|
|
111
|
+
while (!(ds instanceof orm_1.SQLDataSource) && ds.dataSource) {
|
|
112
|
+
ds = ds.dataSource;
|
|
113
|
+
}
|
|
114
|
+
if (ds instanceof orm_1.SQLDataSource) {
|
|
115
|
+
const db = ds.db;
|
|
116
|
+
await db.exec(`delete from ConsoleLogs where timestamp < $timestamp`, { timestamp: cutoffTimestamp });
|
|
117
|
+
console.log(`bulk deleted ${count} logs`);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const cursor = this.cursor({ timestamp: { $lt: cutoffTimestamp } }, { sortBy: ['-timestamp'] });
|
|
121
|
+
let count2 = 0;
|
|
122
|
+
for await (const log of cursor) {
|
|
123
|
+
this.delete(log.logId);
|
|
124
|
+
}
|
|
125
|
+
console.log(`cursor deleted ${count2} logs`);
|
|
126
|
+
}
|
|
127
|
+
console.log(`cleaned up console logs`, { expectedCount: count });
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
})();
|
|
131
|
+
exports.ConsoleLogsTable = ConsoleLogsTable;
|
|
132
|
+
(0, table_definitions_system_1.registerSystemTableDefinition)(metaData, exports.consoleLogSchema, ConsoleLogsTable);
|
|
133
|
+
/**
|
|
134
|
+
* We always use the user's personal data context so all logs are written to the same place. This requires
|
|
135
|
+
* that the table be accessed in an asynchronous way
|
|
136
|
+
*/
|
|
137
|
+
async function ConsoleLogs() {
|
|
138
|
+
const userContext = await (0, user_context_singleton_1.getUserContext)();
|
|
139
|
+
return (0, user_context_singleton_1.getTableContainer)(userContext.userDataContext).getTable(metaData, exports.consoleLogSchema, ConsoleLogsTable);
|
|
140
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./console-logger"), exports);
|
|
18
|
+
__exportStar(require("./console-logs.table"), exports);
|
package/dist/rpc-types.js
CHANGED
|
@@ -16,7 +16,6 @@ exports.rpcServerCalls = {
|
|
|
16
16
|
setUserIdAndSecretKey: rpcStub('setUserIdAndSecretKey'),
|
|
17
17
|
getUserId: rpcStub('getUserId'),
|
|
18
18
|
encryptData: rpcStub('encryptData'),
|
|
19
|
-
// TODO collapse these all down to just tableMethodCall
|
|
20
19
|
tableMethodCall: rpcStub('tableMethodCall'),
|
|
21
20
|
// TODO lock this down so not all code can get any file contents
|
|
22
21
|
getFileContents: rpcStub('getFileContents'),
|
|
@@ -7,6 +7,16 @@ export interface IPeerDevice {
|
|
|
7
7
|
listChanges(filter?: DataFilter<IChange>, opts?: IDataQueryParams<IChange>): Promise<IChange[]>;
|
|
8
8
|
getNetworkInfo(): Promise<INetworkInfo>;
|
|
9
9
|
notifyOfChanges(deviceId: string, timestampLastApplied: number): Promise<void>;
|
|
10
|
+
sendDeviceMessage(message: IDeviceMessage): Promise<any>;
|
|
11
|
+
}
|
|
12
|
+
export interface IDeviceMessage {
|
|
13
|
+
deviceMessageId: string;
|
|
14
|
+
fromDeviceId: string;
|
|
15
|
+
toDeviceId: string;
|
|
16
|
+
dataContextId: string;
|
|
17
|
+
ttl: number;
|
|
18
|
+
payload: any;
|
|
19
|
+
signature: string;
|
|
10
20
|
}
|
|
11
21
|
export interface INetworkInfo {
|
|
12
22
|
deviceId: string;
|