@fileverse/api 0.0.2 → 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.
@@ -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
- // src/commands/index.ts
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 fs from "fs";
10
- import os from "os";
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
- API_URL: "https://prod-apps-storage-5cdacc06ff79.herokuapp.com/",
15
- SERVER_DID: "did:key:z6Mkroj9bxTin6Z5S9qwx2G2b87NPrCX7S85FhCpmBGPcDCz",
16
- PROXY_SERVER_DID: "did:key:z6MkrZSmq8D6vQG87YbjUQatXeptaCCXWdTx8fYaWxWbRUHB",
17
- NETWORK_NAME: "gnosis",
18
- DEFAULT_PORT: "8001",
19
- DEFAULT_RPC_URL: "https://rpc.gnosischain.com",
20
- PIMLICO_PROXY_URL: "https://pimlico-proxy-0a326da116f8.herokuapp.com/",
21
- SERVICE_NAME: "fileverse-api",
22
- LOG_LEVEL: "info",
23
- FRONTEND_URL: "https://docs.fileverse.io"
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
- var projectEnvPath = path.join(process.cwd(), "config", ".env");
28
- var userEnvPath = path.join(os.homedir(), ".fileverse", ".env");
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() {
@@ -62,435 +88,538 @@ function getRuntimeConfig() {
62
88
  }
63
89
  };
64
90
  }
65
- var config = {
66
- ...STATIC_CONFIG,
67
- get SERVICE_NAME() {
68
- return STATIC_CONFIG.SERVICE_NAME;
69
- },
70
- get LOG_LEVEL() {
71
- return STATIC_CONFIG.LOG_LEVEL;
72
- },
73
- get NETWORK_NAME() {
74
- return STATIC_CONFIG.NETWORK_NAME;
75
- },
76
- get UPLOAD_SERVER_URL() {
77
- return STATIC_CONFIG.API_URL;
78
- },
79
- get UPLOAD_SERVER_DID() {
80
- return STATIC_CONFIG.SERVER_DID;
81
- },
82
- get API_KEY() {
83
- return process.env.API_KEY;
84
- },
85
- get RPC_URL() {
86
- return process.env.RPC_URL || STATIC_CONFIG.DEFAULT_RPC_URL;
87
- },
88
- get DB_PATH() {
89
- return process.env.DB_PATH;
90
- },
91
- get DATABASE_URL() {
92
- return process.env.DATABASE_URL;
93
- },
94
- get PORT() {
95
- return process.env.PORT || STATIC_CONFIG.DEFAULT_PORT;
96
- },
97
- get NODE_ENV() {
98
- return process.env.NODE_ENV || "production";
99
- },
100
- get IP() {
101
- return process.env.IP || "0.0.0.0";
102
- },
103
- get FRONTEND_URL() {
104
- return process.env.FRONTEND_URL || STATIC_CONFIG.FRONTEND_URL;
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
+ };
105
142
  }
106
- };
143
+ });
107
144
 
108
145
  // src/infra/logger.ts
109
146
  import pino from "pino";
110
- var isProduction = config.NODE_ENV === "production";
111
- var pinoInstance = pino({
112
- name: STATIC_CONFIG.SERVICE_NAME,
113
- level: STATIC_CONFIG.LOG_LEVEL,
114
- formatters: {
115
- bindings: (bindings) => ({ name: bindings.name }),
116
- level: (label) => ({ level: label })
117
- },
118
- serializers: {
119
- err(err) {
120
- if (!err) return err;
121
- if (isProduction) {
122
- return { type: err.name, message: err.message };
123
- }
124
- return {
125
- type: err.name,
126
- message: err.message,
127
- stack: err.stack
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);
128
206
  };
129
- }
130
- },
131
- transport: config.NODE_ENV !== "production" ? {
132
- target: "pino-pretty",
133
- options: {
134
- colorize: true,
135
- translateTime: "SYS:standard",
136
- ignore: "pid,hostname",
137
- errorProps: "*",
138
- errorLikeObjectKeys: ["err", "error"]
139
- }
140
- } : void 0
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
+ }
141
224
  });
142
- var createLogMethod = (level) => {
143
- return (...args) => {
144
- const [first, ...rest] = args;
145
- const log = pinoInstance[level].bind(pinoInstance);
146
- if (typeof first === "object" && first !== null && !(first instanceof Error)) {
147
- log(first, ...rest);
148
- return;
149
- }
150
- if (rest.length > 0) {
151
- const last = rest[rest.length - 1];
152
- if (last instanceof Error) {
153
- log({ err: last }, first, ...rest.slice(0, -1));
154
- return;
155
- }
156
- }
157
- if (first instanceof Error) {
158
- log({ err: first }, first.message);
159
- return;
160
- }
161
- log(first, ...rest);
162
- };
163
- };
164
- var logger = {
165
- trace: createLogMethod("trace"),
166
- debug: createLogMethod("debug"),
167
- info: createLogMethod("info"),
168
- warn: createLogMethod("warn"),
169
- error: createLogMethod("error"),
170
- fatal: createLogMethod("fatal"),
171
- get level() {
172
- return pinoInstance.level;
173
- },
174
- set level(lvl) {
175
- pinoInstance.level = lvl;
176
- },
177
- child: pinoInstance.child.bind(pinoInstance)
178
- };
179
225
 
180
- // src/infra/database/adapters/sqlite-adapter.ts
181
- import Database from "better-sqlite3";
226
+ // src/infra/asyncHandler.ts
227
+ var init_asyncHandler = __esm({
228
+ "src/infra/asyncHandler.ts"() {
229
+ "use strict";
230
+ init_esm_shims();
231
+ }
232
+ });
182
233
 
183
234
  // src/domain/file/constants.ts
184
- var DEFAULT_LIST_LIMIT = 10;
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
+ });
185
243
 
186
244
  // src/infra/database/query-builder.ts
187
- var QueryBuilder = class {
188
- static async select(sql, params = []) {
189
- return getAdapterSync().select(sql, params);
190
- }
191
- static async selectOne(sql, params = []) {
192
- return getAdapterSync().selectOne(sql, params);
193
- }
194
- static async execute(sql, params = []) {
195
- return getAdapterSync().execute(sql, params);
196
- }
197
- static async transaction(callback) {
198
- return getAdapterSync().transaction(callback);
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);
256
+ }
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
+ };
199
285
  }
200
- static paginate(sql, options = {}) {
201
- let query = sql;
202
- if (options.orderBy) {
203
- query += ` ORDER BY ${options.orderBy} ${options.orderDirection || "ASC"}`;
204
- }
205
- const hasOffset = (options.offset ?? 0) > 0;
206
- const limit = options.limit ?? (hasOffset ? DEFAULT_LIST_LIMIT : void 0);
207
- if (limit) {
208
- query += ` LIMIT ${limit}`;
209
- }
210
- if (hasOffset) {
211
- query += ` OFFSET ${options.offset}`;
212
- }
213
- return query;
286
+ });
287
+
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
+ };
214
299
  }
