@rx-ted/packages-honest-plugins 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +45 -0
  3. package/api-doc/.turbo/turbo-build.log +1 -0
  4. package/api-doc/.turbo/turbo-test.log +11 -0
  5. package/api-doc/.turbo/turbo-typecheck.log +1 -0
  6. package/api-doc/CHANGELOG.md +22 -0
  7. package/api-doc/README.md +80 -0
  8. package/api-doc/dist/api-doc.plugin.d.ts +53 -0
  9. package/api-doc/dist/api-doc.plugin.js +452 -0
  10. package/api-doc/dist/index.d.ts +5 -0
  11. package/api-doc/dist/index.js +3 -0
  12. package/api-doc/dist/interfaces/renderer.interface.d.ts +7 -0
  13. package/api-doc/dist/interfaces/renderer.interface.js +1 -0
  14. package/api-doc/dist/renderers/scalar.renderer.d.ts +10 -0
  15. package/api-doc/dist/renderers/scalar.renderer.js +76 -0
  16. package/api-doc/dist/renderers/swagger.renderer.d.ts +10 -0
  17. package/api-doc/dist/renderers/swagger.renderer.js +83 -0
  18. package/api-doc/node_modules/.bin/esbuild +22 -0
  19. package/api-doc/node_modules/.bin/jiti +22 -0
  20. package/api-doc/node_modules/.bin/sass +22 -0
  21. package/api-doc/node_modules/.bin/tsx +22 -0
  22. package/api-doc/node_modules/.bin/vite +22 -0
  23. package/api-doc/node_modules/.bin/vitest +22 -0
  24. package/api-doc/node_modules/.bin/yaml +22 -0
  25. package/api-doc/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  26. package/api-doc/package.json +48 -0
  27. package/api-doc/src/api-doc.plugin.ts +554 -0
  28. package/api-doc/src/index.ts +5 -0
  29. package/api-doc/src/interfaces/renderer.interface.ts +5 -0
  30. package/api-doc/src/plugin.test.ts +740 -0
  31. package/api-doc/src/renderers/scalar.renderer.ts +82 -0
  32. package/api-doc/src/renderers/swagger.renderer.ts +89 -0
  33. package/api-doc/tsconfig.json +21 -0
  34. package/api-doc/vitest.config.ts +13 -0
  35. package/cache/.turbo/turbo-build.log +1 -0
  36. package/cache/.turbo/turbo-test.log +16 -0
  37. package/cache/CHANGELOG.md +23 -0
  38. package/cache/README.md +79 -0
  39. package/cache/dist/cache-service.d.ts +8 -0
  40. package/cache/dist/cache-service.js +21 -0
  41. package/cache/dist/cacheable.d.ts +2 -0
  42. package/cache/dist/cacheable.js +10 -0
  43. package/cache/dist/cloudflare/driver.d.ts +23 -0
  44. package/cache/dist/cloudflare/driver.js +102 -0
  45. package/cache/dist/cloudflare/index.d.ts +3 -0
  46. package/cache/dist/cloudflare/index.js +2 -0
  47. package/cache/dist/cloudflare/plugin.d.ts +19 -0
  48. package/cache/dist/cloudflare/plugin.js +58 -0
  49. package/cache/dist/index.d.ts +11 -0
  50. package/cache/dist/index.js +14 -0
  51. package/cache/dist/local/driver.d.ts +2 -0
  52. package/cache/dist/local/driver.js +98 -0
  53. package/cache/dist/local/index.d.ts +2 -0
  54. package/cache/dist/local/index.js +2 -0
  55. package/cache/dist/local/plugin.d.ts +14 -0
  56. package/cache/dist/local/plugin.js +24 -0
  57. package/cache/dist/redis/driver.d.ts +10 -0
  58. package/cache/dist/redis/driver.js +102 -0
  59. package/cache/dist/redis/index.d.ts +4 -0
  60. package/cache/dist/redis/index.js +2 -0
  61. package/cache/dist/redis/plugin.d.ts +25 -0
  62. package/cache/dist/redis/plugin.js +61 -0
  63. package/cache/dist/resolve.d.ts +24 -0
  64. package/cache/dist/resolve.js +114 -0
  65. package/cache/dist/types.d.ts +18 -0
  66. package/cache/dist/types.js +1 -0
  67. package/cache/node_modules/.bin/esbuild +22 -0
  68. package/cache/node_modules/.bin/jiti +22 -0
  69. package/cache/node_modules/.bin/sass +22 -0
  70. package/cache/node_modules/.bin/tsx +22 -0
  71. package/cache/node_modules/.bin/vite +22 -0
  72. package/cache/node_modules/.bin/vitest +22 -0
  73. package/cache/node_modules/.bin/yaml +22 -0
  74. package/cache/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  75. package/cache/package.json +46 -0
  76. package/cache/src/cache-service.test.ts +16 -0
  77. package/cache/src/cache-service.ts +15 -0
  78. package/cache/src/cacheable.test.ts +78 -0
  79. package/cache/src/cacheable.ts +16 -0
  80. package/cache/src/cloudflare/driver.test.ts +188 -0
  81. package/cache/src/cloudflare/driver.ts +118 -0
  82. package/cache/src/cloudflare/index.ts +3 -0
  83. package/cache/src/cloudflare/plugin.ts +71 -0
  84. package/cache/src/index.test.ts +68 -0
  85. package/cache/src/index.ts +20 -0
  86. package/cache/src/local/driver.ts +117 -0
  87. package/cache/src/local/index.ts +2 -0
  88. package/cache/src/local/plugin.ts +34 -0
  89. package/cache/src/redis/driver.test.ts +71 -0
  90. package/cache/src/redis/driver.ts +124 -0
  91. package/cache/src/redis/index.ts +4 -0
  92. package/cache/src/redis/plugin.ts +84 -0
  93. package/cache/src/resolve.test.ts +257 -0
  94. package/cache/src/resolve.ts +140 -0
  95. package/cache/src/types.ts +14 -0
  96. package/cache/tsconfig.json +21 -0
  97. package/cache/vitest.config.ts +13 -0
  98. package/db/.turbo/turbo-build.log +1 -0
  99. package/db/.turbo/turbo-test.log +21 -0
  100. package/db/CHANGELOG.md +26 -0
  101. package/db/README.md +99 -0
  102. package/db/dist/constants.d.ts +1 -0
  103. package/db/dist/constants.js +1 -0
  104. package/db/dist/d1/index.d.ts +3 -0
  105. package/db/dist/d1/index.js +2 -0
  106. package/db/dist/d1/plugin.d.ts +18 -0
  107. package/db/dist/d1/plugin.js +104 -0
  108. package/db/dist/db-service.d.ts +7 -0
  109. package/db/dist/db-service.js +21 -0
  110. package/db/dist/index.d.ts +15 -0
  111. package/db/dist/index.js +20 -0
  112. package/db/dist/mysql/client.d.ts +36 -0
  113. package/db/dist/mysql/client.js +84 -0
  114. package/db/dist/mysql/driver.d.ts +18 -0
  115. package/db/dist/mysql/driver.js +107 -0
  116. package/db/dist/mysql/index.d.ts +11 -0
  117. package/db/dist/mysql/index.js +11 -0
  118. package/db/dist/mysql/plugin.d.ts +51 -0
  119. package/db/dist/mysql/plugin.js +94 -0
  120. package/db/dist/mysql/types.d.ts +38 -0
  121. package/db/dist/mysql/types.js +1 -0
  122. package/db/dist/postgres/index.d.ts +2 -0
  123. package/db/dist/postgres/index.js +3 -0
  124. package/db/dist/repository.d.ts +14 -0
  125. package/db/dist/repository.js +79 -0
  126. package/db/dist/resolve.d.ts +6 -0
  127. package/db/dist/resolve.js +81 -0
  128. package/db/dist/schema-builder/column-builder.d.ts +26 -0
  129. package/db/dist/schema-builder/column-builder.js +53 -0
  130. package/db/dist/schema-builder/compile-d1.d.ts +5 -0
  131. package/db/dist/schema-builder/compile-d1.js +67 -0
  132. package/db/dist/schema-builder/compile-mysql.d.ts +12 -0
  133. package/db/dist/schema-builder/compile-mysql.js +78 -0
  134. package/db/dist/schema-builder/index.d.ts +8 -0
  135. package/db/dist/schema-builder/index.js +22 -0
  136. package/db/dist/schema-builder/table-builder.d.ts +16 -0
  137. package/db/dist/schema-builder/table-builder.js +38 -0
  138. package/db/dist/schema-builder/types.d.ts +26 -0
  139. package/db/dist/schema-builder/types.js +1 -0
  140. package/db/dist/schema-builder/zod-bridge.d.ts +24 -0
  141. package/db/dist/schema-builder/zod-bridge.js +53 -0
  142. package/db/dist/sqlite/index.d.ts +4 -0
  143. package/db/dist/sqlite/index.js +2 -0
  144. package/db/dist/sqlite/plugin.d.ts +17 -0
  145. package/db/dist/sqlite/plugin.js +33 -0
  146. package/db/dist/types.d.ts +42 -0
  147. package/db/dist/types.js +1 -0
  148. package/db/node_modules/.bin/esbuild +22 -0
  149. package/db/node_modules/.bin/jiti +22 -0
  150. package/db/node_modules/.bin/sass +22 -0
  151. package/db/node_modules/.bin/tsx +22 -0
  152. package/db/node_modules/.bin/vite +22 -0
  153. package/db/node_modules/.bin/vitest +22 -0
  154. package/db/node_modules/.bin/yaml +22 -0
  155. package/db/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  156. package/db/package.json +59 -0
  157. package/db/src/constants.test.ts +8 -0
  158. package/db/src/constants.ts +1 -0
  159. package/db/src/d1/index.ts +13 -0
  160. package/db/src/d1/plugin.ts +135 -0
  161. package/db/src/db-service.ts +14 -0
  162. package/db/src/index.test.ts +63 -0
  163. package/db/src/index.ts +57 -0
  164. package/db/src/mysql/client.ts +112 -0
  165. package/db/src/mysql/driver.test.ts +190 -0
  166. package/db/src/mysql/driver.ts +116 -0
  167. package/db/src/mysql/index.ts +51 -0
  168. package/db/src/mysql/plugin.test.ts +228 -0
  169. package/db/src/mysql/plugin.ts +128 -0
  170. package/db/src/mysql/types.ts +32 -0
  171. package/db/src/postgres/index.ts +15 -0
  172. package/db/src/repository.test.ts +195 -0
  173. package/db/src/repository.ts +95 -0
  174. package/db/src/resolve.ts +105 -0
  175. package/db/src/schema-builder/column-builder.test.ts +55 -0
  176. package/db/src/schema-builder/column-builder.ts +87 -0
  177. package/db/src/schema-builder/compile-d1.test.ts +60 -0
  178. package/db/src/schema-builder/compile-d1.ts +70 -0
  179. package/db/src/schema-builder/compile-mysql.test.ts +64 -0
  180. package/db/src/schema-builder/compile-mysql.ts +102 -0
  181. package/db/src/schema-builder/index.test.ts +36 -0
  182. package/db/src/schema-builder/index.ts +41 -0
  183. package/db/src/schema-builder/table-builder.test.ts +55 -0
  184. package/db/src/schema-builder/table-builder.ts +50 -0
  185. package/db/src/schema-builder/types.test.ts +68 -0
  186. package/db/src/schema-builder/types.ts +30 -0
  187. package/db/src/schema-builder/zod-bridge.ts +89 -0
  188. package/db/src/sqlite/index.ts +14 -0
  189. package/db/src/sqlite/plugin.ts +46 -0
  190. package/db/src/types.ts +45 -0
  191. package/db/tsconfig.json +21 -0
  192. package/db/vitest.config.ts +13 -0
  193. package/mail/.turbo/turbo-build.log +1 -0
  194. package/mail/.turbo/turbo-test.log +12 -0
  195. package/mail/.turbo/turbo-typecheck.log +1 -0
  196. package/mail/CHANGELOG.md +25 -0
  197. package/mail/README.md +214 -0
  198. package/mail/dist/index.d.ts +4 -0
  199. package/mail/dist/index.js +2 -0
  200. package/mail/dist/plugin.d.ts +64 -0
  201. package/mail/dist/plugin.js +232 -0
  202. package/mail/dist/providers/brevo.provider.d.ts +15 -0
  203. package/mail/dist/providers/brevo.provider.js +75 -0
  204. package/mail/dist/providers/custom.provider.d.ts +9 -0
  205. package/mail/dist/providers/custom.provider.js +22 -0
  206. package/mail/dist/providers/resend.provider.d.ts +16 -0
  207. package/mail/dist/providers/resend.provider.js +77 -0
  208. package/mail/dist/providers/smtp.provider.d.ts +21 -0
  209. package/mail/dist/providers/smtp.provider.js +86 -0
  210. package/mail/dist/rate-limiter.d.ts +16 -0
  211. package/mail/dist/rate-limiter.js +49 -0
  212. package/mail/dist/types.d.ts +68 -0
  213. package/mail/dist/types.js +6 -0
  214. package/mail/node_modules/.bin/esbuild +22 -0
  215. package/mail/node_modules/.bin/jiti +22 -0
  216. package/mail/node_modules/.bin/sass +22 -0
  217. package/mail/node_modules/.bin/tsx +22 -0
  218. package/mail/node_modules/.bin/vite +22 -0
  219. package/mail/node_modules/.bin/vitest +22 -0
  220. package/mail/node_modules/.bin/yaml +22 -0
  221. package/mail/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  222. package/mail/package.json +52 -0
  223. package/mail/src/index.ts +4 -0
  224. package/mail/src/plugin.test.ts +219 -0
  225. package/mail/src/plugin.ts +313 -0
  226. package/mail/src/providers/brevo.provider.ts +78 -0
  227. package/mail/src/providers/custom.provider.ts +29 -0
  228. package/mail/src/providers/resend.provider.ts +74 -0
  229. package/mail/src/providers/smtp.provider.ts +85 -0
  230. package/mail/src/rate-limiter.test.ts +81 -0
  231. package/mail/src/rate-limiter.ts +54 -0
  232. package/mail/src/types.ts +81 -0
  233. package/mail/tsconfig.json +21 -0
  234. package/mail/vitest.config.ts +13 -0
  235. package/package.json +36 -0
  236. package/s3/.turbo/turbo-build.log +1 -0
  237. package/s3/.turbo/turbo-test.log +11 -0
  238. package/s3/CHANGELOG.md +20 -0
  239. package/s3/README.md +90 -0
  240. package/s3/dist/index.d.ts +6 -0
  241. package/s3/dist/index.js +4 -0
  242. package/s3/dist/s3-service.d.ts +7 -0
  243. package/s3/dist/s3-service.js +21 -0
  244. package/s3/dist/s3.driver.d.ts +6 -0
  245. package/s3/dist/s3.driver.js +221 -0
  246. package/s3/dist/s3.plugin.d.ts +24 -0
  247. package/s3/dist/s3.plugin.js +58 -0
  248. package/s3/dist/types.d.ts +30 -0
  249. package/s3/dist/types.js +1 -0
  250. package/s3/node_modules/.bin/esbuild +22 -0
  251. package/s3/node_modules/.bin/jiti +22 -0
  252. package/s3/node_modules/.bin/sass +22 -0
  253. package/s3/node_modules/.bin/tsx +22 -0
  254. package/s3/node_modules/.bin/vite +22 -0
  255. package/s3/node_modules/.bin/vitest +22 -0
  256. package/s3/node_modules/.bin/yaml +22 -0
  257. package/s3/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  258. package/s3/package.json +47 -0
  259. package/s3/src/index.test.ts +20 -0
  260. package/s3/src/index.ts +13 -0
  261. package/s3/src/s3-service.ts +14 -0
  262. package/s3/src/s3.driver.ts +259 -0
  263. package/s3/src/s3.plugin.ts +80 -0
  264. package/s3/src/types.ts +37 -0
  265. package/s3/tsconfig.json +21 -0
  266. package/s3/vitest.config.ts +13 -0
