@aruvili/api 0.1.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 (158) hide show
  1. package/dist/config.d.ts +22 -0
  2. package/dist/config.d.ts.map +1 -0
  3. package/dist/config.js +34 -0
  4. package/dist/config.js.map +1 -0
  5. package/dist/context.d.ts +7 -0
  6. package/dist/context.d.ts.map +1 -0
  7. package/dist/context.js +3 -0
  8. package/dist/context.js.map +1 -0
  9. package/dist/controllers/index.d.ts +39 -0
  10. package/dist/controllers/index.d.ts.map +1 -0
  11. package/dist/controllers/index.js +39 -0
  12. package/dist/controllers/index.js.map +1 -0
  13. package/dist/db.d.ts +6 -0
  14. package/dist/db.d.ts.map +1 -0
  15. package/dist/db.js +74 -0
  16. package/dist/db.js.map +1 -0
  17. package/dist/index.d.ts +17 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +154 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/middleware/auth.d.ts +15 -0
  22. package/dist/middleware/auth.d.ts.map +1 -0
  23. package/dist/middleware/auth.js +93 -0
  24. package/dist/middleware/auth.js.map +1 -0
  25. package/dist/middleware/body-limit.d.ts +9 -0
  26. package/dist/middleware/body-limit.d.ts.map +1 -0
  27. package/dist/middleware/body-limit.js +15 -0
  28. package/dist/middleware/body-limit.js.map +1 -0
  29. package/dist/middleware/rate-limit.d.ts +6 -0
  30. package/dist/middleware/rate-limit.d.ts.map +1 -0
  31. package/dist/middleware/rate-limit.js +40 -0
  32. package/dist/middleware/rate-limit.js.map +1 -0
  33. package/dist/middleware/rbac.d.ts +10 -0
  34. package/dist/middleware/rbac.d.ts.map +1 -0
  35. package/dist/middleware/rbac.js +61 -0
  36. package/dist/middleware/rbac.js.map +1 -0
  37. package/dist/middleware/tenant.d.ts +3 -0
  38. package/dist/middleware/tenant.d.ts.map +1 -0
  39. package/dist/middleware/tenant.js +19 -0
  40. package/dist/middleware/tenant.js.map +1 -0
  41. package/dist/registry.d.ts +26 -0
  42. package/dist/registry.d.ts.map +1 -0
  43. package/dist/registry.js +112 -0
  44. package/dist/registry.js.map +1 -0
  45. package/dist/routes/auth.d.ts +3 -0
  46. package/dist/routes/auth.d.ts.map +1 -0
  47. package/dist/routes/auth.js +141 -0
  48. package/dist/routes/auth.js.map +1 -0
  49. package/dist/routes/crud.d.ts +7 -0
  50. package/dist/routes/crud.d.ts.map +1 -0
  51. package/dist/routes/crud.js +845 -0
  52. package/dist/routes/crud.js.map +1 -0
  53. package/dist/routes/files.d.ts +7 -0
  54. package/dist/routes/files.d.ts.map +1 -0
  55. package/dist/routes/files.js +123 -0
  56. package/dist/routes/files.js.map +1 -0
  57. package/dist/routes/meta.d.ts +3 -0
  58. package/dist/routes/meta.d.ts.map +1 -0
  59. package/dist/routes/meta.js +352 -0
  60. package/dist/routes/meta.js.map +1 -0
  61. package/dist/scheduler.d.ts +33 -0
  62. package/dist/scheduler.d.ts.map +1 -0
  63. package/dist/scheduler.js +97 -0
  64. package/dist/scheduler.js.map +1 -0
  65. package/dist/utils/link-validator.d.ts +7 -0
  66. package/dist/utils/link-validator.d.ts.map +1 -0
  67. package/dist/utils/link-validator.js +33 -0
  68. package/dist/utils/link-validator.js.map +1 -0
  69. package/dist/utils/resolver.d.ts +5 -0
  70. package/dist/utils/resolver.d.ts.map +1 -0
  71. package/dist/utils/resolver.js +58 -0
  72. package/dist/utils/resolver.js.map +1 -0
  73. package/package.json +24 -0
  74. package/src/api.test.ts +362 -0
  75. package/src/config.d.ts +22 -0
  76. package/src/config.d.ts.map +1 -0
  77. package/src/config.js +34 -0
  78. package/src/config.js.map +1 -0
  79. package/src/config.ts +38 -0
  80. package/src/context.d.ts +7 -0
  81. package/src/context.d.ts.map +1 -0
  82. package/src/context.js +3 -0
  83. package/src/context.js.map +1 -0
  84. package/src/context.ts +8 -0
  85. package/src/controllers/index.d.ts +39 -0
  86. package/src/controllers/index.d.ts.map +1 -0
  87. package/src/controllers/index.js +39 -0
  88. package/src/controllers/index.js.map +1 -0
  89. package/src/controllers/index.ts +51 -0
  90. package/src/db.d.ts +6 -0
  91. package/src/db.d.ts.map +1 -0
  92. package/src/db.js +74 -0
  93. package/src/db.js.map +1 -0
  94. package/src/db.ts +73 -0
  95. package/src/index.ts +178 -0
  96. package/src/integration.test.ts +453 -0
  97. package/src/middleware/auth.d.ts +15 -0
  98. package/src/middleware/auth.d.ts.map +1 -0
  99. package/src/middleware/auth.js +93 -0
  100. package/src/middleware/auth.js.map +1 -0
  101. package/src/middleware/auth.ts +109 -0
  102. package/src/middleware/body-limit.d.ts +9 -0
  103. package/src/middleware/body-limit.d.ts.map +1 -0
  104. package/src/middleware/body-limit.js +15 -0
  105. package/src/middleware/body-limit.js.map +1 -0
  106. package/src/middleware/body-limit.ts +16 -0
  107. package/src/middleware/rate-limit.d.ts +6 -0
  108. package/src/middleware/rate-limit.d.ts.map +1 -0
  109. package/src/middleware/rate-limit.js +40 -0
  110. package/src/middleware/rate-limit.js.map +1 -0
  111. package/src/middleware/rate-limit.ts +47 -0
  112. package/src/middleware/rbac.d.ts +10 -0
  113. package/src/middleware/rbac.d.ts.map +1 -0
  114. package/src/middleware/rbac.js +61 -0
  115. package/src/middleware/rbac.js.map +1 -0
  116. package/src/middleware/rbac.ts +71 -0
  117. package/src/middleware/tenant.d.ts +3 -0
  118. package/src/middleware/tenant.d.ts.map +1 -0
  119. package/src/middleware/tenant.js +19 -0
  120. package/src/middleware/tenant.js.map +1 -0
  121. package/src/middleware/tenant.ts +24 -0
  122. package/src/registry.d.ts +26 -0
  123. package/src/registry.d.ts.map +1 -0
  124. package/src/registry.js +112 -0
  125. package/src/registry.js.map +1 -0
  126. package/src/registry.ts +123 -0
  127. package/src/routes/auth.d.ts +3 -0
  128. package/src/routes/auth.d.ts.map +1 -0
  129. package/src/routes/auth.js +141 -0
  130. package/src/routes/auth.js.map +1 -0
  131. package/src/routes/auth.ts +164 -0
  132. package/src/routes/crud.d.ts +7 -0
  133. package/src/routes/crud.d.ts.map +1 -0
  134. package/src/routes/crud.js +845 -0
  135. package/src/routes/crud.js.map +1 -0
  136. package/src/routes/crud.ts +1029 -0
  137. package/src/routes/files.d.ts +7 -0
  138. package/src/routes/files.d.ts.map +1 -0
  139. package/src/routes/files.js +123 -0
  140. package/src/routes/files.js.map +1 -0
  141. package/src/routes/files.ts +143 -0
  142. package/src/routes/meta.d.ts +3 -0
  143. package/src/routes/meta.d.ts.map +1 -0
  144. package/src/routes/meta.js +352 -0
  145. package/src/routes/meta.js.map +1 -0
  146. package/src/routes/meta.ts +448 -0
  147. package/src/scheduler.ts +118 -0
  148. package/src/utils/link-validator.d.ts +7 -0
  149. package/src/utils/link-validator.d.ts.map +1 -0
  150. package/src/utils/link-validator.js +33 -0
  151. package/src/utils/link-validator.js.map +1 -0
  152. package/src/utils/link-validator.ts +45 -0
  153. package/src/utils/resolver.d.ts +5 -0
  154. package/src/utils/resolver.d.ts.map +1 -0
  155. package/src/utils/resolver.js +58 -0
  156. package/src/utils/resolver.js.map +1 -0
  157. package/src/utils/resolver.ts +65 -0
  158. package/tsconfig.json +9 -0
