admindb 2.1.0 → 2.1.1

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.
Files changed (178) hide show
  1. package/README.md +1 -1
  2. package/dist/app.d.ts +1 -69
  3. package/dist/app.js +1 -257
  4. package/dist/auth/config.d.ts +1 -19
  5. package/dist/auth/config.js +1 -147
  6. package/dist/auth/crypto.d.ts +1 -27
  7. package/dist/auth/crypto.js +1 -133
  8. package/dist/auth/index.d.ts +1 -5
  9. package/dist/auth/index.js +1 -22
  10. package/dist/auth/middleware.d.ts +1 -14
  11. package/dist/auth/middleware.js +1 -100
  12. package/dist/auth/routes.d.ts +1 -7
  13. package/dist/auth/routes.js +1 -78
  14. package/dist/auth/types.d.ts +1 -35
  15. package/dist/auth/types.js +1 -11
  16. package/dist/cli/args.d.ts +1 -45
  17. package/dist/cli/args.js +1 -328
  18. package/dist/cli/config.d.ts +1 -56
  19. package/dist/cli/config.js +1 -133
  20. package/dist/cli/index.d.ts +1 -4
  21. package/dist/cli/index.js +1 -21
  22. package/dist/cli/runner.d.ts +1 -1
  23. package/dist/cli/runner.js +1 -222
  24. package/dist/cli.d.ts +1 -2
  25. package/dist/cli.js +1 -5
  26. package/dist/data/datasets.d.ts +1 -17
  27. package/dist/data/datasets.js +1 -133
  28. package/dist/data/detector.d.ts +1 -30
  29. package/dist/data/detector.js +1 -472
  30. package/dist/data/engine.d.ts +1 -10
  31. package/dist/data/engine.js +1 -211
  32. package/dist/data/index.d.ts +1 -5
  33. package/dist/data/index.js +1 -22
  34. package/dist/data/strategies.d.ts +1 -30
  35. package/dist/data/strategies.js +1 -343
  36. package/dist/data/types.d.ts +1 -73
  37. package/dist/data/types.js +1 -8
  38. package/dist/db/database.d.ts +1 -119
  39. package/dist/db/database.js +1 -471
  40. package/dist/db/export.d.ts +1 -12
  41. package/dist/db/export.js +1 -42
  42. package/dist/db/filters.d.ts +1 -22
  43. package/dist/db/filters.js +1 -158
  44. package/dist/db/index.d.ts +1 -8
  45. package/dist/db/index.js +1 -25
  46. package/dist/db/introspection.d.ts +1 -6
  47. package/dist/db/introspection.js +1 -172
  48. package/dist/db/manager.d.ts +1 -81
  49. package/dist/db/manager.js +1 -397
  50. package/dist/db/migrations.d.ts +1 -5
  51. package/dist/db/migrations.js +1 -110
  52. package/dist/db/postgres.d.ts +1 -85
  53. package/dist/db/postgres.js +1 -745
  54. package/dist/db/types.d.ts +1 -206
  55. package/dist/db/types.js +1 -7
  56. package/dist/index.d.ts +1 -23
  57. package/dist/index.js +1 -66
  58. package/dist/public/js/api.js +1 -47
  59. package/dist/public/js/app.js +1 -262
  60. package/dist/public/js/browse.js +1 -1371
  61. package/dist/public/js/databases.js +1 -235
  62. package/dist/public/js/designer.js +1 -258
  63. package/dist/public/js/forms.js +1 -826
  64. package/dist/public/js/icons.js +1 -51
  65. package/dist/public/js/inspector.js +1 -638
  66. package/dist/public/js/query.js +1 -322
  67. package/dist/public/js/schema.js +1 -447
  68. package/dist/public/js/seed.js +1 -1090
  69. package/dist/routes/api/helpers.d.ts +1 -42
  70. package/dist/routes/api/helpers.js +1 -133
  71. package/dist/routes/api/import-export.d.ts +1 -3
  72. package/dist/routes/api/import-export.js +1 -85
  73. package/dist/routes/api/index.d.ts +1 -4
  74. package/dist/routes/api/index.js +1 -37
  75. package/dist/routes/api/query.d.ts +1 -3
  76. package/dist/routes/api/query.js +1 -76
  77. package/dist/routes/api/rows.d.ts +1 -3
  78. package/dist/routes/api/rows.js +1 -373
  79. package/dist/routes/api/seed.d.ts +1 -3
  80. package/dist/routes/api/seed.js +1 -82
  81. package/dist/routes/api/tables.d.ts +1 -3
  82. package/dist/routes/api/tables.js +1 -160
  83. package/dist/routes/databases.d.ts +1 -26
  84. package/dist/routes/databases.js +1 -230
  85. package/dist/routes/index.d.ts +1 -3
  86. package/dist/routes/index.js +1 -20
  87. package/dist/routes/pages.d.ts +1 -9
  88. package/dist/routes/pages.js +1 -390
  89. package/dist/serverless.d.ts +1 -40
  90. package/dist/serverless.js +1 -210
  91. package/dist/sql/classifier.d.ts +1 -19
  92. package/dist/sql/classifier.js +1 -37
  93. package/dist/sql/generator.d.ts +1 -81
  94. package/dist/sql/generator.js +1 -348
  95. package/dist/sql/index.d.ts +1 -2
  96. package/dist/sql/index.js +1 -19
  97. package/dist/types/api.d.ts +1 -412
  98. package/dist/types/api.js +1 -9
  99. package/dist/utils/colors.d.ts +1 -40
  100. package/dist/utils/colors.js +1 -64
  101. package/dist/utils/common.d.ts +1 -50
  102. package/dist/utils/common.js +1 -229
  103. package/dist/utils/csv.d.ts +1 -15
  104. package/dist/utils/csv.js +1 -80
  105. package/dist/utils/datatype.d.ts +1 -49
  106. package/dist/utils/datatype.js +1 -222
  107. package/dist/utils/icons.d.ts +1 -11
  108. package/dist/utils/icons.js +1 -72
  109. package/dist/utils/index.d.ts +1 -4
  110. package/dist/utils/index.js +1 -21
  111. package/dist/utils/logger.d.ts +1 -10
  112. package/dist/utils/logger.js +1 -40
  113. package/dist/views/layouts/main.hbs +0 -4
  114. package/dist/views/pages/databases.hbs +0 -18
  115. package/dist/views/pages/designer.hbs +0 -10
  116. package/dist/views/pages/error.hbs +0 -2
  117. package/dist/views/pages/form.hbs +0 -5
  118. package/dist/views/pages/home.hbs +0 -8
  119. package/dist/views/pages/login.hbs +0 -13
  120. package/dist/views/pages/query.hbs +0 -9
  121. package/dist/views/pages/schema.hbs +0 -20
  122. package/dist/views/pages/seed.hbs +0 -31
  123. package/dist/views/pages/table.hbs +0 -14
  124. package/dist/views/partials/icon.hbs +0 -1
  125. package/dist/views/partials/navbar.hbs +0 -6
  126. package/dist/views/partials/sidebar.hbs +0 -8
  127. package/package.json +3 -2
  128. package/dist/app.js.map +0 -1
  129. package/dist/auth/config.js.map +0 -1
  130. package/dist/auth/crypto.js.map +0 -1
  131. package/dist/auth/index.js.map +0 -1
  132. package/dist/auth/middleware.js.map +0 -1
  133. package/dist/auth/routes.js.map +0 -1
  134. package/dist/auth/types.js.map +0 -1
  135. package/dist/cli/args.js.map +0 -1
  136. package/dist/cli/config.js.map +0 -1
  137. package/dist/cli/index.js.map +0 -1
  138. package/dist/cli/runner.js.map +0 -1
  139. package/dist/cli.js.map +0 -1
  140. package/dist/data/datasets.js.map +0 -1
  141. package/dist/data/detector.js.map +0 -1
  142. package/dist/data/engine.js.map +0 -1
  143. package/dist/data/index.js.map +0 -1
  144. package/dist/data/strategies.js.map +0 -1
  145. package/dist/data/types.js.map +0 -1
  146. package/dist/db/database.js.map +0 -1
  147. package/dist/db/export.js.map +0 -1
  148. package/dist/db/filters.js.map +0 -1
  149. package/dist/db/index.js.map +0 -1
  150. package/dist/db/introspection.js.map +0 -1
  151. package/dist/db/manager.js.map +0 -1
  152. package/dist/db/migrations.js.map +0 -1
  153. package/dist/db/postgres.js.map +0 -1
  154. package/dist/db/types.js.map +0 -1
  155. package/dist/index.js.map +0 -1
  156. package/dist/public/css/input.css +0 -302
  157. package/dist/routes/api/helpers.js.map +0 -1
  158. package/dist/routes/api/import-export.js.map +0 -1
  159. package/dist/routes/api/index.js.map +0 -1
  160. package/dist/routes/api/query.js.map +0 -1
  161. package/dist/routes/api/rows.js.map +0 -1
  162. package/dist/routes/api/seed.js.map +0 -1
  163. package/dist/routes/api/tables.js.map +0 -1
  164. package/dist/routes/databases.js.map +0 -1
  165. package/dist/routes/index.js.map +0 -1
  166. package/dist/routes/pages.js.map +0 -1
  167. package/dist/serverless.js.map +0 -1
  168. package/dist/sql/classifier.js.map +0 -1
  169. package/dist/sql/generator.js.map +0 -1
  170. package/dist/sql/index.js.map +0 -1
  171. package/dist/types/api.js.map +0 -1
  172. package/dist/utils/colors.js.map +0 -1
  173. package/dist/utils/common.js.map +0 -1
  174. package/dist/utils/csv.js.map +0 -1
  175. package/dist/utils/datatype.js.map +0 -1
  176. package/dist/utils/icons.js.map +0 -1
  177. package/dist/utils/index.js.map +0 -1
  178. package/dist/utils/logger.js.map +0 -1