@@ -0,0 +1,140 @@
1
+ import { ENV_SYMBOL, type Env, Platform, resolveBinding } from '@rx-ted/packages-core';
2
+ export { resolveBinding };
3
+ import { ComponentManager, resolvePluginLogger } from '@rx-ted/packages-honest';
4
+ import type { Application, IPlugin } from '@rx-ted/packages-honest';
5
+ import { createCloudflareKvDriver } from './cloudflare/driver';
6
+ import type { KvNamespace } from './cloudflare/driver';
7
+ import { createRedisDriver } from './redis/driver';
8
+ import type { RedisClientOptions } from './redis/driver';
9
+ import { createLocalCacheDriver } from './local/driver';
10
+ import type { CacheDriver } from './types';
11
+ import { CACHE_GLOBAL_KEY } from './cache-service';
12
+
13
+ export interface CachePluginOptions {
14
+ driver?: 'redis' | 'kv' | 'local';
15
+ redis?: RedisClientOptions;
16
+ kvBinding?: string;
17
+ }
18
+
19
+ export function findKvBinding(env?: Env): string {
20
+ const sources: Record<string, unknown>[] = [
21
+ globalThis as Record<string, unknown>,
22
+ ((globalThis as any).env ?? {}) as Record<string, unknown>,
23
+ Platform.env(),
24
+ ];
25
+ for (const source of sources) {
26
+ for (const key of Object.keys(source)) {
27
+ const val = source[key];
28
+ if (val && typeof val === 'object' && 'get' in val && 'put' in val && 'delete' in val) {
29
+ const { get, put, delete: del } = val as any;
30
+ if (typeof get === 'function' && typeof put === 'function' && typeof del === 'function') {
31
+ return key;
32
+ }
33
+ }
34
+ }
35
+ }
36
+ return '';
37
+ }
38
+
39
+ function resolveRedisConfig(
40
+ options: CachePluginOptions | undefined,
41
+ env?: Env,
42
+ ): RedisClientOptions | null {
43
+ if (options?.redis) return options.redis;
44
+ if (env?.has('REDIS_URL')) return { url: env.get('REDIS_URL')! };
45
+ if (env?.has('REDIS_HOST')) {
46
+ return {
47
+ host: env.get('REDIS_HOST'),
48
+ port: env.get('REDIS_PORT', 'number'),
49
+ username: env.get('REDIS_USERNAME'),
50
+ password: env.get('REDIS_PASSWORD'),
51
+ db: env.get('REDIS_DB', 'number'),
52
+ };
53
+ }
54
+ return null;
55
+ }
56
+
57
+ export class CachePlugin implements IPlugin {
58
+ readonly name = 'cache-plugin';
59
+ readonly version = '1.0.0';
60
+ logger?: import('@rx-ted/packages-core').ILogger;
61
+
62
+ private driver: CacheDriver | null = null;
63
+
64
+ constructor(private options?: CachePluginOptions) {}
65
+
66
+ getClient(): CacheDriver {
67
+ if (!this.driver) {
68
+ throw new Error('Cache not initialized. Ensure beforeModulesRegistered has run.');
69
+ }
70
+ return this.driver;
71
+ }
72
+
73
+ async beforeModulesRegistered(app: Application): Promise<void> {
74
+ this.logger ??= resolvePluginLogger(this.name);
75
+ this.logger.info('Cache: initializing...');
76
+
77
+ const appEnv = ComponentManager.hasPlugin(ENV_SYMBOL)
78
+ ? ComponentManager.getPlugin<Env>(ENV_SYMBOL)
79
+ : undefined;
80
+
81
+ const explicit = this.options?.driver;
82
+ const platform = appEnv?.platform ?? 'node';
83
+
84
+ if (explicit === 'kv' || (!explicit && platform === 'cloudflare')) {
85
+ this.driver = this.initCloudflare(appEnv);
86
+ } else if (
87
+ explicit === 'redis' ||
88
+ (!explicit && (platform === 'node' || platform === 'bun' || platform === 'deno'))
89
+ ) {
90
+ this.driver = await this.initNode(appEnv);
91
+ } else {
92
+ this.driver = createLocalCacheDriver();
93
+ }
94
+
95
+ app.getContext().set('honest:cache', this.driver);
96
+ ComponentManager.registerPlugin(CACHE_GLOBAL_KEY, this.driver);
97
+ this.logger.info('Cache: ready');
98
+ }
99
+
100
+ private initCloudflare(env?: Env): CacheDriver {
101
+ const bindingName = this.options?.kvBinding || findKvBinding(env);
102
+ if (bindingName) {
103
+ const ns = resolveBinding(bindingName, env) as KvNamespace | undefined;
104
+ if (ns) {
105
+ this.logger?.info('Cache: using Cloudflare KV');
106
+ return createCloudflareKvDriver(ns);
107
+ }
108
+ }
109
+ throw new Error(
110
+ `Cache: Cloudflare KV binding not found. Configure a KV namespace binding named "${bindingName || '<name>'}" in your wrangler.toml.`,
111
+ );
112
+ }
113
+
114
+ private async initNode(env?: Env): Promise<CacheDriver> {
115
+ const redisConfig = resolveRedisConfig(this.options, env);
116
+ if (redisConfig) {
117
+ try {
118
+ const driver = await createRedisDriver(redisConfig);
119
+ const ok = await driver.healthCheck();
120
+ if (ok) {
121
+ this.logger?.info('Cache: using Redis');
122
+ return driver;
123
+ }
124
+ this.logger?.warn('Cache: Redis health check failed, falling back to local');
125
+ } catch (err) {
126
+ this.logger?.warn(
127
+ { error: err instanceof Error ? err.message : String(err) },
128
+ 'Cache: Redis connection failed, falling back to local',
129
+ );
130
+ }
131
+ }
132
+ this.logger?.info('Cache: using local in-memory cache');
133
+ return createLocalCacheDriver();
134
+ }
135
+
136
+ async close(): Promise<void> {
137
+ await this.driver?.close();
138
+ this.driver = null;
139
+ }
140
+ }
@@ -0,0 +1,14 @@
1
+ export interface CacheDriver {
2
+ get<T = unknown>(key: string): Promise<T | null>;
3
+ set(key: string, value: unknown, ttl?: number): Promise<boolean>;
4
+ delete(key: string): Promise<boolean>;
5
+ exists(key: string): Promise<boolean>;
6
+ mget<T = unknown>(keys: string[]): Promise<(T | null)[]>;
7
+ mset(items: Array<{ key: string; value: unknown; ttl?: number }>): Promise<boolean>;
8
+ deleteByPattern(pattern: string): Promise<number>;
9
+ incr(key: string): Promise<number>;
10
+ decr(key: string): Promise<number>;
11
+ expire(key: string, ttl: number): Promise<boolean>;
12
+ close(): Promise<void>;
13
+ healthCheck(): Promise<boolean>;
14
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "declaration": true,
8
+ "sourceMap": false,
9
+ "experimentalDecorators": true,
10
+ "emitDecoratorMetadata": true,
11
+ "types": ["node"],
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "isolatedModules": true,
15
+ "verbatimModuleSyntax": true,
16
+ "rootDir": "./src",
17
+ "outDir": "./dist"
18
+ },
19
+ "include": ["src"],
20
+ "exclude": ["**/*.test.ts"]
21
+ }
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ import { getWorkspaceAliases } from '../../../vitest.workspace-aliases';
3
+
4
+ export default defineConfig({
5
+ resolve: {
6
+ alias: getWorkspaceAliases(),
7
+ },
8
+ test: {
9
+ globals: true,
10
+ environment: 'node',
11
+ exclude: ['node_modules'],
12
+ },
13
+ });
@@ -0,0 +1 @@
1
+ $ tsc -p tsconfig.json
@@ -0,0 +1,21 @@
1
+ $ vitest run
2
+
3
+  RUN  v4.1.8 /Users/ben/projects/app/packages/honest-plugins/db
4
+
5
+ ✓ src/schema-builder/column-builder.test.ts (6 tests) 3ms
6
+ ✓ src/schema-builder/types.test.ts (7 tests) 2ms
7
+ ✓ src/schema-builder/table-builder.test.ts (5 tests) 2ms
8
+ ✓ src/mysql/driver.test.ts (10 tests) 7ms
9
+ ✓ src/mysql/plugin.test.ts (16 tests) 11ms
10
+ ✓ src/constants.test.ts (1 test) 3ms
11
+ ✓ src/repository.test.ts (14 tests) 5ms
12
+ ✓ src/schema-builder/compile-d1.test.ts (4 tests) 2ms
13
+ ✓ src/schema-builder/compile-mysql.test.ts (4 tests) 2ms
14
+ ✓ src/schema-builder/index.test.ts (4 tests) 3ms
15
+ ✓ src/index.test.ts (8 tests) 2ms
16
+
17
+  Test Files  11 passed (11)
18
+  Tests  79 passed (79)
19
+  Start at  14:17:12
20
+  Duration  1.08s (transform 793ms, setup 0ms, import 2.48s, tests 42ms, environment 1ms)
21
+
@@ -0,0 +1,26 @@
1
+ # @rx-ted/packages-honest-plugins-db
2
+
3
+ ## 1.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 11bbae7: Remove defunct packages (web-admin, auth, http-client, search) and introduce barrel packages for consolidated exports. Migrate all internal imports from scoped plugin names (`@rx-ted/packages-honest-plugins-db`) to path-based barrel imports (`@rx-ted/packages-honest-plugins/db`). Reset all package versions to 1.0.0 with consolidated changelogs. Clean up obsolete documentation across the monorepo.
8
+ - Updated dependencies [11bbae7]
9
+ - @rx-ted/packages-core@1.0.1
10
+ - @rx-ted/packages-honest@1.0.1
11
+
12
+ ## 1.0.0
13
+
14
+ Initial consolidated release.
15
+
16
+ ### Features
17
+
18
+ - Database plugin for @rx-ted/packages-honest
19
+ - Schema-builder with Zod integration (`zdb()` helper)
20
+ - D1 (SQLite) schema compiler with proper JSON mode
21
+ - MySQL schema compiler
22
+ - `compileSchema` dispatcher for multi-dialect support
23
+ - Lazy Proxy D1 binding resolution for wrangler dev compatibility
24
+ - `SqlitePlugin` using better-sqlite3 (WAL mode, foreign keys)
25
+ - Normalize SQLite insert results (`{changes,lastInsertRowid}` → `{affectedRows,insertId}`)
26
+ - Shared `resolveBinding` utility from core
package/db/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # @rx-ted/packages-honest-plugins-db
2
+
3
+ Database plugin for [@rx-ted/packages-honest](https://github.com/rx-ted/honest). Supports MySQL, SQLite, Cloudflare D1, and PostgreSQL via Drizzle ORM.
4
+
5
+ ## Features
6
+
7
+ - **Multi-dialect**: MySQL, SQLite, Cloudflare D1, PostgreSQL
8
+ - **Drizzle ORM**: type-safe SQL with schema-first approach
9
+ - **Runtime-agnostic**: works on Node.js, Bun, Deno, and Cloudflare Workers
10
+ - **Portable schema builder**: define schemas once, compile to any dialect
11
+ - **Zod bridge**: `zdb()` for Zod-to-Drizzle schema conversion
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ pnpm add @rx-ted/packages-honest-plugins-db
17
+ ```
18
+
19
+ Peer dependencies: `@rx-ted/packages-honest`, `hono`
20
+
21
+ ## Usage
22
+
23
+ ### Register as a plugin
24
+
25
+ ```ts
26
+ import { DBPlugin } from '@rx-ted/packages-honest-plugins/db';
27
+
28
+ const plugin = new DBPlugin({
29
+ // dialect is auto-detected from DB env var
30
+ });
31
+
32
+ const { hono } = await Application.create(AppModule, {
33
+ plugins: [plugin],
34
+ });
35
+ ```
36
+
37
+ ### Subpath exports
38
+
39
+ ```ts
40
+ import { DBPlugin } from '@rx-ted/packages-honest-plugins/db' // auto-detect dialect
41
+ import { DBPlugin } from '@rx-ted/packages-honest-plugins/db/d1' // Cloudflare D1
42
+ import { DBPlugin } from '@rx-ted/packages-honest-plugins/db/sqlite' // SQLite
43
+ ```
44
+
45
+ ### Access the database
46
+
47
+ ```ts
48
+ import { ComponentManager } from '@rx-ted/packages-honest';
49
+ import { DbService } from '@rx-ted/packages-honest-plugins/db';
50
+
51
+ const db = ComponentManager.getPlugin<DbService>('db');
52
+ // Use db.client for Drizzle ORM operations
53
+ ```
54
+
55
+ ### Schema builder
56
+
57
+ ```ts
58
+ import { compileSchema, table, column } from '@rx-ted/packages-honest-plugins/db';
59
+
60
+ const schema = table('users', {
61
+ id: column.uuid().primaryKey(),
62
+ name: column.text().notNull(),
63
+ });
64
+
65
+ // Compiles to dialect-specific DDL based on runtime platform
66
+ const ddl = compileSchema(schema);
67
+ ```
68
+
69
+ ### Zod bridge
70
+
71
+ ```ts
72
+ import { zdb, toTableDefinition } from '@rx-ted/packages-honest-plugins/db';
73
+ import { z } from 'zod';
74
+
75
+ const userSchema = z.object({
76
+ id: z.string().uuid(),
77
+ name: z.string().min(1),
78
+ });
79
+
80
+ const meta = getZodDbMeta(userSchema, 'users');
81
+ const tableDef = toTableDefinition(meta);
82
+ ```
83
+
84
+ ## Supported Dialects
85
+
86
+ | Dialect | Env var | Package |
87
+ |---------|---------|---------|
88
+ | MySQL | `DB=mysql` | `mysql2` |
89
+ | SQLite | `DB=sqlite` | `better-sqlite3` |
90
+ | Cloudflare D1 | `DB=d1` | `@libsql/client` |
91
+ | PostgreSQL | `DB=postgres` | `postgres` |
92
+
93
+ ## Scripts
94
+
95
+ | Script | Description |
96
+ |--------|-------------|
97
+ | `pnpm test` | Run tests |
98
+ | `pnpm build` | Build |
99
+ | `pnpm typecheck` | Type check |
@@ -0,0 +1 @@
1
+ export declare const DB_GLOBAL_KEY = "app:db";
@@ -0,0 +1 @@
1
+ export const DB_GLOBAL_KEY = 'app:db';
@@ -0,0 +1,3 @@
1
+ export { sqliteTable, text, integer, real, blob, uniqueIndex, index, primaryKey, foreignKey, } from 'drizzle-orm/sqlite-core';
2
+ export type { AnyD1Database as D1DrizzleDatabase } from 'drizzle-orm/d1';
3
+ export { D1Plugin } from './plugin';
@@ -0,0 +1,2 @@
1
+ export { sqliteTable, text, integer, real, blob, uniqueIndex, index, primaryKey, foreignKey, } from 'drizzle-orm/sqlite-core';
2
+ export { D1Plugin } from './plugin';
@@ -0,0 +1,18 @@
1
+ import type { Hono } from 'hono';
2
+ import { type ILogger } from '@rx-ted/packages-core';
3
+ import type { IPlugin, Application } from '@rx-ted/packages-honest';
4
+ export declare class D1Plugin implements IPlugin {
5
+ private options;
6
+ readonly name = "app:db:d1";
7
+ readonly version = "0.0.1";
8
+ logger?: ILogger;
9
+ private db;
10
+ constructor(options: {
11
+ binding?: string;
12
+ schema: Record<string, any>;
13
+ });
14
+ beforeModulesRegistered(app: Application, _hono: Hono): Promise<void>;
15
+ afterModulesRegistered(_app: Application, _hono: Hono): Promise<void>;
16
+ close(): Promise<void>;
17
+ private resolveBindingName;
18
+ }
@@ -0,0 +1,104 @@
1
+ import { ENV_SYMBOL, Platform, resolveBinding, } from '@rx-ted/packages-core';
2
+ import { ComponentManager, resolvePluginLogger } from '@rx-ted/packages-honest';
3
+ import { drizzle } from 'drizzle-orm/d1';
4
+ import { DB_GLOBAL_KEY } from '../constants';
5
+ import { assertRuntimeSupport } from '../resolve';
6
+ export class D1Plugin {
7
+ options;
8
+ name = `${DB_GLOBAL_KEY}:d1`;
9
+ version = '0.0.1';
10
+ logger;
11
+ db = null;
12
+ constructor(options) {
13
+ this.options = options;
14
+ }
15
+ async beforeModulesRegistered(app, _hono) {
16
+ this.logger ??= resolvePluginLogger(this.name);
17
+ const appEnv = ComponentManager.getPlugin(ENV_SYMBOL);
18
+ assertRuntimeSupport(appEnv.platform, 'd1');
19
+ const bindingName = this.resolveBindingName();
20
+ this.logger.info(`connecting... (binding: ${bindingName})`);
21
+ const binding = resolveBinding(bindingName);
22
+ if (binding) {
23
+ this.db = drizzle(binding, { schema: this.options.schema });
24
+ ComponentManager.registerPlugin(DB_GLOBAL_KEY, this.db);
25
+ return;
26
+ }
27
+ const resolveName = this.resolveBindingName.bind(this);
28
+ const opts = this.options;
29
+ const ensure = () => {
30
+ if (!this.db) {
31
+ const bn = resolveName();
32
+ const b = resolveBinding(bn);
33
+ if (b) {
34
+ this.db = drizzle(b, { schema: opts.schema });
35
+ }
36
+ }
37
+ return this.db;
38
+ };
39
+ ComponentManager.registerPlugin(DB_GLOBAL_KEY, new Proxy({}, {
40
+ get(_, prop) {
41
+ const instance = ensure();
42
+ if (!instance) {
43
+ throw new Error(`D1 binding "${resolveName()}" not found`);
44
+ }
45
+ const val = instance[prop];
46
+ return typeof val === 'function' ? val.bind(instance) : val;
47
+ },
48
+ }));
49
+ }
50
+ async afterModulesRegistered(_app, _hono) {
51
+ if (!this.logger)
52
+ return;
53
+ const bindingName = this.resolveBindingName();
54
+ try {
55
+ if (!this.db) {
56
+ const binding = resolveBinding(bindingName);
57
+ if (!binding) {
58
+ this.logger.warn(`health check skipped — binding "${bindingName}" not resolved`);
59
+ return;
60
+ }
61
+ this.db = drizzle(binding, { schema: this.options.schema });
62
+ ComponentManager.registerPlugin(DB_GLOBAL_KEY, this.db);
63
+ this.logger.info(`connected (binding: ${bindingName})`);
64
+ }
65
+ await healthCheck(this.db, bindingName);
66
+ this.logger.info(`health check passed (binding: ${bindingName})`);
67
+ }
68
+ catch (error) {
69
+ this.logger.error({ error: error instanceof Error ? error.message : String(error) }, `health check failed (binding: ${bindingName})`);
70
+ }
71
+ }
72
+ async close() {
73
+ this.logger?.info(`shutting down (binding: ${this.resolveBindingName()})`);
74
+ }
75
+ resolveBindingName() {
76
+ if (this.options.binding)
77
+ return this.options.binding;
78
+ return findD1Binding() ?? 'DB';
79
+ }
80
+ }
81
+ function isD1Database(value) {
82
+ return (value !== null && typeof value === 'object' && typeof value.prepare === 'function');
83
+ }
84
+ function findD1Binding() {
85
+ const sources = [globalThis, globalThis.env, Platform.env()];
86
+ for (const source of sources) {
87
+ if (!source || typeof source !== 'object')
88
+ continue;
89
+ for (const key of Object.keys(source)) {
90
+ if (isD1Database(source[key]))
91
+ return key;
92
+ }
93
+ }
94
+ return null;
95
+ }
96
+ async function healthCheck(db, bindingName) {
97
+ try {
98
+ await db.run('SELECT 1');
99
+ }
100
+ catch (cause) {
101
+ throw new Error(`D1 health check failed for binding "${bindingName}": the binding has no active database session. ` +
102
+ `Ensure the D1 database is bound correctly in your wrangler.toml and has been created (npx wrangler d1 create <name>).`, { cause });
103
+ }
104
+ }
@@ -0,0 +1,7 @@
1
+ import type { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
2
+ declare class DbService {
3
+ constructor();
4
+ }
5
+ interface DbService extends BaseSQLiteDatabase<'async', any> {
6
+ }
7
+ export { DbService };
@@ -0,0 +1,21 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Service, ComponentManager } from '@rx-ted/packages-honest';
11
+ import { DB_GLOBAL_KEY } from './constants';
12
+ let DbService = class DbService {
13
+ constructor() {
14
+ return ComponentManager.getPlugin(DB_GLOBAL_KEY);
15
+ }
16
+ };
17
+ DbService = __decorate([
18
+ Service(),
19
+ __metadata("design:paramtypes", [])
20
+ ], DbService);
21
+ export { DbService };
@@ -0,0 +1,15 @@
1
+ export { DB_GLOBAL_KEY } from './constants';
2
+ export { DBPlugin, assertRuntimeSupport } from './resolve';
3
+ export type { AppRuntime, DbType } from './resolve';
4
+ export { DbService } from './db-service';
5
+ export { BaseRepository } from './repository';
6
+ export type { DatabaseClient, PreparedStatement, DatabaseConnection, QueryResult, DatabaseDriver, QueryOptions, PaginationResult, } from './types';
7
+ export { eq, and, or, not, inArray, sql, asc, desc, count, like, isNull, isNotNull, } from 'drizzle-orm';
8
+ export * from './mysql';
9
+ export * as mysql from './mysql';
10
+ export * as postgres from './postgres';
11
+ export * as sqlite from './sqlite';
12
+ export * as d1 from './d1';
13
+ export * from './schema-builder';
14
+ export { zdb, getZodDbMeta, isZodObject, toTableDefinition, toColumnDefinition, } from './schema-builder/zod-bridge';
15
+ export type { ZodDbMeta } from './schema-builder/zod-bridge';
@@ -0,0 +1,20 @@
1
+ // Common exports
2
+ export { DB_GLOBAL_KEY } from './constants';
3
+ export { DBPlugin, assertRuntimeSupport } from './resolve';
4
+ export { DbService } from './db-service';
5
+ export { BaseRepository } from './repository';
6
+ // Common Drizzle operators
7
+ export { eq, and, or, not, inArray, sql, asc, desc, count, like, isNull, isNotNull, } from 'drizzle-orm';
8
+ // MySQL dialect (top-level for backward compatibility + namespaced)
9
+ export * from './mysql';
10
+ export * as mysql from './mysql';
11
+ // PostgreSQL dialect (namespaced only)
12
+ export * as postgres from './postgres';
13
+ // SQLite dialect (namespaced only)
14
+ export * as sqlite from './sqlite';
15
+ // Cloudflare D1 dialect (namespaced only)
16
+ export * as d1 from './d1';
17
+ // Portable schema builder (table builder + compile dispatcher)
18
+ export * from './schema-builder';
19
+ // Zod bridge
20
+ export { zdb, getZodDbMeta, isZodObject, toTableDefinition, toColumnDefinition, } from './schema-builder/zod-bridge';
@@ -0,0 +1,36 @@
1
+ import { type Pool } from 'mysql2/promise';
2
+ import type { DatabaseClient, DatabaseConnection, PreparedStatement } from '../types';
3
+ export declare function createMysqlPool(options: {
4
+ host: string;
5
+ port: number;
6
+ user: string;
7
+ password?: string;
8
+ database: string;
9
+ ssl?: boolean | {
10
+ rejectUnauthorized?: boolean;
11
+ ca?: string;
12
+ cert?: string;
13
+ key?: string;
14
+ };
15
+ connectionLimit?: number;
16
+ }): Pool;
17
+ export declare function createMysqlClient(options: {
18
+ host: string;
19
+ port: number;
20
+ user: string;
21
+ password?: string;
22
+ database: string;
23
+ ssl?: boolean | {
24
+ rejectUnauthorized?: boolean;
25
+ ca?: string;
26
+ cert?: string;
27
+ key?: string;
28
+ };
29
+ }): Promise<DatabaseClient>;
30
+ export declare class MysqlDatabaseClient implements DatabaseClient {
31
+ private pool;
32
+ constructor(pool: Pool);
33
+ prepare(sql: string): PreparedStatement;
34
+ getConnection(): Promise<DatabaseConnection>;
35
+ close(): Promise<void>;
36
+ }
@@ -0,0 +1,84 @@
1
+ import MySQL, {} from 'mysql2/promise';
2
+ export function createMysqlPool(options) {
3
+ const mysqlOptions = {
4
+ host: options.host,
5
+ port: options.port,
6
+ user: options.user,
7
+ password: options.password,
8
+ database: options.database,
9
+ waitForConnections: true,
10
+ connectionLimit: options.connectionLimit ?? 10,
11
+ queueLimit: 0,
12
+ };
13
+ if (options.ssl) {
14
+ mysqlOptions.ssl = options.ssl === true ? { rejectUnauthorized: false } : options.ssl;
15
+ }
16
+ return MySQL.createPool(mysqlOptions);
17
+ }
18
+ export async function createMysqlClient(options) {
19
+ const pool = createMysqlPool(options);
20
+ const connection = await pool.getConnection();
21
+ connection.release();
22
+ return new MysqlDatabaseClient(pool);
23
+ }
24
+ export class MysqlDatabaseClient {
25
+ pool;
26
+ constructor(pool) {
27
+ this.pool = pool;
28
+ }
29
+ prepare(sql) {
30
+ return new MysqlPreparedStatement(this.pool, sql);
31
+ }
32
+ async getConnection() {
33
+ const conn = await this.pool.getConnection();
34
+ return new MysqlDatabaseConnection(conn);
35
+ }
36
+ async close() {
37
+ await this.pool.end();
38
+ }
39
+ }
40
+ class MysqlPreparedStatement {
41
+ client;
42
+ sql;
43
+ constructor(client, sql) {
44
+ this.client = client;
45
+ this.sql = sql;
46
+ }
47
+ async execute(params) {
48
+ const connection = 'getConnection' in this.client ? await this.client.getConnection() : this.client;
49
+ try {
50
+ const [result] = await connection.execute(this.sql, params);
51
+ return {
52
+ affectedRows: result.affectedRows,
53
+ insertId: result.insertId ? Number(result.insertId) : undefined,
54
+ };
55
+ }
56
+ finally {
57
+ connection.release();
58
+ }
59
+ }
60
+ release() { }
61
+ }
62
+ class MysqlDatabaseConnection {
63
+ connection;
64
+ constructor(connection) {
65
+ this.connection = connection;
66
+ }
67
+ prepare(sql) {
68
+ return new MysqlPreparedStatement(this.connection, sql);
69
+ }
70
+ async query(sql, params) {
71
+ const [rows] = await this.connection.query(sql, params);
72
+ return rows;
73
+ }
74
+ async execute(sql, params) {
75
+ const [result] = await this.connection.execute(sql, params);
76
+ return {
77
+ affectedRows: result.affectedRows,
78
+ insertId: result.insertId ? Number(result.insertId) : undefined,
79
+ };
80
+ }
81
+ release() {
82
+ this.connection.release();
83
+ }
84
+ }