@@ -0,0 +1,7 @@
1
+ import { Hono } from 'hono';
2
+ export declare const filesRouter: Hono<{
3
+ Variables: {
4
+ user: any;
5
+ };
6
+ }, import("hono/types").BlankSchema, "/">;
7
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAM5B,eAAO,MAAM,WAAW;eAAyB;QAAE,IAAI,EAAE,GAAG,CAAA;KAAE;yCAAK,CAAC"}
@@ -0,0 +1,123 @@
1
+ import { Hono } from 'hono';
2
+ import { query } from '../db.js';
3
+ import crypto from 'crypto';
4
+ import fs from 'fs/promises';
5
+ import path from 'path';
6
+ export const filesRouter = new Hono();
7
+ const UPLOADS_DIR = path.join(process.cwd(), 'uploads');
8
+ // Ensure upload directory exists
9
+ async function ensureUploadsDir() {
10
+ try {
11
+ await fs.mkdir(UPLOADS_DIR, { recursive: true });
12
+ }
13
+ catch (err) {
14
+ console.error('Failed to create uploads directory:', err);
15
+ }
16
+ }
17
+ ensureUploadsDir();
18
+ /**
19
+ * POST /api/files/upload
20
+ * Upload a file and attach it optionally to a document field.
21
+ */
22
+ filesRouter.post('/upload', async (c) => {
23
+ const user = c.get('user');
24
+ if (!user || user.roles.includes('Guest')) {
25
+ return c.json({ error: 'Unauthorized: Guest users cannot upload files.' }, 401);
26
+ }
27
+ try {
28
+ const formData = await c.req.parseBody();
29
+ const file = formData['file'];
30
+ if (!file || !(file instanceof File)) {
31
+ return c.json({ error: 'No file uploaded under form key "file".' }, 400);
32
+ }
33
+ const attachedToDocType = formData['attached_to_doctype'];
34
+ const attachedToName = formData['attached_to_name'];
35
+ const attachedToField = formData['attached_to_field'];
36
+ // Convert file to buffer
37
+ const arrayBuffer = await file.arrayBuffer();
38
+ const buffer = Buffer.from(arrayBuffer);
39
+ // Generate unique name
40
+ const fileUuid = crypto.randomUUID();
41
+ const ext = path.extname(file.name);
42
+ const safeName = `${fileUuid}${ext}`;
43
+ const destinationPath = path.join(UPLOADS_DIR, safeName);
44
+ // Save to disk
45
+ await fs.writeFile(destinationPath, buffer);
46
+ const fileUrl = `/api/files/download/${safeName}`;
47
+ const fileSize = file.size;
48
+ const mimeType = file.type || 'application/octet-stream';
49
+ // Save record to DB
50
+ const res = await query(`INSERT INTO _files (
51
+ name, file_name, file_url, file_size, mime_type,
52
+ attached_to_doctype, attached_to_name, attached_to_field, created_by
53
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING *`, [
54
+ fileUuid, file.name, fileUrl, fileSize, mimeType,
55
+ attachedToDocType || null, attachedToName || null, attachedToField || null, user.email
56
+ ]);
57
+ return c.json({ success: true, file: res.rows[0] }, 201);
58
+ }
59
+ catch (err) {
60
+ return c.json({ error: 'File upload failed', details: err.message }, 500);
61
+ }
62
+ });
63
+ /**
64
+ * GET /api/files/download/:name
65
+ * Download/stream a file.
66
+ */
67
+ filesRouter.get('/download/:name', async (c) => {
68
+ const name = c.req.param('name');
69
+ // Prevent directory traversal attacks
70
+ const safeName = path.basename(name);
71
+ const filePath = path.join(UPLOADS_DIR, safeName);
72
+ try {
73
+ const fileBuffer = await fs.readFile(filePath);
74
+ // Resolve MIME Type from DB
75
+ const res = await query('SELECT mime_type, file_name FROM _files WHERE name = $1 OR file_url LIKE $2', [
76
+ safeName.split('.')[0],
77
+ `%/download/${safeName}`
78
+ ]);
79
+ const mimeType = res.rows[0]?.mime_type || 'application/octet-stream';
80
+ const originalName = res.rows[0]?.file_name || safeName;
81
+ c.header('Content-Type', mimeType);
82
+ c.header('Content-Disposition', `inline; filename="${originalName}"`);
83
+ return c.body(fileBuffer);
84
+ }
85
+ catch (err) {
86
+ return c.json({ error: 'File not found' }, 404);
87
+ }
88
+ });
89
+ /**
90
+ * DELETE /api/files/:name
91
+ * Delete an attachment.
92
+ */
93
+ filesRouter.delete('/:name', async (c) => {
94
+ const user = c.get('user');
95
+ if (!user || user.roles.includes('Guest')) {
96
+ return c.json({ error: 'Unauthorized' }, 401);
97
+ }
98
+ const name = c.req.param('name');
99
+ try {
100
+ const res = await query('SELECT * FROM _files WHERE name = $1', [name]);
101
+ if (res.rows.length === 0) {
102
+ return c.json({ error: 'File attachment record not found.' }, 404);
103
+ }
104
+ const record = res.rows[0];
105
+ // Delete from disk
106
+ const safeName = path.basename(record.file_url);
107
+ const filePath = path.join(UPLOADS_DIR, safeName);
108
+ try {
109
+ await fs.unlink(filePath);
110
+ }
111
+ catch (e) {
112
+ // Log error but proceed if file was already removed from disk
113
+ console.warn(`File file not found on disk: ${filePath}`);
114
+ }
115
+ // Delete record from DB
116
+ await query('DELETE FROM _files WHERE name = $1', [name]);
117
+ return c.json({ success: true, message: 'Attachment deleted successfully.' });
118
+ }
119
+ catch (err) {
120
+ return c.json({ error: 'Failed to delete attachment', details: err.message }, 500);
121
+ }
122
+ });
123
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ import { Hono } from 'hono';
2
+ import { query } from '../db.js';
3
+ import crypto from 'crypto';
4
+ import fs from 'fs/promises';
5
+ import path from 'path';
6
+
7
+ export const filesRouter = new Hono<{ Variables: { user: any } }>();
8
+
9
+ const UPLOADS_DIR = path.join(process.cwd(), 'uploads');
10
+
11
+ // Ensure upload directory exists
12
+ async function ensureUploadsDir() {
13
+ try {
14
+ await fs.mkdir(UPLOADS_DIR, { recursive: true });
15
+ } catch (err) {
16
+ console.error('Failed to create uploads directory:', err);
17
+ }
18
+ }
19
+ ensureUploadsDir();
20
+
21
+ /**
22
+ * POST /api/files/upload
23
+ * Upload a file and attach it optionally to a document field.
24
+ */
25
+ filesRouter.post('/upload', async (c) => {
26
+ const user = c.get('user');
27
+ if (!user || user.roles.includes('Guest')) {
28
+ return c.json({ error: 'Unauthorized: Guest users cannot upload files.' }, 401);
29
+ }
30
+
31
+ try {
32
+ const formData = await c.req.parseBody();
33
+ const file = formData['file'];
34
+
35
+ if (!file || !(file instanceof File)) {
36
+ return c.json({ error: 'No file uploaded under form key "file".' }, 400);
37
+ }
38
+
39
+ const attachedToDocType = formData['attached_to_doctype'] as string | undefined;
40
+ const attachedToName = formData['attached_to_name'] as string | undefined;
41
+ const attachedToField = formData['attached_to_field'] as string | undefined;
42
+
43
+ // Convert file to buffer
44
+ const arrayBuffer = await file.arrayBuffer();
45
+ const buffer = Buffer.from(arrayBuffer);
46
+
47
+ // Generate unique name
48
+ const fileUuid = crypto.randomUUID();
49
+ const ext = path.extname(file.name);
50
+ const safeName = `${fileUuid}${ext}`;
51
+ const destinationPath = path.join(UPLOADS_DIR, safeName);
52
+
53
+ // Save to disk
54
+ await fs.writeFile(destinationPath, buffer);
55
+
56
+ const fileUrl = `/api/files/download/${safeName}`;
57
+ const fileSize = file.size;
58
+ const mimeType = file.type || 'application/octet-stream';
59
+
60
+ // Save record to DB
61
+ const res = await query(
62
+ `INSERT INTO _files (
63
+ name, file_name, file_url, file_size, mime_type,
64
+ attached_to_doctype, attached_to_name, attached_to_field, created_by
65
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING *`,
66
+ [
67
+ fileUuid, file.name, fileUrl, fileSize, mimeType,
68
+ attachedToDocType || null, attachedToName || null, attachedToField || null, user.email
69
+ ]
70
+ );
71
+
72
+ return c.json({ success: true, file: res.rows[0] }, 201);
73
+ } catch (err: any) {
74
+ return c.json({ error: 'File upload failed', details: err.message }, 500);
75
+ }
76
+ });
77
+
78
+ /**
79
+ * GET /api/files/download/:name
80
+ * Download/stream a file.
81
+ */
82
+ filesRouter.get('/download/:name', async (c) => {
83
+ const name = c.req.param('name');
84
+ // Prevent directory traversal attacks
85
+ const safeName = path.basename(name);
86
+ const filePath = path.join(UPLOADS_DIR, safeName);
87
+
88
+ try {
89
+ const fileBuffer = await fs.readFile(filePath);
90
+
91
+ // Resolve MIME Type from DB
92
+ const res = await query('SELECT mime_type, file_name FROM _files WHERE name = $1 OR file_url LIKE $2', [
93
+ safeName.split('.')[0],
94
+ `%/download/${safeName}`
95
+ ]);
96
+ const mimeType = res.rows[0]?.mime_type || 'application/octet-stream';
97
+ const originalName = res.rows[0]?.file_name || safeName;
98
+
99
+ c.header('Content-Type', mimeType);
100
+ c.header('Content-Disposition', `inline; filename="${originalName}"`);
101
+ return c.body(fileBuffer);
102
+ } catch (err) {
103
+ return c.json({ error: 'File not found' }, 404);
104
+ }
105
+ });
106
+
107
+ /**
108
+ * DELETE /api/files/:name
109
+ * Delete an attachment.
110
+ */
111
+ filesRouter.delete('/:name', async (c) => {
112
+ const user = c.get('user');
113
+ if (!user || user.roles.includes('Guest')) {
114
+ return c.json({ error: 'Unauthorized' }, 401);
115
+ }
116
+
117
+ const name = c.req.param('name');
118
+
119
+ try {
120
+ const res = await query('SELECT * FROM _files WHERE name = $1', [name]);
121
+ if (res.rows.length === 0) {
122
+ return c.json({ error: 'File attachment record not found.' }, 404);
123
+ }
124
+ const record = res.rows[0];
125
+
126
+ // Delete from disk
127
+ const safeName = path.basename(record.file_url);
128
+ const filePath = path.join(UPLOADS_DIR, safeName);
129
+ try {
130
+ await fs.unlink(filePath);
131
+ } catch (e) {
132
+ // Log error but proceed if file was already removed from disk
133
+ console.warn(`File file not found on disk: ${filePath}`);
134
+ }
135
+
136
+ // Delete record from DB
137
+ await query('DELETE FROM _files WHERE name = $1', [name]);
138
+
139
+ return c.json({ success: true, message: 'Attachment deleted successfully.' });
140
+ } catch (err: any) {
141
+ return c.json({ error: 'Failed to delete attachment', details: err.message }, 500);
142
+ }
143
+ });
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ export declare const metaRouter: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
3
+ //# sourceMappingURL=meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK5B,eAAO,MAAM,UAAU,4EAAa,CAAC"}
@@ -0,0 +1,352 @@
1
+ import { Hono } from 'hono';
2
+ import { validateDocType, generateCreateTableDDL, generateAlterTableDDL, getTableName } from '@meta/core';
3
+ import { query, withTransaction } from '../db.js';
4
+ import { registry } from '../registry.js';
5
+ export const metaRouter = new Hono();
6
+ /**
7
+ * Helper to fetch existing columns in target table from postgres database catalog.
8
+ */
9
+ async function getExistingColumns(client, tableName, schema) {
10
+ const sql = `
11
+ SELECT
12
+ column_name AS "columnName",
13
+ data_type AS "dataType",
14
+ is_nullable = 'YES' AS "isNullable",
15
+ character_maximum_length AS "characterMaximumLength"
16
+ FROM information_schema.columns
17
+ WHERE table_name = $1 AND table_schema = $2
18
+ `;
19
+ const res = await client.query(sql, [tableName, schema]);
20
+ return res.rows;
21
+ }
22
+ /**
23
+ * Helper to execute schema synchronization across all registered tenant schemas.
24
+ */
25
+ async function syncDatabaseSchema(client, definition) {
26
+ const tableName = getTableName(definition.name);
27
+ // Fetch all active tenants
28
+ const tenantsRes = await client.query('SELECT id FROM _tenants');
29
+ const tenantIds = tenantsRes.rows.map((r) => r.id);
30
+ // Sync both public schema and all tenant schemas
31
+ const schemas = Array.from(new Set(['public', ...tenantIds]));
32
+ let totalDdlExecuted = [];
33
+ for (const schema of schemas) {
34
+ // 1. Temporarily swap search path to target schema
35
+ await client.query(`SET search_path TO ${schema}, public`);
36
+ // 2. Check if table exists in the target schema
37
+ const checkTableRes = await client.query(`SELECT EXISTS (
38
+ SELECT FROM information_schema.tables
39
+ WHERE table_name = $1 AND table_schema = $2
40
+ )`, [tableName, schema]);
41
+ const tableExists = checkTableRes.rows[0].exists;
42
+ let ddl = [];
43
+ if (!tableExists) {
44
+ ddl = generateCreateTableDDL(definition);
45
+ }
46
+ else {
47
+ const cols = await getExistingColumns(client, tableName, schema);
48
+ ddl = generateAlterTableDDL(definition, cols);
49
+ }
50
+ // 3. Run migration DDL
51
+ for (const sql of ddl) {
52
+ await client.query(sql);
53
+ totalDdlExecuted.push(`[${schema}] ${sql}`);
54
+ }
55
+ }
56
+ return totalDdlExecuted;
57
+ }
58
+ /**
59
+ * POST /api/meta/doctypes
60
+ * Create a new DocType. Fails with 409 Conflict if duplicate.
61
+ */
62
+ metaRouter.post('/doctypes', async (c) => {
63
+ const definition = await c.req.json();
64
+ // 1. Perform structural integrity checks on the submitted definition
65
+ const valResult = validateDocType(definition);
66
+ if (!valResult.valid) {
67
+ return c.json({ error: 'Schema validation failed', details: valResult.errors }, 400);
68
+ }
69
+ try {
70
+ const output = await withTransaction(async (client) => {
71
+ // 2. Check if DocType already exists to satisfy Task 2.1
72
+ const checkExists = await client.query('SELECT 1 FROM _doctype_meta WHERE name = $1', [definition.name]);
73
+ if (checkExists.rows.length > 0) {
74
+ throw new Error(`Conflict: DocType '${definition.name}' already exists.`);
75
+ }
76
+ // 3. Insert active metadata registry record
77
+ await client.query(`INSERT INTO _doctype_meta (name, definition, updated_at)
78
+ VALUES ($1, $2, NOW())`, [definition.name, JSON.stringify(definition)]);
79
+ // 4. Perform dynamic schema synchronization across all tenant databases
80
+ const ddlExecuted = await syncDatabaseSchema(client, definition);
81
+ // 5. Log migration history
82
+ if (ddlExecuted.length > 0) {
83
+ await client.query(`INSERT INTO _doctype_migration_history (doctype_name, version, ddl_executed, executed_by)
84
+ VALUES ($1, 1, $2, $3)`, [definition.name, ddlExecuted.join('\n'), 'System Admin']);
85
+ }
86
+ // 6. Log version history tracking (Task 2.3)
87
+ await client.query(`INSERT INTO _doctype_definition_history (doctype_name, version, definition, changed_by, ddl_applied, notes)
88
+ VALUES ($1, 1, $2, $3, $4, $5)`, [
89
+ definition.name,
90
+ JSON.stringify(definition),
91
+ 'System Admin',
92
+ ddlExecuted.join('\n'),
93
+ 'Initial definition creation'
94
+ ]);
95
+ // Invalidate cache immediately
96
+ registry.invalidate(definition.name);
97
+ return {
98
+ doctype: definition.name,
99
+ table: getTableName(definition.name),
100
+ action: 'CREATED',
101
+ version: 1,
102
+ changes_applied: ddlExecuted
103
+ };
104
+ });
105
+ return c.json(output);
106
+ }
107
+ catch (err) {
108
+ if (err.message.includes('Conflict:')) {
109
+ return c.json({ error: err.message }, 409);
110
+ }
111
+ console.error('Doctype creation failed:', err);
112
+ return c.json({ error: 'Failed to create database metadata', details: err.message }, 500);
113
+ }
114
+ });
115
+ /**
116
+ * PUT /api/meta/doctypes/:name
117
+ * Update an existing DocType definition.
118
+ */
119
+ metaRouter.put('/doctypes/:name', async (c) => {
120
+ const name = c.req.param('name');
121
+ const definition = await c.req.json();
122
+ if (definition.name !== name) {
123
+ return c.json({ error: 'Doctype name mismatch between URL and payload' }, 400);
124
+ }
125
+ // 1. Perform structural integrity checks on the submitted definition
126
+ const valResult = validateDocType(definition);
127
+ if (!valResult.valid) {
128
+ return c.json({ error: 'Schema validation failed', details: valResult.errors }, 400);
129
+ }
130
+ try {
131
+ const output = await withTransaction(async (client) => {
132
+ // 2. Verify existence
133
+ const checkExists = await client.query('SELECT 1 FROM _doctype_meta WHERE name = $1', [name]);
134
+ if (checkExists.rows.length === 0) {
135
+ throw new Error(`NotFound: DocType '${name}' does not exist.`);
136
+ }
137
+ // 3. Compute next version number
138
+ const versionRes = await client.query('SELECT COALESCE(MAX(version), 0) + 1 AS next FROM _doctype_definition_history WHERE doctype_name = $1', [name]);
139
+ const nextVersion = versionRes.rows[0].next;
140
+ // 4. Perform dynamic schema synchronization across all tenant databases
141
+ const ddlExecuted = await syncDatabaseSchema(client, definition);
142
+ // 5. Update active registry
143
+ await client.query(`UPDATE _doctype_meta SET definition = $2, updated_at = NOW() WHERE name = $1`, [name, JSON.stringify(definition)]);
144
+ // 6. Log migration history
145
+ if (ddlExecuted.length > 0) {
146
+ await client.query(`INSERT INTO _doctype_migration_history (doctype_name, version, ddl_executed, executed_by)
147
+ VALUES ($1, $2, $3, $4)`, [name, nextVersion, ddlExecuted.join('\n'), 'System Admin']);
148
+ }
149
+ // 7. Log version history tracking (Task 2.3)
150
+ await client.query(`INSERT INTO _doctype_definition_history (doctype_name, version, definition, changed_by, ddl_applied, notes)
151
+ VALUES ($1, $2, $3, $4, $5, $6)`, [
152
+ name,
153
+ nextVersion,
154
+ JSON.stringify(definition),
155
+ 'System Admin',
156
+ ddlExecuted.join('\n'),
157
+ 'Updated definition schema'
158
+ ]);
159
+ // Invalidate cache
160
+ registry.invalidate(name);
161
+ return {
162
+ doctype: name,
163
+ table: getTableName(name),
164
+ action: 'MIGRATED',
165
+ version: nextVersion,
166
+ changes_applied: ddlExecuted
167
+ };
168
+ });
169
+ return c.json(output);
170
+ }
171
+ catch (err) {
172
+ if (err.message.includes('NotFound:')) {
173
+ return c.json({ error: err.message }, 404);
174
+ }
175
+ console.error('Doctype update failed:', err);
176
+ return c.json({ error: 'Failed to update database metadata', details: err.message }, 500);
177
+ }
178
+ });
179
+ /**
180
+ * GET /api/meta/doctypes/:name/history
181
+ * Retrieve historical configuration log.
182
+ */
183
+ metaRouter.get('/doctypes/:name/history', async (c) => {
184
+ const name = c.req.param('name');
185
+ try {
186
+ const res = await query(`SELECT version, changed_by, changed_at, notes, ddl_applied, definition
187
+ FROM _doctype_definition_history
188
+ WHERE doctype_name = $1
189
+ ORDER BY version DESC`, [name]);
190
+ return c.json(res.rows);
191
+ }
192
+ catch (err) {
193
+ return c.json({ error: 'Failed to fetch metadata history', details: err.message }, 500);
194
+ }
195
+ });
196
+ /**
197
+ * POST /api/meta/doctypes/:name/revert
198
+ * Revert doctype metadata schema and trigger safe migrations to target version.
199
+ */
200
+ metaRouter.post('/doctypes/:name/revert', async (c) => {
201
+ const name = c.req.param('name');
202
+ const body = await c.req.json();
203
+ const targetVersion = body.version;
204
+ if (typeof targetVersion !== 'number') {
205
+ return c.json({ error: 'Missing or invalid version number in body' }, 400);
206
+ }
207
+ try {
208
+ const output = await withTransaction(async (client) => {
209
+ // 1. Retrieve definition from history
210
+ const historyRes = await client.query(`SELECT definition FROM _doctype_definition_history
211
+ WHERE doctype_name = $1 AND version = $2`, [name, targetVersion]);
212
+ if (historyRes.rows.length === 0) {
213
+ throw new Error(`NotFound: Version ${targetVersion} for DocType '${name}' was not found.`);
214
+ }
215
+ const targetDefinition = historyRes.rows[0].definition;
216
+ // 2. Compute next version number
217
+ const versionRes = await client.query('SELECT COALESCE(MAX(version), 0) + 1 AS next FROM _doctype_definition_history WHERE doctype_name = $1', [name]);
218
+ const nextVersion = versionRes.rows[0].next;
219
+ // 3. Perform dynamic schema synchronization across all tenant databases
220
+ const ddlExecuted = await syncDatabaseSchema(client, targetDefinition);
221
+ // 4. Update active registry
222
+ await client.query(`UPDATE _doctype_meta SET definition = $2, updated_at = NOW() WHERE name = $1`, [name, JSON.stringify(targetDefinition)]);
223
+ // 5. Log migration history
224
+ if (ddlExecuted.length > 0) {
225
+ await client.query(`INSERT INTO _doctype_migration_history (doctype_name, version, ddl_executed, executed_by)
226
+ VALUES ($1, $2, $3, $4)`, [name, nextVersion, ddlExecuted.join('\n'), 'System Admin']);
227
+ }
228
+ // 6. Log version history tracking
229
+ await client.query(`INSERT INTO _doctype_definition_history (doctype_name, version, definition, changed_by, ddl_applied, notes)
230
+ VALUES ($1, $2, $3, $4, $5, $6)`, [
231
+ name,
232
+ nextVersion,
233
+ JSON.stringify(targetDefinition),
234
+ 'System Admin',
235
+ ddlExecuted.join('\n'),
236
+ `Reverted active schema to version ${targetVersion}`
237
+ ]);
238
+ // Invalidate cache
239
+ registry.invalidate(name);
240
+ return {
241
+ doctype: name,
242
+ table: getTableName(name),
243
+ action: 'REVERTED',
244
+ version: nextVersion,
245
+ changes_applied: ddlExecuted
246
+ };
247
+ });
248
+ return c.json(output);
249
+ }
250
+ catch (err) {
251
+ if (err.message.includes('NotFound:')) {
252
+ return c.json({ error: err.message }, 404);
253
+ }
254
+ console.error('Revert failed:', err);
255
+ return c.json({ error: 'Failed to revert metadata schema', details: err.message }, 500);
256
+ }
257
+ });
258
+ /**
259
+ * POST /api/meta/tenants
260
+ * Register a new tenant, create its Postgres schema, and migrate all existing definitions.
261
+ */
262
+ metaRouter.post('/tenants', async (c) => {
263
+ const body = await c.req.json();
264
+ const { id, name, domain } = body;
265
+ if (!id || !name) {
266
+ return c.json({ error: 'Tenant id and name are required' }, 400);
267
+ }
268
+ const TENANT_REGEX = /^[a-zA-Z0-9_]{1,63}$/;
269
+ if (!TENANT_REGEX.test(id)) {
270
+ return c.json({ error: 'Invalid Tenant ID format' }, 400);
271
+ }
272
+ const tenantId = id.toLowerCase().trim();
273
+ try {
274
+ const output = await withTransaction(async (client) => {
275
+ // 1. Check if tenant already exists
276
+ const checkRes = await client.query('SELECT 1 FROM _tenants WHERE id = $1', [tenantId]);
277
+ if (checkRes.rows.length > 0) {
278
+ throw new Error(`Conflict: Tenant '${tenantId}' already exists.`);
279
+ }
280
+ // 2. Insert tenant record into central _tenants table
281
+ await client.query(`INSERT INTO _tenants (id, name, domain) VALUES ($1, $2, $3)`, [tenantId, name, domain || null]);
282
+ // 3. Create the schema for the tenant
283
+ await client.query(`CREATE SCHEMA IF NOT EXISTS ${tenantId}`);
284
+ // 4. Retrieve all current doctypes to copy schemas to the new tenant schema
285
+ const doctypesRes = await client.query('SELECT definition FROM _doctype_meta');
286
+ const doctypes = doctypesRes.rows.map((row) => row.definition);
287
+ const createdTables = [];
288
+ // Temporarily swap search_path to the new tenant schema to run table creations
289
+ await client.query(`SET search_path TO ${tenantId}, public`);
290
+ for (const doc of doctypes) {
291
+ const ddl = generateCreateTableDDL(doc);
292
+ for (const sql of ddl) {
293
+ await client.query(sql);
294
+ }
295
+ createdTables.push(doc.name);
296
+ }
297
+ return {
298
+ tenantId,
299
+ name,
300
+ domain,
301
+ createdTables
302
+ };
303
+ });
304
+ return c.json(output);
305
+ }
306
+ catch (err) {
307
+ if (err.message.includes('Conflict:')) {
308
+ return c.json({ error: err.message }, 409);
309
+ }
310
+ console.error('Tenant registration failed:', err);
311
+ return c.json({ error: 'Failed to register tenant', details: err.message }, 500);
312
+ }
313
+ });
314
+ /**
315
+ * GET /api/meta/tenants
316
+ * List all registered tenants.
317
+ */
318
+ metaRouter.get('/tenants', async (c) => {
319
+ try {
320
+ const res = await query('SELECT id, name, domain, created_at FROM _tenants ORDER BY id ASC');
321
+ return c.json(res.rows);
322
+ }
323
+ catch (err) {
324
+ return c.json({ error: 'Failed to retrieve tenants', details: err.message }, 500);
325
+ }
326
+ });
327
+ /**
328
+ * GET /api/meta/doctypes
329
+ * List all definitions.
330
+ */
331
+ metaRouter.get('/doctypes', async (c) => {
332
+ try {
333
+ const res = await query('SELECT name, created_at, updated_at FROM _doctype_meta ORDER BY name ASC');
334
+ return c.json(res.rows);
335
+ }
336
+ catch (err) {
337
+ return c.json({ error: 'Failed to retrieve doctypes list', details: err.message }, 500);
338
+ }
339
+ });
340
+ /**
341
+ * GET /api/meta/doctypes/:name
342
+ * Retrieve specific definition metadata.
343
+ */
344
+ metaRouter.get('/doctypes/:name', async (c) => {
345
+ const name = c.req.param('name');
346
+ const doc = await registry.get(name);
347
+ if (!doc) {
348
+ return c.json({ error: `DocType '${name}' not found` }, 404);
349
+ }
350
+ return c.json(doc);
351
+ });
352
+ //# sourceMappingURL=meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["meta.ts"],"names":[],"mappings":"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"}