admindb 2.2.1 → 2.3.0

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 (87) hide show
  1. package/README.md +368 -364
  2. package/dist/app.js +6 -9
  3. package/dist/auth/config.d.ts +1 -1
  4. package/dist/auth/config.js +18 -30
  5. package/dist/auth/crypto.js +11 -21
  6. package/dist/auth/middleware.js +9 -16
  7. package/dist/auth/routes.js +9 -15
  8. package/dist/cli/args.d.ts +1 -1
  9. package/dist/cli/args.js +15 -26
  10. package/dist/cli/config.js +6 -16
  11. package/dist/cli/runner.js +4 -7
  12. package/dist/data/chain.d.ts +1 -1
  13. package/dist/data/chain.js +40 -617
  14. package/dist/data/datasets.d.ts +1 -1
  15. package/dist/data/datasets.js +43 -1
  16. package/dist/data/detector.js +45 -21
  17. package/dist/data/engine.d.ts +1 -1
  18. package/dist/data/engine.js +483 -142
  19. package/dist/data/index.d.ts +1 -1
  20. package/dist/data/index.js +8 -0
  21. package/dist/data/prng.d.ts +1 -0
  22. package/dist/data/prng.js +73 -0
  23. package/dist/data/registry.d.ts +1 -0
  24. package/dist/data/registry.js +805 -0
  25. package/dist/data/schema-graph.d.ts +1 -0
  26. package/dist/data/schema-graph.js +210 -0
  27. package/dist/data/strategies.d.ts +1 -1
  28. package/dist/data/strategies.js +44 -283
  29. package/dist/data/templates.d.ts +1 -0
  30. package/dist/data/templates.js +134 -0
  31. package/dist/data/types.d.ts +1 -1
  32. package/dist/data/validator.d.ts +1 -0
  33. package/dist/data/validator.js +160 -0
  34. package/dist/db/database.js +9 -14
  35. package/dist/db/export.js +32 -55
  36. package/dist/db/filters.d.ts +1 -1
  37. package/dist/db/filters.js +15 -38
  38. package/dist/db/introspection.js +4 -7
  39. package/dist/db/manager.js +27 -51
  40. package/dist/db/migrations.js +7 -14
  41. package/dist/db/postgres.js +30 -78
  42. package/dist/index.d.ts +1 -1
  43. package/dist/public/css/app.css +1 -1
  44. package/dist/public/js/browse.js +1 -1
  45. package/dist/public/js/inspector.js +1 -1
  46. package/dist/public/js/query.js +1 -1
  47. package/dist/public/js/seed.js +1 -1
  48. package/dist/routes/api/erd.js +3 -8
  49. package/dist/routes/api/helpers.d.ts +1 -1
  50. package/dist/routes/api/helpers.js +75 -25
  51. package/dist/routes/api/import-export.js +1 -2
  52. package/dist/routes/api/query.js +2 -6
  53. package/dist/routes/api/rows.js +4 -8
  54. package/dist/routes/api/seed.js +35 -21
  55. package/dist/routes/api/tables.js +15 -30
  56. package/dist/routes/databases.js +8 -26
  57. package/dist/routes/pages.js +67 -18
  58. package/dist/serverless.js +15 -40
  59. package/dist/sql/generator.d.ts +1 -1
  60. package/dist/sql/generator.js +35 -109
  61. package/dist/types/api.d.ts +1 -1
  62. package/dist/utils/common.d.ts +1 -1
  63. package/dist/utils/common.js +45 -85
  64. package/dist/utils/csv.d.ts +1 -1
  65. package/dist/utils/csv.js +11 -17
  66. package/dist/utils/datatype.js +46 -60
  67. package/dist/utils/icons.js +8 -8
  68. package/dist/views/layouts/main.hbs +1 -87
  69. package/dist/views/pages/databases.hbs +1 -233
  70. package/dist/views/pages/designer.hbs +1 -89
  71. package/dist/views/pages/erd.hbs +1 -1241
  72. package/dist/views/pages/error.hbs +1 -10
  73. package/dist/views/pages/form.hbs +1 -59
  74. package/dist/views/pages/home.hbs +1 -220
  75. package/dist/views/pages/info.hbs +1 -107
  76. package/dist/views/pages/login.hbs +1 -98
  77. package/dist/views/pages/query.hbs +1 -129
  78. package/dist/views/pages/schema.hbs +1 -298
  79. package/dist/views/pages/seed-select.hbs +251 -0
  80. package/dist/views/pages/seed.hbs +256 -414
  81. package/dist/views/pages/table.hbs +1 -327
  82. package/dist/views/partials/navbar.hbs +1 -83
  83. package/dist/views/partials/sidebar.hbs +1 -129
  84. package/docs/API.md +149 -149
  85. package/docs/EXAMPLES.md +579 -579
  86. package/docs/SECURITY.md +265 -265
  87. package/package.json +79 -79