@@ -1,390 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerPages = registerPages;
4
- const export_1 = require("../db/export");
5
- const generator_1 = require("../sql/generator");
6
- const common_1 = require("../utils/common");
7
- const datatype_1 = require("../utils/datatype");
8
- const index_1 = require("../data/index");
9
- function buildDisplayRows(rawRows, info, table, basePath = '') {
10
- const pkCols = info.primaryKey.length ? info.primaryKey : ['_rowid_'];
11
- return rawRows.map((row) => {
12
- const pkEncoded = (0, common_1.encodePk)(pkCols.map((c) => row[c]));
13
- return {
14
- cells: info.columns.map((c) => {
15
- const raw = row[c.name];
16
- const v = (0, common_1.normalizeCell)(raw);
17
- const isNull = v == null;
18
- const typeUpper = (c.type || '').toUpperCase();
19
- const isBlob = typeUpper.includes('BLOB') || typeUpper.includes('BYTEA') || Buffer.isBuffer(raw) || raw instanceof Uint8Array || (typeof v === 'string' && (/^0x[0-9a-f]{8,}$/i.test(v) || /^\\x[0-9a-f]{8,}$/i.test(v)));
20
- let isJson = false;
21
- let isImage = false;
22
- let isUrl = false;
23
- let isColor = false;
24
- let blobSize = '';
25
- let blobMime = '';
26
- let blobExt = '';
27
- let blobUrl = '';
28
- if (!isNull) {
29
- const str = String(v);
30
- if (isBlob) {
31
- let buf;
32
- if (Buffer.isBuffer(raw) || raw instanceof Uint8Array) {
33
- buf = Buffer.isBuffer(raw) ? raw : Buffer.from(raw);
34
- }
35
- else if (typeof v === 'string' && /^0x[0-9a-f]*$/i.test(v)) {
36
- buf = Buffer.from(v.slice(2), 'hex');
37
- }
38
- else if (typeof v === 'string' && /^\\x[0-9a-f]*$/i.test(v)) {
39
- buf = Buffer.from(v.slice(2), 'hex');
40
- }
41
- else {
42
- buf = Buffer.from(str, 'utf8');
43
- }
44
- const mimeInfo = (0, datatype_1.sniffMimeType)(buf);
45
- blobSize = (0, common_1.formatBytes)(buf.length);
46
- blobMime = mimeInfo.mime;
47
- blobExt = mimeInfo.ext;
48
- isImage = mimeInfo.isImage;
49
- if (table && pkEncoded) {
50
- blobUrl = `${basePath}/api/tables/${encodeURIComponent(table)}/row/${encodeURIComponent(pkEncoded)}/blob/${encodeURIComponent(c.name)}`;
51
- }
52
- }
53
- else if ((0, datatype_1.isJsonString)(v) || typeUpper.includes('JSON')) {
54
- isJson = (0, datatype_1.isJsonString)(v);
55
- }
56
- else {
57
- if (/^https?:\/\/[^\s$.?#].[^\s]*$/i.test(str)) {
58
- isUrl = true;
59
- }
60
- else if (/^#(?:[0-9a-fA-F]{3}){1,2}$|^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+/i.test(str)) {
61
- isColor = true;
62
- }
63
- }
64
- }
65
- return {
66
- name: c.name,
67
- value: v,
68
- isNull,
69
- display: isNull ? '' : String(v),
70
- type: c.type,
71
- isBlob,
72
- isJson,
73
- isImage,
74
- isUrl,
75
- isColor,
76
- blobSize,
77
- blobMime,
78
- blobExt,
79
- blobUrl,
80
- };
81
- }),
82
- pkEncoded,
83
- };
84
- });
85
- }
86
- function registerPages(router, ctx) {
87
- const { db } = ctx;
88
- const notFound = (res, message) => {
89
- res.status(404).render('pages/error', { title: 'Not found', status: 404, error: message });
90
- };
91
- // Home / browse overview.
92
- router.get('/', async (_req, res, next) => {
93
- try {
94
- const names = res.locals.tables ?? [];
95
- const internalNames = res.locals.internalTables ?? [];
96
- let colCountsMap = {};
97
- if (db.dialect === 'postgres') {
98
- const colRes = await db.all(`SELECT table_name, count(*)::int AS cols FROM information_schema.columns WHERE table_schema = 'public' GROUP BY table_name;`);
99
- if (colRes.success && colRes.data) {
100
- for (const row of colRes.data) {
101
- if (row && typeof row.table_name === 'string') {
102
- colCountsMap[row.table_name] = Number(row.cols ?? 0);
103
- }
104
- }
105
- }
106
- }
107
- const [stats, saved] = await Promise.all([
108
- Promise.all(names.map(async (name) => {
109
- const countR = await db.getRowCount(name);
110
- const cols = colCountsMap[name] !== undefined
111
- ? colCountsMap[name]
112
- : (await db.getTableInfo(name)).data?.columns.length ?? 0;
113
- return {
114
- name,
115
- count: countR.success ? countR.data : 0,
116
- cols,
117
- };
118
- })),
119
- db.listSavedQueries(),
120
- ]);
121
- const counts = {};
122
- const cols = {};
123
- let totalRows = 0;
124
- for (const s of stats) {
125
- counts[s.name] = s.count;
126
- cols[s.name] = s.cols;
127
- totalRows += s.count;
128
- }
129
- res.render('pages/home', {
130
- title: 'Home',
131
- tables: names,
132
- counts,
133
- cols,
134
- totalRows,
135
- savedQueries: saved.success ? (saved.data?.length ?? 0) : 0,
136
- internalCount: internalNames.length,
137
- dbPath: db.path,
138
- });
139
- }
140
- catch (err) {
141
- next(err);
142
- }
143
- });
144
- // Browse a table's rows.
145
- router.get('/tables/:table', async (req, res, next) => {
146
- try {
147
- const table = req.params.table;
148
- const info = await db.getTableInfo(table);
149
- if (!info.success || !info.data || info.data.columns.length === 0) {
150
- return notFound(res, `Table "${table}" does not exist.`);
151
- }
152
- const page = Math.max(1, Number.parseInt(String(req.query.page ?? '1'), 10) || 1);
153
- const pageSize = Math.max(1, Number.parseInt(String(req.query.size ?? '50'), 10) || 50);
154
- const orderBy = req.query.orderBy ? String(req.query.orderBy) : undefined;
155
- const orderDir = String(req.query.orderDir ?? 'asc').toLowerCase() === 'desc' ? 'desc' : 'asc';
156
- const filters = (0, common_1.parseFilters)(req.query.f);
157
- const filterQS = (0, common_1.filtersToQS)(filters);
158
- const [countR, rowsR, refsR] = await Promise.all([
159
- db.getRowCount(table, filters),
160
- db.getRows(table, { page, limit: pageSize, orderBy, orderDir, filters }),
161
- db.getReferencingTables(table),
162
- ]);
163
- const count = countR.success ? countR.data : 0;
164
- const rawRows = (rowsR.data ?? []);
165
- const pages = Math.max(1, Math.ceil(count / pageSize));
166
- const basePath = String(res.locals.basePath ?? '');
167
- const sizes = [25, 50, 100, 250];
168
- const colHeaders = info.data.columns.map((c) => {
169
- const active = c.name === orderBy;
170
- const nextDir = active ? (orderDir === 'asc' ? 'desc' : 'asc') : 'asc';
171
- const qs = `page=1&size=${pageSize}&orderBy=${encodeURIComponent(c.name)}&orderDir=${nextDir}`;
172
- return {
173
- name: c.name,
174
- pk: c.pk,
175
- type: c.type,
176
- active,
177
- dir: active ? orderDir : null,
178
- href: `${basePath}/tables/${encodeURIComponent(table)}?${qs}${filterQS ? '&' + filterQS : ''}`,
179
- };
180
- });
181
- const refColumns = (refsR.data ?? [])
182
- .filter((r) => !r.table.startsWith('_'))
183
- .map((rt) => {
184
- const ref = rt.refs[0];
185
- return { table: rt.table, from: ref?.from ?? '', to: ref?.to ?? '' };
186
- });
187
- // Per-row reference counts: parallel query per referencing table.
188
- const countEntries = await Promise.all(refColumns.map(async (col) => {
189
- const values = rawRows
190
- .map((r) => r[col.to])
191
- .filter((v) => v !== null && v !== undefined);
192
- if (!values.length)
193
- return [col.table, new Map()];
194
- const placeholders = values.map(() => '?').join(', ');
195
- const cR = await db.all(`SELECT ${(0, generator_1.quoteIdentifier)(col.from)} AS fk, COUNT(*) AS c FROM ${(0, generator_1.quoteIdentifier)(col.table)} WHERE ${(0, generator_1.quoteIdentifier)(col.from)} IN (${placeholders}) GROUP BY ${(0, generator_1.quoteIdentifier)(col.from)}`, values);
196
- const map = new Map();
197
- for (const row of (cR.data ?? []))
198
- map.set(String(row.fk), Number(row.c));
199
- return [col.table, map];
200
- }));
201
- const countMap = new Map(countEntries);
202
- const rows = buildDisplayRows(rawRows, info.data, table, basePath).map((dr, i) => {
203
- const raw = rawRows[i];
204
- const refs = refColumns.map((col) => {
205
- const v = raw[col.to];
206
- return {
207
- table: col.table,
208
- from: col.from,
209
- to: col.to,
210
- value: v == null ? '' : String(v),
211
- count: v == null ? 0 : (countMap.get(col.table)?.get(String(v)) ?? 0),
212
- };
213
- });
214
- return { ...dr, refs };
215
- });
216
- res.locals.currentTable = table;
217
- res.render('pages/table', {
218
- title: table,
219
- table,
220
- info: info.data,
221
- rows,
222
- count,
223
- page,
224
- pageSize,
225
- pages,
226
- pkCols: info.data.primaryKey,
227
- colNames: info.data.columns.map((c) => c.name),
228
- colHeaders,
229
- refColumns,
230
- hasPk: true,
231
- orderBy: orderBy ?? '',
232
- orderDir,
233
- sizes,
234
- filters,
235
- filterQS,
236
- firstRow: count === 0 ? 0 : (page - 1) * pageSize + 1,
237
- lastRow: Math.min(page * pageSize, count),
238
- browseConfig: {
239
- table,
240
- filters,
241
- pkCols: info.data.primaryKey.length ? info.data.primaryKey : ['_rowid_'],
242
- hasPk: true,
243
- readonly: db.isReadOnly,
244
- },
245
- });
246
- }
247
- catch (err) {
248
- next(err);
249
- }
250
- });
251
- // Table schema editor.
252
- router.get('/tables/:table/schema', async (req, res, next) => {
253
- try {
254
- const table = req.params.table;
255
- const [info, schema] = await Promise.all([db.getTableInfo(table), db.getSchema(table)]);
256
- if (!info.success || !info.data || info.data.columns.length === 0) {
257
- return notFound(res, `Table "${table}" does not exist.`);
258
- }
259
- if (!schema.success || !schema.data) {
260
- return notFound(res, schema.error ?? 'Failed to load schema.');
261
- }
262
- res.locals.currentTable = table;
263
- res.render('pages/schema', {
264
- title: `Schema · ${table}`,
265
- table,
266
- schema: schema.data,
267
- isInternal: table.startsWith('_'),
268
- dialect: db.dialect,
269
- isSqlite: db.dialect === 'sqlite',
270
- isPostgres: db.dialect === 'postgres',
271
- config: { table, isInternal: table.startsWith('_'), dialect: db.dialect },
272
- });
273
- }
274
- catch (err) {
275
- next(err);
276
- }
277
- });
278
- // Data generator / seeder.
279
- router.get('/tables/:table/seed', async (req, res, next) => {
280
- try {
281
- const table = req.params.table;
282
- const [info, countRes] = await Promise.all([db.getTableInfo(table), db.getRowCount(table)]);
283
- if (!info.success || !info.data || info.data.columns.length === 0) {
284
- return notFound(res, `Table "${table}" does not exist.`);
285
- }
286
- const rowCount = countRes.success ? countRes.data : 0;
287
- const columns = (0, index_1.buildColumnConfigs)(info.data);
288
- res.locals.currentTable = table;
289
- res.render('pages/seed', {
290
- title: `Seed data · ${table}`,
291
- table,
292
- rowCount,
293
- colCount: info.data.columns.length,
294
- maxRows: index_1.MAX_SEED_ROWS,
295
- quickCounts: [10, 50, 100, 500, 1000, index_1.MAX_SEED_ROWS],
296
- seedConfig: { table, columns, rowCount, maxRows: index_1.MAX_SEED_ROWS },
297
- });
298
- }
299
- catch (err) {
300
- next(err);
301
- }
302
- });
303
- // Insert form.
304
- router.get('/tables/:table/rows/new', async (req, res, next) => {
305
- try {
306
- const table = req.params.table;
307
- const info = await db.getTableInfo(table);
308
- if (!info.success || !info.data || info.data.columns.length === 0) {
309
- return notFound(res, `Table "${table}" does not exist.`);
310
- }
311
- const pkColumns = info.data.primaryKey;
312
- res.locals.currentTable = table;
313
- res.render('pages/form', {
314
- title: `New row · ${table}`,
315
- table,
316
- mode: 'insert',
317
- pk: null,
318
- pkColumns,
319
- infoSummary: `${info.data.columns.length} column(s)` + (pkColumns.length ? ` · PK: ${pkColumns.join(', ')}` : ''),
320
- config: { table, mode: 'insert', pk: null, pkColumns },
321
- });
322
- }
323
- catch (err) {
324
- next(err);
325
- }
326
- });
327
- // Edit form.
328
- router.get('/tables/:table/rows/:id/edit', async (req, res, next) => {
329
- try {
330
- const table = req.params.table;
331
- const info = await db.getTableInfo(table);
332
- if (!info.success || !info.data || info.data.columns.length === 0) {
333
- return notFound(res, `Table "${table}" does not exist.`);
334
- }
335
- const pkColumns = info.data.primaryKey.length ? info.data.primaryKey : ['_rowid_'];
336
- const pk = (0, common_1.decodePk)(req.params.id);
337
- if (pk.length !== pkColumns.length) {
338
- return notFound(res, 'Invalid row identifier.');
339
- }
340
- res.locals.currentTable = table;
341
- res.render('pages/form', {
342
- title: `Edit row · ${table}`,
343
- table,
344
- mode: 'edit',
345
- pk: req.params.id,
346
- pkColumns,
347
- infoSummary: `${info.data.columns.length} column(s)` + (info.data.primaryKey.length ? ` · PK: ${info.data.primaryKey.join(', ')}` : ''),
348
- config: { table, mode: 'edit', pk: req.params.id, pkColumns },
349
- });
350
- }
351
- catch (err) {
352
- next(err);
353
- }
354
- });
355
- // Table designer.
356
- router.get('/designer', (_req, res) => {
357
- res.render('pages/designer', {
358
- title: 'New table',
359
- dialect: db.dialect,
360
- isSqlite: db.dialect === 'sqlite',
361
- isPostgres: db.dialect === 'postgres',
362
- });
363
- });
364
- // Query editor.
365
- router.get('/query', async (_req, res, next) => {
366
- try {
367
- const queries = await db.listSavedQueries();
368
- res.render('pages/query', { title: 'Query editor', savedQueries: queries.success ? queries.data : [] });
369
- }
370
- catch (err) {
371
- next(err);
372
- }
373
- });
374
- // Export: downloadable SQL dump.
375
- router.get('/export', async (_req, res, next) => {
376
- try {
377
- const dump = await (0, export_1.generateSqlDump)(db);
378
- if (!dump.success || !dump.data)
379
- throw new Error(dump.error ?? 'Failed to generate dump.');
380
- const stamp = new Date().toISOString().replace(/[:.]/g, '-');
381
- res.setHeader('Content-Type', 'application/sql; charset=utf-8');
382
- res.setHeader('Content-Disposition', `attachment; filename="admindb-${stamp}.sql"`);
383
- res.send(dump.data);
384
- }
385
- catch (err) {
386
- next(err);
387
- }
388
- });
389
- }
390
- //# sourceMappingURL=pages.js.map
1
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.registerPages=function(router,ctx){const{db:db}=ctx,notFound=(res,message)=>{res.status(404).render("pages/error",{title:"Not found",status:404,error:message})};router.get("/",async(_req,res,next)=>{try{const names=res.locals.tables??[],internalNames=res.locals.internalTables??[];let colCountsMap={};if("postgres"===db.dialect){const colRes=await db.all("SELECT table_name, count(*)::int AS cols FROM information_schema.columns WHERE table_schema = 'public' GROUP BY table_name;");if(colRes.success&&colRes.data)for(const row of colRes.data)row&&"string"==typeof row.table_name&&(colCountsMap[row.table_name]=Number(row.cols??0))}const[stats,saved]=await Promise.all([Promise.all(names.map(async name=>{const countR=await db.getRowCount(name),cols=void 0!==colCountsMap[name]?colCountsMap[name]:(await db.getTableInfo(name)).data?.columns.length??0;return{name:name,count:countR.success?countR.data:0,cols:cols}})),db.listSavedQueries()]),counts={},cols={};let totalRows=0;for(const s of stats)counts[s.name]=s.count,cols[s.name]=s.cols,totalRows+=s.count;res.render("pages/home",{title:"Home",tables:names,counts:counts,cols:cols,totalRows:totalRows,savedQueries:saved.success?saved.data?.length??0:0,internalCount:internalNames.length,dbPath:db.path})}catch(err){next(err)}}),router.get("/tables/:table",async(req,res,next)=>{try{const table=req.params.table,info=await db.getTableInfo(table);if(!info.success||!info.data||0===info.data.columns.length)return notFound(res,`Table "${table}" does not exist.`);const page=Math.max(1,Number.parseInt(String(req.query.page??"1"),10)||1),pageSize=Math.max(1,Number.parseInt(String(req.query.size??"50"),10)||50),orderBy=req.query.orderBy?String(req.query.orderBy):void 0,orderDir="desc"===String(req.query.orderDir??"asc").toLowerCase()?"desc":"asc",filters=(0,common_1.parseFilters)(req.query.f),filterQS=(0,common_1.filtersToQS)(filters),[countR,rowsR,refsR]=await Promise.all([db.getRowCount(table,filters),db.getRows(table,{page:page,limit:pageSize,orderBy:orderBy,orderDir:orderDir,filters:filters}),db.getReferencingTables(table)]),count=countR.success?countR.data:0,rawRows=rowsR.data??[],pages=Math.max(1,Math.ceil(count/pageSize)),basePath=String(res.locals.basePath??""),sizes=[25,50,100,250],colHeaders=info.data.columns.map(c=>{const active=c.name===orderBy,nextDir=active&&"asc"===orderDir?"desc":"asc",qs=`page=1&size=${pageSize}&orderBy=${encodeURIComponent(c.name)}&orderDir=${nextDir}`;return{name:c.name,pk:c.pk,type:c.type,active:active,dir:active?orderDir:null,href:`${basePath}/tables/${encodeURIComponent(table)}?${qs}${filterQS?"&"+filterQS:""}`}}),refColumns=(refsR.data??[]).filter(r=>!r.table.startsWith("_")).map(rt=>{const ref=rt.refs[0];return{table:rt.table,from:ref?.from??"",to:ref?.to??""}}),countEntries=await Promise.all(refColumns.map(async col=>{const values=rawRows.map(r=>r[col.to]).filter(v=>null!=v);if(!values.length)return[col.table,new Map];const placeholders=values.map(()=>"?").join(", "),cR=await db.all(`SELECT ${(0,generator_1.quoteIdentifier)(col.from)} AS fk, COUNT(*) AS c FROM ${(0,generator_1.quoteIdentifier)(col.table)} WHERE ${(0,generator_1.quoteIdentifier)(col.from)} IN (${placeholders}) GROUP BY ${(0,generator_1.quoteIdentifier)(col.from)}`,values),map=new Map;for(const row of cR.data??[])map.set(String(row.fk),Number(row.c));return[col.table,map]})),countMap=new Map(countEntries),rows=function(rawRows,info,table,basePath=""){const pkCols=info.primaryKey.length?info.primaryKey:["_rowid_"];return rawRows.map(row=>{const pkEncoded=(0,common_1.encodePk)(pkCols.map(c=>row[c]));return{cells:info.columns.map(c=>{const raw=row[c.name],v=(0,common_1.normalizeCell)(raw),isNull=null==v,typeUpper=(c.type||"").toUpperCase(),isBlob=typeUpper.includes("BLOB")||typeUpper.includes("BYTEA")||Buffer.isBuffer(raw)||raw instanceof Uint8Array||"string"==typeof v&&(/^0x[0-9a-f]{8,}$/i.test(v)||/^\\x[0-9a-f]{8,}$/i.test(v));let isJson=!1,isImage=!1,isUrl=!1,isColor=!1,blobSize="",blobMime="",blobExt="",blobUrl="";if(!isNull){const str=String(v);if(isBlob){let buf;buf=Buffer.isBuffer(raw)||raw instanceof Uint8Array?Buffer.isBuffer(raw)?raw:Buffer.from(raw):"string"==typeof v&&/^0x[0-9a-f]*$/i.test(v)||"string"==typeof v&&/^\\x[0-9a-f]*$/i.test(v)?Buffer.from(v.slice(2),"hex"):Buffer.from(str,"utf8");const mimeInfo=(0,datatype_1.sniffMimeType)(buf);blobSize=(0,common_1.formatBytes)(buf.length),blobMime=mimeInfo.mime,blobExt=mimeInfo.ext,isImage=mimeInfo.isImage,table&&pkEncoded&&(blobUrl=`${basePath}/api/tables/${encodeURIComponent(table)}/row/${encodeURIComponent(pkEncoded)}/blob/${encodeURIComponent(c.name)}`)}else(0,datatype_1.isJsonString)(v)||typeUpper.includes("JSON")?isJson=(0,datatype_1.isJsonString)(v):/^https?:\/\/[^\s$.?#].[^\s]*$/i.test(str)?isUrl=!0:/^#(?:[0-9a-fA-F]{3}){1,2}$|^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+/i.test(str)&&(isColor=!0)}return{name:c.name,value:v,isNull:isNull,display:isNull?"":String(v),type:c.type,isBlob:isBlob,isJson:isJson,isImage:isImage,isUrl:isUrl,isColor:isColor,blobSize:blobSize,blobMime:blobMime,blobExt:blobExt,blobUrl:blobUrl}}),pkEncoded:pkEncoded}})}(rawRows,info.data,table,basePath).map((dr,i)=>{const raw=rawRows[i];return{...dr,refs:refColumns.map(col=>{const v=raw[col.to];return{table:col.table,from:col.from,to:col.to,value:null==v?"":String(v),count:null==v?0:countMap.get(col.table)?.get(String(v))??0}})}});res.locals.currentTable=table,res.render("pages/table",{title:table,table:table,info:info.data,rows:rows,count:count,page:page,pageSize:pageSize,pages:pages,pkCols:info.data.primaryKey,colNames:info.data.columns.map(c=>c.name),colHeaders:colHeaders,refColumns:refColumns,hasPk:!0,orderBy:orderBy??"",orderDir:orderDir,sizes:sizes,filters:filters,filterQS:filterQS,firstRow:0===count?0:(page-1)*pageSize+1,lastRow:Math.min(page*pageSize,count),browseConfig:{table:table,filters:filters,pkCols:info.data.primaryKey.length?info.data.primaryKey:["_rowid_"],hasPk:!0,readonly:db.isReadOnly}})}catch(err){next(err)}}),router.get("/tables/:table/schema",async(req,res,next)=>{try{const table=req.params.table,[info,schema]=await Promise.all([db.getTableInfo(table),db.getSchema(table)]);if(!info.success||!info.data||0===info.data.columns.length)return notFound(res,`Table "${table}" does not exist.`);if(!schema.success||!schema.data)return notFound(res,schema.error??"Failed to load schema.");res.locals.currentTable=table,res.render("pages/schema",{title:`Schema · ${table}`,table:table,schema:schema.data,isInternal:table.startsWith("_"),dialect:db.dialect,isSqlite:"sqlite"===db.dialect,isPostgres:"postgres"===db.dialect,config:{table:table,isInternal:table.startsWith("_"),dialect:db.dialect}})}catch(err){next(err)}}),router.get("/tables/:table/seed",async(req,res,next)=>{try{const table=req.params.table,[info,countRes]=await Promise.all([db.getTableInfo(table),db.getRowCount(table)]);if(!info.success||!info.data||0===info.data.columns.length)return notFound(res,`Table "${table}" does not exist.`);const rowCount=countRes.success?countRes.data:0,columns=(0,index_1.buildColumnConfigs)(info.data);res.locals.currentTable=table,res.render("pages/seed",{title:`Seed data · ${table}`,table:table,rowCount:rowCount,colCount:info.data.columns.length,maxRows:index_1.MAX_SEED_ROWS,quickCounts:[10,50,100,500,1e3,index_1.MAX_SEED_ROWS],seedConfig:{table:table,columns:columns,rowCount:rowCount,maxRows:index_1.MAX_SEED_ROWS}})}catch(err){next(err)}}),router.get("/tables/:table/rows/new",async(req,res,next)=>{try{const table=req.params.table,info=await db.getTableInfo(table);if(!info.success||!info.data||0===info.data.columns.length)return notFound(res,`Table "${table}" does not exist.`);const pkColumns=info.data.primaryKey;res.locals.currentTable=table,res.render("pages/form",{title:`New row · ${table}`,table:table,mode:"insert",pk:null,pkColumns:pkColumns,infoSummary:`${info.data.columns.length} column(s)`+(pkColumns.length?` · PK: ${pkColumns.join(", ")}`:""),config:{table:table,mode:"insert",pk:null,pkColumns:pkColumns}})}catch(err){next(err)}}),router.get("/tables/:table/rows/:id/edit",async(req,res,next)=>{try{const table=req.params.table,info=await db.getTableInfo(table);if(!info.success||!info.data||0===info.data.columns.length)return notFound(res,`Table "${table}" does not exist.`);const pkColumns=info.data.primaryKey.length?info.data.primaryKey:["_rowid_"];if((0,common_1.decodePk)(req.params.id).length!==pkColumns.length)return notFound(res,"Invalid row identifier.");res.locals.currentTable=table,res.render("pages/form",{title:`Edit row · ${table}`,table:table,mode:"edit",pk:req.params.id,pkColumns:pkColumns,infoSummary:`${info.data.columns.length} column(s)`+(info.data.primaryKey.length?` · PK: ${info.data.primaryKey.join(", ")}`:""),config:{table:table,mode:"edit",pk:req.params.id,pkColumns:pkColumns}})}catch(err){next(err)}}),router.get("/designer",(_req,res)=>{res.render("pages/designer",{title:"New table",dialect:db.dialect,isSqlite:"sqlite"===db.dialect,isPostgres:"postgres"===db.dialect})}),router.get("/query",async(_req,res,next)=>{try{const queries=await db.listSavedQueries();res.render("pages/query",{title:"Query editor",savedQueries:queries.success?queries.data:[]})}catch(err){next(err)}}),router.get("/export",async(_req,res,next)=>{try{const dump=await(0,export_1.generateSqlDump)(db);if(!dump.success||!dump.data)throw new Error(dump.error??"Failed to generate dump.");const stamp=(new Date).toISOString().replace(/[:.]/g,"-");res.setHeader("Content-Type","application/sql; charset=utf-8"),res.setHeader("Content-Disposition",`attachment; filename="admindb-${stamp}.sql"`),res.send(dump.data)}catch(err){next(err)}})};const export_1=require("../db/export"),generator_1=require("../sql/generator"),common_1=require("../utils/common"),datatype_1=require("../utils/datatype"),index_1=require("../data/index");
@@ -1,40 +1 @@
1
- import { IncomingMessage, ServerResponse } from 'node:http';
2
- import { type AppOptions } from './app';
3
- /**
4
- * Detects if the current process is running in a serverless environment
5
- * (e.g. Vercel, AWS Lambda, Netlify Functions, Google Cloud Functions/Run, Azure Functions, Cloudflare Pages).
6
- */
7
- export declare function isServerlessEnvironment(env?: NodeJS.ProcessEnv): boolean;
8
- /**
9
- * Creates an HTTP request listener for standard Node.js serverless runtimes
10
- * (Vercel API routes, Next.js custom route handlers, Google Cloud Functions, Azure Functions, Micro).
11
- *
12
- * In serverless mode, all write operations and database mutations are strictly disabled.
13
- *
14
- * Example (Vercel `api/index.ts`):
15
- * ```ts
16
- * import { createServerlessHandler } from 'admindb';
17
- * export default createServerlessHandler({ dbPath: './data.db' });
18
- * ```
19
- */
20
- export declare function createServerlessHandler(options?: AppOptions): (req: IncomingMessage, res: ServerResponse) => void;
21
- export interface LambdaProxyResult {
22
- statusCode: number;
23
- headers: Record<string, string>;
24
- multiValueHeaders?: Record<string, string[]>;
25
- body: string;
26
- isBase64Encoded: boolean;
27
- }
28
- /**
29
- * Creates an AWS Lambda handler for API Gateway (REST v1 and HTTP v2 payloads).
30
- *
31
- * In serverless mode, SQLite databases are read-only, while remote PostgreSQL
32
- * connections are editable unless configured otherwise.
33
- *
34
- * Example (AWS Lambda `index.ts`):
35
- * ```ts
36
- * import { createLambdaHandler } from 'admindb';
37
- * export const handler = createLambdaHandler({ dbPath: './data.db' });
38
- * ```
39
- */
40
- export declare function createLambdaHandler(options?: AppOptions): (event: any, _context?: any) => Promise<LambdaProxyResult>;
1
+ import{IncomingMessage,ServerResponse} from 'node:http';import{type AppOptions} from './app';export declare function isServerlessEnvironment(env?:NodeJS.ProcessEnv):boolean;export declare function createServerlessHandler(options?:AppOptions):(req:IncomingMessage,res:ServerResponse)=>void;export interface LambdaProxyResult{statusCode:number;headers:Record<string,string>;multiValueHeaders?:Record<string,string[]>;body:string;isBase64Encoded:boolean;}export declare function createLambdaHandler(options?:AppOptions):(event:any,_context?:any)=>Promise<LambdaProxyResult>;
@@ -1,210 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isServerlessEnvironment = isServerlessEnvironment;
4
- exports.createServerlessHandler = createServerlessHandler;
5
- exports.createLambdaHandler = createLambdaHandler;
6
- const node_http_1 = require("node:http");
7
- const node_net_1 = require("node:net");
8
- const app_1 = require("./app");
9
- /**
10
- * Detects if the current process is running in a serverless environment
11
- * (e.g. Vercel, AWS Lambda, Netlify Functions, Google Cloud Functions/Run, Azure Functions, Cloudflare Pages).
12
- */
13
- function isServerlessEnvironment(env = process.env) {
14
- // Explicit serverless flags
15
- if (['1', 'true', 'yes', 'on'].includes(String(env.ADMINDB_SERVERLESS ?? env.SERVERLESS ?? env.IS_SERVERLESS ?? '').trim().toLowerCase())) {
16
- return true;
17
- }
18
- // Vercel Serverless Functions
19
- if (Boolean(env.VERCEL || env.VERCEL_ENV || env.NOW_REGION)) {
20
- return true;
21
- }
22
- // AWS Lambda
23
- if (Boolean(env.AWS_LAMBDA_FUNCTION_NAME || env.LAMBDA_TASK_ROOT || env.AWS_EXECUTION_ENV)) {
24
- return true;
25
- }
26
- // Netlify Functions
27
- if (Boolean(env.NETLIFY || env.NETLIFY_LOCAL)) {
28
- return true;
29
- }
30
- // Google Cloud Functions / Cloud Run
31
- if (Boolean(env.FUNCTION_TARGET || env.FUNCTION_NAME || env.K_SERVICE)) {
32
- return true;
33
- }
34
- // Azure Functions
35
- if (Boolean(env.FUNCTIONS_WORKER_RUNTIME || env.WEBSITE_INSTANCE_ID)) {
36
- return true;
37
- }
38
- // Cloudflare Pages
39
- if (Boolean(env.CF_PAGES)) {
40
- return true;
41
- }
42
- return false;
43
- }
44
- /**
45
- * Creates an HTTP request listener for standard Node.js serverless runtimes
46
- * (Vercel API routes, Next.js custom route handlers, Google Cloud Functions, Azure Functions, Micro).
47
- *
48
- * In serverless mode, all write operations and database mutations are strictly disabled.
49
- *
50
- * Example (Vercel `api/index.ts`):
51
- * ```ts
52
- * import { createServerlessHandler } from 'admindb';
53
- * export default createServerlessHandler({ dbPath: './data.db' });
54
- * ```
55
- */
56
- function createServerlessHandler(options = {}) {
57
- const rawTarget = options.connection || options.dbPath || '';
58
- const isPg = Boolean(options.pgOptions) ||
59
- (typeof rawTarget === 'string' && (rawTarget.startsWith('postgres://') || rawTarget.startsWith('postgresql://'))) ||
60
- options.db?.dialect === 'postgres';
61
- const defaultReadonly = isPg ? false : true;
62
- const app = (0, app_1.createRouter)({
63
- ...options,
64
- serverless: options.serverless ?? true,
65
- readonly: options.readonly ?? defaultReadonly,
66
- });
67
- return (req, res) => {
68
- app(req, res);
69
- };
70
- }
71
- /**
72
- * Creates an AWS Lambda handler for API Gateway (REST v1 and HTTP v2 payloads).
73
- *
74
- * In serverless mode, SQLite databases are read-only, while remote PostgreSQL
75
- * connections are editable unless configured otherwise.
76
- *
77
- * Example (AWS Lambda `index.ts`):
78
- * ```ts
79
- * import { createLambdaHandler } from 'admindb';
80
- * export const handler = createLambdaHandler({ dbPath: './data.db' });
81
- * ```
82
- */
83
- function createLambdaHandler(options = {}) {
84
- const rawTarget = options.connection || options.dbPath || '';
85
- const isPg = Boolean(options.pgOptions) ||
86
- (typeof rawTarget === 'string' && (rawTarget.startsWith('postgres://') || rawTarget.startsWith('postgresql://'))) ||
87
- options.db?.dialect === 'postgres';
88
- const defaultReadonly = isPg ? false : true;
89
- const app = (0, app_1.createRouter)({
90
- ...options,
91
- serverless: options.serverless ?? true,
92
- readonly: options.readonly ?? defaultReadonly,
93
- });
94
- return async (event, _context) => {
95
- return new Promise((resolve) => {
96
- try {
97
- const isV2 = Boolean(event.version === '2.0' || event.rawPath);
98
- const method = (isV2
99
- ? event.requestContext?.http?.method
100
- : event.httpMethod) || 'GET';
101
- const rawPath = isV2 ? (event.rawPath || '/') : (event.path || '/');
102
- const qs = isV2
103
- ? (event.rawQueryString || '')
104
- : (event.queryStringParameters
105
- ? Object.entries(event.queryStringParameters)
106
- .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
107
- .join('&')
108
- : '');
109
- const url = qs ? `${rawPath}?${qs}` : rawPath;
110
- const rawHeaders = event.headers || {};
111
- const headers = {};
112
- for (const [k, v] of Object.entries(rawHeaders)) {
113
- if (v !== undefined && v !== null) {
114
- headers[k.toLowerCase()] = String(v);
115
- }
116
- }
117
- if (event.cookies && Array.isArray(event.cookies) && !headers['cookie']) {
118
- headers['cookie'] = event.cookies.join('; ');
119
- }
120
- // Prepare request body
121
- let bodyBuffer = null;
122
- if (event.body) {
123
- if (event.isBase64Encoded) {
124
- bodyBuffer = Buffer.from(event.body, 'base64');
125
- }
126
- else {
127
- bodyBuffer = Buffer.from(event.body, 'utf8');
128
- }
129
- if (!headers['content-length']) {
130
- headers['content-length'] = String(bodyBuffer.length);
131
- }
132
- }
133
- const socket = new node_net_1.Socket();
134
- const req = new node_http_1.IncomingMessage(socket);
135
- req.url = url;
136
- req.method = method;
137
- req.headers = headers;
138
- req.httpVersion = '1.1';
139
- req.httpVersionMajor = 1;
140
- req.httpVersionMinor = 1;
141
- if (bodyBuffer) {
142
- req.push(bodyBuffer);
143
- }
144
- req.push(null);
145
- const res = new node_http_1.ServerResponse(req);
146
- const chunks = [];
147
- res.write = function (chunk, ...args) {
148
- if (chunk) {
149
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
150
- }
151
- const cb = typeof args[0] === 'function' ? args[0] : typeof args[1] === 'function' ? args[1] : undefined;
152
- if (cb)
153
- cb();
154
- return true;
155
- };
156
- res.end = function (chunk, ...args) {
157
- if (chunk && typeof chunk !== 'function') {
158
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
159
- }
160
- const cb = typeof chunk === 'function'
161
- ? chunk
162
- : typeof args[0] === 'function'
163
- ? args[0]
164
- : typeof args[1] === 'function'
165
- ? args[1]
166
- : undefined;
167
- if (cb)
168
- cb();
169
- const responseHeaders = {};
170
- const multiValueHeaders = {};
171
- const resHeaders = res.getHeaders();
172
- for (const [k, v] of Object.entries(resHeaders)) {
173
- if (Array.isArray(v)) {
174
- multiValueHeaders[k] = v.map(String);
175
- responseHeaders[k] = v.map(String).join(', ');
176
- }
177
- else if (v !== undefined) {
178
- responseHeaders[k] = String(v);
179
- }
180
- }
181
- const fullBody = Buffer.concat(chunks);
182
- const contentType = String(responseHeaders['content-type'] || '');
183
- const isBinary = !contentType.startsWith('text/') &&
184
- !contentType.includes('application/json') &&
185
- !contentType.includes('application/javascript') &&
186
- !contentType.includes('application/xml') &&
187
- !contentType.includes('image/svg+xml');
188
- resolve({
189
- statusCode: res.statusCode || 200,
190
- headers: responseHeaders,
191
- multiValueHeaders: Object.keys(multiValueHeaders).length > 0 ? multiValueHeaders : undefined,
192
- body: isBinary ? fullBody.toString('base64') : fullBody.toString('utf8'),
193
- isBase64Encoded: isBinary,
194
- });
195
- return res;
196
- };
197
- app(req, res);
198
- }
199
- catch (err) {
200
- resolve({
201
- statusCode: 500,
202
- headers: { 'content-type': 'application/json' },
203
- body: JSON.stringify({ success: false, error: err?.message || 'Server error' }),
204
- isBase64Encoded: false,
205
- });
206
- }
207
- });
208
- };
209
- }
210
- //# sourceMappingURL=serverless.js.map
1
+ Object.defineProperty(exports,"__esModule",{value:!0}),exports.isServerlessEnvironment=function(env=process.env){if(["1","true","yes","on"].includes(String(env.ADMINDB_SERVERLESS??env.SERVERLESS??env.IS_SERVERLESS??"").trim().toLowerCase()))return!0;if(Boolean(env.VERCEL||env.VERCEL_ENV||env.NOW_REGION))return!0;if(Boolean(env.AWS_LAMBDA_FUNCTION_NAME||env.LAMBDA_TASK_ROOT||env.AWS_EXECUTION_ENV))return!0;if(Boolean(env.NETLIFY||env.NETLIFY_LOCAL))return!0;if(Boolean(env.FUNCTION_TARGET||env.FUNCTION_NAME||env.K_SERVICE))return!0;if(Boolean(env.FUNCTIONS_WORKER_RUNTIME||env.WEBSITE_INSTANCE_ID))return!0;if(Boolean(env.CF_PAGES))return!0;return!1},exports.createServerlessHandler=function(options={}){const rawTarget=options.connection||options.dbPath||"",defaultReadonly=!(Boolean(options.pgOptions)||"string"==typeof rawTarget&&(rawTarget.startsWith("postgres://")||rawTarget.startsWith("postgresql://"))||"postgres"===options.db?.dialect),app=(0,app_1.createRouter)({...options,serverless:options.serverless??!0,readonly:options.readonly??defaultReadonly});return(req,res)=>{app(req,res)}},exports.createLambdaHandler=function(options={}){const rawTarget=options.connection||options.dbPath||"",defaultReadonly=!(Boolean(options.pgOptions)||"string"==typeof rawTarget&&(rawTarget.startsWith("postgres://")||rawTarget.startsWith("postgresql://"))||"postgres"===options.db?.dialect),app=(0,app_1.createRouter)({...options,serverless:options.serverless??!0,readonly:options.readonly??defaultReadonly});return async(event,_context)=>new Promise(resolve=>{try{const isV2=Boolean("2.0"===event.version||event.rawPath),method=(isV2?event.requestContext?.http?.method:event.httpMethod)||"GET",rawPath=isV2?event.rawPath||"/":event.path||"/",qs=isV2?event.rawQueryString||"":event.queryStringParameters?Object.entries(event.queryStringParameters).map(([k,v])=>`${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`).join("&"):"",url=qs?`${rawPath}?${qs}`:rawPath,rawHeaders=event.headers||{},headers={};for(const[k,v]of Object.entries(rawHeaders))null!=v&&(headers[k.toLowerCase()]=String(v));event.cookies&&Array.isArray(event.cookies)&&!headers.cookie&&(headers.cookie=event.cookies.join("; "));let bodyBuffer=null;event.body&&(bodyBuffer=event.isBase64Encoded?Buffer.from(event.body,"base64"):Buffer.from(event.body,"utf8"),headers["content-length"]||(headers["content-length"]=String(bodyBuffer.length)));const socket=new node_net_1.Socket,req=new node_http_1.IncomingMessage(socket);req.url=url,req.method=method,req.headers=headers,req.httpVersion="1.1",req.httpVersionMajor=1,req.httpVersionMinor=1,bodyBuffer&&req.push(bodyBuffer),req.push(null);const res=new node_http_1.ServerResponse(req),chunks=[];res.write=function(chunk,...args){chunk&&chunks.push(Buffer.isBuffer(chunk)?chunk:Buffer.from(chunk));const cb="function"==typeof args[0]?args[0]:"function"==typeof args[1]?args[1]:void 0;return cb&&cb(),!0},res.end=function(chunk,...args){chunk&&"function"!=typeof chunk&&chunks.push(Buffer.isBuffer(chunk)?chunk:Buffer.from(chunk));const cb="function"==typeof chunk?chunk:"function"==typeof args[0]?args[0]:"function"==typeof args[1]?args[1]:void 0;cb&&cb();const responseHeaders={},multiValueHeaders={},resHeaders=res.getHeaders();for(const[k,v]of Object.entries(resHeaders))Array.isArray(v)?(multiValueHeaders[k]=v.map(String),responseHeaders[k]=v.map(String).join(", ")):void 0!==v&&(responseHeaders[k]=String(v));const fullBody=Buffer.concat(chunks),contentType=String(responseHeaders["content-type"]||""),isBinary=!(contentType.startsWith("text/")||contentType.includes("application/json")||contentType.includes("application/javascript")||contentType.includes("application/xml")||contentType.includes("image/svg+xml"));return resolve({statusCode:res.statusCode||200,headers:responseHeaders,multiValueHeaders:Object.keys(multiValueHeaders).length>0?multiValueHeaders:void 0,body:isBinary?fullBody.toString("base64"):fullBody.toString("utf8"),isBase64Encoded:isBinary}),res},app(req,res)}catch(err){resolve({statusCode:500,headers:{"content-type":"application/json"},body:JSON.stringify({success:!1,error:err?.message||"Server error"}),isBase64Encoded:!1})}})};const node_http_1=require("node:http"),node_net_1=require("node:net"),app_1=require("./app");