215
- };
300
+ });
216
301
 
217
302
  // src/infra/database/models/files.model.ts
218
303
  import { uuidv7 } from "uuidv7";
219
- var FilesModel = class {
220
- static TABLE = "files";
221
- static parseFile(fileRaw) {
222
- let metadata = {};
223
- try {
224
- if (fileRaw.metadata) {
225
- metadata = typeof fileRaw.metadata === "string" ? JSON.parse(fileRaw.metadata) : fileRaw.metadata;
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
+ };
226
340
  }
227
- } catch (e) {
228
- metadata = {};
229
- }
230
- return {
231
- _id: fileRaw._id,
232
- ddocId: fileRaw.ddocId,
233
- title: fileRaw.title,
234
- content: fileRaw.content,
235
- localVersion: fileRaw.localVersion,
236
- onchainVersion: fileRaw.onchainVersion,
237
- syncStatus: fileRaw.syncStatus,
238
- isDeleted: fileRaw.isDeleted,
239
- onChainFileId: fileRaw.onChainFileId ?? null,
240
- portalAddress: fileRaw.portalAddress,
241
- metadata: metadata || {},
242
- createdAt: fileRaw.createdAt,
243
- updatedAt: fileRaw.updatedAt,
244
- linkKey: fileRaw.linkKey,
245
- linkKeyNonce: fileRaw.linkKeyNonce,
246
- commentKey: fileRaw.commentKey,
247
- link: fileRaw.link
248
- };
249
- }
250
- static async findAll(portalAddress, limit, skip) {
251
- const whereClause = "isDeleted = 0 AND portalAddress = ?";
252
- const params = [portalAddress];
253
- const countSql = `
341
+ static async findAll(portalAddress, limit, skip) {
342
+ const whereClause = "isDeleted = 0 AND portalAddress = ?";
343
+ const params = [portalAddress];
344
+ const countSql = `
254
345
  SELECT COUNT(*) as count
255
346
  FROM ${this.TABLE}
256
347
  WHERE ${whereClause}
257
348
  `;
258
- const totalResult = await QueryBuilder.selectOne(countSql, params);
259
- const total = totalResult?.count || 0;
260
- const sql = `
349
+ const totalResult = await QueryBuilder.selectOne(countSql, params);
350
+ const total = totalResult?.count || 0;
351
+ const sql = `
261
352
  SELECT *
262
353
  FROM ${this.TABLE}
263
354
  WHERE ${whereClause}
264
355
  `;
265
- const completeSql = QueryBuilder.paginate(sql, {
266
- limit,
267
- offset: skip,
268
- orderBy: "createdAt",
269
- orderDirection: "DESC"
270
- });
271
- const filesRaw = await QueryBuilder.select(completeSql, params);
272
- const files = filesRaw.map(this.parseFile);
273
- const hasNext = skip !== void 0 && limit !== void 0 ? skip + limit < total : false;
274
- return { files, total, hasNext };
275
- }
276
- static async findById(_id, portalAddress) {
277
- const sql = `
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 = `
278
369
  SELECT *
279
370
  FROM ${this.TABLE}
280
371
  WHERE _id = ? AND isDeleted = 0 AND portalAddress = ?
281
372
  `;
282
- const result = await QueryBuilder.selectOne(sql, [_id, portalAddress]);
283
- return result ? this.parseFile(result) : void 0;
284
- }
285
- static async findByIdIncludingDeleted(_id) {
286
- const sql = `
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 = `
287
378
  SELECT *
288
379
  FROM ${this.TABLE}
289
380
  WHERE _id = ?
290
381
  `;
291
- const result = await QueryBuilder.selectOne(sql, [_id]);
292
- return result ? this.parseFile(result) : void 0;
293
- }
294
- static async findByIdExcludingDeleted(_id) {
295
- const sql = `
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 = `
296
387
  SELECT *
297
388
  FROM ${this.TABLE}
298
389
  WHERE _id = ? AND isDeleted = 0
299
390
  `;
300
- const result = await QueryBuilder.selectOne(sql, [_id]);
301
- return result ? this.parseFile(result) : void 0;
302
- }
303
- static async findByDDocId(ddocId, portalAddress) {
304
- const sql = `
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 = `
305
396
  SELECT *
306
397
  FROM ${this.TABLE}
307
398
  WHERE ddocId = ? AND isDeleted = 0 AND portalAddress = ?
308
399
  `;
309
- const result = await QueryBuilder.selectOne(sql, [ddocId, portalAddress]);
310
- return result ? this.parseFile(result) : void 0;
311
- }
312
- static async searchByTitle(searchTerm, portalAddress, limit, skip) {
313
- const sql = `
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 = `
314
405
  SELECT *
315
406
  FROM ${this.TABLE}
316
407
  WHERE LOWER(title) LIKE LOWER(?) AND isDeleted = 0 AND portalAddress = ?
317
408
  `;
318
- const completeSql = QueryBuilder.paginate(sql, {
319
- limit,
320
- offset: skip,
321
- orderBy: "createdAt",
322
- orderDirection: "DESC"
323
- });
324
- const filesRaw = await QueryBuilder.select(completeSql, [`%${searchTerm}%`, portalAddress]);
325
- return filesRaw.map(this.parseFile);
326
- }
327
- static async create(input) {
328
- const _id = uuidv7();
329
- const sql = `
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 = `
330
421
  INSERT INTO ${this.TABLE}
331
422
  (_id, title, content, ddocId, portalAddress)
332
423
  VALUES (?, ?, ?, ?, ?)
333
424
  `;
334
- await QueryBuilder.execute(sql, [_id, input.title, input.content, input.ddocId, input.portalAddress]);
335
- const created = await this.findById(_id, input.portalAddress);
336
- if (!created) {
337
- throw new Error("Failed to create file");
338
- }
339
- return created;
340
- }
341
- static async update(_id, payload, portalAddress) {
342
- const now = (/* @__PURE__ */ new Date()).toISOString();
343
- const keys = [];
344
- const values = [];
345
- for (const [k, v] of Object.entries(payload)) {
346
- if (v !== void 0) {
347
- if (k === "metadata" && typeof v === "object") {
348
- keys.push(`${k} = ?`);
349
- values.push(JSON.stringify(v));
350
- } else {
351
- keys.push(`${k} = ?`);
352
- 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");
353
429
  }
430
+ return created;
354
431
  }
355
- }
356
- keys.push("updatedAt = ?");
357
- values.push(now, _id, portalAddress);
358
- const updateChain = keys.join(", ");
359
- const sql = `UPDATE ${this.TABLE} SET ${updateChain} WHERE _id = ? AND portalAddress = ?`;
360
- await QueryBuilder.execute(sql, values);
361
- const updated = await this.findById(_id, portalAddress);
362
- if (!updated) {
363
- throw new Error("Failed to update file");
364
- }
365
- return updated;
366
- }
367
- static async softDelete(_id) {
368
- const now = (/* @__PURE__ */ new Date()).toISOString();
369
- const sql = `
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 = `
370
461
  UPDATE ${this.TABLE}
371
462
  SET isDeleted = 1, syncStatus = 'pending', updatedAt = ?
372
463
  WHERE _id = ?
373
464
  `;
374
- await QueryBuilder.execute(sql, [now, _id]);
375
- const deleted = await this.findByIdIncludingDeleted(_id);
376
- if (!deleted) {
377
- throw new Error("Failed to delete file");
378
- }
379
- return deleted;
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
+ };
380
473
  }
381
- };
474
+ });
382
475
 
383
476
  // src/infra/database/models/portals.model.ts
384
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
+ });
385
485
 
386
486
  // src/infra/database/models/apikeys.model.ts
387
487
  import { uuidv7 as uuidv73 } from "uuidv7";
388
- var ApiKeysModel = class {
389
- static TABLE = "api_keys";
390
- static async create(input) {
391
- const _id = uuidv73();
392
- const now = (/* @__PURE__ */ new Date()).toISOString();
393
- const sql = `INSERT INTO ${this.TABLE} (_id, apiKeySeed, name, collaboratorAddress, portalAddress, createdAt)
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)
394
500
  VALUES (?, ?, ?, ?, ?, ?)`;
395
- const result = await QueryBuilder.execute(sql, [
396
- _id,
397
- input.apiKeySeed,
398
- input.name,
399
- input.collaboratorAddress,
400
- input.portalAddress,
401
- now
402
- ]);
403
- if (result.changes === 0) {
404
- throw new Error("Failed to create API key");
405
- }
406
- const created = await this.findById(_id);
407
- if (!created) {
408
- throw new Error("Failed to create API key");
409
- }
410
- return created;
411
- }
412
- static async findById(_id) {
413
- const sql = `SELECT _id, apiKeySeed, name, collaboratorAddress, portalAddress, createdAt, isDeleted FROM ${this.TABLE} WHERE _id = ? AND isDeleted = 0`;
414
- return QueryBuilder.selectOne(sql, [_id]);
415
- }
416
- static async findByCollaboratorAddress(collaboratorAddress) {
417
- const sql = `SELECT _id, apiKeySeed, name, collaboratorAddress, portalAddress, createdAt, isDeleted FROM ${this.TABLE} WHERE collaboratorAddress = ? AND isDeleted = 0 LIMIT 1`;
418
- return QueryBuilder.selectOne(sql, [collaboratorAddress]);
419
- }
420
- static async delete(_id) {
421
- const sql = `UPDATE ${this.TABLE} SET isDeleted = 1 WHERE _id = ?`;
422
- await QueryBuilder.execute(sql, [_id]);
423
- }
424
- static async findByPortalAddress(portalAddress) {
425
- const sql = `SELECT _id, apiKeySeed, name, collaboratorAddress, portalAddress, createdAt, isDeleted FROM ${this.TABLE} WHERE portalAddress = ? AND isDeleted = 0`;
426
- return QueryBuilder.selectOne(sql, [portalAddress]);
427
- }
428
- static async findByApiKey(apiKey) {
429
- const sql = `SELECT _id, apiKeySeed, name, collaboratorAddress, portalAddress, createdAt, isDeleted FROM ${this.TABLE} WHERE apiKeySeed = ? AND isDeleted = 0`;
430
- return QueryBuilder.selectOne(sql, [apiKey]);
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
+ };
431
539
  }
432
- };
540
+ });
433
541
 
434
- // src/infra/database/models/events.model.ts
435
- import { uuidv7 as uuidv74 } from "uuidv7";
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
+ });
436
550
 
437
551
  // src/infra/worker/workerSignal.ts
438
552
  import { EventEmitter } from "events";
439
- var WorkerSignal = class extends EventEmitter {
440
- };
441
- var workerSignal = new WorkerSignal();
442
- workerSignal.setMaxListeners(20);
443
553
  function notifyNewEvent() {
444
554
  workerSignal.emit("newEvent");
445
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
+ });
446
567
 
447
568
  // src/infra/database/models/events.model.ts
448
- var RETRY_DELAYS_MS = [5e3, 3e4, 12e4];
449
- var EventsModel = class {
450
- static TABLE = "events";
451
- static async create(input) {
452
- const _id = uuidv74();
453
- const timestamp = Date.now();
454
- const status = "pending";
455
- const sql = `
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 = `
456
585
  INSERT INTO ${this.TABLE}
457
586
  (_id, type, timestamp, fileId, portalAddress, status, retryCount, lastError, lockedAt, nextRetryAt)
458
587
  VALUES (?, ?, ?, ?, ?, ?, 0, NULL, NULL, NULL)
459
588
  `;
