@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,22 @@
1
+ /**
2
+ * Meta Framework - Centralized Configuration Module
3
+ * Validates all required environment variables at startup.
4
+ */
5
+ export declare const config: {
6
+ port: number;
7
+ nodeEnv: string;
8
+ isProduction: boolean;
9
+ databaseUrl: string;
10
+ dbPoolMax: number;
11
+ dbIdleTimeout: number;
12
+ dbConnectTimeout: number;
13
+ dbStatementTimeout: string;
14
+ jwtSecret: string;
15
+ jwtExpiresIn: number;
16
+ bcryptRounds: number;
17
+ corsOrigins: string[];
18
+ rateLimitMax: number;
19
+ rateLimitWindowMs: number;
20
+ bodyLimitBytes: number;
21
+ };
22
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;CAuBlB,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Meta Framework - Centralized Configuration Module
3
+ * Validates all required environment variables at startup.
4
+ */
5
+ function requireEnv(key, fallback) {
6
+ const value = process.env[key] || fallback;
7
+ if (!value && process.env.NODE_ENV === 'production') {
8
+ console.error(`[CONFIG FATAL] Required environment variable ${key} is not set.`);
9
+ process.exit(1);
10
+ }
11
+ return value || '';
12
+ }
13
+ export const config = {
14
+ // Server
15
+ port: parseInt(process.env.PORT || '3000'),
16
+ nodeEnv: process.env.NODE_ENV || 'development',
17
+ isProduction: process.env.NODE_ENV === 'production',
18
+ // Database
19
+ databaseUrl: requireEnv('DATABASE_URL', 'postgresql://postgres:postgres@localhost:5432/meta_db'),
20
+ dbPoolMax: parseInt(process.env.DB_POOL_MAX || '20'),
21
+ dbIdleTimeout: parseInt(process.env.DB_IDLE_TIMEOUT || '30000'),
22
+ dbConnectTimeout: parseInt(process.env.DB_CONNECT_TIMEOUT || '5000'),
23
+ dbStatementTimeout: process.env.DB_STATEMENT_TIMEOUT || '30000',
24
+ // Auth
25
+ jwtSecret: requireEnv('JWT_SECRET', 'dev-secret-change-in-production'),
26
+ jwtExpiresIn: parseInt(process.env.JWT_EXPIRES_IN || '86400'), // 24 hours
27
+ bcryptRounds: parseInt(process.env.BCRYPT_ROUNDS || '12'),
28
+ // Security
29
+ corsOrigins: (process.env.CORS_ORIGINS || '*').split(',').map(s => s.trim()),
30
+ rateLimitMax: parseInt(process.env.RATE_LIMIT_MAX || '100'),
31
+ rateLimitWindowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '60000'),
32
+ bodyLimitBytes: parseInt(process.env.BODY_LIMIT_BYTES || '1048576'), // 1MB
33
+ };
34
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,SAAS,UAAU,CAAC,GAAW,EAAE,QAAiB;IAChD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC;IAC3C,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QACpD,OAAO,CAAC,KAAK,CAAC,gDAAgD,GAAG,cAAc,CAAC,CAAC;QACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,KAAK,IAAI,EAAE,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,SAAS;IACT,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,aAAa;IAC9C,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;IAEnD,WAAW;IACX,WAAW,EAAE,UAAU,CAAC,cAAc,EAAE,uDAAuD,CAAC;IAChG,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC;IACpD,aAAa,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,OAAO,CAAC;IAC/D,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,MAAM,CAAC;IACpE,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO;IAE/D,OAAO;IACP,SAAS,EAAE,UAAU,CAAC,YAAY,EAAE,iCAAiC,CAAC;IACtE,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,OAAO,CAAC,EAAE,WAAW;IAC1E,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC;IAEzD,WAAW;IACX,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5E,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,KAAK,CAAC;IAC3D,iBAAiB,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,CAAC;IACxE,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,SAAS,CAAC,EAAE,MAAM;CAC5E,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { AsyncLocalStorage } from 'async_hooks';
2
+ export interface RequestContextStore {
3
+ tenantId?: string;
4
+ user?: any;
5
+ }
6
+ export declare const requestContext: AsyncLocalStorage<RequestContextStore>;
7
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED,eAAO,MAAM,cAAc,wCAA+C,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { AsyncLocalStorage } from 'async_hooks';
2
+ export const requestContext = new AsyncLocalStorage();
3
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAOhD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,iBAAiB,EAAuB,CAAC"}
@@ -0,0 +1,39 @@
1
+ import pg from 'pg';
2
+ export interface ControllerContext {
3
+ db: pg.PoolClient;
4
+ user: {
5
+ email: string;
6
+ roles: string[];
7
+ };
8
+ }
9
+ export declare abstract class DocTypeController {
10
+ before_insert(doc: any, ctx: ControllerContext): Promise<void>;
11
+ after_insert(doc: any, ctx: ControllerContext): Promise<void>;
12
+ before_save(doc: any, ctx: ControllerContext): Promise<void>;
13
+ on_update(doc: any, oldDoc: any, ctx: ControllerContext): Promise<void>;
14
+ before_delete(doc: any, ctx: ControllerContext): Promise<void>;
15
+ on_trash(doc: any, ctx: ControllerContext): Promise<void>;
16
+ before_submit(doc: any, ctx: ControllerContext): Promise<void>;
17
+ on_submit(doc: any, ctx: ControllerContext): Promise<void>;
18
+ before_cancel(doc: any, ctx: ControllerContext): Promise<void>;
19
+ on_cancel(doc: any, ctx: ControllerContext): Promise<void>;
20
+ }
21
+ declare class ControllerRegistry {
22
+ private controllers;
23
+ register(doctypeName: string, controller: DocTypeController): void;
24
+ get(doctypeName: string): DocTypeController | undefined;
25
+ private trigger;
26
+ triggerBeforeInsert(n: string, doc: any, ctx: ControllerContext): Promise<void>;
27
+ triggerAfterInsert(n: string, doc: any, ctx: ControllerContext): Promise<void>;
28
+ triggerBeforeSave(n: string, doc: any, ctx: ControllerContext): Promise<void>;
29
+ triggerOnUpdate(n: string, doc: any, old: any, ctx: ControllerContext): Promise<void>;
30
+ triggerBeforeDelete(n: string, doc: any, ctx: ControllerContext): Promise<void>;
31
+ triggerOnTrash(n: string, doc: any, ctx: ControllerContext): Promise<void>;
32
+ triggerBeforeSubmit(n: string, doc: any, ctx: ControllerContext): Promise<void>;
33
+ triggerOnSubmit(n: string, doc: any, ctx: ControllerContext): Promise<void>;
34
+ triggerBeforeCancel(n: string, doc: any, ctx: ControllerContext): Promise<void>;
35
+ triggerOnCancel(n: string, doc: any, ctx: ControllerContext): Promise<void>;
36
+ }
37
+ export declare const controllerRegistry: ControllerRegistry;
38
+ export {};
39
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/controllers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC;IAClB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC1C;AAED,8BAAsB,iBAAiB;IAC/B,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9D,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC7D,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC5D,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IACvE,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9D,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IACzD,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9D,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC1D,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9D,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;CACjE;AAED,cAAM,kBAAkB;IACtB,OAAO,CAAC,WAAW,CAAwC;IAEpD,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB;IAI3D,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;YAIhD,OAAO;IAOf,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB;IAC/D,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB;IAC9D,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB;IAC7D,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB;IACrE,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB;IAC/D,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB;IAC1D,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB;IAC/D,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB;IAC3D,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB;IAC/D,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,iBAAiB;CAClE;AAED,eAAO,MAAM,kBAAkB,oBAA2B,CAAC"}
@@ -0,0 +1,39 @@
1
+ export class DocTypeController {
2
+ async before_insert(doc, ctx) { }
3
+ async after_insert(doc, ctx) { }
4
+ async before_save(doc, ctx) { }
5
+ async on_update(doc, oldDoc, ctx) { }
6
+ async before_delete(doc, ctx) { }
7
+ async on_trash(doc, ctx) { }
8
+ async before_submit(doc, ctx) { }
9
+ async on_submit(doc, ctx) { }
10
+ async before_cancel(doc, ctx) { }
11
+ async on_cancel(doc, ctx) { }
12
+ }
13
+ class ControllerRegistry {
14
+ controllers = new Map();
15
+ register(doctypeName, controller) {
16
+ this.controllers.set(doctypeName, controller);
17
+ }
18
+ get(doctypeName) {
19
+ return this.controllers.get(doctypeName);
20
+ }
21
+ async trigger(name, method, ...args) {
22
+ const ctrl = this.get(name);
23
+ if (ctrl && typeof ctrl[method] === 'function') {
24
+ await ctrl[method](...args);
25
+ }
26
+ }
27
+ async triggerBeforeInsert(n, doc, ctx) { await this.trigger(n, 'before_insert', doc, ctx); }
28
+ async triggerAfterInsert(n, doc, ctx) { await this.trigger(n, 'after_insert', doc, ctx); }
29
+ async triggerBeforeSave(n, doc, ctx) { await this.trigger(n, 'before_save', doc, ctx); }
30
+ async triggerOnUpdate(n, doc, old, ctx) { await this.trigger(n, 'on_update', doc, old, ctx); }
31
+ async triggerBeforeDelete(n, doc, ctx) { await this.trigger(n, 'before_delete', doc, ctx); }
32
+ async triggerOnTrash(n, doc, ctx) { await this.trigger(n, 'on_trash', doc, ctx); }
33
+ async triggerBeforeSubmit(n, doc, ctx) { await this.trigger(n, 'before_submit', doc, ctx); }
34
+ async triggerOnSubmit(n, doc, ctx) { await this.trigger(n, 'on_submit', doc, ctx); }
35
+ async triggerBeforeCancel(n, doc, ctx) { await this.trigger(n, 'before_cancel', doc, ctx); }
36
+ async triggerOnCancel(n, doc, ctx) { await this.trigger(n, 'on_cancel', doc, ctx); }
37
+ }
38
+ export const controllerRegistry = new ControllerRegistry();
39
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/controllers/index.ts"],"names":[],"mappings":"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"}
package/dist/db.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import pg from 'pg';
2
+ export declare const pool: import("pg").Pool;
3
+ export declare function query(text: string, params?: any[]): Promise<any>;
4
+ export declare function withTransaction<T>(callback: (client: pg.PoolClient) => Promise<T>): Promise<T>;
5
+ export declare function closePool(): Promise<void>;
6
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,eAAO,MAAM,IAAI,mBAMf,CAAC;AAMH,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,gBA2BvD;AAED,wBAAsB,eAAe,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAuBpG;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/C"}
package/dist/db.js ADDED
@@ -0,0 +1,74 @@
1
+ import pg from 'pg';
2
+ import { config } from './config.js';
3
+ import { requestContext } from './context.js';
4
+ export const pool = new pg.Pool({
5
+ connectionString: config.databaseUrl,
6
+ max: config.dbPoolMax,
7
+ idleTimeoutMillis: config.dbIdleTimeout,
8
+ connectionTimeoutMillis: config.dbConnectTimeout,
9
+ allowExitOnIdle: false
10
+ });
11
+ pool.on('error', (err) => {
12
+ console.error('[DB POOL ERROR] Unexpected error on idle client:', err);
13
+ });
14
+ export async function query(text, params) {
15
+ if (globalThis.dbMock) {
16
+ return globalThis.dbMock.query(text, params);
17
+ }
18
+ const start = Date.now();
19
+ const client = await pool.connect();
20
+ try {
21
+ const store = requestContext.getStore();
22
+ const tenantId = store?.tenantId || 'public';
23
+ await client.query(`SET search_path TO ${tenantId}, public`);
24
+ const result = await client.query(text, params);
25
+ const duration = Date.now() - start;
26
+ if (duration > 1000) {
27
+ console.warn(`[DB SLOW QUERY] ${duration}ms: ${text.substring(0, 120)}...`);
28
+ }
29
+ return result;
30
+ }
31
+ catch (error) {
32
+ const duration = Date.now() - start;
33
+ console.error(`[DB QUERY ERROR] ${duration}ms | ${text.substring(0, 120)} | ${error.message}`);
34
+ throw error;
35
+ }
36
+ finally {
37
+ try {
38
+ await client.query('RESET search_path');
39
+ }
40
+ catch (_) { }
41
+ client.release();
42
+ }
43
+ }
44
+ export async function withTransaction(callback) {
45
+ if (globalThis.dbMock) {
46
+ return globalThis.dbMock.withTransaction(callback);
47
+ }
48
+ const client = await pool.connect();
49
+ try {
50
+ const store = requestContext.getStore();
51
+ const tenantId = store?.tenantId || 'public';
52
+ await client.query('BEGIN');
53
+ await client.query(`SET search_path TO ${tenantId}, public`);
54
+ await client.query(`SET LOCAL statement_timeout = '${config.dbStatementTimeout}'`);
55
+ const result = await callback(client);
56
+ await client.query('COMMIT');
57
+ return result;
58
+ }
59
+ catch (error) {
60
+ await client.query('ROLLBACK');
61
+ throw error;
62
+ }
63
+ finally {
64
+ try {
65
+ await client.query('RESET search_path');
66
+ }
67
+ catch (_) { }
68
+ client.release();
69
+ }
70
+ }
71
+ export async function closePool() {
72
+ await pool.end();
73
+ }
74
+ //# sourceMappingURL=db.js.map
package/dist/db.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ declare const _default: {
2
+ port: number;
3
+ fetch: (request: Request, Env?: unknown, executionCtx?: import("hono").ExecutionContext) => Response | Promise<Response>;
4
+ };
5
+ export default _default;
6
+ export { metaRouter } from './routes/meta.js';
7
+ export { crudRouter } from './routes/crud.js';
8
+ export { authRouter } from './routes/auth.js';
9
+ export { filesRouter } from './routes/files.js';
10
+ export { tenantMiddleware } from './middleware/tenant.js';
11
+ export { bodyLimitMiddleware } from './middleware/body-limit.js';
12
+ export { rateLimitMiddleware } from './middleware/rate-limit.js';
13
+ export { authMiddleware } from './middleware/auth.js';
14
+ export { rbacMiddleware } from './middleware/rbac.js';
15
+ export { query, withTransaction } from './db.js';
16
+ export { config } from './config.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAoKA,wBAAuD;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,154 @@
1
+ import { Hono } from 'hono';
2
+ import { cors } from 'hono/cors';
3
+ import { config } from './config.js';
4
+ import { metaRouter } from './routes/meta.js';
5
+ import { crudRouter } from './routes/crud.js';
6
+ import { authRouter } from './routes/auth.js';
7
+ import { authMiddleware } from './middleware/auth.js';
8
+ import { rbacMiddleware } from './middleware/rbac.js';
9
+ import { rateLimitMiddleware } from './middleware/rate-limit.js';
10
+ import { bodyLimitMiddleware } from './middleware/body-limit.js';
11
+ import { query, closePool } from './db.js';
12
+ import { filesRouter } from './routes/files.js';
13
+ import { tenantMiddleware } from './middleware/tenant.js';
14
+ import crypto from 'crypto';
15
+ const app = new Hono();
16
+ // Global Middleware Stack
17
+ // CORS
18
+ app.use('*', cors({
19
+ origin: config.corsOrigins.includes('*') ? '*' : config.corsOrigins,
20
+ allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
21
+ allowHeaders: ['Content-Type', 'Authorization'],
22
+ exposeHeaders: ['X-Request-ID', 'X-RateLimit-Limit', 'X-RateLimit-Remaining', 'X-RateLimit-Reset'],
23
+ maxAge: 86400
24
+ }));
25
+ // Request ID + structured logging
26
+ app.use('*', async (c, next) => {
27
+ const requestId = crypto.randomUUID();
28
+ c.set('request_id', requestId);
29
+ c.header('X-Request-ID', requestId);
30
+ const start = Date.now();
31
+ await next();
32
+ console.log(JSON.stringify({
33
+ level: 'info', type: 'http', method: c.req.method, url: c.req.url,
34
+ status: c.res.status, duration_ms: Date.now() - start, request_id: requestId
35
+ }));
36
+ });
37
+ // Tenant Isolation Context
38
+ app.use('*', tenantMiddleware);
39
+ // Body size limit
40
+ app.use('*', bodyLimitMiddleware);
41
+ // Rate limiting
42
+ app.use('*', rateLimitMiddleware);
43
+ // Error handler - hide details in production
44
+ app.onError((err, c) => {
45
+ const requestId = c.get('request_id') || crypto.randomUUID();
46
+ console.error(JSON.stringify({
47
+ level: 'error', type: 'exception', request_id: requestId,
48
+ message: err.message, stack: config.isProduction ? undefined : err.stack
49
+ }));
50
+ return c.json({
51
+ error: 'Internal Server Error', request_id: requestId,
52
+ ...(config.isProduction ? {} : { message: err.message })
53
+ }, 500);
54
+ });
55
+ // === Public Routes (no auth required) ===
56
+ app.get('/api/health', (c) => c.json({ status: 'ok', timestamp: new Date().toISOString() }));
57
+ app.route('/api/auth', authRouter);
58
+ app.route('/api/meta', metaRouter);
59
+ // === Protected Routes ===
60
+ app.use('/api/files/*', authMiddleware);
61
+ app.route('/api/files', filesRouter);
62
+ app.use('/api/doctype/*', authMiddleware, rbacMiddleware);
63
+ app.route('/api/doctype/:doctype', crudRouter);
64
+ // === Bootstrap ===
65
+ async function bootstrapDatabase() {
66
+ console.log('[BOOT] Initializing system database schemas...');
67
+ try {
68
+ // System tables
69
+ await query(`CREATE TABLE IF NOT EXISTS _tenants (
70
+ id VARCHAR(100) PRIMARY KEY,
71
+ name VARCHAR(255) NOT NULL,
72
+ domain VARCHAR(255),
73
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
74
+ );`);
75
+ await query(`CREATE TABLE IF NOT EXISTS _doctype_meta (
76
+ name VARCHAR(255) PRIMARY KEY, uuid UUID DEFAULT gen_random_uuid() UNIQUE NOT NULL,
77
+ definition JSONB NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
78
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());`);
79
+ await query(`CREATE TABLE IF NOT EXISTS _doctype_migration_history (
80
+ id SERIAL PRIMARY KEY, uuid UUID DEFAULT gen_random_uuid() UNIQUE NOT NULL,
81
+ doctype_name VARCHAR(255) NOT NULL, version INTEGER NOT NULL,
82
+ ddl_executed TEXT NOT NULL, executed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
83
+ executed_by VARCHAR(255));`);
84
+ await query(`CREATE TABLE IF NOT EXISTS _doctype_definition_history (
85
+ id SERIAL PRIMARY KEY, uuid UUID DEFAULT gen_random_uuid() UNIQUE NOT NULL,
86
+ doctype_name VARCHAR(255) REFERENCES _doctype_meta(name) ON DELETE CASCADE,
87
+ version INTEGER NOT NULL,
88
+ definition JSONB NOT NULL,
89
+ changed_by VARCHAR(255) NOT NULL,
90
+ changed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
91
+ ddl_applied TEXT,
92
+ notes TEXT);`);
93
+ await query(`CREATE TABLE IF NOT EXISTS _naming_series (
94
+ prefix VARCHAR(100) PRIMARY KEY, uuid UUID DEFAULT gen_random_uuid() UNIQUE NOT NULL,
95
+ current_value INTEGER NOT NULL DEFAULT 0);`);
96
+ await query(`CREATE TABLE IF NOT EXISTS _audit_log (
97
+ id BIGSERIAL PRIMARY KEY, uuid UUID DEFAULT gen_random_uuid() UNIQUE NOT NULL,
98
+ doctype_name VARCHAR(255) NOT NULL, docname VARCHAR(255) NOT NULL,
99
+ action VARCHAR(50) NOT NULL, changed_by VARCHAR(255) NOT NULL,
100
+ changed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), diff JSONB NOT NULL);`);
101
+ // User management table
102
+ await query(`CREATE TABLE IF NOT EXISTS _users (
103
+ name VARCHAR(255) PRIMARY KEY, uuid UUID DEFAULT gen_random_uuid() UNIQUE NOT NULL,
104
+ email VARCHAR(255) UNIQUE NOT NULL, full_name VARCHAR(255) DEFAULT '',
105
+ hashed_password TEXT NOT NULL, roles JSONB DEFAULT '["Guest"]',
106
+ enabled BOOLEAN DEFAULT true, last_login TIMESTAMP WITH TIME ZONE,
107
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
108
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());`);
109
+ // Files attachment tracking table
110
+ await query(`CREATE TABLE IF NOT EXISTS _files (
111
+ name VARCHAR(255) PRIMARY KEY, uuid UUID DEFAULT gen_random_uuid() UNIQUE NOT NULL,
112
+ file_name VARCHAR(255) NOT NULL, file_url VARCHAR(255) NOT NULL,
113
+ file_size INTEGER NOT NULL, mime_type VARCHAR(100) NOT NULL,
114
+ attached_to_doctype VARCHAR(255), attached_to_name VARCHAR(255),
115
+ attached_to_field VARCHAR(255), created_by VARCHAR(255),
116
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());`);
117
+ // System indexes
118
+ await query(`CREATE INDEX IF NOT EXISTS idx_audit_log_doctype ON _audit_log (doctype_name, docname);`);
119
+ await query(`CREATE INDEX IF NOT EXISTS idx_audit_log_changed_at ON _audit_log (changed_at);`);
120
+ await query(`CREATE INDEX IF NOT EXISTS idx_users_email ON _users (email);`);
121
+ console.log('[BOOT] System database schemas initialized successfully.');
122
+ }
123
+ catch (err) {
124
+ console.error('[BOOT ERROR] Failed to initialize system schemas:', err);
125
+ process.exit(1);
126
+ }
127
+ }
128
+ bootstrapDatabase().then(() => {
129
+ console.log(`[BOOT] Server launching on http://localhost:${config.port}`);
130
+ if (!config.isProduction) {
131
+ console.log('[BOOT] Running in DEVELOPMENT mode. Set NODE_ENV=production for production.');
132
+ }
133
+ });
134
+ // Graceful shutdown
135
+ const shutdown = async () => {
136
+ console.log('[SHUTDOWN] Graceful shutdown initiated...');
137
+ await closePool();
138
+ process.exit(0);
139
+ };
140
+ process.on('SIGTERM', shutdown);
141
+ process.on('SIGINT', shutdown);
142
+ export default { port: config.port, fetch: app.fetch };
143
+ export { metaRouter } from './routes/meta.js';
144
+ export { crudRouter } from './routes/crud.js';
145
+ export { authRouter } from './routes/auth.js';
146
+ export { filesRouter } from './routes/files.js';
147
+ export { tenantMiddleware } from './middleware/tenant.js';
148
+ export { bodyLimitMiddleware } from './middleware/body-limit.js';
149
+ export { rateLimitMiddleware } from './middleware/rate-limit.js';
150
+ export { authMiddleware } from './middleware/auth.js';
151
+ export { rbacMiddleware } from './middleware/rbac.js';
152
+ export { query, withTransaction } from './db.js';
153
+ export { config } from './config.js';
154
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { Context, Next } from 'hono';
2
+ export interface UserSession {
3
+ email: string;
4
+ roles: string[];
5
+ session_id: string;
6
+ }
7
+ /**
8
+ * Resolves request JWT signature and binds session properties to Hono request context.
9
+ * In production: validates HMAC-SHA256 signature against JWT_SECRET.
10
+ * In development: supports mock tokens for testing.
11
+ */
12
+ export declare function authMiddleware(c: Context, next: Next): Promise<(Response & import("hono").TypedResponse<{
13
+ error: string;
14
+ }, 401, "json">) | undefined>;
15
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAGrC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI;;8BA8F1D"}
@@ -0,0 +1,93 @@
1
+ import crypto from 'crypto';
2
+ /**
3
+ * Resolves request JWT signature and binds session properties to Hono request context.
4
+ * In production: validates HMAC-SHA256 signature against JWT_SECRET.
5
+ * In development: supports mock tokens for testing.
6
+ */
7
+ export async function authMiddleware(c, next) {
8
+ const authHeader = c.req.header('Authorization');
9
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
10
+ // If no auth token is provided, assign Guest role session context
11
+ c.set('user', {
12
+ email: 'guest@system.local',
13
+ roles: ['Guest'],
14
+ session_id: crypto.randomUUID()
15
+ });
16
+ await next();
17
+ return;
18
+ }
19
+ const token = authHeader.split(' ')[1];
20
+ if (!token || token.trim() === '') {
21
+ return c.json({ error: 'Unauthorized: Empty bearer token' }, 401);
22
+ }
23
+ // Enforce maximum token length to prevent abuse
24
+ if (token.length > 4096) {
25
+ return c.json({ error: 'Unauthorized: Token exceeds maximum allowed length' }, 401);
26
+ }
27
+ try {
28
+ const parts = token.split('.');
29
+ if (parts.length === 3) {
30
+ const jwtSecret = process.env.JWT_SECRET;
31
+ if (jwtSecret) {
32
+ // Production: Verify HMAC-SHA256 signature
33
+ const [headerB64, payloadB64, signatureB64] = parts;
34
+ const signatureInput = `${headerB64}.${payloadB64}`;
35
+ const expectedSignature = crypto
36
+ .createHmac('sha256', jwtSecret)
37
+ .update(signatureInput)
38
+ .digest('base64url');
39
+ if (signatureB64 !== expectedSignature) {
40
+ return c.json({ error: 'Unauthorized: Invalid token signature' }, 401);
41
+ }
42
+ // Decode and validate payload
43
+ const payloadJson = Buffer.from(payloadB64.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8');
44
+ const payload = JSON.parse(payloadJson);
45
+ // Check token expiry
46
+ if (payload.exp && Date.now() / 1000 > payload.exp) {
47
+ return c.json({ error: 'Unauthorized: Token has expired' }, 401);
48
+ }
49
+ // Check issued-at is not in the future (clock skew tolerance: 60s)
50
+ if (payload.iat && payload.iat > Date.now() / 1000 + 60) {
51
+ return c.json({ error: 'Unauthorized: Token issued in the future' }, 401);
52
+ }
53
+ c.set('user', {
54
+ email: payload.email || 'unknown@user.local',
55
+ roles: Array.isArray(payload.roles) ? payload.roles : ['Guest'],
56
+ session_id: crypto.randomUUID()
57
+ });
58
+ }
59
+ else {
60
+ // Development fallback: decode without verification (JWT_SECRET not set)
61
+ console.warn('[AUTH] JWT_SECRET not configured. Running in development mode - tokens are NOT verified.');
62
+ const payloadB64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
63
+ const payloadJson = Buffer.from(payloadB64, 'base64').toString('utf-8');
64
+ const payload = JSON.parse(payloadJson);
65
+ c.set('user', {
66
+ email: payload.email || 'unknown@user.local',
67
+ roles: Array.isArray(payload.roles) ? payload.roles : ['Guest'],
68
+ session_id: crypto.randomUUID()
69
+ });
70
+ }
71
+ }
72
+ else {
73
+ // Mock/testing token support (non-JWT format)
74
+ if (process.env.NODE_ENV === 'production') {
75
+ return c.json({ error: 'Unauthorized: Invalid token format' }, 401);
76
+ }
77
+ if (token === 'admin-token') {
78
+ c.set('user', { email: 'admin@system.local', roles: ['System Manager'], session_id: crypto.randomUUID() });
79
+ }
80
+ else if (token === 'user-token') {
81
+ c.set('user', { email: 'user@system.local', roles: ['Employee'], session_id: crypto.randomUUID() });
82
+ }
83
+ else {
84
+ return c.json({ error: 'Unauthorized: Invalid authentication signature' }, 401);
85
+ }
86
+ }
87
+ await next();
88
+ }
89
+ catch (err) {
90
+ return c.json({ error: 'Unauthorized: Could not resolve session token' }, 401);
91
+ }
92
+ }
93
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { Context, Next } from 'hono';
2
+ /**
3
+ * Enforces max request body size to prevent memory exhaustion attacks.
4
+ */
5
+ export declare function bodyLimitMiddleware(c: Context, next: Next): Promise<(Response & import("hono").TypedResponse<{
6
+ error: string;
7
+ max_bytes: number;
8
+ }, 413, "json">) | undefined>;
9
+ //# sourceMappingURL=body-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/body-limit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAGrC;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI;;;8BAS/D"}
@@ -0,0 +1,15 @@
1
+ import { config } from '../config.js';
2
+ /**
3
+ * Enforces max request body size to prevent memory exhaustion attacks.
4
+ */
5
+ export async function bodyLimitMiddleware(c, next) {
6
+ const contentLength = c.req.header('content-length');
7
+ if (contentLength && parseInt(contentLength) > config.bodyLimitBytes) {
8
+ return c.json({
9
+ error: 'Payload Too Large',
10
+ max_bytes: config.bodyLimitBytes
11
+ }, 413);
12
+ }
13
+ await next();
14
+ }
15
+ //# sourceMappingURL=body-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-limit.js","sourceRoot":"","sources":["../../src/middleware/body-limit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,CAAU,EAAE,IAAU;IAC9D,MAAM,aAAa,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;IACrD,IAAI,aAAa,IAAI,QAAQ,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;QACrE,OAAO,CAAC,CAAC,IAAI,CAAC;YACZ,KAAK,EAAE,mBAAmB;YAC1B,SAAS,EAAE,MAAM,CAAC,cAAc;SACjC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC;IACD,MAAM,IAAI,EAAE,CAAC;AACf,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { Context, Next } from 'hono';
2
+ export declare function rateLimitMiddleware(c: Context, next: Next): Promise<(Response & import("hono").TypedResponse<{
3
+ error: string;
4
+ retry_after_ms: number;
5
+ }, 429, "json">) | undefined>;
6
+ //# sourceMappingURL=rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAuBrC,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI;;;8BAuB/D"}