@adonis-agora/flags 0.0.0-beta-20261112141227

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 (322) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/LICENSE +21 -0
  3. package/README.md +16 -0
  4. package/dist/assets/spa/assets/index-DdmFo7xr.js +12 -0
  5. package/dist/assets/spa/assets/index-DdmFo7xr.js.map +1 -0
  6. package/dist/assets/spa/assets/index-DhkcP3Cw.css +2 -0
  7. package/dist/assets/spa/index.html +26 -0
  8. package/dist/commands/flags_list.d.ts +9 -0
  9. package/dist/commands/flags_list.d.ts.map +1 -0
  10. package/dist/commands/flags_list.js +51 -0
  11. package/dist/commands/flags_list.js.map +1 -0
  12. package/dist/commands/flags_ops.d.ts +60 -0
  13. package/dist/commands/flags_ops.d.ts.map +1 -0
  14. package/dist/commands/flags_ops.js +253 -0
  15. package/dist/commands/flags_ops.js.map +1 -0
  16. package/dist/commands/flags_refs.d.ts +15 -0
  17. package/dist/commands/flags_refs.d.ts.map +1 -0
  18. package/dist/commands/flags_refs.js +90 -0
  19. package/dist/commands/flags_refs.js.map +1 -0
  20. package/dist/commands/flags_set.d.ts +19 -0
  21. package/dist/commands/flags_set.d.ts.map +1 -0
  22. package/dist/commands/flags_set.js +97 -0
  23. package/dist/commands/flags_set.js.map +1 -0
  24. package/dist/commands/flags_types.d.ts +18 -0
  25. package/dist/commands/flags_types.d.ts.map +1 -0
  26. package/dist/commands/flags_types.js +94 -0
  27. package/dist/commands/flags_types.js.map +1 -0
  28. package/dist/commands/flags_work.d.ts +16 -0
  29. package/dist/commands/flags_work.d.ts.map +1 -0
  30. package/dist/commands/flags_work.js +71 -0
  31. package/dist/commands/flags_work.js.map +1 -0
  32. package/dist/commands/main.d.ts +15 -0
  33. package/dist/commands/main.d.ts.map +1 -0
  34. package/dist/commands/main.js +30 -0
  35. package/dist/commands/main.js.map +1 -0
  36. package/dist/commands/shared.d.ts +21 -0
  37. package/dist/commands/shared.d.ts.map +1 -0
  38. package/dist/commands/shared.js +70 -0
  39. package/dist/commands/shared.js.map +1 -0
  40. package/dist/configure.d.ts +11 -0
  41. package/dist/configure.d.ts.map +1 -0
  42. package/dist/configure.js +32 -0
  43. package/dist/configure.js.map +1 -0
  44. package/dist/providers/dashboard_provider.d.ts +65 -0
  45. package/dist/providers/dashboard_provider.d.ts.map +1 -0
  46. package/dist/providers/dashboard_provider.js +340 -0
  47. package/dist/providers/dashboard_provider.js.map +1 -0
  48. package/dist/providers/flags_provider.d.ts +30 -0
  49. package/dist/providers/flags_provider.d.ts.map +1 -0
  50. package/dist/providers/flags_provider.js +184 -0
  51. package/dist/providers/flags_provider.js.map +1 -0
  52. package/dist/services/main.d.ts +17 -0
  53. package/dist/services/main.d.ts.map +1 -0
  54. package/dist/services/main.js +20 -0
  55. package/dist/services/main.js.map +1 -0
  56. package/dist/src/admin.d.ts +189 -0
  57. package/dist/src/admin.d.ts.map +1 -0
  58. package/dist/src/admin.js +539 -0
  59. package/dist/src/admin.js.map +1 -0
  60. package/dist/src/analytics/backend.d.ts +18 -0
  61. package/dist/src/analytics/backend.d.ts.map +1 -0
  62. package/dist/src/analytics/backend.js +25 -0
  63. package/dist/src/analytics/backend.js.map +1 -0
  64. package/dist/src/analytics/clickhouse_backend.d.ts +16 -0
  65. package/dist/src/analytics/clickhouse_backend.d.ts.map +1 -0
  66. package/dist/src/analytics/clickhouse_backend.js +48 -0
  67. package/dist/src/analytics/clickhouse_backend.js.map +1 -0
  68. package/dist/src/analytics/duckdb.d.ts +39 -0
  69. package/dist/src/analytics/duckdb.d.ts.map +1 -0
  70. package/dist/src/analytics/duckdb.js +117 -0
  71. package/dist/src/analytics/duckdb.js.map +1 -0
  72. package/dist/src/analytics/lucid_backend.d.ts +16 -0
  73. package/dist/src/analytics/lucid_backend.d.ts.map +1 -0
  74. package/dist/src/analytics/lucid_backend.js +45 -0
  75. package/dist/src/analytics/lucid_backend.js.map +1 -0
  76. package/dist/src/analytics/metrics.d.ts +50 -0
  77. package/dist/src/analytics/metrics.d.ts.map +1 -0
  78. package/dist/src/analytics/metrics.js +42 -0
  79. package/dist/src/analytics/metrics.js.map +1 -0
  80. package/dist/src/analytics/results.d.ts +80 -0
  81. package/dist/src/analytics/results.d.ts.map +1 -0
  82. package/dist/src/analytics/results.js +143 -0
  83. package/dist/src/analytics/results.js.map +1 -0
  84. package/dist/src/dashboard/access_denied_page.d.ts +100 -0
  85. package/dist/src/dashboard/access_denied_page.d.ts.map +1 -0
  86. package/dist/src/dashboard/access_denied_page.js +262 -0
  87. package/dist/src/dashboard/access_denied_page.js.map +1 -0
  88. package/dist/src/dashboard/actor.d.ts +12 -0
  89. package/dist/src/dashboard/actor.d.ts.map +1 -0
  90. package/dist/src/dashboard/actor.js +33 -0
  91. package/dist/src/dashboard/actor.js.map +1 -0
  92. package/dist/src/dashboard/authorize_decision.d.ts +48 -0
  93. package/dist/src/dashboard/authorize_decision.d.ts.map +1 -0
  94. package/dist/src/dashboard/authorize_decision.js +44 -0
  95. package/dist/src/dashboard/authorize_decision.js.map +1 -0
  96. package/dist/src/dashboard/console_authorize.d.ts +77 -0
  97. package/dist/src/dashboard/console_authorize.d.ts.map +1 -0
  98. package/dist/src/dashboard/console_authorize.js +104 -0
  99. package/dist/src/dashboard/console_authorize.js.map +1 -0
  100. package/dist/src/dashboard/define_config.d.ts +71 -0
  101. package/dist/src/dashboard/define_config.d.ts.map +1 -0
  102. package/dist/src/dashboard/define_config.js +18 -0
  103. package/dist/src/dashboard/define_config.js.map +1 -0
  104. package/dist/src/dashboard/handlers.d.ts +172 -0
  105. package/dist/src/dashboard/handlers.d.ts.map +1 -0
  106. package/dist/src/dashboard/handlers.js +949 -0
  107. package/dist/src/dashboard/handlers.js.map +1 -0
  108. package/dist/src/dashboard/index.d.ts +15 -0
  109. package/dist/src/dashboard/index.d.ts.map +1 -0
  110. package/dist/src/dashboard/index.js +10 -0
  111. package/dist/src/dashboard/index.js.map +1 -0
  112. package/dist/src/dashboard/shape.d.ts +12 -0
  113. package/dist/src/dashboard/shape.d.ts.map +1 -0
  114. package/dist/src/dashboard/shape.js +232 -0
  115. package/dist/src/dashboard/shape.js.map +1 -0
  116. package/dist/src/dashboard/spa.d.ts +34 -0
  117. package/dist/src/dashboard/spa.d.ts.map +1 -0
  118. package/dist/src/dashboard/spa.js +50 -0
  119. package/dist/src/dashboard/spa.js.map +1 -0
  120. package/dist/src/declare.d.ts +85 -0
  121. package/dist/src/declare.d.ts.map +1 -0
  122. package/dist/src/declare.js +62 -0
  123. package/dist/src/declare.js.map +1 -0
  124. package/dist/src/define_config.d.ts +256 -0
  125. package/dist/src/define_config.d.ts.map +1 -0
  126. package/dist/src/define_config.js +90 -0
  127. package/dist/src/define_config.js.map +1 -0
  128. package/dist/src/durable.d.ts +29 -0
  129. package/dist/src/durable.d.ts.map +1 -0
  130. package/dist/src/durable.js +55 -0
  131. package/dist/src/durable.js.map +1 -0
  132. package/dist/src/enrichers.d.ts +51 -0
  133. package/dist/src/enrichers.d.ts.map +1 -0
  134. package/dist/src/enrichers.js +105 -0
  135. package/dist/src/enrichers.js.map +1 -0
  136. package/dist/src/events/buffer.d.ts +38 -0
  137. package/dist/src/events/buffer.d.ts.map +1 -0
  138. package/dist/src/events/buffer.js +86 -0
  139. package/dist/src/events/buffer.js.map +1 -0
  140. package/dist/src/events/event.d.ts +42 -0
  141. package/dist/src/events/event.d.ts.map +1 -0
  142. package/dist/src/events/event.js +82 -0
  143. package/dist/src/events/event.js.map +1 -0
  144. package/dist/src/http/browser.d.ts +33 -0
  145. package/dist/src/http/browser.d.ts.map +1 -0
  146. package/dist/src/http/browser.js +81 -0
  147. package/dist/src/http/browser.js.map +1 -0
  148. package/dist/src/http/browser_api.d.ts +48 -0
  149. package/dist/src/http/browser_api.d.ts.map +1 -0
  150. package/dist/src/http/browser_api.js +273 -0
  151. package/dist/src/http/browser_api.js.map +1 -0
  152. package/dist/src/http/browser_tokens.d.ts +27 -0
  153. package/dist/src/http/browser_tokens.d.ts.map +1 -0
  154. package/dist/src/http/browser_tokens.js +48 -0
  155. package/dist/src/http/browser_tokens.js.map +1 -0
  156. package/dist/src/http/control_plane.d.ts +58 -0
  157. package/dist/src/http/control_plane.d.ts.map +1 -0
  158. package/dist/src/http/control_plane.js +318 -0
  159. package/dist/src/http/control_plane.js.map +1 -0
  160. package/dist/src/http/csrf.d.ts +22 -0
  161. package/dist/src/http/csrf.d.ts.map +1 -0
  162. package/dist/src/http/csrf.js +24 -0
  163. package/dist/src/http/csrf.js.map +1 -0
  164. package/dist/src/http/edge_tag.d.ts +55 -0
  165. package/dist/src/http/edge_tag.d.ts.map +1 -0
  166. package/dist/src/http/edge_tag.js +45 -0
  167. package/dist/src/http/edge_tag.js.map +1 -0
  168. package/dist/src/http/flag_middleware.d.ts +27 -0
  169. package/dist/src/http/flag_middleware.d.ts.map +1 -0
  170. package/dist/src/http/flag_middleware.js +30 -0
  171. package/dist/src/http/flag_middleware.js.map +1 -0
  172. package/dist/src/http/flags_middleware.d.ts +20 -0
  173. package/dist/src/http/flags_middleware.d.ts.map +1 -0
  174. package/dist/src/http/flags_middleware.js +20 -0
  175. package/dist/src/http/flags_middleware.js.map +1 -0
  176. package/dist/src/http/subject_resolver.d.ts +45 -0
  177. package/dist/src/http/subject_resolver.d.ts.map +1 -0
  178. package/dist/src/http/subject_resolver.js +93 -0
  179. package/dist/src/http/subject_resolver.js.map +1 -0
  180. package/dist/src/identity.d.ts +82 -0
  181. package/dist/src/identity.d.ts.map +1 -0
  182. package/dist/src/identity.js +100 -0
  183. package/dist/src/identity.js.map +1 -0
  184. package/dist/src/index.d.ts +41 -0
  185. package/dist/src/index.d.ts.map +1 -0
  186. package/dist/src/index.js +34 -0
  187. package/dist/src/index.js.map +1 -0
  188. package/dist/src/manager.d.ts +154 -0
  189. package/dist/src/manager.d.ts.map +1 -0
  190. package/dist/src/manager.js +333 -0
  191. package/dist/src/manager.js.map +1 -0
  192. package/dist/src/openfeature/provider.d.ts +36 -0
  193. package/dist/src/openfeature/provider.d.ts.map +1 -0
  194. package/dist/src/openfeature/provider.js +82 -0
  195. package/dist/src/openfeature/provider.js.map +1 -0
  196. package/dist/src/relay/relay.d.ts +36 -0
  197. package/dist/src/relay/relay.d.ts.map +1 -0
  198. package/dist/src/relay/relay.js +73 -0
  199. package/dist/src/relay/relay.js.map +1 -0
  200. package/dist/src/relay/results_cache.d.ts +20 -0
  201. package/dist/src/relay/results_cache.d.ts.map +1 -0
  202. package/dist/src/relay/results_cache.js +31 -0
  203. package/dist/src/relay/results_cache.js.map +1 -0
  204. package/dist/src/relay/worker.d.ts +66 -0
  205. package/dist/src/relay/worker.d.ts.map +1 -0
  206. package/dist/src/relay/worker.js +177 -0
  207. package/dist/src/relay/worker.js.map +1 -0
  208. package/dist/src/ruleset_source.d.ts +73 -0
  209. package/dist/src/ruleset_source.d.ts.map +1 -0
  210. package/dist/src/ruleset_source.js +128 -0
  211. package/dist/src/ruleset_source.js.map +1 -0
  212. package/dist/src/runtime.d.ts +70 -0
  213. package/dist/src/runtime.d.ts.map +1 -0
  214. package/dist/src/runtime.js +301 -0
  215. package/dist/src/runtime.js.map +1 -0
  216. package/dist/src/schema.d.ts +39 -0
  217. package/dist/src/schema.d.ts.map +1 -0
  218. package/dist/src/schema.js +311 -0
  219. package/dist/src/schema.js.map +1 -0
  220. package/dist/src/services/accessor.d.ts +5 -0
  221. package/dist/src/services/accessor.d.ts.map +1 -0
  222. package/dist/src/services/accessor.js +20 -0
  223. package/dist/src/services/accessor.js.map +1 -0
  224. package/dist/src/sinks/clickhouse.d.ts +41 -0
  225. package/dist/src/sinks/clickhouse.d.ts.map +1 -0
  226. package/dist/src/sinks/clickhouse.js +117 -0
  227. package/dist/src/sinks/clickhouse.js.map +1 -0
  228. package/dist/src/sinks/lucid_sink.d.ts +25 -0
  229. package/dist/src/sinks/lucid_sink.d.ts.map +1 -0
  230. package/dist/src/sinks/lucid_sink.js +87 -0
  231. package/dist/src/sinks/lucid_sink.js.map +1 -0
  232. package/dist/src/sinks/parquet_sink.d.ts +41 -0
  233. package/dist/src/sinks/parquet_sink.d.ts.map +1 -0
  234. package/dist/src/sinks/parquet_sink.js +140 -0
  235. package/dist/src/sinks/parquet_sink.js.map +1 -0
  236. package/dist/src/sinks/posthog_sink.d.ts +29 -0
  237. package/dist/src/sinks/posthog_sink.d.ts.map +1 -0
  238. package/dist/src/sinks/posthog_sink.js +65 -0
  239. package/dist/src/sinks/posthog_sink.js.map +1 -0
  240. package/dist/src/sinks/sink.d.ts +36 -0
  241. package/dist/src/sinks/sink.d.ts.map +1 -0
  242. package/dist/src/sinks/sink.js +36 -0
  243. package/dist/src/sinks/sink.js.map +1 -0
  244. package/dist/src/sql.d.ts +33 -0
  245. package/dist/src/sql.d.ts.map +1 -0
  246. package/dist/src/sql.js +66 -0
  247. package/dist/src/sql.js.map +1 -0
  248. package/dist/src/stores/lucid_store.d.ts +55 -0
  249. package/dist/src/stores/lucid_store.d.ts.map +1 -0
  250. package/dist/src/stores/lucid_store.js +412 -0
  251. package/dist/src/stores/lucid_store.js.map +1 -0
  252. package/dist/src/stores/memory_store.d.ts +38 -0
  253. package/dist/src/stores/memory_store.d.ts.map +1 -0
  254. package/dist/src/stores/memory_store.js +166 -0
  255. package/dist/src/stores/memory_store.js.map +1 -0
  256. package/dist/src/stores/store.d.ts +166 -0
  257. package/dist/src/stores/store.d.ts.map +1 -0
  258. package/dist/src/stores/store.js +67 -0
  259. package/dist/src/stores/store.js.map +1 -0
  260. package/dist/src/subject.d.ts +25 -0
  261. package/dist/src/subject.d.ts.map +1 -0
  262. package/dist/src/subject.js +30 -0
  263. package/dist/src/subject.js.map +1 -0
  264. package/dist/src/testing/index.d.ts +31 -0
  265. package/dist/src/testing/index.d.ts.map +1 -0
  266. package/dist/src/testing/index.js +60 -0
  267. package/dist/src/testing/index.js.map +1 -0
  268. package/dist/src/topology/browser_token.d.ts +48 -0
  269. package/dist/src/topology/browser_token.d.ts.map +1 -0
  270. package/dist/src/topology/browser_token.js +128 -0
  271. package/dist/src/topology/browser_token.js.map +1 -0
  272. package/dist/src/topology/remote_source.d.ts +39 -0
  273. package/dist/src/topology/remote_source.d.ts.map +1 -0
  274. package/dist/src/topology/remote_source.js +184 -0
  275. package/dist/src/topology/remote_source.js.map +1 -0
  276. package/dist/src/topology/token.d.ts +36 -0
  277. package/dist/src/topology/token.d.ts.map +1 -0
  278. package/dist/src/topology/token.js +68 -0
  279. package/dist/src/topology/token.js.map +1 -0
  280. package/dist/src/topology/verify.d.ts +88 -0
  281. package/dist/src/topology/verify.d.ts.map +1 -0
  282. package/dist/src/topology/verify.js +128 -0
  283. package/dist/src/topology/verify.js.map +1 -0
  284. package/dist/src/transports/db_transport.d.ts +55 -0
  285. package/dist/src/transports/db_transport.d.ts.map +1 -0
  286. package/dist/src/transports/db_transport.js +202 -0
  287. package/dist/src/transports/db_transport.js.map +1 -0
  288. package/dist/src/transports/http_transport.d.ts +30 -0
  289. package/dist/src/transports/http_transport.d.ts.map +1 -0
  290. package/dist/src/transports/http_transport.js +51 -0
  291. package/dist/src/transports/http_transport.js.map +1 -0
  292. package/dist/src/transports/memory_transport.d.ts +29 -0
  293. package/dist/src/transports/memory_transport.d.ts.map +1 -0
  294. package/dist/src/transports/memory_transport.js +91 -0
  295. package/dist/src/transports/memory_transport.js.map +1 -0
  296. package/dist/src/transports/redis_transport.d.ts +50 -0
  297. package/dist/src/transports/redis_transport.d.ts.map +1 -0
  298. package/dist/src/transports/redis_transport.js +107 -0
  299. package/dist/src/transports/redis_transport.js.map +1 -0
  300. package/dist/src/transports/transport.d.ts +62 -0
  301. package/dist/src/transports/transport.d.ts.map +1 -0
  302. package/dist/src/transports/transport.js +2 -0
  303. package/dist/src/transports/transport.js.map +1 -0
  304. package/dist/src/types.d.ts +30 -0
  305. package/dist/src/types.d.ts.map +1 -0
  306. package/dist/src/types.js +2 -0
  307. package/dist/src/types.js.map +1 -0
  308. package/dist/src/usage.d.ts +18 -0
  309. package/dist/src/usage.d.ts.map +1 -0
  310. package/dist/src/usage.js +52 -0
  311. package/dist/src/usage.js.map +1 -0
  312. package/dist/stubs/config/flags.stub +50 -0
  313. package/dist/stubs/config/flags_dashboard.stub +35 -0
  314. package/dist/stubs/database/migrations/create_flags_tables.stub +27 -0
  315. package/dist/stubs/main.d.ts +3 -0
  316. package/dist/stubs/main.d.ts.map +1 -0
  317. package/dist/stubs/main.js +9 -0
  318. package/dist/stubs/main.js.map +1 -0
  319. package/package.json +181 -0
  320. package/skills/flags-basics/SKILL.md +142 -0
  321. package/skills/flags-deployment/SKILL.md +125 -0
  322. package/skills/flags-experiments/SKILL.md +99 -0