@@ -1 +1 @@
1
- export declare const FIRST_NAMES:string[];export declare const LAST_NAMES:string[];export declare const CITIES:string[];export declare const COUNTRIES:string[];export declare const DOMAINS:string[];export declare const LOREM_WORDS:string[];export declare const COMPANIES:string[];export declare const JOB_TITLES:string[];export declare const US_STATES:string[];export declare const CURRENCIES:string[];export declare const COUNTRY_CODES:string[];export declare const STATUSES:string[];export declare const HEX_COLORS:string[];export declare const NAMED_COLORS:string[];
1
+ export declare const FIRST_NAMES:string[];export declare const LAST_NAMES:string[];export declare const CITIES:string[];export declare const COUNTRIES:string[];export declare const DOMAINS:string[];export declare const LOREM_WORDS:string[];export declare const COMPANIES:string[];export declare const JOB_TITLES:string[];export declare const US_STATES:string[];export declare const CURRENCIES:string[];export declare const COUNTRY_CODES:string[];export declare const STATUSES:string[];export declare const HEX_COLORS:string[];export declare const NAMED_COLORS:string[];export declare const PRODUCT_CATEGORIES:string[];export declare const PRODUCT_NAMES:string[];export declare const DEPARTMENTS:string[];export declare const PAYMENT_METHODS:string[];export declare const TRANSACTION_TYPES:string[];export declare const TECH_SKILLS:string[];export declare const ORDER_STATUSES:string[];
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NAMED_COLORS = exports.HEX_COLORS = exports.STATUSES = exports.COUNTRY_CODES = exports.CURRENCIES = exports.US_STATES = exports.JOB_TITLES = exports.COMPANIES = exports.LOREM_WORDS = exports.DOMAINS = exports.COUNTRIES = exports.CITIES = exports.LAST_NAMES = exports.FIRST_NAMES = void 0;
3
+ exports.ORDER_STATUSES = exports.TECH_SKILLS = exports.TRANSACTION_TYPES = exports.PAYMENT_METHODS = exports.DEPARTMENTS = exports.PRODUCT_NAMES = exports.PRODUCT_CATEGORIES = exports.NAMED_COLORS = exports.HEX_COLORS = exports.STATUSES = exports.COUNTRY_CODES = exports.CURRENCIES = exports.US_STATES = exports.JOB_TITLES = exports.COMPANIES = exports.LOREM_WORDS = exports.DOMAINS = exports.COUNTRIES = exports.CITIES = exports.LAST_NAMES = exports.FIRST_NAMES = void 0;
4
4
  exports.FIRST_NAMES = [
5
5
  "Sombat", "Ting", "Rajan", "Minh", "Hiroshi", "William", "Made", "Ravi", "John", "Kiran",
6
6
  "Raj", "Wayan", "Chaiwat", "Aarav", "Sita", "Zara", "Ratna", "Ananya", "Ha-eun", "Siti",
@@ -127,3 +127,45 @@ exports.NAMED_COLORS = [
127
127
  "Sky", "Slate", "Teal", "Fuchsia", "Crimson", "Navy",
128
128
  "Coral", "Bronze", "Charcoal", "Mint", "Lavender", "Ruby", "Cobalt"
129
129
  ];
130
+ exports.PRODUCT_CATEGORIES = [
131
+ "Electronics", "Computers & Accessories", "Apparel & Footwear", "Home & Kitchen",
132
+ "Health & Wellness", "Books & Media", "Sports & Outdoors", "Beauty & Personal Care",
133
+ "Toys & Games", "Automotive & Industrial", "Groceries & Gourmet", "Office Products"
134
+ ];
135
+ exports.PRODUCT_NAMES = [
136
+ "Wireless Noise-Canceling Earbuds", "Ergonomic Mechanical Keyboard", "Ultra HD 4K IPS Monitor",
137
+ "Organic Fair-Trade Coffee Beans", "Stainless Steel Thermal Tumbler", "Merino Wool Athletic Socks",
138
+ "Waterproof Smart Fitness Watch", "Non-Stick Ceramic Frying Pan", "Hydrating Hyaluronic Facial Serum",
139
+ "Portable Bluetooth Outdoor Speaker", "Compact Cordless Handheld Vacuum", "Memory Foam Contoured Pillow",
140
+ "Natural Soy Aromatherapy Candle", "Adjustable Standing Desk Converter", "High-Speed 65W GaN Fast Charger",
141
+ "Full-Grain Leather Bi-Fold Wallet", "Polarized Lightweight Sunglasses", "Recycled Aluminum Laptop Stand",
142
+ "Organic Green Matcha Tea Powder", "Precision Kitchen Digital Scale", "Active Noise Canceling Headphones",
143
+ "Tempered Glass Screen Protector", "Braided Nylon Heavy-Duty Cable", "Plant-Based Protein Powder",
144
+ "Ceramic Essential Oil Diffuser", "Stainless Steel Chef Knife 8-Inch", "Resistance Band Exercise Set",
145
+ "Double-Wall Insulated Mug", "Minimalist Water-Resistant Backpack", "Rechargeable LED Desk Lamp"
146
+ ];
147
+ exports.DEPARTMENTS = [
148
+ "Engineering", "Product Management", "Design & UX", "Marketing & Growth",
149
+ "Sales & Business Development", "Customer Support", "Human Resources",
150
+ "Finance & Accounting", "Legal & Compliance", "Operations & Logistics",
151
+ "Data & Analytics", "Quality Assurance", "Information Security", "Corporate Strategy"
152
+ ];
153
+ exports.PAYMENT_METHODS = [
154
+ "Credit Card", "Debit Card", "PayPal", "Apple Pay", "Google Pay",
155
+ "Bank Transfer", "Stripe Checkout", "Klarna Pay in 4", "Cash on Delivery",
156
+ "Affirm", "Afterpay", "Wire Transfer", "Venmo"
157
+ ];
158
+ exports.TRANSACTION_TYPES = [
159
+ "purchase", "refund", "subscription", "authorization", "capture",
160
+ "chargeback", "payout", "transfer", "adjustment", "deposit", "withdrawal"
161
+ ];
162
+ exports.TECH_SKILLS = [
163
+ "TypeScript", "JavaScript", "Python", "Rust", "Go", "SQL", "PostgreSQL",
164
+ "SQLite", "MySQL", "React", "Vue", "Next.js", "Node.js", "GraphQL",
165
+ "Redis", "Docker", "Kubernetes", "AWS", "Cloudflare", "Linux", "Git",
166
+ "TailwindCSS", "Terraform", "Kafka", "Elasticsearch", "Prometheus"
167
+ ];
168
+ exports.ORDER_STATUSES = [
169
+ "pending", "confirmed", "processing", "shipped", "out_for_delivery",
170
+ "delivered", "cancelled", "refunded", "on_hold", "failed"
171
+ ];
@@ -36,41 +36,41 @@ function extractCheckExprs(sql) {
36
36
  while (i < sql.length && depth > 0) {
37
37
  const ch = sql[i];
38
38
  if (ch === "'") {
39
- i += 1;
39
+ i++;
40
40
  while (i < sql.length) {
41
41
  if (sql[i] === "'") {
42
42
  if (sql[i + 1] === "'")
43
43
  i += 2;
44
44
  else {
45
- i += 1;
45
+ i++;
46
46
  break;
47
47
  }
48
48
  }
49
49
  else
50
- i += 1;
50
+ i++;
51
51
  }
52
52
  continue;
53
53
  }
54
54
  if (ch === '"' || ch === '`' || ch === '[') {
55
55
  const close = ch === '[' ? ']' : ch;
56
- i += 1;
56
+ i++;
57
57
  while (i < sql.length && sql[i] !== close) {
58
58
  if (sql[i] === close && sql[i + 1] === close)
59
59
  i += 2;
60
60
  else
61
- i += 1;
61
+ i++;
62
62
  }
63
- i += 1;
63
+ i++;
64
64
  continue;
65
65
  }
66
66
  if (ch === '(')
67
- depth += 1;
67
+ depth++;
68
68
  else if (ch === ')') {
69
- depth -= 1;
69
+ depth--;
70
70
  if (depth === 0)
71
71
  break;
72
72
  }
73
- i += 1;
73
+ i++;
74
74
  }
75
75
  out.push(sql.slice(start, i));
76
76
  }
@@ -128,8 +128,7 @@ function parseChecks(sql) {
128
128
  const col = mColIn[1] || mColIn[2] || mColIn[3] || mColIn[4];
129
129
  if (!col || ['json_extract', 'strftime', 'datetime', 'date', 'length', 'typeof'].includes(col.toLowerCase()))
130
130
  continue;
131
- const matchPos = mColIn.index;
132
- if (expr.slice(Math.max(0, matchPos - 5), matchPos).includes('->'))
131
+ if (expr.slice(Math.max(0, mColIn.index - 5), mColIn.index).includes('->'))
133
132
  continue;
134
133
  const inContent = mColIn[5];
135
134
  const strValues = (inContent.match(/'(?:[^']|'')*'/g) ?? []).map((s) => s.slice(1, -1).replace(/''/g, "'"));
@@ -253,6 +252,13 @@ function extractJsonColumns(sql) {
253
252
  const TEXT_PATTERNS = [
254
253
  [/avatar|picture|photo|image|img|thumbnail|icon|logo/, () => ({ strategy: 'avatar' })],
255
254
  [/company|organization|org|firm|corp|employer|agency/, () => ({ strategy: 'company' })],
255
+ [/department|division|dept/, () => ({ strategy: 'department' })],
256
+ [/productcategory|categoryname|^category$/, () => ({ strategy: 'productCategory' })],
257
+ [/productname|producttitle|^product$|^item$|itemname/, () => ({ strategy: 'product' })],
258
+ [/paymentmethod|paymenttype|paymentmode|paymentprovider/, () => ({ strategy: 'paymentMethod' })],
259
+ [/transactiontype|txntype|txtype/, () => ({ strategy: 'transactionType' })],
260
+ [/techskill|skill|skills|techstack|technology/, () => ({ strategy: 'techSkill' })],
261
+ [/orderstatus|shipmentstatus|deliverystatus/, () => ({ strategy: 'orderStatus' })],
256
262
  [/job|title|role|position|occupation|profession/, () => ({ strategy: 'job' })],
257
263
  [/currency|curr|currencycode/, () => ({ strategy: 'currency' })],
258
264
  [/countrycode|countryiso|isocountry|cca2/, () => ({ strategy: 'countryCode' })],
@@ -398,12 +404,18 @@ function buildColumnConfigs(info) {
398
404
  let uqM;
399
405
  while ((uqM = uqRe.exec(info.sql))) {
400
406
  const rawCols = uqM[1].split(',').map((s) => s.trim().replace(/[`"\[\]]/g, ''));
401
- if (rawCols.length === 1 && rawCols[0]) {
407
+ if (rawCols.length === 1 && rawCols[0])
402
408
  uniqueCols.add(rawCols[0]);
403
- }
404
409
  }
405
410
  }
406
411
  const checkInfo = parseChecks(info.sql ?? null);
412
+ const colNames = info.columns.map((c) => c.name.toLowerCase());
413
+ const hasFirstName = colNames.includes('first_name') || colNames.includes('firstname');
414
+ const hasLastName = colNames.includes('last_name') || colNames.includes('lastname');
415
+ const fullNameCol = info.columns.find((c) => {
416
+ const lc = c.name.toLowerCase();
417
+ return lc === 'full_name' || lc === 'fullname' || lc === 'name' || lc === 'customer_name';
418
+ });
407
419
  return info.columns.map((col) => {
408
420
  const fk = fkByColumn.get(col.name) ?? null;
409
421
  const strategies = (0, strategies_1.strategiesFor)(col, fk);
@@ -450,6 +462,17 @@ function buildColumnConfigs(info) {
450
462
  defaultPlan.maxLen = colLen.max;
451
463
  }
452
464
  }
465
+ if (defaultPlan.strategy === 'email' && !col.pk) {
466
+ if (hasFirstName && hasLastName) {
467
+ defaultPlan = { strategy: 'template', template: '{{first_name}}.{{last_name}}@example.com' };
468
+ }
469
+ else if (fullNameCol && fullNameCol.name !== col.name) {
470
+ defaultPlan = { strategy: 'template', template: `{{${fullNameCol.name}}}@example.com` };
471
+ }
472
+ }
473
+ if ((col.name.toLowerCase() === 'full_name' || col.name.toLowerCase() === 'fullname') && hasFirstName && hasLastName && !col.pk) {
474
+ defaultPlan = { strategy: 'template', template: '{{first_name}} {{last_name}}' };
475
+ }
453
476
  if (!strategies.some((s) => s.id === defaultPlan.strategy) || (!col.pk && col.notnull && col.dflt_value == null && (defaultPlan.strategy === 'skip' || defaultPlan.strategy === 'null'))) {
454
477
  defaultPlan = (0, strategies_1.fallbackPlanFor)(col);
455
478
  }
@@ -457,7 +480,7 @@ function buildColumnConfigs(info) {
457
480
  name: col.name,
458
481
  type: col.type,
459
482
  pk: col.pk > 0,
460
- notnull: !!col.notnull,
483
+ notnull: Boolean(col.notnull),
461
484
  hasDefault: col.dflt_value != null,
462
485
  unique,
463
486
  fk,
@@ -466,7 +489,7 @@ function buildColumnConfigs(info) {
466
489
  };
467
490
  });
468
491
  }
469
- const STR_PLAN_KEYS = ['value', 'from', 'to', 'prefix', 'suffix', 'pattern', 'format'];
492
+ const STR_PLAN_KEYS = ['value', 'from', 'to', 'prefix', 'suffix', 'pattern', 'format', 'template', 'refTable', 'refColumn'];
470
493
  const NUM_PLAN_KEYS = ['min', 'max', 'precision', 'minLen', 'maxLen', 'nullPct', 'start', 'step'];
471
494
  function sanitizeColumnPlan(raw) {
472
495
  if (!raw || typeof raw !== 'object')
@@ -475,24 +498,25 @@ function sanitizeColumnPlan(raw) {
475
498
  if (typeof r.strategy !== 'string' || !r.strategy)
476
499
  return null;
477
500
  const out = { strategy: r.strategy };
478
- if (r.values !== undefined && r.values !== null && Array.isArray(r.values)) {
479
- out.values = r.values.map((x) => String(x));
501
+ if (Array.isArray(r.values)) {
502
+ out.values = r.values.map(String);
503
+ }
504
+ if (r.unique !== undefined && r.unique !== null) {
505
+ out.unique = Boolean(r.unique);
480
506
  }
481
507
  if (r.jsonKeys !== undefined && r.jsonKeys !== null) {
482
508
  const rawKeys = Array.isArray(r.jsonKeys) ? r.jsonKeys.map(String) : String(r.jsonKeys).split(/[,;]/);
483
509
  out.jsonKeys = rawKeys.map((s) => s.trim()).filter(Boolean);
484
510
  }
485
511
  for (const key of STR_PLAN_KEYS) {
486
- if (r[key] !== undefined && r[key] !== null) {
512
+ if (r[key] !== undefined && r[key] !== null)
487
513
  out[key] = String(r[key]);
488
- }
489
514
  }
490
515
  for (const key of NUM_PLAN_KEYS) {
491
516
  if (r[key] !== undefined && r[key] !== null) {
492
517
  const n = Number(r[key]);
493
- if (Number.isFinite(n)) {
518
+ if (Number.isFinite(n))
494
519
  out[key] = n;
495
- }
496
520
  }
497
521
  }
498
522
  if (r.jsonValues && typeof r.jsonValues === 'object' && !Array.isArray(r.jsonValues)) {
@@ -1 +1 @@
1
- import type {IDatabase,TableInfoData,WhereClause} from '../db/index';import{type ColumnGeneratorConfig,type ColumnPlan,type GenerateResult} from './types';export declare function generateRows(db:IDatabase,info:TableInfoData,configs:ColumnGeneratorConfig[],count:number,plan?:Record<string,ColumnPlan>,truncate?:boolean):Promise<GenerateResult>;export declare function buildSeedInsertSql(table:string,rows:WhereClause[][]):string;
1
+ import type {IDatabase,TableInfoData,WhereClause} from '../db/index';import{type ColumnGeneratorConfig,type ColumnPlan,type ErChainResult,type GenerateResult,type GenerationOptions,type GenerationPlan} from './types';export declare class SeedEngine{static executePlan(db:IDatabase,plan:GenerationPlan,optionsOverride?:Partial<GenerationOptions>):Promise<ErChainResult>;}export declare function buildSeedInsertSql(table:string,rows:WhereClause[][]):string;export declare function buildChainInsertSql(executionOrder:string[],tableResults:ErChainResult['tableResults']):string;export declare function generateRows(db:IDatabase,info:TableInfoData,configs:ColumnGeneratorConfig[],count:number,plan?:Record<string,ColumnPlan>,truncate?:boolean):Promise<GenerateResult>;