@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,412 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { RULESET_SCHEMA_VERSION, } from '@adonis-agora/flags-core';
3
+ import { createFlagsTables } from '../schema.js';
4
+ import { dialectOf, insertIgnore, jsonValue, parseJson, query, toDate, toNumber, } from '../sql.js';
5
+ import { applyChange, auditAction, currentValue, } from './store.js';
6
+ /** Postgres channel notified on every ruleset change (payload: `environment:version`). */
7
+ export const RULESET_CHANNEL = 'adonis_agora_flags';
8
+ const HOLDOUT_KEY = '__holdout__';
9
+ /**
10
+ * The ruleset in your database, through Lucid. Works on Postgres, MySQL and SQLite. Every write
11
+ * runs in one transaction that also bumps the environment version and writes the audit row, and on
12
+ * Postgres sends `NOTIFY` so other replicas reload immediately instead of at the next poll.
13
+ */
14
+ export class LucidStore {
15
+ db;
16
+ options;
17
+ dialect;
18
+ constructor(db, options = {}) {
19
+ this.db = db;
20
+ this.options = options;
21
+ this.dialect = dialectOf(db);
22
+ }
23
+ async setup() {
24
+ if (this.options.autoCreateSchema === false)
25
+ return;
26
+ await createFlagsTables(this.db, this.options);
27
+ }
28
+ /**
29
+ * Postgres `LISTEN` on {@link RULESET_CHANNEL}: holds one connection from the pool for the life of
30
+ * the process. Other dialects have no notifications; the source falls back to polling.
31
+ */
32
+ async listen(onMessage) {
33
+ if (this.dialect !== 'postgres')
34
+ throw new Error('notifications need Postgres');
35
+ // A QueryClient exposes getWriteClient(); a Database exposes connection() returning one.
36
+ const holder = this.db;
37
+ const knex = typeof holder.getWriteClient === 'function'
38
+ ? holder.getWriteClient()
39
+ : typeof holder.connection === 'function'
40
+ ? holder.connection().getWriteClient()
41
+ : undefined;
42
+ if (!knex)
43
+ throw new Error('cannot reach the underlying knex client to LISTEN');
44
+ const connection = (await knex.client.acquireConnection());
45
+ const handler = (message) => {
46
+ if (message.channel === RULESET_CHANNEL)
47
+ onMessage(message.payload ?? '');
48
+ };
49
+ connection.on('notification', handler);
50
+ await connection.query(`LISTEN ${RULESET_CHANNEL}`);
51
+ return async () => {
52
+ connection.removeListener('notification', handler);
53
+ try {
54
+ await connection.query(`UNLISTEN ${RULESET_CHANNEL}`);
55
+ }
56
+ finally {
57
+ await knex.client.releaseConnection(connection);
58
+ }
59
+ };
60
+ }
61
+ async readRuleset(environment) {
62
+ // One snapshot: the version and the entities must come from the same moment.
63
+ return this.db.transaction(async (trx) => {
64
+ const version = await this.#version(trx, environment);
65
+ const rows = await query(trx, 'SELECT entity, entity_key, definition FROM flags_entities WHERE environment = ?', [environment]);
66
+ const ruleset = {
67
+ schemaVersion: RULESET_SCHEMA_VERSION,
68
+ version,
69
+ flags: {},
70
+ segments: {},
71
+ layers: {},
72
+ };
73
+ for (const row of rows) {
74
+ const definition = parseJson(row.definition);
75
+ if (row.entity === 'flag')
76
+ ruleset.flags[row.entity_key] = definition;
77
+ else if (row.entity === 'segment')
78
+ ruleset.segments[row.entity_key] = definition;
79
+ else if (row.entity === 'layer')
80
+ ruleset.layers[row.entity_key] = definition;
81
+ else if (row.entity === 'holdout')
82
+ ruleset.holdout = definition;
83
+ }
84
+ return ruleset;
85
+ });
86
+ }
87
+ async version(environment) {
88
+ return this.#version(this.db, environment);
89
+ }
90
+ async #version(client, environment) {
91
+ const rows = await query(client, 'SELECT version FROM flags_environments WHERE name = ?', [environment]);
92
+ return String(toNumber(rows[0]?.version ?? 0));
93
+ }
94
+ async apply(environment, change, actor, options = {}) {
95
+ const result = await this.db.transaction(async (trx) => {
96
+ const now = Date.now();
97
+ await this.#ensureEnvironment(trx, environment, now);
98
+ // Row lock on the environment serializes concurrent writers (SQLite is single-writer).
99
+ if (this.dialect !== 'sqlite') {
100
+ await trx.rawQuery('SELECT version FROM flags_environments WHERE name = ? FOR UPDATE', [
101
+ environment,
102
+ ]);
103
+ }
104
+ const before = currentValue(await this.#readIn(trx, environment), change);
105
+ await this.#write(trx, environment, change, actor, now);
106
+ await trx.rawQuery('UPDATE flags_environments SET version = version + 1, updated_at = ? WHERE name = ?', [now, environment]);
107
+ const version = await this.#version(trx, environment);
108
+ await trx.rawQuery(`INSERT INTO flags_audit (id, environment, entity, entity_key, action, before_value, after_value, actor_id, actor_name, change_request_id, version, at)
109
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
110
+ randomUUID(),
111
+ environment,
112
+ change.entity,
113
+ change.key ?? null,
114
+ auditAction(before, change),
115
+ jsonValue(before),
116
+ jsonValue(change.value),
117
+ actor.id,
118
+ actor.name ?? null,
119
+ options.changeRequestId ?? null,
120
+ Number(version),
121
+ now,
122
+ ]);
123
+ if (this.dialect === 'postgres') {
124
+ await trx.rawQuery('SELECT pg_notify(?, ?)', [
125
+ RULESET_CHANNEL,
126
+ `${environment}:${version}`,
127
+ ]);
128
+ }
129
+ return { version };
130
+ });
131
+ return result;
132
+ }
133
+ async #readIn(trx, environment) {
134
+ const rows = await query(trx, 'SELECT entity, entity_key, definition FROM flags_entities WHERE environment = ?', [environment]);
135
+ let ruleset = {
136
+ schemaVersion: RULESET_SCHEMA_VERSION,
137
+ version: '0',
138
+ flags: {},
139
+ segments: {},
140
+ layers: {},
141
+ };
142
+ for (const row of rows) {
143
+ const value = parseJson(row.definition);
144
+ ruleset =
145
+ row.entity === 'holdout'
146
+ ? applyChange(ruleset, { entity: 'holdout', value })
147
+ : applyChange(ruleset, { entity: row.entity, key: row.entity_key, value });
148
+ }
149
+ return ruleset;
150
+ }
151
+ async #ensureEnvironment(trx, environment, now) {
152
+ await trx.rawQuery(insertIgnore(this.dialect, 'flags_environments', ['name', 'version', 'updated_at'], 1), [environment, 0, now]);
153
+ }
154
+ async #write(trx, environment, change, actor, now) {
155
+ const upsert = async (entity, key, value) => {
156
+ await trx.rawQuery('DELETE FROM flags_entities WHERE environment = ? AND entity = ? AND entity_key = ?', [environment, entity, key]);
157
+ if (value === null)
158
+ return;
159
+ await trx.rawQuery('INSERT INTO flags_entities (environment, entity, entity_key, definition, updated_at, updated_by) VALUES (?, ?, ?, ?, ?, ?)', [environment, entity, key, jsonValue(value), now, actor.id]);
160
+ };
161
+ switch (change.entity) {
162
+ case 'flag':
163
+ case 'segment':
164
+ case 'layer':
165
+ await upsert(change.entity, change.key, change.value);
166
+ return;
167
+ case 'holdout':
168
+ await upsert('holdout', HOLDOUT_KEY, change.value);
169
+ return;
170
+ case 'ruleset': {
171
+ await trx.rawQuery('DELETE FROM flags_entities WHERE environment = ?', [environment]);
172
+ const value = change.value;
173
+ for (const [key, def] of Object.entries(value.flags))
174
+ await upsert('flag', key, def);
175
+ for (const [key, def] of Object.entries(value.segments ?? {}))
176
+ await upsert('segment', key, def);
177
+ for (const [key, def] of Object.entries(value.layers ?? {}))
178
+ await upsert('layer', key, def);
179
+ if (value.holdout)
180
+ await upsert('holdout', HOLDOUT_KEY, value.holdout);
181
+ }
182
+ }
183
+ }
184
+ async environments() {
185
+ const rows = await query(this.db, 'SELECT name FROM flags_environments ORDER BY name');
186
+ return rows.map((row) => row.name);
187
+ }
188
+ async audit(q) {
189
+ const where = [];
190
+ const bindings = [];
191
+ if (q.environment !== undefined)
192
+ where.push('environment = ?') && bindings.push(q.environment);
193
+ if (q.entity !== undefined)
194
+ where.push('entity = ?') && bindings.push(q.entity);
195
+ if (q.key !== undefined)
196
+ where.push('entity_key = ?') && bindings.push(q.key);
197
+ if (q.before !== undefined)
198
+ where.push('at < ?') && bindings.push(q.before.getTime());
199
+ bindings.push(q.limit ?? 100);
200
+ const rows = await query(this.db, `SELECT * FROM flags_audit ${where.length ? `WHERE ${where.join(' AND ')}` : ''} ORDER BY version DESC, at DESC LIMIT ?`, bindings);
201
+ return rows.map((row) => ({
202
+ id: String(row.id),
203
+ environment: String(row.environment),
204
+ entity: row.entity,
205
+ key: row.entity_key ?? null,
206
+ action: row.action,
207
+ before: row.before_value === null ? null : parseJson(row.before_value),
208
+ after: row.after_value === null ? null : parseJson(row.after_value),
209
+ actor: {
210
+ id: String(row.actor_id),
211
+ ...(row.actor_name ? { name: String(row.actor_name) } : {}),
212
+ },
213
+ ...(row.change_request_id ? { changeRequestId: String(row.change_request_id) } : {}),
214
+ version: String(toNumber(row.version)),
215
+ at: toDate(row.at),
216
+ }));
217
+ }
218
+ async createChangeRequest(request) {
219
+ const id = randomUUID();
220
+ const now = Date.now();
221
+ await this.db.rawQuery(`INSERT INTO flags_change_requests (id, environment, change_value, note, requested_by, requested_at, status, base_version)
222
+ VALUES (?, ?, ?, ?, ?, ?, 'pending', ?)`, [
223
+ id,
224
+ request.environment,
225
+ jsonValue(request.change),
226
+ request.note ?? null,
227
+ jsonValue(request.requestedBy),
228
+ now,
229
+ request.baseVersion,
230
+ ]);
231
+ return (await this.getChangeRequest(id));
232
+ }
233
+ async getChangeRequest(id) {
234
+ const rows = await query(this.db, 'SELECT * FROM flags_change_requests WHERE id = ?', [id]);
235
+ return rows[0] ? toChangeRequest(rows[0]) : null;
236
+ }
237
+ async listChangeRequests(q) {
238
+ const where = [];
239
+ const bindings = [];
240
+ if (q.environment !== undefined)
241
+ where.push('environment = ?') && bindings.push(q.environment);
242
+ if (q.status !== undefined)
243
+ where.push('status = ?') && bindings.push(q.status);
244
+ bindings.push(q.limit ?? 100);
245
+ const rows = await query(this.db, `SELECT * FROM flags_change_requests ${where.length ? `WHERE ${where.join(' AND ')}` : ''} ORDER BY requested_at DESC LIMIT ?`, bindings);
246
+ return rows.map(toChangeRequest);
247
+ }
248
+ async updateChangeRequest(id, patch) {
249
+ const sets = [];
250
+ const bindings = [];
251
+ if (patch.status !== undefined)
252
+ sets.push('status = ?') && bindings.push(patch.status);
253
+ if (patch.reviewedBy !== undefined)
254
+ sets.push('reviewed_by = ?') && bindings.push(jsonValue(patch.reviewedBy));
255
+ if (patch.reviewedAt !== undefined)
256
+ sets.push('reviewed_at = ?') && bindings.push(patch.reviewedAt.getTime());
257
+ if (patch.reviewNote !== undefined)
258
+ sets.push('review_note = ?') && bindings.push(patch.reviewNote);
259
+ if (sets.length > 0) {
260
+ await this.db.rawQuery(`UPDATE flags_change_requests SET ${sets.join(', ')} WHERE id = ?`, [
261
+ ...bindings,
262
+ id,
263
+ ]);
264
+ }
265
+ const updated = await this.getChangeRequest(id);
266
+ if (!updated)
267
+ throw new Error(`change request ${id} not found`);
268
+ return updated;
269
+ }
270
+ async createSchedule(schedule) {
271
+ const id = randomUUID();
272
+ await this.db.rawQuery(`INSERT INTO flags_schedules (id, environment, flag, kind, payload, run_at, status, created_by)
273
+ VALUES (?, ?, ?, ?, ?, ?, 'pending', ?)`, [
274
+ id,
275
+ schedule.environment,
276
+ schedule.flag,
277
+ schedule.kind,
278
+ jsonValue(schedule.payload),
279
+ schedule.runAt.getTime(),
280
+ jsonValue(schedule.createdBy),
281
+ ]);
282
+ return (await this.#schedule(id));
283
+ }
284
+ getSchedule(id) {
285
+ return this.#schedule(id);
286
+ }
287
+ /** Whether this store can push change notifications (Postgres `LISTEN/NOTIFY`). */
288
+ get canListen() {
289
+ return this.dialect === 'postgres';
290
+ }
291
+ async #schedule(id) {
292
+ const rows = await query(this.db, 'SELECT * FROM flags_schedules WHERE id = ?', [id]);
293
+ return rows[0] ? toSchedule(rows[0]) : null;
294
+ }
295
+ async listSchedules(q) {
296
+ const where = [];
297
+ const bindings = [];
298
+ if (q.environment !== undefined)
299
+ where.push('environment = ?') && bindings.push(q.environment);
300
+ if (q.flag !== undefined)
301
+ where.push('flag = ?') && bindings.push(q.flag);
302
+ if (q.status !== undefined)
303
+ where.push('status = ?') && bindings.push(q.status);
304
+ if (q.dueBefore !== undefined)
305
+ where.push('run_at <= ?') && bindings.push(q.dueBefore.getTime());
306
+ bindings.push(q.limit ?? 100);
307
+ const rows = await query(this.db, `SELECT * FROM flags_schedules ${where.length ? `WHERE ${where.join(' AND ')}` : ''} ORDER BY run_at ASC LIMIT ?`, bindings);
308
+ return rows.map(toSchedule);
309
+ }
310
+ async updateSchedule(id, patch) {
311
+ const sets = [];
312
+ const bindings = [];
313
+ if (patch.status !== undefined)
314
+ sets.push('status = ?') && bindings.push(patch.status);
315
+ if (patch.error !== undefined)
316
+ sets.push('error = ?') && bindings.push(patch.error);
317
+ if (patch.executedAt !== undefined)
318
+ sets.push('executed_at = ?') && bindings.push(patch.executedAt.getTime());
319
+ if (sets.length > 0) {
320
+ await this.db.rawQuery(`UPDATE flags_schedules SET ${sets.join(', ')} WHERE id = ?`, [
321
+ ...bindings,
322
+ id,
323
+ ]);
324
+ }
325
+ const updated = await this.#schedule(id);
326
+ if (!updated)
327
+ throw new Error(`schedule ${id} not found`);
328
+ return updated;
329
+ }
330
+ async claimSchedule(id) {
331
+ // Compare-and-set in one statement: only one replica's UPDATE matches the pending row, and the
332
+ // token it writes tells it apart from a replica that lost the race.
333
+ const token = `claim:${randomUUID()}`;
334
+ await this.db.rawQuery("UPDATE flags_schedules SET status = 'running', error = ? WHERE id = ? AND status = 'pending'", [token, id]);
335
+ const rows = await query(this.db, 'SELECT error FROM flags_schedules WHERE id = ?', [id]);
336
+ if (rows[0]?.error !== token)
337
+ return false;
338
+ await this.db.rawQuery('UPDATE flags_schedules SET error = NULL WHERE id = ?', [id]);
339
+ return true;
340
+ }
341
+ async recordUsage(rows) {
342
+ if (rows.length === 0)
343
+ return;
344
+ for (const row of rows) {
345
+ const sql = this.dialect === 'mysql'
346
+ ? 'INSERT INTO flags_usage (environment, flag, day, evaluations) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE evaluations = evaluations + VALUES(evaluations)'
347
+ : 'INSERT INTO flags_usage (environment, flag, day, evaluations) VALUES (?, ?, ?, ?) ON CONFLICT (environment, flag, day) DO UPDATE SET evaluations = flags_usage.evaluations + excluded.evaluations';
348
+ await this.db.rawQuery(sql, [row.environment, row.flag, row.day, row.evaluations]);
349
+ }
350
+ }
351
+ async usage(q) {
352
+ const rows = await query(this.db, 'SELECT environment, flag, day, evaluations FROM flags_usage WHERE environment = ? AND day >= ?', [q.environment, q.since]);
353
+ return rows.map((row) => ({
354
+ environment: String(row.environment),
355
+ flag: String(row.flag),
356
+ day: String(row.day),
357
+ evaluations: toNumber(row.evaluations),
358
+ }));
359
+ }
360
+ async saveDeclarations(app, declarations) {
361
+ const now = Date.now();
362
+ await this.db.transaction(async (trx) => {
363
+ for (const [key, declaration] of Object.entries(declarations)) {
364
+ await trx.rawQuery('DELETE FROM flags_declarations WHERE app = ? AND flag = ?', [app, key]);
365
+ await trx.rawQuery('INSERT INTO flags_declarations (app, flag, declaration, last_seen_at) VALUES (?, ?, ?, ?)', [app, key, jsonValue(declaration), now]);
366
+ }
367
+ });
368
+ }
369
+ async declarations(app) {
370
+ const rows = await query(this.db, `SELECT * FROM flags_declarations ${app !== undefined ? 'WHERE app = ?' : ''} ORDER BY app, flag`, app !== undefined ? [app] : []);
371
+ return rows.map((row) => ({
372
+ app: String(row.app),
373
+ key: String(row.flag),
374
+ declaration: parseJson(row.declaration),
375
+ lastSeenAt: toDate(row.last_seen_at),
376
+ }));
377
+ }
378
+ }
379
+ function toChangeRequest(row) {
380
+ return {
381
+ id: String(row.id),
382
+ environment: String(row.environment),
383
+ change: parseJson(row.change_value),
384
+ ...(row.note ? { note: String(row.note) } : {}),
385
+ requestedBy: parseJson(row.requested_by),
386
+ requestedAt: toDate(row.requested_at),
387
+ status: row.status,
388
+ ...(row.reviewed_by ? { reviewedBy: parseJson(row.reviewed_by) } : {}),
389
+ ...(row.reviewed_at !== null && row.reviewed_at !== undefined
390
+ ? { reviewedAt: toDate(row.reviewed_at) }
391
+ : {}),
392
+ ...(row.review_note ? { reviewNote: String(row.review_note) } : {}),
393
+ baseVersion: String(row.base_version),
394
+ };
395
+ }
396
+ function toSchedule(row) {
397
+ return {
398
+ id: String(row.id),
399
+ environment: String(row.environment),
400
+ flag: String(row.flag),
401
+ kind: row.kind,
402
+ payload: parseJson(row.payload),
403
+ runAt: toDate(row.run_at),
404
+ status: row.status,
405
+ createdBy: parseJson(row.created_by),
406
+ ...(row.error && !String(row.error).startsWith('claim:') ? { error: String(row.error) } : {}),
407
+ ...(row.executed_at !== null && row.executed_at !== undefined
408
+ ? { executedAt: toDate(row.executed_at) }
409
+ : {}),
410
+ };
411
+ }
412
+ //# sourceMappingURL=lucid_store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lucid_store.js","sourceRoot":"","sources":["../../../src/stores/lucid_store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { type Ruleset } from '@adonis-agora/flags-core';
2
+ import type { FlagDeclaration } from '../declare.js';
3
+ import { type Actor, type AuditEntry, type ChangeRequest, type DeclarationRow, type FlagsStore, type RulesetChange, type ScheduledChange, type UsageRow } from './store.js';
4
+ /**
5
+ * A store that lives in process memory. For tests, local development and apps whose flags are
6
+ * only toggled from code. Nothing survives a restart, and replicas do not share it.
7
+ */
8
+ export declare class MemoryStore implements FlagsStore {
9
+ #private;
10
+ /** Seed environments with a ruleset (`{ production: { flags: {…} } }`). */
11
+ constructor(seed?: Record<string, Partial<Omit<Ruleset, 'version'>>>);
12
+ readRuleset(environment: string): Promise<Ruleset>;
13
+ version(environment: string): Promise<string>;
14
+ apply(environment: string, change: RulesetChange, actor: Actor, options?: {
15
+ changeRequestId?: string;
16
+ }): Promise<{
17
+ version: string;
18
+ }>;
19
+ environments(): Promise<string[]>;
20
+ audit(query: Parameters<FlagsStore['audit']>[0]): Promise<AuditEntry[]>;
21
+ createChangeRequest(request: Omit<ChangeRequest, 'id' | 'status' | 'requestedAt'>): Promise<ChangeRequest>;
22
+ getChangeRequest(id: string): Promise<ChangeRequest | null>;
23
+ listChangeRequests(query: Parameters<FlagsStore['listChangeRequests']>[0]): Promise<ChangeRequest[]>;
24
+ updateChangeRequest(id: string, patch: Parameters<FlagsStore['updateChangeRequest']>[1]): Promise<ChangeRequest>;
25
+ createSchedule(schedule: Omit<ScheduledChange, 'id' | 'status'>): Promise<ScheduledChange>;
26
+ getSchedule(id: string): Promise<ScheduledChange | null>;
27
+ listSchedules(query: Parameters<FlagsStore['listSchedules']>[0]): Promise<ScheduledChange[]>;
28
+ updateSchedule(id: string, patch: Parameters<FlagsStore['updateSchedule']>[1]): Promise<ScheduledChange>;
29
+ claimSchedule(id: string): Promise<boolean>;
30
+ recordUsage(rows: UsageRow[]): Promise<void>;
31
+ usage(query: {
32
+ environment: string;
33
+ since: string;
34
+ }): Promise<UsageRow[]>;
35
+ saveDeclarations(app: string, declarations: Record<string, FlagDeclaration>): Promise<void>;
36
+ declarations(app?: string): Promise<DeclarationRow[]>;
37
+ }
38
+ //# sourceMappingURL=memory_store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory_store.d.ts","sourceRoot":"","sources":["../../../src/stores/memory_store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,166 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { emptyRuleset, RULESET_SCHEMA_VERSION } from '@adonis-agora/flags-core';
3
+ import { applyChange, auditAction, currentValue, } from './store.js';
4
+ /**
5
+ * A store that lives in process memory. For tests, local development and apps whose flags are
6
+ * only toggled from code. Nothing survives a restart, and replicas do not share it.
7
+ */
8
+ export class MemoryStore {
9
+ #rulesets = new Map();
10
+ #versions = new Map();
11
+ #audit = [];
12
+ #requests = new Map();
13
+ #schedules = new Map();
14
+ #usage = new Map();
15
+ #declarations = new Map();
16
+ /** Seed environments with a ruleset (`{ production: { flags: {…} } }`). */
17
+ constructor(seed = {}) {
18
+ for (const [environment, ruleset] of Object.entries(seed)) {
19
+ this.#rulesets.set(environment, {
20
+ ...emptyRuleset(),
21
+ ...ruleset,
22
+ schemaVersion: RULESET_SCHEMA_VERSION,
23
+ version: '1',
24
+ });
25
+ this.#versions.set(environment, 1);
26
+ }
27
+ }
28
+ async readRuleset(environment) {
29
+ const ruleset = this.#rulesets.get(environment) ?? emptyRuleset('0');
30
+ return structuredClone({ ...ruleset, version: await this.version(environment) });
31
+ }
32
+ async version(environment) {
33
+ return String(this.#versions.get(environment) ?? 0);
34
+ }
35
+ async apply(environment, change, actor, options = {}) {
36
+ const current = this.#rulesets.get(environment) ?? emptyRuleset('0');
37
+ const before = currentValue(current, change);
38
+ const version = (this.#versions.get(environment) ?? 0) + 1;
39
+ this.#rulesets.set(environment, { ...applyChange(current, change), version: String(version) });
40
+ this.#versions.set(environment, version);
41
+ this.#audit.push({
42
+ id: randomUUID(),
43
+ environment,
44
+ entity: change.entity,
45
+ key: change.key ?? null,
46
+ action: auditAction(before, change),
47
+ before: structuredClone(before),
48
+ after: structuredClone(change.value),
49
+ actor,
50
+ ...(options.changeRequestId ? { changeRequestId: options.changeRequestId } : {}),
51
+ version: String(version),
52
+ at: new Date(),
53
+ });
54
+ return { version: String(version) };
55
+ }
56
+ async environments() {
57
+ return [...this.#rulesets.keys()].sort();
58
+ }
59
+ async audit(query) {
60
+ return this.#audit
61
+ .filter((entry) => (query.environment === undefined || entry.environment === query.environment) &&
62
+ (query.entity === undefined || entry.entity === query.entity) &&
63
+ (query.key === undefined || entry.key === query.key) &&
64
+ (query.before === undefined || entry.at < query.before))
65
+ .reverse()
66
+ .slice(0, query.limit ?? 100);
67
+ }
68
+ async createChangeRequest(request) {
69
+ const created = {
70
+ ...structuredClone(request),
71
+ id: randomUUID(),
72
+ status: 'pending',
73
+ requestedAt: new Date(),
74
+ };
75
+ this.#requests.set(created.id, created);
76
+ return structuredClone(created);
77
+ }
78
+ async getChangeRequest(id) {
79
+ const found = this.#requests.get(id);
80
+ return found ? structuredClone(found) : null;
81
+ }
82
+ async listChangeRequests(query) {
83
+ return [...this.#requests.values()]
84
+ .filter((r) => (query.environment === undefined || r.environment === query.environment) &&
85
+ (query.status === undefined || r.status === query.status))
86
+ .sort((a, b) => b.requestedAt.getTime() - a.requestedAt.getTime())
87
+ .slice(0, query.limit ?? 100)
88
+ .map((r) => structuredClone(r));
89
+ }
90
+ async updateChangeRequest(id, patch) {
91
+ const found = this.#requests.get(id);
92
+ if (!found)
93
+ throw new Error(`change request ${id} not found`);
94
+ Object.assign(found, structuredClone(patch));
95
+ return structuredClone(found);
96
+ }
97
+ async createSchedule(schedule) {
98
+ const created = {
99
+ ...structuredClone(schedule),
100
+ id: randomUUID(),
101
+ status: 'pending',
102
+ };
103
+ this.#schedules.set(created.id, created);
104
+ return structuredClone(created);
105
+ }
106
+ async getSchedule(id) {
107
+ const found = this.#schedules.get(id);
108
+ return found ? structuredClone(found) : null;
109
+ }
110
+ async listSchedules(query) {
111
+ return [...this.#schedules.values()]
112
+ .filter((s) => (query.environment === undefined || s.environment === query.environment) &&
113
+ (query.flag === undefined || s.flag === query.flag) &&
114
+ (query.status === undefined || s.status === query.status) &&
115
+ (query.dueBefore === undefined || s.runAt <= query.dueBefore))
116
+ .sort((a, b) => a.runAt.getTime() - b.runAt.getTime())
117
+ .slice(0, query.limit ?? 100)
118
+ .map((s) => structuredClone(s));
119
+ }
120
+ async updateSchedule(id, patch) {
121
+ const found = this.#schedules.get(id);
122
+ if (!found)
123
+ throw new Error(`schedule ${id} not found`);
124
+ Object.assign(found, structuredClone(patch));
125
+ return structuredClone(found);
126
+ }
127
+ async claimSchedule(id) {
128
+ const found = this.#schedules.get(id);
129
+ if (found?.status !== 'pending')
130
+ return false;
131
+ found.status = 'running';
132
+ return true;
133
+ }
134
+ async recordUsage(rows) {
135
+ for (const row of rows) {
136
+ const key = `${row.environment}\u0000${row.flag}\u0000${row.day}`;
137
+ const existing = this.#usage.get(key);
138
+ if (existing)
139
+ existing.evaluations += row.evaluations;
140
+ else
141
+ this.#usage.set(key, { ...row });
142
+ }
143
+ }
144
+ async usage(query) {
145
+ return [...this.#usage.values()]
146
+ .filter((row) => row.environment === query.environment && row.day >= query.since)
147
+ .map((row) => ({ ...row }));
148
+ }
149
+ async saveDeclarations(app, declarations) {
150
+ const now = new Date();
151
+ for (const [key, declaration] of Object.entries(declarations)) {
152
+ this.#declarations.set(`${app}\u0000${key}`, {
153
+ app,
154
+ key,
155
+ declaration: structuredClone(declaration),
156
+ lastSeenAt: now,
157
+ });
158
+ }
159
+ }
160
+ async declarations(app) {
161
+ return [...this.#declarations.values()]
162
+ .filter((row) => app === undefined || row.app === app)
163
+ .map((row) => structuredClone(row));
164
+ }
165
+ }
166
+ //# sourceMappingURL=memory_store.js.map