@@ -0,0 +1,41 @@
1
+ import { type DuckDbOptions } from '../analytics/duckdb.js';
2
+ import type { FlagEvent } from '../events/event.js';
3
+ import type { Sink } from './sink.js';
4
+ export interface ParquetSinkOptions extends DuckDbOptions {
5
+ /**
6
+ * Where the files go: a local directory (`storage/flags`) or an object-store prefix DuckDB can
7
+ * write (`s3://bucket/flags`, with credentials in `duckdb.setup`). Files are laid out as
8
+ * `type=…/day=YYYY-MM-DD/<uuid>.parquet`.
9
+ */
10
+ path: string;
11
+ /**
12
+ * Events per file. Parquet wants big files: the default 50,000 keeps file counts sane. The relay
13
+ * hands this sink batches of this size.
14
+ */
15
+ batchSize?: number;
16
+ /** Delivery interval (ms). Default 60000 — let batches fill. */
17
+ intervalMs?: number;
18
+ }
19
+ /**
20
+ * Writes events as Parquet through DuckDB. Cheap, long retention with no server: the `duckdb`
21
+ * analytics backend reads the same files. `@duckdb/node-api` is an optional peer with a native
22
+ * binary; run the relay for this sink in a worker, not in web processes.
23
+ *
24
+ * Erasure rewrites the affected local files without the subject's rows (`forget`). For object
25
+ * stores, rewrite them with your own tooling.
26
+ */
27
+ export declare class ParquetSink implements Sink {
28
+ #private;
29
+ private readonly options;
30
+ readonly kind = "parquet";
31
+ constructor(options: ParquetSinkOptions);
32
+ get batchSize(): number;
33
+ get intervalMs(): number;
34
+ setup(): Promise<void>;
35
+ write(events: FlagEvent[]): Promise<void>;
36
+ forget(subject: string): Promise<void>;
37
+ close(): Promise<void>;
38
+ }
39
+ /** A SQL literal for DuckDB. */
40
+ export declare function literal(value: unknown): string;
41
+ //# sourceMappingURL=parquet_sink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parquet_sink.d.ts","sourceRoot":"","sources":["../../../src/sinks/parquet_sink.ts"],"names":[],"mappings":"AAGA,OAAO,EAAU,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,qBAAa,WAAY,YAAW,IAAI;;IAI1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,QAAQ,CAAC,IAAI,aAAa;IAG1B,YAA6B,OAAO,EAAE,kBAAkB,EAEvD;IAED,IAAI,SAAS,WAEZ;IAED,IAAI,UAAU,WAEb;IAMK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAEK,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0D9C;IAEK,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB3C;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;CACF;AAkBD,gCAAgC;AAChC,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAM9C"}
@@ -0,0 +1,140 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdir, readdir, rm } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { DuckDb } from '../analytics/duckdb.js';
5
+ /**
6
+ * Writes events as Parquet through DuckDB. Cheap, long retention with no server: the `duckdb`
7
+ * analytics backend reads the same files. `@duckdb/node-api` is an optional peer with a native
8
+ * binary; run the relay for this sink in a worker, not in web processes.
9
+ *
10
+ * Erasure rewrites the affected local files without the subject's rows (`forget`). For object
11
+ * stores, rewrite them with your own tooling.
12
+ */
13
+ export class ParquetSink {
14
+ options;
15
+ kind = 'parquet';
16
+ #duck;
17
+ constructor(options) {
18
+ this.options = options;
19
+ this.#duck = new DuckDb(options);
20
+ }
21
+ get batchSize() {
22
+ return this.options.batchSize ?? 50_000;
23
+ }
24
+ get intervalMs() {
25
+ return this.options.intervalMs ?? 60_000;
26
+ }
27
+ get #local() {
28
+ return !/^[a-z0-9]+:\/\//i.test(this.options.path);
29
+ }
30
+ async setup() {
31
+ if (this.#local)
32
+ await mkdir(this.options.path, { recursive: true });
33
+ }
34
+ async write(events) {
35
+ if (events.length === 0)
36
+ return;
37
+ const rows = events.map((e) => ({
38
+ event_id: e.id,
39
+ schema_version: e.schemaVersion,
40
+ app: e.app,
41
+ environment: e.environment,
42
+ type: e.type,
43
+ flag: e.flag ?? null,
44
+ experiment: e.experiment ?? null,
45
+ variant: e.variant ?? null,
46
+ name: e.name ?? null,
47
+ subject: e.subject,
48
+ subject_type: e.subjectType,
49
+ value: e.value ?? null,
50
+ props: JSON.stringify(e.props ?? {}),
51
+ ts: e.ts,
52
+ day: new Date(e.ts).toISOString().slice(0, 10),
53
+ }));
54
+ const staging = `staging_${randomUUID().replaceAll('-', '')}`;
55
+ await this.#duck.withConnection(async (sql) => {
56
+ await sql(`CREATE TEMP TABLE ${staging} (
57
+ event_id VARCHAR, schema_version INTEGER, app VARCHAR, environment VARCHAR, type VARCHAR, flag VARCHAR,
58
+ experiment VARCHAR, variant VARCHAR, name VARCHAR, subject VARCHAR, subject_type VARCHAR,
59
+ value DOUBLE, props VARCHAR, ts BIGINT, day VARCHAR)`);
60
+ for (let i = 0; i < rows.length; i += 1000) {
61
+ const chunk = rows.slice(i, i + 1000);
62
+ const values = chunk
63
+ .map((r) => `(${[
64
+ r.event_id,
65
+ r.schema_version,
66
+ r.app,
67
+ r.environment,
68
+ r.type,
69
+ r.flag,
70
+ r.experiment,
71
+ r.variant,
72
+ r.name,
73
+ r.subject,
74
+ r.subject_type,
75
+ r.value,
76
+ r.props,
77
+ r.ts,
78
+ r.day,
79
+ ]
80
+ .map(literal)
81
+ .join(', ')})`)
82
+ .join(', ');
83
+ await sql(`INSERT INTO ${staging} VALUES ${values}`);
84
+ }
85
+ await sql(`COPY ${staging} TO ${literal(this.options.path)} (FORMAT PARQUET, PARTITION_BY (type, day), FILENAME_PATTERN 'part_{uuid}', APPEND)`);
86
+ await sql(`DROP TABLE ${staging}`);
87
+ });
88
+ }
89
+ async forget(subject) {
90
+ if (!this.#local) {
91
+ throw new Error('ParquetSink.forget only rewrites local files; rewrite object-store files with your own tooling');
92
+ }
93
+ for (const file of await listParquet(this.options.path)) {
94
+ await this.#duck.withConnection(async (sql, select) => {
95
+ const matches = await select(`SELECT COUNT(*) AS n FROM read_parquet(${literal(file)}) WHERE subject = ${literal(subject)}`);
96
+ if (Number(matches[0]?.n ?? 0) === 0)
97
+ return;
98
+ const rewritten = `${file}.rewrite`;
99
+ await sql(`COPY (SELECT * FROM read_parquet(${literal(file)}) WHERE subject <> ${literal(subject)}) TO ${literal(rewritten)} (FORMAT PARQUET)`);
100
+ await rm(file);
101
+ const { rename } = await import('node:fs/promises');
102
+ await rename(rewritten, file);
103
+ });
104
+ }
105
+ }
106
+ async close() {
107
+ await this.#duck.close();
108
+ }
109
+ }
110
+ async function listParquet(dir) {
111
+ const out = [];
112
+ let entries;
113
+ try {
114
+ entries = await readdir(dir, { withFileTypes: true });
115
+ }
116
+ catch {
117
+ return out;
118
+ }
119
+ for (const entry of entries) {
120
+ const full = join(dir, entry.name);
121
+ if (entry.isDirectory())
122
+ out.push(...(await listParquet(full)));
123
+ else if (entry.name.endsWith('.parquet'))
124
+ out.push(full);
125
+ }
126
+ return out;
127
+ }
128
+ /** A SQL literal for DuckDB. */
129
+ export function literal(value) {
130
+ if (value === null || value === undefined)
131
+ return 'NULL';
132
+ if (typeof value === 'number')
133
+ return Number.isFinite(value) ? String(value) : 'NULL';
134
+ if (typeof value === 'bigint')
135
+ return value.toString();
136
+ if (typeof value === 'boolean')
137
+ return value ? 'TRUE' : 'FALSE';
138
+ return `'${String(value).replaceAll("'", "''")}'`;
139
+ }
140
+ //# sourceMappingURL=parquet_sink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parquet_sink.js","sourceRoot":"","sources":["../../../src/sinks/parquet_sink.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAsB,MAAM,wBAAwB,CAAC;AAoBpE;;;;;;;GAOG;AACH,MAAM,OAAO,WAAW;IAIO,OAAO;IAH3B,IAAI,GAAG,SAAS,CAAC;IACjB,KAAK,CAAS;IAEvB,YAA6B,OAA2B;uBAA3B,OAAO;QAClC,IAAI,CAAC,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;IAC1C,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC;IAC3C,CAAC;IAED,IAAI,MAAM;QACR,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAmB;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAChC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9B,QAAQ,EAAE,CAAC,CAAC,EAAE;YACd,cAAc,EAAE,CAAC,CAAC,aAAa;YAC/B,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI;YACpB,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,IAAI;YAChC,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,IAAI;YAC1B,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI;YACpB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,YAAY,EAAE,CAAC,CAAC,WAAW;YAC3B,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI;YACtB,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACpC,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,GAAG,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;SAC/C,CAAC,CAAC,CAAC;QACJ,MAAM,OAAO,GAAG,WAAW,UAAU,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAC5C,MAAM,GAAG,CAAC,qBAAqB,OAAO;;;6DAGiB,CAAC,CAAC;YACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;gBACtC,MAAM,MAAM,GAAG,KAAK;qBACjB,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CACJ,IAAI;oBACF,CAAC,CAAC,QAAQ;oBACV,CAAC,CAAC,cAAc;oBAChB,CAAC,CAAC,GAAG;oBACL,CAAC,CAAC,WAAW;oBACb,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,UAAU;oBACZ,CAAC,CAAC,OAAO;oBACT,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,OAAO;oBACT,CAAC,CAAC,YAAY;oBACd,CAAC,CAAC,KAAK;oBACP,CAAC,CAAC,KAAK;oBACP,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC,GAAG;iBACN;qBACE,GAAG,CAAC,OAAO,CAAC;qBACZ,IAAI,CAAC,IAAI,CAAC,GAAG,CACnB;qBACA,IAAI,CAAC,IAAI,CAAC,CAAC;gBACd,MAAM,GAAG,CAAC,eAAe,OAAO,WAAW,MAAM,EAAE,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,GAAG,CACP,QAAQ,OAAO,OAAO,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,qFAAqF,CACtI,CAAC;YACF,MAAM,GAAG,CAAC,cAAc,OAAO,EAAE,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QAC1B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,gGAAgG,CACjG,CAAC;QACJ,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,MAAM,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACxD,MAAM,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;gBACpD,MAAM,OAAO,GAAG,MAAM,MAAM,CAC1B,0CAA0C,OAAO,CAAC,IAAI,CAAC,qBAAqB,OAAO,CAAC,OAAO,CAAC,EAAE,CAC/F,CAAC;gBACF,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;oBAAE,OAAO;gBAC7C,MAAM,SAAS,GAAG,GAAG,IAAI,UAAU,CAAC;gBACpC,MAAM,GAAG,CACP,oCAAoC,OAAO,CAAC,IAAI,CAAC,sBAAsB,OAAO,CAAC,OAAO,CAAC,QAAQ,OAAO,CAAC,SAAS,CAAC,mBAAmB,CACrI,CAAC;gBACF,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;gBACf,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;gBACpD,MAAM,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAChC,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;CACF;AAED,KAAK,UAAU,WAAW,CAAC,GAAW;IACpC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,OAAwD,CAAC;IAC7D,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,KAAK,CAAC,WAAW,EAAE;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;aAC3D,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACzD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACtF,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;IACvD,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAChE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;AACpD,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { FlagEvent } from '../events/event.js';
2
+ import type { Sink } from './sink.js';
3
+ export interface PostHogSinkOptions {
4
+ /** Project API key (the public `phc_…` key). */
5
+ apiKey: string;
6
+ /** Default `https://us.i.posthog.com`. */
7
+ host?: string;
8
+ batchSize?: number;
9
+ intervalMs?: number;
10
+ fetch?: typeof fetch;
11
+ }
12
+ /**
13
+ * Sends exposures as PostHog's `$feature_flag_called` events (so PostHog's experiment tooling
14
+ * recognises them) and tracks as regular events, through the `/batch/` endpoint. Every event
15
+ * carries its id as `uuid`, which PostHog uses to dedupe re-sends.
16
+ *
17
+ * Erasure (`forget`) is not implemented here: deleting a person in PostHog goes through its
18
+ * private API with a personal key. Do it there.
19
+ */
20
+ export declare class PostHogSink implements Sink {
21
+ #private;
22
+ private readonly options;
23
+ readonly kind = "posthog";
24
+ constructor(options: PostHogSinkOptions);
25
+ get batchSize(): number;
26
+ get intervalMs(): number | undefined;
27
+ write(events: FlagEvent[]): Promise<void>;
28
+ }
29
+ //# sourceMappingURL=posthog_sink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posthog_sink.d.ts","sourceRoot":"","sources":["../../../src/sinks/posthog_sink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,qBAAa,WAAY,YAAW,IAAI;;IAI1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,QAAQ,CAAC,IAAI,aAAa;IAG1B,YAA6B,OAAO,EAAE,kBAAkB,EAEvD;IAED,IAAI,SAAS,WAEZ;IAED,IAAI,UAAU,uBAEb;IAEK,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyC9C;CACF"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Sends exposures as PostHog's `$feature_flag_called` events (so PostHog's experiment tooling
3
+ * recognises them) and tracks as regular events, through the `/batch/` endpoint. Every event
4
+ * carries its id as `uuid`, which PostHog uses to dedupe re-sends.
5
+ *
6
+ * Erasure (`forget`) is not implemented here: deleting a person in PostHog goes through its
7
+ * private API with a personal key. Do it there.
8
+ */
9
+ export class PostHogSink {
10
+ options;
11
+ kind = 'posthog';
12
+ #fetch;
13
+ constructor(options) {
14
+ this.options = options;
15
+ this.#fetch = options.fetch ?? fetch;
16
+ }
17
+ get batchSize() {
18
+ return this.options.batchSize ?? 500;
19
+ }
20
+ get intervalMs() {
21
+ return this.options.intervalMs;
22
+ }
23
+ async write(events) {
24
+ if (events.length === 0)
25
+ return;
26
+ const batch = events.map((e) => e.type === 'exposure'
27
+ ? {
28
+ event: '$feature_flag_called',
29
+ distinct_id: e.subject,
30
+ uuid: e.id,
31
+ timestamp: new Date(e.ts).toISOString(),
32
+ properties: {
33
+ $feature_flag: e.flag ?? e.experiment,
34
+ $feature_flag_response: e.variant,
35
+ experiment: e.experiment,
36
+ app: e.app,
37
+ environment: e.environment,
38
+ subject_type: e.subjectType,
39
+ ...e.props,
40
+ },
41
+ }
42
+ : {
43
+ event: e.name,
44
+ distinct_id: e.subject,
45
+ uuid: e.id,
46
+ timestamp: new Date(e.ts).toISOString(),
47
+ properties: {
48
+ ...(e.value !== undefined ? { value: e.value } : {}),
49
+ app: e.app,
50
+ environment: e.environment,
51
+ subject_type: e.subjectType,
52
+ ...e.props,
53
+ },
54
+ });
55
+ const host = (this.options.host ?? 'https://us.i.posthog.com').replace(/\/$/, '');
56
+ const response = await this.#fetch(`${host}/batch/`, {
57
+ method: 'POST',
58
+ headers: { 'content-type': 'application/json' },
59
+ body: JSON.stringify({ api_key: this.options.apiKey, historical_migration: false, batch }),
60
+ });
61
+ if (!response.ok)
62
+ throw new Error(`PostHog answered ${response.status}: ${await response.text()}`);
63
+ }
64
+ }
65
+ //# sourceMappingURL=posthog_sink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posthog_sink.js","sourceRoot":"","sources":["../../../src/sinks/posthog_sink.ts"],"names":[],"mappings":"AAaA;;;;;;;GAOG;AACH,MAAM,OAAO,WAAW;IAIO,OAAO;IAH3B,IAAI,GAAG,SAAS,CAAC;IACjB,MAAM,CAAe;IAE9B,YAA6B,OAA2B;uBAA3B,OAAO;QAClC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;IACvC,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,GAAG,CAAC;IACvC,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAmB;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAChC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC7B,CAAC,CAAC,IAAI,KAAK,UAAU;YACnB,CAAC,CAAC;gBACE,KAAK,EAAE,sBAAsB;gBAC7B,WAAW,EAAE,CAAC,CAAC,OAAO;gBACtB,IAAI,EAAE,CAAC,CAAC,EAAE;gBACV,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE;gBACvC,UAAU,EAAE;oBACV,aAAa,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,UAAU;oBACrC,sBAAsB,EAAE,CAAC,CAAC,OAAO;oBACjC,UAAU,EAAE,CAAC,CAAC,UAAU;oBACxB,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,WAAW,EAAE,CAAC,CAAC,WAAW;oBAC1B,YAAY,EAAE,CAAC,CAAC,WAAW;oBAC3B,GAAG,CAAC,CAAC,KAAK;iBACX;aACF;YACH,CAAC,CAAC;gBACE,KAAK,EAAE,CAAC,CAAC,IAAI;gBACb,WAAW,EAAE,CAAC,CAAC,OAAO;gBACtB,IAAI,EAAE,CAAC,CAAC,EAAE;gBACV,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE;gBACvC,UAAU,EAAE;oBACV,GAAG,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACpD,GAAG,EAAE,CAAC,CAAC,GAAG;oBACV,WAAW,EAAE,CAAC,CAAC,WAAW;oBAC1B,YAAY,EAAE,CAAC,CAAC,WAAW;oBAC3B,GAAG,CAAC,CAAC,KAAK;iBACX;aACF,CACN,CAAC;QACF,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,0BAA0B,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAClF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,SAAS,EAAE;YACnD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;SAC3F,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE;YACd,MAAM,IAAI,KAAK,CAAC,oBAAoB,QAAQ,CAAC,MAAM,KAAK,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACrF,CAAC;CACF"}
@@ -0,0 +1,36 @@
1
+ import type { FlagEvent } from '../events/event.js';
2
+ /**
3
+ * A destination for events. The relay hands each sink batches from its own cursor; a sink must be
4
+ * idempotent by `event.id`, because delivery is at-least-once.
5
+ */
6
+ export interface Sink {
7
+ /** Kind, for logs (`lucid`, `posthog`, …). The sink's name is its key in the config. */
8
+ readonly kind: string;
9
+ /** Per-sink batch size. Default: the relay's. */
10
+ readonly batchSize?: number | undefined;
11
+ /** Per-sink delivery interval in ms. Default: the relay's. */
12
+ readonly intervalMs?: number | undefined;
13
+ setup?(): Promise<void>;
14
+ write(events: FlagEvent[]): Promise<void>;
15
+ /** Deletes everything stored about a subject (right to erasure). */
16
+ forget?(subject: string): Promise<void>;
17
+ close?(): Promise<void>;
18
+ }
19
+ /** Keeps events in memory. For tests. */
20
+ export declare class MemorySink implements Sink {
21
+ #private;
22
+ readonly kind = "memory";
23
+ readonly events: FlagEvent[];
24
+ write(events: FlagEvent[]): Promise<void>;
25
+ forget(subject: string): Promise<void>;
26
+ }
27
+ /** Hands batches to your function (a queue, a webhook, another warehouse). */
28
+ export declare class CallbackSink implements Sink {
29
+ private readonly callback;
30
+ readonly batchSize?: number | undefined;
31
+ readonly intervalMs?: number | undefined;
32
+ readonly kind = "callback";
33
+ constructor(callback: (events: FlagEvent[]) => Promise<void>, batchSize?: number | undefined, intervalMs?: number | undefined);
34
+ write(events: FlagEvent[]): Promise<void>;
35
+ }
36
+ //# sourceMappingURL=sink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../../../src/sinks/sink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;GAGG;AACH,MAAM,WAAW,IAAI;IACnB,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,oEAAoE;IACpE,MAAM,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAED,yCAAyC;AACzC,qBAAa,UAAW,YAAW,IAAI;;IACrC,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,CAAM;IAG5B,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9C;IAEK,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3C;CACF;AAED,8EAA8E;AAC9E,qBAAa,YAAa,YAAW,IAAI;IAGrC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM;IAJ9B,QAAQ,CAAC,IAAI,cAAc;IAC3B,YACmB,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,EACxD,SAAS,CAAC,EAAE,MAAM,YAAA,EAClB,UAAU,CAAC,EAAE,MAAM,YAAA,EAC1B;IAEJ,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAExC;CACF"}
@@ -0,0 +1,36 @@
1
+ /** Keeps events in memory. For tests. */
2
+ export class MemorySink {
3
+ kind = 'memory';
4
+ events = [];
5
+ #seen = new Set();
6
+ async write(events) {
7
+ for (const event of events) {
8
+ if (this.#seen.has(event.id))
9
+ continue;
10
+ this.#seen.add(event.id);
11
+ this.events.push(event);
12
+ }
13
+ }
14
+ async forget(subject) {
15
+ for (let i = this.events.length - 1; i >= 0; i--) {
16
+ if (this.events[i].subject === subject)
17
+ this.events.splice(i, 1);
18
+ }
19
+ }
20
+ }
21
+ /** Hands batches to your function (a queue, a webhook, another warehouse). */
22
+ export class CallbackSink {
23
+ callback;
24
+ batchSize;
25
+ intervalMs;
26
+ kind = 'callback';
27
+ constructor(callback, batchSize, intervalMs) {
28
+ this.callback = callback;
29
+ this.batchSize = batchSize;
30
+ this.intervalMs = intervalMs;
31
+ }
32
+ write(events) {
33
+ return this.callback(events);
34
+ }
35
+ }
36
+ //# sourceMappingURL=sink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sink.js","sourceRoot":"","sources":["../../../src/sinks/sink.ts"],"names":[],"mappings":"AAoBA,yCAAyC;AACzC,MAAM,OAAO,UAAU;IACZ,IAAI,GAAG,QAAQ,CAAC;IAChB,MAAM,GAAgB,EAAE,CAAC;IACzB,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAEnC,KAAK,CAAC,KAAK,CAAC,MAAmB;QAC7B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBAAE,SAAS;YACvC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAe;QAC1B,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACjD,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,OAAO,KAAK,OAAO;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;CACF;AAED,8EAA8E;AAC9E,MAAM,OAAO,YAAY;IAGJ,QAAQ;IAChB,SAAS;IACT,UAAU;IAJZ,IAAI,GAAG,UAAU,CAAC;IAC3B,YACmB,QAAgD,EACxD,SAAkB,EAClB,UAAmB;wBAFX,QAAQ;yBAChB,SAAS;0BACT,UAAU;IAClB,CAAC;IAEJ,KAAK,CAAC,MAAmB;QACvB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The slice of Lucid this package needs: raw SQL and transactions. Typed structurally so the
3
+ * package does not import `@adonisjs/lucid` at module load (it is an optional peer), and so a
4
+ * `Database`, a `QueryClient` or a `TransactionClient` all fit.
5
+ */
6
+ export interface SqlClient {
7
+ rawQuery(sql: string, bindings?: readonly unknown[]): PromiseLike<unknown>;
8
+ dialect?: {
9
+ name?: string;
10
+ };
11
+ }
12
+ export interface SqlDatabase extends SqlClient {
13
+ transaction<T>(callback: (trx: SqlClient) => Promise<T>): Promise<T>;
14
+ }
15
+ export type Dialect = 'postgres' | 'mysql' | 'sqlite';
16
+ export declare function dialectOf(client: SqlClient): Dialect;
17
+ /** Normalizes `rawQuery` results across drivers into an array of row objects. */
18
+ export declare function rowsOf<T = Record<string, unknown>>(result: unknown): T[];
19
+ export declare function query<T = Record<string, unknown>>(client: SqlClient, sql: string, bindings?: readonly unknown[]): Promise<T[]>;
20
+ /** JSON column values come back parsed on Postgres/MySQL and as text on SQLite. */
21
+ export declare function parseJson<T>(value: unknown): T;
22
+ /** Bindings for JSON columns: always a string, which every driver accepts. */
23
+ export declare function jsonValue(value: unknown): string | null;
24
+ /** Numbers come back as strings for BIGINT on pg/mysql. */
25
+ export declare function toNumber(value: unknown): number;
26
+ /**
27
+ * Every timestamp this package stores is a BIGINT of epoch milliseconds: no time zone handling,
28
+ * identical in every dialect and in the analytics backends.
29
+ */
30
+ export declare function toDate(value: unknown): Date;
31
+ /** `INSERT … ON CONFLICT DO NOTHING` in each dialect. */
32
+ export declare function insertIgnore(dialect: Dialect, table: string, columns: string[], rows: number): string;
33
+ //# sourceMappingURL=sql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IAC3E,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7B;AAED,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACtE;AAED,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEtD,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAMpD;AAED,iFAAiF;AACjF,wBAAgB,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,CAAC,EAAE,CAYxE;AAED,wBAAsB,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrD,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,SAAS,OAAO,EAAO,GAChC,OAAO,CAAC,CAAC,EAAE,CAAC,CAEd;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,CAG9C;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAEvD;AAED,2DAA2D;AAC3D,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAK/C;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAG3C;AAED,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,UAM5F"}
@@ -0,0 +1,66 @@
1
+ export function dialectOf(client) {
2
+ const name = client.dialect?.name ?? '';
3
+ if (/postgres|pg|redshift/i.test(name))
4
+ return 'postgres';
5
+ if (/mysql|mariadb/i.test(name))
6
+ return 'mysql';
7
+ if (/sqlite/i.test(name))
8
+ return 'sqlite';
9
+ throw new Error(`@adonis-agora/flags: unsupported database dialect "${name}"`);
10
+ }
11
+ /** Normalizes `rawQuery` results across drivers into an array of row objects. */
12
+ export function rowsOf(result) {
13
+ if (Array.isArray(result)) {
14
+ // mysql2: [rows, fields]; better-sqlite3 through knex: rows.
15
+ if (result.length === 2 && Array.isArray(result[0]) && Array.isArray(result[1])) {
16
+ return result[0];
17
+ }
18
+ return result;
19
+ }
20
+ if (result && typeof result === 'object' && 'rows' in result) {
21
+ return result.rows;
22
+ }
23
+ return [];
24
+ }
25
+ export async function query(client, sql, bindings = []) {
26
+ return rowsOf(await client.rawQuery(sql, bindings));
27
+ }
28
+ /** JSON column values come back parsed on Postgres/MySQL and as text on SQLite. */
29
+ export function parseJson(value) {
30
+ if (typeof value === 'string')
31
+ return JSON.parse(value);
32
+ return value;
33
+ }
34
+ /** Bindings for JSON columns: always a string, which every driver accepts. */
35
+ export function jsonValue(value) {
36
+ return value === undefined || value === null ? null : JSON.stringify(value);
37
+ }
38
+ /** Numbers come back as strings for BIGINT on pg/mysql. */
39
+ export function toNumber(value) {
40
+ if (typeof value === 'number')
41
+ return value;
42
+ if (typeof value === 'bigint')
43
+ return Number(value);
44
+ if (typeof value === 'string')
45
+ return Number(value);
46
+ return 0;
47
+ }
48
+ /**
49
+ * Every timestamp this package stores is a BIGINT of epoch milliseconds: no time zone handling,
50
+ * identical in every dialect and in the analytics backends.
51
+ */
52
+ export function toDate(value) {
53
+ if (value instanceof Date)
54
+ return value;
55
+ return new Date(toNumber(value));
56
+ }
57
+ /** `INSERT … ON CONFLICT DO NOTHING` in each dialect. */
58
+ export function insertIgnore(dialect, table, columns, rows) {
59
+ const placeholders = `(${columns.map(() => '?').join(', ')})`;
60
+ const values = Array.from({ length: rows }, () => placeholders).join(', ');
61
+ const cols = columns.join(', ');
62
+ if (dialect === 'mysql')
63
+ return `INSERT IGNORE INTO ${table} (${cols}) VALUES ${values}`;
64
+ return `INSERT INTO ${table} (${cols}) VALUES ${values} ON CONFLICT DO NOTHING`;
65
+ }
66
+ //# sourceMappingURL=sql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.js","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { type Ruleset } from '@adonis-agora/flags-core';
2
+ import type { FlagDeclaration } from '../declare.js';
3
+ import { type SchemaOptions } from '../schema.js';
4
+ import { type Dialect, type SqlDatabase } from '../sql.js';
5
+ import { type Actor, type AuditEntry, type ChangeRequest, type DeclarationRow, type FlagsStore, type RulesetChange, type ScheduledChange, type UsageRow } from './store.js';
6
+ /** Postgres channel notified on every ruleset change (payload: `environment:version`). */
7
+ export declare const RULESET_CHANNEL = "adonis_agora_flags";
8
+ /**
9
+ * The ruleset in your database, through Lucid. Works on Postgres, MySQL and SQLite. Every write
10
+ * runs in one transaction that also bumps the environment version and writes the audit row, and on
11
+ * Postgres sends `NOTIFY` so other replicas reload immediately instead of at the next poll.
12
+ */
13
+ export declare class LucidStore implements FlagsStore {
14
+ #private;
15
+ readonly db: SqlDatabase;
16
+ private readonly options;
17
+ readonly dialect: Dialect;
18
+ constructor(db: SqlDatabase, options?: SchemaOptions & {
19
+ autoCreateSchema?: boolean;
20
+ });
21
+ setup(): Promise<void>;
22
+ /**
23
+ * Postgres `LISTEN` on {@link RULESET_CHANNEL}: holds one connection from the pool for the life of
24
+ * the process. Other dialects have no notifications; the source falls back to polling.
25
+ */
26
+ listen(onMessage: (payload: string) => void): Promise<() => Promise<void>>;
27
+ readRuleset(environment: string): Promise<Ruleset>;
28
+ version(environment: string): Promise<string>;
29
+ apply(environment: string, change: RulesetChange, actor: Actor, options?: {
30
+ changeRequestId?: string;
31
+ }): Promise<{
32
+ version: string;
33
+ }>;
34
+ environments(): Promise<string[]>;
35
+ audit(q: Parameters<FlagsStore['audit']>[0]): Promise<AuditEntry[]>;
36
+ createChangeRequest(request: Omit<ChangeRequest, 'id' | 'status' | 'requestedAt'>): Promise<ChangeRequest>;
37
+ getChangeRequest(id: string): Promise<ChangeRequest | null>;
38
+ listChangeRequests(q: Parameters<FlagsStore['listChangeRequests']>[0]): Promise<ChangeRequest[]>;
39
+ updateChangeRequest(id: string, patch: Parameters<FlagsStore['updateChangeRequest']>[1]): Promise<ChangeRequest>;
40
+ createSchedule(schedule: Omit<ScheduledChange, 'id' | 'status'>): Promise<ScheduledChange>;
41
+ getSchedule(id: string): Promise<ScheduledChange | null>;
42
+ /** Whether this store can push change notifications (Postgres `LISTEN/NOTIFY`). */
43
+ get canListen(): boolean;
44
+ listSchedules(q: Parameters<FlagsStore['listSchedules']>[0]): Promise<ScheduledChange[]>;
45
+ updateSchedule(id: string, patch: Parameters<FlagsStore['updateSchedule']>[1]): Promise<ScheduledChange>;
46
+ claimSchedule(id: string): Promise<boolean>;
47
+ recordUsage(rows: UsageRow[]): Promise<void>;
48
+ usage(q: {
49
+ environment: string;
50
+ since: string;
51
+ }): Promise<UsageRow[]>;
52
+ saveDeclarations(app: string, declarations: Record<string, FlagDeclaration>): Promise<void>;
53
+ declarations(app?: string): Promise<DeclarationRow[]>;
54
+ }
55
+ //# sourceMappingURL=lucid_store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lucid_store.d.ts","sourceRoot":"","sources":["../../../src/stores/lucid_store.ts"],"names":[],"mappings":"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"}