460
- await QueryBuilder.execute(sql, [_id, input.type, timestamp, input.fileId, input.portalAddress, status]);
461
- notifyNewEvent();
462
- return {
463
- _id,
464
- type: input.type,
465
- timestamp,
466
- fileId: input.fileId,
467
- portalAddress: input.portalAddress,
468
- status,
469
- retryCount: 0,
470
- lastError: null,
471
- lockedAt: null,
472
- nextRetryAt: null
473
- };
474
- }
475
- static async findById(_id) {
476
- const sql = `SELECT * FROM ${this.TABLE} WHERE _id = ?`;
477
- const row = await QueryBuilder.selectOne(sql, [_id]);
478
- return row ? this.parseEvent(row) : void 0;
479
- }
480
- static async findNextPending() {
481
- const sql = `
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 = `
482
611
  SELECT * FROM ${this.TABLE}
483
612
  WHERE status = 'pending'
484
613
  ORDER BY timestamp ASC
485
614
  LIMIT 1
486
615
  `;
487
- const row = await QueryBuilder.selectOne(sql, []);
488
- return row ? this.parseEvent(row) : void 0;
489
- }
490
- static async findNextEligible(lockedFileIds) {
491
- const now = Date.now();
492
- const exclusionClause = lockedFileIds.length > 0 ? `AND e1.fileId NOT IN (${lockedFileIds.map(() => "?").join(", ")})` : "";
493
- const sql = `
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 = `
494
623
  SELECT e1.* FROM ${this.TABLE} e1
495
624
  WHERE e1.status = 'pending'
496
625
  AND (e1.nextRetryAt IS NULL OR e1.nextRetryAt <= ?)
@@ -504,34 +633,34 @@ var EventsModel = class {
504
633
  ORDER BY e1.timestamp ASC
505
634
  LIMIT 1
506
635
  `;
507
- const params = [now, ...lockedFileIds];
508
- const row = await QueryBuilder.selectOne(sql, params);
509
- return row ? this.parseEvent(row) : void 0;
510
- }
511
- static async markProcessing(_id) {
512
- const sql = `
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 = `
513
642
  UPDATE ${this.TABLE}
514
643
  SET status = 'processing',
515
644
  lockedAt = ?
516
645
  WHERE _id = ?
517
646
  `;
518
- await QueryBuilder.execute(sql, [Date.now(), _id]);
519
- }
520
- static async markProcessed(_id) {
521
- const sql = `
647
+ await QueryBuilder.execute(sql, [Date.now(), _id]);
648
+ }
649
+ static async markProcessed(_id) {
650
+ const sql = `
522
651
  UPDATE ${this.TABLE}
523
652
  SET status = 'processed',
524
653
  lockedAt = NULL
525
654
  WHERE _id = ?
526
655
  `;
527
- await QueryBuilder.execute(sql, [_id]);
528
- }
529
- static async scheduleRetry(_id, errorMsg) {
530
- const event = await this.findById(_id);
531
- if (!event) return;
532
- const delay = RETRY_DELAYS_MS[Math.min(event.retryCount, RETRY_DELAYS_MS.length - 1)];
533
- const nextRetryAt = Date.now() + delay;
534
- const sql = `
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 = `
535
664
  UPDATE ${this.TABLE}
536
665
  SET status = 'pending',
537
666
  retryCount = retryCount + 1,
@@ -540,11 +669,11 @@ var EventsModel = class {
540
669
  lockedAt = NULL
541
670
  WHERE _id = ?
542
671
  `;
543
- await QueryBuilder.execute(sql, [errorMsg, nextRetryAt, _id]);
544
- }
545
- static async scheduleRetryAfter(_id, errorMsg, retryAfterMs) {
546
- const nextRetryAt = Date.now() + retryAfterMs;
547
- const sql = `
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 = `
548
677
  UPDATE ${this.TABLE}
549
678
  SET status = 'pending',
550
679
  lastError = ?,
@@ -552,33 +681,33 @@ var EventsModel = class {
552
681
  lockedAt = NULL
553
682
  WHERE _id = ?
554
683
  `;
555
- await QueryBuilder.execute(sql, [errorMsg, nextRetryAt, _id]);
556
- }
557
- static async markFailed(_id, errorMsg) {
558
- const sql = `
684
+ await QueryBuilder.execute(sql, [errorMsg, nextRetryAt, _id]);
685
+ }
686
+ static async markFailed(_id, errorMsg) {
687
+ const sql = `
559
688
  UPDATE ${this.TABLE}
560
689
  SET status = 'failed',
561
690
  lastError = ?,
562
691
  lockedAt = NULL
563
692
  WHERE _id = ?
564
693
  `;
565
- await QueryBuilder.execute(sql, [errorMsg, _id]);
566
- }
567
- static async listFailed(portalAddress) {
568
- const portalClause = portalAddress != null ? "AND portalAddress = ?" : "";
569
- const sql = `
694
+ await QueryBuilder.execute(sql, [errorMsg, _id]);
695
+ }
696
+ static async listFailed(portalAddress) {
697
+ const portalClause = portalAddress != null ? "AND portalAddress = ?" : "";
698
+ const sql = `
570
699
  SELECT * FROM ${this.TABLE}
571
700
  WHERE status = 'failed'
572
701
  ${portalClause}
573
702
  ORDER BY timestamp ASC
574
703
  `;
575
- const params = portalAddress != null ? [portalAddress] : [];
576
- const rows = await QueryBuilder.select(sql, params);
577
- return rows.map((row) => this.parseEvent(row));
578
- }
579
- static async resetFailedToPending(_id, portalAddress) {
580
- const portalClause = portalAddress != null ? "AND portalAddress = ?" : "";
581
- const sql = `
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 = `
582
711
  UPDATE ${this.TABLE}
583
712
  SET status = 'pending',
584
713
  retryCount = 0,
@@ -589,16 +718,16 @@ var EventsModel = class {
589
718
  AND status = 'failed'
590
719
  ${portalClause}
591
720
  `;
592
- const params = portalAddress != null ? [_id, portalAddress] : [_id];
593
- const result = await QueryBuilder.execute(sql, params);
594
- if (result.changes > 0) {
595
- notifyNewEvent();
596
- }
597
- return result.changes > 0;
598
- }
599
- static async resetAllFailedToPending(portalAddress) {
600
- const portalClause = portalAddress != null ? "AND portalAddress = ?" : "";
601
- const sql = `
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 = `
602
731
  UPDATE ${this.TABLE}
603
732
  SET status = 'pending',
604
733
  retryCount = 0,
@@ -608,15 +737,15 @@ var EventsModel = class {
608
737
  WHERE status = 'failed'
609
738
  ${portalClause}
610
739
  `;
611
- const params = portalAddress != null ? [portalAddress] : [];
612
- const result = await QueryBuilder.execute(sql, params);
613
- if (result.changes > 0) {
614
- notifyNewEvent();
615
- }
616
- return result.changes;
617
- }
618
- static async resetStaleEvents(staleThreshold) {
619
- const sql = `
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 = `
620
749
  UPDATE ${this.TABLE}
621
750
  SET status = 'pending',
622
751
  lockedAt = NULL,
@@ -626,51 +755,113 @@ var EventsModel = class {
626
755
  AND lockedAt IS NOT NULL
627
756
  AND lockedAt < ?
628
757
  `;
629
- const result = await QueryBuilder.execute(sql, [staleThreshold]);
630
- return result.changes;
631
- }
632
- static async setEventPendingOp(_id, userOpHash, payload) {
633
- const sql = `UPDATE ${this.TABLE} SET userOpHash = ?, pendingPayload = ? WHERE _id = ?`;
634
- await QueryBuilder.execute(sql, [userOpHash, JSON.stringify(payload), _id]);
635
- }
636
- static async clearEventPendingOp(_id) {
637
- const sql = `UPDATE ${this.TABLE} SET userOpHash = NULL, pendingPayload = NULL WHERE _id = ?`;
638
- await QueryBuilder.execute(sql, [_id]);
639
- }
640
- static parseEvent(row) {
641
- return {
642
- _id: row._id,
643
- type: row.type,
644
- timestamp: row.timestamp,
645
- fileId: row.fileId,
646
- portalAddress: row.portalAddress ?? "",
647
- status: row.status,
648
- retryCount: row.retryCount,
649
- lastError: row.lastError,
650
- lockedAt: row.lockedAt,
651
- nextRetryAt: row.nextRetryAt,
652
- userOpHash: row.userOpHash ?? null,
653
- pendingPayload: row.pendingPayload ?? null
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
+ }
654
785
  };
655
786
  }
656
- };
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
+ });
657
801
 
658
802
  // src/sdk/key-store.ts
659
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
+ });
660
810
 
661
811
  // src/sdk/auth-token-provider.ts
662
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
+ });
663
819
 
664
- // src/domain/portal/publish.ts
665
- import { fromUint8Array as fromUint8Array3, toUint8Array as toUint8Array3 } from "js-base64";
666
- import { stringToBytes } from "viem";
667
- import { deriveHKDFKey } from "@fileverse/crypto/kdf";
668
- import { generateKeyPairFromSeed } from "@stablelib/ed25519";
669
- import * as ucans2 from "@ucans/ucans";
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
+ });
670
828
 
671
- // src/sdk/smart-agent.ts
672
- import { toHex as toHex2 } from "viem";
673
- import { privateKeyToAccount } from "viem/accounts";
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
+ });
674
865
 
675
866
  // src/sdk/pimlico-utils.ts
676
867
  import { createPublicClient, http, hexToBigInt, toHex, toBytes } from "viem";
@@ -678,24 +869,35 @@ import { createPimlicoClient } from "permissionless/clients/pimlico";
678
869
  import { createSmartAccountClient } from "permissionless";
679
870
  import { toSafeSmartAccount } from "permissionless/accounts";
680
871
  import { entryPoint07Address } from "viem/account-abstraction";
681
-
682
- // src/constants/chains.ts
683
- import { sepolia, gnosis } from "viem/chains";
684
-
685
- // src/constants/index.ts
686
- var NETWORK_NAME = STATIC_CONFIG.NETWORK_NAME;
687
- var UPLOAD_SERVER_URL = STATIC_CONFIG.API_URL;
688
- var CHAIN_MAP = {
689
- gnosis,
690
- sepolia
691
- };
692
- var CHAIN = CHAIN_MAP[NETWORK_NAME];
693
-
694
- // src/sdk/pimlico-utils.ts
695
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
+ });
696
880
 
697
- // src/sdk/file-manager.ts
698
- import { fromUint8Array as fromUint8Array2, toUint8Array as toUint8Array2 } from "js-base64";
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
+ });
699
901
 
700
902
  // src/sdk/file-utils.ts
701
903
  import { getArgon2idHash } from "@fileverse/crypto/argon";
@@ -705,246 +907,419 @@ import { secretBoxEncrypt } from "@fileverse/crypto/nacl";
705
907
  import hkdf from "futoin-hkdf";
706
908
  import tweetnacl from "tweetnacl";
707
909
  import { fromUint8Array, toUint8Array } from "js-base64";
708
-
709
- // src/sdk/file-encryption.ts
710
- import { generateRandomBytes } from "@fileverse/crypto/utils";
711
-
712
- // src/sdk/file-utils.ts
713
910
  import { toAESKey, aesEncrypt } from "@fileverse/crypto/webcrypto";
714
911
  import axios from "axios";
715
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
+ });
716
921
 
717
922
  // src/sdk/file-manager.ts
923
+ import { fromUint8Array as fromUint8Array2, toUint8Array as toUint8Array2 } from "js-base64";
718
924
  import { generateAESKey, exportAESKey } from "@fileverse/crypto/webcrypto";
719
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
+ });
720
995
 
721
996
  // src/errors/rate-limit.ts
722
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
+ });
723
1020
 
724
1021
  // src/infra/worker/worker.ts
725
- var STALE_THRESHOLD_MS = 5 * 60 * 1e3;
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
+ });
726
1045
 
727
1046
  // src/appWorker.ts
728
- var worker = null;
729
1047
  async function closeWorker() {
730
1048
  if (worker) {
731
1049
  await worker.close();
732
1050
  worker = null;
733
1051
  }
734
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
+ });
735
1062
 
736
1063
  // src/infra/reporter.ts
737
- var Reporter = class {
738
- async reportError(message) {
739
- console.error("Error reported:", message);
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();
740
1075
  }
741
- };
742
- var reporter_default = new Reporter();
1076
+ });
743
1077
 
744
- // src/infra/database/adapters/sqlite-adapter.ts
745
- var SqliteAdapter = class {
746
- db;
747
- constructor(dbPath) {
748
- this.db = new Database(dbPath, {
749
- verbose: config.NODE_ENV === "development" ? (msg) => logger.debug(String(msg)) : void 0
750
- });
751
- this.db.pragma("journal_mode = WAL");
752
- this.db.pragma("foreign_keys = ON");
753
- this.db.prepare("SELECT 1").get();
754
- logger.info(`SQLite database connected: ${dbPath}`);
755
- }
756
- async select(sql, params = []) {
757
- const stmt = this.db.prepare(sql);
758
- return stmt.all(params);
759
- }
760
- async selectOne(sql, params = []) {
761
- const stmt = this.db.prepare(sql);
762
- return stmt.get(params);
763
- }
764
- async execute(sql, params = []) {
765
- const stmt = this.db.prepare(sql);
766
- const result = stmt.run(params);
767
- return {
768
- changes: result.changes,
769
- lastInsertRowid: result.lastInsertRowid
770
- };
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();
771
1088
  }
772
- async transaction(callback) {
773
- this.db.exec("SAVEPOINT txn");
774
- try {
775
- const result = await callback(this);
776
- this.db.exec("RELEASE txn");
777
- return result;
778
- } catch (err) {
779
- this.db.exec("ROLLBACK TO txn");
780
- throw err;
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;
781
1111
  }
782
1112
  }
783
- async exec(sql) {
784
- this.db.exec(sql);
785
- }
786
- async close() {
787
- this.db.close();
788
- logger.info("Database connection closed");
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();
789
1119
  }
790
- };
1120
+ });
791
1121
 
792
- // src/infra/database/adapters/pg-adapter.ts
793
- import pg from "pg";
794
- var { Pool } = pg;
795
- var COLUMN_NAME_MAP = {
796
- ddocid: "ddocId",
797
- localversion: "localVersion",
798
- onchainversion: "onchainVersion",
799
- syncstatus: "syncStatus",
800
- isdeleted: "isDeleted",
801
- onchainfileid: "onChainFileId",
802
- portaladdress: "portalAddress",
803
- createdat: "createdAt",
804
- updatedat: "updatedAt",
805
- linkkey: "linkKey",
806
- linkkeynonce: "linkKeyNonce",
807
- commentkey: "commentKey",
808
- portalseed: "portalSeed",
809
- owneraddress: "ownerAddress",
810
- apikeyseed: "apiKeySeed",
811
- collaboratoraddress: "collaboratorAddress",
812
- fileid: "fileId",
813
- retrycount: "retryCount",
814
- lasterror: "lastError",
815
- lockedat: "lockedAt",
816
- nextretryat: "nextRetryAt",
817
- userophash: "userOpHash",
818
- pendingpayload: "pendingPayload",
819
- folderid: "folderId",
820
- folderref: "folderRef",
821
- foldername: "folderName",
822
- metadataipfshash: "metadataIPFSHash",
823
- contentipfshash: "contentIPFSHash",
824
- lasttransactionhash: "lastTransactionHash",
825
- lasttransactionblocknumber: "lastTransactionBlockNumber",
826
- lasttransactionblocktimestamp: "lastTransactionBlockTimestamp",
827
- created_at: "created_at",
828
- updated_at: "updated_at"
829
- };
830
- function translateParams(sql) {
831
- let idx = 0;
832
- return sql.replace(/\?/g, () => `$${++idx}`);
833
- }
834
- function mapRow(row) {
835
- const mapped = {};
836
- for (const [key, value] of Object.entries(row)) {
837
- const mappedKey = COLUMN_NAME_MAP[key] ?? key;
838
- mapped[mappedKey] = value instanceof Date ? value.toISOString() : value;
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");
839
1130
  }
840
- return mapped;
1131
+ return pgModule;
841
1132
  }
842
- var PgClientAdapter = class {
843
- constructor(client) {
844
- this.client = client;
845
- }
846
- async select(sql, params = []) {
847
- const result = await this.client.query(translateParams(sql), params);
848
- return result.rows.map((row) => mapRow(row));
849
- }
850
- async selectOne(sql, params = []) {
851
- const result = await this.client.query(translateParams(sql), params);
852
- return result.rows[0] ? mapRow(result.rows[0]) : void 0;
853
- }
854
- async execute(sql, params = []) {
855
- const result = await this.client.query(translateParams(sql), params);
856
- return { changes: result.rowCount ?? 0, lastInsertRowid: 0 };
857
- }
858
- async transaction(callback) {
859
- await this.client.query("SAVEPOINT nested_txn");
860
- try {
861
- const result = await callback(this);
862
- await this.client.query("RELEASE SAVEPOINT nested_txn");
863
- return result;
864
- } catch (err) {
865
- await this.client.query("ROLLBACK TO SAVEPOINT nested_txn");
866
- throw err;
867
- }
868
- }
869
- async exec(sql) {
870
- await this.client.query(sql);
871
- }
872
- async close() {
873
- }
874
- };
875
- var PgAdapter = class {
876
- pool;
877
- constructor(connectionString) {
878
- const url = new URL(connectionString);
879
- const isLocal = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "::1";
880
- const sslDisabled = connectionString.includes("sslmode=disable");
881
- const needsSsl = !isLocal && !sslDisabled;
882
- this.pool = new Pool({
883
- connectionString,
884
- // pg requires password to be a string; local trust/peer auth uses empty string
885
- password: url.password || "",
886
- max: 20,
887
- idleTimeoutMillis: 3e4,
888
- ssl: needsSsl ? { rejectUnauthorized: false } : void 0
889
- });
890
- logger.info(`PostgreSQL pool created (ssl: ${needsSsl ? "on" : "off"})`);
891
- }
892
- async select(sql, params = []) {
893
- const result = await this.pool.query(translateParams(sql), params);
894
- return result.rows.map((row) => mapRow(row));
895
- }
896
- async selectOne(sql, params = []) {
897
- const result = await this.pool.query(translateParams(sql), params);
898
- return result.rows[0] ? mapRow(result.rows[0]) : void 0;
899
- }
900
- async execute(sql, params = []) {
901
- const result = await this.pool.query(translateParams(sql), params);
902
- return { changes: result.rowCount ?? 0, lastInsertRowid: 0 };
903
- }
904
- async transaction(callback) {
905
- const client = await this.pool.connect();
906
- try {
907
- await client.query("BEGIN");
908
- const clientAdapter = new PgClientAdapter(client);
909
- const result = await callback(clientAdapter);
910
- await client.query("COMMIT");
911
- return result;
912
- } catch (err) {
913
- await client.query("ROLLBACK");
914
- throw err;
915
- } finally {
916
- client.release();
917
- }
918
- }
919
- async exec(sql) {
920
- await this.pool.query(sql);
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
+ }
1215
+ };
921
1216
  }
922
- async close() {
923
- await this.pool.end();
924
- logger.info("PostgreSQL pool closed");
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
+ };
925
1291
  }
926
- };
1292
+ });
927
1293
 
928
1294
  // src/infra/database/connection.ts
929
- var adapter = null;
930
- async function getAdapter() {
1295
+ import path3 from "path";
1296
+ import fs2 from "fs";
1297
+ async function initializeAdapter() {
931
1298
  if (adapter) return adapter;
932
- const databaseUrl = config.DATABASE_URL;
933
- const dbPath = config.DB_PATH;
1299
+ const databaseUrl = process.env.DATABASE_URL;
1300
+ const dbPath = process.env.DB_PATH;
934
1301
  if (databaseUrl) {
935
- adapter = new PgAdapter(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");
936
1305
  } else if (dbPath) {
937
- adapter = new SqliteAdapter(dbPath);
1306
+ const dbDir = path3.dirname(dbPath.trim());
1307
+ if (!fs2.existsSync(dbDir)) {
1308
+ fs2.mkdirSync(dbDir, { recursive: true });
1309
+ }
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");
938
1313
  } else {
939
- throw new Error("Either DATABASE_URL or DB_PATH must be set");
1314
+ throw new Error(
1315
+ "No database configured. Set DATABASE_URL (PostgreSQL) or DB_PATH (SQLite)."
1316
+ );
940
1317
  }
941
1318
  return adapter;
942
1319
  }
943
- function getAdapterSync() {
1320
+ async function getAdapter() {
944
1321
  if (!adapter) {
945
- throw new Error(
946
- "Database adapter not initialized. Call getAdapter() at startup first."
947
- );
1322
+ return initializeAdapter();
948
1323
  }
949
1324
  return adapter;
950
1325
  }
@@ -954,8 +1329,26 @@ async function closeAdapter() {
954
1329
  adapter = null;
955
1330
  }
956
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";
957
1347
 
958
1348
  // src/infra/database/migrations/index.ts
1349
+ init_esm_shims();
1350
+ init_connection();
1351
+ init_infra();
959
1352
  var STABLE_SCHEMA = `
960
1353
  CREATE TABLE IF NOT EXISTS files (
961
1354
  _id TEXT PRIMARY KEY,
@@ -1040,16 +1433,20 @@ CREATE INDEX IF NOT EXISTS idx_folders_folderRef ON folders(folderRef);
1040
1433
  CREATE INDEX IF NOT EXISTS idx_folders_created_at ON folders(created_at);
1041
1434
  `;
1042
1435
  async function runMigrations() {
1043
- const adapter2 = getAdapterSync();
1436
+ const adapter2 = await getAdapter();
1044
1437
  await adapter2.exec(STABLE_SCHEMA);
1045
1438
  logger.debug("Database schema ready");
1046
1439
  }
1047
1440
 
1048
1441
  // src/commands/listCommand.ts
1442
+ init_esm_shims();
1049
1443
  import { Command } from "commander";
1050
1444
  import Table from "cli-table3";
1051
1445
 
1052
1446
  // src/domain/file/index.ts
1447
+ init_esm_shims();
1448
+ init_models();
1449
+ init_constants2();
1053
1450
  import { generate } from "short-uuid";
1054
1451
  async function listFiles(params) {
1055
1452
  const { limit, skip, portalAddress } = params;
@@ -1160,6 +1557,7 @@ var deleteFile = async (ddocId, portalAddress) => {
1160
1557
  };
1161
1558
 
1162
1559
  // src/commands/utils/util.ts
1560
+ init_esm_shims();
1163
1561
  var columnNames = {
1164
1562
  index: "#",
1165
1563
  ddocId: "DDoc ID",
@@ -1236,12 +1634,15 @@ After setup, you can use ddctl commands.
1236
1634
  }
1237
1635
 
1238
1636
  // src/commands/listCommand.ts
1637
+ init_config();
1638
+ init_models();
1239
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) => {
1240
1640
  try {
1241
1641
  const runtimeConfig = getRuntimeConfig();
1242
1642
  const apiKey = runtimeConfig.API_KEY;
1243
1643
  validateApiKey(apiKey);
1244
- const portalAddress = (await ApiKeysModel.findByApiKey(apiKey))?.portalAddress;
1644
+ const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
1645
+ const portalAddress = apiKeyInfo?.portalAddress;
1245
1646
  if (!portalAddress) throw new Error("Portal address is required");
1246
1647
  const params = {
1247
1648
  limit: options.limit,
@@ -1303,14 +1704,18 @@ Found ${result.total} ddoc(s):
1303
1704
  });
1304
1705
 
1305
1706
  // src/commands/getCommand.ts
1707
+ init_esm_shims();
1306
1708
  import { Command as Command2 } from "commander";
1307
1709
  import Table2 from "cli-table3";
1710
+ init_config();
1711
+ init_models();
1308
1712
  var getCommand = new Command2().name("get").description("Get a ddoc by its ID").argument("<ddocId>", "The ddoc ID to retrieve").action(async (ddocId) => {
1309
1713
  try {
1310
1714
  const runtimeConfig = getRuntimeConfig();
1311
1715
  const apiKey = runtimeConfig.API_KEY;
1312
1716
  validateApiKey(apiKey);
1313
- const portalAddress = (await ApiKeysModel.findByApiKey(apiKey))?.portalAddress;
1717
+ const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
1718
+ const portalAddress = apiKeyInfo?.portalAddress;
1314
1719
  if (!portalAddress) throw new Error("Portal address is required");
1315
1720
  const file = await getFile(ddocId, portalAddress);
1316
1721
  if (!file) {
@@ -1365,26 +1770,30 @@ Link: ${file.link}
1365
1770
  });
1366
1771
 
1367
1772
  // src/commands/createCommand.ts
1773
+ init_esm_shims();
1368
1774
  import { Command as Command3 } from "commander";
1369
- import * as fs2 from "fs";
1370
- import * as path2 from "path";
1775
+ import * as fs3 from "fs";
1776
+ import * as path4 from "path";
1371
1777
  import Table3 from "cli-table3";
1778
+ init_config();
1779
+ init_models();
1372
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) => {
1373
1781
  try {
1374
- if (!fs2.existsSync(filepath)) {
1782
+ if (!fs3.existsSync(filepath)) {
1375
1783
  throw new Error(`File not found: ${filepath}`);
1376
1784
  }
1377
1785
  const runtimeConfig = getRuntimeConfig();
1378
1786
  const apiKey = runtimeConfig.API_KEY;
1379
1787
  validateApiKey(apiKey);
1380
- const portalAddress = (await ApiKeysModel.findByApiKey(apiKey))?.portalAddress;
1788
+ const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
1789
+ const portalAddress = apiKeyInfo?.portalAddress;
1381
1790
  if (!portalAddress) throw new Error("Portal address is required");
1382
- const content = fs2.readFileSync(filepath, "utf-8");
1791
+ const content = fs3.readFileSync(filepath, "utf-8");
1383
1792
  if (!content || content.trim().length === 0) {
1384
1793
  console.error("Error creating ddoc: File content cannot be empty. Add some content to the file and try again.");
1385
1794
  process.exit(1);
1386
1795
  }
1387
- const basename3 = path2.basename(filepath);
1796
+ const basename3 = path4.basename(filepath);
1388
1797
  const lastDotIndex = basename3.lastIndexOf(".");
1389
1798
  const title = lastDotIndex > 0 ? basename3.substring(0, lastDotIndex) : basename3;
1390
1799
  const file = await createFile({ title, content, portalAddress });
@@ -1428,12 +1837,15 @@ var createCommand = new Command3().name("create").description("Create a new ddoc
1428
1837
  });
1429
1838
 
1430
1839
  // src/commands/updateCommand.ts
1431
- import * as fs3 from "fs";
1432
- import * as path3 from "path";
1840
+ init_esm_shims();
1841
+ import * as fs4 from "fs";
1842
+ import * as path5 from "path";
1433
1843
  import * as os2 from "os";
1434
1844
  import { Command as Command4 } from "commander";
1435
1845
  import { spawnSync } from "child_process";
1436
1846
  import Table4 from "cli-table3";
1847
+ init_models();
1848
+ init_config();
1437
1849
  function showTable(updatedFile) {
1438
1850
  const table = new Table4({
1439
1851
  head: [
@@ -1473,7 +1885,8 @@ var updateCommand = new Command4().name("update").description("Update an existin
1473
1885
  const runtimeConfig = getRuntimeConfig();
1474
1886
  const apiKey = runtimeConfig.API_KEY;
1475
1887
  validateApiKey(apiKey);
1476
- const portalAddress = (await ApiKeysModel.findByApiKey(apiKey))?.portalAddress;
1888
+ const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
1889
+ const portalAddress = apiKeyInfo?.portalAddress;
1477
1890
  if (!portalAddress) throw new Error("Portal address is required");
1478
1891
  const file = await getFile(ddocId, portalAddress);
1479
1892
  if (!file) {
@@ -1481,11 +1894,13 @@ var updateCommand = new Command4().name("update").description("Update an existin
1481
1894
  }
1482
1895
  const filePath = options?.file ?? "";
1483
1896
  if (filePath) {
1484
- const content = fs3.readFileSync(filePath, "utf-8");
1897
+ const content = fs4.readFileSync(filePath, "utf-8");
1485
1898
  if (!content || content.trim().length === 0) {
1486
1899
  throw new Error(`file content cannot be empty`);
1487
1900
  }
1488
- const title = path3.basename(filePath);
1901
+ const basename3 = path5.basename(filePath);
1902
+ const lastDotIndex = basename3.lastIndexOf(".");
1903
+ const title = lastDotIndex > 0 ? basename3.substring(0, lastDotIndex) : basename3;
1489
1904
  const payload = {
1490
1905
  title,
1491
1906
  content
@@ -1495,15 +1910,15 @@ var updateCommand = new Command4().name("update").description("Update an existin
1495
1910
  showTable(updatedFile);
1496
1911
  return;
1497
1912
  }
1498
- const tmpFilePath = path3.join(os2.tmpdir(), `tmp-${ddocId}-${Date.now()}.txt`);
1499
- fs3.writeFileSync(tmpFilePath, file.content);
1913
+ const tmpFilePath = path5.join(os2.tmpdir(), `tmp-${ddocId}-${Date.now()}.txt`);
1914
+ fs4.writeFileSync(tmpFilePath, file.content);
1500
1915
  const editor = process.env.EDITOR || "vi";
1501
1916
  const result = spawnSync(editor, [tmpFilePath], { stdio: "inherit" });
1502
1917
  if (result.status === 0) {
1503
- const newContent = fs3.readFileSync(tmpFilePath, "utf-8");
1918
+ const newContent = fs4.readFileSync(tmpFilePath, "utf-8");
1504
1919
  if (newContent === file.content) {
1505
1920
  console.log(`No changes made. Update cancelled.`);
1506
- fs3.unlinkSync(tmpFilePath);
1921
+ fs4.unlinkSync(tmpFilePath);
1507
1922
  return;
1508
1923
  }
1509
1924
  const payload = {
@@ -1515,7 +1930,7 @@ var updateCommand = new Command4().name("update").description("Update an existin
1515
1930
  console.log("\n\u2713 Ddoc updated successfully!\n");
1516
1931
  showTable(updatedFile);
1517
1932
  }
1518
- fs3.unlinkSync(tmpFilePath);
1933
+ fs4.unlinkSync(tmpFilePath);
1519
1934
  } catch (error) {
1520
1935
  console.error("Error updating ddoc:", error.message);
1521
1936
  throw error;
@@ -1523,13 +1938,17 @@ var updateCommand = new Command4().name("update").description("Update an existin
1523
1938
  });
1524
1939
 
1525
1940
  // src/commands/deleteCommand.ts
1941
+ init_esm_shims();
1526
1942
  import { Command as Command5 } from "commander";
1943
+ init_config();
1944
+ init_models();
1527
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) => {
1528
1946
  try {
1529
1947
  const runtimeConfig = getRuntimeConfig();
1530
1948
  const apiKey = runtimeConfig.API_KEY;
1531
1949
  validateApiKey(apiKey);
1532
- const portalAddress = (await ApiKeysModel.findByApiKey(apiKey))?.portalAddress;
1950
+ const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
1951
+ const portalAddress = apiKeyInfo?.portalAddress;
1533
1952
  if (!portalAddress) throw new Error("Portal address is required");
1534
1953
  for (const ddocId of ddocIds) {
1535
1954
  try {
@@ -1546,14 +1965,18 @@ var deleteCommand = new Command5().name("delete").description("Delete one or mor
1546
1965
  });
1547
1966
 
1548
1967
  // src/commands/downloadCommand.ts
1968
+ init_esm_shims();
1549
1969
  import { Command as Command6 } from "commander";
1550
- import * as fs4 from "fs";
1970
+ import * as fs5 from "fs";
1971
+ init_config();
1972
+ init_models();
1551
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) => {
1552
1974
  try {
1553
1975
  const runtimeConfig = getRuntimeConfig();
1554
1976
  const apiKey = runtimeConfig.API_KEY;
1555
1977
  validateApiKey(apiKey);
1556
- const portalAddress = (await ApiKeysModel.findByApiKey(apiKey))?.portalAddress;
1978
+ const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
1979
+ const portalAddress = apiKeyInfo?.portalAddress;
1557
1980
  if (!portalAddress) throw new Error("Portal address is required");
1558
1981
  const file = await getFile(ddocId, portalAddress);
1559
1982
  if (!file) {
@@ -1564,7 +1987,7 @@ var downloadCommand = new Command6().name("download").description("Download a dd
1564
1987
  if (options.output) {
1565
1988
  outputFilename = options.output.endsWith(".md") ? options.output : `${options.output}.md`;
1566
1989
  }
1567
- fs4.writeFileSync(outputFilename, file.content, "utf-8");
1990
+ fs5.writeFileSync(outputFilename, file.content, "utf-8");
1568
1991
  console.log(`
1569
1992
  \u2713 Ddoc downloaded successfully to: ${outputFilename}
1570
1993
  `);
@@ -1575,13 +1998,17 @@ var downloadCommand = new Command6().name("download").description("Download a dd
1575
1998
  });
1576
1999
 
1577
2000
  // src/commands/viewCommand.ts
2001
+ init_esm_shims();
1578
2002
  import { Command as Command7 } from "commander";
2003
+ init_config();
2004
+ init_models();
1579
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) => {
1580
2006
  try {
1581
2007
  const runtimeConfig = getRuntimeConfig();
1582
2008
  const apiKey = runtimeConfig.API_KEY;
1583
2009
  validateApiKey(apiKey);
1584
- const portalAddress = (await ApiKeysModel.findByApiKey(apiKey))?.portalAddress;
2010
+ const apiKeyInfo = await ApiKeysModel.findByApiKey(apiKey);
2011
+ const portalAddress = apiKeyInfo?.portalAddress;
1585
2012
  if (!portalAddress) throw new Error("Portal address is required");
1586
2013
  const file = await getFile(ddocId, portalAddress);
1587
2014
  if (!file) {
@@ -1619,6 +2046,8 @@ Showing ${linesToShow} of ${totalLines} line${totalLines === 1 ? "" : "s"}
1619
2046
  });
1620
2047
 
1621
2048
  // src/commands/eventsCommand.ts
2049
+ init_esm_shims();
2050
+ init_models();
1622
2051
  import { Command as Command8 } from "commander";
1623
2052
  import Table5 from "cli-table3";
1624
2053
  var MAX_ERROR_LEN = 60;
@@ -1683,8 +2112,10 @@ eventsCommand.command("retry-all").description("Retry all failed events").action
1683
2112
  });
1684
2113
 
1685
2114
  // src/commands/index.ts
2115
+ init_infra();
1686
2116
  logger.level = "error";
1687
- var program = new Command9().name("ddctl").description("CLI tool to manage your ddocs").version("0.0.2").addHelpText("beforeAll", "\n").addHelpText("afterAll", "\n");
2117
+ await runMigrations();
2118
+ var program = new Command9().name("ddctl").description("CLI tool to manage your ddocs").version("0.0.3").addHelpText("beforeAll", "\n").addHelpText("afterAll", "\n");
1688
2119
  program.addCommand(listCommand);
1689
2120
  program.addCommand(getCommand);
1690
2121
  program.addCommand(createCommand);
@@ -1693,14 +2124,10 @@ program.addCommand(deleteCommand);
1693
2124
  program.addCommand(downloadCommand);
1694
2125
  program.addCommand(viewCommand);
1695
2126
  program.addCommand(eventsCommand);
1696
- (async () => {
1697
- await getAdapter();
1698
- await runMigrations();
1699
- await program.parseAsync();
1700
- })().then(async () => {
2127
+ program.parseAsync().then(async () => {
1701
2128
  try {
1702
2129
  await closeWorker();
1703
- await closeAdapter();
2130
+ await closeDatabase();
1704
2131
  } catch (error) {
1705
2132
  }
1706
2133
  process.exit(0);