@kuckit/infrastructure 1.0.2 → 1.0.3

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 (131) hide show
  1. package/dist/apply-decorators-CW23qWy7.d.ts +23 -0
  2. package/dist/apply-decorators-CaHIAL5X.js +29 -0
  3. package/dist/apply-decorators-CaHIAL5X.js.map +1 -0
  4. package/dist/cache/in-memory-cache-store.d.ts +2 -0
  5. package/dist/cache/in-memory-cache-store.js +3 -0
  6. package/dist/cache/index.d.ts +3 -0
  7. package/dist/cache/index.js +4 -0
  8. package/dist/cache-BjdZ-Ye4.js +1 -0
  9. package/dist/core.module-B1TdC0yX.d.ts +17 -0
  10. package/dist/core.module-DMtIkTcz.js +48 -0
  11. package/dist/core.module-DMtIkTcz.js.map +1 -0
  12. package/dist/db/drizzle/db.d.ts +2 -0
  13. package/dist/db/drizzle/db.js +3 -0
  14. package/dist/db/drizzle/repositories/index.d.ts +3 -0
  15. package/dist/db/drizzle/repositories/index.js +4 -0
  16. package/dist/db/drizzle/repositories/user.drizzle.d.ts +2 -0
  17. package/dist/db/drizzle/repositories/user.drizzle.js +3 -0
  18. package/dist/db/transaction.d.ts +2 -0
  19. package/dist/db/transaction.js +4 -0
  20. package/dist/db-C4IcCT04.js +25 -0
  21. package/dist/db-C4IcCT04.js.map +1 -0
  22. package/dist/db-tAPHBDyL.d.ts +17 -0
  23. package/dist/decorators/apply-decorators.d.ts +2 -0
  24. package/dist/decorators/apply-decorators.js +5 -0
  25. package/dist/decorators/index.d.ts +8 -0
  26. package/dist/decorators/index.js +9 -0
  27. package/dist/decorators/use-case-decorator.d.ts +3 -0
  28. package/dist/decorators/use-case-decorator.js +4 -0
  29. package/dist/decorators/with-caching.d.ts +2 -0
  30. package/dist/decorators/with-caching.js +3 -0
  31. package/dist/decorators/with-rate-limit.d.ts +2 -0
  32. package/dist/decorators/with-rate-limit.js +3 -0
  33. package/dist/decorators/with-retry.d.ts +2 -0
  34. package/dist/decorators/with-retry.js +3 -0
  35. package/dist/decorators-CqyPE9AQ.js +1 -0
  36. package/dist/error-handler-BDid7SIZ.d.ts +47 -0
  37. package/dist/error-handler-D4s_TTI1.js +80 -0
  38. package/dist/error-handler-D4s_TTI1.js.map +1 -0
  39. package/dist/errors/error-handler.d.ts +3 -0
  40. package/dist/errors/error-handler.js +4 -0
  41. package/dist/errors/index.d.ts +4 -0
  42. package/dist/errors/index.js +5 -0
  43. package/dist/errors-BB_jeye8.js +43 -0
  44. package/dist/errors-BB_jeye8.js.map +1 -0
  45. package/dist/errors-DfkerzdO.js +1 -0
  46. package/dist/event-publisher-adapter-B02oKEmP.js +46 -0
  47. package/dist/event-publisher-adapter-B02oKEmP.js.map +1 -0
  48. package/dist/event-publisher-adapter-CpxK0OJ3.d.ts +12 -0
  49. package/dist/events/event-publisher-adapter.d.ts +2 -0
  50. package/dist/events/event-publisher-adapter.js +3 -0
  51. package/dist/events/in-memory-event-bus.d.ts +2 -0
  52. package/dist/events/in-memory-event-bus.js +3 -0
  53. package/dist/events/in-memory-event-publisher.d.ts +2 -0
  54. package/dist/events/in-memory-event-publisher.js +3 -0
  55. package/dist/events/index.d.ts +5 -0
  56. package/dist/events/index.js +6 -0
  57. package/dist/events-Dqynhuj2.js +1 -0
  58. package/dist/in-memory-cache-store-BaRxM--K.d.ts +31 -0
  59. package/dist/in-memory-cache-store-oClww-8m.js +72 -0
  60. package/dist/in-memory-cache-store-oClww-8m.js.map +1 -0
  61. package/dist/in-memory-event-bus-BCyPrNAE.js +60 -0
  62. package/dist/in-memory-event-bus-BCyPrNAE.js.map +1 -0
  63. package/dist/in-memory-event-bus-CqIBLRze.d.ts +21 -0
  64. package/dist/in-memory-event-publisher-BdOlxfkx.js +28 -0
  65. package/dist/in-memory-event-publisher-BdOlxfkx.js.map +1 -0
  66. package/dist/in-memory-event-publisher-CxOQ-hnq.d.ts +12 -0
  67. package/dist/in-memory-rate-limiter-BDSHZXxf.js +72 -0
  68. package/dist/in-memory-rate-limiter-BDSHZXxf.js.map +1 -0
  69. package/dist/in-memory-rate-limiter-DJsxdZZR.d.ts +34 -0
  70. package/dist/index-B5F3AfVc.d.ts +1 -0
  71. package/dist/index-B7z6dpFd.d.ts +1 -0
  72. package/dist/index-BH67NKRs.d.ts +2 -0
  73. package/dist/index-C0yeuOwC.d.ts +1 -0
  74. package/dist/index-C6nYd7xV.d.ts +2 -0
  75. package/dist/index-DVGDAddE.d.ts +1 -0
  76. package/dist/index-DXJbbtWQ.d.ts +1 -0
  77. package/dist/index-LKrIp3Oo.d.ts +1 -0
  78. package/dist/index.d.ts +29 -506
  79. package/dist/index.js +27 -969
  80. package/dist/logger-Bl10drB8.d.ts +23 -0
  81. package/dist/logging/index.d.ts +5 -0
  82. package/dist/logging/index.js +5 -0
  83. package/dist/logging/request-logger.d.ts +2 -0
  84. package/dist/logging/request-logger.js +3 -0
  85. package/dist/logging/structured-logger.d.ts +3 -0
  86. package/dist/logging/structured-logger.js +3 -0
  87. package/dist/logging-4mLSrMc6.js +1 -0
  88. package/dist/modules/core.module.d.ts +10 -0
  89. package/dist/modules/core.module.js +13 -0
  90. package/dist/modules/index.d.ts +12 -0
  91. package/dist/modules/index.js +16 -0
  92. package/dist/modules/types.d.ts +9 -0
  93. package/dist/modules/types.js +6 -0
  94. package/dist/modules/user.module.d.ts +10 -0
  95. package/dist/modules/user.module.js +4 -0
  96. package/dist/modules-C_2SF3he.js +1 -0
  97. package/dist/rate-limiter/in-memory-rate-limiter.d.ts +2 -0
  98. package/dist/rate-limiter/in-memory-rate-limiter.js +3 -0
  99. package/dist/rate-limiter/index.d.ts +3 -0
  100. package/dist/rate-limiter/index.js +4 -0
  101. package/dist/rate-limiter-BnvPGJOK.js +1 -0
  102. package/dist/repositories-nTfSJyvW.js +1 -0
  103. package/dist/request-logger-CK3SOnoz.d.ts +23 -0
  104. package/dist/request-logger-Cw1XQWTV.js +49 -0
  105. package/dist/request-logger-Cw1XQWTV.js.map +1 -0
  106. package/dist/structured-logger-BsxDI9zX.js +119 -0
  107. package/dist/structured-logger-BsxDI9zX.js.map +1 -0
  108. package/dist/structured-logger-Dz06Uz-u.d.ts +47 -0
  109. package/dist/transaction-akuz5Fch.d.ts +22 -0
  110. package/dist/transaction-r4Sy3eC-.js +35 -0
  111. package/dist/transaction-r4Sy3eC-.js.map +1 -0
  112. package/dist/types-65aFqB5L.d.ts +62 -0
  113. package/dist/use-case-decorator-DzPSPSv5.d.ts +52 -0
  114. package/dist/use-case-decorator-GmDeYViz.js +118 -0
  115. package/dist/use-case-decorator-GmDeYViz.js.map +1 -0
  116. package/dist/user.drizzle-9kkstnkV.d.ts +12 -0
  117. package/dist/user.drizzle-CgKIqqb3.js +57 -0
  118. package/dist/user.drizzle-CgKIqqb3.js.map +1 -0
  119. package/dist/user.module-BEpCbKsU.js +17 -0
  120. package/dist/user.module-BEpCbKsU.js.map +1 -0
  121. package/dist/user.module-D3lVJ98T.d.ts +15 -0
  122. package/dist/with-caching-BniS1aZd.d.ts +39 -0
  123. package/dist/with-caching-NmBxu7vJ.js +37 -0
  124. package/dist/with-caching-NmBxu7vJ.js.map +1 -0
  125. package/dist/with-rate-limit-Cp2V1RHn.js +48 -0
  126. package/dist/with-rate-limit-Cp2V1RHn.js.map +1 -0
  127. package/dist/with-rate-limit-DK4ZF-Qg.d.ts +45 -0
  128. package/dist/with-retry-B9-hUj7I.d.ts +40 -0
  129. package/dist/with-retry-coyYPiX1.js +49 -0
  130. package/dist/with-retry-coyYPiX1.js.map +1 -0
  131. package/package.json +4 -4
