@fileverse/api 0.0.3 → 0.0.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/dist/cli/index.js +275 -83
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/index.js +1193 -602
- package/dist/commands/index.js.map +1 -1
- package/dist/index.js +3096 -2356
- package/dist/index.js.map +1 -1
- package/dist/worker.js +2731 -2139
- package/dist/worker.js.map +1 -1
- package/package.json +3 -1
package/dist/commands/index.js
CHANGED
|
@@ -1,31 +1,58 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
2
11
|
|
|
3
|
-
//
|
|
4
|
-
import { Command as Command9 } from "commander";
|
|
5
|
-
|
|
6
|
-
// src/config/index.ts
|
|
7
|
-
import dotenv from "dotenv";
|
|
12
|
+
// node_modules/tsup/assets/esm_shims.js
|
|
8
13
|
import path from "path";
|
|
9
|
-
import
|
|
10
|
-
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
15
|
+
var init_esm_shims = __esm({
|
|
16
|
+
"node_modules/tsup/assets/esm_shims.js"() {
|
|
17
|
+
"use strict";
|
|
18
|
+
}
|
|
19
|
+
});
|
|
11
20
|
|
|
12
21
|
// src/cli/constants.generated.ts
|
|
13
|
-
var STATIC_CONFIG
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
var STATIC_CONFIG;
|
|
23
|
+
var init_constants_generated = __esm({
|
|
24
|
+
"src/cli/constants.generated.ts"() {
|
|
25
|
+
"use strict";
|
|
26
|
+
init_esm_shims();
|
|
27
|
+
STATIC_CONFIG = {
|
|
28
|
+
API_URL: "https://prod-apps-storage-5cdacc06ff79.herokuapp.com/",
|
|
29
|
+
SERVER_DID: "did:key:z6Mkroj9bxTin6Z5S9qwx2G2b87NPrCX7S85FhCpmBGPcDCz",
|
|
30
|
+
PROXY_SERVER_DID: "did:key:z6MkrZSmq8D6vQG87YbjUQatXeptaCCXWdTx8fYaWxWbRUHB",
|
|
31
|
+
NETWORK_NAME: "gnosis",
|
|
32
|
+
DEFAULT_PORT: "8001",
|
|
33
|
+
DEFAULT_RPC_URL: "https://rpc.gnosischain.com",
|
|
34
|
+
PIMLICO_PROXY_URL: "https://pimlico-proxy-0a326da116f8.herokuapp.com/",
|
|
35
|
+
SERVICE_NAME: "fileverse-api",
|
|
36
|
+
LOG_LEVEL: "info",
|
|
37
|
+
FRONTEND_URL: "https://docs.fileverse.io"
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// src/cli/constants.ts
|
|
43
|
+
var init_constants = __esm({
|
|
44
|
+
"src/cli/constants.ts"() {
|
|
45
|
+
"use strict";
|
|
46
|
+
init_esm_shims();
|
|
47
|
+
init_constants_generated();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
25
50
|
|
|
26
51
|
// src/config/index.ts
|
|
27
|
-
|
|
28
|
-
|
|
52
|
+
import dotenv from "dotenv";
|
|
53
|
+
import path2 from "path";
|
|
54
|
+
import fs from "fs";
|
|
55
|
+
import os from "os";
|
|
29
56
|
function getEnvPath() {
|
|
30
57
|
if (fs.existsSync(projectEnvPath)) {
|
|
31
58
|
return projectEnvPath;
|
|
@@ -36,7 +63,6 @@ function loadConfig(override = true) {
|
|
|
36
63
|
const envPath = getEnvPath();
|
|
37
64
|
dotenv.config({ path: envPath, override });
|
|
38
65
|
}
|
|
39
|
-
loadConfig(false);
|
|
40
66
|
function getRuntimeConfig() {
|
|
41
67
|
return {
|
|
42
68
|
get API_KEY() {
|
|
@@ -48,6 +74,9 @@ function getRuntimeConfig() {
|
|
|
48
74
|
get DB_PATH() {
|
|
49
75
|
return process.env.DB_PATH;
|
|
50
76
|
},
|
|
77
|
+
get DATABASE_URL() {
|
|
78
|
+
return process.env.DATABASE_URL;
|
|
79
|
+
},
|
|
51
80
|
get PORT() {
|
|
52
81
|
return process.env.PORT || STATIC_CONFIG.DEFAULT_PORT;
|
|
53
82
|
},
|
|
@@ -59,398 +88,538 @@ function getRuntimeConfig() {
|
|
|
59
88
|
}
|
|
60
89
|
};
|
|
61
90
|
}
|
|
62
|
-
var
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
91
|
+
var projectEnvPath, userEnvPath, config;
|
|
92
|
+
var init_config = __esm({
|
|
93
|
+
"src/config/index.ts"() {
|
|
94
|
+
"use strict";
|
|
95
|
+
init_esm_shims();
|
|
96
|
+
init_constants();
|
|
97
|
+
projectEnvPath = path2.join(process.cwd(), "config", ".env");
|
|
98
|
+
userEnvPath = path2.join(os.homedir(), ".fileverse", ".env");
|
|
99
|
+
loadConfig(false);
|
|
100
|
+
config = {
|
|
101
|
+
...STATIC_CONFIG,
|
|
102
|
+
get SERVICE_NAME() {
|
|
103
|
+
return STATIC_CONFIG.SERVICE_NAME;
|
|
104
|
+
},
|
|
105
|
+
get LOG_LEVEL() {
|
|
106
|
+
return STATIC_CONFIG.LOG_LEVEL;
|
|
107
|
+
},
|
|
108
|
+
get NETWORK_NAME() {
|
|
109
|
+
return STATIC_CONFIG.NETWORK_NAME;
|
|
110
|
+
},
|
|
111
|
+
get UPLOAD_SERVER_URL() {
|
|
112
|
+
return STATIC_CONFIG.API_URL;
|
|
113
|
+
},
|
|
114
|
+
get UPLOAD_SERVER_DID() {
|
|
115
|
+
return STATIC_CONFIG.SERVER_DID;
|
|
116
|
+
},
|
|
117
|
+
get API_KEY() {
|
|
118
|
+
return process.env.API_KEY;
|
|
119
|
+
},
|
|
120
|
+
get RPC_URL() {
|
|
121
|
+
return process.env.RPC_URL || STATIC_CONFIG.DEFAULT_RPC_URL;
|
|
122
|
+
},
|
|
123
|
+
get DB_PATH() {
|
|
124
|
+
return process.env.DB_PATH;
|
|
125
|
+
},
|
|
126
|
+
get DATABASE_URL() {
|
|
127
|
+
return process.env.DATABASE_URL;
|
|
128
|
+
},
|
|
129
|
+
get PORT() {
|
|
130
|
+
return process.env.PORT || STATIC_CONFIG.DEFAULT_PORT;
|
|
131
|
+
},
|
|
132
|
+
get NODE_ENV() {
|
|
133
|
+
return process.env.NODE_ENV || "production";
|
|
134
|
+
},
|
|
135
|
+
get IP() {
|
|
136
|
+
return process.env.IP || "0.0.0.0";
|
|
137
|
+
},
|
|
138
|
+
get FRONTEND_URL() {
|
|
139
|
+
return process.env.FRONTEND_URL || STATIC_CONFIG.FRONTEND_URL;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
99
142
|
}
|
|
100
|
-
};
|
|
143
|
+
});
|
|
101
144
|
|
|
102
145
|
// src/infra/logger.ts
|
|
103
146
|
import pino from "pino";
|
|
104
|
-
var isProduction
|
|
105
|
-
var
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
147
|
+
var isProduction, pinoInstance, createLogMethod, logger;
|
|
148
|
+
var init_logger = __esm({
|
|
149
|
+
"src/infra/logger.ts"() {
|
|
150
|
+
"use strict";
|
|
151
|
+
init_esm_shims();
|
|
152
|
+
init_constants();
|
|
153
|
+
init_config();
|
|
154
|
+
isProduction = config.NODE_ENV === "production";
|
|
155
|
+
pinoInstance = pino({
|
|
156
|
+
name: STATIC_CONFIG.SERVICE_NAME,
|
|
157
|
+
level: STATIC_CONFIG.LOG_LEVEL,
|
|
158
|
+
formatters: {
|
|
159
|
+
bindings: (bindings) => ({ name: bindings.name }),
|
|
160
|
+
level: (label) => ({ level: label })
|
|
161
|
+
},
|
|
162
|
+
serializers: {
|
|
163
|
+
err(err) {
|
|
164
|
+
if (!err) return err;
|
|
165
|
+
if (isProduction) {
|
|
166
|
+
return { type: err.name, message: err.message };
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
type: err.name,
|
|
170
|
+
message: err.message,
|
|
171
|
+
stack: err.stack
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
transport: config.NODE_ENV !== "production" ? {
|
|
176
|
+
target: "pino-pretty",
|
|
177
|
+
options: {
|
|
178
|
+
colorize: true,
|
|
179
|
+
translateTime: "SYS:standard",
|
|
180
|
+
ignore: "pid,hostname",
|
|
181
|
+
errorProps: "*",
|
|
182
|
+
errorLikeObjectKeys: ["err", "error"]
|
|
183
|
+
}
|
|
184
|
+
} : void 0
|
|
185
|
+
});
|
|
186
|
+
createLogMethod = (level) => {
|
|
187
|
+
return (...args) => {
|
|
188
|
+
const [first, ...rest] = args;
|
|
189
|
+
const log = pinoInstance[level].bind(pinoInstance);
|
|
190
|
+
if (typeof first === "object" && first !== null && !(first instanceof Error)) {
|
|
191
|
+
log(first, ...rest);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (rest.length > 0) {
|
|
195
|
+
const last = rest[rest.length - 1];
|
|
196
|
+
if (last instanceof Error) {
|
|
197
|
+
log({ err: last }, first, ...rest.slice(0, -1));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (first instanceof Error) {
|
|
202
|
+
log({ err: first }, first.message);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
log(first, ...rest);
|
|
122
206
|
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
207
|
+
};
|
|
208
|
+
logger = {
|
|
209
|
+
trace: createLogMethod("trace"),
|
|
210
|
+
debug: createLogMethod("debug"),
|
|
211
|
+
info: createLogMethod("info"),
|
|
212
|
+
warn: createLogMethod("warn"),
|
|
213
|
+
error: createLogMethod("error"),
|
|
214
|
+
fatal: createLogMethod("fatal"),
|
|
215
|
+
get level() {
|
|
216
|
+
return pinoInstance.level;
|
|
217
|
+
},
|
|
218
|
+
set level(lvl) {
|
|
219
|
+
pinoInstance.level = lvl;
|
|
220
|
+
},
|
|
221
|
+
child: pinoInstance.child.bind(pinoInstance)
|
|
222
|
+
};
|
|
223
|
+
}
|
|
135
224
|
});
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
225
|
+
|
|
226
|
+
// src/infra/asyncHandler.ts
|
|
227
|
+
var init_asyncHandler = __esm({
|
|
228
|
+
"src/infra/asyncHandler.ts"() {
|
|
229
|
+
"use strict";
|
|
230
|
+
init_esm_shims();
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// src/domain/file/constants.ts
|
|
235
|
+
var DEFAULT_LIST_LIMIT;
|
|
236
|
+
var init_constants2 = __esm({
|
|
237
|
+
"src/domain/file/constants.ts"() {
|
|
238
|
+
"use strict";
|
|
239
|
+
init_esm_shims();
|
|
240
|
+
DEFAULT_LIST_LIMIT = 10;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// src/infra/database/query-builder.ts
|
|
245
|
+
var QueryBuilder;
|
|
246
|
+
var init_query_builder = __esm({
|
|
247
|
+
"src/infra/database/query-builder.ts"() {
|
|
248
|
+
"use strict";
|
|
249
|
+
init_esm_shims();
|
|
250
|
+
init_connection();
|
|
251
|
+
init_constants2();
|
|
252
|
+
QueryBuilder = class {
|
|
253
|
+
static async select(sql, params = []) {
|
|
254
|
+
const adapter2 = await getAdapter();
|
|
255
|
+
return adapter2.select(sql, params);
|
|
149
256
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
257
|
+
static async selectOne(sql, params = []) {
|
|
258
|
+
const adapter2 = await getAdapter();
|
|
259
|
+
return adapter2.selectOne(sql, params);
|
|
260
|
+
}
|
|
261
|
+
static async execute(sql, params = []) {
|
|
262
|
+
const adapter2 = await getAdapter();
|
|
263
|
+
return adapter2.execute(sql, params);
|
|
264
|
+
}
|
|
265
|
+
static async transaction(callback) {
|
|
266
|
+
const adapter2 = await getAdapter();
|
|
267
|
+
return adapter2.transaction(callback);
|
|
268
|
+
}
|
|
269
|
+
static paginate(sql, options = {}) {
|
|
270
|
+
let query = sql;
|
|
271
|
+
if (options.orderBy) {
|
|
272
|
+
query += ` ORDER BY ${options.orderBy} ${options.orderDirection || "ASC"}`;
|
|
273
|
+
}
|
|
274
|
+
const hasOffset = (options.offset ?? 0) > 0;
|
|
275
|
+
const limit = options.limit ?? (hasOffset ? DEFAULT_LIST_LIMIT : void 0);
|
|
276
|
+
if (limit) {
|
|
277
|
+
query += ` LIMIT ${limit}`;
|
|
278
|
+
}
|
|
279
|
+
if (hasOffset) {
|
|
280
|
+
query += ` OFFSET ${options.offset}`;
|
|
281
|
+
}
|
|
282
|
+
return query;
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
});
|
|
173
287
|
|
|
174
|
-
// src/infra/database/
|
|
175
|
-
|
|
288
|
+
// src/infra/database/index.ts
|
|
289
|
+
var closeDatabase;
|
|
290
|
+
var init_database = __esm({
|
|
291
|
+
"src/infra/database/index.ts"() {
|
|
292
|
+
"use strict";
|
|
293
|
+
init_esm_shims();
|
|
294
|
+
init_connection();
|
|
295
|
+
init_query_builder();
|
|
296
|
+
closeDatabase = async () => {
|
|
297
|
+
await closeAdapter();
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
});
|
|
176
301
|
|
|
177
302
|
// src/infra/database/models/files.model.ts
|
|
178
303
|
import { uuidv7 } from "uuidv7";
|
|
179
|
-
var FilesModel
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
304
|
+
var FilesModel;
|
|
305
|
+
var init_files_model = __esm({
|
|
306
|
+
"src/infra/database/models/files.model.ts"() {
|
|
307
|
+
"use strict";
|
|
308
|
+
init_esm_shims();
|
|
309
|
+
init_database();
|
|
310
|
+
FilesModel = class {
|
|
311
|
+
static TABLE = "files";
|
|
312
|
+
static parseFile(fileRaw) {
|
|
313
|
+
let metadata = {};
|
|
314
|
+
try {
|
|
315
|
+
if (fileRaw.metadata) {
|
|
316
|
+
metadata = typeof fileRaw.metadata === "string" ? JSON.parse(fileRaw.metadata) : fileRaw.metadata;
|
|
317
|
+
}
|
|
318
|
+
} catch (e) {
|
|
319
|
+
metadata = {};
|
|
320
|
+
}
|
|
321
|
+
return {
|
|
322
|
+
_id: fileRaw._id,
|
|
323
|
+
ddocId: fileRaw.ddocId,
|
|
324
|
+
title: fileRaw.title,
|
|
325
|
+
content: fileRaw.content,
|
|
326
|
+
localVersion: fileRaw.localVersion,
|
|
327
|
+
onchainVersion: fileRaw.onchainVersion,
|
|
328
|
+
syncStatus: fileRaw.syncStatus,
|
|
329
|
+
isDeleted: fileRaw.isDeleted,
|
|
330
|
+
onChainFileId: fileRaw.onChainFileId ?? null,
|
|
331
|
+
portalAddress: fileRaw.portalAddress,
|
|
332
|
+
metadata: metadata || {},
|
|
333
|
+
createdAt: fileRaw.createdAt,
|
|
334
|
+
updatedAt: fileRaw.updatedAt,
|
|
335
|
+
linkKey: fileRaw.linkKey,
|
|
336
|
+
linkKeyNonce: fileRaw.linkKeyNonce,
|
|
337
|
+
commentKey: fileRaw.commentKey,
|
|
338
|
+
link: fileRaw.link
|
|
339
|
+
};
|
|
186
340
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
title: fileRaw.title,
|
|
194
|
-
content: fileRaw.content,
|
|
195
|
-
localVersion: fileRaw.localVersion,
|
|
196
|
-
onchainVersion: fileRaw.onchainVersion,
|
|
197
|
-
syncStatus: fileRaw.syncStatus,
|
|
198
|
-
isDeleted: fileRaw.isDeleted,
|
|
199
|
-
onChainFileId: fileRaw.onChainFileId ?? null,
|
|
200
|
-
portalAddress: fileRaw.portalAddress,
|
|
201
|
-
metadata: metadata || {},
|
|
202
|
-
createdAt: fileRaw.createdAt,
|
|
203
|
-
updatedAt: fileRaw.updatedAt,
|
|
204
|
-
linkKey: fileRaw.linkKey,
|
|
205
|
-
linkKeyNonce: fileRaw.linkKeyNonce,
|
|
206
|
-
commentKey: fileRaw.commentKey,
|
|
207
|
-
link: fileRaw.link
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
static findAll(portalAddress, limit, skip) {
|
|
211
|
-
const whereClause = "isDeleted = 0 AND portalAddress = ?";
|
|
212
|
-
const params = [portalAddress];
|
|
213
|
-
const countSql = `
|
|
214
|
-
SELECT COUNT(*) as count
|
|
215
|
-
FROM ${this.TABLE}
|
|
341
|
+
static async findAll(portalAddress, limit, skip) {
|
|
342
|
+
const whereClause = "isDeleted = 0 AND portalAddress = ?";
|
|
343
|
+
const params = [portalAddress];
|
|
344
|
+
const countSql = `
|
|
345
|
+
SELECT COUNT(*) as count
|
|
346
|
+
FROM ${this.TABLE}
|
|
216
347
|
WHERE ${whereClause}
|
|
217
348
|
`;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
349
|
+
const totalResult = await QueryBuilder.selectOne(countSql, params);
|
|
350
|
+
const total = totalResult?.count || 0;
|
|
351
|
+
const sql = `
|
|
221
352
|
SELECT *
|
|
222
353
|
FROM ${this.TABLE}
|
|
223
354
|
WHERE ${whereClause}
|
|
224
355
|
`;
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
356
|
+
const completeSql = QueryBuilder.paginate(sql, {
|
|
357
|
+
limit,
|
|
358
|
+
offset: skip,
|
|
359
|
+
orderBy: "createdAt",
|
|
360
|
+
orderDirection: "DESC"
|
|
361
|
+
});
|
|
362
|
+
const filesRaw = await QueryBuilder.select(completeSql, params);
|
|
363
|
+
const files = filesRaw.map(this.parseFile);
|
|
364
|
+
const hasNext = skip !== void 0 && limit !== void 0 ? skip + limit < total : false;
|
|
365
|
+
return { files, total, hasNext };
|
|
366
|
+
}
|
|
367
|
+
static async findById(_id, portalAddress) {
|
|
368
|
+
const sql = `
|
|
238
369
|
SELECT *
|
|
239
|
-
FROM ${this.TABLE}
|
|
370
|
+
FROM ${this.TABLE}
|
|
240
371
|
WHERE _id = ? AND isDeleted = 0 AND portalAddress = ?
|
|
241
372
|
`;
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
373
|
+
const result = await QueryBuilder.selectOne(sql, [_id, portalAddress]);
|
|
374
|
+
return result ? this.parseFile(result) : void 0;
|
|
375
|
+
}
|
|
376
|
+
static async findByIdIncludingDeleted(_id) {
|
|
377
|
+
const sql = `
|
|
247
378
|
SELECT *
|
|
248
|
-
FROM ${this.TABLE}
|
|
379
|
+
FROM ${this.TABLE}
|
|
249
380
|
WHERE _id = ?
|
|
250
381
|
`;
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
382
|
+
const result = await QueryBuilder.selectOne(sql, [_id]);
|
|
383
|
+
return result ? this.parseFile(result) : void 0;
|
|
384
|
+
}
|
|
385
|
+
static async findByIdExcludingDeleted(_id) {
|
|
386
|
+
const sql = `
|
|
256
387
|
SELECT *
|
|
257
|
-
FROM ${this.TABLE}
|
|
388
|
+
FROM ${this.TABLE}
|
|
258
389
|
WHERE _id = ? AND isDeleted = 0
|
|
259
390
|
`;
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
391
|
+
const result = await QueryBuilder.selectOne(sql, [_id]);
|
|
392
|
+
return result ? this.parseFile(result) : void 0;
|
|
393
|
+
}
|
|
394
|
+
static async findByDDocId(ddocId, portalAddress) {
|
|
395
|
+
const sql = `
|
|
265
396
|
SELECT *
|
|
266
|
-
FROM ${this.TABLE}
|
|
397
|
+
FROM ${this.TABLE}
|
|
267
398
|
WHERE ddocId = ? AND isDeleted = 0 AND portalAddress = ?
|
|
268
399
|
`;
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
400
|
+
const result = await QueryBuilder.selectOne(sql, [ddocId, portalAddress]);
|
|
401
|
+
return result ? this.parseFile(result) : void 0;
|
|
402
|
+
}
|
|
403
|
+
static async searchByTitle(searchTerm, portalAddress, limit, skip) {
|
|
404
|
+
const sql = `
|
|
274
405
|
SELECT *
|
|
275
|
-
FROM ${this.TABLE}
|
|
406
|
+
FROM ${this.TABLE}
|
|
276
407
|
WHERE LOWER(title) LIKE LOWER(?) AND isDeleted = 0 AND portalAddress = ?
|
|
277
408
|
`;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
INSERT INTO ${this.TABLE}
|
|
291
|
-
(_id, title, content, ddocId, portalAddress)
|
|
409
|
+
const completeSql = QueryBuilder.paginate(sql, {
|
|
410
|
+
limit,
|
|
411
|
+
offset: skip,
|
|
412
|
+
orderBy: "createdAt",
|
|
413
|
+
orderDirection: "DESC"
|
|
414
|
+
});
|
|
415
|
+
const filesRaw = await QueryBuilder.select(completeSql, [`%${searchTerm}%`, portalAddress]);
|
|
416
|
+
return filesRaw.map(this.parseFile);
|
|
417
|
+
}
|
|
418
|
+
static async create(input) {
|
|
419
|
+
const _id = uuidv7();
|
|
420
|
+
const sql = `
|
|
421
|
+
INSERT INTO ${this.TABLE}
|
|
422
|
+
(_id, title, content, ddocId, portalAddress)
|
|
292
423
|
VALUES (?, ?, ?, ?, ?)
|
|
293
424
|
`;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
return created;
|
|
300
|
-
}
|
|
301
|
-
static update(_id, payload, portalAddress) {
|
|
302
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
303
|
-
const keys = [];
|
|
304
|
-
const values = [];
|
|
305
|
-
for (const [k, v] of Object.entries(payload)) {
|
|
306
|
-
if (v !== void 0) {
|
|
307
|
-
if (k === "metadata" && typeof v === "object") {
|
|
308
|
-
keys.push(`${k} = ?`);
|
|
309
|
-
values.push(JSON.stringify(v));
|
|
310
|
-
} else {
|
|
311
|
-
keys.push(`${k} = ?`);
|
|
312
|
-
values.push(v);
|
|
425
|
+
await QueryBuilder.execute(sql, [_id, input.title, input.content, input.ddocId, input.portalAddress]);
|
|
426
|
+
const created = await this.findById(_id, input.portalAddress);
|
|
427
|
+
if (!created) {
|
|
428
|
+
throw new Error("Failed to create file");
|
|
313
429
|
}
|
|
430
|
+
return created;
|
|
314
431
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
432
|
+
static async update(_id, payload, portalAddress) {
|
|
433
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
434
|
+
const keys = [];
|
|
435
|
+
const values = [];
|
|
436
|
+
for (const [k, v] of Object.entries(payload)) {
|
|
437
|
+
if (v !== void 0) {
|
|
438
|
+
if (k === "metadata" && typeof v === "object") {
|
|
439
|
+
keys.push(`${k} = ?`);
|
|
440
|
+
values.push(JSON.stringify(v));
|
|
441
|
+
} else {
|
|
442
|
+
keys.push(`${k} = ?`);
|
|
443
|
+
values.push(v);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
keys.push("updatedAt = ?");
|
|
448
|
+
values.push(now, _id, portalAddress);
|
|
449
|
+
const updateChain = keys.join(", ");
|
|
450
|
+
const sql = `UPDATE ${this.TABLE} SET ${updateChain} WHERE _id = ? AND portalAddress = ?`;
|
|
451
|
+
await QueryBuilder.execute(sql, values);
|
|
452
|
+
const updated = await this.findById(_id, portalAddress);
|
|
453
|
+
if (!updated) {
|
|
454
|
+
throw new Error("Failed to update file");
|
|
455
|
+
}
|
|
456
|
+
return updated;
|
|
457
|
+
}
|
|
458
|
+
static async softDelete(_id) {
|
|
459
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
460
|
+
const sql = `
|
|
461
|
+
UPDATE ${this.TABLE}
|
|
331
462
|
SET isDeleted = 1, syncStatus = 'pending', updatedAt = ?
|
|
332
463
|
WHERE _id = ?
|
|
333
464
|
`;
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
465
|
+
await QueryBuilder.execute(sql, [now, _id]);
|
|
466
|
+
const deleted = await this.findByIdIncludingDeleted(_id);
|
|
467
|
+
if (!deleted) {
|
|
468
|
+
throw new Error("Failed to delete file");
|
|
469
|
+
}
|
|
470
|
+
return deleted;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
340
473
|
}
|
|
341
|
-
};
|
|
474
|
+
});
|
|
342
475
|
|
|
343
476
|
// src/infra/database/models/portals.model.ts
|
|
344
477
|
import { uuidv7 as uuidv72 } from "uuidv7";
|
|
478
|
+
var init_portals_model = __esm({
|
|
479
|
+
"src/infra/database/models/portals.model.ts"() {
|
|
480
|
+
"use strict";
|
|
481
|
+
init_esm_shims();
|
|
482
|
+
init_database();
|
|
483
|
+
}
|
|
484
|
+
});
|
|
345
485
|
|
|
346
486
|
// src/infra/database/models/apikeys.model.ts
|
|
347
487
|
import { uuidv7 as uuidv73 } from "uuidv7";
|
|
348
|
-
var ApiKeysModel
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
488
|
+
var ApiKeysModel;
|
|
489
|
+
var init_apikeys_model = __esm({
|
|
490
|
+
"src/infra/database/models/apikeys.model.ts"() {
|
|
491
|
+
"use strict";
|
|
492
|
+
init_esm_shims();
|
|
493
|
+
init_database();
|
|
494
|
+
ApiKeysModel = class {
|
|
495
|
+
static TABLE = "api_keys";
|
|
496
|
+
static async create(input) {
|
|
497
|
+
const _id = uuidv73();
|
|
498
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
499
|
+
const sql = `INSERT INTO ${this.TABLE} (_id, apiKeySeed, name, collaboratorAddress, portalAddress, createdAt)
|
|
354
500
|
VALUES (?, ?, ?, ?, ?, ?)`;
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
501
|
+
const result = await QueryBuilder.execute(sql, [
|
|
502
|
+
_id,
|
|
503
|
+
input.apiKeySeed,
|
|
504
|
+
input.name,
|
|
505
|
+
input.collaboratorAddress,
|
|
506
|
+
input.portalAddress,
|
|
507
|
+
now
|
|
508
|
+
]);
|
|
509
|
+
if (result.changes === 0) {
|
|
510
|
+
throw new Error("Failed to create API key");
|
|
511
|
+
}
|
|
512
|
+
const created = await this.findById(_id);
|
|
513
|
+
if (!created) {
|
|
514
|
+
throw new Error("Failed to create API key");
|
|
515
|
+
}
|
|
516
|
+
return created;
|
|
517
|
+
}
|
|
518
|
+
static async findById(_id) {
|
|
519
|
+
const sql = `SELECT _id, apiKeySeed, name, collaboratorAddress, portalAddress, createdAt, isDeleted FROM ${this.TABLE} WHERE _id = ? AND isDeleted = 0`;
|
|
520
|
+
return QueryBuilder.selectOne(sql, [_id]);
|
|
521
|
+
}
|
|
522
|
+
static async findByCollaboratorAddress(collaboratorAddress) {
|
|
523
|
+
const sql = `SELECT _id, apiKeySeed, name, collaboratorAddress, portalAddress, createdAt, isDeleted FROM ${this.TABLE} WHERE collaboratorAddress = ? AND isDeleted = 0 LIMIT 1`;
|
|
524
|
+
return QueryBuilder.selectOne(sql, [collaboratorAddress]);
|
|
525
|
+
}
|
|
526
|
+
static async delete(_id) {
|
|
527
|
+
const sql = `UPDATE ${this.TABLE} SET isDeleted = 1 WHERE _id = ?`;
|
|
528
|
+
await QueryBuilder.execute(sql, [_id]);
|
|
529
|
+
}
|
|
530
|
+
static async findByPortalAddress(portalAddress) {
|
|
531
|
+
const sql = `SELECT _id, apiKeySeed, name, collaboratorAddress, portalAddress, createdAt, isDeleted FROM ${this.TABLE} WHERE portalAddress = ? AND isDeleted = 0`;
|
|
532
|
+
return QueryBuilder.selectOne(sql, [portalAddress]);
|
|
533
|
+
}
|
|
534
|
+
static async findByApiKey(apiKey) {
|
|
535
|
+
const sql = `SELECT _id, apiKeySeed, name, collaboratorAddress, portalAddress, createdAt, isDeleted FROM ${this.TABLE} WHERE apiKeySeed = ? AND isDeleted = 0`;
|
|
536
|
+
return QueryBuilder.selectOne(sql, [apiKey]);
|
|
537
|
+
}
|
|
538
|
+
};
|
|
391
539
|
}
|
|
392
|
-
};
|
|
540
|
+
});
|
|
393
541
|
|
|
394
|
-
// src/infra/database/models/
|
|
395
|
-
|
|
542
|
+
// src/infra/database/models/folders.model.ts
|
|
543
|
+
var init_folders_model = __esm({
|
|
544
|
+
"src/infra/database/models/folders.model.ts"() {
|
|
545
|
+
"use strict";
|
|
546
|
+
init_esm_shims();
|
|
547
|
+
init_database();
|
|
548
|
+
}
|
|
549
|
+
});
|
|
396
550
|
|
|
397
551
|
// src/infra/worker/workerSignal.ts
|
|
398
552
|
import { EventEmitter } from "events";
|
|
399
|
-
var WorkerSignal = class extends EventEmitter {
|
|
400
|
-
};
|
|
401
|
-
var workerSignal = new WorkerSignal();
|
|
402
|
-
workerSignal.setMaxListeners(20);
|
|
403
553
|
function notifyNewEvent() {
|
|
404
554
|
workerSignal.emit("newEvent");
|
|
405
555
|
}
|
|
556
|
+
var WorkerSignal, workerSignal;
|
|
557
|
+
var init_workerSignal = __esm({
|
|
558
|
+
"src/infra/worker/workerSignal.ts"() {
|
|
559
|
+
"use strict";
|
|
560
|
+
init_esm_shims();
|
|
561
|
+
WorkerSignal = class extends EventEmitter {
|
|
562
|
+
};
|
|
563
|
+
workerSignal = new WorkerSignal();
|
|
564
|
+
workerSignal.setMaxListeners(20);
|
|
565
|
+
}
|
|
566
|
+
});
|
|
406
567
|
|
|
407
568
|
// src/infra/database/models/events.model.ts
|
|
408
|
-
|
|
409
|
-
var EventsModel
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
569
|
+
import { uuidv7 as uuidv74 } from "uuidv7";
|
|
570
|
+
var RETRY_DELAYS_MS, EventsModel;
|
|
571
|
+
var init_events_model = __esm({
|
|
572
|
+
"src/infra/database/models/events.model.ts"() {
|
|
573
|
+
"use strict";
|
|
574
|
+
init_esm_shims();
|
|
575
|
+
init_database();
|
|
576
|
+
init_workerSignal();
|
|
577
|
+
RETRY_DELAYS_MS = [5e3, 3e4, 12e4];
|
|
578
|
+
EventsModel = class {
|
|
579
|
+
static TABLE = "events";
|
|
580
|
+
static async create(input) {
|
|
581
|
+
const _id = uuidv74();
|
|
582
|
+
const timestamp = Date.now();
|
|
583
|
+
const status = "pending";
|
|
584
|
+
const sql = `
|
|
585
|
+
INSERT INTO ${this.TABLE}
|
|
586
|
+
(_id, type, timestamp, fileId, portalAddress, status, retryCount, lastError, lockedAt, nextRetryAt)
|
|
418
587
|
VALUES (?, ?, ?, ?, ?, ?, 0, NULL, NULL, NULL)
|
|
419
588
|
`;
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
589
|
+
await QueryBuilder.execute(sql, [_id, input.type, timestamp, input.fileId, input.portalAddress, status]);
|
|
590
|
+
notifyNewEvent();
|
|
591
|
+
return {
|
|
592
|
+
_id,
|
|
593
|
+
type: input.type,
|
|
594
|
+
timestamp,
|
|
595
|
+
fileId: input.fileId,
|
|
596
|
+
portalAddress: input.portalAddress,
|
|
597
|
+
status,
|
|
598
|
+
retryCount: 0,
|
|
599
|
+
lastError: null,
|
|
600
|
+
lockedAt: null,
|
|
601
|
+
nextRetryAt: null
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
static async findById(_id) {
|
|
605
|
+
const sql = `SELECT * FROM ${this.TABLE} WHERE _id = ?`;
|
|
606
|
+
const row = await QueryBuilder.selectOne(sql, [_id]);
|
|
607
|
+
return row ? this.parseEvent(row) : void 0;
|
|
608
|
+
}
|
|
609
|
+
static async findNextPending() {
|
|
610
|
+
const sql = `
|
|
442
611
|
SELECT * FROM ${this.TABLE}
|
|
443
612
|
WHERE status = 'pending'
|
|
444
613
|
ORDER BY timestamp ASC
|
|
445
614
|
LIMIT 1
|
|
446
615
|
`;
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
616
|
+
const row = await QueryBuilder.selectOne(sql, []);
|
|
617
|
+
return row ? this.parseEvent(row) : void 0;
|
|
618
|
+
}
|
|
619
|
+
static async findNextEligible(lockedFileIds) {
|
|
620
|
+
const now = Date.now();
|
|
621
|
+
const exclusionClause = lockedFileIds.length > 0 ? `AND e1.fileId NOT IN (${lockedFileIds.map(() => "?").join(", ")})` : "";
|
|
622
|
+
const sql = `
|
|
454
623
|
SELECT e1.* FROM ${this.TABLE} e1
|
|
455
624
|
WHERE e1.status = 'pending'
|
|
456
625
|
AND (e1.nextRetryAt IS NULL OR e1.nextRetryAt <= ?)
|
|
@@ -464,34 +633,34 @@ var EventsModel = class {
|
|
|
464
633
|
ORDER BY e1.timestamp ASC
|
|
465
634
|
LIMIT 1
|
|
466
635
|
`;
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
636
|
+
const params = [now, ...lockedFileIds];
|
|
637
|
+
const row = await QueryBuilder.selectOne(sql, params);
|
|
638
|
+
return row ? this.parseEvent(row) : void 0;
|
|
639
|
+
}
|
|
640
|
+
static async markProcessing(_id) {
|
|
641
|
+
const sql = `
|
|
473
642
|
UPDATE ${this.TABLE}
|
|
474
643
|
SET status = 'processing',
|
|
475
644
|
lockedAt = ?
|
|
476
645
|
WHERE _id = ?
|
|
477
646
|
`;
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
647
|
+
await QueryBuilder.execute(sql, [Date.now(), _id]);
|
|
648
|
+
}
|
|
649
|
+
static async markProcessed(_id) {
|
|
650
|
+
const sql = `
|
|
482
651
|
UPDATE ${this.TABLE}
|
|
483
652
|
SET status = 'processed',
|
|
484
653
|
lockedAt = NULL
|
|
485
654
|
WHERE _id = ?
|
|
486
655
|
`;
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
656
|
+
await QueryBuilder.execute(sql, [_id]);
|
|
657
|
+
}
|
|
658
|
+
static async scheduleRetry(_id, errorMsg) {
|
|
659
|
+
const event = await this.findById(_id);
|
|
660
|
+
if (!event) return;
|
|
661
|
+
const delay = RETRY_DELAYS_MS[Math.min(event.retryCount, RETRY_DELAYS_MS.length - 1)];
|
|
662
|
+
const nextRetryAt = Date.now() + delay;
|
|
663
|
+
const sql = `
|
|
495
664
|
UPDATE ${this.TABLE}
|
|
496
665
|
SET status = 'pending',
|
|
497
666
|
retryCount = retryCount + 1,
|
|
@@ -500,11 +669,11 @@ var EventsModel = class {
|
|
|
500
669
|
lockedAt = NULL
|
|
501
670
|
WHERE _id = ?
|
|
502
671
|
`;
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
672
|
+
await QueryBuilder.execute(sql, [errorMsg, nextRetryAt, _id]);
|
|
673
|
+
}
|
|
674
|
+
static async scheduleRetryAfter(_id, errorMsg, retryAfterMs) {
|
|
675
|
+
const nextRetryAt = Date.now() + retryAfterMs;
|
|
676
|
+
const sql = `
|
|
508
677
|
UPDATE ${this.TABLE}
|
|
509
678
|
SET status = 'pending',
|
|
510
679
|
lastError = ?,
|
|
@@ -512,33 +681,33 @@ var EventsModel = class {
|
|
|
512
681
|
lockedAt = NULL
|
|
513
682
|
WHERE _id = ?
|
|
514
683
|
`;
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
684
|
+
await QueryBuilder.execute(sql, [errorMsg, nextRetryAt, _id]);
|
|
685
|
+
}
|
|
686
|
+
static async markFailed(_id, errorMsg) {
|
|
687
|
+
const sql = `
|
|
519
688
|
UPDATE ${this.TABLE}
|
|
520
689
|
SET status = 'failed',
|
|
521
690
|
lastError = ?,
|
|
522
691
|
lockedAt = NULL
|
|
523
692
|
WHERE _id = ?
|
|
524
693
|
`;
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
694
|
+
await QueryBuilder.execute(sql, [errorMsg, _id]);
|
|
695
|
+
}
|
|
696
|
+
static async listFailed(portalAddress) {
|
|
697
|
+
const portalClause = portalAddress != null ? "AND portalAddress = ?" : "";
|
|
698
|
+
const sql = `
|
|
530
699
|
SELECT * FROM ${this.TABLE}
|
|
531
700
|
WHERE status = 'failed'
|
|
532
701
|
${portalClause}
|
|
533
702
|
ORDER BY timestamp ASC
|
|
534
703
|
`;
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
704
|
+
const params = portalAddress != null ? [portalAddress] : [];
|
|
705
|
+
const rows = await QueryBuilder.select(sql, params);
|
|
706
|
+
return rows.map((row) => this.parseEvent(row));
|
|
707
|
+
}
|
|
708
|
+
static async resetFailedToPending(_id, portalAddress) {
|
|
709
|
+
const portalClause = portalAddress != null ? "AND portalAddress = ?" : "";
|
|
710
|
+
const sql = `
|
|
542
711
|
UPDATE ${this.TABLE}
|
|
543
712
|
SET status = 'pending',
|
|
544
713
|
retryCount = 0,
|
|
@@ -549,16 +718,16 @@ var EventsModel = class {
|
|
|
549
718
|
AND status = 'failed'
|
|
550
719
|
${portalClause}
|
|
551
720
|
`;
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
721
|
+
const params = portalAddress != null ? [_id, portalAddress] : [_id];
|
|
722
|
+
const result = await QueryBuilder.execute(sql, params);
|
|
723
|
+
if (result.changes > 0) {
|
|
724
|
+
notifyNewEvent();
|
|
725
|
+
}
|
|
726
|
+
return result.changes > 0;
|
|
727
|
+
}
|
|
728
|
+
static async resetAllFailedToPending(portalAddress) {
|
|
729
|
+
const portalClause = portalAddress != null ? "AND portalAddress = ?" : "";
|
|
730
|
+
const sql = `
|
|
562
731
|
UPDATE ${this.TABLE}
|
|
563
732
|
SET status = 'pending',
|
|
564
733
|
retryCount = 0,
|
|
@@ -568,15 +737,15 @@ var EventsModel = class {
|
|
|
568
737
|
WHERE status = 'failed'
|
|
569
738
|
${portalClause}
|
|
570
739
|
`;
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
740
|
+
const params = portalAddress != null ? [portalAddress] : [];
|
|
741
|
+
const result = await QueryBuilder.execute(sql, params);
|
|
742
|
+
if (result.changes > 0) {
|
|
743
|
+
notifyNewEvent();
|
|
744
|
+
}
|
|
745
|
+
return result.changes;
|
|
746
|
+
}
|
|
747
|
+
static async resetStaleEvents(staleThreshold) {
|
|
748
|
+
const sql = `
|
|
580
749
|
UPDATE ${this.TABLE}
|
|
581
750
|
SET status = 'pending',
|
|
582
751
|
lockedAt = NULL,
|
|
@@ -586,51 +755,113 @@ var EventsModel = class {
|
|
|
586
755
|
AND lockedAt IS NOT NULL
|
|
587
756
|
AND lockedAt < ?
|
|
588
757
|
`;
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
758
|
+
const result = await QueryBuilder.execute(sql, [staleThreshold]);
|
|
759
|
+
return result.changes;
|
|
760
|
+
}
|
|
761
|
+
static async setEventPendingOp(_id, userOpHash, payload) {
|
|
762
|
+
const sql = `UPDATE ${this.TABLE} SET userOpHash = ?, pendingPayload = ? WHERE _id = ?`;
|
|
763
|
+
await QueryBuilder.execute(sql, [userOpHash, JSON.stringify(payload), _id]);
|
|
764
|
+
}
|
|
765
|
+
static async clearEventPendingOp(_id) {
|
|
766
|
+
const sql = `UPDATE ${this.TABLE} SET userOpHash = NULL, pendingPayload = NULL WHERE _id = ?`;
|
|
767
|
+
await QueryBuilder.execute(sql, [_id]);
|
|
768
|
+
}
|
|
769
|
+
static parseEvent(row) {
|
|
770
|
+
return {
|
|
771
|
+
_id: row._id,
|
|
772
|
+
type: row.type,
|
|
773
|
+
timestamp: row.timestamp,
|
|
774
|
+
fileId: row.fileId,
|
|
775
|
+
portalAddress: row.portalAddress ?? "",
|
|
776
|
+
status: row.status,
|
|
777
|
+
retryCount: row.retryCount,
|
|
778
|
+
lastError: row.lastError,
|
|
779
|
+
lockedAt: row.lockedAt,
|
|
780
|
+
nextRetryAt: row.nextRetryAt,
|
|
781
|
+
userOpHash: row.userOpHash ?? null,
|
|
782
|
+
pendingPayload: row.pendingPayload ?? null
|
|
783
|
+
};
|
|
784
|
+
}
|
|
614
785
|
};
|
|
615
786
|
}
|
|
616
|
-
};
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
// src/infra/database/models/index.ts
|
|
790
|
+
var init_models = __esm({
|
|
791
|
+
"src/infra/database/models/index.ts"() {
|
|
792
|
+
"use strict";
|
|
793
|
+
init_esm_shims();
|
|
794
|
+
init_files_model();
|
|
795
|
+
init_portals_model();
|
|
796
|
+
init_apikeys_model();
|
|
797
|
+
init_folders_model();
|
|
798
|
+
init_events_model();
|
|
799
|
+
}
|
|
800
|
+
});
|
|
617
801
|
|
|
618
802
|
// src/sdk/key-store.ts
|
|
619
803
|
import { eciesDecrypt, eciesEncrypt, generateECKeyPair } from "@fileverse/crypto/ecies";
|
|
804
|
+
var init_key_store = __esm({
|
|
805
|
+
"src/sdk/key-store.ts"() {
|
|
806
|
+
"use strict";
|
|
807
|
+
init_esm_shims();
|
|
808
|
+
}
|
|
809
|
+
});
|
|
620
810
|
|
|
621
811
|
// src/sdk/auth-token-provider.ts
|
|
622
812
|
import * as ucans from "@ucans/ucans";
|
|
813
|
+
var init_auth_token_provider = __esm({
|
|
814
|
+
"src/sdk/auth-token-provider.ts"() {
|
|
815
|
+
"use strict";
|
|
816
|
+
init_esm_shims();
|
|
817
|
+
}
|
|
818
|
+
});
|
|
623
819
|
|
|
624
|
-
// src/
|
|
625
|
-
import {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
820
|
+
// src/constants/chains.ts
|
|
821
|
+
import { sepolia, gnosis } from "viem/chains";
|
|
822
|
+
var init_chains = __esm({
|
|
823
|
+
"src/constants/chains.ts"() {
|
|
824
|
+
"use strict";
|
|
825
|
+
init_esm_shims();
|
|
826
|
+
}
|
|
827
|
+
});
|
|
630
828
|
|
|
631
|
-
// src/
|
|
632
|
-
|
|
633
|
-
|
|
829
|
+
// src/constants/events.ts
|
|
830
|
+
var init_events = __esm({
|
|
831
|
+
"src/constants/events.ts"() {
|
|
832
|
+
"use strict";
|
|
833
|
+
init_esm_shims();
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
// src/constants/methods.ts
|
|
838
|
+
var init_methods = __esm({
|
|
839
|
+
"src/constants/methods.ts"() {
|
|
840
|
+
"use strict";
|
|
841
|
+
init_esm_shims();
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
// src/constants/index.ts
|
|
846
|
+
var NETWORK_NAME, UPLOAD_SERVER_URL, CHAIN_MAP, CHAIN;
|
|
847
|
+
var init_constants3 = __esm({
|
|
848
|
+
"src/constants/index.ts"() {
|
|
849
|
+
"use strict";
|
|
850
|
+
init_esm_shims();
|
|
851
|
+
init_constants();
|
|
852
|
+
init_config();
|
|
853
|
+
init_chains();
|
|
854
|
+
init_events();
|
|
855
|
+
init_methods();
|
|
856
|
+
NETWORK_NAME = STATIC_CONFIG.NETWORK_NAME;
|
|
857
|
+
UPLOAD_SERVER_URL = STATIC_CONFIG.API_URL;
|
|
858
|
+
CHAIN_MAP = {
|
|
859
|
+
gnosis,
|
|
860
|
+
sepolia
|
|
861
|
+
};
|
|
862
|
+
CHAIN = CHAIN_MAP[NETWORK_NAME];
|
|
863
|
+
}
|
|
864
|
+
});
|
|
634
865
|
|
|
635
866
|
// src/sdk/pimlico-utils.ts
|
|
636
867
|
import { createPublicClient, http, hexToBigInt, toHex, toBytes } from "viem";
|
|
@@ -638,24 +869,35 @@ import { createPimlicoClient } from "permissionless/clients/pimlico";
|
|
|
638
869
|
import { createSmartAccountClient } from "permissionless";
|
|
639
870
|
import { toSafeSmartAccount } from "permissionless/accounts";
|
|
640
871
|
import { entryPoint07Address } from "viem/account-abstraction";
|
|
641
|
-
|
|
642
|
-
// src/constants/chains.ts
|
|
643
|
-
import { sepolia, gnosis } from "viem/chains";
|
|
644
|
-
|
|
645
|
-
// src/constants/index.ts
|
|
646
|
-
var NETWORK_NAME = STATIC_CONFIG.NETWORK_NAME;
|
|
647
|
-
var UPLOAD_SERVER_URL = STATIC_CONFIG.API_URL;
|
|
648
|
-
var CHAIN_MAP = {
|
|
649
|
-
gnosis,
|
|
650
|
-
sepolia
|
|
651
|
-
};
|
|
652
|
-
var CHAIN = CHAIN_MAP[NETWORK_NAME];
|
|
653
|
-
|
|
654
|
-
// src/sdk/pimlico-utils.ts
|
|
655
872
|
import { generatePrivateKey } from "viem/accounts";
|
|
873
|
+
var init_pimlico_utils = __esm({
|
|
874
|
+
"src/sdk/pimlico-utils.ts"() {
|
|
875
|
+
"use strict";
|
|
876
|
+
init_esm_shims();
|
|
877
|
+
init_constants3();
|
|
878
|
+
}
|
|
879
|
+
});
|
|
656
880
|
|
|
657
|
-
// src/sdk/
|
|
658
|
-
import {
|
|
881
|
+
// src/sdk/smart-agent.ts
|
|
882
|
+
import { toHex as toHex2 } from "viem";
|
|
883
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
884
|
+
var init_smart_agent = __esm({
|
|
885
|
+
"src/sdk/smart-agent.ts"() {
|
|
886
|
+
"use strict";
|
|
887
|
+
init_esm_shims();
|
|
888
|
+
init_pimlico_utils();
|
|
889
|
+
init_constants();
|
|
890
|
+
}
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
// src/sdk/file-encryption.ts
|
|
894
|
+
import { generateRandomBytes } from "@fileverse/crypto/utils";
|
|
895
|
+
var init_file_encryption = __esm({
|
|
896
|
+
"src/sdk/file-encryption.ts"() {
|
|
897
|
+
"use strict";
|
|
898
|
+
init_esm_shims();
|
|
899
|
+
}
|
|
900
|
+
});
|
|
659
901
|
|
|
660
902
|
// src/sdk/file-utils.ts
|
|
661
903
|
import { getArgon2idHash } from "@fileverse/crypto/argon";
|
|
@@ -665,134 +907,448 @@ import { secretBoxEncrypt } from "@fileverse/crypto/nacl";
|
|
|
665
907
|
import hkdf from "futoin-hkdf";
|
|
666
908
|
import tweetnacl from "tweetnacl";
|
|
667
909
|
import { fromUint8Array, toUint8Array } from "js-base64";
|
|
668
|
-
|
|
669
|
-
// src/sdk/file-encryption.ts
|
|
670
|
-
import { generateRandomBytes } from "@fileverse/crypto/utils";
|
|
671
|
-
|
|
672
|
-
// src/sdk/file-utils.ts
|
|
673
910
|
import { toAESKey, aesEncrypt } from "@fileverse/crypto/webcrypto";
|
|
674
911
|
import axios from "axios";
|
|
675
912
|
import { encodeFunctionData, parseEventLogs } from "viem";
|
|
913
|
+
var init_file_utils = __esm({
|
|
914
|
+
"src/sdk/file-utils.ts"() {
|
|
915
|
+
"use strict";
|
|
916
|
+
init_esm_shims();
|
|
917
|
+
init_file_encryption();
|
|
918
|
+
init_constants3();
|
|
919
|
+
}
|
|
920
|
+
});
|
|
676
921
|
|
|
677
922
|
// src/sdk/file-manager.ts
|
|
923
|
+
import { fromUint8Array as fromUint8Array2, toUint8Array as toUint8Array2 } from "js-base64";
|
|
678
924
|
import { generateAESKey, exportAESKey } from "@fileverse/crypto/webcrypto";
|
|
679
925
|
import { markdownToYjs } from "@fileverse/content-processor";
|
|
926
|
+
var init_file_manager = __esm({
|
|
927
|
+
"src/sdk/file-manager.ts"() {
|
|
928
|
+
"use strict";
|
|
929
|
+
init_esm_shims();
|
|
930
|
+
init_file_utils();
|
|
931
|
+
init_constants();
|
|
932
|
+
init_constants3();
|
|
933
|
+
init_infra();
|
|
934
|
+
}
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
// src/domain/portal/publish.ts
|
|
938
|
+
import { fromUint8Array as fromUint8Array3, toUint8Array as toUint8Array3 } from "js-base64";
|
|
939
|
+
import { stringToBytes } from "viem";
|
|
940
|
+
import { deriveHKDFKey } from "@fileverse/crypto/kdf";
|
|
941
|
+
import { generateKeyPairFromSeed } from "@stablelib/ed25519";
|
|
942
|
+
import * as ucans2 from "@ucans/ucans";
|
|
943
|
+
var init_publish = __esm({
|
|
944
|
+
"src/domain/portal/publish.ts"() {
|
|
945
|
+
"use strict";
|
|
946
|
+
init_esm_shims();
|
|
947
|
+
init_models();
|
|
948
|
+
init_infra();
|
|
949
|
+
init_key_store();
|
|
950
|
+
init_auth_token_provider();
|
|
951
|
+
init_smart_agent();
|
|
952
|
+
init_file_manager();
|
|
953
|
+
init_config();
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
// src/domain/portal/savePortal.ts
|
|
958
|
+
var init_savePortal = __esm({
|
|
959
|
+
"src/domain/portal/savePortal.ts"() {
|
|
960
|
+
"use strict";
|
|
961
|
+
init_esm_shims();
|
|
962
|
+
init_models();
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
// src/domain/portal/saveApiKey.ts
|
|
967
|
+
var init_saveApiKey = __esm({
|
|
968
|
+
"src/domain/portal/saveApiKey.ts"() {
|
|
969
|
+
"use strict";
|
|
970
|
+
init_esm_shims();
|
|
971
|
+
init_models();
|
|
972
|
+
}
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
// src/domain/portal/removeApiKey.ts
|
|
976
|
+
var init_removeApiKey = __esm({
|
|
977
|
+
"src/domain/portal/removeApiKey.ts"() {
|
|
978
|
+
"use strict";
|
|
979
|
+
init_esm_shims();
|
|
980
|
+
init_models();
|
|
981
|
+
}
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
// src/domain/portal/index.ts
|
|
985
|
+
var init_portal = __esm({
|
|
986
|
+
"src/domain/portal/index.ts"() {
|
|
987
|
+
"use strict";
|
|
988
|
+
init_esm_shims();
|
|
989
|
+
init_publish();
|
|
990
|
+
init_savePortal();
|
|
991
|
+
init_saveApiKey();
|
|
992
|
+
init_removeApiKey();
|
|
993
|
+
}
|
|
994
|
+
});
|
|
680
995
|
|
|
681
996
|
// src/errors/rate-limit.ts
|
|
682
997
|
import { HttpRequestError } from "viem";
|
|
998
|
+
var init_rate_limit = __esm({
|
|
999
|
+
"src/errors/rate-limit.ts"() {
|
|
1000
|
+
"use strict";
|
|
1001
|
+
init_esm_shims();
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
1004
|
+
|
|
1005
|
+
// src/infra/worker/eventProcessor.ts
|
|
1006
|
+
var init_eventProcessor = __esm({
|
|
1007
|
+
"src/infra/worker/eventProcessor.ts"() {
|
|
1008
|
+
"use strict";
|
|
1009
|
+
init_esm_shims();
|
|
1010
|
+
init_config();
|
|
1011
|
+
init_portal();
|
|
1012
|
+
init_models();
|
|
1013
|
+
init_infra();
|
|
1014
|
+
init_pimlico_utils();
|
|
1015
|
+
init_file_utils();
|
|
1016
|
+
init_constants3();
|
|
1017
|
+
init_rate_limit();
|
|
1018
|
+
}
|
|
1019
|
+
});
|
|
683
1020
|
|
|
684
1021
|
// src/infra/worker/worker.ts
|
|
685
|
-
var STALE_THRESHOLD_MS
|
|
1022
|
+
var STALE_THRESHOLD_MS;
|
|
1023
|
+
var init_worker = __esm({
|
|
1024
|
+
"src/infra/worker/worker.ts"() {
|
|
1025
|
+
"use strict";
|
|
1026
|
+
init_esm_shims();
|
|
1027
|
+
init_infra();
|
|
1028
|
+
init_eventProcessor();
|
|
1029
|
+
init_workerSignal();
|
|
1030
|
+
init_models();
|
|
1031
|
+
init_rate_limit();
|
|
1032
|
+
STALE_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
// src/infra/worker/index.ts
|
|
1037
|
+
var init_worker2 = __esm({
|
|
1038
|
+
"src/infra/worker/index.ts"() {
|
|
1039
|
+
"use strict";
|
|
1040
|
+
init_esm_shims();
|
|
1041
|
+
init_worker();
|
|
1042
|
+
init_workerSignal();
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
686
1045
|
|
|
687
1046
|
// src/appWorker.ts
|
|
688
|
-
var worker = null;
|
|
689
1047
|
async function closeWorker() {
|
|
690
1048
|
if (worker) {
|
|
691
1049
|
await worker.close();
|
|
692
1050
|
worker = null;
|
|
693
1051
|
}
|
|
694
1052
|
}
|
|
1053
|
+
var worker;
|
|
1054
|
+
var init_appWorker = __esm({
|
|
1055
|
+
"src/appWorker.ts"() {
|
|
1056
|
+
"use strict";
|
|
1057
|
+
init_esm_shims();
|
|
1058
|
+
init_worker2();
|
|
1059
|
+
worker = null;
|
|
1060
|
+
}
|
|
1061
|
+
});
|
|
695
1062
|
|
|
696
1063
|
// src/infra/reporter.ts
|
|
697
|
-
var Reporter
|
|
698
|
-
|
|
699
|
-
|
|
1064
|
+
var Reporter, reporter_default;
|
|
1065
|
+
var init_reporter = __esm({
|
|
1066
|
+
"src/infra/reporter.ts"() {
|
|
1067
|
+
"use strict";
|
|
1068
|
+
init_esm_shims();
|
|
1069
|
+
Reporter = class {
|
|
1070
|
+
async reportError(message) {
|
|
1071
|
+
console.error("Error reported:", message);
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
reporter_default = new Reporter();
|
|
700
1075
|
}
|
|
701
|
-
};
|
|
702
|
-
var reporter_default = new Reporter();
|
|
1076
|
+
});
|
|
703
1077
|
|
|
704
|
-
// src/infra/
|
|
705
|
-
var
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
return _DatabaseConnectionManager.instance;
|
|
715
|
-
}
|
|
716
|
-
getConnection() {
|
|
717
|
-
if (!this.db) {
|
|
718
|
-
const dbPath = config.DB_PATH;
|
|
719
|
-
this.db = new Database(dbPath, {
|
|
720
|
-
verbose: config.NODE_ENV === "development" ? (msg) => logger.debug(String(msg)) : void 0
|
|
721
|
-
});
|
|
722
|
-
this.db.pragma("journal_mode = WAL");
|
|
723
|
-
this.db.pragma("foreign_keys = ON");
|
|
724
|
-
this.db.prepare("SELECT 1").get();
|
|
725
|
-
logger.info(`SQLite database connected: ${dbPath}`);
|
|
726
|
-
}
|
|
727
|
-
return this.db;
|
|
1078
|
+
// src/infra/index.ts
|
|
1079
|
+
var init_infra = __esm({
|
|
1080
|
+
"src/infra/index.ts"() {
|
|
1081
|
+
"use strict";
|
|
1082
|
+
init_esm_shims();
|
|
1083
|
+
init_logger();
|
|
1084
|
+
init_asyncHandler();
|
|
1085
|
+
init_appWorker();
|
|
1086
|
+
init_database();
|
|
1087
|
+
init_reporter();
|
|
728
1088
|
}
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
// src/infra/database/adapters/sql-compat.ts
|
|
1092
|
+
function sqliteToPostgres(sql) {
|
|
1093
|
+
let result = "";
|
|
1094
|
+
let paramIndex = 0;
|
|
1095
|
+
let inString = false;
|
|
1096
|
+
for (let i = 0; i < sql.length; i++) {
|
|
1097
|
+
const ch = sql[i];
|
|
1098
|
+
if (ch === "'") {
|
|
1099
|
+
if (inString && i + 1 < sql.length && sql[i + 1] === "'") {
|
|
1100
|
+
result += "''";
|
|
1101
|
+
i++;
|
|
1102
|
+
continue;
|
|
1103
|
+
}
|
|
1104
|
+
inString = !inString;
|
|
1105
|
+
result += ch;
|
|
1106
|
+
} else if (ch === "?" && !inString) {
|
|
1107
|
+
paramIndex++;
|
|
1108
|
+
result += `$${paramIndex}`;
|
|
1109
|
+
} else {
|
|
1110
|
+
result += ch;
|
|
734
1111
|
}
|
|
735
1112
|
}
|
|
736
|
-
|
|
737
|
-
|
|
1113
|
+
return result;
|
|
1114
|
+
}
|
|
1115
|
+
var init_sql_compat = __esm({
|
|
1116
|
+
"src/infra/database/adapters/sql-compat.ts"() {
|
|
1117
|
+
"use strict";
|
|
1118
|
+
init_esm_shims();
|
|
738
1119
|
}
|
|
739
|
-
};
|
|
740
|
-
var databaseConnectionManager = DatabaseConnectionManager.getInstance();
|
|
741
|
-
|
|
742
|
-
// src/domain/file/constants.ts
|
|
743
|
-
var DEFAULT_LIST_LIMIT = 10;
|
|
1120
|
+
});
|
|
744
1121
|
|
|
745
|
-
// src/infra/database/
|
|
746
|
-
|
|
747
|
-
|
|
1122
|
+
// src/infra/database/adapters/postgres-adapter.ts
|
|
1123
|
+
var postgres_adapter_exports = {};
|
|
1124
|
+
__export(postgres_adapter_exports, {
|
|
1125
|
+
PostgresAdapter: () => PostgresAdapter
|
|
1126
|
+
});
|
|
1127
|
+
async function getPg() {
|
|
1128
|
+
if (!pgModule) {
|
|
1129
|
+
pgModule = await import("pg");
|
|
1130
|
+
}
|
|
1131
|
+
return pgModule;
|
|
748
1132
|
}
|
|
749
|
-
var
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
1133
|
+
var pgModule, PostgresAdapter;
|
|
1134
|
+
var init_postgres_adapter = __esm({
|
|
1135
|
+
"src/infra/database/adapters/postgres-adapter.ts"() {
|
|
1136
|
+
"use strict";
|
|
1137
|
+
init_esm_shims();
|
|
1138
|
+
init_sql_compat();
|
|
1139
|
+
init_infra();
|
|
1140
|
+
pgModule = null;
|
|
1141
|
+
PostgresAdapter = class {
|
|
1142
|
+
pool = null;
|
|
1143
|
+
connectionUrl;
|
|
1144
|
+
connected = false;
|
|
1145
|
+
dialect = "postgres";
|
|
1146
|
+
constructor(connectionUrl) {
|
|
1147
|
+
this.connectionUrl = connectionUrl;
|
|
1148
|
+
}
|
|
1149
|
+
async getPool() {
|
|
1150
|
+
if (!this.pool) {
|
|
1151
|
+
const pg = await getPg();
|
|
1152
|
+
this.pool = new pg.default.Pool({
|
|
1153
|
+
connectionString: this.connectionUrl,
|
|
1154
|
+
max: 10,
|
|
1155
|
+
ssl: this.connectionUrl.includes("sslmode=require") || this.connectionUrl.includes("amazonaws.com") || this.connectionUrl.includes("heroku") ? { rejectUnauthorized: false } : void 0
|
|
1156
|
+
});
|
|
1157
|
+
const client = await this.pool.connect();
|
|
1158
|
+
client.release();
|
|
1159
|
+
this.connected = true;
|
|
1160
|
+
logger.info("PostgreSQL database connected");
|
|
1161
|
+
}
|
|
1162
|
+
return this.pool;
|
|
1163
|
+
}
|
|
1164
|
+
async select(sql, params = []) {
|
|
1165
|
+
const pool = await this.getPool();
|
|
1166
|
+
const pgSql = sqliteToPostgres(sql);
|
|
1167
|
+
const result = await pool.query(pgSql, params);
|
|
1168
|
+
return result.rows;
|
|
1169
|
+
}
|
|
1170
|
+
async selectOne(sql, params = []) {
|
|
1171
|
+
const pool = await this.getPool();
|
|
1172
|
+
const pgSql = sqliteToPostgres(sql);
|
|
1173
|
+
const result = await pool.query(pgSql, params);
|
|
1174
|
+
return result.rows[0] ?? void 0;
|
|
1175
|
+
}
|
|
1176
|
+
async execute(sql, params = []) {
|
|
1177
|
+
const pool = await this.getPool();
|
|
1178
|
+
const pgSql = sqliteToPostgres(sql);
|
|
1179
|
+
const result = await pool.query(pgSql, params);
|
|
1180
|
+
return {
|
|
1181
|
+
changes: result.rowCount ?? 0,
|
|
1182
|
+
lastInsertRowid: 0
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
async transaction(callback) {
|
|
1186
|
+
const pool = await this.getPool();
|
|
1187
|
+
const client = await pool.connect();
|
|
1188
|
+
try {
|
|
1189
|
+
await client.query("BEGIN");
|
|
1190
|
+
const result = await callback();
|
|
1191
|
+
await client.query("COMMIT");
|
|
1192
|
+
return result;
|
|
1193
|
+
} catch (error) {
|
|
1194
|
+
await client.query("ROLLBACK");
|
|
1195
|
+
throw error;
|
|
1196
|
+
} finally {
|
|
1197
|
+
client.release();
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
async exec(sql) {
|
|
1201
|
+
const pool = await this.getPool();
|
|
1202
|
+
await pool.query(sql);
|
|
1203
|
+
}
|
|
1204
|
+
async close() {
|
|
1205
|
+
if (this.pool) {
|
|
1206
|
+
await this.pool.end();
|
|
1207
|
+
this.pool = null;
|
|
1208
|
+
this.connected = false;
|
|
1209
|
+
logger.info("Database connection closed");
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
isConnected() {
|
|
1213
|
+
return this.connected;
|
|
1214
|
+
}
|
|
764
1215
|
};
|
|
765
1216
|
}
|
|
766
|
-
|
|
767
|
-
|
|
1217
|
+
});
|
|
1218
|
+
|
|
1219
|
+
// src/infra/database/adapters/sqlite-adapter.ts
|
|
1220
|
+
var sqlite_adapter_exports = {};
|
|
1221
|
+
__export(sqlite_adapter_exports, {
|
|
1222
|
+
SqliteAdapter: () => SqliteAdapter
|
|
1223
|
+
});
|
|
1224
|
+
import Database from "better-sqlite3";
|
|
1225
|
+
var SqliteAdapter;
|
|
1226
|
+
var init_sqlite_adapter = __esm({
|
|
1227
|
+
"src/infra/database/adapters/sqlite-adapter.ts"() {
|
|
1228
|
+
"use strict";
|
|
1229
|
+
init_esm_shims();
|
|
1230
|
+
init_infra();
|
|
1231
|
+
SqliteAdapter = class {
|
|
1232
|
+
constructor(dbPath) {
|
|
1233
|
+
this.dbPath = dbPath;
|
|
1234
|
+
}
|
|
1235
|
+
db = null;
|
|
1236
|
+
dialect = "sqlite";
|
|
1237
|
+
getDb() {
|
|
1238
|
+
if (!this.db) {
|
|
1239
|
+
this.db = new Database(this.dbPath);
|
|
1240
|
+
this.db.pragma("journal_mode = WAL");
|
|
1241
|
+
this.db.pragma("foreign_keys = ON");
|
|
1242
|
+
this.db.prepare("SELECT 1").get();
|
|
1243
|
+
logger.info(`SQLite database connected: ${this.dbPath}`);
|
|
1244
|
+
}
|
|
1245
|
+
return this.db;
|
|
1246
|
+
}
|
|
1247
|
+
async select(sql, params = []) {
|
|
1248
|
+
const stmt = this.getDb().prepare(sql);
|
|
1249
|
+
return stmt.all(params);
|
|
1250
|
+
}
|
|
1251
|
+
async selectOne(sql, params = []) {
|
|
1252
|
+
const stmt = this.getDb().prepare(sql);
|
|
1253
|
+
return stmt.get(params);
|
|
1254
|
+
}
|
|
1255
|
+
async execute(sql, params = []) {
|
|
1256
|
+
const stmt = this.getDb().prepare(sql);
|
|
1257
|
+
const result = stmt.run(params);
|
|
1258
|
+
return {
|
|
1259
|
+
changes: result.changes,
|
|
1260
|
+
lastInsertRowid: result.lastInsertRowid
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
async transaction(callback) {
|
|
1264
|
+
const db = this.getDb();
|
|
1265
|
+
const savepointName = `sp_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
1266
|
+
db.exec(`SAVEPOINT ${savepointName}`);
|
|
1267
|
+
try {
|
|
1268
|
+
const result = await callback();
|
|
1269
|
+
db.exec(`RELEASE ${savepointName}`);
|
|
1270
|
+
return result;
|
|
1271
|
+
} catch (error) {
|
|
1272
|
+
db.exec(`ROLLBACK TO ${savepointName}`);
|
|
1273
|
+
db.exec(`RELEASE ${savepointName}`);
|
|
1274
|
+
throw error;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
async exec(sql) {
|
|
1278
|
+
this.getDb().exec(sql);
|
|
1279
|
+
}
|
|
1280
|
+
async close() {
|
|
1281
|
+
if (this.db) {
|
|
1282
|
+
this.db.close();
|
|
1283
|
+
this.db = null;
|
|
1284
|
+
logger.info("Database connection closed");
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
isConnected() {
|
|
1288
|
+
return this.db !== null && this.db.open;
|
|
1289
|
+
}
|
|
1290
|
+
};
|
|
768
1291
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1294
|
+
// src/infra/database/connection.ts
|
|
1295
|
+
import path3 from "path";
|
|
1296
|
+
import fs2 from "fs";
|
|
1297
|
+
async function initializeAdapter() {
|
|
1298
|
+
if (adapter) return adapter;
|
|
1299
|
+
const databaseUrl = process.env.DATABASE_URL;
|
|
1300
|
+
const dbPath = process.env.DB_PATH;
|
|
1301
|
+
if (databaseUrl) {
|
|
1302
|
+
const { PostgresAdapter: PostgresAdapter2 } = await Promise.resolve().then(() => (init_postgres_adapter(), postgres_adapter_exports));
|
|
1303
|
+
adapter = new PostgresAdapter2(databaseUrl);
|
|
1304
|
+
logger.info("Using PostgreSQL adapter");
|
|
1305
|
+
} else if (dbPath) {
|
|
1306
|
+
const dbDir = path3.dirname(dbPath.trim());
|
|
1307
|
+
if (!fs2.existsSync(dbDir)) {
|
|
1308
|
+
fs2.mkdirSync(dbDir, { recursive: true });
|
|
781
1309
|
}
|
|
782
|
-
|
|
1310
|
+
const { SqliteAdapter: SqliteAdapter2 } = await Promise.resolve().then(() => (init_sqlite_adapter(), sqlite_adapter_exports));
|
|
1311
|
+
adapter = new SqliteAdapter2(dbPath);
|
|
1312
|
+
logger.info("Using SQLite adapter");
|
|
1313
|
+
} else {
|
|
1314
|
+
throw new Error(
|
|
1315
|
+
"No database configured. Set DATABASE_URL (PostgreSQL) or DB_PATH (SQLite)."
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
return adapter;
|
|
1319
|
+
}
|
|
1320
|
+
async function getAdapter() {
|
|
1321
|
+
if (!adapter) {
|
|
1322
|
+
return initializeAdapter();
|
|
783
1323
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
// src/infra/database/index.ts
|
|
787
|
-
function getDb2() {
|
|
788
|
-
return databaseConnectionManager.getConnection();
|
|
1324
|
+
return adapter;
|
|
789
1325
|
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
1326
|
+
async function closeAdapter() {
|
|
1327
|
+
if (adapter) {
|
|
1328
|
+
await adapter.close();
|
|
1329
|
+
adapter = null;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
var adapter;
|
|
1333
|
+
var init_connection = __esm({
|
|
1334
|
+
"src/infra/database/connection.ts"() {
|
|
1335
|
+
"use strict";
|
|
1336
|
+
init_esm_shims();
|
|
1337
|
+
init_infra();
|
|
1338
|
+
adapter = null;
|
|
1339
|
+
}
|
|
1340
|
+
});
|
|
1341
|
+
|
|
1342
|
+
// src/commands/index.ts
|
|
1343
|
+
init_esm_shims();
|
|
1344
|
+
init_config();
|
|
1345
|
+
init_logger();
|
|
1346
|
+
import { Command as Command9 } from "commander";
|
|
794
1347
|
|
|
795
1348
|
// src/infra/database/migrations/index.ts
|
|
1349
|
+
init_esm_shims();
|
|
1350
|
+
init_connection();
|
|
1351
|
+
init_infra();
|
|
796
1352
|
var STABLE_SCHEMA = `
|
|
797
1353
|
CREATE TABLE IF NOT EXISTS files (
|
|
798
1354
|
_id TEXT PRIMARY KEY,
|
|
@@ -802,8 +1358,8 @@ CREATE TABLE IF NOT EXISTS files (
|
|
|
802
1358
|
localVersion INTEGER NOT NULL DEFAULT 1,
|
|
803
1359
|
onchainVersion INTEGER NOT NULL DEFAULT 0,
|
|
804
1360
|
syncStatus TEXT NOT NULL DEFAULT 'pending',
|
|
805
|
-
createdAt
|
|
806
|
-
updatedAt
|
|
1361
|
+
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
1362
|
+
updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
807
1363
|
isDeleted INTEGER NOT NULL DEFAULT 0,
|
|
808
1364
|
portalAddress TEXT NOT NULL,
|
|
809
1365
|
metadata TEXT DEFAULT '{}',
|
|
@@ -823,8 +1379,8 @@ CREATE TABLE IF NOT EXISTS portals (
|
|
|
823
1379
|
portalAddress TEXT NOT NULL UNIQUE,
|
|
824
1380
|
portalSeed TEXT NOT NULL UNIQUE,
|
|
825
1381
|
ownerAddress TEXT NOT NULL,
|
|
826
|
-
createdAt
|
|
827
|
-
updatedAt
|
|
1382
|
+
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
1383
|
+
updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
828
1384
|
);
|
|
829
1385
|
|
|
830
1386
|
CREATE TABLE IF NOT EXISTS api_keys (
|
|
@@ -833,7 +1389,7 @@ CREATE TABLE IF NOT EXISTS api_keys (
|
|
|
833
1389
|
name TEXT NOT NULL,
|
|
834
1390
|
collaboratorAddress TEXT NOT NULL UNIQUE,
|
|
835
1391
|
portalAddress TEXT NOT NULL,
|
|
836
|
-
createdAt
|
|
1392
|
+
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
837
1393
|
isDeleted INTEGER NOT NULL DEFAULT 0
|
|
838
1394
|
);
|
|
839
1395
|
|
|
@@ -869,29 +1425,33 @@ CREATE TABLE IF NOT EXISTS folders (
|
|
|
869
1425
|
lastTransactionHash TEXT,
|
|
870
1426
|
lastTransactionBlockNumber INTEGER NOT NULL,
|
|
871
1427
|
lastTransactionBlockTimestamp INTEGER NOT NULL,
|
|
872
|
-
created_at
|
|
873
|
-
updated_at
|
|
1428
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
1429
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
874
1430
|
);
|
|
875
1431
|
CREATE INDEX IF NOT EXISTS idx_folders_folderRef_folderId ON folders(folderRef, folderId);
|
|
876
1432
|
CREATE INDEX IF NOT EXISTS idx_folders_folderRef ON folders(folderRef);
|
|
877
1433
|
CREATE INDEX IF NOT EXISTS idx_folders_created_at ON folders(created_at);
|
|
878
1434
|
`;
|
|
879
|
-
function runMigrations() {
|
|
880
|
-
const
|
|
881
|
-
|
|
1435
|
+
async function runMigrations() {
|
|
1436
|
+
const adapter2 = await getAdapter();
|
|
1437
|
+
await adapter2.exec(STABLE_SCHEMA);
|
|
882
1438
|
logger.debug("Database schema ready");
|
|
883
1439
|
}
|
|
884
1440
|
|
|
885
1441
|
// src/commands/listCommand.ts
|
|
1442
|
+
init_esm_shims();
|
|
886
1443
|
import { Command } from "commander";
|
|
887
1444
|
import Table from "cli-table3";
|
|
888
1445
|
|
|
889
1446
|
// src/domain/file/index.ts
|
|
1447
|
+
init_esm_shims();
|
|
1448
|
+
init_models();
|
|
1449
|
+
init_constants2();
|
|
890
1450
|
import { generate } from "short-uuid";
|
|
891
|
-
function listFiles(params) {
|
|
1451
|
+
async function listFiles(params) {
|
|
892
1452
|
const { limit, skip, portalAddress } = params;
|
|
893
1453
|
const effectiveLimit = limit || DEFAULT_LIST_LIMIT;
|
|
894
|
-
const result = FilesModel.findAll(portalAddress, effectiveLimit, skip);
|
|
1454
|
+
const result = await FilesModel.findAll(portalAddress, effectiveLimit, skip);
|
|
895
1455
|
const processedFiles = result.files.map((file) => ({
|
|
896
1456
|
ddocId: file.ddocId,
|
|
897
1457
|
link: file.link,
|
|
@@ -912,11 +1472,11 @@ function listFiles(params) {
|
|
|
912
1472
|
hasNext: result.hasNext
|
|
913
1473
|
};
|
|
914
1474
|
}
|
|
915
|
-
function getFile(ddocId, portalAddress) {
|
|
1475
|
+
async function getFile(ddocId, portalAddress) {
|
|
916
1476
|
if (!ddocId) {
|
|
917
1477
|
throw new Error("ddocId is required");
|
|
918
1478
|
}
|
|
919
|
-
const file = FilesModel.findByDDocId(ddocId, portalAddress);
|
|
1479
|
+
const file = await FilesModel.findByDDocId(ddocId, portalAddress);
|
|
920
1480
|
if (!file) {
|
|
921
1481
|
return null;
|
|
922
1482
|
}
|
|
@@ -940,13 +1500,13 @@ var createFile = async (input) => {
|
|
|
940
1500
|
throw new Error("title, content, and portalAddress are required");
|
|
941
1501
|
}
|
|
942
1502
|
const ddocId = generate();
|
|
943
|
-
const file = FilesModel.create({
|
|
1503
|
+
const file = await FilesModel.create({
|
|
944
1504
|
title: input.title,
|
|
945
1505
|
content: input.content,
|
|
946
1506
|
ddocId,
|
|
947
1507
|
portalAddress: input.portalAddress
|
|
948
1508
|
});
|
|
949
|
-
EventsModel.create({ type: "create", fileId: file._id, portalAddress: file.portalAddress });
|
|
1509
|
+
await EventsModel.create({ type: "create", fileId: file._id, portalAddress: file.portalAddress });
|
|
950
1510
|
return file;
|
|
951
1511
|
};
|
|
952
1512
|
var updateFile = async (ddocId, payload, portalAddress) => {
|
|
@@ -956,7 +1516,7 @@ var updateFile = async (ddocId, payload, portalAddress) => {
|
|
|
956
1516
|
if (!payload.title && !payload.content) {
|
|
957
1517
|
throw new Error("At least one field is required: Either provide title, content, or both");
|
|
958
1518
|
}
|
|
959
|
-
const existingFile = FilesModel.findByDDocId(ddocId, portalAddress);
|
|
1519
|
+
const existingFile = await FilesModel.findByDDocId(ddocId, portalAddress);
|
|
960
1520
|
if (!existingFile) {
|
|
961
1521
|
throw new Error(`File with ddocId ${ddocId} not found`);
|
|
962
1522
|
}
|
|
@@ -966,8 +1526,8 @@ var updateFile = async (ddocId, payload, portalAddress) => {
|
|
|
966
1526
|
syncStatus: "pending"
|
|
967
1527
|
// since the update is done in local db, it's not on the chain yet. hence pending
|
|
968
1528
|
};
|
|
969
|
-
const updatedFile = FilesModel.update(existingFile._id, updatePayload, portalAddress);
|
|
970
|
-
EventsModel.create({ type: "update", fileId: updatedFile._id, portalAddress: updatedFile.portalAddress });
|
|
1529
|
+
const updatedFile = await FilesModel.update(existingFile._id, updatePayload, portalAddress);
|
|
1530
|
+
await EventsModel.create({ type: "update", fileId: updatedFile._id, portalAddress: updatedFile.portalAddress });
|
|
971
1531
|
return {
|
|
972
1532
|
ddocId: updatedFile.ddocId,
|
|
973
1533
|
link: updatedFile.link,
|
|
@@ -987,16 +1547,17 @@ var deleteFile = async (ddocId, portalAddress) => {
|
|
|
987
1547
|
if (!ddocId) {
|
|
988
1548
|
throw new Error("ddocId is required");
|
|
989
1549
|
}
|
|
990
|
-
const existingFile = FilesModel.findByDDocId(ddocId, portalAddress);
|
|
1550
|
+
const existingFile = await FilesModel.findByDDocId(ddocId, portalAddress);
|
|
991
1551
|
if (!existingFile) {
|
|
992
1552
|
throw new Error(`File with ddocId ${ddocId} not found`);
|
|
993
1553
|
}
|
|
994
|
-
const deletedFile = FilesModel.softDelete(existingFile._id);
|
|
995
|
-
EventsModel.create({ type: "delete", fileId: deletedFile._id, portalAddress: deletedFile.portalAddress });
|
|
1554
|
+
const deletedFile = await FilesModel.softDelete(existingFile._id);
|
|
1555
|
+
await EventsModel.create({ type: "delete", fileId: deletedFile._id, portalAddress: deletedFile.portalAddress });
|
|
996
1556
|
return deletedFile;
|
|
997
1557
|
};
|
|
998
1558
|
|
|
999
1559
|
// src/commands/utils/util.ts
|
|
1560
|
+
init_esm_shims();
|
|
1000
1561
|
var columnNames = {
|
|
1001
1562
|
index: "#",
|
|
1002
1563
|
ddocId: "DDoc ID",
|
|
@@ -1073,19 +1634,22 @@ After setup, you can use ddctl commands.
|
|
|
1073
1634
|
}
|
|
1074
1635
|
|
|
1075
1636
|
// src/commands/listCommand.ts
|
|
1637
|
+
init_config();
|
|
1638
|
+
init_models();
|
|
1076
1639
|
var listCommand = new Command().name("list").description("List all ddocs").option("-l, --limit <number>", "Limit the number of results", parseInt).option("-s, --skip <number>", "Skip the first N results", parseInt).action(async (options) => {
|
|
1077
1640
|
try {
|
|
1078
1641
|
const runtimeConfig = getRuntimeConfig();
|
|
1079
1642
|
const apiKey = runtimeConfig.API_KEY;
|
|
1080
1643
|
validateApiKey(apiKey);
|
|
1081
|
-
const
|
|
1644
|
+
const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
|
|
1645
|
+
const portalAddress = apiKeyInfo?.portalAddress;
|
|
1082
1646
|
if (!portalAddress) throw new Error("Portal address is required");
|
|
1083
1647
|
const params = {
|
|
1084
1648
|
limit: options.limit,
|
|
1085
1649
|
skip: options.skip,
|
|
1086
1650
|
portalAddress
|
|
1087
1651
|
};
|
|
1088
|
-
const result = listFiles(params);
|
|
1652
|
+
const result = await listFiles(params);
|
|
1089
1653
|
if (result.ddocs.length === 0) {
|
|
1090
1654
|
console.log("No ddocs found.");
|
|
1091
1655
|
return;
|
|
@@ -1140,16 +1704,20 @@ Found ${result.total} ddoc(s):
|
|
|
1140
1704
|
});
|
|
1141
1705
|
|
|
1142
1706
|
// src/commands/getCommand.ts
|
|
1707
|
+
init_esm_shims();
|
|
1143
1708
|
import { Command as Command2 } from "commander";
|
|
1144
1709
|
import Table2 from "cli-table3";
|
|
1710
|
+
init_config();
|
|
1711
|
+
init_models();
|
|
1145
1712
|
var getCommand = new Command2().name("get").description("Get a ddoc by its ID").argument("<ddocId>", "The ddoc ID to retrieve").action(async (ddocId) => {
|
|
1146
1713
|
try {
|
|
1147
1714
|
const runtimeConfig = getRuntimeConfig();
|
|
1148
1715
|
const apiKey = runtimeConfig.API_KEY;
|
|
1149
1716
|
validateApiKey(apiKey);
|
|
1150
|
-
const
|
|
1717
|
+
const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
|
|
1718
|
+
const portalAddress = apiKeyInfo?.portalAddress;
|
|
1151
1719
|
if (!portalAddress) throw new Error("Portal address is required");
|
|
1152
|
-
const file = getFile(ddocId, portalAddress);
|
|
1720
|
+
const file = await getFile(ddocId, portalAddress);
|
|
1153
1721
|
if (!file) {
|
|
1154
1722
|
console.error(`Ddoc with ID "${ddocId}" not found.`);
|
|
1155
1723
|
return;
|
|
@@ -1202,26 +1770,30 @@ Link: ${file.link}
|
|
|
1202
1770
|
});
|
|
1203
1771
|
|
|
1204
1772
|
// src/commands/createCommand.ts
|
|
1773
|
+
init_esm_shims();
|
|
1205
1774
|
import { Command as Command3 } from "commander";
|
|
1206
|
-
import * as
|
|
1207
|
-
import * as
|
|
1775
|
+
import * as fs3 from "fs";
|
|
1776
|
+
import * as path4 from "path";
|
|
1208
1777
|
import Table3 from "cli-table3";
|
|
1778
|
+
init_config();
|
|
1779
|
+
init_models();
|
|
1209
1780
|
var createCommand = new Command3().name("create").description("Create a new ddoc from a file").argument("<filepath>", "Path to the file to create ddoc from").action(async (filepath) => {
|
|
1210
1781
|
try {
|
|
1211
|
-
if (!
|
|
1782
|
+
if (!fs3.existsSync(filepath)) {
|
|
1212
1783
|
throw new Error(`File not found: ${filepath}`);
|
|
1213
1784
|
}
|
|
1214
1785
|
const runtimeConfig = getRuntimeConfig();
|
|
1215
1786
|
const apiKey = runtimeConfig.API_KEY;
|
|
1216
1787
|
validateApiKey(apiKey);
|
|
1217
|
-
const
|
|
1788
|
+
const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
|
|
1789
|
+
const portalAddress = apiKeyInfo?.portalAddress;
|
|
1218
1790
|
if (!portalAddress) throw new Error("Portal address is required");
|
|
1219
|
-
const content =
|
|
1791
|
+
const content = fs3.readFileSync(filepath, "utf-8");
|
|
1220
1792
|
if (!content || content.trim().length === 0) {
|
|
1221
1793
|
console.error("Error creating ddoc: File content cannot be empty. Add some content to the file and try again.");
|
|
1222
1794
|
process.exit(1);
|
|
1223
1795
|
}
|
|
1224
|
-
const basename3 =
|
|
1796
|
+
const basename3 = path4.basename(filepath);
|
|
1225
1797
|
const lastDotIndex = basename3.lastIndexOf(".");
|
|
1226
1798
|
const title = lastDotIndex > 0 ? basename3.substring(0, lastDotIndex) : basename3;
|
|
1227
1799
|
const file = await createFile({ title, content, portalAddress });
|
|
@@ -1265,12 +1837,15 @@ var createCommand = new Command3().name("create").description("Create a new ddoc
|
|
|
1265
1837
|
});
|
|
1266
1838
|
|
|
1267
1839
|
// src/commands/updateCommand.ts
|
|
1268
|
-
|
|
1269
|
-
import * as
|
|
1840
|
+
init_esm_shims();
|
|
1841
|
+
import * as fs4 from "fs";
|
|
1842
|
+
import * as path5 from "path";
|
|
1270
1843
|
import * as os2 from "os";
|
|
1271
1844
|
import { Command as Command4 } from "commander";
|
|
1272
1845
|
import { spawnSync } from "child_process";
|
|
1273
1846
|
import Table4 from "cli-table3";
|
|
1847
|
+
init_models();
|
|
1848
|
+
init_config();
|
|
1274
1849
|
function showTable(updatedFile) {
|
|
1275
1850
|
const table = new Table4({
|
|
1276
1851
|
head: [
|
|
@@ -1310,19 +1885,20 @@ var updateCommand = new Command4().name("update").description("Update an existin
|
|
|
1310
1885
|
const runtimeConfig = getRuntimeConfig();
|
|
1311
1886
|
const apiKey = runtimeConfig.API_KEY;
|
|
1312
1887
|
validateApiKey(apiKey);
|
|
1313
|
-
const
|
|
1888
|
+
const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
|
|
1889
|
+
const portalAddress = apiKeyInfo?.portalAddress;
|
|
1314
1890
|
if (!portalAddress) throw new Error("Portal address is required");
|
|
1315
|
-
const file = getFile(ddocId, portalAddress);
|
|
1891
|
+
const file = await getFile(ddocId, portalAddress);
|
|
1316
1892
|
if (!file) {
|
|
1317
1893
|
throw new Error(`ddoc with ${ddocId} not found.`);
|
|
1318
1894
|
}
|
|
1319
1895
|
const filePath = options?.file ?? "";
|
|
1320
1896
|
if (filePath) {
|
|
1321
|
-
const content =
|
|
1897
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
1322
1898
|
if (!content || content.trim().length === 0) {
|
|
1323
1899
|
throw new Error(`file content cannot be empty`);
|
|
1324
1900
|
}
|
|
1325
|
-
const basename3 =
|
|
1901
|
+
const basename3 = path5.basename(filePath);
|
|
1326
1902
|
const lastDotIndex = basename3.lastIndexOf(".");
|
|
1327
1903
|
const title = lastDotIndex > 0 ? basename3.substring(0, lastDotIndex) : basename3;
|
|
1328
1904
|
const payload = {
|
|
@@ -1334,15 +1910,15 @@ var updateCommand = new Command4().name("update").description("Update an existin
|
|
|
1334
1910
|
showTable(updatedFile);
|
|
1335
1911
|
return;
|
|
1336
1912
|
}
|
|
1337
|
-
const tmpFilePath =
|
|
1338
|
-
|
|
1913
|
+
const tmpFilePath = path5.join(os2.tmpdir(), `tmp-${ddocId}-${Date.now()}.txt`);
|
|
1914
|
+
fs4.writeFileSync(tmpFilePath, file.content);
|
|
1339
1915
|
const editor = process.env.EDITOR || "vi";
|
|
1340
1916
|
const result = spawnSync(editor, [tmpFilePath], { stdio: "inherit" });
|
|
1341
1917
|
if (result.status === 0) {
|
|
1342
|
-
const newContent =
|
|
1918
|
+
const newContent = fs4.readFileSync(tmpFilePath, "utf-8");
|
|
1343
1919
|
if (newContent === file.content) {
|
|
1344
1920
|
console.log(`No changes made. Update cancelled.`);
|
|
1345
|
-
|
|
1921
|
+
fs4.unlinkSync(tmpFilePath);
|
|
1346
1922
|
return;
|
|
1347
1923
|
}
|
|
1348
1924
|
const payload = {
|
|
@@ -1354,7 +1930,7 @@ var updateCommand = new Command4().name("update").description("Update an existin
|
|
|
1354
1930
|
console.log("\n\u2713 Ddoc updated successfully!\n");
|
|
1355
1931
|
showTable(updatedFile);
|
|
1356
1932
|
}
|
|
1357
|
-
|
|
1933
|
+
fs4.unlinkSync(tmpFilePath);
|
|
1358
1934
|
} catch (error) {
|
|
1359
1935
|
console.error("Error updating ddoc:", error.message);
|
|
1360
1936
|
throw error;
|
|
@@ -1362,13 +1938,17 @@ var updateCommand = new Command4().name("update").description("Update an existin
|
|
|
1362
1938
|
});
|
|
1363
1939
|
|
|
1364
1940
|
// src/commands/deleteCommand.ts
|
|
1941
|
+
init_esm_shims();
|
|
1365
1942
|
import { Command as Command5 } from "commander";
|
|
1943
|
+
init_config();
|
|
1944
|
+
init_models();
|
|
1366
1945
|
var deleteCommand = new Command5().name("delete").description("Delete one or more ddocs by their IDs").argument("<ddocIds...>", "One or more ddoc IDs to delete (space-separated)").action(async (ddocIds) => {
|
|
1367
1946
|
try {
|
|
1368
1947
|
const runtimeConfig = getRuntimeConfig();
|
|
1369
1948
|
const apiKey = runtimeConfig.API_KEY;
|
|
1370
1949
|
validateApiKey(apiKey);
|
|
1371
|
-
const
|
|
1950
|
+
const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
|
|
1951
|
+
const portalAddress = apiKeyInfo?.portalAddress;
|
|
1372
1952
|
if (!portalAddress) throw new Error("Portal address is required");
|
|
1373
1953
|
for (const ddocId of ddocIds) {
|
|
1374
1954
|
try {
|
|
@@ -1385,16 +1965,20 @@ var deleteCommand = new Command5().name("delete").description("Delete one or mor
|
|
|
1385
1965
|
});
|
|
1386
1966
|
|
|
1387
1967
|
// src/commands/downloadCommand.ts
|
|
1968
|
+
init_esm_shims();
|
|
1388
1969
|
import { Command as Command6 } from "commander";
|
|
1389
|
-
import * as
|
|
1970
|
+
import * as fs5 from "fs";
|
|
1971
|
+
init_config();
|
|
1972
|
+
init_models();
|
|
1390
1973
|
var downloadCommand = new Command6().name("download").description("Download a ddoc to a local file").argument("<ddocId>", "The ddoc ID to download").option("-o, --output <filename>", "Output filename (only supports markdown)").action(async (ddocId, options) => {
|
|
1391
1974
|
try {
|
|
1392
1975
|
const runtimeConfig = getRuntimeConfig();
|
|
1393
1976
|
const apiKey = runtimeConfig.API_KEY;
|
|
1394
1977
|
validateApiKey(apiKey);
|
|
1395
|
-
const
|
|
1978
|
+
const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
|
|
1979
|
+
const portalAddress = apiKeyInfo?.portalAddress;
|
|
1396
1980
|
if (!portalAddress) throw new Error("Portal address is required");
|
|
1397
|
-
const file = getFile(ddocId, portalAddress);
|
|
1981
|
+
const file = await getFile(ddocId, portalAddress);
|
|
1398
1982
|
if (!file) {
|
|
1399
1983
|
console.error(`Ddoc with ID "${ddocId}" not found.`);
|
|
1400
1984
|
return;
|
|
@@ -1403,7 +1987,7 @@ var downloadCommand = new Command6().name("download").description("Download a dd
|
|
|
1403
1987
|
if (options.output) {
|
|
1404
1988
|
outputFilename = options.output.endsWith(".md") ? options.output : `${options.output}.md`;
|
|
1405
1989
|
}
|
|
1406
|
-
|
|
1990
|
+
fs5.writeFileSync(outputFilename, file.content, "utf-8");
|
|
1407
1991
|
console.log(`
|
|
1408
1992
|
\u2713 Ddoc downloaded successfully to: ${outputFilename}
|
|
1409
1993
|
`);
|
|
@@ -1414,15 +1998,19 @@ var downloadCommand = new Command6().name("download").description("Download a dd
|
|
|
1414
1998
|
});
|
|
1415
1999
|
|
|
1416
2000
|
// src/commands/viewCommand.ts
|
|
2001
|
+
init_esm_shims();
|
|
1417
2002
|
import { Command as Command7 } from "commander";
|
|
2003
|
+
init_config();
|
|
2004
|
+
init_models();
|
|
1418
2005
|
var viewCommand = new Command7().name("view").description("View content preview of a ddoc").argument("<ddocId>", "The ddoc ID to view").option("-n, --lines <number>", "Number of lines to preview (default: 10)", "10").action(async (ddocId, options) => {
|
|
1419
2006
|
try {
|
|
1420
2007
|
const runtimeConfig = getRuntimeConfig();
|
|
1421
2008
|
const apiKey = runtimeConfig.API_KEY;
|
|
1422
2009
|
validateApiKey(apiKey);
|
|
1423
|
-
const
|
|
2010
|
+
const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
|
|
2011
|
+
const portalAddress = apiKeyInfo?.portalAddress;
|
|
1424
2012
|
if (!portalAddress) throw new Error("Portal address is required");
|
|
1425
|
-
const file = getFile(ddocId, portalAddress);
|
|
2013
|
+
const file = await getFile(ddocId, portalAddress);
|
|
1426
2014
|
if (!file) {
|
|
1427
2015
|
console.error(`Ddoc with ID "${ddocId}" not found.`);
|
|
1428
2016
|
return;
|
|
@@ -1458,13 +2046,15 @@ Showing ${linesToShow} of ${totalLines} line${totalLines === 1 ? "" : "s"}
|
|
|
1458
2046
|
});
|
|
1459
2047
|
|
|
1460
2048
|
// src/commands/eventsCommand.ts
|
|
2049
|
+
init_esm_shims();
|
|
2050
|
+
init_models();
|
|
1461
2051
|
import { Command as Command8 } from "commander";
|
|
1462
2052
|
import Table5 from "cli-table3";
|
|
1463
2053
|
var MAX_ERROR_LEN = 60;
|
|
1464
2054
|
var eventsCommand = new Command8().name("events").description("Worker event operations (list failed, retry)");
|
|
1465
2055
|
eventsCommand.command("list-failed").description("List all failed events").action(async () => {
|
|
1466
2056
|
try {
|
|
1467
|
-
const events = EventsModel.listFailed();
|
|
2057
|
+
const events = await EventsModel.listFailed();
|
|
1468
2058
|
if (events.length === 0) {
|
|
1469
2059
|
console.log("No failed events.");
|
|
1470
2060
|
return;
|
|
@@ -1497,7 +2087,7 @@ Failed events (${events.length}):
|
|
|
1497
2087
|
});
|
|
1498
2088
|
eventsCommand.command("retry <eventId>").description("Retry a single failed event by ID").action(async (eventId) => {
|
|
1499
2089
|
try {
|
|
1500
|
-
const updated = EventsModel.resetFailedToPending(eventId);
|
|
2090
|
+
const updated = await EventsModel.resetFailedToPending(eventId);
|
|
1501
2091
|
if (updated) {
|
|
1502
2092
|
console.log(`Event ${eventId} reset to pending. Worker will pick it up.`);
|
|
1503
2093
|
} else {
|
|
@@ -1512,7 +2102,7 @@ eventsCommand.command("retry <eventId>").description("Retry a single failed even
|
|
|
1512
2102
|
});
|
|
1513
2103
|
eventsCommand.command("retry-all").description("Retry all failed events").action(async () => {
|
|
1514
2104
|
try {
|
|
1515
|
-
const count = EventsModel.resetAllFailedToPending();
|
|
2105
|
+
const count = await EventsModel.resetAllFailedToPending();
|
|
1516
2106
|
console.log(`Reset ${count} failed event(s) to pending. Worker will pick them up.`);
|
|
1517
2107
|
} catch (error) {
|
|
1518
2108
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -1522,8 +2112,9 @@ eventsCommand.command("retry-all").description("Retry all failed events").action
|
|
|
1522
2112
|
});
|
|
1523
2113
|
|
|
1524
2114
|
// src/commands/index.ts
|
|
2115
|
+
init_infra();
|
|
1525
2116
|
logger.level = "error";
|
|
1526
|
-
runMigrations();
|
|
2117
|
+
await runMigrations();
|
|
1527
2118
|
var program = new Command9().name("ddctl").description("CLI tool to manage your ddocs").version("0.0.3").addHelpText("beforeAll", "\n").addHelpText("afterAll", "\n");
|
|
1528
2119
|
program.addCommand(listCommand);
|
|
1529
2120
|
program.addCommand(getCommand);
|