@@ -0,0 +1,118 @@
1
+ import { t as AppError } from "./errors-BB_jeye8.js";
2
+
3
+ //#region src/decorators/use-case-decorator.ts
4
+ /**
5
+ * Base decorator that adds performance monitoring
6
+ */
7
+ const withPerformanceMonitoring = (useCase, context, featureName) => {
8
+ return (async (...args) => {
9
+ const startTime = Date.now();
10
+ try {
11
+ const result = await useCase(...args);
12
+ const durationMs = Date.now() - startTime;
13
+ context.logger.debug(`${featureName}_completed`, {
14
+ requestId: context.requestId,
15
+ feature: featureName,
16
+ durationMs
17
+ });
18
+ return result;
19
+ } catch (error) {
20
+ const durationMs = Date.now() - startTime;
21
+ if (error instanceof AppError) context.logger.debug(`${featureName}_error`, {
22
+ requestId: context.requestId,
23
+ feature: featureName,
24
+ durationMs,
25
+ code: error.code,
26
+ severity: error.severity
27
+ });
28
+ throw error;
29
+ }
30
+ });
31
+ };
32
+ /**
33
+ * Base decorator that adds error handling and conversion
34
+ */
35
+ const withErrorHandling = (useCase, context, featureName) => {
36
+ return (async (...args) => {
37
+ try {
38
+ return await useCase(...args);
39
+ } catch (error) {
40
+ if (error instanceof AppError) throw error;
41
+ if (error instanceof Error) {
42
+ context.logger.error(`${featureName}_unexpected_error`, {
43
+ requestId: context.requestId,
44
+ feature: featureName,
45
+ errorName: error.name,
46
+ errorMessage: error.message,
47
+ stack: error.stack
48
+ });
49
+ throw new AppError("INTERNAL_SERVER_ERROR", `Unexpected error in ${featureName}`, {
50
+ statusCode: 500,
51
+ meta: {
52
+ originalError: error.message,
53
+ feature: featureName
54
+ }
55
+ });
56
+ }
57
+ context.logger.error(`${featureName}_unknown_error`, {
58
+ requestId: context.requestId,
59
+ feature: featureName
60
+ });
61
+ throw new AppError("INTERNAL_SERVER_ERROR", `Unknown error in ${featureName}`, {
62
+ statusCode: 500,
63
+ meta: { feature: featureName }
64
+ });
65
+ }
66
+ });
67
+ };
68
+ /**
69
+ * Request tracing decorator - adds context to logs
70
+ */
71
+ const withRequestTracing = (useCase, context, featureName) => {
72
+ return (async (...args) => {
73
+ context.logger.info(`${featureName}_started`, {
74
+ requestId: context.requestId,
75
+ userId: context.userId,
76
+ feature: featureName
77
+ });
78
+ try {
79
+ const result = await useCase(...args);
80
+ context.logger.info(`${featureName}_success`, {
81
+ requestId: context.requestId,
82
+ userId: context.userId,
83
+ feature: featureName
84
+ });
85
+ return result;
86
+ } catch (error) {
87
+ context.logger.error(`${featureName}_failed`, {
88
+ requestId: context.requestId,
89
+ userId: context.userId,
90
+ feature: featureName,
91
+ error: error instanceof Error ? error.message : "Unknown error"
92
+ });
93
+ throw error;
94
+ }
95
+ });
96
+ };
97
+ /**
98
+ * Compose multiple decorators together
99
+ * Order: Tracing → Performance → Error Handling
100
+ * (outermost → innermost)
101
+ */
102
+ const decorateUseCase = (useCase, context, featureName) => {
103
+ let decorated = withErrorHandling(useCase, context, featureName);
104
+ decorated = withPerformanceMonitoring(decorated, context, featureName);
105
+ decorated = withRequestTracing(decorated, context, featureName);
106
+ return decorated;
107
+ };
108
+ /**
109
+ * Factory for creating decorated use cases
110
+ * Used in dependency injection to wrap use cases automatically
111
+ */
112
+ const makeDecoratedUseCase = (useCase, context, featureName) => {
113
+ return decorateUseCase(useCase, context, featureName);
114
+ };
115
+
116
+ //#endregion
117
+ export { withRequestTracing as a, withPerformanceMonitoring as i, makeDecoratedUseCase as n, withErrorHandling as r, decorateUseCase as t };
118
+ //# sourceMappingURL=use-case-decorator-GmDeYViz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-case-decorator-GmDeYViz.js","names":[],"sources":["../src/decorators/use-case-decorator.ts"],"sourcesContent":["import type { Logger } from '../../../domain/src/ports/logger'\nimport { AppError } from '../../../domain/src/errors'\n\n/**\n * Use case decorator type\n * Wraps a use case function with cross-cutting concerns\n */\nexport type UseCase<T extends (...args: any[]) => Promise<any>> = T\n\n/**\n * Decorator context passed to all decorators\n */\nexport interface DecoratorContext {\n\tlogger: Logger\n\trequestId?: string\n\tuserId?: string\n\tfeature?: string\n}\n\n/**\n * Performance metrics collected by decorator\n */\nexport interface PerformanceMetrics {\n\tstartTime: number\n\tendTime: number\n\tdurationMs: number\n}\n\n/**\n * Base decorator that adds performance monitoring\n */\nexport const withPerformanceMonitoring = <T extends (...args: any[]) => Promise<any>>(\n\tuseCase: T,\n\tcontext: DecoratorContext,\n\tfeatureName: string\n): T => {\n\treturn (async (...args: Parameters<T>) => {\n\t\tconst startTime = Date.now()\n\n\t\ttry {\n\t\t\tconst result = await useCase(...args)\n\t\t\tconst durationMs = Date.now() - startTime\n\n\t\t\tcontext.logger.debug(`${featureName}_completed`, {\n\t\t\t\trequestId: context.requestId,\n\t\t\t\tfeature: featureName,\n\t\t\t\tdurationMs,\n\t\t\t})\n\n\t\t\treturn result\n\t\t} catch (error) {\n\t\t\tconst durationMs = Date.now() - startTime\n\n\t\t\t// Log even errors with timing\n\t\t\tif (error instanceof AppError) {\n\t\t\t\tcontext.logger.debug(`${featureName}_error`, {\n\t\t\t\t\trequestId: context.requestId,\n\t\t\t\t\tfeature: featureName,\n\t\t\t\t\tdurationMs,\n\t\t\t\t\tcode: error.code,\n\t\t\t\t\tseverity: error.severity,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tthrow error\n\t\t}\n\t}) as T\n}\n\n/**\n * Base decorator that adds error handling and conversion\n */\nexport const withErrorHandling = <T extends (...args: any[]) => Promise<any>>(\n\tuseCase: T,\n\tcontext: DecoratorContext,\n\tfeatureName: string\n): T => {\n\treturn (async (...args: Parameters<T>) => {\n\t\ttry {\n\t\t\treturn await useCase(...args)\n\t\t} catch (error) {\n\t\t\t// AppErrors pass through (already have proper structure)\n\t\t\tif (error instanceof AppError) {\n\t\t\t\tthrow error\n\t\t\t}\n\n\t\t\t// Wrap unexpected errors\n\t\t\tif (error instanceof Error) {\n\t\t\t\tcontext.logger.error(`${featureName}_unexpected_error`, {\n\t\t\t\t\trequestId: context.requestId,\n\t\t\t\t\tfeature: featureName,\n\t\t\t\t\terrorName: error.name,\n\t\t\t\t\terrorMessage: error.message,\n\t\t\t\t\tstack: error.stack,\n\t\t\t\t})\n\n\t\t\t\tthrow new AppError('INTERNAL_SERVER_ERROR' as any, `Unexpected error in ${featureName}`, {\n\t\t\t\t\tstatusCode: 500,\n\t\t\t\t\tmeta: {\n\t\t\t\t\t\toriginalError: error.message,\n\t\t\t\t\t\tfeature: featureName,\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// Unknown errors\n\t\t\tcontext.logger.error(`${featureName}_unknown_error`, {\n\t\t\t\trequestId: context.requestId,\n\t\t\t\tfeature: featureName,\n\t\t\t})\n\n\t\t\tthrow new AppError('INTERNAL_SERVER_ERROR' as any, `Unknown error in ${featureName}`, {\n\t\t\t\tstatusCode: 500,\n\t\t\t\tmeta: { feature: featureName },\n\t\t\t})\n\t\t}\n\t}) as T\n}\n\n/**\n * Request tracing decorator - adds context to logs\n */\nexport const withRequestTracing = <T extends (...args: any[]) => Promise<any>>(\n\tuseCase: T,\n\tcontext: DecoratorContext,\n\tfeatureName: string\n): T => {\n\treturn (async (...args: Parameters<T>) => {\n\t\tcontext.logger.info(`${featureName}_started`, {\n\t\t\trequestId: context.requestId,\n\t\t\tuserId: context.userId,\n\t\t\tfeature: featureName,\n\t\t})\n\n\t\ttry {\n\t\t\tconst result = await useCase(...args)\n\n\t\t\tcontext.logger.info(`${featureName}_success`, {\n\t\t\t\trequestId: context.requestId,\n\t\t\t\tuserId: context.userId,\n\t\t\t\tfeature: featureName,\n\t\t\t})\n\n\t\t\treturn result\n\t\t} catch (error) {\n\t\t\tcontext.logger.error(`${featureName}_failed`, {\n\t\t\t\trequestId: context.requestId,\n\t\t\t\tuserId: context.userId,\n\t\t\t\tfeature: featureName,\n\t\t\t\terror: error instanceof Error ? error.message : 'Unknown error',\n\t\t\t})\n\n\t\t\tthrow error\n\t\t}\n\t}) as T\n}\n\n/**\n * Compose multiple decorators together\n * Order: Tracing → Performance → Error Handling\n * (outermost → innermost)\n */\nexport const decorateUseCase = <T extends (...args: any[]) => Promise<any>>(\n\tuseCase: T,\n\tcontext: DecoratorContext,\n\tfeatureName: string\n): T => {\n\t// Apply decorators from outermost to innermost\n\t// Error handling (innermost - catches first)\n\tlet decorated = withErrorHandling(useCase, context, featureName)\n\n\t// Performance monitoring (middle - wraps error handling)\n\tdecorated = withPerformanceMonitoring(decorated, context, featureName)\n\n\t// Request tracing (outermost - visible in logs)\n\tdecorated = withRequestTracing(decorated, context, featureName)\n\n\treturn decorated\n}\n\n/**\n * Factory for creating decorated use cases\n * Used in dependency injection to wrap use cases automatically\n */\nexport const makeDecoratedUseCase = <T extends (...args: any[]) => Promise<any>>(\n\tuseCase: T,\n\tcontext: DecoratorContext,\n\tfeatureName: string\n): T => {\n\treturn decorateUseCase(useCase, context, featureName)\n}\n"],"mappings":";;;;;;AA+BA,MAAa,6BACZ,SACA,SACA,gBACO;AACP,SAAQ,OAAO,GAAG,SAAwB;EACzC,MAAM,YAAY,KAAK,KAAK;AAE5B,MAAI;GACH,MAAM,SAAS,MAAM,QAAQ,GAAG,KAAK;GACrC,MAAM,aAAa,KAAK,KAAK,GAAG;AAEhC,WAAQ,OAAO,MAAM,GAAG,YAAY,aAAa;IAChD,WAAW,QAAQ;IACnB,SAAS;IACT;IACA,CAAC;AAEF,UAAO;WACC,OAAO;GACf,MAAM,aAAa,KAAK,KAAK,GAAG;AAGhC,OAAI,iBAAiB,SACpB,SAAQ,OAAO,MAAM,GAAG,YAAY,SAAS;IAC5C,WAAW,QAAQ;IACnB,SAAS;IACT;IACA,MAAM,MAAM;IACZ,UAAU,MAAM;IAChB,CAAC;AAGH,SAAM;;;;;;;AAQT,MAAa,qBACZ,SACA,SACA,gBACO;AACP,SAAQ,OAAO,GAAG,SAAwB;AACzC,MAAI;AACH,UAAO,MAAM,QAAQ,GAAG,KAAK;WACrB,OAAO;AAEf,OAAI,iBAAiB,SACpB,OAAM;AAIP,OAAI,iBAAiB,OAAO;AAC3B,YAAQ,OAAO,MAAM,GAAG,YAAY,oBAAoB;KACvD,WAAW,QAAQ;KACnB,SAAS;KACT,WAAW,MAAM;KACjB,cAAc,MAAM;KACpB,OAAO,MAAM;KACb,CAAC;AAEF,UAAM,IAAI,SAAS,yBAAgC,uBAAuB,eAAe;KACxF,YAAY;KACZ,MAAM;MACL,eAAe,MAAM;MACrB,SAAS;MACT;KACD,CAAC;;AAIH,WAAQ,OAAO,MAAM,GAAG,YAAY,iBAAiB;IACpD,WAAW,QAAQ;IACnB,SAAS;IACT,CAAC;AAEF,SAAM,IAAI,SAAS,yBAAgC,oBAAoB,eAAe;IACrF,YAAY;IACZ,MAAM,EAAE,SAAS,aAAa;IAC9B,CAAC;;;;;;;AAQL,MAAa,sBACZ,SACA,SACA,gBACO;AACP,SAAQ,OAAO,GAAG,SAAwB;AACzC,UAAQ,OAAO,KAAK,GAAG,YAAY,WAAW;GAC7C,WAAW,QAAQ;GACnB,QAAQ,QAAQ;GAChB,SAAS;GACT,CAAC;AAEF,MAAI;GACH,MAAM,SAAS,MAAM,QAAQ,GAAG,KAAK;AAErC,WAAQ,OAAO,KAAK,GAAG,YAAY,WAAW;IAC7C,WAAW,QAAQ;IACnB,QAAQ,QAAQ;IAChB,SAAS;IACT,CAAC;AAEF,UAAO;WACC,OAAO;AACf,WAAQ,OAAO,MAAM,GAAG,YAAY,UAAU;IAC7C,WAAW,QAAQ;IACnB,QAAQ,QAAQ;IAChB,SAAS;IACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU;IAChD,CAAC;AAEF,SAAM;;;;;;;;;AAUT,MAAa,mBACZ,SACA,SACA,gBACO;CAGP,IAAI,YAAY,kBAAkB,SAAS,SAAS,YAAY;AAGhE,aAAY,0BAA0B,WAAW,SAAS,YAAY;AAGtE,aAAY,mBAAmB,WAAW,SAAS,YAAY;AAE/D,QAAO;;;;;;AAOR,MAAa,wBACZ,SACA,SACA,gBACO;AACP,QAAO,gBAAgB,SAAS,SAAS,YAAY"}
@@ -0,0 +1,12 @@
1
+ import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
+ import { UserRepository } from "@kuckit/domain/ports/user-repository";
3
+
4
+ //#region src/db/drizzle/repositories/user.drizzle.d.ts
5
+
6
+ /**
7
+ * Drizzle implementation of UserRepository
8
+ */
9
+ declare const makeDrizzleUserRepository: (db: NodePgDatabase) => UserRepository;
10
+ //#endregion
11
+ export { makeDrizzleUserRepository as t };
12
+ //# sourceMappingURL=user.drizzle-9kkstnkV.d.ts.map
@@ -0,0 +1,57 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { user } from "@kuckit/db/schema/auth";
3
+
4
+ //#region src/db/drizzle/repositories/user.drizzle.ts
5
+ /**
6
+ * Map Drizzle row to domain entity
7
+ */
8
+ const toDomainUser = (row) => ({
9
+ id: row.id,
10
+ name: row.name,
11
+ email: row.email,
12
+ emailVerified: row.emailVerified,
13
+ permissions: row.permissions,
14
+ createdAt: row.createdAt,
15
+ updatedAt: row.updatedAt
16
+ });
17
+ /**
18
+ * Map domain entity to Drizzle insert type
19
+ */
20
+ const toDbUser = (user$1) => ({
21
+ id: user$1.id,
22
+ name: user$1.name,
23
+ email: user$1.email,
24
+ emailVerified: user$1.emailVerified,
25
+ permissions: [...user$1.permissions],
26
+ createdAt: user$1.createdAt,
27
+ updatedAt: user$1.updatedAt
28
+ });
29
+ /**
30
+ * Drizzle implementation of UserRepository
31
+ */
32
+ const makeDrizzleUserRepository = (db) => ({
33
+ async findById(id) {
34
+ const rows = await db.select().from(user).where(eq(user.id, id)).limit(1);
35
+ return rows[0] ? toDomainUser(rows[0]) : null;
36
+ },
37
+ async findByEmail(email) {
38
+ const rows = await db.select().from(user).where(eq(user.email, email)).limit(1);
39
+ return rows[0] ? toDomainUser(rows[0]) : null;
40
+ },
41
+ async save(user$1) {
42
+ await db.insert(user).values(toDbUser(user$1)).onConflictDoUpdate({
43
+ target: user.id,
44
+ set: {
45
+ name: user$1.name,
46
+ email: user$1.email,
47
+ emailVerified: user$1.emailVerified,
48
+ permissions: [...user$1.permissions],
49
+ updatedAt: user$1.updatedAt
50
+ }
51
+ });
52
+ }
53
+ });
54
+
55
+ //#endregion
56
+ export { makeDrizzleUserRepository as t };
57
+ //# sourceMappingURL=user.drizzle-CgKIqqb3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.drizzle-CgKIqqb3.js","names":["user","userTable"],"sources":["../src/db/drizzle/repositories/user.drizzle.ts"],"sourcesContent":["import type { NodePgDatabase } from 'drizzle-orm/node-postgres'\nimport { eq } from 'drizzle-orm'\nimport { user as userTable } from '@kuckit/db/schema/auth'\nimport type { UserRepository } from '@kuckit/domain/ports/user-repository'\nimport type { User } from '@kuckit/domain/entities/user'\n\n/**\n * Map Drizzle row to domain entity\n */\nconst toDomainUser = (row: typeof userTable.$inferSelect): User => ({\n\tid: row.id,\n\tname: row.name,\n\temail: row.email,\n\temailVerified: row.emailVerified,\n\tpermissions: row.permissions,\n\tcreatedAt: row.createdAt,\n\tupdatedAt: row.updatedAt,\n})\n\n/**\n * Map domain entity to Drizzle insert type\n */\nconst toDbUser = (user: User) => ({\n\tid: user.id,\n\tname: user.name,\n\temail: user.email,\n\temailVerified: user.emailVerified,\n\tpermissions: [...user.permissions],\n\tcreatedAt: user.createdAt,\n\tupdatedAt: user.updatedAt,\n})\n\n/**\n * Drizzle implementation of UserRepository\n */\nexport const makeDrizzleUserRepository = (db: NodePgDatabase): UserRepository => ({\n\tasync findById(id: string): Promise<User | null> {\n\t\tconst rows = await db.select().from(userTable).where(eq(userTable.id, id)).limit(1)\n\n\t\treturn rows[0] ? toDomainUser(rows[0]) : null\n\t},\n\n\tasync findByEmail(email: string): Promise<User | null> {\n\t\tconst rows = await db.select().from(userTable).where(eq(userTable.email, email)).limit(1)\n\n\t\treturn rows[0] ? toDomainUser(rows[0]) : null\n\t},\n\n\tasync save(user: User): Promise<void> {\n\t\tawait db\n\t\t\t.insert(userTable)\n\t\t\t.values(toDbUser(user))\n\t\t\t.onConflictDoUpdate({\n\t\t\t\ttarget: userTable.id,\n\t\t\t\tset: {\n\t\t\t\t\tname: user.name,\n\t\t\t\t\temail: user.email,\n\t\t\t\t\temailVerified: user.emailVerified,\n\t\t\t\t\tpermissions: [...user.permissions],\n\t\t\t\t\tupdatedAt: user.updatedAt,\n\t\t\t\t},\n\t\t\t})\n\t},\n})\n"],"mappings":";;;;;;;AASA,MAAM,gBAAgB,SAA8C;CACnE,IAAI,IAAI;CACR,MAAM,IAAI;CACV,OAAO,IAAI;CACX,eAAe,IAAI;CACnB,aAAa,IAAI;CACjB,WAAW,IAAI;CACf,WAAW,IAAI;CACf;;;;AAKD,MAAM,YAAY,YAAgB;CACjC,IAAIA,OAAK;CACT,MAAMA,OAAK;CACX,OAAOA,OAAK;CACZ,eAAeA,OAAK;CACpB,aAAa,CAAC,GAAGA,OAAK,YAAY;CAClC,WAAWA,OAAK;CAChB,WAAWA,OAAK;CAChB;;;;AAKD,MAAa,6BAA6B,QAAwC;CACjF,MAAM,SAAS,IAAkC;EAChD,MAAM,OAAO,MAAM,GAAG,QAAQ,CAAC,KAAKC,KAAU,CAAC,MAAM,GAAGA,KAAU,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE;AAEnF,SAAO,KAAK,KAAK,aAAa,KAAK,GAAG,GAAG;;CAG1C,MAAM,YAAY,OAAqC;EACtD,MAAM,OAAO,MAAM,GAAG,QAAQ,CAAC,KAAKA,KAAU,CAAC,MAAM,GAAGA,KAAU,OAAO,MAAM,CAAC,CAAC,MAAM,EAAE;AAEzF,SAAO,KAAK,KAAK,aAAa,KAAK,GAAG,GAAG;;CAG1C,MAAM,KAAK,QAA2B;AACrC,QAAM,GACJ,OAAOA,KAAU,CACjB,OAAO,SAASD,OAAK,CAAC,CACtB,mBAAmB;GACnB,QAAQC,KAAU;GAClB,KAAK;IACJ,MAAMD,OAAK;IACX,OAAOA,OAAK;IACZ,eAAeA,OAAK;IACpB,aAAa,CAAC,GAAGA,OAAK,YAAY;IAClC,WAAWA,OAAK;IAChB;GACD,CAAC;;CAEJ"}
@@ -0,0 +1,17 @@
1
+ import { t as makeDrizzleUserRepository } from "./user.drizzle-CgKIqqb3.js";
2
+ import { asFunction } from "awilix";
3
+
4
+ //#region src/modules/user.module.ts
5
+ /**
6
+ * User repository module: registers user-related repositories
7
+ *
8
+ * Note: Use case registrations are in apps/server/src/modules/user.module.ts
9
+ * to maintain Clean Architecture layering (Infrastructure should not import Application)
10
+ */
11
+ const registerUserModule = (container) => {
12
+ container.register({ userRepository: asFunction(({ db }) => makeDrizzleUserRepository(db)).scoped() });
13
+ };
14
+
15
+ //#endregion
16
+ export { registerUserModule as t };
17
+ //# sourceMappingURL=user.module-BEpCbKsU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.module-BEpCbKsU.js","names":[],"sources":["../src/modules/user.module.ts"],"sourcesContent":["import { asFunction, type AwilixContainer } from 'awilix'\nimport { makeDrizzleUserRepository } from '../db/drizzle/repositories/user.drizzle'\nimport type { Cradle } from './types'\n\n/**\n * User repository module: registers user-related repositories\n *\n * Note: Use case registrations are in apps/server/src/modules/user.module.ts\n * to maintain Clean Architecture layering (Infrastructure should not import Application)\n */\nexport const registerUserModule = (container: AwilixContainer<Cradle>): void => {\n\tcontainer.register({\n\t\tuserRepository: asFunction(({ db }) => makeDrizzleUserRepository(db)).scoped(),\n\t})\n}\n"],"mappings":";;;;;;;;;;AAUA,MAAa,sBAAsB,cAA6C;AAC/E,WAAU,SAAS,EAClB,gBAAgB,YAAY,EAAE,SAAS,0BAA0B,GAAG,CAAC,CAAC,QAAQ,EAC9E,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { n as Cradle } from "./types-65aFqB5L.js";
2
+ import { AwilixContainer } from "awilix";
3
+
4
+ //#region src/modules/user.module.d.ts
5
+
6
+ /**
7
+ * User repository module: registers user-related repositories
8
+ *
9
+ * Note: Use case registrations are in apps/server/src/modules/user.module.ts
10
+ * to maintain Clean Architecture layering (Infrastructure should not import Application)
11
+ */
12
+ declare const registerUserModule: (container: AwilixContainer<Cradle>) => void;
13
+ //#endregion
14
+ export { registerUserModule as t };
15
+ //# sourceMappingURL=user.module-D3lVJ98T.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { CacheStore } from "@kuckit/domain";
2
+
3
+ //#region src/decorators/with-caching.d.ts
4
+
5
+ /**
6
+ * Options for caching decorator
7
+ */
8
+ interface WithCachingOptions {
9
+ /** Cache key function - maps input to cache key */
10
+ keyFn: (input: any) => string;
11
+ /** Time to live in milliseconds */
12
+ ttlMs: number;
13
+ /** Stale-while-revalidate: return stale value while refreshing in background */
14
+ staleWhileRevalidateMs?: number;
15
+ }
16
+ /**
17
+ * Wraps a use case with caching
18
+ * - Only works with idempotent read operations
19
+ * - Key function determines cache key from input
20
+ * - TTL controls cache expiration
21
+ * - SWR allows returning stale value while revalidating
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const cachedGetUser = withCaching(
26
+ * getUserProfile,
27
+ * cacheStore,
28
+ * {
29
+ * keyFn: (input) => `user:${input.userId}`,
30
+ * ttlMs: 60000, // 1 minute
31
+ * staleWhileRevalidateMs: 120000, // 2 minutes
32
+ * }
33
+ * )
34
+ * ```
35
+ */
36
+ declare const withCaching: <I extends Record<string, any>, O>(fn: (input: I) => Promise<O>, cacheStore: CacheStore, options: WithCachingOptions) => ((input: I) => Promise<O>);
37
+ //#endregion
38
+ export { withCaching as n, WithCachingOptions as t };
39
+ //# sourceMappingURL=with-caching-BniS1aZd.d.ts.map
@@ -0,0 +1,37 @@
1
+ //#region src/decorators/with-caching.ts
2
+ /**
3
+ * Wraps a use case with caching
4
+ * - Only works with idempotent read operations
5
+ * - Key function determines cache key from input
6
+ * - TTL controls cache expiration
7
+ * - SWR allows returning stale value while revalidating
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const cachedGetUser = withCaching(
12
+ * getUserProfile,
13
+ * cacheStore,
14
+ * {
15
+ * keyFn: (input) => `user:${input.userId}`,
16
+ * ttlMs: 60000, // 1 minute
17
+ * staleWhileRevalidateMs: 120000, // 2 minutes
18
+ * }
19
+ * )
20
+ * ```
21
+ */
22
+ const withCaching = (fn, cacheStore, options) => {
23
+ const cached = async (input) => {
24
+ const cacheKey = options.keyFn(input);
25
+ const cached$1 = await cacheStore.get(cacheKey);
26
+ if (cached$1 !== void 0) return cached$1;
27
+ const result = await fn(input);
28
+ await cacheStore.set(cacheKey, result, options.ttlMs);
29
+ return result;
30
+ };
31
+ Object.defineProperty(cached, "name", { value: `withCaching(${fn.name || "anonymous"})` });
32
+ return cached;
33
+ };
34
+
35
+ //#endregion
36
+ export { withCaching as t };
37
+ //# sourceMappingURL=with-caching-NmBxu7vJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-caching-NmBxu7vJ.js","names":["cached"],"sources":["../src/decorators/with-caching.ts"],"sourcesContent":["import type { CacheStore } from '@kuckit/domain'\n\n/**\n * Options for caching decorator\n */\nexport interface WithCachingOptions {\n\t/** Cache key function - maps input to cache key */\n\tkeyFn: (input: any) => string\n\t/** Time to live in milliseconds */\n\tttlMs: number\n\t/** Stale-while-revalidate: return stale value while refreshing in background */\n\tstaleWhileRevalidateMs?: number\n}\n\n/**\n * Wraps a use case with caching\n * - Only works with idempotent read operations\n * - Key function determines cache key from input\n * - TTL controls cache expiration\n * - SWR allows returning stale value while revalidating\n *\n * @example\n * ```ts\n * const cachedGetUser = withCaching(\n * getUserProfile,\n * cacheStore,\n * {\n * keyFn: (input) => `user:${input.userId}`,\n * ttlMs: 60000, // 1 minute\n * staleWhileRevalidateMs: 120000, // 2 minutes\n * }\n * )\n * ```\n */\nexport const withCaching = <I extends Record<string, any>, O>(\n\tfn: (input: I) => Promise<O>,\n\tcacheStore: CacheStore,\n\toptions: WithCachingOptions\n): ((input: I) => Promise<O>) => {\n\tconst cached = async (input: I): Promise<O> => {\n\t\tconst cacheKey = options.keyFn(input)\n\n\t\t// Try to get from cache\n\t\tconst cached = await cacheStore.get<O>(cacheKey)\n\t\tif (cached !== undefined) {\n\t\t\treturn cached\n\t\t}\n\n\t\t// Not in cache, call function\n\t\tconst result = await fn(input)\n\n\t\t// Store in cache\n\t\tawait cacheStore.set(cacheKey, result, options.ttlMs)\n\n\t\treturn result\n\t}\n\n\t// Preserve function name for debugging\n\tObject.defineProperty(cached, 'name', {\n\t\tvalue: `withCaching(${fn.name || 'anonymous'})`,\n\t})\n\n\treturn cached\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAkCA,MAAa,eACZ,IACA,YACA,YACgC;CAChC,MAAM,SAAS,OAAO,UAAyB;EAC9C,MAAM,WAAW,QAAQ,MAAM,MAAM;EAGrC,MAAMA,WAAS,MAAM,WAAW,IAAO,SAAS;AAChD,MAAIA,aAAW,OACd,QAAOA;EAIR,MAAM,SAAS,MAAM,GAAG,MAAM;AAG9B,QAAM,WAAW,IAAI,UAAU,QAAQ,QAAQ,MAAM;AAErD,SAAO;;AAIR,QAAO,eAAe,QAAQ,QAAQ,EACrC,OAAO,eAAe,GAAG,QAAQ,YAAY,IAC7C,CAAC;AAEF,QAAO"}
@@ -0,0 +1,48 @@
1
+ import { AppError, ErrorCode } from "@kuckit/domain";
2
+
3
+ //#region src/decorators/with-rate-limit.ts
4
+ /**
5
+ * Rate limit error
6
+ */
7
+ var RateLimitError = class extends AppError {
8
+ constructor(resetAt) {
9
+ super(ErrorCode.RATE_LIMITED, `Rate limit exceeded. Reset at ${resetAt.toISOString()}`, {
10
+ statusCode: 429,
11
+ meta: { resetAt }
12
+ });
13
+ this.resetAt = resetAt;
14
+ }
15
+ };
16
+ /**
17
+ * Wraps a use case with rate limiting
18
+ * - Uses token bucket algorithm
19
+ * - Per-input rate limit tracking via keyFn
20
+ * - Throws RateLimitError when limit exceeded
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const limitedCreatePost = withRateLimit(
25
+ * createPost,
26
+ * rateLimiterStore,
27
+ * {
28
+ * keyFn: (input) => `user:${input.userId}`,
29
+ * capacity: 10,
30
+ * refillPerSecond: 1, // 1 request per second
31
+ * }
32
+ * )
33
+ * ```
34
+ */
35
+ const withRateLimit = (fn, rateLimiterStore, options) => {
36
+ const limited = async (input) => {
37
+ const limitKey = options.keyFn(input);
38
+ const result = await rateLimiterStore.checkLimit(limitKey, options.capacity, options.refillPerSecond);
39
+ if (!result.allowed) throw new RateLimitError(result.resetAt);
40
+ return await fn(input);
41
+ };
42
+ Object.defineProperty(limited, "name", { value: `withRateLimit(${fn.name || "anonymous"})` });
43
+ return limited;
44
+ };
45
+
46
+ //#endregion
47
+ export { withRateLimit as n, RateLimitError as t };
48
+ //# sourceMappingURL=with-rate-limit-Cp2V1RHn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-rate-limit-Cp2V1RHn.js","names":["resetAt: Date"],"sources":["../src/decorators/with-rate-limit.ts"],"sourcesContent":["import type { RateLimiterStore } from '@kuckit/domain'\nimport { AppError, ErrorCode } from '@kuckit/domain'\n\n/**\n * Options for rate limiting decorator\n */\nexport interface WithRateLimitOptions {\n\t/** Rate limit key function - maps input to limit key */\n\tkeyFn: (input: any) => string\n\t/** Bucket capacity (max requests) */\n\tcapacity: number\n\t/** Tokens refilled per second */\n\trefillPerSecond: number\n}\n\n/**\n * Rate limit error\n */\nexport class RateLimitError extends AppError {\n\tconstructor(public readonly resetAt: Date) {\n\t\tsuper(ErrorCode.RATE_LIMITED, `Rate limit exceeded. Reset at ${resetAt.toISOString()}`, {\n\t\t\tstatusCode: 429,\n\t\t\tmeta: { resetAt },\n\t\t})\n\t}\n}\n\n/**\n * Wraps a use case with rate limiting\n * - Uses token bucket algorithm\n * - Per-input rate limit tracking via keyFn\n * - Throws RateLimitError when limit exceeded\n *\n * @example\n * ```ts\n * const limitedCreatePost = withRateLimit(\n * createPost,\n * rateLimiterStore,\n * {\n * keyFn: (input) => `user:${input.userId}`,\n * capacity: 10,\n * refillPerSecond: 1, // 1 request per second\n * }\n * )\n * ```\n */\nexport const withRateLimit = <I extends Record<string, any>, O>(\n\tfn: (input: I) => Promise<O>,\n\trateLimiterStore: RateLimiterStore,\n\toptions: WithRateLimitOptions\n): ((input: I) => Promise<O>) => {\n\tconst limited = async (input: I): Promise<O> => {\n\t\tconst limitKey = options.keyFn(input)\n\n\t\tconst result = await rateLimiterStore.checkLimit(\n\t\t\tlimitKey,\n\t\t\toptions.capacity,\n\t\t\toptions.refillPerSecond\n\t\t)\n\n\t\tif (!result.allowed) {\n\t\t\tthrow new RateLimitError(result.resetAt)\n\t\t}\n\n\t\t// Rate limit allows, call function\n\t\treturn await fn(input)\n\t}\n\n\t// Preserve function name for debugging\n\tObject.defineProperty(limited, 'name', {\n\t\tvalue: `withRateLimit(${fn.name || 'anonymous'})`,\n\t})\n\n\treturn limited\n}\n"],"mappings":";;;;;;AAkBA,IAAa,iBAAb,cAAoC,SAAS;CAC5C,YAAY,AAAgBA,SAAe;AAC1C,QAAM,UAAU,cAAc,iCAAiC,QAAQ,aAAa,IAAI;GACvF,YAAY;GACZ,MAAM,EAAE,SAAS;GACjB,CAAC;EAJyB;;;;;;;;;;;;;;;;;;;;;;AA2B7B,MAAa,iBACZ,IACA,kBACA,YACgC;CAChC,MAAM,UAAU,OAAO,UAAyB;EAC/C,MAAM,WAAW,QAAQ,MAAM,MAAM;EAErC,MAAM,SAAS,MAAM,iBAAiB,WACrC,UACA,QAAQ,UACR,QAAQ,gBACR;AAED,MAAI,CAAC,OAAO,QACX,OAAM,IAAI,eAAe,OAAO,QAAQ;AAIzC,SAAO,MAAM,GAAG,MAAM;;AAIvB,QAAO,eAAe,SAAS,QAAQ,EACtC,OAAO,iBAAiB,GAAG,QAAQ,YAAY,IAC/C,CAAC;AAEF,QAAO"}
@@ -0,0 +1,45 @@
1
+ import { AppError, RateLimiterStore } from "@kuckit/domain";
2
+
3
+ //#region src/decorators/with-rate-limit.d.ts
4
+
5
+ /**
6
+ * Options for rate limiting decorator
7
+ */
8
+ interface WithRateLimitOptions {
9
+ /** Rate limit key function - maps input to limit key */
10
+ keyFn: (input: any) => string;
11
+ /** Bucket capacity (max requests) */
12
+ capacity: number;
13
+ /** Tokens refilled per second */
14
+ refillPerSecond: number;
15
+ }
16
+ /**
17
+ * Rate limit error
18
+ */
19
+ declare class RateLimitError extends AppError {
20
+ readonly resetAt: Date;
21
+ constructor(resetAt: Date);
22
+ }
23
+ /**
24
+ * Wraps a use case with rate limiting
25
+ * - Uses token bucket algorithm
26
+ * - Per-input rate limit tracking via keyFn
27
+ * - Throws RateLimitError when limit exceeded
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const limitedCreatePost = withRateLimit(
32
+ * createPost,
33
+ * rateLimiterStore,
34
+ * {
35
+ * keyFn: (input) => `user:${input.userId}`,
36
+ * capacity: 10,
37
+ * refillPerSecond: 1, // 1 request per second
38
+ * }
39
+ * )
40
+ * ```
41
+ */
42
+ declare const withRateLimit: <I extends Record<string, any>, O>(fn: (input: I) => Promise<O>, rateLimiterStore: RateLimiterStore, options: WithRateLimitOptions) => ((input: I) => Promise<O>);
43
+ //#endregion
44
+ export { WithRateLimitOptions as n, withRateLimit as r, RateLimitError as t };
45
+ //# sourceMappingURL=with-rate-limit-DK4ZF-Qg.d.ts.map
@@ -0,0 +1,40 @@
1
+ //#region src/decorators/with-retry.d.ts
2
+ /**
3
+ * Options for retry decorator
4
+ */
5
+ interface WithRetryOptions {
6
+ /** Maximum number of retry attempts (default: 3) */
7
+ maxAttempts?: number;
8
+ /** Initial backoff in milliseconds (default: 100) */
9
+ initialBackoffMs?: number;
10
+ /** Maximum backoff in milliseconds (default: 30000) */
11
+ maxBackoffMs?: number;
12
+ /** Backoff multiplier for exponential backoff (default: 2) */
13
+ backoffMultiplier?: number;
14
+ /** Predicate to determine if error is retryable */
15
+ retryOn?: (error: Error) => boolean;
16
+ }
17
+ /**
18
+ * Wraps a use case with retry logic
19
+ * - Uses exponential backoff
20
+ * - Only retries on specific errors via retryOn predicate
21
+ * - Backoff is capped at maxBackoffMs
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * const retriedGetUser = withRetry(
26
+ * getUserProfile,
27
+ * {
28
+ * maxAttempts: 3,
29
+ * initialBackoffMs: 100,
30
+ * maxBackoffMs: 30000,
31
+ * backoffMultiplier: 2,
32
+ * retryOn: (error) => error.message.includes('TIMEOUT'),
33
+ * }
34
+ * )
35
+ * ```
36
+ */
37
+ declare const withRetry: <I extends any[], O>(fn: (...args: I) => Promise<O>, options?: WithRetryOptions) => ((...args: I) => Promise<O>);
38
+ //#endregion
39
+ export { withRetry as n, WithRetryOptions as t };
40
+ //# sourceMappingURL=with-retry-B9-hUj7I.d.ts.map
@@ -0,0 +1,49 @@
1
+ //#region src/decorators/with-retry.ts
2
+ /**
3
+ * Wraps a use case with retry logic
4
+ * - Uses exponential backoff
5
+ * - Only retries on specific errors via retryOn predicate
6
+ * - Backoff is capped at maxBackoffMs
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const retriedGetUser = withRetry(
11
+ * getUserProfile,
12
+ * {
13
+ * maxAttempts: 3,
14
+ * initialBackoffMs: 100,
15
+ * maxBackoffMs: 30000,
16
+ * backoffMultiplier: 2,
17
+ * retryOn: (error) => error.message.includes('TIMEOUT'),
18
+ * }
19
+ * )
20
+ * ```
21
+ */
22
+ const withRetry = (fn, options = {}) => {
23
+ const maxAttempts = options.maxAttempts ?? 3;
24
+ const initialBackoffMs = options.initialBackoffMs ?? 100;
25
+ const maxBackoffMs = options.maxBackoffMs ?? 3e4;
26
+ const backoffMultiplier = options.backoffMultiplier ?? 2;
27
+ const retryOn = options.retryOn ?? ((error) => error instanceof Error);
28
+ const retried = async (...args) => {
29
+ let lastError = null;
30
+ let backoffMs = initialBackoffMs;
31
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) try {
32
+ return await fn(...args);
33
+ } catch (error) {
34
+ lastError = error instanceof Error ? error : new Error(String(error));
35
+ if (!retryOn(lastError)) throw error;
36
+ if (attempt < maxAttempts) {
37
+ await new Promise((resolve) => setTimeout(resolve, backoffMs));
38
+ backoffMs = Math.min(backoffMs * backoffMultiplier, maxBackoffMs);
39
+ }
40
+ }
41
+ throw lastError ?? /* @__PURE__ */ new Error("Retry failed without error");
42
+ };
43
+ Object.defineProperty(retried, "name", { value: `withRetry(${fn.name || "anonymous"})` });
44
+ return retried;
45
+ };
46
+
47
+ //#endregion
48
+ export { withRetry as t };
49
+ //# sourceMappingURL=with-retry-coyYPiX1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-retry-coyYPiX1.js","names":["lastError: Error | null"],"sources":["../src/decorators/with-retry.ts"],"sourcesContent":["/**\n * Options for retry decorator\n */\nexport interface WithRetryOptions {\n\t/** Maximum number of retry attempts (default: 3) */\n\tmaxAttempts?: number\n\t/** Initial backoff in milliseconds (default: 100) */\n\tinitialBackoffMs?: number\n\t/** Maximum backoff in milliseconds (default: 30000) */\n\tmaxBackoffMs?: number\n\t/** Backoff multiplier for exponential backoff (default: 2) */\n\tbackoffMultiplier?: number\n\t/** Predicate to determine if error is retryable */\n\tretryOn?: (error: Error) => boolean\n}\n\n/**\n * Wraps a use case with retry logic\n * - Uses exponential backoff\n * - Only retries on specific errors via retryOn predicate\n * - Backoff is capped at maxBackoffMs\n *\n * @example\n * ```ts\n * const retriedGetUser = withRetry(\n * getUserProfile,\n * {\n * maxAttempts: 3,\n * initialBackoffMs: 100,\n * maxBackoffMs: 30000,\n * backoffMultiplier: 2,\n * retryOn: (error) => error.message.includes('TIMEOUT'),\n * }\n * )\n * ```\n */\nexport const withRetry = <I extends any[], O>(\n\tfn: (...args: I) => Promise<O>,\n\toptions: WithRetryOptions = {}\n): ((...args: I) => Promise<O>) => {\n\tconst maxAttempts = options.maxAttempts ?? 3\n\tconst initialBackoffMs = options.initialBackoffMs ?? 100\n\tconst maxBackoffMs = options.maxBackoffMs ?? 30000\n\tconst backoffMultiplier = options.backoffMultiplier ?? 2\n\tconst retryOn = options.retryOn ?? ((error: Error) => error instanceof Error)\n\n\tconst retried = async (...args: I): Promise<O> => {\n\t\tlet lastError: Error | null = null\n\t\tlet backoffMs = initialBackoffMs\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\ttry {\n\t\t\t\treturn await fn(...args)\n\t\t\t} catch (error) {\n\t\t\t\tlastError = error instanceof Error ? error : new Error(String(error))\n\n\t\t\t\t// Check if error is retryable\n\t\t\t\tif (!retryOn(lastError)) {\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\n\t\t\t\t// Don't wait after last attempt\n\t\t\t\tif (attempt < maxAttempts) {\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, backoffMs))\n\n\t\t\t\t\t// Calculate next backoff (with cap)\n\t\t\t\t\tbackoffMs = Math.min(backoffMs * backoffMultiplier, maxBackoffMs)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// All attempts exhausted\n\t\tthrow lastError ?? new Error('Retry failed without error')\n\t}\n\n\t// Preserve function name for debugging\n\tObject.defineProperty(retried, 'name', {\n\t\tvalue: `withRetry(${fn.name || 'anonymous'})`,\n\t})\n\n\treturn retried\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoCA,MAAa,aACZ,IACA,UAA4B,EAAE,KACI;CAClC,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,mBAAmB,QAAQ,oBAAoB;CACrD,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,oBAAoB,QAAQ,qBAAqB;CACvD,MAAM,UAAU,QAAQ,aAAa,UAAiB,iBAAiB;CAEvE,MAAM,UAAU,OAAO,GAAG,SAAwB;EACjD,IAAIA,YAA0B;EAC9B,IAAI,YAAY;AAEhB,OAAK,IAAI,UAAU,GAAG,WAAW,aAAa,UAC7C,KAAI;AACH,UAAO,MAAM,GAAG,GAAG,KAAK;WAChB,OAAO;AACf,eAAY,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;AAGrE,OAAI,CAAC,QAAQ,UAAU,CACtB,OAAM;AAIP,OAAI,UAAU,aAAa;AAC1B,UAAM,IAAI,SAAS,YAAY,WAAW,SAAS,UAAU,CAAC;AAG9D,gBAAY,KAAK,IAAI,YAAY,mBAAmB,aAAa;;;AAMpE,QAAM,6BAAa,IAAI,MAAM,6BAA6B;;AAI3D,QAAO,eAAe,SAAS,QAAQ,EACtC,OAAO,aAAa,GAAG,QAAQ,YAAY,IAC3C,CAAC;AAEF,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kuckit/infrastructure",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,9 +22,9 @@
22
22
  "prepublishOnly": "npm run build && node ../../scripts/resolve-workspace-protocols.cjs && node ../../scripts/check-no-workspace-protocol.cjs"
23
23
  },
24
24
  "dependencies": {
25
- "@kuckit/domain": "^1.0.2",
26
- "@kuckit/db": "^1.0.2",
27
- "@kuckit/auth": "^1.0.2",
25
+ "@kuckit/domain": "^1.0.3",
26
+ "@kuckit/db": "^1.0.3",
27
+ "@kuckit/auth": "^1.0.3",
28
28
  "@ai-sdk/google": "^2.0.13",
29
29
  "awilix": "^10.0.2",
30
30
  "drizzle-orm": "^0.44.2",